]> bbs.cooldavid.org Git - net-next-2.6.git/commitdiff
Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
authorDavid S. Miller <davem@davemloft.net>
Fri, 10 Sep 2010 05:27:33 +0000 (22:27 -0700)
committerDavid S. Miller <davem@davemloft.net>
Fri, 10 Sep 2010 05:27:33 +0000 (22:27 -0700)
Conflicts:
net/mac80211/main.c

690 files changed:
Documentation/DocBook/80211.tmpl [new file with mode: 0644]
Documentation/DocBook/Makefile
Documentation/DocBook/mac80211.tmpl [deleted file]
Documentation/networking/dccp.txt
Documentation/networking/ip-sysctl.txt
Documentation/networking/timestamping.txt
MAINTAINERS
arch/s390/include/asm/qdio.h
drivers/atm/firestream.c
drivers/atm/iphase.c
drivers/firewire/net.c
drivers/ieee1394/eth1394.c
drivers/isdn/capi/capidrv.c
drivers/isdn/divert/isdn_divert.c
drivers/isdn/hisax/hfc_sx.c
drivers/isdn/i4l/isdn_tty.c
drivers/isdn/mISDN/dsp_cmx.c
drivers/isdn/mISDN/l1oip_core.c
drivers/net/3c503.c
drivers/net/3c515.c
drivers/net/3c59x.c
drivers/net/8139cp.c
drivers/net/Kconfig
drivers/net/Makefile
drivers/net/acenic.c
drivers/net/amd8111e.c
drivers/net/amd8111e.h
drivers/net/arm/am79c961a.c
drivers/net/arm/am79c961a.h
drivers/net/arm/ep93xx_eth.c
drivers/net/arm/ether1.c
drivers/net/arm/ether1.h
drivers/net/arm/ether3.c
drivers/net/arm/ether3.h
drivers/net/atl1c/atl1c.h
drivers/net/atl1c/atl1c_hw.c
drivers/net/atl1c/atl1c_main.c
drivers/net/atl1e/atl1e_main.c
drivers/net/atlx/atl1.c
drivers/net/atlx/atl2.c
drivers/net/atp.c
drivers/net/au1000_eth.c
drivers/net/au1000_eth.h
drivers/net/b44.c
drivers/net/bcm63xx_enet.c
drivers/net/bcm63xx_enet.h
drivers/net/benet/be.h
drivers/net/benet/be_ethtool.c
drivers/net/benet/be_main.c
drivers/net/bfin_mac.c
drivers/net/bmac.c
drivers/net/bna/Makefile [new file with mode: 0644]
drivers/net/bna/bfa_cee.c [new file with mode: 0644]
drivers/net/bna/bfa_cee.h [new file with mode: 0644]
drivers/net/bna/bfa_defs.h [new file with mode: 0644]
drivers/net/bna/bfa_defs_cna.h [new file with mode: 0644]
drivers/net/bna/bfa_defs_mfg_comm.h [new file with mode: 0644]
drivers/net/bna/bfa_defs_status.h [new file with mode: 0644]
drivers/net/bna/bfa_ioc.c [new file with mode: 0644]
drivers/net/bna/bfa_ioc.h [new file with mode: 0644]
drivers/net/bna/bfa_ioc_ct.c [new file with mode: 0644]
drivers/net/bna/bfa_sm.h [new file with mode: 0644]
drivers/net/bna/bfa_wc.h [new file with mode: 0644]
drivers/net/bna/bfi.h [new file with mode: 0644]
drivers/net/bna/bfi_cna.h [new file with mode: 0644]
drivers/net/bna/bfi_ctreg.h [new file with mode: 0644]
drivers/net/bna/bfi_ll.h [new file with mode: 0644]
drivers/net/bna/bna.h [new file with mode: 0644]
drivers/net/bna/bna_ctrl.c [new file with mode: 0644]
drivers/net/bna/bna_hw.h [new file with mode: 0644]
drivers/net/bna/bna_txrx.c [new file with mode: 0644]
drivers/net/bna/bna_types.h [new file with mode: 0644]
drivers/net/bna/bnad.c [new file with mode: 0644]
drivers/net/bna/bnad.h [new file with mode: 0644]
drivers/net/bna/bnad_ethtool.c [new file with mode: 0644]
drivers/net/bna/cna.h [new file with mode: 0644]
drivers/net/bna/cna_fwimg.c [new file with mode: 0644]
drivers/net/bnx2.c
drivers/net/bnx2x/bnx2x.h
drivers/net/bnx2x/bnx2x_cmn.c
drivers/net/bnx2x/bnx2x_cmn.h
drivers/net/bnx2x/bnx2x_ethtool.c
drivers/net/bnx2x/bnx2x_hsi.h
drivers/net/bnx2x/bnx2x_link.c
drivers/net/bnx2x/bnx2x_link.h
drivers/net/bnx2x/bnx2x_main.c
drivers/net/bnx2x/bnx2x_reg.h
drivers/net/bnx2x/bnx2x_stats.c
drivers/net/can/mscan/mpc5xxx_can.c
drivers/net/cassini.c
drivers/net/chelsio/sge.c
drivers/net/chelsio/subr.c
drivers/net/cnic.c
drivers/net/cpmac.c
drivers/net/cxgb3/cxgb3_main.c
drivers/net/cxgb3/regs.h
drivers/net/cxgb3/sge.c
drivers/net/cxgb3/t3_hw.c
drivers/net/cxgb4/cxgb4.h
drivers/net/cxgb4/cxgb4_main.c
drivers/net/cxgb4/sge.c
drivers/net/cxgb4/t4_hw.h
drivers/net/cxgb4/t4fw_api.h
drivers/net/cxgb4vf/sge.c
drivers/net/declance.c
drivers/net/dl2k.c
drivers/net/dm9000.c
drivers/net/e1000/e1000_main.c
drivers/net/e1000e/netdev.c
drivers/net/eepro.c
drivers/net/ehea/ehea_main.c
drivers/net/enic/enic.h
drivers/net/enic/enic_main.c
drivers/net/enic/vnic_dev.c
drivers/net/enic/vnic_devcmd.h
drivers/net/enic/vnic_enet.h
drivers/net/enic/vnic_resource.h
drivers/net/enic/vnic_rq.c
drivers/net/enic/vnic_vic.c
drivers/net/enic/vnic_wq.c
drivers/net/epic100.c
drivers/net/ethoc.c
drivers/net/fealnx.c
drivers/net/fec_mpc52xx.c
drivers/net/forcedeth.c
drivers/net/fs_enet/fs_enet-main.c
drivers/net/gianfar.c
drivers/net/greth.c
drivers/net/hamachi.c
drivers/net/hamradio/scc.c
drivers/net/hp.c
drivers/net/hydra.c
drivers/net/ibmlana.c
drivers/net/ibmveth.c
drivers/net/ibmveth.h
drivers/net/igb/igb.h
drivers/net/igb/igb_main.c
drivers/net/igbvf/netdev.c
drivers/net/ioc3-eth.c
drivers/net/ipg.c
drivers/net/irda/mcs7780.c
drivers/net/irda/via-ircc.c
drivers/net/iseries_veth.c
drivers/net/ixgb/ixgb_main.c
drivers/net/ixgbe/ixgbe.h
drivers/net/ixgbe/ixgbe_ethtool.c
drivers/net/ixgbe/ixgbe_fcoe.c
drivers/net/ixgbe/ixgbe_main.c
drivers/net/ixgbe/ixgbe_type.h
drivers/net/ixgbevf/ixgbevf.h
drivers/net/ixgbevf/ixgbevf_main.c
drivers/net/ixgbevf/vf.h
drivers/net/jme.c
drivers/net/jme.h
drivers/net/ll_temac_main.c
drivers/net/mac8390.c
drivers/net/macb.c
drivers/net/macvtap.c
drivers/net/mlx4/Makefile
drivers/net/mlx4/alloc.c
drivers/net/mlx4/en_ethtool.c
drivers/net/mlx4/en_main.c
drivers/net/mlx4/en_netdev.c
drivers/net/mlx4/en_port.c
drivers/net/mlx4/en_port.h
drivers/net/mlx4/en_rx.c
drivers/net/mlx4/en_selftest.c [new file with mode: 0644]
drivers/net/mlx4/en_tx.c
drivers/net/mlx4/eq.c
drivers/net/mlx4/fw.c
drivers/net/mlx4/fw.h
drivers/net/mlx4/main.c
drivers/net/mlx4/mlx4_en.h
drivers/net/mlx4/profile.c
drivers/net/myri10ge/myri10ge.c
drivers/net/natsemi.c
drivers/net/niu.c
drivers/net/ns83820.c
drivers/net/pasemi_mac.c
drivers/net/pasemi_mac_ethtool.c
drivers/net/pci-skeleton.c
drivers/net/pcmcia/3c574_cs.c
drivers/net/pcmcia/3c589_cs.c
drivers/net/pcmcia/axnet_cs.c
drivers/net/pcmcia/com20020_cs.c
drivers/net/pcmcia/fmvj18x_cs.c
drivers/net/pcmcia/ibmtr_cs.c
drivers/net/pcmcia/nmclan_cs.c
drivers/net/pcmcia/pcnet_cs.c
drivers/net/pcmcia/smc91c92_cs.c
drivers/net/pcmcia/xirc2ps_cs.c
drivers/net/plip.c
drivers/net/pptp.c [new file with mode: 0644]
drivers/net/ps3_gelic_net.c
drivers/net/pxa168_eth.c
drivers/net/qla3xxx.c
drivers/net/qlcnic/qlcnic.h
drivers/net/qlcnic/qlcnic_ctx.c
drivers/net/qlcnic/qlcnic_ethtool.c
drivers/net/qlcnic/qlcnic_hdr.h
drivers/net/qlcnic/qlcnic_hw.c
drivers/net/qlcnic/qlcnic_init.c
drivers/net/qlcnic/qlcnic_main.c
drivers/net/qlge/qlge_main.c
drivers/net/r6040.c
drivers/net/r8169.c
drivers/net/rrunner.c
drivers/net/s2io.c
drivers/net/s2io.h
drivers/net/sb1250-mac.c
drivers/net/sc92031.c
drivers/net/sfc/rx.c
drivers/net/sh_eth.c
drivers/net/sis900.c
drivers/net/skge.c
drivers/net/slip.c
drivers/net/slip.h
drivers/net/smsc911x.c
drivers/net/spider_net.c
drivers/net/starfire.c
drivers/net/stmmac/Kconfig
drivers/net/stmmac/common.h
drivers/net/stmmac/dwmac1000_core.c
drivers/net/stmmac/dwmac1000_dma.c
drivers/net/stmmac/dwmac100_core.c
drivers/net/stmmac/dwmac100_dma.c
drivers/net/stmmac/dwmac_dma.h
drivers/net/stmmac/dwmac_lib.c
drivers/net/stmmac/enh_desc.c
drivers/net/stmmac/norm_desc.c
drivers/net/stmmac/stmmac.h
drivers/net/stmmac/stmmac_ethtool.c
drivers/net/stmmac/stmmac_main.c
drivers/net/stmmac/stmmac_mdio.c
drivers/net/sunbmac.c
drivers/net/sundance.c
drivers/net/sungem.c
drivers/net/sungem_phy.c
drivers/net/sunhme.c
drivers/net/sunlance.c
drivers/net/sunvnet.c
drivers/net/tehuti.c
drivers/net/tehuti.h
drivers/net/tg3.c
drivers/net/tlan.c
drivers/net/tokenring/tms380tr.c
drivers/net/tulip/dmfe.c
drivers/net/tulip/interrupt.c
drivers/net/tulip/tulip.h
drivers/net/tulip/tulip_core.c
drivers/net/tulip/uli526x.c
drivers/net/tulip/winbond-840.c
drivers/net/tulip/xircom_cb.c
drivers/net/typhoon.c
drivers/net/usb/Kconfig
drivers/net/usb/Makefile
drivers/net/usb/cx82310_eth.c [new file with mode: 0644]
drivers/net/usb/hso.c
drivers/net/usb/kaweth.c
drivers/net/via-velocity.c
drivers/net/virtio_net.c
drivers/net/vmxnet3/vmxnet3_drv.c
drivers/net/vxge/vxge-main.c
drivers/net/vxge/vxge-main.h
drivers/net/wan/c101.c
drivers/net/wan/cycx_drv.c
drivers/net/wan/cycx_main.c
drivers/net/wan/lapbether.c
drivers/net/wan/lmc/lmc_main.c
drivers/net/wan/n2.c
drivers/net/wan/pc300_drv.c
drivers/net/wan/pci200syn.c
drivers/net/wan/z85230.c
drivers/net/wd.c
drivers/net/wireless/airo.c
drivers/net/wireless/at76c50x-usb.c
drivers/net/wireless/ath/ar9170/main.c
drivers/net/wireless/ath/ath.h
drivers/net/wireless/ath/ath5k/ani.c
drivers/net/wireless/ath/ath5k/ath5k.h
drivers/net/wireless/ath/ath5k/attach.c
drivers/net/wireless/ath/ath5k/base.c
drivers/net/wireless/ath/ath5k/debug.c
drivers/net/wireless/ath/ath5k/debug.h
drivers/net/wireless/ath/ath5k/dma.c
drivers/net/wireless/ath/ath5k/eeprom.c
drivers/net/wireless/ath/ath5k/pcu.c
drivers/net/wireless/ath/ath5k/phy.c
drivers/net/wireless/ath/ath5k/reg.h
drivers/net/wireless/ath/ath5k/reset.c
drivers/net/wireless/ath/ath5k/rfbuffer.h
drivers/net/wireless/ath/ath9k/Makefile
drivers/net/wireless/ath/ath9k/ar9003_mac.c
drivers/net/wireless/ath/ath9k/ath9k.h
drivers/net/wireless/ath/ath9k/beacon.c
drivers/net/wireless/ath/ath9k/btcoex.c
drivers/net/wireless/ath/ath9k/calib.c
drivers/net/wireless/ath/ath9k/calib.h
drivers/net/wireless/ath/ath9k/common.c
drivers/net/wireless/ath/ath9k/common.h
drivers/net/wireless/ath/ath9k/gpio.c
drivers/net/wireless/ath/ath9k/hif_usb.c
drivers/net/wireless/ath/ath9k/htc.h
drivers/net/wireless/ath/ath9k/htc_drv_gpio.c [new file with mode: 0644]
drivers/net/wireless/ath/ath9k/htc_drv_init.c
drivers/net/wireless/ath/ath9k/htc_drv_main.c
drivers/net/wireless/ath/ath9k/htc_hst.c
drivers/net/wireless/ath/ath9k/htc_hst.h
drivers/net/wireless/ath/ath9k/hw.h
drivers/net/wireless/ath/ath9k/init.c
drivers/net/wireless/ath/ath9k/mac.c
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/recv.c
drivers/net/wireless/ath/ath9k/wmi.c
drivers/net/wireless/ath/ath9k/wmi.h
drivers/net/wireless/ath/ath9k/xmit.c
drivers/net/wireless/ath/debug.h
drivers/net/wireless/b43/main.c
drivers/net/wireless/b43/phy_n.c
drivers/net/wireless/b43legacy/main.c
drivers/net/wireless/hostap/hostap_ioctl.c
drivers/net/wireless/ipw2x00/ipw2100.c
drivers/net/wireless/ipw2x00/ipw2200.c
drivers/net/wireless/iwlwifi/Kconfig
drivers/net/wireless/iwlwifi/Makefile
drivers/net/wireless/iwlwifi/iwl-1000.c
drivers/net/wireless/iwlwifi/iwl-3945-hw.h
drivers/net/wireless/iwlwifi/iwl-3945-rs.c
drivers/net/wireless/iwlwifi/iwl-3945.c
drivers/net/wireless/iwlwifi/iwl-4965.c
drivers/net/wireless/iwlwifi/iwl-5000-hw.h
drivers/net/wireless/iwlwifi/iwl-5000.c
drivers/net/wireless/iwlwifi/iwl-6000-hw.h
drivers/net/wireless/iwlwifi/iwl-6000.c
drivers/net/wireless/iwlwifi/iwl-agn-calib.c
drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c
drivers/net/wireless/iwlwifi/iwl-agn-lib.c
drivers/net/wireless/iwlwifi/iwl-agn-rs.c
drivers/net/wireless/iwlwifi/iwl-agn-rs.h
drivers/net/wireless/iwlwifi/iwl-agn-tt.c [new file with mode: 0644]
drivers/net/wireless/iwlwifi/iwl-agn-tt.h [new file with mode: 0644]
drivers/net/wireless/iwlwifi/iwl-agn-tx.c
drivers/net/wireless/iwlwifi/iwl-agn-ucode.c
drivers/net/wireless/iwlwifi/iwl-agn.c
drivers/net/wireless/iwlwifi/iwl-agn.h
drivers/net/wireless/iwlwifi/iwl-commands.h
drivers/net/wireless/iwlwifi/iwl-core.c
drivers/net/wireless/iwlwifi/iwl-core.h
drivers/net/wireless/iwlwifi/iwl-debugfs.c
drivers/net/wireless/iwlwifi/iwl-dev.h
drivers/net/wireless/iwlwifi/iwl-hcmd.c
drivers/net/wireless/iwlwifi/iwl-power.c
drivers/net/wireless/iwlwifi/iwl-power.h
drivers/net/wireless/iwlwifi/iwl-prph.h
drivers/net/wireless/iwlwifi/iwl-rx.c
drivers/net/wireless/iwlwifi/iwl-scan.c
drivers/net/wireless/iwlwifi/iwl-sta.c
drivers/net/wireless/iwlwifi/iwl-sta.h
drivers/net/wireless/iwlwifi/iwl-tx.c
drivers/net/wireless/iwlwifi/iwl3945-base.c
drivers/net/wireless/iwmc3200wifi/rx.c
drivers/net/wireless/libertas/cfg.c
drivers/net/wireless/libertas/decl.h
drivers/net/wireless/libertas/if_cs.c
drivers/net/wireless/libertas/if_sdio.c
drivers/net/wireless/libertas/if_sdio.h
drivers/net/wireless/libertas/if_spi.c
drivers/net/wireless/libertas/if_spi.h
drivers/net/wireless/libertas/if_usb.c
drivers/net/wireless/libertas/if_usb.h
drivers/net/wireless/libertas/main.c
drivers/net/wireless/libertas_tf/if_usb.c
drivers/net/wireless/mac80211_hwsim.c
drivers/net/wireless/orinoco/hw.c
drivers/net/wireless/orinoco/wext.c
drivers/net/wireless/p54/Kconfig
drivers/net/wireless/p54/eeprom.c
drivers/net/wireless/p54/fwio.c
drivers/net/wireless/p54/main.c
drivers/net/wireless/p54/p54spi.c
drivers/net/wireless/p54/p54spi_eeprom.h
drivers/net/wireless/p54/p54usb.c
drivers/net/wireless/p54/txrx.c
drivers/net/wireless/prism54/isl_ioctl.c
drivers/net/wireless/ray_cs.c
drivers/net/wireless/rt2x00/rt2400pci.c
drivers/net/wireless/rt2x00/rt2500pci.c
drivers/net/wireless/rt2x00/rt2500usb.c
drivers/net/wireless/rt2x00/rt2800.h
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/rt2x00config.c
drivers/net/wireless/rt2x00/rt2x00crypto.c
drivers/net/wireless/rt2x00/rt2x00debug.c
drivers/net/wireless/rt2x00/rt2x00dev.c
drivers/net/wireless/rt2x00/rt2x00firmware.c
drivers/net/wireless/rt2x00/rt2x00ht.c
drivers/net/wireless/rt2x00/rt2x00queue.c
drivers/net/wireless/rt2x00/rt2x00queue.h
drivers/net/wireless/rt2x00/rt2x00usb.c
drivers/net/wireless/rt2x00/rt2x00usb.h
drivers/net/wireless/rt2x00/rt61pci.c
drivers/net/wireless/rt2x00/rt73usb.c
drivers/net/wireless/rtl818x/rtl8180_dev.c
drivers/net/wireless/rtl818x/rtl8187_dev.c
drivers/net/wireless/wl12xx/wl1251.h
drivers/net/wireless/wl12xx/wl1251_acx.c
drivers/net/wireless/wl12xx/wl1251_acx.h
drivers/net/wireless/wl12xx/wl1251_boot.c
drivers/net/wireless/wl12xx/wl1251_boot.h
drivers/net/wireless/wl12xx/wl1251_cmd.c
drivers/net/wireless/wl12xx/wl1251_cmd.h
drivers/net/wireless/wl12xx/wl1251_debugfs.c
drivers/net/wireless/wl12xx/wl1251_debugfs.h
drivers/net/wireless/wl12xx/wl1251_event.c
drivers/net/wireless/wl12xx/wl1251_event.h
drivers/net/wireless/wl12xx/wl1251_init.c
drivers/net/wireless/wl12xx/wl1251_init.h
drivers/net/wireless/wl12xx/wl1251_io.c
drivers/net/wireless/wl12xx/wl1251_main.c
drivers/net/wireless/wl12xx/wl1251_ps.c
drivers/net/wireless/wl12xx/wl1251_ps.h
drivers/net/wireless/wl12xx/wl1251_reg.h
drivers/net/wireless/wl12xx/wl1251_rx.c
drivers/net/wireless/wl12xx/wl1251_rx.h
drivers/net/wireless/wl12xx/wl1251_sdio.c
drivers/net/wireless/wl12xx/wl1251_spi.c
drivers/net/wireless/wl12xx/wl1251_spi.h
drivers/net/wireless/wl12xx/wl1251_tx.c
drivers/net/wireless/wl12xx/wl1251_tx.h
drivers/net/wireless/wl12xx/wl1271_acx.c
drivers/net/wireless/wl12xx/wl1271_main.c
drivers/net/wireless/wl12xx/wl1271_scan.c
drivers/net/wireless/wl12xx/wl1271_tx.c
drivers/net/wireless/wl3501_cs.c
drivers/net/wireless/zd1211rw/zd_chip.c
drivers/net/xen-netfront.c
drivers/net/xilinx_emaclite.c
drivers/net/yellowfin.c
drivers/s390/cio/qdio.h
drivers/s390/cio/qdio_debug.c
drivers/s390/cio/qdio_main.c
drivers/s390/cio/qdio_setup.c
drivers/s390/cio/qdio_thinint.c
drivers/s390/net/Kconfig
drivers/s390/net/qeth_core.h
drivers/s390/net/qeth_core_main.c
drivers/s390/net/qeth_l2_main.c
drivers/s390/net/qeth_l3_main.c
drivers/s390/scsi/zfcp_qdio.c
drivers/usb/atm/cxacru.c
include/linux/Kbuild
include/linux/etherdevice.h
include/linux/if.h
include/linux/if_ether.h
include/linux/if_macvlan.h
include/linux/if_pppox.h
include/linux/if_vlan.h
include/linux/in.h
include/linux/mlx4/cmd.h
include/linux/mlx4/device.h
include/linux/netdevice.h
include/linux/nl80211.h
include/linux/pci_ids.h
include/linux/phy.h
include/linux/pkt_cls.h
include/linux/rds.h
include/linux/rtnetlink.h
include/linux/skbuff.h
include/linux/spi/wl12xx.h
include/linux/ssb/ssb_regs.h
include/linux/stmmac.h
include/linux/tc_act/Kbuild
include/linux/tc_act/tc_csum.h [new file with mode: 0644]
include/linux/tc_ematch/tc_em_meta.h
include/linux/tcp.h
include/net/cfg80211.h
include/net/gre.h [new file with mode: 0644]
include/net/inet_connection_sock.h
include/net/ip.h
include/net/irda/irlan_common.h
include/net/mac80211.h
include/net/raw.h
include/net/sctp/sctp.h
include/net/sock.h
include/net/tc_act/tc_csum.h [new file with mode: 0644]
include/net/tcp.h
net/8021q/vlan_core.c
net/9p/trans_fd.c
net/atm/common.c
net/atm/lec.c
net/ax25/af_ax25.c
net/ax25/ax25_route.c
net/bluetooth/af_bluetooth.c
net/bridge/br_if.c
net/bridge/br_input.c
net/caif/caif_dev.c
net/caif/caif_socket.c
net/caif/cfcnfg.c
net/caif/cfctrl.c
net/caif/cfdbgl.c
net/caif/cfdgml.c
net/caif/cffrml.c
net/caif/cfmuxl.c
net/caif/cfpkt_skbuff.c
net/caif/cfrfml.c
net/caif/cfserl.c
net/caif/cfsrvl.c
net/caif/cfutill.c
net/caif/cfveil.c
net/caif/cfvidl.c
net/caif/chnl_net.c
net/can/raw.c
net/core/datagram.c
net/core/dev.c
net/core/ethtool.c
net/core/iovec.c
net/core/net-sysfs.c
net/core/pktgen.c
net/core/rtnetlink.c
net/core/skbuff.c
net/core/sock.c
net/dccp/ccids/Kconfig
net/dccp/ccids/ccid2.c
net/dccp/ccids/ccid2.h
net/dccp/ccids/ccid3.c
net/dccp/ccids/ccid3.h
net/decnet/dn_nsp_out.c
net/econet/af_econet.c
net/ethernet/eth.c
net/ipv4/Kconfig
net/ipv4/Makefile
net/ipv4/af_inet.c
net/ipv4/arp.c
net/ipv4/gre.c [new file with mode: 0644]
net/ipv4/icmp.c
net/ipv4/ip_fragment.c
net/ipv4/ip_gre.c
net/ipv4/ip_output.c
net/ipv4/ipip.c
net/ipv4/netfilter/ipt_CLUSTERIP.c
net/ipv4/protocol.c
net/ipv4/raw.c
net/ipv4/route.c
net/ipv4/tcp.c
net/ipv4/tcp_input.c
net/ipv4/tcp_ipv4.c
net/ipv4/tcp_output.c
net/ipv4/tcp_timer.c
net/ipv4/tunnel4.c
net/ipv4/udp.c
net/ipv4/xfrm4_tunnel.c
net/ipv6/addrconf.c
net/ipv6/ip6_output.c
net/ipv6/ip6_tunnel.c
net/ipv6/ndisc.c
net/ipv6/netfilter/nf_conntrack_reasm.c
net/ipv6/protocol.c
net/ipv6/reassembly.c
net/ipv6/sit.c
net/ipv6/tunnel6.c
net/ipv6/xfrm6_tunnel.c
net/irda/irlan/irlan_eth.c
net/l2tp/l2tp_eth.c
net/mac80211/aes_ccm.c
net/mac80211/aes_cmac.c
net/mac80211/agg-rx.c
net/mac80211/cfg.c
net/mac80211/debugfs.c
net/mac80211/debugfs_key.c
net/mac80211/driver-ops.h
net/mac80211/driver-trace.h
net/mac80211/ht.c
net/mac80211/ibss.c
net/mac80211/ieee80211_i.h
net/mac80211/iface.c
net/mac80211/key.c
net/mac80211/key.h
net/mac80211/main.c
net/mac80211/mlme.c
net/mac80211/offchannel.c
net/mac80211/pm.c
net/mac80211/rate.c
net/mac80211/rc80211_pid_debugfs.c
net/mac80211/rx.c
net/mac80211/scan.c
net/mac80211/sta_info.c
net/mac80211/sta_info.h
net/mac80211/status.c
net/mac80211/tx.c
net/mac80211/util.c
net/mac80211/wep.c
net/mac80211/work.c
net/mac80211/wpa.c
net/netfilter/ipvs/ip_vs_core.c
net/netfilter/ipvs/ip_vs_ctl.c
net/netfilter/ipvs/ip_vs_sched.c
net/netfilter/xt_hashlimit.c
net/packet/af_packet.c
net/phonet/pep.c
net/phonet/pn_dev.c
net/phonet/socket.c
net/rds/af_rds.c
net/rds/bind.c
net/rds/cong.c
net/rds/connection.c
net/rds/ib.c
net/rds/ib.h
net/rds/ib_cm.c
net/rds/ib_rdma.c
net/rds/ib_recv.c
net/rds/ib_send.c
net/rds/ib_stats.c
net/rds/ib_sysctl.c
net/rds/info.c
net/rds/iw.c
net/rds/iw.h
net/rds/iw_cm.c
net/rds/iw_rdma.c
net/rds/iw_recv.c
net/rds/iw_send.c
net/rds/iw_sysctl.c
net/rds/loop.c
net/rds/message.c
net/rds/page.c
net/rds/rdma.c
net/rds/rdma.h [deleted file]
net/rds/rdma_transport.c
net/rds/rds.h
net/rds/recv.c
net/rds/send.c
net/rds/stats.c
net/rds/sysctl.c
net/rds/tcp.c
net/rds/tcp.h
net/rds/tcp_connect.c
net/rds/tcp_listen.c
net/rds/tcp_recv.c
net/rds/tcp_send.c
net/rds/threads.c
net/rds/transport.c
net/rds/xlist.h [new file with mode: 0644]
net/sched/Kconfig
net/sched/Makefile
net/sched/act_csum.c [new file with mode: 0644]
net/sched/cls_flow.c
net/sched/em_meta.c
net/sched/sch_api.c
net/sched/sch_sfq.c
net/sctp/associola.c
net/sctp/chunk.c
net/sctp/inqueue.c
net/sctp/ipv6.c
net/sctp/objcnt.c
net/sctp/output.c
net/sctp/outqueue.c
net/sctp/probe.c
net/sctp/protocol.c
net/sctp/sm_make_chunk.c
net/sctp/sm_sideeffect.c
net/sctp/sm_statefuns.c
net/sctp/sm_statetable.c
net/sctp/socket.c
net/sctp/transport.c
net/socket.c
net/tipc/bcast.c
net/tipc/core.c
net/tipc/discover.c
net/tipc/eth_media.c
net/tipc/link.c
net/tipc/name_table.c
net/tipc/net.c
net/tipc/node.c
net/tipc/node.h
net/tipc/port.c
net/tipc/socket.c
net/unix/af_unix.c
net/wireless/core.c
net/wireless/core.h
net/wireless/mlme.c
net/wireless/nl80211.c
net/wireless/nl80211.h
net/wireless/reg.c
net/wireless/sysfs.c
net/wireless/util.c
net/wireless/wext-core.c
net/wireless/wext-sme.c

diff --git a/Documentation/DocBook/80211.tmpl b/Documentation/DocBook/80211.tmpl
new file mode 100644 (file)
index 0000000..19a1210
--- /dev/null
@@ -0,0 +1,495 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE set PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+       "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
+<set>
+  <setinfo>
+    <title>The 802.11 subsystems &ndash; for kernel developers</title>
+    <subtitle>
+      Explaining wireless 802.11 networking in the Linux kernel
+    </subtitle>
+
+    <copyright>
+      <year>2007-2009</year>
+      <holder>Johannes Berg</holder>
+    </copyright>
+
+    <authorgroup>
+      <author>
+        <firstname>Johannes</firstname>
+        <surname>Berg</surname>
+        <affiliation>
+          <address><email>johannes@sipsolutions.net</email></address>
+        </affiliation>
+      </author>
+    </authorgroup>
+
+    <legalnotice>
+      <para>
+        This documentation 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.
+      </para>
+      <para>
+        This documentation 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.
+      </para>
+      <para>
+        You should have received a copy of the GNU General Public
+        License along with this documentation; if not, write to the Free
+        Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+        MA 02111-1307 USA
+      </para>
+      <para>
+        For more details see the file COPYING in the source
+        distribution of Linux.
+      </para>
+    </legalnotice>
+
+    <abstract>
+      <para>
+        These books attempt to give a description of the
+        various subsystems that play a role in 802.11 wireless
+        networking in Linux. Since these books are for kernel
+        developers they attempts to document the structures
+        and functions used in the kernel as well as giving a
+        higher-level overview.
+      </para>
+      <para>
+       The reader is expected to be familiar with the 802.11
+       standard as published by the IEEE in 802.11-2007 (or
+       possibly later versions). References to this standard
+       will be given as "802.11-2007 8.1.5".
+      </para>
+    </abstract>
+  </setinfo>
+  <book id="cfg80211-developers-guide">
+    <bookinfo>
+      <title>The cfg80211 subsystem</title>
+
+      <abstract>
+!Pinclude/net/cfg80211.h Introduction
+      </abstract>
+    </bookinfo>
+      <chapter>
+      <title>Device registration</title>
+!Pinclude/net/cfg80211.h Device registration
+!Finclude/net/cfg80211.h ieee80211_band
+!Finclude/net/cfg80211.h ieee80211_channel_flags
+!Finclude/net/cfg80211.h ieee80211_channel
+!Finclude/net/cfg80211.h ieee80211_rate_flags
+!Finclude/net/cfg80211.h ieee80211_rate
+!Finclude/net/cfg80211.h ieee80211_sta_ht_cap
+!Finclude/net/cfg80211.h ieee80211_supported_band
+!Finclude/net/cfg80211.h cfg80211_signal_type
+!Finclude/net/cfg80211.h wiphy_params_flags
+!Finclude/net/cfg80211.h wiphy_flags
+!Finclude/net/cfg80211.h wiphy
+!Finclude/net/cfg80211.h wireless_dev
+!Finclude/net/cfg80211.h wiphy_new
+!Finclude/net/cfg80211.h wiphy_register
+!Finclude/net/cfg80211.h wiphy_unregister
+!Finclude/net/cfg80211.h wiphy_free
+
+!Finclude/net/cfg80211.h wiphy_name
+!Finclude/net/cfg80211.h wiphy_dev
+!Finclude/net/cfg80211.h wiphy_priv
+!Finclude/net/cfg80211.h priv_to_wiphy
+!Finclude/net/cfg80211.h set_wiphy_dev
+!Finclude/net/cfg80211.h wdev_priv
+      </chapter>
+      <chapter>
+      <title>Actions and configuration</title>
+!Pinclude/net/cfg80211.h Actions and configuration
+!Finclude/net/cfg80211.h cfg80211_ops
+!Finclude/net/cfg80211.h vif_params
+!Finclude/net/cfg80211.h key_params
+!Finclude/net/cfg80211.h survey_info_flags
+!Finclude/net/cfg80211.h survey_info
+!Finclude/net/cfg80211.h beacon_parameters
+!Finclude/net/cfg80211.h plink_actions
+!Finclude/net/cfg80211.h station_parameters
+!Finclude/net/cfg80211.h station_info_flags
+!Finclude/net/cfg80211.h rate_info_flags
+!Finclude/net/cfg80211.h rate_info
+!Finclude/net/cfg80211.h station_info
+!Finclude/net/cfg80211.h monitor_flags
+!Finclude/net/cfg80211.h mpath_info_flags
+!Finclude/net/cfg80211.h mpath_info
+!Finclude/net/cfg80211.h bss_parameters
+!Finclude/net/cfg80211.h ieee80211_txq_params
+!Finclude/net/cfg80211.h cfg80211_crypto_settings
+!Finclude/net/cfg80211.h cfg80211_auth_request
+!Finclude/net/cfg80211.h cfg80211_assoc_request
+!Finclude/net/cfg80211.h cfg80211_deauth_request
+!Finclude/net/cfg80211.h cfg80211_disassoc_request
+!Finclude/net/cfg80211.h cfg80211_ibss_params
+!Finclude/net/cfg80211.h cfg80211_connect_params
+!Finclude/net/cfg80211.h cfg80211_pmksa
+!Finclude/net/cfg80211.h cfg80211_send_rx_auth
+!Finclude/net/cfg80211.h cfg80211_send_auth_timeout
+!Finclude/net/cfg80211.h __cfg80211_auth_canceled
+!Finclude/net/cfg80211.h cfg80211_send_rx_assoc
+!Finclude/net/cfg80211.h cfg80211_send_assoc_timeout
+!Finclude/net/cfg80211.h cfg80211_send_deauth
+!Finclude/net/cfg80211.h __cfg80211_send_deauth
+!Finclude/net/cfg80211.h cfg80211_send_disassoc
+!Finclude/net/cfg80211.h __cfg80211_send_disassoc
+!Finclude/net/cfg80211.h cfg80211_ibss_joined
+!Finclude/net/cfg80211.h cfg80211_connect_result
+!Finclude/net/cfg80211.h cfg80211_roamed
+!Finclude/net/cfg80211.h cfg80211_disconnected
+!Finclude/net/cfg80211.h cfg80211_ready_on_channel
+!Finclude/net/cfg80211.h cfg80211_remain_on_channel_expired
+!Finclude/net/cfg80211.h cfg80211_new_sta
+!Finclude/net/cfg80211.h cfg80211_rx_mgmt
+!Finclude/net/cfg80211.h cfg80211_mgmt_tx_status
+!Finclude/net/cfg80211.h cfg80211_cqm_rssi_notify
+!Finclude/net/cfg80211.h cfg80211_michael_mic_failure
+      </chapter>
+      <chapter>
+      <title>Scanning and BSS list handling</title>
+!Pinclude/net/cfg80211.h Scanning and BSS list handling
+!Finclude/net/cfg80211.h cfg80211_ssid
+!Finclude/net/cfg80211.h cfg80211_scan_request
+!Finclude/net/cfg80211.h cfg80211_scan_done
+!Finclude/net/cfg80211.h cfg80211_bss
+!Finclude/net/cfg80211.h cfg80211_inform_bss_frame
+!Finclude/net/cfg80211.h cfg80211_inform_bss
+!Finclude/net/cfg80211.h cfg80211_unlink_bss
+!Finclude/net/cfg80211.h cfg80211_find_ie
+!Finclude/net/cfg80211.h ieee80211_bss_get_ie
+      </chapter>
+      <chapter>
+      <title>Utility functions</title>
+!Pinclude/net/cfg80211.h Utility functions
+!Finclude/net/cfg80211.h ieee80211_channel_to_frequency
+!Finclude/net/cfg80211.h ieee80211_frequency_to_channel
+!Finclude/net/cfg80211.h ieee80211_get_channel
+!Finclude/net/cfg80211.h ieee80211_get_response_rate
+!Finclude/net/cfg80211.h ieee80211_hdrlen
+!Finclude/net/cfg80211.h ieee80211_get_hdrlen_from_skb
+!Finclude/net/cfg80211.h ieee80211_radiotap_iterator
+      </chapter>
+      <chapter>
+      <title>Data path helpers</title>
+!Pinclude/net/cfg80211.h Data path helpers
+!Finclude/net/cfg80211.h ieee80211_data_to_8023
+!Finclude/net/cfg80211.h ieee80211_data_from_8023
+!Finclude/net/cfg80211.h ieee80211_amsdu_to_8023s
+!Finclude/net/cfg80211.h cfg80211_classify8021d
+      </chapter>
+      <chapter>
+      <title>Regulatory enforcement infrastructure</title>
+!Pinclude/net/cfg80211.h Regulatory enforcement infrastructure
+!Finclude/net/cfg80211.h regulatory_hint
+!Finclude/net/cfg80211.h wiphy_apply_custom_regulatory
+!Finclude/net/cfg80211.h freq_reg_info
+      </chapter>
+      <chapter>
+      <title>RFkill integration</title>
+!Pinclude/net/cfg80211.h RFkill integration
+!Finclude/net/cfg80211.h wiphy_rfkill_set_hw_state
+!Finclude/net/cfg80211.h wiphy_rfkill_start_polling
+!Finclude/net/cfg80211.h wiphy_rfkill_stop_polling
+      </chapter>
+      <chapter>
+      <title>Test mode</title>
+!Pinclude/net/cfg80211.h Test mode
+!Finclude/net/cfg80211.h cfg80211_testmode_alloc_reply_skb
+!Finclude/net/cfg80211.h cfg80211_testmode_reply
+!Finclude/net/cfg80211.h cfg80211_testmode_alloc_event_skb
+!Finclude/net/cfg80211.h cfg80211_testmode_event
+      </chapter>
+  </book>
+  <book id="mac80211-developers-guide">
+    <bookinfo>
+      <title>The mac80211 subsystem</title>
+      <abstract>
+!Pinclude/net/mac80211.h Introduction
+!Pinclude/net/mac80211.h Warning
+      </abstract>
+    </bookinfo>
+
+    <toc></toc>
+
+  <!--
+  Generally, this document shall be ordered by increasing complexity.
+  It is important to note that readers should be able to read only
+  the first few sections to get a working driver and only advanced
+  usage should require reading the full document.
+  -->
+
+    <part>
+      <title>The basic mac80211 driver interface</title>
+      <partintro>
+        <para>
+          You should read and understand the information contained
+          within this part of the book while implementing a driver.
+          In some chapters, advanced usage is noted, that may be
+          skipped at first.
+        </para>
+        <para>
+          This part of the book only covers station and monitor mode
+          functionality, additional information required to implement
+          the other modes is covered in the second part of the book.
+        </para>
+      </partintro>
+
+      <chapter id="basics">
+        <title>Basic hardware handling</title>
+        <para>TBD</para>
+        <para>
+          This chapter shall contain information on getting a hw
+          struct allocated and registered with mac80211.
+        </para>
+        <para>
+          Since it is required to allocate rates/modes before registering
+          a hw struct, this chapter shall also contain information on setting
+          up the rate/mode structs.
+        </para>
+        <para>
+          Additionally, some discussion about the callbacks and
+          the general programming model should be in here, including
+          the definition of ieee80211_ops which will be referred to
+          a lot.
+        </para>
+        <para>
+          Finally, a discussion of hardware capabilities should be done
+          with references to other parts of the book.
+        </para>
+  <!-- intentionally multiple !F lines to get proper order -->
+!Finclude/net/mac80211.h ieee80211_hw
+!Finclude/net/mac80211.h ieee80211_hw_flags
+!Finclude/net/mac80211.h SET_IEEE80211_DEV
+!Finclude/net/mac80211.h SET_IEEE80211_PERM_ADDR
+!Finclude/net/mac80211.h ieee80211_ops
+!Finclude/net/mac80211.h ieee80211_alloc_hw
+!Finclude/net/mac80211.h ieee80211_register_hw
+!Finclude/net/mac80211.h ieee80211_get_tx_led_name
+!Finclude/net/mac80211.h ieee80211_get_rx_led_name
+!Finclude/net/mac80211.h ieee80211_get_assoc_led_name
+!Finclude/net/mac80211.h ieee80211_get_radio_led_name
+!Finclude/net/mac80211.h ieee80211_unregister_hw
+!Finclude/net/mac80211.h ieee80211_free_hw
+      </chapter>
+
+      <chapter id="phy-handling">
+        <title>PHY configuration</title>
+        <para>TBD</para>
+        <para>
+          This chapter should describe PHY handling including
+          start/stop callbacks and the various structures used.
+        </para>
+!Finclude/net/mac80211.h ieee80211_conf
+!Finclude/net/mac80211.h ieee80211_conf_flags
+      </chapter>
+
+      <chapter id="iface-handling">
+        <title>Virtual interfaces</title>
+        <para>TBD</para>
+        <para>
+          This chapter should describe virtual interface basics
+          that are relevant to the driver (VLANs, MGMT etc are not.)
+          It should explain the use of the add_iface/remove_iface
+          callbacks as well as the interface configuration callbacks.
+        </para>
+        <para>Things related to AP mode should be discussed there.</para>
+        <para>
+          Things related to supporting multiple interfaces should be
+          in the appropriate chapter, a BIG FAT note should be here about
+          this though and the recommendation to allow only a single
+          interface in STA mode at first!
+        </para>
+!Finclude/net/mac80211.h ieee80211_vif
+      </chapter>
+
+      <chapter id="rx-tx">
+        <title>Receive and transmit processing</title>
+        <sect1>
+          <title>what should be here</title>
+          <para>TBD</para>
+          <para>
+            This should describe the receive and transmit
+            paths in mac80211/the drivers as well as
+            transmit status handling.
+          </para>
+        </sect1>
+        <sect1>
+          <title>Frame format</title>
+!Pinclude/net/mac80211.h Frame format
+        </sect1>
+        <sect1>
+          <title>Packet alignment</title>
+!Pnet/mac80211/rx.c Packet alignment
+        </sect1>
+        <sect1>
+          <title>Calling into mac80211 from interrupts</title>
+!Pinclude/net/mac80211.h Calling mac80211 from interrupts
+        </sect1>
+        <sect1>
+          <title>functions/definitions</title>
+!Finclude/net/mac80211.h ieee80211_rx_status
+!Finclude/net/mac80211.h mac80211_rx_flags
+!Finclude/net/mac80211.h ieee80211_tx_info
+!Finclude/net/mac80211.h ieee80211_rx
+!Finclude/net/mac80211.h ieee80211_rx_irqsafe
+!Finclude/net/mac80211.h ieee80211_tx_status
+!Finclude/net/mac80211.h ieee80211_tx_status_irqsafe
+!Finclude/net/mac80211.h ieee80211_rts_get
+!Finclude/net/mac80211.h ieee80211_rts_duration
+!Finclude/net/mac80211.h ieee80211_ctstoself_get
+!Finclude/net/mac80211.h ieee80211_ctstoself_duration
+!Finclude/net/mac80211.h ieee80211_generic_frame_duration
+!Finclude/net/mac80211.h ieee80211_wake_queue
+!Finclude/net/mac80211.h ieee80211_stop_queue
+!Finclude/net/mac80211.h ieee80211_wake_queues
+!Finclude/net/mac80211.h ieee80211_stop_queues
+        </sect1>
+      </chapter>
+
+      <chapter id="filters">
+        <title>Frame filtering</title>
+!Pinclude/net/mac80211.h Frame filtering
+!Finclude/net/mac80211.h ieee80211_filter_flags
+      </chapter>
+    </part>
+
+    <part id="advanced">
+      <title>Advanced driver interface</title>
+      <partintro>
+        <para>
+         Information contained within this part of the book is
+         of interest only for advanced interaction of mac80211
+         with drivers to exploit more hardware capabilities and
+         improve performance.
+        </para>
+      </partintro>
+
+      <chapter id="hardware-crypto-offload">
+        <title>Hardware crypto acceleration</title>
+!Pinclude/net/mac80211.h Hardware crypto acceleration
+  <!-- intentionally multiple !F lines to get proper order -->
+!Finclude/net/mac80211.h set_key_cmd
+!Finclude/net/mac80211.h ieee80211_key_conf
+!Finclude/net/mac80211.h ieee80211_key_flags
+      </chapter>
+
+      <chapter id="powersave">
+        <title>Powersave support</title>
+!Pinclude/net/mac80211.h Powersave support
+      </chapter>
+
+      <chapter id="beacon-filter">
+        <title>Beacon filter support</title>
+!Pinclude/net/mac80211.h Beacon filter support
+!Finclude/net/mac80211.h ieee80211_beacon_loss
+      </chapter>
+
+      <chapter id="qos">
+        <title>Multiple queues and QoS support</title>
+        <para>TBD</para>
+!Finclude/net/mac80211.h ieee80211_tx_queue_params
+      </chapter>
+
+      <chapter id="AP">
+        <title>Access point mode support</title>
+        <para>TBD</para>
+        <para>Some parts of the if_conf should be discussed here instead</para>
+        <para>
+          Insert notes about VLAN interfaces with hw crypto here or
+          in the hw crypto chapter.
+        </para>
+!Finclude/net/mac80211.h ieee80211_get_buffered_bc
+!Finclude/net/mac80211.h ieee80211_beacon_get
+      </chapter>
+
+      <chapter id="multi-iface">
+        <title>Supporting multiple virtual interfaces</title>
+        <para>TBD</para>
+        <para>
+          Note: WDS with identical MAC address should almost always be OK
+        </para>
+        <para>
+          Insert notes about having multiple virtual interfaces with
+          different MAC addresses here, note which configurations are
+          supported by mac80211, add notes about supporting hw crypto
+          with it.
+        </para>
+      </chapter>
+
+      <chapter id="hardware-scan-offload">
+        <title>Hardware scan offload</title>
+        <para>TBD</para>
+!Finclude/net/mac80211.h ieee80211_scan_completed
+      </chapter>
+    </part>
+
+    <part id="rate-control">
+      <title>Rate control interface</title>
+      <partintro>
+        <para>TBD</para>
+        <para>
+         This part of the book describes the rate control algorithm
+         interface and how it relates to mac80211 and drivers.
+        </para>
+      </partintro>
+      <chapter id="dummy">
+        <title>dummy chapter</title>
+        <para>TBD</para>
+      </chapter>
+    </part>
+
+    <part id="internal">
+      <title>Internals</title>
+      <partintro>
+        <para>TBD</para>
+        <para>
+         This part of the book describes mac80211 internals.
+        </para>
+      </partintro>
+
+      <chapter id="key-handling">
+        <title>Key handling</title>
+        <sect1>
+          <title>Key handling basics</title>
+!Pnet/mac80211/key.c Key handling basics
+        </sect1>
+        <sect1>
+          <title>MORE TBD</title>
+          <para>TBD</para>
+        </sect1>
+      </chapter>
+
+      <chapter id="rx-processing">
+        <title>Receive processing</title>
+        <para>TBD</para>
+      </chapter>
+
+      <chapter id="tx-processing">
+        <title>Transmit processing</title>
+        <para>TBD</para>
+      </chapter>
+
+      <chapter id="sta-info">
+        <title>Station info handling</title>
+        <sect1>
+          <title>Programming information</title>
+!Fnet/mac80211/sta_info.h sta_info
+!Fnet/mac80211/sta_info.h ieee80211_sta_info_flags
+        </sect1>
+        <sect1>
+          <title>STA information lifetime rules</title>
+!Pnet/mac80211/sta_info.c STA information lifetime rules
+        </sect1>
+      </chapter>
+
+      <chapter id="synchronisation">
+        <title>Synchronisation</title>
+        <para>TBD</para>
+        <para>Locking, lots of RCU</para>
+      </chapter>
+    </part>
+  </book>
+</set>
index 34929f24c2846010bded3b426f20cdb54d4abc57..8b6e00a71034cbd7151ace7adbe3558f3cbb99bd 100644 (file)
@@ -12,7 +12,7 @@ DOCBOOKS := z8530book.xml mcabook.xml device-drivers.xml \
            kernel-api.xml filesystems.xml lsm.xml usb.xml kgdb.xml \
            gadget.xml libata.xml mtdnand.xml librs.xml rapidio.xml \
            genericirq.xml s390-drivers.xml uio-howto.xml scsi.xml \
-           mac80211.xml debugobjects.xml sh.xml regulator.xml \
+           80211.xml debugobjects.xml sh.xml regulator.xml \
            alsa-driver-api.xml writing-an-alsa-driver.xml \
            tracepoint.xml media.xml drm.xml
 
diff --git a/Documentation/DocBook/mac80211.tmpl b/Documentation/DocBook/mac80211.tmpl
deleted file mode 100644 (file)
index affb15a..0000000
+++ /dev/null
@@ -1,337 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
-       "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
-
-<book id="mac80211-developers-guide">
-  <bookinfo>
-    <title>The mac80211 subsystem for kernel developers</title>
-
-    <authorgroup>
-      <author>
-        <firstname>Johannes</firstname>
-        <surname>Berg</surname>
-        <affiliation>
-          <address><email>johannes@sipsolutions.net</email></address>
-        </affiliation>
-      </author>
-    </authorgroup>
-
-    <copyright>
-      <year>2007-2009</year>
-      <holder>Johannes Berg</holder>
-    </copyright>
-
-    <legalnotice>
-      <para>
-        This documentation 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.
-      </para>
-
-      <para>
-        This documentation 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.
-      </para>
-
-      <para>
-        You should have received a copy of the GNU General Public
-        License along with this documentation; if not, write to the Free
-        Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
-        MA 02111-1307 USA
-      </para>
-
-      <para>
-        For more details see the file COPYING in the source
-        distribution of Linux.
-      </para>
-    </legalnotice>
-
-    <abstract>
-!Pinclude/net/mac80211.h Introduction
-!Pinclude/net/mac80211.h Warning
-    </abstract>
-  </bookinfo>
-
-  <toc></toc>
-
-<!--
-Generally, this document shall be ordered by increasing complexity.
-It is important to note that readers should be able to read only
-the first few sections to get a working driver and only advanced
-usage should require reading the full document.
--->
-
-  <part>
-    <title>The basic mac80211 driver interface</title>
-    <partintro>
-      <para>
-        You should read and understand the information contained
-        within this part of the book while implementing a driver.
-        In some chapters, advanced usage is noted, that may be
-        skipped at first.
-      </para>
-      <para>
-        This part of the book only covers station and monitor mode
-        functionality, additional information required to implement
-        the other modes is covered in the second part of the book.
-      </para>
-    </partintro>
-
-    <chapter id="basics">
-      <title>Basic hardware handling</title>
-      <para>TBD</para>
-      <para>
-        This chapter shall contain information on getting a hw
-        struct allocated and registered with mac80211.
-      </para>
-      <para>
-        Since it is required to allocate rates/modes before registering
-        a hw struct, this chapter shall also contain information on setting
-        up the rate/mode structs.
-      </para>
-      <para>
-        Additionally, some discussion about the callbacks and
-        the general programming model should be in here, including
-        the definition of ieee80211_ops which will be referred to
-        a lot.
-      </para>
-      <para>
-        Finally, a discussion of hardware capabilities should be done
-        with references to other parts of the book.
-      </para>
-<!-- intentionally multiple !F lines to get proper order -->
-!Finclude/net/mac80211.h ieee80211_hw
-!Finclude/net/mac80211.h ieee80211_hw_flags
-!Finclude/net/mac80211.h SET_IEEE80211_DEV
-!Finclude/net/mac80211.h SET_IEEE80211_PERM_ADDR
-!Finclude/net/mac80211.h ieee80211_ops
-!Finclude/net/mac80211.h ieee80211_alloc_hw
-!Finclude/net/mac80211.h ieee80211_register_hw
-!Finclude/net/mac80211.h ieee80211_get_tx_led_name
-!Finclude/net/mac80211.h ieee80211_get_rx_led_name
-!Finclude/net/mac80211.h ieee80211_get_assoc_led_name
-!Finclude/net/mac80211.h ieee80211_get_radio_led_name
-!Finclude/net/mac80211.h ieee80211_unregister_hw
-!Finclude/net/mac80211.h ieee80211_free_hw
-    </chapter>
-
-    <chapter id="phy-handling">
-      <title>PHY configuration</title>
-      <para>TBD</para>
-      <para>
-        This chapter should describe PHY handling including
-        start/stop callbacks and the various structures used.
-      </para>
-!Finclude/net/mac80211.h ieee80211_conf
-!Finclude/net/mac80211.h ieee80211_conf_flags
-    </chapter>
-
-    <chapter id="iface-handling">
-      <title>Virtual interfaces</title>
-      <para>TBD</para>
-      <para>
-        This chapter should describe virtual interface basics
-        that are relevant to the driver (VLANs, MGMT etc are not.)
-        It should explain the use of the add_iface/remove_iface
-        callbacks as well as the interface configuration callbacks.
-      </para>
-      <para>Things related to AP mode should be discussed there.</para>
-      <para>
-        Things related to supporting multiple interfaces should be
-        in the appropriate chapter, a BIG FAT note should be here about
-        this though and the recommendation to allow only a single
-        interface in STA mode at first!
-      </para>
-!Finclude/net/mac80211.h ieee80211_vif
-    </chapter>
-
-    <chapter id="rx-tx">
-      <title>Receive and transmit processing</title>
-      <sect1>
-        <title>what should be here</title>
-        <para>TBD</para>
-        <para>
-          This should describe the receive and transmit
-          paths in mac80211/the drivers as well as
-          transmit status handling.
-        </para>
-      </sect1>
-      <sect1>
-        <title>Frame format</title>
-!Pinclude/net/mac80211.h Frame format
-      </sect1>
-      <sect1>
-        <title>Packet alignment</title>
-!Pnet/mac80211/rx.c Packet alignment
-      </sect1>
-      <sect1>
-        <title>Calling into mac80211 from interrupts</title>
-!Pinclude/net/mac80211.h Calling mac80211 from interrupts
-      </sect1>
-      <sect1>
-        <title>functions/definitions</title>
-!Finclude/net/mac80211.h ieee80211_rx_status
-!Finclude/net/mac80211.h mac80211_rx_flags
-!Finclude/net/mac80211.h ieee80211_tx_info
-!Finclude/net/mac80211.h ieee80211_rx
-!Finclude/net/mac80211.h ieee80211_rx_irqsafe
-!Finclude/net/mac80211.h ieee80211_tx_status
-!Finclude/net/mac80211.h ieee80211_tx_status_irqsafe
-!Finclude/net/mac80211.h ieee80211_rts_get
-!Finclude/net/mac80211.h ieee80211_rts_duration
-!Finclude/net/mac80211.h ieee80211_ctstoself_get
-!Finclude/net/mac80211.h ieee80211_ctstoself_duration
-!Finclude/net/mac80211.h ieee80211_generic_frame_duration
-!Finclude/net/mac80211.h ieee80211_wake_queue
-!Finclude/net/mac80211.h ieee80211_stop_queue
-!Finclude/net/mac80211.h ieee80211_wake_queues
-!Finclude/net/mac80211.h ieee80211_stop_queues
-      </sect1>
-    </chapter>
-
-    <chapter id="filters">
-      <title>Frame filtering</title>
-!Pinclude/net/mac80211.h Frame filtering
-!Finclude/net/mac80211.h ieee80211_filter_flags
-    </chapter>
-  </part>
-
-  <part id="advanced">
-    <title>Advanced driver interface</title>
-    <partintro>
-      <para>
-       Information contained within this part of the book is
-       of interest only for advanced interaction of mac80211
-       with drivers to exploit more hardware capabilities and
-       improve performance.
-      </para>
-    </partintro>
-
-    <chapter id="hardware-crypto-offload">
-      <title>Hardware crypto acceleration</title>
-!Pinclude/net/mac80211.h Hardware crypto acceleration
-<!-- intentionally multiple !F lines to get proper order -->
-!Finclude/net/mac80211.h set_key_cmd
-!Finclude/net/mac80211.h ieee80211_key_conf
-!Finclude/net/mac80211.h ieee80211_key_alg
-!Finclude/net/mac80211.h ieee80211_key_flags
-    </chapter>
-
-    <chapter id="powersave">
-      <title>Powersave support</title>
-!Pinclude/net/mac80211.h Powersave support
-    </chapter>
-
-    <chapter id="beacon-filter">
-      <title>Beacon filter support</title>
-!Pinclude/net/mac80211.h Beacon filter support
-!Finclude/net/mac80211.h ieee80211_beacon_loss
-    </chapter>
-
-    <chapter id="qos">
-      <title>Multiple queues and QoS support</title>
-      <para>TBD</para>
-!Finclude/net/mac80211.h ieee80211_tx_queue_params
-    </chapter>
-
-    <chapter id="AP">
-      <title>Access point mode support</title>
-      <para>TBD</para>
-      <para>Some parts of the if_conf should be discussed here instead</para>
-      <para>
-        Insert notes about VLAN interfaces with hw crypto here or
-        in the hw crypto chapter.
-      </para>
-!Finclude/net/mac80211.h ieee80211_get_buffered_bc
-!Finclude/net/mac80211.h ieee80211_beacon_get
-    </chapter>
-
-    <chapter id="multi-iface">
-      <title>Supporting multiple virtual interfaces</title>
-      <para>TBD</para>
-      <para>
-        Note: WDS with identical MAC address should almost always be OK
-      </para>
-      <para>
-        Insert notes about having multiple virtual interfaces with
-        different MAC addresses here, note which configurations are
-        supported by mac80211, add notes about supporting hw crypto
-        with it.
-      </para>
-    </chapter>
-
-    <chapter id="hardware-scan-offload">
-      <title>Hardware scan offload</title>
-      <para>TBD</para>
-!Finclude/net/mac80211.h ieee80211_scan_completed
-    </chapter>
-  </part>
-
-  <part id="rate-control">
-    <title>Rate control interface</title>
-    <partintro>
-      <para>TBD</para>
-      <para>
-       This part of the book describes the rate control algorithm
-       interface and how it relates to mac80211 and drivers.
-      </para>
-    </partintro>
-    <chapter id="dummy">
-      <title>dummy chapter</title>
-      <para>TBD</para>
-    </chapter>
-  </part>
-
-  <part id="internal">
-    <title>Internals</title>
-    <partintro>
-      <para>TBD</para>
-      <para>
-       This part of the book describes mac80211 internals.
-      </para>
-    </partintro>
-
-    <chapter id="key-handling">
-      <title>Key handling</title>
-      <sect1>
-        <title>Key handling basics</title>
-!Pnet/mac80211/key.c Key handling basics
-      </sect1>
-      <sect1>
-        <title>MORE TBD</title>
-        <para>TBD</para>
-      </sect1>
-    </chapter>
-
-    <chapter id="rx-processing">
-      <title>Receive processing</title>
-      <para>TBD</para>
-    </chapter>
-
-    <chapter id="tx-processing">
-      <title>Transmit processing</title>
-      <para>TBD</para>
-    </chapter>
-
-    <chapter id="sta-info">
-      <title>Station info handling</title>
-      <sect1>
-        <title>Programming information</title>
-!Fnet/mac80211/sta_info.h sta_info
-!Fnet/mac80211/sta_info.h ieee80211_sta_info_flags
-      </sect1>
-      <sect1>
-        <title>STA information lifetime rules</title>
-!Pnet/mac80211/sta_info.c STA information lifetime rules
-      </sect1>
-    </chapter>
-
-    <chapter id="synchronisation">
-      <title>Synchronisation</title>
-      <para>TBD</para>
-      <para>Locking, lots of RCU</para>
-    </chapter>
-  </part>
-</book>
index a62fdf7a6bffa2cfe2212a4b64d71b4dd9903531..271d524a4c8d53dc4fab4aa91fee28ea89fe4f62 100644 (file)
@@ -1,18 +1,20 @@
 DCCP protocol
-============
+=============
 
 
 Contents
 ========
-
 - Introduction
 - Missing features
 - Socket options
+- Sysctl variables
+- IOCTLs
+- Other tunables
 - Notes
 
+
 Introduction
 ============
-
 Datagram Congestion Control Protocol (DCCP) is an unreliable, connection
 oriented protocol designed to solve issues present in UDP and TCP, particularly
 for real-time and multimedia (streaming) traffic.
@@ -29,9 +31,9 @@ It has a base protocol and pluggable congestion control IDs (CCIDs).
 DCCP is a Proposed Standard (RFC 2026), and the homepage for DCCP as a protocol
 is at http://www.ietf.org/html.charters/dccp-charter.html
 
+
 Missing features
 ================
-
 The Linux DCCP implementation does not currently support all the features that are
 specified in RFCs 4340...42.
 
@@ -45,7 +47,6 @@ http://linux-net.osdl.org/index.php/DCCP_Testing#Experimental_DCCP_source_tree
 
 Socket options
 ==============
-
 DCCP_SOCKOPT_SERVICE sets the service. The specification mandates use of
 service codes (RFC 4340, sec. 8.1.2); if this socket option is not set,
 the socket will fall back to 0 (which means that no meaningful service code
@@ -112,6 +113,7 @@ DCCP_SOCKOPT_CCID_TX_INFO
 On unidirectional connections it is useful to close the unused half-connection
 via shutdown (SHUT_WR or SHUT_RD): this will reduce per-packet processing costs.
 
+
 Sysctl variables
 ================
 Several DCCP default parameters can be managed by the following sysctls
@@ -155,15 +157,30 @@ sync_ratelimit = 125 ms
        sequence-invalid packets on the same socket (RFC 4340, 7.5.4). The unit
        of this parameter is milliseconds; a value of 0 disables rate-limiting.
 
+
 IOCTLS
 ======
 FIONREAD
        Works as in udp(7): returns in the `int' argument pointer the size of
        the next pending datagram in bytes, or 0 when no datagram is pending.
 
+
+Other tunables
+==============
+Per-route rto_min support
+       CCID-2 supports the RTAX_RTO_MIN per-route setting for the minimum value
+       of the RTO timer. This setting can be modified via the 'rto_min' option
+       of iproute2; for example:
+               > ip route change 10.0.0.0/24   rto_min 250j dev wlan0
+               > ip route add    10.0.0.254/32 rto_min 800j dev wlan0
+               > ip route show dev wlan0
+       CCID-3 also supports the rto_min setting: it is used to define the lower
+       bound for the expiry of the nofeedback timer. This can be useful on LANs
+       with very low RTTs (e.g., loopback, Gbit ethernet).
+
+
 Notes
 =====
-
 DCCP does not travel through NAT successfully at present on many boxes. This is
 because the checksum covers the pseudo-header as per TCP and UDP. Linux NAT
 support for DCCP has been added.
index f350c69b2bb4f807340416ffe7cf29cc8b02e662..c7165f4cb7927a152ec547caeecb393f5ad3c27e 100644 (file)
@@ -1014,6 +1014,12 @@ conf/interface/*:
 accept_ra - BOOLEAN
        Accept Router Advertisements; autoconfigure using them.
 
+       Possible values are:
+               0 Do not accept Router Advertisements.
+               1 Accept Router Advertisements if forwarding is disabled.
+               2 Overrule forwarding behaviour. Accept Router Advertisements
+                 even if forwarding is enabled.
+
        Functional default: enabled if local forwarding is disabled.
                            disabled if local forwarding is enabled.
 
@@ -1075,7 +1081,12 @@ forwarding - BOOLEAN
        Note: It is recommended to have the same setting on all
        interfaces; mixed router/host scenarios are rather uncommon.
 
-       FALSE:
+       Possible values are:
+               0 Forwarding disabled
+               1 Forwarding enabled
+               2 Forwarding enabled (Hybrid Mode)
+
+       FALSE (0):
 
        By default, Host behaviour is assumed.  This means:
 
@@ -1085,18 +1096,24 @@ forwarding - BOOLEAN
           Advertisements (and do autoconfiguration).
        4. If accept_redirects is TRUE (default), accept Redirects.
 
-       TRUE:
+       TRUE (1):
 
        If local forwarding is enabled, Router behaviour is assumed.
        This means exactly the reverse from the above:
 
        1. IsRouter flag is set in Neighbour Advertisements.
        2. Router Solicitations are not sent.
-       3. Router Advertisements are ignored.
+       3. Router Advertisements are ignored unless accept_ra is 2.
        4. Redirects are ignored.
 
-       Default: FALSE if global forwarding is disabled (default),
-                otherwise TRUE.
+       TRUE (2):
+
+       Hybrid mode. Same behaviour as TRUE, except for:
+
+       2. Router Solicitations are being sent when necessary.
+
+       Default: 0 (disabled) if global forwarding is disabled (default),
+                otherwise 1 (enabled).
 
 hop_limit - INTEGER
        Default Hop Limit to set.
index e8c8f4f06c67f104523ae9c4f9bafbf659d5e139..98097d8cb910ba9d42f25e7860bec06e61a89faa 100644 (file)
@@ -172,15 +172,19 @@ struct skb_shared_hwtstamps {
 };
 
 Time stamps for outgoing packets are to be generated as follows:
-- In hard_start_xmit(), check if skb_tx(skb)->hardware is set no-zero.
-  If yes, then the driver is expected to do hardware time stamping.
+- In hard_start_xmit(), check if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)
+  is set no-zero. If yes, then the driver is expected to do hardware time
+  stamping.
 - If this is possible for the skb and requested, then declare
-  that the driver is doing the time stamping by setting the field
-  skb_tx(skb)->in_progress non-zero. You might want to keep a pointer
-  to the associated skb for the next step and not free the skb. A driver
-  not supporting hardware time stamping doesn't do that. A driver must
-  never touch sk_buff::tstamp! It is used to store software generated
-  time stamps by the network subsystem.
+  that the driver is doing the time stamping by setting the flag
+  SKBTX_IN_PROGRESS in skb_shinfo(skb)->tx_flags , e.g. with
+
+      skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
+
+  You might want to keep a pointer to the associated skb for the next step
+  and not free the skb. A driver not supporting hardware time stamping doesn't
+  do that. A driver must never touch sk_buff::tstamp! It is used to store
+  software generated time stamps by the network subsystem.
 - As soon as the driver has sent the packet and/or obtained a
   hardware time stamp for it, it passes the time stamp back by
   calling skb_hwtstamp_tx() with the original skb, the raw
@@ -191,6 +195,6 @@ Time stamps for outgoing packets are to be generated as follows:
   this would occur at a later time in the processing pipeline than other
   software time stamping and therefore could lead to unexpected deltas
   between time stamps.
-- If the driver did not call set skb_tx(skb)->in_progress, then
+- If the driver did not set the SKBTX_IN_PROGRESS flag (see above), then
   dev_hard_start_xmit() checks whether software time stamping
   is wanted as fallback and potentially generates the time stamp.
index b5fb9bdcabb1e2df5f7516eb3d4547c3cd622a96..102352e6d61ddba67a4162423eca11f4e429dc9b 100644 (file)
@@ -1398,6 +1398,13 @@ L:       linux-scsi@vger.kernel.org
 S:     Supported
 F:     drivers/scsi/bfa/
 
+BROCADE BNA 10 GIGABIT ETHERNET DRIVER
+M:     Rasesh Mody <rmody@brocade.com>
+M:     Debashis Dutt <ddutt@brocade.com>
+L:     netdev@vger.kernel.org
+S:     Supported
+F:     drivers/net/bna/
+
 BSG (block layer generic sg v4 driver)
 M:     FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
 L:     linux-scsi@vger.kernel.org
@@ -2881,6 +2888,12 @@ M:       Brian King <brking@us.ibm.com>
 S:     Supported
 F:     drivers/scsi/ipr.*
 
+IBM Power Virtual Ethernet Device Driver
+M:     Santiago Leon <santil@linux.vnet.ibm.com>
+L:     netdev@vger.kernel.org
+S:     Supported
+F:     drivers/net/ibmveth.*
+
 IBM ServeRAID RAID DRIVER
 P:     Jack Hammer
 M:     Dave Jeffery <ipslinux@adaptec.com>
@@ -4328,13 +4341,12 @@ F:      Documentation/filesystems/dlmfs.txt
 F:     fs/ocfs2/
 
 ORINOCO DRIVER
-M:     Pavel Roskin <proski@gnu.org>
-M:     David Gibson <hermes@gibson.dropbear.id.au>
 L:     linux-wireless@vger.kernel.org
 L:     orinoco-users@lists.sourceforge.net
 L:     orinoco-devel@lists.sourceforge.net
+W:     http://linuxwireless.org/en/users/Drivers/orinoco
 W:     http://www.nongnu.org/orinoco/
-S:     Maintained
+S:     Orphan
 F:     drivers/net/wireless/orinoco/
 
 OSD LIBRARY and FILESYSTEM
@@ -6400,7 +6412,7 @@ S:        Maintained
 F:     drivers/input/misc/wistron_btns.c
 
 WL1251 WIRELESS DRIVER
-M:     Kalle Valo <kalle.valo@iki.fi>
+M:     Kalle Valo <kvalo@adurom.com>
 L:     linux-wireless@vger.kernel.org
 W:     http://wireless.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git
@@ -6415,6 +6427,7 @@ W:        http://wireless.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git
 S:     Maintained
 F:     drivers/net/wireless/wl12xx/wl1271*
+F:     include/linux/spi/wl12xx.h
 
 WL3501 WIRELESS PCMCIA CARD DRIVER
 M:     Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
@@ -6559,6 +6572,20 @@ M:       "Maciej W. Rozycki" <macro@linux-mips.org>
 S:     Maintained
 F:     drivers/serial/zs.*
 
+GRE DEMULTIPLEXER DRIVER
+M:     Dmitry Kozlov <xeb@mail.ru>
+L:     netdev@vger.kernel.org
+S:     Maintained
+F:     net/ipv4/gre.c
+F:     include/net/gre.h
+
+PPTP DRIVER
+M:     Dmitry Kozlov <xeb@mail.ru>
+L:     netdev@vger.kernel.org
+S:     Maintained
+F:     drivers/net/pptp.c
+W:     http://sourceforge.net/projects/accel-pptp
+
 THE REST
 M:     Linus Torvalds <torvalds@linux-foundation.org>
 L:     linux-kernel@vger.kernel.org
index 2ba6302762957a20dc30779ebe01a27060a97f63..46e96bc1f5a155ea988961b0078ecbdc854c973e 100644 (file)
@@ -360,6 +360,7 @@ struct qdio_initialize {
        unsigned int no_output_qs;
        qdio_handler_t *input_handler;
        qdio_handler_t *output_handler;
+       void (*queue_start_poll) (struct ccw_device *, int, unsigned long);
        unsigned long int_parm;
        void **input_sbal_addr_array;
        void **output_sbal_addr_array;
@@ -377,11 +378,13 @@ struct qdio_initialize {
 extern int qdio_allocate(struct qdio_initialize *);
 extern int qdio_establish(struct qdio_initialize *);
 extern int qdio_activate(struct ccw_device *);
-
-extern int do_QDIO(struct ccw_device *cdev, unsigned int callflags,
-                  int q_nr, unsigned int bufnr, unsigned int count);
-extern int qdio_shutdown(struct ccw_device*, int);
+extern int do_QDIO(struct ccw_device *, unsigned int, int, unsigned int,
+                  unsigned int);
+extern int qdio_start_irq(struct ccw_device *, int);
+extern int qdio_stop_irq(struct ccw_device *, int);
+extern int qdio_get_next_buffers(struct ccw_device *, int, int *, int *);
+extern int qdio_shutdown(struct ccw_device *, int);
 extern int qdio_free(struct ccw_device *);
-extern int qdio_get_ssqd_desc(struct ccw_device *dev, struct qdio_ssqd_desc*);
+extern int qdio_get_ssqd_desc(struct ccw_device *, struct qdio_ssqd_desc *);
 
 #endif /* __QDIO_H__ */
index 8717809787fb7af21069dd726e11abbdcff70ee5..5d86bb803e9493443659f49180b68c147066a166 100644 (file)
@@ -444,8 +444,8 @@ static inline void fs_kfree_skb (struct sk_buff * skb)
 #define ROUND_NEAREST 3
 /********** make rate (not quite as much fun as Horizon) **********/
 
-static unsigned int make_rate (unsigned int rate, int r,
-                              u16 * bits, unsigned int * actual) 
+static int make_rate(unsigned int rate, int r,
+                     u16 *bits, unsigned int *actual)
 {
        unsigned char exp = -1; /* hush gcc */
        unsigned int man = -1;  /* hush gcc */
index ee9ddeb53417c7da782d252f7d9e4f8113ee44b4..8b358d7d958fbc17aeb5b9be4b5b7983700732e0 100644 (file)
@@ -220,7 +220,7 @@ static u16 get_desc (IADEV *dev, struct ia_vcc *iavcc) {
   while (!desc_num || (dev->desc_tbl[desc_num -1]).timestamp) {
      dev->ffL.tcq_rd += 2;
      if (dev->ffL.tcq_rd > dev->ffL.tcq_ed) 
-     dev->ffL.tcq_rd = dev->ffL.tcq_st;
+       dev->ffL.tcq_rd = dev->ffL.tcq_st;
      if (dev->ffL.tcq_rd == dev->host_tcq_wr) 
         return 0xFFFF; 
      desc_num = *(u_short *)(dev->seg_ram + dev->ffL.tcq_rd);
index 33f8421c71cc05001c57bbf275b61679fded72eb..18fdd9703b483fbdaadbaec83cbbb956ffa669dd 100644 (file)
@@ -8,7 +8,6 @@
 
 #include <linux/bug.h>
 #include <linux/device.h>
-#include <linux/ethtool.h>
 #include <linux/firewire.h>
 #include <linux/firewire-constants.h>
 #include <linux/highmem.h>
@@ -1361,17 +1360,6 @@ static int fwnet_change_mtu(struct net_device *net, int new_mtu)
        return 0;
 }
 
-static void fwnet_get_drvinfo(struct net_device *net,
-                             struct ethtool_drvinfo *info)
-{
-       strcpy(info->driver, KBUILD_MODNAME);
-       strcpy(info->bus_info, "ieee1394");
-}
-
-static const struct ethtool_ops fwnet_ethtool_ops = {
-       .get_drvinfo = fwnet_get_drvinfo,
-};
-
 static const struct net_device_ops fwnet_netdev_ops = {
        .ndo_open       = fwnet_open,
        .ndo_stop       = fwnet_stop,
@@ -1390,7 +1378,6 @@ static void fwnet_init_dev(struct net_device *net)
        net->hard_header_len    = FWNET_HLEN;
        net->type               = ARPHRD_IEEE1394;
        net->tx_queue_len       = 10;
-       SET_ETHTOOL_OPS(net, &fwnet_ethtool_ops);
 }
 
 /* caller must hold fwnet_device_mutex */
index bc289e367e30ec06a815224914ef5036ea9d9d41..63403822330eced0a2593f98f5025d9d5d136dd8 100644 (file)
@@ -58,7 +58,6 @@
 #include <linux/tcp.h>
 #include <linux/skbuff.h>
 #include <linux/bitops.h>
-#include <linux/ethtool.h>
 #include <asm/uaccess.h>
 #include <asm/delay.h>
 #include <asm/unaligned.h>
@@ -173,8 +172,6 @@ static netdev_tx_t ether1394_tx(struct sk_buff *skb,
                                struct net_device *dev);
 static void ether1394_iso(struct hpsb_iso *iso);
 
-static const struct ethtool_ops ethtool_ops;
-
 static int ether1394_write(struct hpsb_host *host, int srcid, int destid,
                           quadlet_t *data, u64 addr, size_t len, u16 flags);
 static void ether1394_add_host(struct hpsb_host *host);
@@ -525,8 +522,6 @@ static void ether1394_init_dev(struct net_device *dev)
        dev->header_ops         = &ether1394_header_ops;
        dev->netdev_ops         = &ether1394_netdev_ops;
 
-       SET_ETHTOOL_OPS(dev, &ethtool_ops);
-
        dev->watchdog_timeo     = ETHER1394_TIMEOUT;
        dev->flags              = IFF_BROADCAST | IFF_MULTICAST;
        dev->features           = NETIF_F_HIGHDMA;
@@ -1695,17 +1690,6 @@ fail:
        return NETDEV_TX_OK;
 }
 
-static void ether1394_get_drvinfo(struct net_device *dev,
-                                 struct ethtool_drvinfo *info)
-{
-       strcpy(info->driver, driver_name);
-       strcpy(info->bus_info, "ieee1394"); /* FIXME provide more detail? */
-}
-
-static const struct ethtool_ops ethtool_ops = {
-       .get_drvinfo = ether1394_get_drvinfo
-};
-
 static int __init ether1394_init_module(void)
 {
        int err;
index 2978bdaa6b8823473a029bce120237b94e133c2f..e54e79d4e2c124310e552f3daccb512d5cff25c2 100644 (file)
@@ -1515,8 +1515,13 @@ static int decodeFVteln(char *teln, unsigned long *bmaskp, int *activep)
        while (*s) {
                int digit1 = 0;
                int digit2 = 0;
-               if (!isdigit(*s)) return -3;
-               while (isdigit(*s)) { digit1 = digit1*10 + (*s - '0'); s++; }
+               char *endp;
+
+               digit1 = simple_strtoul(s, &endp, 10);
+               if (s == endp)
+                       return -3;
+               s = endp;
+
                if (digit1 <= 0 || digit1 > 30) return -4;
                if (*s == 0 || *s == ',' || *s == ' ') {
                        bmask |= (1 << digit1);
@@ -1526,8 +1531,12 @@ static int decodeFVteln(char *teln, unsigned long *bmaskp, int *activep)
                }
                if (*s != '-') return -5;
                s++;
-               if (!isdigit(*s)) return -3;
-               while (isdigit(*s)) { digit2 = digit2*10 + (*s - '0'); s++; }
+
+               digit2 = simple_strtoul(s, &endp, 10);
+               if (s == endp)
+                       return -3;
+               s = endp;
+
                if (digit2 <= 0 || digit2 > 30) return -4;
                if (*s == 0 || *s == ',' || *s == ' ') {
                        if (digit1 > digit2)
index 70cf6bac7a5aa1041cfa6067df7a62c1964debd5..48e6d220f62c4d56b9bd3a5830552ccb8d684039 100644 (file)
@@ -77,7 +77,7 @@ static void deflect_timer_expire(ulong arg)
 
      case DEFLECT_ALERT:
        cs->ics.command = ISDN_CMD_REDIR; /* protocol */
-       strcpy(cs->ics.parm.setup.phone,cs->deflect_dest);
+       strlcpy(cs->ics.parm.setup.phone, cs->deflect_dest, sizeof(cs->ics.parm.setup.phone));
        strcpy(cs->ics.parm.setup.eazmsn,"Testtext delayed");
        divert_if.ll_cmd(&cs->ics);
        spin_lock_irqsave(&divert_lock, flags);
@@ -251,7 +251,7 @@ int deflect_extern_action(u_char cmd, ulong callid, char *to_nr)
 
      case 2: /* redir */
        del_timer(&cs->timer); 
-       strcpy(cs->ics.parm.setup.phone, 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)))
@@ -480,7 +480,7 @@ static int isdn_divert_icall(isdn_ctrl *ic)
                if (!cs->timer.expires)
                 { strcpy(ic->parm.setup.eazmsn,"Testtext direct");
                    ic->parm.setup.screen = dv->rule.screen;
-                   strcpy(ic->parm.setup.phone,dv->rule.to_nr);
+                   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; 
index be5faf4aa8689b7475485a6e25d9a3b606f2a65e..5aa138eb0b3c6a3cd45abfc2b3fb024f4b56d27a 100644 (file)
@@ -234,13 +234,14 @@ read_fifo(struct IsdnCardState *cs, u_char fifo, int trans_max)
          count++;
          if (count > trans_max) 
            count = trans_max; /* limit length */
-           if ((skb = dev_alloc_skb(count))) {
-             dst = skb_put(skb, count);
-             while (count--) 
+         skb = dev_alloc_skb(count);
+         if (skb) {
+           dst = skb_put(skb, count);
+           while (count--)
                *dst++ = Read_hfc(cs, HFCSX_FIF_DRD);
-             return(skb);
-           }
-           else return(NULL); /* no memory */
+           return skb;
+         } else
+               return NULL; /* no memory */
        }
 
        do {
index 51dc60da333bcf17cadca7554283b60ce98b21d7..f013ee15327c65a23ca0fc4f5091f70bfd654610 100644 (file)
@@ -3515,7 +3515,7 @@ isdn_tty_parse_at(modem_info * info)
 {
        atemu *m = &info->emu;
        char *p;
-       char ds[40];
+       char ds[ISDN_MSNLEN];
 
 #ifdef ISDN_DEBUG_AT
        printk(KERN_DEBUG "AT: '%s'\n", m->mdmcmd);
@@ -3594,7 +3594,7 @@ isdn_tty_parse_at(modem_info * info)
                                                break;
                                        case '3':
                                                 p++;
-                                                sprintf(ds, "\r\n%d", info->emu.charge);
+                                                snprintf(ds, sizeof(ds), "\r\n%d", info->emu.charge);
                                                 isdn_tty_at_cout(ds, info);
                                                 break;
                                        default:;
index 713ef2b805a2aabec1803b6f7607f9104517fc84..76d9e673b4e16af63e296f37418fd77411f5b1bf 100644 (file)
@@ -1237,6 +1237,7 @@ dsp_cmx_receive(struct dsp *dsp, struct sk_buff *skb)
                        if (dsp->cmx_delay)
                                dsp->rx_W = (dsp->rx_R + dsp->cmx_delay)
                                        & CMX_BUFF_MASK;
+                       else
                                dsp->rx_W = (dsp->rx_R + (dsp_poll >> 1))
                                        & CMX_BUFF_MASK;
                } else {
index 22f38e48ac4eddca6e27afa74df9c5122b940e4f..5b59796ed250f53ae4e3a261583cd60a525a0cc1 100644 (file)
@@ -972,7 +972,7 @@ channel_dctrl(struct dchannel *dch, struct mISDN_ctrl_req *cq)
                if (debug & DEBUG_L1OIP_SOCKET)
                        printk(KERN_DEBUG "%s: got new ip address from user "
                                "space.\n", __func__);
-                       l1oip_socket_open(hc);
+               l1oip_socket_open(hc);
                break;
        case MISDN_CTRL_UNSETPEER:
                if (debug & DEBUG_L1OIP_SOCKET)
index baac246561b9c99b6b1b15eaef7d8ddf5e5f1da9..4777a1cbcd8d6f7f7f9b032f9f1bbe385f1f6538 100644 (file)
@@ -337,10 +337,10 @@ el2_probe1(struct net_device *dev, int ioaddr)
     /* 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;
+    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;
index 3bba835f1a214c875352c7335dd251b27e6286d6..8a6eb0c444869fd6e75c155bbc1929dccc60570b 100644 (file)
@@ -734,7 +734,7 @@ static int corkscrew_open(struct net_device *dev)
                init_timer(&vp->timer);
                vp->timer.expires = jiffies + media_tbl[dev->if_port].wait;
                vp->timer.data = (unsigned long) dev;
-               vp->timer.function = &corkscrew_timer;  /* timer handler */
+               vp->timer.function = corkscrew_timer;   /* timer handler */
                add_timer(&vp->timer);
        } else
                dev->if_port = vp->default_media;
index 85671adae455dc59bd29405aa2b196e5b0ebd9c2..e31a6d1919c6c10369df1b205d59ed13026ebeb8 100644 (file)
@@ -1739,7 +1739,7 @@ vortex_open(struct net_device *dev)
 
        /* Use the now-standard shared IRQ implementation. */
        if ((retval = request_irq(dev->irq, vp->full_bus_master_rx ?
-                               &boomerang_interrupt : &vortex_interrupt, IRQF_SHARED, dev->name, dev))) {
+                               boomerang_interrupt : vortex_interrupt, IRQF_SHARED, dev->name, dev))) {
                pr_err("%s: Could not reserve IRQ %d\n", dev->name, dev->irq);
                goto err;
        }
index 4a4f6b81e32de9ae8c85f9dd6aa379927d0ffaa0..237d4ea5a416f071cd50e5b9f3333da00cf062be 100644 (file)
@@ -561,7 +561,7 @@ rx_status_loop:
                if (cp_rx_csum_ok(status))
                        skb->ip_summed = CHECKSUM_UNNECESSARY;
                else
-                       skb->ip_summed = CHECKSUM_NONE;
+                       skb_checksum_none_assert(skb);
 
                skb_put(skb, len);
 
index 2cc81a54cbf322a49ccbf474f5d41f654faf109d..53c4810b119ea7712c0b6b88b54110a3fa876034 100644 (file)
@@ -2869,6 +2869,20 @@ config QLGE
          To compile this driver as a module, choose M here: the module
          will be called qlge.
 
+config BNA
+        tristate "Brocade 1010/1020 10Gb Ethernet Driver support"
+        depends on PCI
+        ---help---
+          This driver supports Brocade 1010/1020 10Gb CEE capable Ethernet
+          cards.
+          To compile this driver as a module, choose M here: the module
+          will be called bna.
+
+          For general information and support, go to the Brocade support
+          website at:
+
+          <http://support.brocade.com>
+
 source "drivers/net/sfc/Kconfig"
 
 source "drivers/net/benet/Kconfig"
@@ -3202,6 +3216,17 @@ config PPPOE
          which contains instruction on how to use this driver (under 
          the heading "Kernel mode PPPoE").
 
+config PPTP
+       tristate "PPP over IPv4 (PPTP) (EXPERIMENTAL)"
+       depends on EXPERIMENTAL && PPP && NET_IPGRE_DEMUX
+       help
+         Support for PPP over IPv4.(Point-to-Point Tunneling Protocol)
+
+         This driver requires pppd plugin to work in client mode or
+         modified pptpd (poptop) to work in server mode.
+         See http://accel-pptp.sourceforge.net/ for information how to
+         utilize this module.
+
 config PPPOATM
        tristate "PPP over ATM"
        depends on ATM && PPP
index 3e8f150c4b14b0034edb3632b9de33b1338b9635..18a277709a2ae776586917634a850473ecfd9075 100644 (file)
@@ -34,6 +34,7 @@ obj-$(CONFIG_ENIC) += enic/
 obj-$(CONFIG_JME) += jme.o
 obj-$(CONFIG_BE2NET) += benet/
 obj-$(CONFIG_VMXNET3) += vmxnet3/
+obj-$(CONFIG_BNA) += bna/
 
 gianfar_driver-objs := gianfar.o \
                gianfar_ethtool.o \
@@ -162,6 +163,7 @@ obj-$(CONFIG_PPP_BSDCOMP) += bsd_comp.o
 obj-$(CONFIG_PPP_MPPE) += ppp_mppe.o
 obj-$(CONFIG_PPPOE) += pppox.o pppoe.o
 obj-$(CONFIG_PPPOL2TP) += pppox.o
+obj-$(CONFIG_PPTP) += pppox.o pptp.o
 
 obj-$(CONFIG_SLIP) += slip.o
 obj-$(CONFIG_SLHC) += slhc.o
index b9a591604e5b538b1d6c39bc8dea5abd82d13f01..41d9911202d01e4b721e7a2221a15f0dd8e82c3b 100644 (file)
@@ -2033,7 +2033,7 @@ static void ace_rx_int(struct net_device *dev, u32 rxretprd, u32 rxretcsm)
                        skb->csum = htons(csum);
                        skb->ip_summed = CHECKSUM_COMPLETE;
                } else {
-                       skb->ip_summed = CHECKSUM_NONE;
+                       skb_checksum_none_assert(skb);
                }
 
                /* send it up */
index 585c25f4b60c27437043eacbea291d137a60a210..58a0ab4923ee64013886fc056a1e63c0fa1192f5 100644 (file)
@@ -396,7 +396,7 @@ static int amd8111e_set_coalesce(struct net_device * dev, enum coal_mode cmod)
                        event_count = coal_conf->rx_event_count;
                        if( timeout > MAX_TIMEOUT ||
                                        event_count > MAX_EVENT_COUNT )
-                       return -EINVAL;
+                               return -EINVAL;
 
                        timeout = timeout * DELAY_TIMER_CONV;
                        writel(VAL0|STINTEN, mmio+INTEN0);
@@ -409,7 +409,7 @@ static int amd8111e_set_coalesce(struct net_device * dev, enum coal_mode cmod)
                        event_count = coal_conf->tx_event_count;
                        if( timeout > MAX_TIMEOUT ||
                                        event_count > MAX_EVENT_COUNT )
-                       return -EINVAL;
+                               return -EINVAL;
 
 
                        timeout = timeout * DELAY_TIMER_CONV;
@@ -903,18 +903,18 @@ static int amd8111e_read_mib(void __iomem *mmio, u8 MIB_COUNTER)
 }
 
 /*
-This function reads the mib registers and returns the hardware statistics. It  updates previous internal driver statistics with new values.
-*/
-static struct net_device_stats *amd8111e_get_stats(struct net_device * dev)
+ * This function reads the mib registers and returns the hardware statistics.
+ * It updates previous internal driver statistics with new values.
+ */
+static struct net_device_stats *amd8111e_get_stats(struct net_device *dev)
 {
        struct amd8111e_priv *lp = netdev_priv(dev);
        void __iomem *mmio = lp->mmio;
        unsigned long flags;
-       /* struct net_device_stats *prev_stats = &lp->prev_stats; */
-       struct net_device_stats* new_stats = &lp->stats;
+       struct net_device_stats *new_stats = &dev->stats;
 
-       if(!lp->opened)
-               return &lp->stats;
+       if (!lp->opened)
+               return new_stats;
        spin_lock_irqsave (&lp->lock, flags);
 
        /* stats.rx_packets */
index ac36eb6981e3ba12c06ee7f318699eb9db2e9717..b5926af03a7ef78905b90e62e7082f5e8dba6ba2 100644 (file)
@@ -787,7 +787,6 @@ struct amd8111e_priv{
        struct vlan_group               *vlgrp;
 #endif
        char opened;
-       struct net_device_stats stats;
        unsigned int drv_rx_errors;
        struct amd8111e_coalesce_conf coal_conf;
 
index 8c496fb1ac9e5fc17108d9b14ba5ac489030740c..62f21106efec224d3447f408439a55bb7d4743e3 100644 (file)
@@ -300,8 +300,6 @@ am79c961_open(struct net_device *dev)
        struct dev_priv *priv = netdev_priv(dev);
        int ret;
 
-       memset (&priv->stats, 0, sizeof (priv->stats));
-
        ret = request_irq(dev->irq, am79c961_interrupt, 0, dev->name, dev);
        if (ret)
                return ret;
@@ -347,8 +345,7 @@ am79c961_close(struct net_device *dev)
  */
 static struct net_device_stats *am79c961_getstats (struct net_device *dev)
 {
-       struct dev_priv *priv = netdev_priv(dev);
-       return &priv->stats;
+       return &dev->stats;
 }
 
 static void am79c961_mc_hash(char *addr, unsigned short *hash)
@@ -510,14 +507,14 @@ am79c961_rx(struct net_device *dev, struct dev_priv *priv)
 
                if ((status & (RMD_ERR|RMD_STP|RMD_ENP)) != (RMD_STP|RMD_ENP)) {
                        am_writeword (dev, hdraddr + 2, RMD_OWN);
-                       priv->stats.rx_errors ++;
+                       dev->stats.rx_errors++;
                        if (status & RMD_ERR) {
                                if (status & RMD_FRAM)
-                                       priv->stats.rx_frame_errors ++;
+                                       dev->stats.rx_frame_errors++;
                                if (status & RMD_CRC)
-                                       priv->stats.rx_crc_errors ++;
+                                       dev->stats.rx_crc_errors++;
                        } else if (status & RMD_STP)
-                               priv->stats.rx_length_errors ++;
+                               dev->stats.rx_length_errors++;
                        continue;
                }
 
@@ -531,12 +528,12 @@ am79c961_rx(struct net_device *dev, struct dev_priv *priv)
                        am_writeword(dev, hdraddr + 2, RMD_OWN);
                        skb->protocol = eth_type_trans(skb, dev);
                        netif_rx(skb);
-                       priv->stats.rx_bytes += len;
-                       priv->stats.rx_packets ++;
+                       dev->stats.rx_bytes += len;
+                       dev->stats.rx_packets++;
                } else {
                        am_writeword (dev, hdraddr + 2, RMD_OWN);
                        printk (KERN_WARNING "%s: memory squeeze, dropping packet.\n", dev->name);
-                       priv->stats.rx_dropped ++;
+                       dev->stats.rx_dropped++;
                        break;
                }
        } while (1);
@@ -565,7 +562,7 @@ am79c961_tx(struct net_device *dev, struct dev_priv *priv)
                if (status & TMD_ERR) {
                        u_int status2;
 
-                       priv->stats.tx_errors ++;
+                       dev->stats.tx_errors++;
 
                        status2 = am_readword (dev, hdraddr + 6);
 
@@ -575,18 +572,18 @@ am79c961_tx(struct net_device *dev, struct dev_priv *priv)
                        am_writeword (dev, hdraddr + 6, 0);
 
                        if (status2 & TST_RTRY)
-                               priv->stats.collisions += 16;
+                               dev->stats.collisions += 16;
                        if (status2 & TST_LCOL)
-                               priv->stats.tx_window_errors ++;
+                               dev->stats.tx_window_errors++;
                        if (status2 & TST_LCAR)
-                               priv->stats.tx_carrier_errors ++;
+                               dev->stats.tx_carrier_errors++;
                        if (status2 & TST_UFLO)
-                               priv->stats.tx_fifo_errors ++;
+                               dev->stats.tx_fifo_errors++;
                        continue;
                }
-               priv->stats.tx_packets ++;
+               dev->stats.tx_packets++;
                len = am_readword (dev, hdraddr + 4);
-               priv->stats.tx_bytes += -len;
+               dev->stats.tx_bytes += -len;
        } while (priv->txtail != priv->txhead);
 
        netif_wake_queue(dev);
@@ -616,7 +613,7 @@ am79c961_interrupt(int irq, void *dev_id)
                }
                if (status & CSR0_MISS) {
                        handled = 1;
-                       priv->stats.rx_dropped ++;
+                       dev->stats.rx_dropped++;
                }
                if (status & CSR0_CERR) {
                        handled = 1;
index 483009fe6ec2545010f9bb95fec9ac0ce9d981d9..fd634d32756bddcfcbe7b1d79f1b1b3105d32162 100644 (file)
 #define ISALED0_LNKST  0x8000
 
 struct dev_priv {
-    struct net_device_stats stats;
     unsigned long      rxbuffer[RX_BUFFERS];
     unsigned long      txbuffer[TX_BUFFERS];
     unsigned char      txhead;
index 4a5ec9470aa1fca56d2be28893e54e39bed346ee..5a77001b6d1053d4898b4635b0f1b9d1357e5868 100644 (file)
@@ -175,8 +175,6 @@ struct ep93xx_priv
        struct net_device       *dev;
        struct napi_struct      napi;
 
-       struct net_device_stats stats;
-
        struct mii_if_info      mii;
        u8                      mdc_divisor;
 };
@@ -230,12 +228,6 @@ static void ep93xx_mdio_write(struct net_device *dev, int phy_id, int reg, int d
                pr_info("mdio write timed out\n");
 }
 
-static struct net_device_stats *ep93xx_get_stats(struct net_device *dev)
-{
-       struct ep93xx_priv *ep = netdev_priv(dev);
-       return &(ep->stats);
-}
-
 static int ep93xx_rx(struct net_device *dev, int processed, int budget)
 {
        struct ep93xx_priv *ep = netdev_priv(dev);
@@ -267,15 +259,15 @@ static int ep93xx_rx(struct net_device *dev, int processed, int budget)
                        pr_crit("entry mismatch %.8x %.8x\n", rstat0, rstat1);
 
                if (!(rstat0 & RSTAT0_RWE)) {
-                       ep->stats.rx_errors++;
+                       dev->stats.rx_errors++;
                        if (rstat0 & RSTAT0_OE)
-                               ep->stats.rx_fifo_errors++;
+                               dev->stats.rx_fifo_errors++;
                        if (rstat0 & RSTAT0_FE)
-                               ep->stats.rx_frame_errors++;
+                               dev->stats.rx_frame_errors++;
                        if (rstat0 & (RSTAT0_RUNT | RSTAT0_EDATA))
-                               ep->stats.rx_length_errors++;
+                               dev->stats.rx_length_errors++;
                        if (rstat0 & RSTAT0_CRCE)
-                               ep->stats.rx_crc_errors++;
+                               dev->stats.rx_crc_errors++;
                        goto err;
                }
 
@@ -300,10 +292,10 @@ static int ep93xx_rx(struct net_device *dev, int processed, int budget)
 
                        netif_receive_skb(skb);
 
-                       ep->stats.rx_packets++;
-                       ep->stats.rx_bytes += length;
+                       dev->stats.rx_packets++;
+                       dev->stats.rx_bytes += length;
                } else {
-                       ep->stats.rx_dropped++;
+                       dev->stats.rx_dropped++;
                }
 
 err:
@@ -359,7 +351,7 @@ static int ep93xx_xmit(struct sk_buff *skb, struct net_device *dev)
        int entry;
 
        if (unlikely(skb->len > MAX_PKT_SIZE)) {
-               ep->stats.tx_dropped++;
+               dev->stats.tx_dropped++;
                dev_kfree_skb(skb);
                return NETDEV_TX_OK;
        }
@@ -415,17 +407,17 @@ static void ep93xx_tx_complete(struct net_device *dev)
                if (tstat0 & TSTAT0_TXWE) {
                        int length = ep->descs->tdesc[entry].tdesc1 & 0xfff;
 
-                       ep->stats.tx_packets++;
-                       ep->stats.tx_bytes += length;
+                       dev->stats.tx_packets++;
+                       dev->stats.tx_bytes += length;
                } else {
-                       ep->stats.tx_errors++;
+                       dev->stats.tx_errors++;
                }
 
                if (tstat0 & TSTAT0_OW)
-                       ep->stats.tx_window_errors++;
+                       dev->stats.tx_window_errors++;
                if (tstat0 & TSTAT0_TXU)
-                       ep->stats.tx_fifo_errors++;
-               ep->stats.collisions += (tstat0 >> 16) & 0x1f;
+                       dev->stats.tx_fifo_errors++;
+               dev->stats.collisions += (tstat0 >> 16) & 0x1f;
 
                ep->tx_clean_pointer = (entry + 1) & (TX_QUEUE_ENTRIES - 1);
                if (ep->tx_pending == TX_QUEUE_ENTRIES)
@@ -758,7 +750,6 @@ static const struct net_device_ops ep93xx_netdev_ops = {
        .ndo_open               = ep93xx_open,
        .ndo_stop               = ep93xx_close,
        .ndo_start_xmit         = ep93xx_xmit,
-       .ndo_get_stats          = ep93xx_get_stats,
        .ndo_do_ioctl           = ep93xx_ioctl,
        .ndo_validate_addr      = eth_validate_addr,
        .ndo_change_mtu         = eth_change_mtu,
index b17ab5153f51e5aca038cb7a32c9bde62a0496e5..b00781c02d5d40b8b2e1aece3bba6070f24872ea 100644 (file)
@@ -68,7 +68,6 @@ static int ether1_open(struct net_device *dev);
 static int ether1_sendpacket(struct sk_buff *skb, struct net_device *dev);
 static irqreturn_t ether1_interrupt(int irq, void *dev_id);
 static int ether1_close(struct net_device *dev);
-static struct net_device_stats *ether1_getstats(struct net_device *dev);
 static void ether1_setmulticastlist(struct net_device *dev);
 static void ether1_timeout(struct net_device *dev);
 
@@ -649,8 +648,6 @@ ether1_open (struct net_device *dev)
        if (request_irq(dev->irq, ether1_interrupt, 0, "ether1", dev))
                return -EAGAIN;
 
-       memset (&priv(dev)->stats, 0, sizeof (struct net_device_stats));
-
        if (ether1_init_for_open (dev)) {
                free_irq (dev->irq, dev);
                return -EAGAIN;
@@ -673,7 +670,7 @@ ether1_timeout(struct net_device *dev)
        if (ether1_init_for_open (dev))
                printk (KERN_ERR "%s: unable to restart interface\n", dev->name);
 
-       priv(dev)->stats.tx_errors++;
+       dev->stats.tx_errors++;
        netif_wake_queue(dev);
 }
 
@@ -802,21 +799,21 @@ again:
 
        while (nop.nop_status & STAT_COMPLETE) {
                if (nop.nop_status & STAT_OK) {
-                       priv(dev)->stats.tx_packets ++;
-                       priv(dev)->stats.collisions += (nop.nop_status & STAT_COLLISIONS);
+                       dev->stats.tx_packets++;
+                       dev->stats.collisions += (nop.nop_status & STAT_COLLISIONS);
                } else {
-                       priv(dev)->stats.tx_errors ++;
+                       dev->stats.tx_errors++;
 
                        if (nop.nop_status & STAT_COLLAFTERTX)
-                               priv(dev)->stats.collisions ++;
+                               dev->stats.collisions++;
                        if (nop.nop_status & STAT_NOCARRIER)
-                               priv(dev)->stats.tx_carrier_errors ++;
+                               dev->stats.tx_carrier_errors++;
                        if (nop.nop_status & STAT_TXLOSTCTS)
                                printk (KERN_WARNING "%s: cts lost\n", dev->name);
                        if (nop.nop_status & STAT_TXSLOWDMA)
-                               priv(dev)->stats.tx_fifo_errors ++;
+                               dev->stats.tx_fifo_errors++;
                        if (nop.nop_status & STAT_COLLEXCESSIVE)
-                               priv(dev)->stats.collisions += 16;
+                               dev->stats.collisions += 16;
                }
 
                if (nop.nop_link == caddr) {
@@ -879,13 +876,13 @@ ether1_recv_done (struct net_device *dev)
 
                                skb->protocol = eth_type_trans (skb, dev);
                                netif_rx (skb);
-                               priv(dev)->stats.rx_packets ++;
+                               dev->stats.rx_packets++;
                        } else
-                               priv(dev)->stats.rx_dropped ++;
+                               dev->stats.rx_dropped++;
                } else {
                        printk(KERN_WARNING "%s: %s\n", dev->name,
                                (rbd.rbd_status & RBD_EOF) ? "oversized packet" : "acnt not valid");
-                       priv(dev)->stats.rx_dropped ++;
+                       dev->stats.rx_dropped++;
                }
 
                nexttail = ether1_readw(dev, priv(dev)->rx_tail, rfd_t, rfd_link, NORMALIRQS);
@@ -939,7 +936,7 @@ ether1_interrupt (int irq, void *dev_id)
                                printk (KERN_WARNING "%s: RU went not ready: RU suspended\n", dev->name);
                                ether1_writew(dev, SCB_CMDRXRESUME, SCB_ADDR, scb_t, scb_command, NORMALIRQS);
                                writeb(CTRL_CA, REG_CONTROL);
-                               priv(dev)->stats.rx_dropped ++; /* we suspended due to lack of buffer space */
+                               dev->stats.rx_dropped++;        /* we suspended due to lack of buffer space */
                        } else
                                printk(KERN_WARNING "%s: RU went not ready: %04X\n", dev->name,
                                        ether1_readw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS));
@@ -962,12 +959,6 @@ ether1_close (struct net_device *dev)
        return 0;
 }
 
-static struct net_device_stats *
-ether1_getstats (struct net_device *dev)
-{
-       return &priv(dev)->stats;
-}
-
 /*
  * Set or clear the multicast filter for this adaptor.
  * num_addrs == -1     Promiscuous mode, receive all packets.
@@ -994,7 +985,6 @@ static const struct net_device_ops ether1_netdev_ops = {
        .ndo_open               = ether1_open,
        .ndo_stop               = ether1_close,
        .ndo_start_xmit         = ether1_sendpacket,
-       .ndo_get_stats          = ether1_getstats,
        .ndo_set_multicast_list = ether1_setmulticastlist,
        .ndo_tx_timeout         = ether1_timeout,
        .ndo_validate_addr      = eth_validate_addr,
index c8a4b2389d854b5ff22ad59716888c4c2c2324a3..3a5830ab3dc7dd2aacb6229b10624921f7c05087 100644 (file)
@@ -38,7 +38,6 @@
 
 struct ether1_priv {
        void __iomem *base;
-       struct net_device_stats stats;
        unsigned int tx_link;
        unsigned int tx_head;
        volatile unsigned int tx_tail;
index 1361b7367c28bd86f6bbd63ad3816186ec55eaf8..44a8746f4014b81f8f767a81c45c8826f8ac03cc 100644 (file)
@@ -81,7 +81,6 @@ static int    ether3_open (struct net_device *dev);
 static int     ether3_sendpacket (struct sk_buff *skb, struct net_device *dev);
 static irqreturn_t ether3_interrupt (int irq, void *dev_id);
 static int     ether3_close (struct net_device *dev);
-static struct net_device_stats *ether3_getstats (struct net_device *dev);
 static void    ether3_setmulticastlist (struct net_device *dev);
 static void    ether3_timeout(struct net_device *dev);
 
@@ -323,8 +322,6 @@ ether3_init_for_open(struct net_device *dev)
 {
        int i;
 
-       memset(&priv(dev)->stats, 0, sizeof(struct net_device_stats));
-
        /* Reset the chip */
        ether3_outw(CFG2_RESET, REG_CONFIG2);
        udelay(4);
@@ -441,15 +438,6 @@ ether3_close(struct net_device *dev)
        return 0;
 }
 
-/*
- * Get the current statistics. This may be called with the card open or
- * closed.
- */
-static struct net_device_stats *ether3_getstats(struct net_device *dev)
-{
-       return &priv(dev)->stats;
-}
-
 /*
  * Set or clear promiscuous/multicast mode filter for this adaptor.
  *
@@ -490,7 +478,7 @@ static void ether3_timeout(struct net_device *dev)
        local_irq_restore(flags);
 
        priv(dev)->regs.config2 |= CFG2_CTRLO;
-       priv(dev)->stats.tx_errors += 1;
+       dev->stats.tx_errors += 1;
        ether3_outw(priv(dev)->regs.config2, REG_CONFIG2);
        priv(dev)->tx_head = priv(dev)->tx_tail = 0;
 
@@ -509,7 +497,7 @@ ether3_sendpacket(struct sk_buff *skb, struct net_device *dev)
 
        if (priv(dev)->broken) {
                dev_kfree_skb(skb);
-               priv(dev)->stats.tx_dropped ++;
+               dev->stats.tx_dropped++;
                netif_start_queue(dev);
                return NETDEV_TX_OK;
        }
@@ -673,7 +661,7 @@ if (next_ptr < RX_START || next_ptr >= RX_END) {
                        } else
                                goto dropping;
                } else {
-                       struct net_device_stats *stats = &priv(dev)->stats;
+                       struct net_device_stats *stats = &dev->stats;
                        ether3_outw(next_ptr >> 8, REG_RECVEND);
                        if (status & RXSTAT_OVERSIZE)     stats->rx_over_errors ++;
                        if (status & RXSTAT_CRCERROR)     stats->rx_crc_errors ++;
@@ -685,14 +673,14 @@ if (next_ptr < RX_START || next_ptr >= RX_END) {
        while (-- maxcnt);
 
 done:
-       priv(dev)->stats.rx_packets += received;
+       dev->stats.rx_packets += received;
        priv(dev)->rx_head = next_ptr;
        /*
         * If rx went off line, then that means that the buffer may be full.  We
         * have dropped at least one packet.
         */
        if (!(ether3_inw(REG_STATUS) & STAT_RXON)) {
-               priv(dev)->stats.rx_dropped ++;
+               dev->stats.rx_dropped++;
                ether3_outw(next_ptr, REG_RECVPTR);
                ether3_outw(priv(dev)->regs.command | CMD_RXON, REG_COMMAND);
        }
@@ -710,7 +698,7 @@ dropping:{
                last_warned = jiffies;
                printk("%s: memory squeeze, dropping packet.\n", dev->name);
        }
-       priv(dev)->stats.rx_dropped ++;
+       dev->stats.rx_dropped++;
        goto done;
        }
 }
@@ -743,13 +731,13 @@ static void ether3_tx(struct net_device *dev)
                 * Update errors
                 */
                if (!(status & (TXSTAT_BABBLED | TXSTAT_16COLLISIONS)))
-                       priv(dev)->stats.tx_packets++;
+                       dev->stats.tx_packets++;
                else {
-                       priv(dev)->stats.tx_errors ++;
+                       dev->stats.tx_errors++;
                        if (status & TXSTAT_16COLLISIONS)
-                               priv(dev)->stats.collisions += 16;
+                               dev->stats.collisions += 16;
                        if (status & TXSTAT_BABBLED)
-                               priv(dev)->stats.tx_fifo_errors ++;
+                               dev->stats.tx_fifo_errors++;
                }
 
                tx_tail = (tx_tail + 1) & 15;
@@ -773,7 +761,6 @@ static const struct net_device_ops ether3_netdev_ops = {
        .ndo_open               = ether3_open,
        .ndo_stop               = ether3_close,
        .ndo_start_xmit         = ether3_sendpacket,
-       .ndo_get_stats          = ether3_getstats,
        .ndo_set_multicast_list = ether3_setmulticastlist,
        .ndo_tx_timeout         = ether3_timeout,
        .ndo_validate_addr      = eth_validate_addr,
index 1921a3a07da70d14892588da230c78fd4f142a9b..2db63b08bdf37885e0b97ec5a025ea5da3fb4013 100644 (file)
@@ -164,7 +164,6 @@ struct dev_priv {
     unsigned char tx_head;             /* buffer nr to insert next packet       */
     unsigned char tx_tail;             /* buffer nr of transmitting packet      */
     unsigned int rx_head;              /* address to fetch next packet from     */
-    struct net_device_stats stats;
     struct timer_list timer;
     int broken;                                /* 0 = ok, 1 = something went wrong      */
 };
index 52abbbdf8a08c46df73b8e83d2566fe741f8043d..ef4115b897bf8d394b85e4123ca7160c73eaf134 100644 (file)
@@ -559,7 +559,6 @@ struct atl1c_adapter {
        struct napi_struct  napi;
        struct atl1c_hw        hw;
        struct atl1c_hw_stats  hw_stats;
-       struct net_device_stats net_stats;
        struct mii_if_info  mii;    /* MII interface info */
        u16 rx_buffer_len;
 
index d8501f060957afac49afd7726158020aa96de4b2..919080b2c3a50eb48bea7311ac0db4e8d3e8103e 100644 (file)
@@ -480,7 +480,7 @@ int atl1c_phy_reset(struct atl1c_hw *hw)
                atl1c_write_phy_reg(hw, MII_DBG_DATA, 0x929D);
        }
        if (hw->nic_type == athr_l1c || hw->nic_type == athr_l2c_b2
-               || hw->nic_type == athr_l2c || hw->nic_type == athr_l2c) {
+               || hw->nic_type == athr_l2c) {
                atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x29);
                atl1c_write_phy_reg(hw, MII_DBG_DATA, 0xB6DD);
        }
index c7b8ef507ebd4d71fd653240c1a1f26183c4daf1..553230eb365c547fce10d845051d5dbed8558753 100644 (file)
@@ -1562,7 +1562,7 @@ static struct net_device_stats *atl1c_get_stats(struct net_device *netdev)
 {
        struct atl1c_adapter *adapter = netdev_priv(netdev);
        struct atl1c_hw_stats  *hw_stats = &adapter->hw_stats;
-       struct net_device_stats *net_stats = &adapter->net_stats;
+       struct net_device_stats *net_stats = &netdev->stats;
 
        atl1c_update_hw_stats(adapter);
        net_stats->rx_packets = hw_stats->rx_ok;
@@ -1590,7 +1590,7 @@ static struct net_device_stats *atl1c_get_stats(struct net_device *netdev)
        net_stats->tx_aborted_errors = hw_stats->tx_abort_col;
        net_stats->tx_window_errors  = hw_stats->tx_late_col;
 
-       return &adapter->net_stats;
+       return net_stats;
 }
 
 static inline void atl1c_clear_phy_int(struct atl1c_adapter *adapter)
@@ -1700,7 +1700,7 @@ static irqreturn_t atl1c_intr(int irq, void *data)
 
                /* link event */
                if (status & (ISR_GPHY | ISR_MANUAL)) {
-                       adapter->net_stats.tx_carrier_errors++;
+                       netdev->stats.tx_carrier_errors++;
                        atl1c_link_chg_event(adapter);
                        break;
                }
@@ -1719,7 +1719,7 @@ static inline void atl1c_rx_checksum(struct atl1c_adapter *adapter,
         * cannot figure out if the packet is fragmented or not,
         * so we tell the KERNEL CHECKSUM_NONE
         */
-       skb->ip_summed = CHECKSUM_NONE;
+       skb_checksum_none_assert(skb);
 }
 
 static int atl1c_alloc_rx_buffer(struct atl1c_adapter *adapter, const int ringid)
index 1acea5774e8936ed0b78352c871b8b0d9734b518..56ace3fbe40d879002a80fc111e966121d692557 100644 (file)
@@ -1331,7 +1331,7 @@ static inline void atl1e_rx_checksum(struct atl1e_adapter *adapter,
        u16 pkt_flags;
        u16 err_flags;
 
-       skb->ip_summed = CHECKSUM_NONE;
+       skb_checksum_none_assert(skb);
        pkt_flags = prrs->pkt_flag;
        err_flags = prrs->err_flag;
        if (((pkt_flags & RRS_IS_IPV4) || (pkt_flags & RRS_IS_IPV6)) &&
@@ -2316,7 +2316,7 @@ static int __devinit atl1e_probe(struct pci_dev *pdev,
        netif_napi_add(netdev, &adapter->napi, atl1e_clean, 64);
 
        init_timer(&adapter->phy_config_timer);
-       adapter->phy_config_timer.function = &atl1e_phy_config;
+       adapter->phy_config_timer.function = atl1e_phy_config;
        adapter->phy_config_timer.data = (unsigned long) adapter;
 
        /* get user settings */
index 63b9ba0cc67e13c408686442f1e2fe984ee9b462..e1e0171d6e62fa1cd6144fe6bfb32285ec8f8ecc 100644 (file)
@@ -1805,7 +1805,7 @@ static void atl1_rx_checksum(struct atl1_adapter *adapter,
         * the higher layers and let it be sorted out there.
         */
 
-       skb->ip_summed = CHECKSUM_NONE;
+       skb_checksum_none_assert(skb);
 
        if (unlikely(rrd->pkt_flg & PACKET_FLAG_ERR)) {
                if (rrd->err_flg & (ERR_FLAG_CRC | ERR_FLAG_TRUNC |
@@ -3036,7 +3036,7 @@ static int __devinit atl1_probe(struct pci_dev *pdev,
        netif_carrier_off(netdev);
        netif_stop_queue(netdev);
 
-       setup_timer(&adapter->phy_config_timer, &atl1_phy_config,
+       setup_timer(&adapter->phy_config_timer, atl1_phy_config,
                    (unsigned long)adapter);
        adapter->phy_timer_pending = false;
 
index 8da87383fb3938dc0fe8d9031ff3860a3f24ac97..29c0265ccc5d2d65e08d0d4506870046cdf5bc3d 100644 (file)
 
 #define ATL2_DRV_VERSION "2.2.3"
 
-static char atl2_driver_name[] = "atl2";
+static const char atl2_driver_name[] = "atl2";
 static const char atl2_driver_string[] = "Atheros(R) L2 Ethernet Driver";
-static char atl2_copyright[] = "Copyright (c) 2007 Atheros Corporation.";
-static char atl2_driver_version[] = ATL2_DRV_VERSION;
+static const char atl2_copyright[] = "Copyright (c) 2007 Atheros Corporation.";
+static const char atl2_driver_version[] = ATL2_DRV_VERSION;
 
 MODULE_AUTHOR("Atheros Corporation <xiong.huang@atheros.com>, Chris Snook <csnook@redhat.com>");
 MODULE_DESCRIPTION("Atheros Fast Ethernet Network Driver");
@@ -1444,11 +1444,11 @@ static int __devinit atl2_probe(struct pci_dev *pdev,
        atl2_check_options(adapter);
 
        init_timer(&adapter->watchdog_timer);
-       adapter->watchdog_timer.function = &atl2_watchdog;
+       adapter->watchdog_timer.function = atl2_watchdog;
        adapter->watchdog_timer.data = (unsigned long) adapter;
 
        init_timer(&adapter->phy_config_timer);
-       adapter->phy_config_timer.function = &atl2_phy_config;
+       adapter->phy_config_timer.function = atl2_phy_config;
        adapter->phy_config_timer.data = (unsigned long) adapter;
 
        INIT_WORK(&adapter->reset_task, atl2_reset_task);
index bd2f9d331dac79ee89d3729dce6b9072b91b6a0d..dfd96b20547f2caa362050897568468e904bd3b6 100644 (file)
@@ -445,7 +445,7 @@ static int net_open(struct net_device *dev)
        init_timer(&lp->timer);
        lp->timer.expires = jiffies + TIMED_CHECKER;
        lp->timer.data = (unsigned long)dev;
-       lp->timer.function = &atp_timed_checker;    /* timer handler */
+       lp->timer.function = atp_timed_checker;    /* timer handler */
        add_timer(&lp->timer);
 
        netif_start_queue(dev);
index 15ae6df2ff00b89885e778f8b1a8241a1959ddc3..43489f89c142f7d10e25f0454287ef28939fd228 100644 (file)
@@ -13,7 +13,7 @@
  *  converted to use linux-2.6.x's PHY framework
  *
  * Author: MontaVista Software, Inc.
- *             ppopov@mvista.com or source@mvista.com
+ *             ppopov@mvista.com or source@mvista.com
  *
  * ########################################################################
  *
@@ -34,6 +34,8 @@
  *
  *
  */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/capability.h>
 #include <linux/dma-mapping.h>
 #include <linux/module.h>
 #include <linux/crc32.h>
 #include <linux/phy.h>
 #include <linux/platform_device.h>
+#include <linux/cpu.h>
+#include <linux/io.h>
 
-#include <asm/cpu.h>
 #include <asm/mipsregs.h>
 #include <asm/irq.h>
-#include <asm/io.h>
 #include <asm/processor.h>
 
 #include <au1000.h>
@@ -152,11 +154,11 @@ static void au1000_enable_mac(struct net_device *dev, int force_reset)
 
        spin_lock_irqsave(&aup->lock, flags);
 
-       if(force_reset || (!aup->mac_enabled)) {
-               *aup->enable = MAC_EN_CLOCK_ENABLE;
+       if (force_reset || (!aup->mac_enabled)) {
+               writel(MAC_EN_CLOCK_ENABLE, &aup->enable);
                au_sync_delay(2);
-               *aup->enable = (MAC_EN_RESET0 | MAC_EN_RESET1 | MAC_EN_RESET2
-                               | MAC_EN_CLOCK_ENABLE);
+               writel((MAC_EN_RESET0 | MAC_EN_RESET1 | MAC_EN_RESET2
+                               | MAC_EN_CLOCK_ENABLE), &aup->enable);
                au_sync_delay(2);
 
                aup->mac_enabled = 1;
@@ -171,12 +173,12 @@ static void au1000_enable_mac(struct net_device *dev, int force_reset)
 static int au1000_mdio_read(struct net_device *dev, int phy_addr, int reg)
 {
        struct au1000_private *aup = netdev_priv(dev);
-       volatile u32 *const mii_control_reg = &aup->mac->mii_control;
-       volatile u32 *const mii_data_reg = &aup->mac->mii_data;
+       u32 *const mii_control_reg = &aup->mac->mii_control;
+       u32 *const mii_data_reg = &aup->mac->mii_data;
        u32 timedout = 20;
        u32 mii_control;
 
-       while (*mii_control_reg & MAC_MII_BUSY) {
+       while (readl(mii_control_reg) & MAC_MII_BUSY) {
                mdelay(1);
                if (--timedout == 0) {
                        netdev_err(dev, "read_MII busy timeout!!\n");
@@ -187,29 +189,29 @@ static int au1000_mdio_read(struct net_device *dev, int phy_addr, int reg)
        mii_control = MAC_SET_MII_SELECT_REG(reg) |
                MAC_SET_MII_SELECT_PHY(phy_addr) | MAC_MII_READ;
 
-       *mii_control_reg = mii_control;
+       writel(mii_control, mii_control_reg);
 
        timedout = 20;
-       while (*mii_control_reg & MAC_MII_BUSY) {
+       while (readl(mii_control_reg) & MAC_MII_BUSY) {
                mdelay(1);
                if (--timedout == 0) {
                        netdev_err(dev, "mdio_read busy timeout!!\n");
                        return -1;
                }
        }
-       return (int)*mii_data_reg;
+       return readl(mii_data_reg);
 }
 
 static void au1000_mdio_write(struct net_device *dev, int phy_addr,
                              int reg, u16 value)
 {
        struct au1000_private *aup = netdev_priv(dev);
-       volatile u32 *const mii_control_reg = &aup->mac->mii_control;
-       volatile u32 *const mii_data_reg = &aup->mac->mii_data;
+       u32 *const mii_control_reg = &aup->mac->mii_control;
+       u32 *const mii_data_reg = &aup->mac->mii_data;
        u32 timedout = 20;
        u32 mii_control;
 
-       while (*mii_control_reg & MAC_MII_BUSY) {
+       while (readl(mii_control_reg) & MAC_MII_BUSY) {
                mdelay(1);
                if (--timedout == 0) {
                        netdev_err(dev, "mdio_write busy timeout!!\n");
@@ -220,18 +222,22 @@ static void au1000_mdio_write(struct net_device *dev, int phy_addr,
        mii_control = MAC_SET_MII_SELECT_REG(reg) |
                MAC_SET_MII_SELECT_PHY(phy_addr) | MAC_MII_WRITE;
 
-       *mii_data_reg = value;
-       *mii_control_reg = mii_control;
+       writel(value, mii_data_reg);
+       writel(mii_control, mii_control_reg);
 }
 
 static int au1000_mdiobus_read(struct mii_bus *bus, int phy_addr, int regnum)
 {
        /* WARNING: bus->phy_map[phy_addr].attached_dev == dev does
-        * _NOT_ hold (e.g. when PHY is accessed through other MAC's MII bus) */
+        * _NOT_ hold (e.g. when PHY is accessed through other MAC's MII bus)
+        */
        struct net_device *const dev = bus->priv;
 
-       au1000_enable_mac(dev, 0); /* make sure the MAC associated with this
-                            * mii_bus is enabled */
+       /* make sure the MAC associated with this
+        * mii_bus is enabled
+        */
+       au1000_enable_mac(dev, 0);
+
        return au1000_mdio_read(dev, phy_addr, regnum);
 }
 
@@ -240,8 +246,11 @@ static int au1000_mdiobus_write(struct mii_bus *bus, int phy_addr, int regnum,
 {
        struct net_device *const dev = bus->priv;
 
-       au1000_enable_mac(dev, 0); /* make sure the MAC associated with this
-                            * mii_bus is enabled */
+       /* make sure the MAC associated with this
+        * mii_bus is enabled
+        */
+       au1000_enable_mac(dev, 0);
+
        au1000_mdio_write(dev, phy_addr, regnum, value);
        return 0;
 }
@@ -250,28 +259,37 @@ static int au1000_mdiobus_reset(struct mii_bus *bus)
 {
        struct net_device *const dev = bus->priv;
 
-       au1000_enable_mac(dev, 0); /* make sure the MAC associated with this
-                            * mii_bus is enabled */
+       /* make sure the MAC associated with this
+        * mii_bus is enabled
+        */
+       au1000_enable_mac(dev, 0);
+
        return 0;
 }
 
 static void au1000_hard_stop(struct net_device *dev)
 {
        struct au1000_private *aup = netdev_priv(dev);
+       u32 reg;
 
        netif_dbg(aup, drv, dev, "hard stop\n");
 
-       aup->mac->control &= ~(MAC_RX_ENABLE | MAC_TX_ENABLE);
+       reg = readl(&aup->mac->control);
+       reg &= ~(MAC_RX_ENABLE | MAC_TX_ENABLE);
+       writel(reg, &aup->mac->control);
        au_sync_delay(10);
 }
 
 static void au1000_enable_rx_tx(struct net_device *dev)
 {
        struct au1000_private *aup = netdev_priv(dev);
+       u32 reg;
 
        netif_dbg(aup, hw, dev, "enable_rx_tx\n");
 
-       aup->mac->control |= (MAC_RX_ENABLE | MAC_TX_ENABLE);
+       reg = readl(&aup->mac->control);
+       reg |= (MAC_RX_ENABLE | MAC_TX_ENABLE);
+       writel(reg, &aup->mac->control);
        au_sync_delay(10);
 }
 
@@ -281,6 +299,7 @@ au1000_adjust_link(struct net_device *dev)
        struct au1000_private *aup = netdev_priv(dev);
        struct phy_device *phydev = aup->phy_dev;
        unsigned long flags;
+       u32 reg;
 
        int status_change = 0;
 
@@ -312,14 +331,15 @@ au1000_adjust_link(struct net_device *dev)
                /* switching duplex mode requires to disable rx and tx! */
                au1000_hard_stop(dev);
 
-               if (DUPLEX_FULL == phydev->duplex)
-                       aup->mac->control = ((aup->mac->control
-                                            | MAC_FULL_DUPLEX)
-                                            & ~MAC_DISABLE_RX_OWN);
-               else
-                       aup->mac->control = ((aup->mac->control
-                                             & ~MAC_FULL_DUPLEX)
-                                            | MAC_DISABLE_RX_OWN);
+               reg = readl(&aup->mac->control);
+               if (DUPLEX_FULL == phydev->duplex) {
+                       reg |= MAC_FULL_DUPLEX;
+                       reg &= ~MAC_DISABLE_RX_OWN;
+               } else {
+                       reg &= ~MAC_FULL_DUPLEX;
+                       reg |= MAC_DISABLE_RX_OWN;
+               }
+               writel(reg, &aup->mac->control);
                au_sync_delay(1);
 
                au1000_enable_rx_tx(dev);
@@ -353,10 +373,11 @@ au1000_adjust_link(struct net_device *dev)
        }
 }
 
-static int au1000_mii_probe (struct net_device *dev)
+static int au1000_mii_probe(struct net_device *dev)
 {
        struct au1000_private *const aup = netdev_priv(dev);
        struct phy_device *phydev = NULL;
+       int phy_addr;
 
        if (aup->phy_static_config) {
                BUG_ON(aup->mac_id < 0 || aup->mac_id > 1);
@@ -366,42 +387,46 @@ static int au1000_mii_probe (struct net_device *dev)
                else
                        netdev_info(dev, "using PHY-less setup\n");
                return 0;
-       } else {
-               int phy_addr;
-
-               /* find the first (lowest address) PHY on the current MAC's MII bus */
-               for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++)
-                       if (aup->mii_bus->phy_map[phy_addr]) {
-                               phydev = aup->mii_bus->phy_map[phy_addr];
-                               if (!aup->phy_search_highest_addr)
-                                       break; /* break out with first one found */
-                       }
-
-               if (aup->phy1_search_mac0) {
-                       /* try harder to find a PHY */
-                       if (!phydev && (aup->mac_id == 1)) {
-                               /* no PHY found, maybe we have a dual PHY? */
-                               dev_info(&dev->dev, ": no PHY found on MAC1, "
-                                       "let's see if it's attached to MAC0...\n");
-
-                               /* find the first (lowest address) non-attached PHY on
-                                * the MAC0 MII bus */
-                               for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) {
-                                       struct phy_device *const tmp_phydev =
-                                                       aup->mii_bus->phy_map[phy_addr];
-
-                                       if (aup->mac_id == 1)
-                                               break;
-
-                                       if (!tmp_phydev)
-                                               continue; /* no PHY here... */
+       }
 
-                                       if (tmp_phydev->attached_dev)
-                                               continue; /* already claimed by MAC0 */
+       /* find the first (lowest address) PHY
+        * on the current MAC's MII bus
+        */
+       for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++)
+               if (aup->mii_bus->phy_map[phy_addr]) {
+                       phydev = aup->mii_bus->phy_map[phy_addr];
+                       if (!aup->phy_search_highest_addr)
+                               /* break out with first one found */
+                               break;
+               }
 
-                                       phydev = tmp_phydev;
-                                       break; /* found it */
-                               }
+       if (aup->phy1_search_mac0) {
+               /* try harder to find a PHY */
+               if (!phydev && (aup->mac_id == 1)) {
+                       /* no PHY found, maybe we have a dual PHY? */
+                       dev_info(&dev->dev, ": no PHY found on MAC1, "
+                               "let's see if it's attached to MAC0...\n");
+
+                       /* find the first (lowest address) non-attached
+                        * PHY on the MAC0 MII bus
+                        */
+                       for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) {
+                               struct phy_device *const tmp_phydev =
+                                       aup->mii_bus->phy_map[phy_addr];
+
+                               if (aup->mac_id == 1)
+                                       break;
+
+                               /* no PHY here... */
+                               if (!tmp_phydev)
+                                       continue;
+
+                               /* already claimed by MAC0 */
+                               if (tmp_phydev->attached_dev)
+                                       continue;
+
+                               phydev = tmp_phydev;
+                               break; /* found it */
                        }
                }
        }
@@ -452,20 +477,20 @@ static int au1000_mii_probe (struct net_device *dev)
  * has the virtual and dma address of a buffer suitable for
  * both, receive and transmit operations.
  */
-static db_dest_t *au1000_GetFreeDB(struct au1000_private *aup)
+static struct db_dest *au1000_GetFreeDB(struct au1000_private *aup)
 {
-       db_dest_t *pDB;
+       struct db_dest *pDB;
        pDB = aup->pDBfree;
 
-       if (pDB) {
+       if (pDB)
                aup->pDBfree = pDB->pnext;
-       }
+
        return pDB;
 }
 
-void au1000_ReleaseDB(struct au1000_private *aup, db_dest_t *pDB)
+void au1000_ReleaseDB(struct au1000_private *aup, struct db_dest *pDB)
 {
-       db_dest_t *pDBfree = aup->pDBfree;
+       struct db_dest *pDBfree = aup->pDBfree;
        if (pDBfree)
                pDBfree->pnext = pDB;
        aup->pDBfree = pDB;
@@ -478,9 +503,9 @@ static void au1000_reset_mac_unlocked(struct net_device *dev)
 
        au1000_hard_stop(dev);
 
-       *aup->enable = MAC_EN_CLOCK_ENABLE;
+       writel(MAC_EN_CLOCK_ENABLE, &aup->enable);
        au_sync_delay(2);
-       *aup->enable = 0;
+       writel(0, &aup->enable);
        au_sync_delay(2);
 
        aup->tx_full = 0;
@@ -507,7 +532,7 @@ static void au1000_reset_mac(struct net_device *dev)
 
        spin_lock_irqsave(&aup->lock, flags);
 
-       au1000_reset_mac_unlocked (dev);
+       au1000_reset_mac_unlocked(dev);
 
        spin_unlock_irqrestore(&aup->lock, flags);
 }
@@ -524,11 +549,13 @@ au1000_setup_hw_rings(struct au1000_private *aup, u32 rx_base, u32 tx_base)
 
        for (i = 0; i < NUM_RX_DMA; i++) {
                aup->rx_dma_ring[i] =
-                       (volatile rx_dma_t *) (rx_base + sizeof(rx_dma_t)*i);
+                       (struct rx_dma *)
+                                       (rx_base + sizeof(struct rx_dma)*i);
        }
        for (i = 0; i < NUM_TX_DMA; i++) {
                aup->tx_dma_ring[i] =
-                       (volatile tx_dma_t *) (tx_base + sizeof(tx_dma_t)*i);
+                       (struct tx_dma *)
+                                       (tx_base + sizeof(struct tx_dma)*i);
        }
 }
 
@@ -616,18 +643,21 @@ static int au1000_init(struct net_device *dev)
 
        spin_lock_irqsave(&aup->lock, flags);
 
-       aup->mac->control = 0;
+       writel(0, &aup->mac->control);
        aup->tx_head = (aup->tx_dma_ring[0]->buff_stat & 0xC) >> 2;
        aup->tx_tail = aup->tx_head;
        aup->rx_head = (aup->rx_dma_ring[0]->buff_stat & 0xC) >> 2;
 
-       aup->mac->mac_addr_high = dev->dev_addr[5]<<8 | dev->dev_addr[4];
-       aup->mac->mac_addr_low = dev->dev_addr[3]<<24 | dev->dev_addr[2]<<16 |
-               dev->dev_addr[1]<<8 | dev->dev_addr[0];
+       writel(dev->dev_addr[5]<<8 | dev->dev_addr[4],
+                                       &aup->mac->mac_addr_high);
+       writel(dev->dev_addr[3]<<24 | dev->dev_addr[2]<<16 |
+               dev->dev_addr[1]<<8 | dev->dev_addr[0],
+                                       &aup->mac->mac_addr_low);
 
-       for (i = 0; i < NUM_RX_DMA; i++) {
+
+       for (i = 0; i < NUM_RX_DMA; i++)
                aup->rx_dma_ring[i]->buff_stat |= RX_DMA_ENABLE;
-       }
+
        au_sync();
 
        control = MAC_RX_ENABLE | MAC_TX_ENABLE;
@@ -643,8 +673,8 @@ static int au1000_init(struct net_device *dev)
                control |= MAC_FULL_DUPLEX;
        }
 
-       aup->mac->control = control;
-       aup->mac->vlan1_tag = 0x8100; /* activate vlan support */
+       writel(control, &aup->mac->control);
+       writel(0x8100, &aup->mac->vlan1_tag); /* activate vlan support */
        au_sync();
 
        spin_unlock_irqrestore(&aup->lock, flags);
@@ -681,9 +711,9 @@ static int au1000_rx(struct net_device *dev)
 {
        struct au1000_private *aup = netdev_priv(dev);
        struct sk_buff *skb;
-       volatile rx_dma_t *prxd;
+       struct rx_dma *prxd;
        u32 buff_stat, status;
-       db_dest_t *pDB;
+       struct db_dest *pDB;
        u32     frmlen;
 
        netif_dbg(aup, rx_status, dev, "au1000_rx head %d\n", aup->rx_head);
@@ -713,24 +743,26 @@ static int au1000_rx(struct net_device *dev)
                        netif_rx(skb);  /* pass the packet to upper layers */
                } else {
                        if (au1000_debug > 4) {
+                               pr_err("rx_error(s):");
                                if (status & RX_MISSED_FRAME)
-                                       printk("rx miss\n");
+                                       pr_cont(" miss");
                                if (status & RX_WDOG_TIMER)
-                                       printk("rx wdog\n");
+                                       pr_cont(" wdog");
                                if (status & RX_RUNT)
-                                       printk("rx runt\n");
+                                       pr_cont(" runt");
                                if (status & RX_OVERLEN)
-                                       printk("rx overlen\n");
+                                       pr_cont(" overlen");
                                if (status & RX_COLL)
-                                       printk("rx coll\n");
+                                       pr_cont(" coll");
                                if (status & RX_MII_ERROR)
-                                       printk("rx mii error\n");
+                                       pr_cont(" mii error");
                                if (status & RX_CRC_ERROR)
-                                       printk("rx crc error\n");
+                                       pr_cont(" crc error");
                                if (status & RX_LEN_ERROR)
-                                       printk("rx len error\n");
+                                       pr_cont(" len error");
                                if (status & RX_U_CNTRL_FRAME)
-                                       printk("rx u control frame\n");
+                                       pr_cont(" u control frame");
+                               pr_cont("\n");
                        }
                }
                prxd->buff_stat = (u32)(pDB->dma_addr | RX_DMA_ENABLE);
@@ -753,7 +785,8 @@ static void au1000_update_tx_stats(struct net_device *dev, u32 status)
                if (!aup->phy_dev || (DUPLEX_FULL == aup->phy_dev->duplex)) {
                        if (status & (TX_JAB_TIMEOUT | TX_UNDERRUN)) {
                                /* any other tx errors are only valid
-                                * in half duplex mode */
+                                * in half duplex mode
+                                */
                                ps->tx_errors++;
                                ps->tx_aborted_errors++;
                        }
@@ -774,7 +807,7 @@ static void au1000_update_tx_stats(struct net_device *dev, u32 status)
 static void au1000_tx_ack(struct net_device *dev)
 {
        struct au1000_private *aup = netdev_priv(dev);
-       volatile tx_dma_t *ptxd;
+       struct tx_dma *ptxd;
 
        ptxd = aup->tx_dma_ring[aup->tx_tail];
 
@@ -854,7 +887,7 @@ static int au1000_close(struct net_device *dev)
 
        spin_lock_irqsave(&aup->lock, flags);
 
-       au1000_reset_mac_unlocked (dev);
+       au1000_reset_mac_unlocked(dev);
 
        /* stop the device */
        netif_stop_queue(dev);
@@ -873,9 +906,9 @@ static netdev_tx_t au1000_tx(struct sk_buff *skb, struct net_device *dev)
 {
        struct au1000_private *aup = netdev_priv(dev);
        struct net_device_stats *ps = &dev->stats;
-       volatile tx_dma_t *ptxd;
+       struct tx_dma *ptxd;
        u32 buff_stat;
-       db_dest_t *pDB;
+       struct db_dest *pDB;
        int i;
 
        netif_dbg(aup, tx_queued, dev, "tx: aup %x len=%d, data=%p, head %d\n",
@@ -902,9 +935,9 @@ static netdev_tx_t au1000_tx(struct sk_buff *skb, struct net_device *dev)
        pDB = aup->tx_db_inuse[aup->tx_head];
        skb_copy_from_linear_data(skb, (void *)pDB->vaddr, skb->len);
        if (skb->len < ETH_ZLEN) {
-               for (i = skb->len; i < ETH_ZLEN; i++) {
+               for (i = skb->len; i < ETH_ZLEN; i++)
                        ((char *)pDB->vaddr)[i] = 0;
-               }
+
                ptxd->len = ETH_ZLEN;
        } else
                ptxd->len = skb->len;
@@ -935,15 +968,16 @@ static void au1000_tx_timeout(struct net_device *dev)
 static void au1000_multicast_list(struct net_device *dev)
 {
        struct au1000_private *aup = netdev_priv(dev);
+       u32 reg;
 
-       netif_dbg(aup, drv, dev, "au1000_multicast_list: flags=%x\n", dev->flags);
-
+       netif_dbg(aup, drv, dev, "%s: flags=%x\n", __func__, dev->flags);
+       reg = readl(&aup->mac->control);
        if (dev->flags & IFF_PROMISC) {                 /* Set promiscuous. */
-               aup->mac->control |= MAC_PROMISCUOUS;
+               reg |= MAC_PROMISCUOUS;
        } else if ((dev->flags & IFF_ALLMULTI)  ||
                           netdev_mc_count(dev) > MULTICAST_FILTER_LIMIT) {
-               aup->mac->control |= MAC_PASS_ALL_MULTI;
-               aup->mac->control &= ~MAC_PROMISCUOUS;
+               reg |= MAC_PASS_ALL_MULTI;
+               reg &= ~MAC_PROMISCUOUS;
                netdev_info(dev, "Pass all multicast\n");
        } else {
                struct netdev_hw_addr *ha;
@@ -953,11 +987,12 @@ static void au1000_multicast_list(struct net_device *dev)
                netdev_for_each_mc_addr(ha, dev)
                        set_bit(ether_crc(ETH_ALEN, ha->addr)>>26,
                                        (long *)mc_filter);
-               aup->mac->multi_hash_high = mc_filter[1];
-               aup->mac->multi_hash_low = mc_filter[0];
-               aup->mac->control &= ~MAC_PROMISCUOUS;
-               aup->mac->control |= MAC_HASH_MODE;
+               writel(mc_filter[1], &aup->mac->multi_hash_high);
+               writel(mc_filter[0], &aup->mac->multi_hash_low);
+               reg &= ~MAC_PROMISCUOUS;
+               reg |= MAC_HASH_MODE;
        }
+       writel(reg, &aup->mac->control);
 }
 
 static int au1000_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
@@ -991,7 +1026,7 @@ static int __devinit au1000_probe(struct platform_device *pdev)
        struct au1000_private *aup = NULL;
        struct au1000_eth_platform_data *pd;
        struct net_device *dev = NULL;
-       db_dest_t *pDB, *pDBfree;
+       struct db_dest *pDB, *pDBfree;
        int irq, i, err = 0;
        struct resource *base, *macen;
 
@@ -1016,13 +1051,15 @@ static int __devinit au1000_probe(struct platform_device *pdev)
                goto out;
        }
 
-       if (!request_mem_region(base->start, resource_size(base), pdev->name)) {
+       if (!request_mem_region(base->start, resource_size(base),
+                                                       pdev->name)) {
                dev_err(&pdev->dev, "failed to request memory region for base registers\n");
                err = -ENXIO;
                goto out;
        }
 
-       if (!request_mem_region(macen->start, resource_size(macen), pdev->name)) {
+       if (!request_mem_region(macen->start, resource_size(macen),
+                                                       pdev->name)) {
                dev_err(&pdev->dev, "failed to request memory region for MAC enable register\n");
                err = -ENXIO;
                goto err_request;
@@ -1040,10 +1077,12 @@ static int __devinit au1000_probe(struct platform_device *pdev)
        aup = netdev_priv(dev);
 
        spin_lock_init(&aup->lock);
-       aup->msg_enable = (au1000_debug < 4 ? AU1000_DEF_MSG_ENABLE : au1000_debug);
+       aup->msg_enable = (au1000_debug < 4 ?
+                               AU1000_DEF_MSG_ENABLE : au1000_debug);
 
-       /* Allocate the data buffers */
-       /* Snooping works fine with eth on all au1xxx */
+       /* Allocate the data buffers
+        * Snooping works fine with eth on all au1xxx
+        */
        aup->vaddr = (u32)dma_alloc_noncoherent(NULL, MAX_BUF_SIZE *
                                                (NUM_TX_BUFFS + NUM_RX_BUFFS),
                                                &aup->dma_addr, 0);
@@ -1054,15 +1093,17 @@ static int __devinit au1000_probe(struct platform_device *pdev)
        }
 
        /* aup->mac is the base address of the MAC's registers */
-       aup->mac = (volatile mac_reg_t *)ioremap_nocache(base->start, resource_size(base));
+       aup->mac = (struct mac_reg *)
+                       ioremap_nocache(base->start, resource_size(base));
        if (!aup->mac) {
                dev_err(&pdev->dev, "failed to ioremap MAC registers\n");
                err = -ENXIO;
                goto err_remap1;
        }
 
-        /* Setup some variables for quick register address access */
-       aup->enable = (volatile u32 *)ioremap_nocache(macen->start, resource_size(macen));
+       /* Setup some variables for quick register address access */
+       aup->enable = (u32 *)ioremap_nocache(macen->start,
+                                               resource_size(macen));
        if (!aup->enable) {
                dev_err(&pdev->dev, "failed to ioremap MAC enable register\n");
                err = -ENXIO;
@@ -1078,12 +1119,13 @@ static int __devinit au1000_probe(struct platform_device *pdev)
        /* set a random MAC now in case platform_data doesn't provide one */
        random_ether_addr(dev->dev_addr);
 
-       *aup->enable = 0;
+       writel(0, &aup->enable);
        aup->mac_enabled = 0;
 
        pd = pdev->dev.platform_data;
        if (!pd) {
-               dev_info(&pdev->dev, "no platform_data passed, PHY search on MAC0\n");
+               dev_info(&pdev->dev, "no platform_data passed,"
+                                       " PHY search on MAC0\n");
                aup->phy1_search_mac0 = 1;
        } else {
                if (is_valid_ether_addr(pd->mac))
@@ -1098,8 +1140,7 @@ static int __devinit au1000_probe(struct platform_device *pdev)
        }
 
        if (aup->phy_busid && aup->phy_busid > 0) {
-               dev_err(&pdev->dev, "MAC0-associated PHY attached 2nd MACs MII"
-                               "bus not supported yet\n");
+               dev_err(&pdev->dev, "MAC0-associated PHY attached 2nd MACs MII bus not supported yet\n");
                err = -ENODEV;
                goto err_mdiobus_alloc;
        }
@@ -1151,17 +1192,17 @@ static int __devinit au1000_probe(struct platform_device *pdev)
 
        for (i = 0; i < NUM_RX_DMA; i++) {
                pDB = au1000_GetFreeDB(aup);
-               if (!pDB) {
+               if (!pDB)
                        goto err_out;
-               }
+
                aup->rx_dma_ring[i]->buff_stat = (unsigned)pDB->dma_addr;
                aup->rx_db_inuse[i] = pDB;
        }
        for (i = 0; i < NUM_TX_DMA; i++) {
                pDB = au1000_GetFreeDB(aup);
-               if (!pDB) {
+               if (!pDB)
                        goto err_out;
-               }
+
                aup->tx_dma_ring[i]->buff_stat = (unsigned)pDB->dma_addr;
                aup->tx_dma_ring[i]->len = 0;
                aup->tx_db_inuse[i] = pDB;
@@ -1188,7 +1229,8 @@ static int __devinit au1000_probe(struct platform_device *pdev)
        netdev_info(dev, "Au1xx0 Ethernet found at 0x%lx, irq %d\n",
                        (unsigned long)base->start, irq);
        if (version_printed++ == 0)
-               printk("%s version %s %s\n", DRV_NAME, DRV_VERSION, DRV_AUTHOR);
+               pr_info("%s version %s %s\n",
+                                       DRV_NAME, DRV_VERSION, DRV_AUTHOR);
 
        return 0;
 
@@ -1197,7 +1239,8 @@ err_out:
                mdiobus_unregister(aup->mii_bus);
 
        /* here we should have a valid dev plus aup-> register addresses
-        * so we can reset the mac properly.*/
+        * so we can reset the mac properly.
+        */
        au1000_reset_mac(dev);
 
        for (i = 0; i < NUM_RX_DMA; i++) {
index d06ec008fbf1756dee1545225d26fe25902a4054..6229c774552cbe507c05866a8602a9a3e175ee72 100644 (file)
  * Data Buffer Descriptor. Data buffers must be aligned on 32 byte
  * boundary for both, receive and transmit.
  */
-typedef struct db_dest {
+struct db_dest {
        struct db_dest *pnext;
-       volatile u32 *vaddr;
+       u32 *vaddr;
        dma_addr_t dma_addr;
-} db_dest_t;
+};
 
 /*
  * The transmit and receive descriptors are memory
  * mapped registers.
  */
-typedef struct tx_dma {
+struct tx_dma {
        u32 status;
        u32 buff_stat;
        u32 len;
        u32 pad;
-} tx_dma_t;
+};
 
-typedef struct rx_dma {
+struct rx_dma {
        u32 status;
        u32 buff_stat;
        u32 pad[2];
-} rx_dma_t;
+};
 
 
 /*
  * MAC control registers, memory mapped.
  */
-typedef struct mac_reg {
+struct mac_reg {
        u32 control;
        u32 mac_addr_high;
        u32 mac_addr_low;
@@ -82,16 +82,16 @@ typedef struct mac_reg {
        u32 flow_control;
        u32 vlan1_tag;
        u32 vlan2_tag;
-} mac_reg_t;
+};
 
 
 struct au1000_private {
-       db_dest_t *pDBfree;
-       db_dest_t db[NUM_RX_BUFFS+NUM_TX_BUFFS];
-       volatile rx_dma_t *rx_dma_ring[NUM_RX_DMA];
-       volatile tx_dma_t *tx_dma_ring[NUM_TX_DMA];
-       db_dest_t *rx_db_inuse[NUM_RX_DMA];
-       db_dest_t *tx_db_inuse[NUM_TX_DMA];
+       struct db_dest *pDBfree;
+       struct db_dest db[NUM_RX_BUFFS+NUM_TX_BUFFS];
+       struct rx_dma *rx_dma_ring[NUM_RX_DMA];
+       struct tx_dma *tx_dma_ring[NUM_TX_DMA];
+       struct db_dest *rx_db_inuse[NUM_RX_DMA];
+       struct db_dest *tx_db_inuse[NUM_TX_DMA];
        u32 rx_head;
        u32 tx_head;
        u32 tx_tail;
@@ -99,7 +99,9 @@ struct au1000_private {
 
        int mac_id;
 
-       int mac_enabled;       /* whether MAC is currently enabled and running (req. for mdio) */
+       int mac_enabled;       /* whether MAC is currently enabled and running
+                               * (req. for mdio)
+                               */
 
        int old_link;          /* used by au1000_adjust_link */
        int old_speed;
@@ -117,9 +119,11 @@ struct au1000_private {
        int phy_busid;
        int phy_irq;
 
-       /* These variables are just for quick access to certain regs addresses. */
-       volatile mac_reg_t *mac;  /* mac registers                      */
-       volatile u32 *enable;     /* address of MAC Enable Register     */
+       /* These variables are just for quick access
+        * to certain regs addresses.
+        */
+       struct mac_reg *mac;  /* mac registers                      */
+       u32 *enable;     /* address of MAC Enable Register     */
 
        u32 vaddr;                /* virtual address of rx/tx buffers   */
        dma_addr_t dma_addr;      /* dma address of rx/tx buffers       */
index 1e620e287ae0cc9fbe9894a105fedbfdc9fbb6be..8e7c8a8e61c7756231191e6dc379732432a0e9b4 100644 (file)
@@ -818,7 +818,7 @@ static int b44_rx(struct b44 *bp, int budget)
                                                         copy_skb->data, len);
                        skb = copy_skb;
                }
-               skb->ip_summed = CHECKSUM_NONE;
+               skb_checksum_none_assert(skb);
                skb->protocol = eth_type_trans(skb, bp->dev);
                netif_receive_skb(skb);
                received++;
index 0d2c5da08937d33ad4a381e8a08ef04de378df86..ecfef240a303039390088f59b6425747377f1cdc 100644 (file)
@@ -293,22 +293,22 @@ static int bcm_enet_receive_queue(struct net_device *dev, int budget)
                /* if the packet does not have start of packet _and_
                 * end of packet flag set, then just recycle it */
                if ((len_stat & DMADESC_ESOP_MASK) != DMADESC_ESOP_MASK) {
-                       priv->stats.rx_dropped++;
+                       dev->stats.rx_dropped++;
                        continue;
                }
 
                /* recycle packet if it's marked as bad */
                if (unlikely(len_stat & DMADESC_ERR_MASK)) {
-                       priv->stats.rx_errors++;
+                       dev->stats.rx_errors++;
 
                        if (len_stat & DMADESC_OVSIZE_MASK)
-                               priv->stats.rx_length_errors++;
+                               dev->stats.rx_length_errors++;
                        if (len_stat & DMADESC_CRC_MASK)
-                               priv->stats.rx_crc_errors++;
+                               dev->stats.rx_crc_errors++;
                        if (len_stat & DMADESC_UNDER_MASK)
-                               priv->stats.rx_frame_errors++;
+                               dev->stats.rx_frame_errors++;
                        if (len_stat & DMADESC_OV_MASK)
-                               priv->stats.rx_fifo_errors++;
+                               dev->stats.rx_fifo_errors++;
                        continue;
                }
 
@@ -324,7 +324,7 @@ static int bcm_enet_receive_queue(struct net_device *dev, int budget)
                        nskb = netdev_alloc_skb_ip_align(dev, len);
                        if (!nskb) {
                                /* forget packet, just rearm desc */
-                               priv->stats.rx_dropped++;
+                               dev->stats.rx_dropped++;
                                continue;
                        }
 
@@ -342,8 +342,8 @@ static int bcm_enet_receive_queue(struct net_device *dev, int budget)
 
                skb_put(skb, len);
                skb->protocol = eth_type_trans(skb, dev);
-               priv->stats.rx_packets++;
-               priv->stats.rx_bytes += len;
+               dev->stats.rx_packets++;
+               dev->stats.rx_bytes += len;
                netif_receive_skb(skb);
 
        } while (--budget > 0);
@@ -403,7 +403,7 @@ static int bcm_enet_tx_reclaim(struct net_device *dev, int force)
                spin_unlock(&priv->tx_lock);
 
                if (desc->len_stat & DMADESC_UNDER_MASK)
-                       priv->stats.tx_errors++;
+                       dev->stats.tx_errors++;
 
                dev_kfree_skb(skb);
                released++;
@@ -563,8 +563,8 @@ static int bcm_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
        if (!priv->tx_desc_count)
                netif_stop_queue(dev);
 
-       priv->stats.tx_bytes += skb->len;
-       priv->stats.tx_packets++;
+       dev->stats.tx_bytes += skb->len;
+       dev->stats.tx_packets++;
        ret = NETDEV_TX_OK;
 
 out_unlock:
@@ -798,7 +798,7 @@ static int bcm_enet_open(struct net_device *dev)
                snprintf(phy_id, sizeof(phy_id), PHY_ID_FMT,
                         priv->mac_id ? "1" : "0", 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, 0,
                                     PHY_INTERFACE_MODE_MII);
 
                if (IS_ERR(phydev)) {
@@ -1140,17 +1140,6 @@ static int bcm_enet_stop(struct net_device *dev)
        return 0;
 }
 
-/*
- * core request to return device rx/tx stats
- */
-static struct net_device_stats *bcm_enet_get_stats(struct net_device *dev)
-{
-       struct bcm_enet_priv *priv;
-
-       priv = netdev_priv(dev);
-       return &priv->stats;
-}
-
 /*
  * ethtool callbacks
  */
@@ -1163,16 +1152,18 @@ struct bcm_enet_stats {
 
 #define GEN_STAT(m) sizeof(((struct bcm_enet_priv *)0)->m),            \
                     offsetof(struct bcm_enet_priv, m)
+#define DEV_STAT(m) sizeof(((struct net_device_stats *)0)->m),         \
+                    offsetof(struct net_device_stats, m)
 
 static const struct bcm_enet_stats bcm_enet_gstrings_stats[] = {
-       { "rx_packets", GEN_STAT(stats.rx_packets), -1 },
-       { "tx_packets", GEN_STAT(stats.tx_packets), -1 },
-       { "rx_bytes", GEN_STAT(stats.rx_bytes), -1 },
-       { "tx_bytes", GEN_STAT(stats.tx_bytes), -1 },
-       { "rx_errors", GEN_STAT(stats.rx_errors), -1 },
-       { "tx_errors", GEN_STAT(stats.tx_errors), -1 },
-       { "rx_dropped", GEN_STAT(stats.rx_dropped), -1 },
-       { "tx_dropped", GEN_STAT(stats.tx_dropped), -1 },
+       { "rx_packets", DEV_STAT(rx_packets), -1 },
+       { "tx_packets", DEV_STAT(tx_packets), -1 },
+       { "rx_bytes", DEV_STAT(rx_bytes), -1 },
+       { "tx_bytes", DEV_STAT(tx_bytes), -1 },
+       { "rx_errors", DEV_STAT(rx_errors), -1 },
+       { "tx_errors", DEV_STAT(tx_errors), -1 },
+       { "rx_dropped", DEV_STAT(rx_dropped), -1 },
+       { "tx_dropped", DEV_STAT(tx_dropped), -1 },
 
        { "rx_good_octets", GEN_STAT(mib.rx_gd_octets), ETH_MIB_RX_GD_OCTETS},
        { "rx_good_pkts", GEN_STAT(mib.rx_gd_pkts), ETH_MIB_RX_GD_PKTS },
@@ -1328,7 +1319,11 @@ static void bcm_enet_get_ethtool_stats(struct net_device *netdev,
                char *p;
 
                s = &bcm_enet_gstrings_stats[i];
-               p = (char *)priv + s->stat_offset;
+               if (s->mib_reg == -1)
+                       p = (char *)&netdev->stats;
+               else
+                       p = (char *)priv;
+               p += s->stat_offset;
                data[i] = (s->sizeof_stat == sizeof(u64)) ?
                        *(u64 *)p : *(u32 *)p;
        }
@@ -1605,7 +1600,6 @@ static const struct net_device_ops bcm_enet_ops = {
        .ndo_open               = bcm_enet_open,
        .ndo_stop               = bcm_enet_stop,
        .ndo_start_xmit         = bcm_enet_start_xmit,
-       .ndo_get_stats          = bcm_enet_get_stats,
        .ndo_set_mac_address    = bcm_enet_set_mac_address,
        .ndo_set_multicast_list = bcm_enet_set_multicast_list,
        .ndo_do_ioctl           = bcm_enet_ioctl,
index bd3684d42d748502760309dbdb6c0312c09d2267..0e3048b788c2c366595c9da160b344bbb6dd1fb0 100644 (file)
@@ -274,7 +274,6 @@ struct bcm_enet_priv {
        int pause_tx;
 
        /* stats */
-       struct net_device_stats stats;
        struct bcm_enet_mib_counters mib;
 
        /* after mib interrupt, mib registers update is done in this
index 53306bf3f401bee193fc89f5c6c4d1b35759ecb0..4faf6961dcec868ccda9f3ea15c168c29d1bd532 100644 (file)
@@ -414,6 +414,20 @@ static inline void be_check_sriov_fn_type(struct be_adapter *adapter)
        adapter->is_virtfn = (data != 0xAA);
 }
 
+static inline void be_vf_eth_addr_generate(struct be_adapter *adapter, u8 *mac)
+{
+       u32 addr;
+
+       addr = jhash(adapter->netdev->dev_addr, ETH_ALEN, 0);
+
+       mac[5] = (u8)(addr & 0xFF);
+       mac[4] = (u8)((addr >> 8) & 0xFF);
+       mac[3] = (u8)((addr >> 16) & 0xFF);
+       mac[2] = 0xC9;
+       mac[1] = 0x00;
+       mac[0] = 0x00;
+}
+
 extern void be_cq_notify(struct be_adapter *adapter, u16 qid, bool arm,
                u16 num_popped);
 extern void be_link_status_update(struct be_adapter *adapter, bool link_up);
index 13f0abbc520550b0b22ef48d0ed2a4da56d69187..d92063420c25f2cdb7b3cc81633f20113852d248 100644 (file)
@@ -91,6 +91,9 @@ static const struct be_ethtool_stat et_stats[] = {
        {PORTSTAT_INFO(rx_non_rss_packets)},
        {PORTSTAT_INFO(rx_ipv4_packets)},
        {PORTSTAT_INFO(rx_ipv6_packets)},
+       {PORTSTAT_INFO(rx_switched_unicast_packets)},
+       {PORTSTAT_INFO(rx_switched_multicast_packets)},
+       {PORTSTAT_INFO(rx_switched_broadcast_packets)},
        {PORTSTAT_INFO(tx_unicastframes)},
        {PORTSTAT_INFO(tx_multicastframes)},
        {PORTSTAT_INFO(tx_broadcastframes)},
index 6eda7a02225623943a35293cada545b8d20d752b..43a3a574e2e04509e51bd8e8f319affda5e7e70d 100644 (file)
@@ -365,11 +365,6 @@ static void be_rx_eqd_update(struct be_adapter *adapter)
        rx_eq->cur_eqd = eqd;
 }
 
-static struct net_device_stats *be_get_stats(struct net_device *dev)
-{
-       return &dev->stats;
-}
-
 static u32 be_calc_rate(u64 bytes, unsigned long ticks)
 {
        u64 rate = bytes;
@@ -1026,7 +1021,7 @@ static void be_rx_compl_process(struct be_adapter *adapter,
        skb_fill_rx_data(adapter, skb, rxcp, num_rcvd);
 
        if (do_pkt_csum(rxcp, adapter->rx_csum))
-               skb->ip_summed = CHECKSUM_NONE;
+               skb_checksum_none_assert(skb);
        else
                skb->ip_summed = CHECKSUM_UNNECESSARY;
 
@@ -2084,6 +2079,47 @@ static int be_setup_wol(struct be_adapter *adapter, bool enable)
        return status;
 }
 
+/*
+ * Generate a seed MAC address from the PF MAC Address using jhash.
+ * MAC Address for VFs are assigned incrementally starting from the seed.
+ * These addresses are programmed in the ASIC by the PF and the VF driver
+ * queries for the MAC address during its probe.
+ */
+static inline int be_vf_eth_addr_config(struct be_adapter *adapter)
+{
+       u32 vf = 0;
+       int status;
+       u8 mac[ETH_ALEN];
+
+       be_vf_eth_addr_generate(adapter, mac);
+
+       for (vf = 0; vf < num_vfs; vf++) {
+               status = be_cmd_pmac_add(adapter, mac,
+                                       adapter->vf_cfg[vf].vf_if_handle,
+                                       &adapter->vf_cfg[vf].vf_pmac_id);
+               if (status)
+                       dev_err(&adapter->pdev->dev,
+                               "Mac address add failed for VF %d\n", vf);
+               else
+                       memcpy(adapter->vf_cfg[vf].vf_mac_addr, mac, ETH_ALEN);
+
+               mac[5] += 1;
+       }
+       return status;
+}
+
+static inline void be_vf_eth_addr_rem(struct be_adapter *adapter)
+{
+       u32 vf;
+
+       for (vf = 0; vf < num_vfs; vf++) {
+               if (adapter->vf_cfg[vf].vf_pmac_id != BE_INVALID_PMAC_ID)
+                       be_cmd_pmac_del(adapter,
+                                       adapter->vf_cfg[vf].vf_if_handle,
+                                       adapter->vf_cfg[vf].vf_pmac_id);
+       }
+}
+
 static int be_setup(struct be_adapter *adapter)
 {
        struct net_device *netdev = adapter->netdev;
@@ -2143,10 +2179,20 @@ static int be_setup(struct be_adapter *adapter)
        if (status != 0)
                goto rx_qs_destroy;
 
+       if (be_physfn(adapter)) {
+               status = be_vf_eth_addr_config(adapter);
+               if (status)
+                       goto mcc_q_destroy;
+       }
+
        adapter->link_speed = -1;
 
        return 0;
 
+mcc_q_destroy:
+       if (be_physfn(adapter))
+               be_vf_eth_addr_rem(adapter);
+       be_mcc_queues_destroy(adapter);
 rx_qs_destroy:
        be_rx_queues_destroy(adapter);
 tx_qs_destroy:
@@ -2163,6 +2209,9 @@ do_none:
 
 static int be_clear(struct be_adapter *adapter)
 {
+       if (be_physfn(adapter))
+               be_vf_eth_addr_rem(adapter);
+
        be_mcc_queues_destroy(adapter);
        be_rx_queues_destroy(adapter);
        be_tx_queues_destroy(adapter);
@@ -2390,7 +2439,6 @@ static struct net_device_ops be_netdev_ops = {
        .ndo_open               = be_open,
        .ndo_stop               = be_close,
        .ndo_start_xmit         = be_xmit,
-       .ndo_get_stats          = be_get_stats,
        .ndo_set_rx_mode        = be_set_multicast_list,
        .ndo_set_mac_address    = be_mac_addr_set,
        .ndo_change_mtu         = be_change_mtu,
index 012613fde3f4d61f1217603a3bd811673f43d324..7a0e4156fade266ffbe1913c7ee0ad0ca639c0f9 100644 (file)
@@ -803,15 +803,14 @@ static void bfin_dump_hwtamp(char *s, ktime_t *hw, ktime_t *ts, struct timecompa
 static void bfin_tx_hwtstamp(struct net_device *netdev, struct sk_buff *skb)
 {
        struct bfin_mac_local *lp = netdev_priv(netdev);
-       union skb_shared_tx *shtx = skb_tx(skb);
 
-       if (shtx->hardware) {
+       if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) {
                int timeout_cnt = MAX_TIMEOUT_CNT;
 
                /* When doing time stamping, keep the connection to the socket
                 * a while longer
                 */
-               shtx->in_progress = 1;
+               skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
 
                /*
                 * The timestamping is done at the EMAC module's MII/RMII interface
@@ -991,7 +990,6 @@ static int bfin_mac_hard_start_xmit(struct sk_buff *skb,
        struct bfin_mac_local *lp = netdev_priv(dev);
        u16 *data;
        u32 data_align = (unsigned long)(skb->data) & 0x3;
-       union skb_shared_tx *shtx = skb_tx(skb);
 
        current_tx_ptr->skb = skb;
 
@@ -1005,7 +1003,7 @@ static int bfin_mac_hard_start_xmit(struct sk_buff *skb,
                 * of this field are the length of the packet payload in bytes and the higher
                 * 4 bits are the timestamping enable field.
                 */
-               if (shtx->hardware)
+               if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)
                        *data |= 0x1000;
 
                current_tx_ptr->desc_a.start_addr = (u32)data;
@@ -1015,7 +1013,7 @@ static int bfin_mac_hard_start_xmit(struct sk_buff *skb,
        } else {
                *((u16 *)(current_tx_ptr->packet)) = (u16)(skb->len);
                /* enable timestamping for the sent packet */
-               if (shtx->hardware)
+               if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)
                        *((u16 *)(current_tx_ptr->packet)) |= 0x1000;
                memcpy((u8 *)(current_tx_ptr->packet + 2), skb->data,
                        skb->len);
index 959add2410bf1787f8dff73ff786582be105831e..9322699bb31c64c800384701e3c4c20bab107aab 100644 (file)
@@ -1233,15 +1233,8 @@ static void bmac_reset_and_enable(struct net_device *dev)
        }
        spin_unlock_irqrestore(&bp->lock, flags);
 }
-static void bmac_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
-{
-       struct bmac_data *bp = netdev_priv(dev);
-       strcpy(info->driver, "bmac");
-       strcpy(info->bus_info, dev_name(&bp->mdev->ofdev.dev));
-}
 
 static const struct ethtool_ops bmac_ethtool_ops = {
-       .get_drvinfo            = bmac_get_drvinfo,
        .get_link               = ethtool_op_get_link,
 };
 
diff --git a/drivers/net/bna/Makefile b/drivers/net/bna/Makefile
new file mode 100644 (file)
index 0000000..a5d604d
--- /dev/null
@@ -0,0 +1,11 @@
+#
+# Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+# All rights reserved.
+#
+
+obj-$(CONFIG_BNA) += bna.o
+
+bna-objs := bnad.o bnad_ethtool.o bna_ctrl.o bna_txrx.o
+bna-objs += bfa_ioc.o bfa_ioc_ct.o bfa_cee.o cna_fwimg.o
+
+EXTRA_CFLAGS := -Idrivers/net/bna
diff --git a/drivers/net/bna/bfa_cee.c b/drivers/net/bna/bfa_cee.c
new file mode 100644 (file)
index 0000000..f7b789a
--- /dev/null
@@ -0,0 +1,291 @@
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * 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.
+ */
+/*
+ * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+
+#include "bfa_defs_cna.h"
+#include "cna.h"
+#include "bfa_cee.h"
+#include "bfi_cna.h"
+#include "bfa_ioc.h"
+
+#define bfa_ioc_portid(__ioc) ((__ioc)->port_id)
+#define bfa_lpuid(__arg) bfa_ioc_portid(&(__arg)->ioc)
+
+static void bfa_cee_format_lldp_cfg(struct bfa_cee_lldp_cfg *lldp_cfg);
+static void bfa_cee_format_cee_cfg(void *buffer);
+
+static void
+bfa_cee_format_cee_cfg(void *buffer)
+{
+       struct bfa_cee_attr *cee_cfg = buffer;
+       bfa_cee_format_lldp_cfg(&cee_cfg->lldp_remote);
+}
+
+static void
+bfa_cee_stats_swap(struct bfa_cee_stats *stats)
+{
+       u32 *buffer = (u32 *)stats;
+       int i;
+
+       for (i = 0; i < (sizeof(struct bfa_cee_stats) / sizeof(u32));
+               i++) {
+               buffer[i] = ntohl(buffer[i]);
+       }
+}
+
+static void
+bfa_cee_format_lldp_cfg(struct bfa_cee_lldp_cfg *lldp_cfg)
+{
+       lldp_cfg->time_to_live =
+                       ntohs(lldp_cfg->time_to_live);
+       lldp_cfg->enabled_system_cap =
+                       ntohs(lldp_cfg->enabled_system_cap);
+}
+
+/**
+ * bfa_cee_attr_meminfo()
+ *
+ * @brief Returns the size of the DMA memory needed by CEE attributes
+ *
+ * @param[in] void
+ *
+ * @return Size of DMA region
+ */
+static u32
+bfa_cee_attr_meminfo(void)
+{
+       return roundup(sizeof(struct bfa_cee_attr), BFA_DMA_ALIGN_SZ);
+}
+/**
+ * bfa_cee_stats_meminfo()
+ *
+ * @brief Returns the size of the DMA memory needed by CEE stats
+ *
+ * @param[in] void
+ *
+ * @return Size of DMA region
+ */
+static u32
+bfa_cee_stats_meminfo(void)
+{
+       return roundup(sizeof(struct bfa_cee_stats), BFA_DMA_ALIGN_SZ);
+}
+
+/**
+ * bfa_cee_get_attr_isr()
+ *
+ * @brief CEE ISR for get-attributes responses from f/w
+ *
+ * @param[in] cee - Pointer to the CEE module
+ *            status - Return status from the f/w
+ *
+ * @return void
+ */
+static void
+bfa_cee_get_attr_isr(struct bfa_cee *cee, enum bfa_status status)
+{
+       cee->get_attr_status = status;
+       if (status == BFA_STATUS_OK) {
+               memcpy(cee->attr, cee->attr_dma.kva,
+                   sizeof(struct bfa_cee_attr));
+               bfa_cee_format_cee_cfg(cee->attr);
+       }
+       cee->get_attr_pending = false;
+       if (cee->cbfn.get_attr_cbfn)
+               cee->cbfn.get_attr_cbfn(cee->cbfn.get_attr_cbarg, status);
+}
+
+/**
+ * bfa_cee_get_attr_isr()
+ *
+ * @brief CEE ISR for get-stats responses from f/w
+ *
+ * @param[in] cee - Pointer to the CEE module
+ *            status - Return status from the f/w
+ *
+ * @return void
+ */
+static void
+bfa_cee_get_stats_isr(struct bfa_cee *cee, enum bfa_status status)
+{
+       cee->get_stats_status = status;
+       if (status == BFA_STATUS_OK) {
+               memcpy(cee->stats, cee->stats_dma.kva,
+                       sizeof(struct bfa_cee_stats));
+               bfa_cee_stats_swap(cee->stats);
+       }
+       cee->get_stats_pending = false;
+       if (cee->cbfn.get_stats_cbfn)
+               cee->cbfn.get_stats_cbfn(cee->cbfn.get_stats_cbarg, status);
+}
+
+/**
+ * bfa_cee_get_attr_isr()
+ *
+ * @brief CEE ISR for reset-stats responses from f/w
+ *
+ * @param[in] cee - Pointer to the CEE module
+ *            status - Return status from the f/w
+ *
+ * @return void
+ */
+static void
+bfa_cee_reset_stats_isr(struct bfa_cee *cee, enum bfa_status status)
+{
+       cee->reset_stats_status = status;
+       cee->reset_stats_pending = false;
+       if (cee->cbfn.reset_stats_cbfn)
+               cee->cbfn.reset_stats_cbfn(cee->cbfn.reset_stats_cbarg, status);
+}
+/**
+ * bfa_nw_cee_meminfo()
+ *
+ * @brief Returns the size of the DMA memory needed by CEE module
+ *
+ * @param[in] void
+ *
+ * @return Size of DMA region
+ */
+u32
+bfa_nw_cee_meminfo(void)
+{
+       return bfa_cee_attr_meminfo() + bfa_cee_stats_meminfo();
+}
+
+/**
+ * bfa_nw_cee_mem_claim()
+ *
+ * @brief Initialized CEE DMA Memory
+ *
+ * @param[in] cee CEE module pointer
+ *           dma_kva Kernel Virtual Address of CEE DMA Memory
+ *           dma_pa  Physical Address of CEE DMA Memory
+ *
+ * @return void
+ */
+void
+bfa_nw_cee_mem_claim(struct bfa_cee *cee, u8 *dma_kva, u64 dma_pa)
+{
+       cee->attr_dma.kva = dma_kva;
+       cee->attr_dma.pa = dma_pa;
+       cee->stats_dma.kva = dma_kva + bfa_cee_attr_meminfo();
+       cee->stats_dma.pa = dma_pa + bfa_cee_attr_meminfo();
+       cee->attr = (struct bfa_cee_attr *) dma_kva;
+       cee->stats = (struct bfa_cee_stats *)
+               (dma_kva + bfa_cee_attr_meminfo());
+}
+
+/**
+ * bfa_cee_isrs()
+ *
+ * @brief Handles Mail-box interrupts for CEE module.
+ *
+ * @param[in] Pointer to the CEE module data structure.
+ *
+ * @return void
+ */
+
+static void
+bfa_cee_isr(void *cbarg, struct bfi_mbmsg *m)
+{
+       union bfi_cee_i2h_msg_u *msg;
+       struct bfi_cee_get_rsp *get_rsp;
+       struct bfa_cee *cee = (struct bfa_cee *) cbarg;
+       msg = (union bfi_cee_i2h_msg_u *) m;
+       get_rsp = (struct bfi_cee_get_rsp *) m;
+       switch (msg->mh.msg_id) {
+       case BFI_CEE_I2H_GET_CFG_RSP:
+               bfa_cee_get_attr_isr(cee, get_rsp->cmd_status);
+               break;
+       case BFI_CEE_I2H_GET_STATS_RSP:
+               bfa_cee_get_stats_isr(cee, get_rsp->cmd_status);
+               break;
+       case BFI_CEE_I2H_RESET_STATS_RSP:
+               bfa_cee_reset_stats_isr(cee, get_rsp->cmd_status);
+               break;
+       default:
+               BUG_ON(1);
+       }
+}
+
+/**
+ * bfa_cee_hbfail()
+ *
+ * @brief CEE module heart-beat failure handler.
+ *
+ * @param[in] Pointer to the CEE module data structure.
+ *
+ * @return void
+ */
+
+static void
+bfa_cee_hbfail(void *arg)
+{
+       struct bfa_cee *cee;
+       cee = (struct bfa_cee *) arg;
+
+       if (cee->get_attr_pending == true) {
+               cee->get_attr_status = BFA_STATUS_FAILED;
+               cee->get_attr_pending  = false;
+               if (cee->cbfn.get_attr_cbfn) {
+                       cee->cbfn.get_attr_cbfn(cee->cbfn.get_attr_cbarg,
+                           BFA_STATUS_FAILED);
+               }
+       }
+       if (cee->get_stats_pending == true) {
+               cee->get_stats_status = BFA_STATUS_FAILED;
+               cee->get_stats_pending  = false;
+               if (cee->cbfn.get_stats_cbfn) {
+                       cee->cbfn.get_stats_cbfn(cee->cbfn.get_stats_cbarg,
+                           BFA_STATUS_FAILED);
+               }
+       }
+       if (cee->reset_stats_pending == true) {
+               cee->reset_stats_status = BFA_STATUS_FAILED;
+               cee->reset_stats_pending  = false;
+               if (cee->cbfn.reset_stats_cbfn) {
+                       cee->cbfn.reset_stats_cbfn(cee->cbfn.reset_stats_cbarg,
+                           BFA_STATUS_FAILED);
+               }
+       }
+}
+
+/**
+ * bfa_nw_cee_attach()
+ *
+ * @brief CEE module-attach API
+ *
+ * @param[in] cee - Pointer to the CEE module data structure
+ *            ioc - Pointer to the ioc module data structure
+ *            dev - Pointer to the device driver module data structure
+ *                  The device driver specific mbox ISR functions have
+ *                  this pointer as one of the parameters.
+ *
+ * @return void
+ */
+void
+bfa_nw_cee_attach(struct bfa_cee *cee, struct bfa_ioc *ioc,
+               void *dev)
+{
+       BUG_ON(!(cee != NULL));
+       cee->dev = dev;
+       cee->ioc = ioc;
+
+       bfa_nw_ioc_mbox_regisr(cee->ioc, BFI_MC_CEE, bfa_cee_isr, cee);
+       bfa_ioc_hbfail_init(&cee->hbfail, bfa_cee_hbfail, cee);
+       bfa_nw_ioc_hbfail_register(cee->ioc, &cee->hbfail);
+}
diff --git a/drivers/net/bna/bfa_cee.h b/drivers/net/bna/bfa_cee.h
new file mode 100644 (file)
index 0000000..20543d1
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * 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.
+ */
+/*
+ * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+
+#ifndef __BFA_CEE_H__
+#define __BFA_CEE_H__
+
+#include "bfa_defs_cna.h"
+#include "bfa_ioc.h"
+
+typedef void (*bfa_cee_get_attr_cbfn_t) (void *dev, enum bfa_status status);
+typedef void (*bfa_cee_get_stats_cbfn_t) (void *dev, enum bfa_status status);
+typedef void (*bfa_cee_reset_stats_cbfn_t) (void *dev, enum bfa_status status);
+typedef void (*bfa_cee_hbfail_cbfn_t) (void *dev, enum bfa_status status);
+
+struct bfa_cee_cbfn {
+       bfa_cee_get_attr_cbfn_t    get_attr_cbfn;
+       void *get_attr_cbarg;
+       bfa_cee_get_stats_cbfn_t   get_stats_cbfn;
+       void *get_stats_cbarg;
+       bfa_cee_reset_stats_cbfn_t reset_stats_cbfn;
+       void *reset_stats_cbarg;
+};
+
+struct bfa_cee {
+       void *dev;
+       bool get_attr_pending;
+       bool get_stats_pending;
+       bool reset_stats_pending;
+       enum bfa_status get_attr_status;
+       enum bfa_status get_stats_status;
+       enum bfa_status reset_stats_status;
+       struct bfa_cee_cbfn cbfn;
+       struct bfa_ioc_hbfail_notify hbfail;
+       struct bfa_cee_attr *attr;
+       struct bfa_cee_stats *stats;
+       struct bfa_dma attr_dma;
+       struct bfa_dma stats_dma;
+       struct bfa_ioc *ioc;
+       struct bfa_mbox_cmd get_cfg_mb;
+       struct bfa_mbox_cmd get_stats_mb;
+       struct bfa_mbox_cmd reset_stats_mb;
+};
+
+u32 bfa_nw_cee_meminfo(void);
+void bfa_nw_cee_mem_claim(struct bfa_cee *cee, u8 *dma_kva,
+       u64 dma_pa);
+void bfa_nw_cee_attach(struct bfa_cee *cee, struct bfa_ioc *ioc, void *dev);
+
+#endif /* __BFA_CEE_H__ */
diff --git a/drivers/net/bna/bfa_defs.h b/drivers/net/bna/bfa_defs.h
new file mode 100644 (file)
index 0000000..29c1b8d
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * 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.
+ */
+/*
+ * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+
+#ifndef __BFA_DEFS_H__
+#define __BFA_DEFS_H__
+
+#include "cna.h"
+#include "bfa_defs_status.h"
+#include "bfa_defs_mfg_comm.h"
+
+#define BFA_STRING_32  32
+#define BFA_VERSION_LEN 64
+
+/**
+ * ---------------------- adapter definitions ------------
+ */
+
+/**
+ * BFA adapter level attributes.
+ */
+enum {
+       BFA_ADAPTER_SERIAL_NUM_LEN = STRSZ(BFA_MFG_SERIALNUM_SIZE),
+                                       /*
+                                        *!< adapter serial num length
+                                        */
+       BFA_ADAPTER_MODEL_NAME_LEN  = 16,  /*!< model name length */
+       BFA_ADAPTER_MODEL_DESCR_LEN = 128, /*!< model description length */
+       BFA_ADAPTER_MFG_NAME_LEN    = 8,   /*!< manufacturer name length */
+       BFA_ADAPTER_SYM_NAME_LEN    = 64,  /*!< adapter symbolic name length */
+       BFA_ADAPTER_OS_TYPE_LEN     = 64,  /*!< adapter os type length */
+};
+
+struct bfa_adapter_attr {
+       char            manufacturer[BFA_ADAPTER_MFG_NAME_LEN];
+       char            serial_num[BFA_ADAPTER_SERIAL_NUM_LEN];
+       u32     card_type;
+       char            model[BFA_ADAPTER_MODEL_NAME_LEN];
+       char            model_descr[BFA_ADAPTER_MODEL_DESCR_LEN];
+       u64             pwwn;
+       char            node_symname[FC_SYMNAME_MAX];
+       char            hw_ver[BFA_VERSION_LEN];
+       char            fw_ver[BFA_VERSION_LEN];
+       char            optrom_ver[BFA_VERSION_LEN];
+       char            os_type[BFA_ADAPTER_OS_TYPE_LEN];
+       struct bfa_mfg_vpd vpd;
+       struct mac mac;
+
+       u8              nports;
+       u8              max_speed;
+       u8              prototype;
+       char            asic_rev;
+
+       u8              pcie_gen;
+       u8              pcie_lanes_orig;
+       u8              pcie_lanes;
+       u8              cna_capable;
+
+       u8              is_mezz;
+       u8              trunk_capable;
+};
+
+/**
+ * ---------------------- IOC definitions ------------
+ */
+
+enum {
+       BFA_IOC_DRIVER_LEN      = 16,
+       BFA_IOC_CHIP_REV_LEN    = 8,
+};
+
+/**
+ * Driver and firmware versions.
+ */
+struct bfa_ioc_driver_attr {
+       char            driver[BFA_IOC_DRIVER_LEN];     /*!< driver name */
+       char            driver_ver[BFA_VERSION_LEN];    /*!< driver version */
+       char            fw_ver[BFA_VERSION_LEN];        /*!< firmware version */
+       char            bios_ver[BFA_VERSION_LEN];      /*!< bios version */
+       char            efi_ver[BFA_VERSION_LEN];       /*!< EFI version */
+       char            ob_ver[BFA_VERSION_LEN];        /*!< openboot version */
+};
+
+/**
+ * IOC PCI device attributes
+ */
+struct bfa_ioc_pci_attr {
+       u16     vendor_id;      /*!< PCI vendor ID */
+       u16     device_id;      /*!< PCI device ID */
+       u16     ssid;           /*!< subsystem ID */
+       u16     ssvid;          /*!< subsystem vendor ID */
+       u32     pcifn;          /*!< PCI device function */
+       u32     rsvd;           /* padding */
+       char            chip_rev[BFA_IOC_CHIP_REV_LEN];  /*!< chip revision */
+};
+
+/**
+ * IOC states
+ */
+enum bfa_ioc_state {
+       BFA_IOC_RESET           = 1,    /*!< IOC is in reset state */
+       BFA_IOC_SEMWAIT         = 2,    /*!< Waiting for IOC h/w semaphore */
+       BFA_IOC_HWINIT          = 3,    /*!< IOC h/w is being initialized */
+       BFA_IOC_GETATTR         = 4,    /*!< IOC is being configured */
+       BFA_IOC_OPERATIONAL     = 5,    /*!< IOC is operational */
+       BFA_IOC_INITFAIL        = 6,    /*!< IOC hardware failure */
+       BFA_IOC_HBFAIL          = 7,    /*!< IOC heart-beat failure */
+       BFA_IOC_DISABLING       = 8,    /*!< IOC is being disabled */
+       BFA_IOC_DISABLED        = 9,    /*!< IOC is disabled */
+       BFA_IOC_FWMISMATCH      = 10,   /*!< IOC f/w different from drivers */
+};
+
+/**
+ * IOC firmware stats
+ */
+struct bfa_fw_ioc_stats {
+       u32     enable_reqs;
+       u32     disable_reqs;
+       u32     get_attr_reqs;
+       u32     dbg_sync;
+       u32     dbg_dump;
+       u32     unknown_reqs;
+};
+
+/**
+ * IOC driver stats
+ */
+struct bfa_ioc_drv_stats {
+       u32     ioc_isrs;
+       u32     ioc_enables;
+       u32     ioc_disables;
+       u32     ioc_hbfails;
+       u32     ioc_boots;
+       u32     stats_tmos;
+       u32     hb_count;
+       u32     disable_reqs;
+       u32     enable_reqs;
+       u32     disable_replies;
+       u32     enable_replies;
+};
+
+/**
+ * IOC statistics
+ */
+struct bfa_ioc_stats {
+       struct bfa_ioc_drv_stats drv_stats; /*!< driver IOC stats */
+       struct bfa_fw_ioc_stats fw_stats;  /*!< firmware IOC stats */
+};
+
+enum bfa_ioc_type {
+       BFA_IOC_TYPE_FC         = 1,
+       BFA_IOC_TYPE_FCoE       = 2,
+       BFA_IOC_TYPE_LL         = 3,
+};
+
+/**
+ * IOC attributes returned in queries
+ */
+struct bfa_ioc_attr {
+       enum bfa_ioc_type ioc_type;
+       enum bfa_ioc_state              state;          /*!< IOC state      */
+       struct bfa_adapter_attr adapter_attr;   /*!< HBA attributes */
+       struct bfa_ioc_driver_attr driver_attr; /*!< driver attr    */
+       struct bfa_ioc_pci_attr pci_attr;
+       u8                              port_id;        /*!< port number    */
+       u8                              rsvd[7];        /*!< 64bit align    */
+};
+
+/**
+ * ---------------------- mfg definitions ------------
+ */
+
+/**
+ * Checksum size
+ */
+#define BFA_MFG_CHKSUM_SIZE                    16
+
+#define BFA_MFG_PARTNUM_SIZE                   14
+#define BFA_MFG_SUPPLIER_ID_SIZE               10
+#define BFA_MFG_SUPPLIER_PARTNUM_SIZE          20
+#define BFA_MFG_SUPPLIER_SERIALNUM_SIZE                20
+#define BFA_MFG_SUPPLIER_REVISION_SIZE         4
+
+#pragma pack(1)
+
+/**
+ * @brief BFA adapter manufacturing block definition.
+ *
+ * All numerical fields are in big-endian format.
+ */
+struct bfa_mfg_block {
+       u8              version;        /*!< manufacturing block version */
+       u8              mfg_sig[3];     /*!< characters 'M', 'F', 'G' */
+       u16     mfgsize;        /*!< mfg block size */
+       u16     u16_chksum;     /*!< old u16 checksum */
+       char            brcd_serialnum[STRSZ(BFA_MFG_SERIALNUM_SIZE)];
+       char            brcd_partnum[STRSZ(BFA_MFG_PARTNUM_SIZE)];
+       u8              mfg_day;        /*!< manufacturing day */
+       u8              mfg_month;      /*!< manufacturing month */
+       u16     mfg_year;       /*!< manufacturing year */
+       u64             mfg_wwn;        /*!< wwn base for this adapter */
+       u8              num_wwn;        /*!< number of wwns assigned */
+       u8              mfg_speeds;     /*!< speeds allowed for this adapter */
+       u8              rsv[2];
+       char            supplier_id[STRSZ(BFA_MFG_SUPPLIER_ID_SIZE)];
+       char            supplier_partnum[STRSZ(BFA_MFG_SUPPLIER_PARTNUM_SIZE)];
+       char
+               supplier_serialnum[STRSZ(BFA_MFG_SUPPLIER_SERIALNUM_SIZE)];
+       char
+               supplier_revision[STRSZ(BFA_MFG_SUPPLIER_REVISION_SIZE)];
+       mac_t           mfg_mac;        /*!< mac address */
+       u8              num_mac;        /*!< number of mac addresses */
+       u8              rsv2;
+       u32     mfg_type;       /*!< card type */
+       u8              rsv3[108];
+       u8              md5_chksum[BFA_MFG_CHKSUM_SIZE]; /*!< md5 checksum */
+};
+
+#pragma pack()
+
+/**
+ * ---------------------- pci definitions ------------
+ */
+
+#define bfa_asic_id_ct(devid)                  \
+       ((devid) == PCI_DEVICE_ID_BROCADE_CT || \
+       (devid) == PCI_DEVICE_ID_BROCADE_CT_FC)
+
+#endif /* __BFA_DEFS_H__ */
diff --git a/drivers/net/bna/bfa_defs_cna.h b/drivers/net/bna/bfa_defs_cna.h
new file mode 100644 (file)
index 0000000..7e0a918
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * 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.
+ */
+/*
+ * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+
+#ifndef __BFA_DEFS_CNA_H__
+#define __BFA_DEFS_CNA_H__
+
+#include "bfa_defs.h"
+
+/**
+ * @brief
+ * FC physical port statistics.
+ */
+struct bfa_port_fc_stats {
+       u64     secs_reset;     /*!< Seconds since stats is reset */
+       u64     tx_frames;      /*!< Tx frames                  */
+       u64     tx_words;       /*!< Tx words                   */
+       u64     tx_lip;         /*!< Tx LIP                     */
+       u64     tx_nos;         /*!< Tx NOS                     */
+       u64     tx_ols;         /*!< Tx OLS                     */
+       u64     tx_lr;          /*!< Tx LR                      */
+       u64     tx_lrr;         /*!< Tx LRR                     */
+       u64     rx_frames;      /*!< Rx frames                  */
+       u64     rx_words;       /*!< Rx words                   */
+       u64     lip_count;      /*!< Rx LIP                     */
+       u64     nos_count;      /*!< Rx NOS                     */
+       u64     ols_count;      /*!< Rx OLS                     */
+       u64     lr_count;       /*!< Rx LR                      */
+       u64     lrr_count;      /*!< Rx LRR                     */
+       u64     invalid_crcs;   /*!< Rx CRC err frames          */
+       u64     invalid_crc_gd_eof; /*!< Rx CRC err good EOF frames */
+       u64     undersized_frm; /*!< Rx undersized frames       */
+       u64     oversized_frm;  /*!< Rx oversized frames        */
+       u64     bad_eof_frm;    /*!< Rx frames with bad EOF     */
+       u64     error_frames;   /*!< Errored frames             */
+       u64     dropped_frames; /*!< Dropped frames             */
+       u64     link_failures;  /*!< Link Failure (LF) count    */
+       u64     loss_of_syncs;  /*!< Loss of sync count         */
+       u64     loss_of_signals; /*!< Loss of signal count      */
+       u64     primseq_errs;   /*!< Primitive sequence protocol err. */
+       u64     bad_os_count;   /*!< Invalid ordered sets       */
+       u64     err_enc_out;    /*!< Encoding err nonframe_8b10b */
+       u64     err_enc;        /*!< Encoding err frame_8b10b   */
+};
+
+/**
+ * @brief
+ * Eth Physical Port statistics.
+ */
+struct bfa_port_eth_stats {
+       u64     secs_reset;     /*!< Seconds since stats is reset */
+       u64     frame_64;       /*!< Frames 64 bytes            */
+       u64     frame_65_127;   /*!< Frames 65-127 bytes        */
+       u64     frame_128_255;  /*!< Frames 128-255 bytes       */
+       u64     frame_256_511;  /*!< Frames 256-511 bytes       */
+       u64     frame_512_1023; /*!< Frames 512-1023 bytes      */
+       u64     frame_1024_1518; /*!< Frames 1024-1518 bytes    */
+       u64     frame_1519_1522; /*!< Frames 1519-1522 bytes    */
+       u64     tx_bytes;       /*!< Tx bytes                   */
+       u64     tx_packets;      /*!< Tx packets                */
+       u64     tx_mcast_packets; /*!< Tx multicast packets     */
+       u64     tx_bcast_packets; /*!< Tx broadcast packets     */
+       u64     tx_control_frame; /*!< Tx control frame         */
+       u64     tx_drop;        /*!< Tx drops                   */
+       u64     tx_jabber;      /*!< Tx jabber                  */
+       u64     tx_fcs_error;   /*!< Tx FCS errors              */
+       u64     tx_fragments;   /*!< Tx fragments               */
+       u64     rx_bytes;       /*!< Rx bytes                   */
+       u64     rx_packets;     /*!< Rx packets                 */
+       u64     rx_mcast_packets; /*!< Rx multicast packets     */
+       u64     rx_bcast_packets; /*!< Rx broadcast packets     */
+       u64     rx_control_frames; /*!< Rx control frames       */
+       u64     rx_unknown_opcode; /*!< Rx unknown opcode       */
+       u64     rx_drop;        /*!< Rx drops                   */
+       u64     rx_jabber;      /*!< Rx jabber                  */
+       u64     rx_fcs_error;   /*!< Rx FCS errors              */
+       u64     rx_alignment_error; /*!< Rx alignment errors    */
+       u64     rx_frame_length_error; /*!< Rx frame len errors */
+       u64     rx_code_error;  /*!< Rx code errors             */
+       u64     rx_fragments;   /*!< Rx fragments               */
+       u64     rx_pause;       /*!< Rx pause                   */
+       u64     rx_zero_pause;  /*!< Rx zero pause              */
+       u64     tx_pause;       /*!< Tx pause                   */
+       u64     tx_zero_pause;  /*!< Tx zero pause              */
+       u64     rx_fcoe_pause;  /*!< Rx FCoE pause              */
+       u64     rx_fcoe_zero_pause; /*!< Rx FCoE zero pause     */
+       u64     tx_fcoe_pause;  /*!< Tx FCoE pause              */
+       u64     tx_fcoe_zero_pause; /*!< Tx FCoE zero pause     */
+};
+
+/**
+ * @brief
+ *             Port statistics.
+ */
+union bfa_port_stats_u {
+       struct bfa_port_fc_stats fc;
+       struct bfa_port_eth_stats eth;
+};
+
+#pragma pack(1)
+
+#define BFA_CEE_LLDP_MAX_STRING_LEN (128)
+#define BFA_CEE_DCBX_MAX_PRIORITY      (8)
+#define BFA_CEE_DCBX_MAX_PGID          (8)
+
+#define BFA_CEE_LLDP_SYS_CAP_OTHER     0x0001
+#define BFA_CEE_LLDP_SYS_CAP_REPEATER  0x0002
+#define BFA_CEE_LLDP_SYS_CAP_MAC_BRIDGE        0x0004
+#define BFA_CEE_LLDP_SYS_CAP_WLAN_AP   0x0008
+#define BFA_CEE_LLDP_SYS_CAP_ROUTER    0x0010
+#define BFA_CEE_LLDP_SYS_CAP_TELEPHONE 0x0020
+#define BFA_CEE_LLDP_SYS_CAP_DOCSIS_CD 0x0040
+#define BFA_CEE_LLDP_SYS_CAP_STATION   0x0080
+#define BFA_CEE_LLDP_SYS_CAP_CVLAN     0x0100
+#define BFA_CEE_LLDP_SYS_CAP_SVLAN     0x0200
+#define BFA_CEE_LLDP_SYS_CAP_TPMR      0x0400
+
+/* LLDP string type */
+struct bfa_cee_lldp_str {
+       u8 sub_type;
+       u8 len;
+       u8 rsvd[2];
+       u8 value[BFA_CEE_LLDP_MAX_STRING_LEN];
+};
+
+/* LLDP paramters */
+struct bfa_cee_lldp_cfg {
+       struct bfa_cee_lldp_str chassis_id;
+       struct bfa_cee_lldp_str port_id;
+       struct bfa_cee_lldp_str port_desc;
+       struct bfa_cee_lldp_str sys_name;
+       struct bfa_cee_lldp_str sys_desc;
+       struct bfa_cee_lldp_str mgmt_addr;
+       u16 time_to_live;
+       u16 enabled_system_cap;
+};
+
+enum bfa_cee_dcbx_version {
+       DCBX_PROTOCOL_PRECEE    = 1,
+       DCBX_PROTOCOL_CEE       = 2,
+};
+
+enum bfa_cee_lls {
+       /* LLS is down because the TLV not sent by the peer */
+       CEE_LLS_DOWN_NO_TLV = 0,
+       /* LLS is down as advertised by the peer */
+       CEE_LLS_DOWN    = 1,
+       CEE_LLS_UP      = 2,
+};
+
+/* CEE/DCBX parameters */
+struct bfa_cee_dcbx_cfg {
+       u8 pgid[BFA_CEE_DCBX_MAX_PRIORITY];
+       u8 pg_percentage[BFA_CEE_DCBX_MAX_PGID];
+       u8 pfc_primap; /* bitmap of priorties with PFC enabled */
+       u8 fcoe_primap; /* bitmap of priorities used for FcoE traffic */
+       u8 iscsi_primap; /* bitmap of priorities used for iSCSI traffic */
+       u8 dcbx_version; /* operating version:CEE or preCEE */
+       u8 lls_fcoe; /* FCoE Logical Link Status */
+       u8 lls_lan; /* LAN Logical Link Status */
+       u8 rsvd[2];
+};
+
+/* CEE status */
+/* Making this to tri-state for the benefit of port list command */
+enum bfa_cee_status {
+       CEE_UP = 0,
+       CEE_PHY_UP = 1,
+       CEE_LOOPBACK = 2,
+       CEE_PHY_DOWN = 3,
+};
+
+/* CEE Query */
+struct bfa_cee_attr {
+       u8      cee_status;
+       u8 error_reason;
+       struct bfa_cee_lldp_cfg lldp_remote;
+       struct bfa_cee_dcbx_cfg dcbx_remote;
+       mac_t src_mac;
+       u8 link_speed;
+       u8 nw_priority;
+       u8 filler[2];
+};
+
+/* LLDP/DCBX/CEE Statistics */
+struct bfa_cee_stats {
+       u32     lldp_tx_frames;         /*!< LLDP Tx Frames */
+       u32     lldp_rx_frames;         /*!< LLDP Rx Frames */
+       u32     lldp_rx_frames_invalid; /*!< LLDP Rx Frames invalid */
+       u32     lldp_rx_frames_new;     /*!< LLDP Rx Frames new */
+       u32     lldp_tlvs_unrecognized; /*!< LLDP Rx unrecognized TLVs */
+       u32     lldp_rx_shutdown_tlvs;  /*!< LLDP Rx shutdown TLVs */
+       u32     lldp_info_aged_out;     /*!< LLDP remote info aged out */
+       u32     dcbx_phylink_ups;       /*!< DCBX phy link ups */
+       u32     dcbx_phylink_downs;     /*!< DCBX phy link downs */
+       u32     dcbx_rx_tlvs;           /*!< DCBX Rx TLVs */
+       u32     dcbx_rx_tlvs_invalid;   /*!< DCBX Rx TLVs invalid */
+       u32     dcbx_control_tlv_error; /*!< DCBX control TLV errors */
+       u32     dcbx_feature_tlv_error; /*!< DCBX feature TLV errors */
+       u32     dcbx_cee_cfg_new;       /*!< DCBX new CEE cfg rcvd */
+       u32     cee_status_down;        /*!< CEE status down */
+       u32     cee_status_up;          /*!< CEE status up */
+       u32     cee_hw_cfg_changed;     /*!< CEE hw cfg changed */
+       u32     cee_rx_invalid_cfg;     /*!< CEE invalid cfg */
+};
+
+#pragma pack()
+
+#endif /* __BFA_DEFS_CNA_H__ */
diff --git a/drivers/net/bna/bfa_defs_mfg_comm.h b/drivers/net/bna/bfa_defs_mfg_comm.h
new file mode 100644 (file)
index 0000000..987978f
--- /dev/null
@@ -0,0 +1,244 @@
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * 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.
+ */
+/*
+ * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+#ifndef __BFA_DEFS_MFG_COMM_H__
+#define __BFA_DEFS_MFG_COMM_H__
+
+#include "cna.h"
+
+/**
+ * Manufacturing block version
+ */
+#define BFA_MFG_VERSION                                2
+#define BFA_MFG_VERSION_UNINIT                 0xFF
+
+/**
+ * Manufacturing block encrypted version
+ */
+#define BFA_MFG_ENC_VER                                2
+
+/**
+ * Manufacturing block version 1 length
+ */
+#define BFA_MFG_VER1_LEN                       128
+
+/**
+ * Manufacturing block header length
+ */
+#define BFA_MFG_HDR_LEN                                4
+
+#define BFA_MFG_SERIALNUM_SIZE                 11
+#define STRSZ(_n)                              (((_n) + 4) & ~3)
+
+/**
+ * Manufacturing card type
+ */
+enum {
+       BFA_MFG_TYPE_CB_MAX  = 825,      /*!< Crossbow card type max    */
+       BFA_MFG_TYPE_FC8P2   = 825,      /*!< 8G 2port FC card          */
+       BFA_MFG_TYPE_FC8P1   = 815,      /*!< 8G 1port FC card          */
+       BFA_MFG_TYPE_FC4P2   = 425,      /*!< 4G 2port FC card          */
+       BFA_MFG_TYPE_FC4P1   = 415,      /*!< 4G 1port FC card          */
+       BFA_MFG_TYPE_CNA10P2 = 1020,     /*!< 10G 2port CNA card        */
+       BFA_MFG_TYPE_CNA10P1 = 1010,     /*!< 10G 1port CNA card        */
+       BFA_MFG_TYPE_JAYHAWK = 804,      /*!< Jayhawk mezz card         */
+       BFA_MFG_TYPE_WANCHESE = 1007,    /*!< Wanchese mezz card        */
+       BFA_MFG_TYPE_ASTRA    = 807,     /*!< Astra mezz card           */
+       BFA_MFG_TYPE_LIGHTNING_P0 = 902, /*!< Lightning mezz card - old */
+       BFA_MFG_TYPE_LIGHTNING = 1741,   /*!< Lightning mezz card       */
+       BFA_MFG_TYPE_INVALID = 0,        /*!< Invalid card type         */
+};
+
+#pragma pack(1)
+
+/**
+ * Check if 1-port card
+ */
+#define bfa_mfg_is_1port(type) (( \
+       (type) == BFA_MFG_TYPE_FC8P1 || \
+       (type) == BFA_MFG_TYPE_FC4P1 || \
+       (type) == BFA_MFG_TYPE_CNA10P1))
+
+/**
+ * Check if Mezz card
+ */
+#define bfa_mfg_is_mezz(type) (( \
+       (type) == BFA_MFG_TYPE_JAYHAWK || \
+       (type) == BFA_MFG_TYPE_WANCHESE || \
+       (type) == BFA_MFG_TYPE_ASTRA || \
+       (type) == BFA_MFG_TYPE_LIGHTNING_P0 || \
+       (type) == BFA_MFG_TYPE_LIGHTNING))
+
+/**
+ * Check if card type valid
+ */
+#define bfa_mfg_is_card_type_valid(type) (( \
+       (type) == BFA_MFG_TYPE_FC8P2 || \
+       (type) == BFA_MFG_TYPE_FC8P1 || \
+       (type) == BFA_MFG_TYPE_FC4P2 || \
+       (type) == BFA_MFG_TYPE_FC4P1 || \
+       (type) == BFA_MFG_TYPE_CNA10P2 || \
+       (type) == BFA_MFG_TYPE_CNA10P1 || \
+       bfa_mfg_is_mezz(type)))
+
+/**
+ * Check if the card having old wwn/mac handling
+ */
+#define bfa_mfg_is_old_wwn_mac_model(type) (( \
+       (type) == BFA_MFG_TYPE_FC8P2 || \
+       (type) == BFA_MFG_TYPE_FC8P1 || \
+       (type) == BFA_MFG_TYPE_FC4P2 || \
+       (type) == BFA_MFG_TYPE_FC4P1 || \
+       (type) == BFA_MFG_TYPE_CNA10P2 || \
+       (type) == BFA_MFG_TYPE_CNA10P1 || \
+       (type) == BFA_MFG_TYPE_JAYHAWK || \
+       (type) == BFA_MFG_TYPE_WANCHESE))
+
+#define bfa_mfg_increment_wwn_mac(m, i)                                \
+do {                                                           \
+       u32 t = ((m)[0] << 16) | ((m)[1] << 8) | (m)[2];        \
+       t += (i);                                               \
+       (m)[0] = (t >> 16) & 0xFF;                              \
+       (m)[1] = (t >> 8) & 0xFF;                               \
+       (m)[2] = t & 0xFF;                                      \
+} while (0)
+
+#define bfa_mfg_adapter_prop_init_flash(card_type, prop)       \
+do {                                                           \
+       switch ((card_type)) {                                  \
+       case BFA_MFG_TYPE_FC8P2:                                \
+       case BFA_MFG_TYPE_JAYHAWK:                              \
+       case BFA_MFG_TYPE_ASTRA:                                \
+               (prop) = BFI_ADAPTER_SETP(NPORTS, 2) |          \
+                       BFI_ADAPTER_SETP(SPEED, 8);             \
+               break;                                          \
+       case BFA_MFG_TYPE_FC8P1:                                \
+               (prop) = BFI_ADAPTER_SETP(NPORTS, 1) |          \
+                       BFI_ADAPTER_SETP(SPEED, 8);             \
+               break;                                          \
+       case BFA_MFG_TYPE_FC4P2:                                \
+               (prop) = BFI_ADAPTER_SETP(NPORTS, 2) |          \
+                       BFI_ADAPTER_SETP(SPEED, 4);             \
+               break;                                          \
+       case BFA_MFG_TYPE_FC4P1:                                \
+               (prop) = BFI_ADAPTER_SETP(NPORTS, 1) |          \
+                       BFI_ADAPTER_SETP(SPEED, 4);             \
+               break;                                          \
+       case BFA_MFG_TYPE_CNA10P2:                              \
+       case BFA_MFG_TYPE_WANCHESE:                             \
+       case BFA_MFG_TYPE_LIGHTNING_P0:                         \
+       case BFA_MFG_TYPE_LIGHTNING:                            \
+               (prop) = BFI_ADAPTER_SETP(NPORTS, 2);           \
+               (prop) |= BFI_ADAPTER_SETP(SPEED, 10);          \
+               break;                                          \
+       case BFA_MFG_TYPE_CNA10P1:                              \
+               (prop) = BFI_ADAPTER_SETP(NPORTS, 1);           \
+               (prop) |= BFI_ADAPTER_SETP(SPEED, 10);          \
+               break;                                          \
+       default:                                                \
+               (prop) = BFI_ADAPTER_UNSUPP;                    \
+       }                                                       \
+} while (0)
+
+enum {
+       CB_GPIO_TTV     = (1),          /*!< TTV debug capable cards    */
+       CB_GPIO_FC8P2   = (2),          /*!< 8G 2port FC card           */
+       CB_GPIO_FC8P1   = (3),          /*!< 8G 1port FC card           */
+       CB_GPIO_FC4P2   = (4),          /*!< 4G 2port FC card           */
+       CB_GPIO_FC4P1   = (5),          /*!< 4G 1port FC card           */
+       CB_GPIO_DFLY    = (6),          /*!< 8G 2port FC mezzanine card */
+       CB_GPIO_PROTO   = (1 << 7)      /*!< 8G 2port FC prototypes     */
+};
+
+#define bfa_mfg_adapter_prop_init_gpio(gpio, card_type, prop)  \
+do {                                                           \
+       if ((gpio) & CB_GPIO_PROTO) {                           \
+               (prop) |= BFI_ADAPTER_PROTO;                    \
+               (gpio) &= ~CB_GPIO_PROTO;                       \
+       }                                                       \
+       switch ((gpio)) {                                       \
+       case CB_GPIO_TTV:                                       \
+               (prop) |= BFI_ADAPTER_TTV;                      \
+       case CB_GPIO_DFLY:                                      \
+       case CB_GPIO_FC8P2:                                     \
+               (prop) |= BFI_ADAPTER_SETP(NPORTS, 2);          \
+               (prop) |= BFI_ADAPTER_SETP(SPEED, 8);           \
+               (card_type) = BFA_MFG_TYPE_FC8P2;               \
+               break;                                          \
+       case CB_GPIO_FC8P1:                                     \
+               (prop) |= BFI_ADAPTER_SETP(NPORTS, 1);          \
+               (prop) |= BFI_ADAPTER_SETP(SPEED, 8);           \
+               (card_type) = BFA_MFG_TYPE_FC8P1;               \
+               break;                                          \
+       case CB_GPIO_FC4P2:                                     \
+               (prop) |= BFI_ADAPTER_SETP(NPORTS, 2);          \
+               (prop) |= BFI_ADAPTER_SETP(SPEED, 4);           \
+               (card_type) = BFA_MFG_TYPE_FC4P2;               \
+               break;                                          \
+       case CB_GPIO_FC4P1:                                     \
+               (prop) |= BFI_ADAPTER_SETP(NPORTS, 1);          \
+               (prop) |= BFI_ADAPTER_SETP(SPEED, 4);           \
+               (card_type) = BFA_MFG_TYPE_FC4P1;               \
+               break;                                          \
+       default:                                                \
+               (prop) |= BFI_ADAPTER_UNSUPP;                   \
+               (card_type) = BFA_MFG_TYPE_INVALID;             \
+       }                                                       \
+} while (0)
+
+/**
+ * VPD data length
+ */
+#define BFA_MFG_VPD_LEN                        512
+#define BFA_MFG_VPD_LEN_INVALID                0
+
+#define BFA_MFG_VPD_PCI_HDR_OFF                137
+#define BFA_MFG_VPD_PCI_VER_MASK       0x07    /*!< version mask 3 bits */
+#define BFA_MFG_VPD_PCI_VDR_MASK       0xf8    /*!< vendor mask 5 bits */
+
+/**
+ * VPD vendor tag
+ */
+enum {
+       BFA_MFG_VPD_UNKNOWN     = 0,     /*!< vendor unknown            */
+       BFA_MFG_VPD_IBM         = 1,     /*!< vendor IBM                */
+       BFA_MFG_VPD_HP          = 2,     /*!< vendor HP                 */
+       BFA_MFG_VPD_DELL        = 3,     /*!< vendor DELL               */
+       BFA_MFG_VPD_PCI_IBM     = 0x08,  /*!< PCI VPD IBM               */
+       BFA_MFG_VPD_PCI_HP      = 0x10,  /*!< PCI VPD HP                */
+       BFA_MFG_VPD_PCI_DELL    = 0x20,  /*!< PCI VPD DELL              */
+       BFA_MFG_VPD_PCI_BRCD    = 0xf8,  /*!< PCI VPD Brocade           */
+};
+
+/**
+ * @brief BFA adapter flash vpd data definition.
+ *
+ * All numerical fields are in big-endian format.
+ */
+struct bfa_mfg_vpd {
+       u8              version;        /*!< vpd data version */
+       u8              vpd_sig[3];     /*!< characters 'V', 'P', 'D' */
+       u8              chksum;         /*!< u8 checksum */
+       u8              vendor;         /*!< vendor */
+       u8      len;            /*!< vpd data length excluding header */
+       u8      rsv;
+       u8              data[BFA_MFG_VPD_LEN];  /*!< vpd data */
+};
+
+#pragma pack()
+
+#endif /* __BFA_DEFS_MFG_H__ */
diff --git a/drivers/net/bna/bfa_defs_status.h b/drivers/net/bna/bfa_defs_status.h
new file mode 100644 (file)
index 0000000..af95112
--- /dev/null
@@ -0,0 +1,216 @@
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * 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.
+ */
+/*
+ * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+#ifndef __BFA_DEFS_STATUS_H__
+#define __BFA_DEFS_STATUS_H__
+
+/**
+ * API status return values
+ *
+ * NOTE: The error msgs are auto generated from the comments. Only singe line
+ * comments are supported
+ */
+enum bfa_status {
+       BFA_STATUS_OK           = 0,
+       BFA_STATUS_FAILED       = 1,
+       BFA_STATUS_EINVAL       = 2,
+       BFA_STATUS_ENOMEM       = 3,
+       BFA_STATUS_ENOSYS       = 4,
+       BFA_STATUS_ETIMER       = 5,
+       BFA_STATUS_EPROTOCOL    = 6,
+       BFA_STATUS_ENOFCPORTS   = 7,
+       BFA_STATUS_NOFLASH      = 8,
+       BFA_STATUS_BADFLASH     = 9,
+       BFA_STATUS_SFP_UNSUPP   = 10,
+       BFA_STATUS_UNKNOWN_VFID = 11,
+       BFA_STATUS_DATACORRUPTED = 12,
+       BFA_STATUS_DEVBUSY      = 13,
+       BFA_STATUS_ABORTED      = 14,
+       BFA_STATUS_NODEV        = 15,
+       BFA_STATUS_HDMA_FAILED  = 16,
+       BFA_STATUS_FLASH_BAD_LEN = 17,
+       BFA_STATUS_UNKNOWN_LWWN = 18,
+       BFA_STATUS_UNKNOWN_RWWN = 19,
+       BFA_STATUS_FCPT_LS_RJT  = 20,
+       BFA_STATUS_VPORT_EXISTS = 21,
+       BFA_STATUS_VPORT_MAX    = 22,
+       BFA_STATUS_UNSUPP_SPEED = 23,
+       BFA_STATUS_INVLD_DFSZ   = 24,
+       BFA_STATUS_CNFG_FAILED  = 25,
+       BFA_STATUS_CMD_NOTSUPP  = 26,
+       BFA_STATUS_NO_ADAPTER   = 27,
+       BFA_STATUS_LINKDOWN     = 28,
+       BFA_STATUS_FABRIC_RJT   = 29,
+       BFA_STATUS_UNKNOWN_VWWN = 30,
+       BFA_STATUS_NSLOGIN_FAILED = 31,
+       BFA_STATUS_NO_RPORTS    = 32,
+       BFA_STATUS_NSQUERY_FAILED = 33,
+       BFA_STATUS_PORT_OFFLINE = 34,
+       BFA_STATUS_RPORT_OFFLINE = 35,
+       BFA_STATUS_TGTOPEN_FAILED = 36,
+       BFA_STATUS_BAD_LUNS     = 37,
+       BFA_STATUS_IO_FAILURE   = 38,
+       BFA_STATUS_NO_FABRIC    = 39,
+       BFA_STATUS_EBADF        = 40,
+       BFA_STATUS_EINTR        = 41,
+       BFA_STATUS_EIO          = 42,
+       BFA_STATUS_ENOTTY       = 43,
+       BFA_STATUS_ENXIO        = 44,
+       BFA_STATUS_EFOPEN       = 45,
+       BFA_STATUS_VPORT_WWN_BP = 46,
+       BFA_STATUS_PORT_NOT_DISABLED = 47,
+       BFA_STATUS_BADFRMHDR    = 48,
+       BFA_STATUS_BADFRMSZ     = 49,
+       BFA_STATUS_MISSINGFRM   = 50,
+       BFA_STATUS_LINKTIMEOUT  = 51,
+       BFA_STATUS_NO_FCPIM_NEXUS = 52,
+       BFA_STATUS_CHECKSUM_FAIL = 53,
+       BFA_STATUS_GZME_FAILED  = 54,
+       BFA_STATUS_SCSISTART_REQD = 55,
+       BFA_STATUS_IOC_FAILURE  = 56,
+       BFA_STATUS_INVALID_WWN  = 57,
+       BFA_STATUS_MISMATCH     = 58,
+       BFA_STATUS_IOC_ENABLED  = 59,
+       BFA_STATUS_ADAPTER_ENABLED = 60,
+       BFA_STATUS_IOC_NON_OP   = 61,
+       BFA_STATUS_ADDR_MAP_FAILURE = 62,
+       BFA_STATUS_SAME_NAME    = 63,
+       BFA_STATUS_PENDING      = 64,
+       BFA_STATUS_8G_SPD       = 65,
+       BFA_STATUS_4G_SPD       = 66,
+       BFA_STATUS_AD_IS_ENABLE = 67,
+       BFA_STATUS_EINVAL_TOV   = 68,
+       BFA_STATUS_EINVAL_QDEPTH = 69,
+       BFA_STATUS_VERSION_FAIL = 70,
+       BFA_STATUS_DIAG_BUSY    = 71,
+       BFA_STATUS_BEACON_ON    = 72,
+       BFA_STATUS_BEACON_OFF   = 73,
+       BFA_STATUS_LBEACON_ON   = 74,
+       BFA_STATUS_LBEACON_OFF  = 75,
+       BFA_STATUS_PORT_NOT_INITED = 76,
+       BFA_STATUS_RPSC_ENABLED = 77,
+       BFA_STATUS_ENOFSAVE     = 78,
+       BFA_STATUS_BAD_FILE             = 79,
+       BFA_STATUS_RLIM_EN              = 80,
+       BFA_STATUS_RLIM_DIS             = 81,
+       BFA_STATUS_IOC_DISABLED  = 82,
+       BFA_STATUS_ADAPTER_DISABLED  = 83,
+       BFA_STATUS_BIOS_DISABLED  = 84,
+       BFA_STATUS_AUTH_ENABLED  = 85,
+       BFA_STATUS_AUTH_DISABLED  = 86,
+       BFA_STATUS_ERROR_TRL_ENABLED  = 87,
+       BFA_STATUS_ERROR_QOS_ENABLED  = 88,
+       BFA_STATUS_NO_SFP_DEV = 89,
+       BFA_STATUS_MEMTEST_FAILED = 90,
+       BFA_STATUS_INVALID_DEVID = 91,
+       BFA_STATUS_QOS_ENABLED = 92,
+       BFA_STATUS_QOS_DISABLED = 93,
+       BFA_STATUS_INCORRECT_DRV_CONFIG = 94,
+       BFA_STATUS_REG_FAIL = 95,
+       BFA_STATUS_IM_INV_CODE = 96,
+       BFA_STATUS_IM_INV_VLAN = 97,
+       BFA_STATUS_IM_INV_ADAPT_NAME = 98,
+       BFA_STATUS_IM_LOW_RESOURCES = 99,
+       BFA_STATUS_IM_VLANID_IS_PVID = 100,
+       BFA_STATUS_IM_VLANID_EXISTS = 101,
+       BFA_STATUS_IM_FW_UPDATE_FAIL = 102,
+       BFA_STATUS_PORTLOG_ENABLED = 103,
+       BFA_STATUS_PORTLOG_DISABLED = 104,
+       BFA_STATUS_FILE_NOT_FOUND = 105,
+       BFA_STATUS_QOS_FC_ONLY = 106,
+       BFA_STATUS_RLIM_FC_ONLY = 107,
+       BFA_STATUS_CT_SPD = 108,
+       BFA_STATUS_LEDTEST_OP = 109,
+       BFA_STATUS_CEE_NOT_DN = 110,
+       BFA_STATUS_10G_SPD = 111,
+       BFA_STATUS_IM_INV_TEAM_NAME = 112,
+       BFA_STATUS_IM_DUP_TEAM_NAME = 113,
+       BFA_STATUS_IM_ADAPT_ALREADY_IN_TEAM = 114,
+       BFA_STATUS_IM_ADAPT_HAS_VLANS = 115,
+       BFA_STATUS_IM_PVID_MISMATCH = 116,
+       BFA_STATUS_IM_LINK_SPEED_MISMATCH = 117,
+       BFA_STATUS_IM_MTU_MISMATCH = 118,
+       BFA_STATUS_IM_RSS_MISMATCH = 119,
+       BFA_STATUS_IM_HDS_MISMATCH = 120,
+       BFA_STATUS_IM_OFFLOAD_MISMATCH = 121,
+       BFA_STATUS_IM_PORT_PARAMS = 122,
+       BFA_STATUS_IM_PORT_NOT_IN_TEAM = 123,
+       BFA_STATUS_IM_CANNOT_REM_PRI = 124,
+       BFA_STATUS_IM_MAX_PORTS_REACHED = 125,
+       BFA_STATUS_IM_LAST_PORT_DELETE = 126,
+       BFA_STATUS_IM_NO_DRIVER = 127,
+       BFA_STATUS_IM_MAX_VLANS_REACHED = 128,
+       BFA_STATUS_TOMCAT_SPD_NOT_ALLOWED = 129,
+       BFA_STATUS_NO_MINPORT_DRIVER = 130,
+       BFA_STATUS_CARD_TYPE_MISMATCH = 131,
+       BFA_STATUS_BAD_ASICBLK = 132,
+       BFA_STATUS_NO_DRIVER = 133,
+       BFA_STATUS_INVALID_MAC = 134,
+       BFA_STATUS_IM_NO_VLAN = 135,
+       BFA_STATUS_IM_ETH_LB_FAILED = 136,
+       BFA_STATUS_IM_PVID_REMOVE = 137,
+       BFA_STATUS_IM_PVID_EDIT = 138,
+       BFA_STATUS_CNA_NO_BOOT = 139,
+       BFA_STATUS_IM_PVID_NON_ZERO = 140,
+       BFA_STATUS_IM_INETCFG_LOCK_FAILED = 141,
+       BFA_STATUS_IM_GET_INETCFG_FAILED = 142,
+       BFA_STATUS_IM_NOT_BOUND = 143,
+       BFA_STATUS_INSUFFICIENT_PERMS = 144,
+       BFA_STATUS_IM_INV_VLAN_NAME = 145,
+       BFA_STATUS_CMD_NOTSUPP_CNA = 146,
+       BFA_STATUS_IM_PASSTHRU_EDIT = 147,
+       BFA_STATUS_IM_BIND_FAILED = 148,
+       BFA_STATUS_IM_UNBIND_FAILED = 149,
+       BFA_STATUS_IM_PORT_IN_TEAM = 150,
+       BFA_STATUS_IM_VLAN_NOT_FOUND = 151,
+       BFA_STATUS_IM_TEAM_NOT_FOUND = 152,
+       BFA_STATUS_IM_TEAM_CFG_NOT_ALLOWED = 153,
+       BFA_STATUS_PBC = 154,
+       BFA_STATUS_DEVID_MISSING = 155,
+       BFA_STATUS_BAD_FWCFG = 156,
+       BFA_STATUS_CREATE_FILE = 157,
+       BFA_STATUS_INVALID_VENDOR = 158,
+       BFA_STATUS_SFP_NOT_READY = 159,
+       BFA_STATUS_FLASH_UNINIT = 160,
+       BFA_STATUS_FLASH_EMPTY = 161,
+       BFA_STATUS_FLASH_CKFAIL = 162,
+       BFA_STATUS_TRUNK_UNSUPP = 163,
+       BFA_STATUS_TRUNK_ENABLED = 164,
+       BFA_STATUS_TRUNK_DISABLED  = 165,
+       BFA_STATUS_TRUNK_ERROR_TRL_ENABLED = 166,
+       BFA_STATUS_BOOT_CODE_UPDATED = 167,
+       BFA_STATUS_BOOT_VERSION = 168,
+       BFA_STATUS_CARDTYPE_MISSING = 169,
+       BFA_STATUS_INVALID_CARDTYPE = 170,
+       BFA_STATUS_NO_TOPOLOGY_FOR_CNA = 171,
+       BFA_STATUS_IM_VLAN_OVER_TEAM_DELETE_FAILED = 172,
+       BFA_STATUS_ETHBOOT_ENABLED  = 173,
+       BFA_STATUS_ETHBOOT_DISABLED  = 174,
+       BFA_STATUS_IOPROFILE_OFF = 175,
+       BFA_STATUS_NO_PORT_INSTANCE = 176,
+       BFA_STATUS_BOOT_CODE_TIMEDOUT = 177,
+       BFA_STATUS_NO_VPORT_LOCK = 178,
+       BFA_STATUS_VPORT_NO_CNFG = 179,
+       BFA_STATUS_MAX_VAL
+};
+
+enum bfa_eproto_status {
+       BFA_EPROTO_BAD_ACCEPT = 0,
+       BFA_EPROTO_UNKNOWN_RSP = 1
+};
+
+#endif /* __BFA_DEFS_STATUS_H__ */
diff --git a/drivers/net/bna/bfa_ioc.c b/drivers/net/bna/bfa_ioc.c
new file mode 100644 (file)
index 0000000..caa45c2
--- /dev/null
@@ -0,0 +1,1738 @@
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * 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.
+ */
+/*
+ * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+
+#include "bfa_ioc.h"
+#include "cna.h"
+#include "bfi.h"
+#include "bfi_ctreg.h"
+#include "bfa_defs.h"
+
+/**
+ * IOC local definitions
+ */
+
+#define bfa_ioc_timer_start(__ioc)                                     \
+       mod_timer(&(__ioc)->ioc_timer, jiffies +        \
+                       msecs_to_jiffies(BFA_IOC_TOV))
+#define bfa_ioc_timer_stop(__ioc)   del_timer(&(__ioc)->ioc_timer)
+
+#define bfa_ioc_recovery_timer_start(__ioc)                            \
+       mod_timer(&(__ioc)->ioc_timer, jiffies +        \
+                       msecs_to_jiffies(BFA_IOC_TOV_RECOVER))
+
+#define bfa_sem_timer_start(__ioc)                                     \
+       mod_timer(&(__ioc)->sem_timer, jiffies +        \
+                       msecs_to_jiffies(BFA_IOC_HWSEM_TOV))
+#define bfa_sem_timer_stop(__ioc)      del_timer(&(__ioc)->sem_timer)
+
+#define bfa_hb_timer_start(__ioc)                                      \
+       mod_timer(&(__ioc)->hb_timer, jiffies +         \
+                       msecs_to_jiffies(BFA_IOC_HB_TOV))
+#define bfa_hb_timer_stop(__ioc)       del_timer(&(__ioc)->hb_timer)
+
+/**
+ * Asic specific macros : see bfa_hw_cb.c and bfa_hw_ct.c for details.
+ */
+
+#define bfa_ioc_firmware_lock(__ioc)                   \
+                       ((__ioc)->ioc_hwif->ioc_firmware_lock(__ioc))
+#define bfa_ioc_firmware_unlock(__ioc)                 \
+                       ((__ioc)->ioc_hwif->ioc_firmware_unlock(__ioc))
+#define bfa_ioc_reg_init(__ioc) ((__ioc)->ioc_hwif->ioc_reg_init(__ioc))
+#define bfa_ioc_map_port(__ioc) ((__ioc)->ioc_hwif->ioc_map_port(__ioc))
+#define bfa_ioc_notify_hbfail(__ioc)                   \
+                       ((__ioc)->ioc_hwif->ioc_notify_hbfail(__ioc))
+
+#define bfa_ioc_is_optrom(__ioc)       \
+       (bfa_cb_image_get_size(BFA_IOC_FWIMG_TYPE(__ioc)) < BFA_IOC_FWIMG_MINSZ)
+
+#define bfa_ioc_mbox_cmd_pending(__ioc)                \
+                       (!list_empty(&((__ioc)->mbox_mod.cmd_q)) || \
+                       readl((__ioc)->ioc_regs.hfn_mbox_cmd))
+
+bool bfa_nw_auto_recover = true;
+
+/*
+ * forward declarations
+ */
+static void bfa_ioc_hw_sem_get(struct bfa_ioc *ioc);
+static void bfa_ioc_hw_sem_get_cancel(struct bfa_ioc *ioc);
+static void bfa_ioc_hwinit(struct bfa_ioc *ioc, bool force);
+static void bfa_ioc_send_enable(struct bfa_ioc *ioc);
+static void bfa_ioc_send_disable(struct bfa_ioc *ioc);
+static void bfa_ioc_send_getattr(struct bfa_ioc *ioc);
+static void bfa_ioc_hb_monitor(struct bfa_ioc *ioc);
+static void bfa_ioc_hb_stop(struct bfa_ioc *ioc);
+static void bfa_ioc_reset(struct bfa_ioc *ioc, bool force);
+static void bfa_ioc_mbox_poll(struct bfa_ioc *ioc);
+static void bfa_ioc_mbox_hbfail(struct bfa_ioc *ioc);
+static void bfa_ioc_recover(struct bfa_ioc *ioc);
+static void bfa_ioc_check_attr_wwns(struct bfa_ioc *ioc);
+static void bfa_ioc_disable_comp(struct bfa_ioc *ioc);
+static void bfa_ioc_lpu_stop(struct bfa_ioc *ioc);
+static void bfa_ioc_boot(struct bfa_ioc *ioc, u32 boot_type,
+                        u32 boot_param);
+static u32 bfa_ioc_smem_pgnum(struct bfa_ioc *ioc, u32 fmaddr);
+static u32 bfa_ioc_smem_pgoff(struct bfa_ioc *ioc, u32 fmaddr);
+static void bfa_ioc_get_adapter_serial_num(struct bfa_ioc *ioc,
+                                               char *serial_num);
+static void bfa_ioc_get_adapter_fw_ver(struct bfa_ioc *ioc,
+                                               char *fw_ver);
+static void bfa_ioc_get_pci_chip_rev(struct bfa_ioc *ioc,
+                                               char *chip_rev);
+static void bfa_ioc_get_adapter_optrom_ver(struct bfa_ioc *ioc,
+                                               char *optrom_ver);
+static void bfa_ioc_get_adapter_manufacturer(struct bfa_ioc *ioc,
+                                               char *manufacturer);
+static void bfa_ioc_get_adapter_model(struct bfa_ioc *ioc, char *model);
+static u64 bfa_ioc_get_pwwn(struct bfa_ioc *ioc);
+static mac_t bfa_ioc_get_mfg_mac(struct bfa_ioc *ioc);
+
+/**
+ * IOC state machine events
+ */
+enum ioc_event {
+       IOC_E_ENABLE            = 1,    /*!< IOC enable request         */
+       IOC_E_DISABLE           = 2,    /*!< IOC disable request        */
+       IOC_E_TIMEOUT           = 3,    /*!< f/w response timeout       */
+       IOC_E_FWREADY           = 4,    /*!< f/w initialization done    */
+       IOC_E_FWRSP_GETATTR     = 5,    /*!< IOC get attribute response */
+       IOC_E_FWRSP_ENABLE      = 6,    /*!< enable f/w response        */
+       IOC_E_FWRSP_DISABLE     = 7,    /*!< disable f/w response       */
+       IOC_E_HBFAIL            = 8,    /*!< heartbeat failure          */
+       IOC_E_HWERROR           = 9,    /*!< hardware error interrupt   */
+       IOC_E_SEMLOCKED         = 10,   /*!< h/w semaphore is locked    */
+       IOC_E_DETACH            = 11,   /*!< driver detach cleanup      */
+};
+
+bfa_fsm_state_decl(bfa_ioc, reset, struct bfa_ioc, enum ioc_event);
+bfa_fsm_state_decl(bfa_ioc, fwcheck, struct bfa_ioc, enum ioc_event);
+bfa_fsm_state_decl(bfa_ioc, mismatch, struct bfa_ioc, enum ioc_event);
+bfa_fsm_state_decl(bfa_ioc, semwait, struct bfa_ioc, enum ioc_event);
+bfa_fsm_state_decl(bfa_ioc, hwinit, struct bfa_ioc, enum ioc_event);
+bfa_fsm_state_decl(bfa_ioc, enabling, struct bfa_ioc, enum ioc_event);
+bfa_fsm_state_decl(bfa_ioc, getattr, struct bfa_ioc, enum ioc_event);
+bfa_fsm_state_decl(bfa_ioc, op, struct bfa_ioc, enum ioc_event);
+bfa_fsm_state_decl(bfa_ioc, initfail, struct bfa_ioc, enum ioc_event);
+bfa_fsm_state_decl(bfa_ioc, hbfail, struct bfa_ioc, enum ioc_event);
+bfa_fsm_state_decl(bfa_ioc, disabling, struct bfa_ioc, enum ioc_event);
+bfa_fsm_state_decl(bfa_ioc, disabled, struct bfa_ioc, enum ioc_event);
+
+static struct bfa_sm_table ioc_sm_table[] = {
+       {BFA_SM(bfa_ioc_sm_reset), BFA_IOC_RESET},
+       {BFA_SM(bfa_ioc_sm_fwcheck), BFA_IOC_FWMISMATCH},
+       {BFA_SM(bfa_ioc_sm_mismatch), BFA_IOC_FWMISMATCH},
+       {BFA_SM(bfa_ioc_sm_semwait), BFA_IOC_SEMWAIT},
+       {BFA_SM(bfa_ioc_sm_hwinit), BFA_IOC_HWINIT},
+       {BFA_SM(bfa_ioc_sm_enabling), BFA_IOC_HWINIT},
+       {BFA_SM(bfa_ioc_sm_getattr), BFA_IOC_GETATTR},
+       {BFA_SM(bfa_ioc_sm_op), BFA_IOC_OPERATIONAL},
+       {BFA_SM(bfa_ioc_sm_initfail), BFA_IOC_INITFAIL},
+       {BFA_SM(bfa_ioc_sm_hbfail), BFA_IOC_HBFAIL},
+       {BFA_SM(bfa_ioc_sm_disabling), BFA_IOC_DISABLING},
+       {BFA_SM(bfa_ioc_sm_disabled), BFA_IOC_DISABLED},
+};
+
+/**
+ * Reset entry actions -- initialize state machine
+ */
+static void
+bfa_ioc_sm_reset_entry(struct bfa_ioc *ioc)
+{
+       ioc->retry_count = 0;
+       ioc->auto_recover = bfa_nw_auto_recover;
+}
+
+/**
+ * Beginning state. IOC is in reset state.
+ */
+static void
+bfa_ioc_sm_reset(struct bfa_ioc *ioc, enum ioc_event event)
+{
+       switch (event) {
+       case IOC_E_ENABLE:
+               bfa_fsm_set_state(ioc, bfa_ioc_sm_fwcheck);
+               break;
+
+       case IOC_E_DISABLE:
+               bfa_ioc_disable_comp(ioc);
+               break;
+
+       case IOC_E_DETACH:
+               break;
+
+       default:
+               bfa_sm_fault(ioc, event);
+       }
+}
+
+/**
+ * Semaphore should be acquired for version check.
+ */
+static void
+bfa_ioc_sm_fwcheck_entry(struct bfa_ioc *ioc)
+{
+       bfa_ioc_hw_sem_get(ioc);
+}
+
+/**
+ * Awaiting h/w semaphore to continue with version check.
+ */
+static void
+bfa_ioc_sm_fwcheck(struct bfa_ioc *ioc, enum ioc_event event)
+{
+       switch (event) {
+       case IOC_E_SEMLOCKED:
+               if (bfa_ioc_firmware_lock(ioc)) {
+                       ioc->retry_count = 0;
+                       bfa_fsm_set_state(ioc, bfa_ioc_sm_hwinit);
+               } else {
+                       bfa_nw_ioc_hw_sem_release(ioc);
+                       bfa_fsm_set_state(ioc, bfa_ioc_sm_mismatch);
+               }
+               break;
+
+       case IOC_E_DISABLE:
+               bfa_ioc_disable_comp(ioc);
+               /* fall through */
+
+       case IOC_E_DETACH:
+               bfa_ioc_hw_sem_get_cancel(ioc);
+               bfa_fsm_set_state(ioc, bfa_ioc_sm_reset);
+               break;
+
+       case IOC_E_FWREADY:
+               break;
+
+       default:
+               bfa_sm_fault(ioc, event);
+       }
+}
+
+/**
+ * Notify enable completion callback and generate mismatch AEN.
+ */
+static void
+bfa_ioc_sm_mismatch_entry(struct bfa_ioc *ioc)
+{
+       /**
+        * Provide enable completion callback and AEN notification only once.
+        */
+       if (ioc->retry_count == 0)
+               ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);
+       ioc->retry_count++;
+       bfa_ioc_timer_start(ioc);
+}
+
+/**
+ * Awaiting firmware version match.
+ */
+static void
+bfa_ioc_sm_mismatch(struct bfa_ioc *ioc, enum ioc_event event)
+{
+       switch (event) {
+       case IOC_E_TIMEOUT:
+               bfa_fsm_set_state(ioc, bfa_ioc_sm_fwcheck);
+               break;
+
+       case IOC_E_DISABLE:
+               bfa_ioc_disable_comp(ioc);
+               /* fall through */
+
+       case IOC_E_DETACH:
+               bfa_ioc_timer_stop(ioc);
+               bfa_fsm_set_state(ioc, bfa_ioc_sm_reset);
+               break;
+
+       case IOC_E_FWREADY:
+               break;
+
+       default:
+               bfa_sm_fault(ioc, event);
+       }
+}
+
+/**
+ * Request for semaphore.
+ */
+static void
+bfa_ioc_sm_semwait_entry(struct bfa_ioc *ioc)
+{
+       bfa_ioc_hw_sem_get(ioc);
+}
+
+/**
+ * Awaiting semaphore for h/w initialzation.
+ */
+static void
+bfa_ioc_sm_semwait(struct bfa_ioc *ioc, enum ioc_event event)
+{
+       switch (event) {
+       case IOC_E_SEMLOCKED:
+               ioc->retry_count = 0;
+               bfa_fsm_set_state(ioc, bfa_ioc_sm_hwinit);
+               break;
+
+       case IOC_E_DISABLE:
+               bfa_ioc_hw_sem_get_cancel(ioc);
+               bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled);
+               break;
+
+       default:
+               bfa_sm_fault(ioc, event);
+       }
+}
+
+static void
+bfa_ioc_sm_hwinit_entry(struct bfa_ioc *ioc)
+{
+       bfa_ioc_timer_start(ioc);
+       bfa_ioc_reset(ioc, false);
+}
+
+/**
+ * @brief
+ * Hardware is being initialized. Interrupts are enabled.
+ * Holding hardware semaphore lock.
+ */
+static void
+bfa_ioc_sm_hwinit(struct bfa_ioc *ioc, enum ioc_event event)
+{
+       switch (event) {
+       case IOC_E_FWREADY:
+               bfa_ioc_timer_stop(ioc);
+               bfa_fsm_set_state(ioc, bfa_ioc_sm_enabling);
+               break;
+
+       case IOC_E_HWERROR:
+               bfa_ioc_timer_stop(ioc);
+               /* fall through */
+
+       case IOC_E_TIMEOUT:
+               ioc->retry_count++;
+               if (ioc->retry_count < BFA_IOC_HWINIT_MAX) {
+                       bfa_ioc_timer_start(ioc);
+                       bfa_ioc_reset(ioc, true);
+                       break;
+               }
+
+               bfa_nw_ioc_hw_sem_release(ioc);
+               bfa_fsm_set_state(ioc, bfa_ioc_sm_initfail);
+               break;
+
+       case IOC_E_DISABLE:
+               bfa_nw_ioc_hw_sem_release(ioc);
+               bfa_ioc_timer_stop(ioc);
+               bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled);
+               break;
+
+       default:
+               bfa_sm_fault(ioc, event);
+       }
+}
+
+static void
+bfa_ioc_sm_enabling_entry(struct bfa_ioc *ioc)
+{
+       bfa_ioc_timer_start(ioc);
+       bfa_ioc_send_enable(ioc);
+}
+
+/**
+ * Host IOC function is being enabled, awaiting response from firmware.
+ * Semaphore is acquired.
+ */
+static void
+bfa_ioc_sm_enabling(struct bfa_ioc *ioc, enum ioc_event event)
+{
+       switch (event) {
+       case IOC_E_FWRSP_ENABLE:
+               bfa_ioc_timer_stop(ioc);
+               bfa_nw_ioc_hw_sem_release(ioc);
+               bfa_fsm_set_state(ioc, bfa_ioc_sm_getattr);
+               break;
+
+       case IOC_E_HWERROR:
+               bfa_ioc_timer_stop(ioc);
+               /* fall through */
+
+       case IOC_E_TIMEOUT:
+               ioc->retry_count++;
+               if (ioc->retry_count < BFA_IOC_HWINIT_MAX) {
+                       writel(BFI_IOC_UNINIT,
+                                     ioc->ioc_regs.ioc_fwstate);
+                       bfa_fsm_set_state(ioc, bfa_ioc_sm_hwinit);
+                       break;
+               }
+
+               bfa_nw_ioc_hw_sem_release(ioc);
+               bfa_fsm_set_state(ioc, bfa_ioc_sm_initfail);
+               break;
+
+       case IOC_E_DISABLE:
+               bfa_ioc_timer_stop(ioc);
+               bfa_nw_ioc_hw_sem_release(ioc);
+               bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled);
+               break;
+
+       case IOC_E_FWREADY:
+               bfa_ioc_send_enable(ioc);
+               break;
+
+       default:
+               bfa_sm_fault(ioc, event);
+       }
+}
+
+static void
+bfa_ioc_sm_getattr_entry(struct bfa_ioc *ioc)
+{
+       bfa_ioc_timer_start(ioc);
+       bfa_ioc_send_getattr(ioc);
+}
+
+/**
+ * @brief
+ * IOC configuration in progress. Timer is active.
+ */
+static void
+bfa_ioc_sm_getattr(struct bfa_ioc *ioc, enum ioc_event event)
+{
+       switch (event) {
+       case IOC_E_FWRSP_GETATTR:
+               bfa_ioc_timer_stop(ioc);
+               bfa_ioc_check_attr_wwns(ioc);
+               bfa_fsm_set_state(ioc, bfa_ioc_sm_op);
+               break;
+
+       case IOC_E_HWERROR:
+               bfa_ioc_timer_stop(ioc);
+               /* fall through */
+
+       case IOC_E_TIMEOUT:
+               bfa_fsm_set_state(ioc, bfa_ioc_sm_initfail);
+               break;
+
+       case IOC_E_DISABLE:
+               bfa_ioc_timer_stop(ioc);
+               bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled);
+               break;
+
+       default:
+               bfa_sm_fault(ioc, event);
+       }
+}
+
+static void
+bfa_ioc_sm_op_entry(struct bfa_ioc *ioc)
+{
+       ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_OK);
+       bfa_ioc_hb_monitor(ioc);
+}
+
+static void
+bfa_ioc_sm_op(struct bfa_ioc *ioc, enum ioc_event event)
+{
+       switch (event) {
+       case IOC_E_ENABLE:
+               break;
+
+       case IOC_E_DISABLE:
+               bfa_ioc_hb_stop(ioc);
+               bfa_fsm_set_state(ioc, bfa_ioc_sm_disabling);
+               break;
+
+       case IOC_E_HWERROR:
+       case IOC_E_FWREADY:
+               /**
+                * Hard error or IOC recovery by other function.
+                * Treat it same as heartbeat failure.
+                */
+               bfa_ioc_hb_stop(ioc);
+               /* !!! fall through !!! */
+
+       case IOC_E_HBFAIL:
+               bfa_fsm_set_state(ioc, bfa_ioc_sm_hbfail);
+               break;
+
+       default:
+               bfa_sm_fault(ioc, event);
+       }
+}
+
+static void
+bfa_ioc_sm_disabling_entry(struct bfa_ioc *ioc)
+{
+       bfa_ioc_timer_start(ioc);
+       bfa_ioc_send_disable(ioc);
+}
+
+/**
+ * IOC is being disabled
+ */
+static void
+bfa_ioc_sm_disabling(struct bfa_ioc *ioc, enum ioc_event event)
+{
+       switch (event) {
+       case IOC_E_FWRSP_DISABLE:
+               bfa_ioc_timer_stop(ioc);
+               bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled);
+               break;
+
+       case IOC_E_HWERROR:
+               bfa_ioc_timer_stop(ioc);
+               /*
+                * !!! fall through !!!
+                */
+
+       case IOC_E_TIMEOUT:
+               writel(BFI_IOC_FAIL, ioc->ioc_regs.ioc_fwstate);
+               bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled);
+               break;
+
+       default:
+               bfa_sm_fault(ioc, event);
+       }
+}
+
+/**
+ * IOC disable completion entry.
+ */
+static void
+bfa_ioc_sm_disabled_entry(struct bfa_ioc *ioc)
+{
+       bfa_ioc_disable_comp(ioc);
+}
+
+static void
+bfa_ioc_sm_disabled(struct bfa_ioc *ioc, enum ioc_event event)
+{
+       switch (event) {
+       case IOC_E_ENABLE:
+               bfa_fsm_set_state(ioc, bfa_ioc_sm_semwait);
+               break;
+
+       case IOC_E_DISABLE:
+               ioc->cbfn->disable_cbfn(ioc->bfa);
+               break;
+
+       case IOC_E_FWREADY:
+               break;
+
+       case IOC_E_DETACH:
+               bfa_ioc_firmware_unlock(ioc);
+               bfa_fsm_set_state(ioc, bfa_ioc_sm_reset);
+               break;
+
+       default:
+               bfa_sm_fault(ioc, event);
+       }
+}
+
+static void
+bfa_ioc_sm_initfail_entry(struct bfa_ioc *ioc)
+{
+       ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);
+       bfa_ioc_timer_start(ioc);
+}
+
+/**
+ * @brief
+ * Hardware initialization failed.
+ */
+static void
+bfa_ioc_sm_initfail(struct bfa_ioc *ioc, enum ioc_event event)
+{
+       switch (event) {
+       case IOC_E_DISABLE:
+               bfa_ioc_timer_stop(ioc);
+               bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled);
+               break;
+
+       case IOC_E_DETACH:
+               bfa_ioc_timer_stop(ioc);
+               bfa_ioc_firmware_unlock(ioc);
+               bfa_fsm_set_state(ioc, bfa_ioc_sm_reset);
+               break;
+
+       case IOC_E_TIMEOUT:
+               bfa_fsm_set_state(ioc, bfa_ioc_sm_semwait);
+               break;
+
+       default:
+               bfa_sm_fault(ioc, event);
+       }
+}
+
+static void
+bfa_ioc_sm_hbfail_entry(struct bfa_ioc *ioc)
+{
+       struct list_head                        *qe;
+       struct bfa_ioc_hbfail_notify *notify;
+
+       /**
+        * Mark IOC as failed in hardware and stop firmware.
+        */
+       bfa_ioc_lpu_stop(ioc);
+       writel(BFI_IOC_FAIL, ioc->ioc_regs.ioc_fwstate);
+
+       /**
+        * Notify other functions on HB failure.
+        */
+       bfa_ioc_notify_hbfail(ioc);
+
+       /**
+        * Notify driver and common modules registered for notification.
+        */
+       ioc->cbfn->hbfail_cbfn(ioc->bfa);
+       list_for_each(qe, &ioc->hb_notify_q) {
+               notify = (struct bfa_ioc_hbfail_notify *) qe;
+               notify->cbfn(notify->cbarg);
+       }
+
+       /**
+        * Flush any queued up mailbox requests.
+        */
+       bfa_ioc_mbox_hbfail(ioc);
+
+       /**
+        * Trigger auto-recovery after a delay.
+        */
+       if (ioc->auto_recover)
+               mod_timer(&ioc->ioc_timer, jiffies +
+                       msecs_to_jiffies(BFA_IOC_TOV_RECOVER));
+}
+
+/**
+ * @brief
+ * IOC heartbeat failure.
+ */
+static void
+bfa_ioc_sm_hbfail(struct bfa_ioc *ioc, enum ioc_event event)
+{
+       switch (event) {
+
+       case IOC_E_ENABLE:
+               ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);
+               break;
+
+       case IOC_E_DISABLE:
+               if (ioc->auto_recover)
+                       bfa_ioc_timer_stop(ioc);
+               bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled);
+               break;
+
+       case IOC_E_TIMEOUT:
+               bfa_fsm_set_state(ioc, bfa_ioc_sm_semwait);
+               break;
+
+       case IOC_E_FWREADY:
+               /**
+                * Recovery is already initiated by other function.
+                */
+               break;
+
+       case IOC_E_HWERROR:
+               /*
+                * HB failure notification, ignore.
+                */
+               break;
+       default:
+               bfa_sm_fault(ioc, event);
+       }
+}
+
+/**
+ * BFA IOC private functions
+ */
+
+static void
+bfa_ioc_disable_comp(struct bfa_ioc *ioc)
+{
+       struct list_head                        *qe;
+       struct bfa_ioc_hbfail_notify *notify;
+
+       ioc->cbfn->disable_cbfn(ioc->bfa);
+
+       /**
+        * Notify common modules registered for notification.
+        */
+       list_for_each(qe, &ioc->hb_notify_q) {
+               notify = (struct bfa_ioc_hbfail_notify *) qe;
+               notify->cbfn(notify->cbarg);
+       }
+}
+
+void
+bfa_nw_ioc_sem_timeout(void *ioc_arg)
+{
+       struct bfa_ioc *ioc = (struct bfa_ioc *) ioc_arg;
+
+       bfa_ioc_hw_sem_get(ioc);
+}
+
+bool
+bfa_nw_ioc_sem_get(void __iomem *sem_reg)
+{
+       u32 r32;
+       int cnt = 0;
+#define BFA_SEM_SPINCNT        3000
+
+       r32 = readl(sem_reg);
+
+       while (r32 && (cnt < BFA_SEM_SPINCNT)) {
+               cnt++;
+               udelay(2);
+               r32 = readl(sem_reg);
+       }
+
+       if (r32 == 0)
+               return true;
+
+       BUG_ON(!(cnt < BFA_SEM_SPINCNT));
+       return false;
+}
+
+void
+bfa_nw_ioc_sem_release(void __iomem *sem_reg)
+{
+       writel(1, sem_reg);
+}
+
+static void
+bfa_ioc_hw_sem_get(struct bfa_ioc *ioc)
+{
+       u32     r32;
+
+       /**
+        * First read to the semaphore register will return 0, subsequent reads
+        * will return 1. Semaphore is released by writing 1 to the register
+        */
+       r32 = readl(ioc->ioc_regs.ioc_sem_reg);
+       if (r32 == 0) {
+               bfa_fsm_send_event(ioc, IOC_E_SEMLOCKED);
+               return;
+       }
+
+       mod_timer(&ioc->sem_timer, jiffies +
+               msecs_to_jiffies(BFA_IOC_HWSEM_TOV));
+}
+
+void
+bfa_nw_ioc_hw_sem_release(struct bfa_ioc *ioc)
+{
+       writel(1, ioc->ioc_regs.ioc_sem_reg);
+}
+
+static void
+bfa_ioc_hw_sem_get_cancel(struct bfa_ioc *ioc)
+{
+       del_timer(&ioc->sem_timer);
+}
+
+/**
+ * @brief
+ * Initialize LPU local memory (aka secondary memory / SRAM)
+ */
+static void
+bfa_ioc_lmem_init(struct bfa_ioc *ioc)
+{
+       u32     pss_ctl;
+       int             i;
+#define PSS_LMEM_INIT_TIME  10000
+
+       pss_ctl = readl(ioc->ioc_regs.pss_ctl_reg);
+       pss_ctl &= ~__PSS_LMEM_RESET;
+       pss_ctl |= __PSS_LMEM_INIT_EN;
+
+       /*
+        * i2c workaround 12.5khz clock
+        */
+       pss_ctl |= __PSS_I2C_CLK_DIV(3UL);
+       writel(pss_ctl, ioc->ioc_regs.pss_ctl_reg);
+
+       /**
+        * wait for memory initialization to be complete
+        */
+       i = 0;
+       do {
+               pss_ctl = readl(ioc->ioc_regs.pss_ctl_reg);
+               i++;
+       } while (!(pss_ctl & __PSS_LMEM_INIT_DONE) && (i < PSS_LMEM_INIT_TIME));
+
+       /**
+        * If memory initialization is not successful, IOC timeout will catch
+        * such failures.
+        */
+       BUG_ON(!(pss_ctl & __PSS_LMEM_INIT_DONE));
+
+       pss_ctl &= ~(__PSS_LMEM_INIT_DONE | __PSS_LMEM_INIT_EN);
+       writel(pss_ctl, ioc->ioc_regs.pss_ctl_reg);
+}
+
+static void
+bfa_ioc_lpu_start(struct bfa_ioc *ioc)
+{
+       u32     pss_ctl;
+
+       /**
+        * Take processor out of reset.
+        */
+       pss_ctl = readl(ioc->ioc_regs.pss_ctl_reg);
+       pss_ctl &= ~__PSS_LPU0_RESET;
+
+       writel(pss_ctl, ioc->ioc_regs.pss_ctl_reg);
+}
+
+static void
+bfa_ioc_lpu_stop(struct bfa_ioc *ioc)
+{
+       u32     pss_ctl;
+
+       /**
+        * Put processors in reset.
+        */
+       pss_ctl = readl(ioc->ioc_regs.pss_ctl_reg);
+       pss_ctl |= (__PSS_LPU0_RESET | __PSS_LPU1_RESET);
+
+       writel(pss_ctl, ioc->ioc_regs.pss_ctl_reg);
+}
+
+/**
+ * Get driver and firmware versions.
+ */
+void
+bfa_nw_ioc_fwver_get(struct bfa_ioc *ioc, struct bfi_ioc_image_hdr *fwhdr)
+{
+       u32     pgnum, pgoff;
+       u32     loff = 0;
+       int             i;
+       u32     *fwsig = (u32 *) fwhdr;
+
+       pgnum = bfa_ioc_smem_pgnum(ioc, loff);
+       pgoff = bfa_ioc_smem_pgoff(ioc, loff);
+       writel(pgnum, ioc->ioc_regs.host_page_num_fn);
+
+       for (i = 0; i < (sizeof(struct bfi_ioc_image_hdr) / sizeof(u32));
+            i++) {
+               fwsig[i] =
+                       swab32(readl((loff) + (ioc->ioc_regs.smem_page_start)));
+               loff += sizeof(u32);
+       }
+}
+
+/**
+ * Returns TRUE if same.
+ */
+bool
+bfa_nw_ioc_fwver_cmp(struct bfa_ioc *ioc, struct bfi_ioc_image_hdr *fwhdr)
+{
+       struct bfi_ioc_image_hdr *drv_fwhdr;
+       int i;
+
+       drv_fwhdr = (struct bfi_ioc_image_hdr *)
+               bfa_cb_image_get_chunk(BFA_IOC_FWIMG_TYPE(ioc), 0);
+
+       for (i = 0; i < BFI_IOC_MD5SUM_SZ; i++) {
+               if (fwhdr->md5sum[i] != drv_fwhdr->md5sum[i])
+                       return false;
+       }
+
+       return true;
+}
+
+/**
+ * Return true if current running version is valid. Firmware signature and
+ * execution context (driver/bios) must match.
+ */
+static bool
+bfa_ioc_fwver_valid(struct bfa_ioc *ioc)
+{
+       struct bfi_ioc_image_hdr fwhdr, *drv_fwhdr;
+
+       /**
+        * If bios/efi boot (flash based) -- return true
+        */
+       if (bfa_ioc_is_optrom(ioc))
+               return true;
+
+       bfa_nw_ioc_fwver_get(ioc, &fwhdr);
+       drv_fwhdr = (struct bfi_ioc_image_hdr *)
+               bfa_cb_image_get_chunk(BFA_IOC_FWIMG_TYPE(ioc), 0);
+
+       if (fwhdr.signature != drv_fwhdr->signature)
+               return false;
+
+       if (fwhdr.exec != drv_fwhdr->exec)
+               return false;
+
+       return bfa_nw_ioc_fwver_cmp(ioc, &fwhdr);
+}
+
+/**
+ * Conditionally flush any pending message from firmware at start.
+ */
+static void
+bfa_ioc_msgflush(struct bfa_ioc *ioc)
+{
+       u32     r32;
+
+       r32 = readl(ioc->ioc_regs.lpu_mbox_cmd);
+       if (r32)
+               writel(1, ioc->ioc_regs.lpu_mbox_cmd);
+}
+
+/**
+ * @img ioc_init_logic.jpg
+ */
+static void
+bfa_ioc_hwinit(struct bfa_ioc *ioc, bool force)
+{
+       enum bfi_ioc_state ioc_fwstate;
+       bool fwvalid;
+
+       ioc_fwstate = readl(ioc->ioc_regs.ioc_fwstate);
+
+       if (force)
+               ioc_fwstate = BFI_IOC_UNINIT;
+
+       /**
+        * check if firmware is valid
+        */
+       fwvalid = (ioc_fwstate == BFI_IOC_UNINIT) ?
+               false : bfa_ioc_fwver_valid(ioc);
+
+       if (!fwvalid) {
+               bfa_ioc_boot(ioc, BFI_BOOT_TYPE_NORMAL, ioc->pcidev.device_id);
+               return;
+       }
+
+       /**
+        * If hardware initialization is in progress (initialized by other IOC),
+        * just wait for an initialization completion interrupt.
+        */
+       if (ioc_fwstate == BFI_IOC_INITING) {
+               ioc->cbfn->reset_cbfn(ioc->bfa);
+               return;
+       }
+
+       /**
+        * If IOC function is disabled and firmware version is same,
+        * just re-enable IOC.
+        *
+        * If option rom, IOC must not be in operational state. With
+        * convergence, IOC will be in operational state when 2nd driver
+        * is loaded.
+        */
+       if (ioc_fwstate == BFI_IOC_DISABLED ||
+           (!bfa_ioc_is_optrom(ioc) && ioc_fwstate == BFI_IOC_OP)) {
+               /**
+                * When using MSI-X any pending firmware ready event should
+                * be flushed. Otherwise MSI-X interrupts are not delivered.
+                */
+               bfa_ioc_msgflush(ioc);
+               ioc->cbfn->reset_cbfn(ioc->bfa);
+               bfa_fsm_send_event(ioc, IOC_E_FWREADY);
+               return;
+       }
+
+       /**
+        * Initialize the h/w for any other states.
+        */
+       bfa_ioc_boot(ioc, BFI_BOOT_TYPE_NORMAL, ioc->pcidev.device_id);
+}
+
+void
+bfa_nw_ioc_timeout(void *ioc_arg)
+{
+       struct bfa_ioc *ioc = (struct bfa_ioc *) ioc_arg;
+
+       bfa_fsm_send_event(ioc, IOC_E_TIMEOUT);
+}
+
+static void
+bfa_ioc_mbox_send(struct bfa_ioc *ioc, void *ioc_msg, int len)
+{
+       u32 *msgp = (u32 *) ioc_msg;
+       u32 i;
+
+       BUG_ON(!(len <= BFI_IOC_MSGLEN_MAX));
+
+       /*
+        * first write msg to mailbox registers
+        */
+       for (i = 0; i < len / sizeof(u32); i++)
+               writel(cpu_to_le32(msgp[i]),
+                             ioc->ioc_regs.hfn_mbox + i * sizeof(u32));
+
+       for (; i < BFI_IOC_MSGLEN_MAX / sizeof(u32); i++)
+               writel(0, ioc->ioc_regs.hfn_mbox + i * sizeof(u32));
+
+       /*
+        * write 1 to mailbox CMD to trigger LPU event
+        */
+       writel(1, ioc->ioc_regs.hfn_mbox_cmd);
+       (void) readl(ioc->ioc_regs.hfn_mbox_cmd);
+}
+
+static void
+bfa_ioc_send_enable(struct bfa_ioc *ioc)
+{
+       struct bfi_ioc_ctrl_req enable_req;
+       struct timeval tv;
+
+       bfi_h2i_set(enable_req.mh, BFI_MC_IOC, BFI_IOC_H2I_ENABLE_REQ,
+                   bfa_ioc_portid(ioc));
+       enable_req.ioc_class = ioc->ioc_mc;
+       do_gettimeofday(&tv);
+       enable_req.tv_sec = ntohl(tv.tv_sec);
+       bfa_ioc_mbox_send(ioc, &enable_req, sizeof(struct bfi_ioc_ctrl_req));
+}
+
+static void
+bfa_ioc_send_disable(struct bfa_ioc *ioc)
+{
+       struct bfi_ioc_ctrl_req disable_req;
+
+       bfi_h2i_set(disable_req.mh, BFI_MC_IOC, BFI_IOC_H2I_DISABLE_REQ,
+                   bfa_ioc_portid(ioc));
+       bfa_ioc_mbox_send(ioc, &disable_req, sizeof(struct bfi_ioc_ctrl_req));
+}
+
+static void
+bfa_ioc_send_getattr(struct bfa_ioc *ioc)
+{
+       struct bfi_ioc_getattr_req attr_req;
+
+       bfi_h2i_set(attr_req.mh, BFI_MC_IOC, BFI_IOC_H2I_GETATTR_REQ,
+                   bfa_ioc_portid(ioc));
+       bfa_dma_be_addr_set(attr_req.attr_addr, ioc->attr_dma.pa);
+       bfa_ioc_mbox_send(ioc, &attr_req, sizeof(attr_req));
+}
+
+void
+bfa_nw_ioc_hb_check(void *cbarg)
+{
+       struct bfa_ioc *ioc = cbarg;
+       u32     hb_count;
+
+       hb_count = readl(ioc->ioc_regs.heartbeat);
+       if (ioc->hb_count == hb_count) {
+               pr_crit("Firmware heartbeat failure at %d", hb_count);
+               bfa_ioc_recover(ioc);
+               return;
+       } else {
+               ioc->hb_count = hb_count;
+       }
+
+       bfa_ioc_mbox_poll(ioc);
+       mod_timer(&ioc->hb_timer, jiffies +
+               msecs_to_jiffies(BFA_IOC_HB_TOV));
+}
+
+static void
+bfa_ioc_hb_monitor(struct bfa_ioc *ioc)
+{
+       ioc->hb_count = readl(ioc->ioc_regs.heartbeat);
+       mod_timer(&ioc->hb_timer, jiffies +
+               msecs_to_jiffies(BFA_IOC_HB_TOV));
+}
+
+static void
+bfa_ioc_hb_stop(struct bfa_ioc *ioc)
+{
+       del_timer(&ioc->hb_timer);
+}
+
+/**
+ * @brief
+ *     Initiate a full firmware download.
+ */
+static void
+bfa_ioc_download_fw(struct bfa_ioc *ioc, u32 boot_type,
+                   u32 boot_param)
+{
+       u32 *fwimg;
+       u32 pgnum, pgoff;
+       u32 loff = 0;
+       u32 chunkno = 0;
+       u32 i;
+
+       /**
+        * Initialize LMEM first before code download
+        */
+       bfa_ioc_lmem_init(ioc);
+
+       /**
+        * Flash based firmware boot
+        */
+       if (bfa_ioc_is_optrom(ioc))
+               boot_type = BFI_BOOT_TYPE_FLASH;
+       fwimg = bfa_cb_image_get_chunk(BFA_IOC_FWIMG_TYPE(ioc), chunkno);
+
+       pgnum = bfa_ioc_smem_pgnum(ioc, loff);
+       pgoff = bfa_ioc_smem_pgoff(ioc, loff);
+
+       writel(pgnum, ioc->ioc_regs.host_page_num_fn);
+
+       for (i = 0; i < bfa_cb_image_get_size(BFA_IOC_FWIMG_TYPE(ioc)); i++) {
+               if (BFA_IOC_FLASH_CHUNK_NO(i) != chunkno) {
+                       chunkno = BFA_IOC_FLASH_CHUNK_NO(i);
+                       fwimg = bfa_cb_image_get_chunk(BFA_IOC_FWIMG_TYPE(ioc),
+                                       BFA_IOC_FLASH_CHUNK_ADDR(chunkno));
+               }
+
+               /**
+                * write smem
+                */
+               writel((swab32(fwimg[BFA_IOC_FLASH_OFFSET_IN_CHUNK(i)])),
+                             ((ioc->ioc_regs.smem_page_start) + (loff)));
+
+               loff += sizeof(u32);
+
+               /**
+                * handle page offset wrap around
+                */
+               loff = PSS_SMEM_PGOFF(loff);
+               if (loff == 0) {
+                       pgnum++;
+                       writel(pgnum,
+                                     ioc->ioc_regs.host_page_num_fn);
+               }
+       }
+
+       writel(bfa_ioc_smem_pgnum(ioc, 0),
+                     ioc->ioc_regs.host_page_num_fn);
+
+       /*
+        * Set boot type and boot param at the end.
+       */
+       writel((swab32(swab32(boot_type))), ((ioc->ioc_regs.smem_page_start)
+                       + (BFI_BOOT_TYPE_OFF)));
+       writel((swab32(swab32(boot_param))), ((ioc->ioc_regs.smem_page_start)
+                       + (BFI_BOOT_PARAM_OFF)));
+}
+
+static void
+bfa_ioc_reset(struct bfa_ioc *ioc, bool force)
+{
+       bfa_ioc_hwinit(ioc, force);
+}
+
+/**
+ * @brief
+ * Update BFA configuration from firmware configuration.
+ */
+static void
+bfa_ioc_getattr_reply(struct bfa_ioc *ioc)
+{
+       struct bfi_ioc_attr *attr = ioc->attr;
+
+       attr->adapter_prop  = ntohl(attr->adapter_prop);
+       attr->card_type     = ntohl(attr->card_type);
+       attr->maxfrsize     = ntohs(attr->maxfrsize);
+
+       bfa_fsm_send_event(ioc, IOC_E_FWRSP_GETATTR);
+}
+
+/**
+ * Attach time initialization of mbox logic.
+ */
+static void
+bfa_ioc_mbox_attach(struct bfa_ioc *ioc)
+{
+       struct bfa_ioc_mbox_mod *mod = &ioc->mbox_mod;
+       int     mc;
+
+       INIT_LIST_HEAD(&mod->cmd_q);
+       for (mc = 0; mc < BFI_MC_MAX; mc++) {
+               mod->mbhdlr[mc].cbfn = NULL;
+               mod->mbhdlr[mc].cbarg = ioc->bfa;
+       }
+}
+
+/**
+ * Mbox poll timer -- restarts any pending mailbox requests.
+ */
+static void
+bfa_ioc_mbox_poll(struct bfa_ioc *ioc)
+{
+       struct bfa_ioc_mbox_mod *mod = &ioc->mbox_mod;
+       struct bfa_mbox_cmd *cmd;
+       u32                     stat;
+
+       /**
+        * If no command pending, do nothing
+        */
+       if (list_empty(&mod->cmd_q))
+               return;
+
+       /**
+        * If previous command is not yet fetched by firmware, do nothing
+        */
+       stat = readl(ioc->ioc_regs.hfn_mbox_cmd);
+       if (stat)
+               return;
+
+       /**
+        * Enqueue command to firmware.
+        */
+       bfa_q_deq(&mod->cmd_q, &cmd);
+       bfa_ioc_mbox_send(ioc, cmd->msg, sizeof(cmd->msg));
+}
+
+/**
+ * Cleanup any pending requests.
+ */
+static void
+bfa_ioc_mbox_hbfail(struct bfa_ioc *ioc)
+{
+       struct bfa_ioc_mbox_mod *mod = &ioc->mbox_mod;
+       struct bfa_mbox_cmd *cmd;
+
+       while (!list_empty(&mod->cmd_q))
+               bfa_q_deq(&mod->cmd_q, &cmd);
+}
+
+/**
+ * IOC public
+ */
+static enum bfa_status
+bfa_ioc_pll_init(struct bfa_ioc *ioc)
+{
+       /*
+        *  Hold semaphore so that nobody can access the chip during init.
+        */
+       bfa_nw_ioc_sem_get(ioc->ioc_regs.ioc_init_sem_reg);
+
+       bfa_ioc_pll_init_asic(ioc);
+
+       ioc->pllinit = true;
+       /*
+        *  release semaphore.
+        */
+       bfa_nw_ioc_sem_release(ioc->ioc_regs.ioc_init_sem_reg);
+
+       return BFA_STATUS_OK;
+}
+
+/**
+ * Interface used by diag module to do firmware boot with memory test
+ * as the entry vector.
+ */
+static void
+bfa_ioc_boot(struct bfa_ioc *ioc, u32 boot_type, u32 boot_param)
+{
+       void __iomem *rb;
+
+       bfa_ioc_stats(ioc, ioc_boots);
+
+       if (bfa_ioc_pll_init(ioc) != BFA_STATUS_OK)
+               return;
+
+       /**
+        * Initialize IOC state of all functions on a chip reset.
+        */
+       rb = ioc->pcidev.pci_bar_kva;
+       if (boot_param == BFI_BOOT_TYPE_MEMTEST) {
+               writel(BFI_IOC_MEMTEST, (rb + BFA_IOC0_STATE_REG));
+               writel(BFI_IOC_MEMTEST, (rb + BFA_IOC1_STATE_REG));
+       } else {
+               writel(BFI_IOC_INITING, (rb + BFA_IOC0_STATE_REG));
+               writel(BFI_IOC_INITING, (rb + BFA_IOC1_STATE_REG));
+       }
+
+       bfa_ioc_msgflush(ioc);
+       bfa_ioc_download_fw(ioc, boot_type, boot_param);
+
+       /**
+        * Enable interrupts just before starting LPU
+        */
+       ioc->cbfn->reset_cbfn(ioc->bfa);
+       bfa_ioc_lpu_start(ioc);
+}
+
+/**
+ * Enable/disable IOC failure auto recovery.
+ */
+void
+bfa_nw_ioc_auto_recover(bool auto_recover)
+{
+       bfa_nw_auto_recover = auto_recover;
+}
+
+bool
+bfa_nw_ioc_is_operational(struct bfa_ioc *ioc)
+{
+       return bfa_fsm_cmp_state(ioc, bfa_ioc_sm_op);
+}
+
+static void
+bfa_ioc_msgget(struct bfa_ioc *ioc, void *mbmsg)
+{
+       u32     *msgp = mbmsg;
+       u32     r32;
+       int             i;
+
+       /**
+        * read the MBOX msg
+        */
+       for (i = 0; i < (sizeof(union bfi_ioc_i2h_msg_u) / sizeof(u32));
+            i++) {
+               r32 = readl(ioc->ioc_regs.lpu_mbox +
+                                  i * sizeof(u32));
+               msgp[i] = htonl(r32);
+       }
+
+       /**
+        * turn off mailbox interrupt by clearing mailbox status
+        */
+       writel(1, ioc->ioc_regs.lpu_mbox_cmd);
+       readl(ioc->ioc_regs.lpu_mbox_cmd);
+}
+
+static void
+bfa_ioc_isr(struct bfa_ioc *ioc, struct bfi_mbmsg *m)
+{
+       union bfi_ioc_i2h_msg_u *msg;
+
+       msg = (union bfi_ioc_i2h_msg_u *) m;
+
+       bfa_ioc_stats(ioc, ioc_isrs);
+
+       switch (msg->mh.msg_id) {
+       case BFI_IOC_I2H_HBEAT:
+               break;
+
+       case BFI_IOC_I2H_READY_EVENT:
+               bfa_fsm_send_event(ioc, IOC_E_FWREADY);
+               break;
+
+       case BFI_IOC_I2H_ENABLE_REPLY:
+               bfa_fsm_send_event(ioc, IOC_E_FWRSP_ENABLE);
+               break;
+
+       case BFI_IOC_I2H_DISABLE_REPLY:
+               bfa_fsm_send_event(ioc, IOC_E_FWRSP_DISABLE);
+               break;
+
+       case BFI_IOC_I2H_GETATTR_REPLY:
+               bfa_ioc_getattr_reply(ioc);
+               break;
+
+       default:
+               BUG_ON(1);
+       }
+}
+
+/**
+ * IOC attach time initialization and setup.
+ *
+ * @param[in]  ioc     memory for IOC
+ * @param[in]  bfa     driver instance structure
+ */
+void
+bfa_nw_ioc_attach(struct bfa_ioc *ioc, void *bfa, struct bfa_ioc_cbfn *cbfn)
+{
+       ioc->bfa        = bfa;
+       ioc->cbfn       = cbfn;
+       ioc->fcmode     = false;
+       ioc->pllinit    = false;
+       ioc->dbg_fwsave_once = true;
+
+       bfa_ioc_mbox_attach(ioc);
+       INIT_LIST_HEAD(&ioc->hb_notify_q);
+
+       bfa_fsm_set_state(ioc, bfa_ioc_sm_reset);
+}
+
+/**
+ * Driver detach time IOC cleanup.
+ */
+void
+bfa_nw_ioc_detach(struct bfa_ioc *ioc)
+{
+       bfa_fsm_send_event(ioc, IOC_E_DETACH);
+}
+
+/**
+ * Setup IOC PCI properties.
+ *
+ * @param[in]  pcidev  PCI device information for this IOC
+ */
+void
+bfa_nw_ioc_pci_init(struct bfa_ioc *ioc, struct bfa_pcidev *pcidev,
+                enum bfi_mclass mc)
+{
+       ioc->ioc_mc     = mc;
+       ioc->pcidev     = *pcidev;
+       ioc->ctdev      = bfa_asic_id_ct(ioc->pcidev.device_id);
+       ioc->cna        = ioc->ctdev && !ioc->fcmode;
+
+       bfa_nw_ioc_set_ct_hwif(ioc);
+
+       bfa_ioc_map_port(ioc);
+       bfa_ioc_reg_init(ioc);
+}
+
+/**
+ * Initialize IOC dma memory
+ *
+ * @param[in]  dm_kva  kernel virtual address of IOC dma memory
+ * @param[in]  dm_pa   physical address of IOC dma memory
+ */
+void
+bfa_nw_ioc_mem_claim(struct bfa_ioc *ioc,  u8 *dm_kva, u64 dm_pa)
+{
+       /**
+        * dma memory for firmware attribute
+        */
+       ioc->attr_dma.kva = dm_kva;
+       ioc->attr_dma.pa = dm_pa;
+       ioc->attr = (struct bfi_ioc_attr *) dm_kva;
+}
+
+/**
+ * Return size of dma memory required.
+ */
+u32
+bfa_nw_ioc_meminfo(void)
+{
+       return roundup(sizeof(struct bfi_ioc_attr), BFA_DMA_ALIGN_SZ);
+}
+
+void
+bfa_nw_ioc_enable(struct bfa_ioc *ioc)
+{
+       bfa_ioc_stats(ioc, ioc_enables);
+       ioc->dbg_fwsave_once = true;
+
+       bfa_fsm_send_event(ioc, IOC_E_ENABLE);
+}
+
+void
+bfa_nw_ioc_disable(struct bfa_ioc *ioc)
+{
+       bfa_ioc_stats(ioc, ioc_disables);
+       bfa_fsm_send_event(ioc, IOC_E_DISABLE);
+}
+
+static u32
+bfa_ioc_smem_pgnum(struct bfa_ioc *ioc, u32 fmaddr)
+{
+       return PSS_SMEM_PGNUM(ioc->ioc_regs.smem_pg0, fmaddr);
+}
+
+static u32
+bfa_ioc_smem_pgoff(struct bfa_ioc *ioc, u32 fmaddr)
+{
+       return PSS_SMEM_PGOFF(fmaddr);
+}
+
+/**
+ * Register mailbox message handler function, to be called by common modules
+ */
+void
+bfa_nw_ioc_mbox_regisr(struct bfa_ioc *ioc, enum bfi_mclass mc,
+                   bfa_ioc_mbox_mcfunc_t cbfn, void *cbarg)
+{
+       struct bfa_ioc_mbox_mod *mod = &ioc->mbox_mod;
+
+       mod->mbhdlr[mc].cbfn    = cbfn;
+       mod->mbhdlr[mc].cbarg = cbarg;
+}
+
+/**
+ * Queue a mailbox command request to firmware. Waits if mailbox is busy.
+ * Responsibility of caller to serialize
+ *
+ * @param[in]  ioc     IOC instance
+ * @param[i]   cmd     Mailbox command
+ */
+void
+bfa_nw_ioc_mbox_queue(struct bfa_ioc *ioc, struct bfa_mbox_cmd *cmd)
+{
+       struct bfa_ioc_mbox_mod *mod = &ioc->mbox_mod;
+       u32                     stat;
+
+       /**
+        * If a previous command is pending, queue new command
+        */
+       if (!list_empty(&mod->cmd_q)) {
+               list_add_tail(&cmd->qe, &mod->cmd_q);
+               return;
+       }
+
+       /**
+        * If mailbox is busy, queue command for poll timer
+        */
+       stat = readl(ioc->ioc_regs.hfn_mbox_cmd);
+       if (stat) {
+               list_add_tail(&cmd->qe, &mod->cmd_q);
+               return;
+       }
+
+       /**
+        * mailbox is free -- queue command to firmware
+        */
+       bfa_ioc_mbox_send(ioc, cmd->msg, sizeof(cmd->msg));
+}
+
+/**
+ * Handle mailbox interrupts
+ */
+void
+bfa_nw_ioc_mbox_isr(struct bfa_ioc *ioc)
+{
+       struct bfa_ioc_mbox_mod *mod = &ioc->mbox_mod;
+       struct bfi_mbmsg m;
+       int                             mc;
+
+       bfa_ioc_msgget(ioc, &m);
+
+       /**
+        * Treat IOC message class as special.
+        */
+       mc = m.mh.msg_class;
+       if (mc == BFI_MC_IOC) {
+               bfa_ioc_isr(ioc, &m);
+               return;
+       }
+
+       if ((mc > BFI_MC_MAX) || (mod->mbhdlr[mc].cbfn == NULL))
+               return;
+
+       mod->mbhdlr[mc].cbfn(mod->mbhdlr[mc].cbarg, &m);
+}
+
+void
+bfa_nw_ioc_error_isr(struct bfa_ioc *ioc)
+{
+       bfa_fsm_send_event(ioc, IOC_E_HWERROR);
+}
+
+/**
+ * Add to IOC heartbeat failure notification queue. To be used by common
+ * modules such as cee, port, diag.
+ */
+void
+bfa_nw_ioc_hbfail_register(struct bfa_ioc *ioc,
+                       struct bfa_ioc_hbfail_notify *notify)
+{
+       list_add_tail(&notify->qe, &ioc->hb_notify_q);
+}
+
+#define BFA_MFG_NAME "Brocade"
+static void
+bfa_ioc_get_adapter_attr(struct bfa_ioc *ioc,
+                        struct bfa_adapter_attr *ad_attr)
+{
+       struct bfi_ioc_attr *ioc_attr;
+
+       ioc_attr = ioc->attr;
+
+       bfa_ioc_get_adapter_serial_num(ioc, ad_attr->serial_num);
+       bfa_ioc_get_adapter_fw_ver(ioc, ad_attr->fw_ver);
+       bfa_ioc_get_adapter_optrom_ver(ioc, ad_attr->optrom_ver);
+       bfa_ioc_get_adapter_manufacturer(ioc, ad_attr->manufacturer);
+       memcpy(&ad_attr->vpd, &ioc_attr->vpd,
+                     sizeof(struct bfa_mfg_vpd));
+
+       ad_attr->nports = bfa_ioc_get_nports(ioc);
+       ad_attr->max_speed = bfa_ioc_speed_sup(ioc);
+
+       bfa_ioc_get_adapter_model(ioc, ad_attr->model);
+       /* For now, model descr uses same model string */
+       bfa_ioc_get_adapter_model(ioc, ad_attr->model_descr);
+
+       ad_attr->card_type = ioc_attr->card_type;
+       ad_attr->is_mezz = bfa_mfg_is_mezz(ioc_attr->card_type);
+
+       if (BFI_ADAPTER_IS_SPECIAL(ioc_attr->adapter_prop))
+               ad_attr->prototype = 1;
+       else
+               ad_attr->prototype = 0;
+
+       ad_attr->pwwn = bfa_ioc_get_pwwn(ioc);
+       ad_attr->mac  = bfa_nw_ioc_get_mac(ioc);
+
+       ad_attr->pcie_gen = ioc_attr->pcie_gen;
+       ad_attr->pcie_lanes = ioc_attr->pcie_lanes;
+       ad_attr->pcie_lanes_orig = ioc_attr->pcie_lanes_orig;
+       ad_attr->asic_rev = ioc_attr->asic_rev;
+
+       bfa_ioc_get_pci_chip_rev(ioc, ad_attr->hw_ver);
+
+       ad_attr->cna_capable = ioc->cna;
+       ad_attr->trunk_capable = (ad_attr->nports > 1) && !ioc->cna;
+}
+
+static enum bfa_ioc_type
+bfa_ioc_get_type(struct bfa_ioc *ioc)
+{
+       if (!ioc->ctdev || ioc->fcmode)
+               return BFA_IOC_TYPE_FC;
+       else if (ioc->ioc_mc == BFI_MC_IOCFC)
+               return BFA_IOC_TYPE_FCoE;
+       else if (ioc->ioc_mc == BFI_MC_LL)
+               return BFA_IOC_TYPE_LL;
+       else {
+               BUG_ON(!(ioc->ioc_mc == BFI_MC_LL));
+               return BFA_IOC_TYPE_LL;
+       }
+}
+
+static void
+bfa_ioc_get_adapter_serial_num(struct bfa_ioc *ioc, char *serial_num)
+{
+       memset(serial_num, 0, BFA_ADAPTER_SERIAL_NUM_LEN);
+       memcpy(serial_num,
+                       (void *)ioc->attr->brcd_serialnum,
+                       BFA_ADAPTER_SERIAL_NUM_LEN);
+}
+
+static void
+bfa_ioc_get_adapter_fw_ver(struct bfa_ioc *ioc, char *fw_ver)
+{
+       memset(fw_ver, 0, BFA_VERSION_LEN);
+       memcpy(fw_ver, ioc->attr->fw_version, BFA_VERSION_LEN);
+}
+
+static void
+bfa_ioc_get_pci_chip_rev(struct bfa_ioc *ioc, char *chip_rev)
+{
+       BUG_ON(!(chip_rev));
+
+       memset(chip_rev, 0, BFA_IOC_CHIP_REV_LEN);
+
+       chip_rev[0] = 'R';
+       chip_rev[1] = 'e';
+       chip_rev[2] = 'v';
+       chip_rev[3] = '-';
+       chip_rev[4] = ioc->attr->asic_rev;
+       chip_rev[5] = '\0';
+}
+
+static void
+bfa_ioc_get_adapter_optrom_ver(struct bfa_ioc *ioc, char *optrom_ver)
+{
+       memset(optrom_ver, 0, BFA_VERSION_LEN);
+       memcpy(optrom_ver, ioc->attr->optrom_version,
+                     BFA_VERSION_LEN);
+}
+
+static void
+bfa_ioc_get_adapter_manufacturer(struct bfa_ioc *ioc, char *manufacturer)
+{
+       memset(manufacturer, 0, BFA_ADAPTER_MFG_NAME_LEN);
+       memcpy(manufacturer, BFA_MFG_NAME, BFA_ADAPTER_MFG_NAME_LEN);
+}
+
+static void
+bfa_ioc_get_adapter_model(struct bfa_ioc *ioc, char *model)
+{
+       struct bfi_ioc_attr *ioc_attr;
+
+       BUG_ON(!(model));
+       memset(model, 0, BFA_ADAPTER_MODEL_NAME_LEN);
+
+       ioc_attr = ioc->attr;
+
+       /**
+        * model name
+        */
+       snprintf(model, BFA_ADAPTER_MODEL_NAME_LEN, "%s-%u",
+               BFA_MFG_NAME, ioc_attr->card_type);
+}
+
+static enum bfa_ioc_state
+bfa_ioc_get_state(struct bfa_ioc *ioc)
+{
+       return bfa_sm_to_state(ioc_sm_table, ioc->fsm);
+}
+
+void
+bfa_nw_ioc_get_attr(struct bfa_ioc *ioc, struct bfa_ioc_attr *ioc_attr)
+{
+       memset((void *)ioc_attr, 0, sizeof(struct bfa_ioc_attr));
+
+       ioc_attr->state = bfa_ioc_get_state(ioc);
+       ioc_attr->port_id = ioc->port_id;
+
+       ioc_attr->ioc_type = bfa_ioc_get_type(ioc);
+
+       bfa_ioc_get_adapter_attr(ioc, &ioc_attr->adapter_attr);
+
+       ioc_attr->pci_attr.device_id = ioc->pcidev.device_id;
+       ioc_attr->pci_attr.pcifn = ioc->pcidev.pci_func;
+       bfa_ioc_get_pci_chip_rev(ioc, ioc_attr->pci_attr.chip_rev);
+}
+
+/**
+ * WWN public
+ */
+static u64
+bfa_ioc_get_pwwn(struct bfa_ioc *ioc)
+{
+       return ioc->attr->pwwn;
+}
+
+mac_t
+bfa_nw_ioc_get_mac(struct bfa_ioc *ioc)
+{
+       /*
+        * Currently mfg mac is used as FCoE enode mac (not configured by PBC)
+        */
+       if (bfa_ioc_get_type(ioc) == BFA_IOC_TYPE_FCoE)
+               return bfa_ioc_get_mfg_mac(ioc);
+       else
+               return ioc->attr->mac;
+}
+
+static mac_t
+bfa_ioc_get_mfg_mac(struct bfa_ioc *ioc)
+{
+       mac_t   m;
+
+       m = ioc->attr->mfg_mac;
+       if (bfa_mfg_is_old_wwn_mac_model(ioc->attr->card_type))
+               m.mac[MAC_ADDRLEN - 1] += bfa_ioc_pcifn(ioc);
+       else
+               bfa_mfg_increment_wwn_mac(&(m.mac[MAC_ADDRLEN-3]),
+                       bfa_ioc_pcifn(ioc));
+
+       return m;
+}
+
+/**
+ * Firmware failure detected. Start recovery actions.
+ */
+static void
+bfa_ioc_recover(struct bfa_ioc *ioc)
+{
+       bfa_ioc_stats(ioc, ioc_hbfails);
+       bfa_fsm_send_event(ioc, IOC_E_HBFAIL);
+}
+
+static void
+bfa_ioc_check_attr_wwns(struct bfa_ioc *ioc)
+{
+       if (bfa_ioc_get_type(ioc) == BFA_IOC_TYPE_LL)
+               return;
+
+}
diff --git a/drivers/net/bna/bfa_ioc.h b/drivers/net/bna/bfa_ioc.h
new file mode 100644 (file)
index 0000000..7f0719e
--- /dev/null
@@ -0,0 +1,301 @@
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * 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.
+ */
+/*
+ * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+
+#ifndef __BFA_IOC_H__
+#define __BFA_IOC_H__
+
+#include "bfa_sm.h"
+#include "bfi.h"
+#include "cna.h"
+
+#define BFA_IOC_TOV            3000    /* msecs */
+#define BFA_IOC_HWSEM_TOV      500     /* msecs */
+#define BFA_IOC_HB_TOV         500     /* msecs */
+#define BFA_IOC_HWINIT_MAX     2
+#define BFA_IOC_TOV_RECOVER    BFA_IOC_HB_TOV
+
+/**
+ * Generic Scatter Gather Element used by driver
+ */
+struct bfa_sge {
+       u32     sg_len;
+       void    *sg_addr;
+};
+
+/**
+ * PCI device information required by IOC
+ */
+struct bfa_pcidev {
+       int     pci_slot;
+       u8      pci_func;
+       u16     device_id;
+       void    __iomem *pci_bar_kva;
+};
+
+/**
+ * Structure used to remember the DMA-able memory block's KVA and Physical
+ * Address
+ */
+struct bfa_dma {
+       void    *kva;   /* ! Kernel virtual address     */
+       u64     pa;     /* ! Physical address           */
+};
+
+#define BFA_DMA_ALIGN_SZ       256
+
+/**
+ * smem size for Crossbow and Catapult
+ */
+#define BFI_SMEM_CB_SIZE       0x200000U       /* ! 2MB for crossbow   */
+#define BFI_SMEM_CT_SIZE       0x280000U       /* ! 2.5MB for catapult */
+
+/**
+ * @brief BFA dma address assignment macro
+ */
+#define bfa_dma_addr_set(dma_addr, pa) \
+               __bfa_dma_addr_set(&dma_addr, (u64)pa)
+
+static inline void
+__bfa_dma_addr_set(union bfi_addr_u *dma_addr, u64 pa)
+{
+       dma_addr->a32.addr_lo = (u32) pa;
+       dma_addr->a32.addr_hi = (u32) (upper_32_bits(pa));
+}
+
+/**
+ * @brief BFA dma address assignment macro. (big endian format)
+ */
+#define bfa_dma_be_addr_set(dma_addr, pa)      \
+               __bfa_dma_be_addr_set(&dma_addr, (u64)pa)
+static inline void
+__bfa_dma_be_addr_set(union bfi_addr_u *dma_addr, u64 pa)
+{
+       dma_addr->a32.addr_lo = (u32) htonl(pa);
+       dma_addr->a32.addr_hi = (u32) htonl(upper_32_bits(pa));
+}
+
+struct bfa_ioc_regs {
+       void __iomem *hfn_mbox_cmd;
+       void __iomem *hfn_mbox;
+       void __iomem *lpu_mbox_cmd;
+       void __iomem *lpu_mbox;
+       void __iomem *pss_ctl_reg;
+       void __iomem *pss_err_status_reg;
+       void __iomem *app_pll_fast_ctl_reg;
+       void __iomem *app_pll_slow_ctl_reg;
+       void __iomem *ioc_sem_reg;
+       void __iomem *ioc_usage_sem_reg;
+       void __iomem *ioc_init_sem_reg;
+       void __iomem *ioc_usage_reg;
+       void __iomem *host_page_num_fn;
+       void __iomem *heartbeat;
+       void __iomem *ioc_fwstate;
+       void __iomem *ll_halt;
+       void __iomem *err_set;
+       void __iomem *shirq_isr_next;
+       void __iomem *shirq_msk_next;
+       void __iomem *smem_page_start;
+       u32     smem_pg0;
+};
+
+/**
+ * IOC Mailbox structures
+ */
+struct bfa_mbox_cmd {
+       struct list_head        qe;
+       u32                     msg[BFI_IOC_MSGSZ];
+};
+
+/**
+ * IOC mailbox module
+ */
+typedef void (*bfa_ioc_mbox_mcfunc_t)(void *cbarg, struct bfi_mbmsg *m);
+struct bfa_ioc_mbox_mod {
+       struct list_head        cmd_q;          /*!< pending mbox queue */
+       int                     nmclass;        /*!< number of handlers */
+       struct {
+               bfa_ioc_mbox_mcfunc_t   cbfn;   /*!< message handlers   */
+               void                    *cbarg;
+       } mbhdlr[BFI_MC_MAX];
+};
+
+/**
+ * IOC callback function interfaces
+ */
+typedef void (*bfa_ioc_enable_cbfn_t)(void *bfa, enum bfa_status status);
+typedef void (*bfa_ioc_disable_cbfn_t)(void *bfa);
+typedef void (*bfa_ioc_hbfail_cbfn_t)(void *bfa);
+typedef void (*bfa_ioc_reset_cbfn_t)(void *bfa);
+struct bfa_ioc_cbfn {
+       bfa_ioc_enable_cbfn_t   enable_cbfn;
+       bfa_ioc_disable_cbfn_t  disable_cbfn;
+       bfa_ioc_hbfail_cbfn_t   hbfail_cbfn;
+       bfa_ioc_reset_cbfn_t    reset_cbfn;
+};
+
+/**
+ * Heartbeat failure notification queue element.
+ */
+struct bfa_ioc_hbfail_notify {
+       struct list_head        qe;
+       bfa_ioc_hbfail_cbfn_t   cbfn;
+       void                    *cbarg;
+};
+
+/**
+ * Initialize a heartbeat failure notification structure
+ */
+#define bfa_ioc_hbfail_init(__notify, __cbfn, __cbarg) do {    \
+       (__notify)->cbfn = (__cbfn);                            \
+       (__notify)->cbarg = (__cbarg);                          \
+} while (0)
+
+struct bfa_ioc {
+       bfa_fsm_t               fsm;
+       struct bfa              *bfa;
+       struct bfa_pcidev       pcidev;
+       struct bfa_timer_mod    *timer_mod;
+       struct timer_list       ioc_timer;
+       struct timer_list       sem_timer;
+       struct timer_list       hb_timer;
+       u32                     hb_count;
+       u32                     retry_count;
+       struct list_head        hb_notify_q;
+       void                    *dbg_fwsave;
+       int                     dbg_fwsave_len;
+       bool                    dbg_fwsave_once;
+       enum bfi_mclass         ioc_mc;
+       struct bfa_ioc_regs     ioc_regs;
+       struct bfa_ioc_drv_stats stats;
+       bool                    auto_recover;
+       bool                    fcmode;
+       bool                    ctdev;
+       bool                    cna;
+       bool                    pllinit;
+       bool                    stats_busy;     /*!< outstanding stats */
+       u8                      port_id;
+
+       struct bfa_dma          attr_dma;
+       struct bfi_ioc_attr     *attr;
+       struct bfa_ioc_cbfn     *cbfn;
+       struct bfa_ioc_mbox_mod mbox_mod;
+       struct bfa_ioc_hwif     *ioc_hwif;
+};
+
+struct bfa_ioc_hwif {
+       enum bfa_status (*ioc_pll_init) (void __iomem *rb, bool fcmode);
+       bool            (*ioc_firmware_lock)    (struct bfa_ioc *ioc);
+       void            (*ioc_firmware_unlock)  (struct bfa_ioc *ioc);
+       void            (*ioc_reg_init) (struct bfa_ioc *ioc);
+       void            (*ioc_map_port) (struct bfa_ioc *ioc);
+       void            (*ioc_isr_mode_set)     (struct bfa_ioc *ioc,
+                                       bool msix);
+       void            (*ioc_notify_hbfail)    (struct bfa_ioc *ioc);
+       void            (*ioc_ownership_reset)  (struct bfa_ioc *ioc);
+};
+
+#define bfa_ioc_pcifn(__ioc)           ((__ioc)->pcidev.pci_func)
+#define bfa_ioc_devid(__ioc)           ((__ioc)->pcidev.device_id)
+#define bfa_ioc_bar0(__ioc)            ((__ioc)->pcidev.pci_bar_kva)
+#define bfa_ioc_portid(__ioc)          ((__ioc)->port_id)
+#define bfa_ioc_fetch_stats(__ioc, __stats) \
+               (((__stats)->drv_stats) = (__ioc)->stats)
+#define bfa_ioc_clr_stats(__ioc)       \
+               memset(&(__ioc)->stats, 0, sizeof((__ioc)->stats))
+#define bfa_ioc_maxfrsize(__ioc)       ((__ioc)->attr->maxfrsize)
+#define bfa_ioc_rx_bbcredit(__ioc)     ((__ioc)->attr->rx_bbcredit)
+#define bfa_ioc_speed_sup(__ioc)       \
+       BFI_ADAPTER_GETP(SPEED, (__ioc)->attr->adapter_prop)
+#define bfa_ioc_get_nports(__ioc)      \
+       BFI_ADAPTER_GETP(NPORTS, (__ioc)->attr->adapter_prop)
+
+#define bfa_ioc_stats(_ioc, _stats)    ((_ioc)->stats._stats++)
+#define BFA_IOC_FWIMG_MINSZ    (16 * 1024)
+#define BFA_IOC_FWIMG_TYPE(__ioc)                                      \
+       (((__ioc)->ctdev) ?                                             \
+        (((__ioc)->fcmode) ? BFI_IMAGE_CT_FC : BFI_IMAGE_CT_CNA) :     \
+        BFI_IMAGE_CB_FC)
+#define BFA_IOC_FW_SMEM_SIZE(__ioc)                                    \
+       (((__ioc)->ctdev) ? BFI_SMEM_CT_SIZE : BFI_SMEM_CB_SIZE)
+#define BFA_IOC_FLASH_CHUNK_NO(off)            (off / BFI_FLASH_CHUNK_SZ_WORDS)
+#define BFA_IOC_FLASH_OFFSET_IN_CHUNK(off)     (off % BFI_FLASH_CHUNK_SZ_WORDS)
+#define BFA_IOC_FLASH_CHUNK_ADDR(chunkno)  (chunkno * BFI_FLASH_CHUNK_SZ_WORDS)
+
+/**
+ * IOC mailbox interface
+ */
+void bfa_nw_ioc_mbox_queue(struct bfa_ioc *ioc, struct bfa_mbox_cmd *cmd);
+void bfa_nw_ioc_mbox_isr(struct bfa_ioc *ioc);
+void bfa_nw_ioc_mbox_regisr(struct bfa_ioc *ioc, enum bfi_mclass mc,
+               bfa_ioc_mbox_mcfunc_t cbfn, void *cbarg);
+
+/**
+ * IOC interfaces
+ */
+
+#define bfa_ioc_pll_init_asic(__ioc) \
+       ((__ioc)->ioc_hwif->ioc_pll_init((__ioc)->pcidev.pci_bar_kva, \
+                          (__ioc)->fcmode))
+
+#define        bfa_ioc_isr_mode_set(__ioc, __msix)                     \
+                       ((__ioc)->ioc_hwif->ioc_isr_mode_set(__ioc, __msix))
+#define        bfa_ioc_ownership_reset(__ioc)                          \
+                       ((__ioc)->ioc_hwif->ioc_ownership_reset(__ioc))
+
+void bfa_nw_ioc_set_ct_hwif(struct bfa_ioc *ioc);
+
+void bfa_nw_ioc_attach(struct bfa_ioc *ioc, void *bfa,
+               struct bfa_ioc_cbfn *cbfn);
+void bfa_nw_ioc_auto_recover(bool auto_recover);
+void bfa_nw_ioc_detach(struct bfa_ioc *ioc);
+void bfa_nw_ioc_pci_init(struct bfa_ioc *ioc, struct bfa_pcidev *pcidev,
+               enum bfi_mclass mc);
+u32 bfa_nw_ioc_meminfo(void);
+void bfa_nw_ioc_mem_claim(struct bfa_ioc *ioc,  u8 *dm_kva, u64 dm_pa);
+void bfa_nw_ioc_enable(struct bfa_ioc *ioc);
+void bfa_nw_ioc_disable(struct bfa_ioc *ioc);
+
+void bfa_nw_ioc_error_isr(struct bfa_ioc *ioc);
+bool bfa_nw_ioc_is_operational(struct bfa_ioc *ioc);
+
+void bfa_nw_ioc_get_attr(struct bfa_ioc *ioc, struct bfa_ioc_attr *ioc_attr);
+void bfa_nw_ioc_hbfail_register(struct bfa_ioc *ioc,
+       struct bfa_ioc_hbfail_notify *notify);
+bool bfa_nw_ioc_sem_get(void __iomem *sem_reg);
+void bfa_nw_ioc_sem_release(void __iomem *sem_reg);
+void bfa_nw_ioc_hw_sem_release(struct bfa_ioc *ioc);
+void bfa_nw_ioc_fwver_get(struct bfa_ioc *ioc,
+                       struct bfi_ioc_image_hdr *fwhdr);
+bool bfa_nw_ioc_fwver_cmp(struct bfa_ioc *ioc,
+                       struct bfi_ioc_image_hdr *fwhdr);
+mac_t bfa_nw_ioc_get_mac(struct bfa_ioc *ioc);
+
+/*
+ * Timeout APIs
+ */
+void bfa_nw_ioc_timeout(void *ioc);
+void bfa_nw_ioc_hb_check(void *ioc);
+void bfa_nw_ioc_sem_timeout(void *ioc);
+
+/*
+ * F/W Image Size & Chunk
+ */
+u32 *bfa_cb_image_get_chunk(int type, u32 off);
+u32 bfa_cb_image_get_size(int type);
+
+#endif /* __BFA_IOC_H__ */
diff --git a/drivers/net/bna/bfa_ioc_ct.c b/drivers/net/bna/bfa_ioc_ct.c
new file mode 100644 (file)
index 0000000..462857c
--- /dev/null
@@ -0,0 +1,392 @@
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * 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.
+ */
+/*
+ * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+
+#include "bfa_ioc.h"
+#include "cna.h"
+#include "bfi.h"
+#include "bfi_ctreg.h"
+#include "bfa_defs.h"
+
+/*
+ * forward declarations
+ */
+static bool bfa_ioc_ct_firmware_lock(struct bfa_ioc *ioc);
+static void bfa_ioc_ct_firmware_unlock(struct bfa_ioc *ioc);
+static void bfa_ioc_ct_reg_init(struct bfa_ioc *ioc);
+static void bfa_ioc_ct_map_port(struct bfa_ioc *ioc);
+static void bfa_ioc_ct_isr_mode_set(struct bfa_ioc *ioc, bool msix);
+static void bfa_ioc_ct_notify_hbfail(struct bfa_ioc *ioc);
+static void bfa_ioc_ct_ownership_reset(struct bfa_ioc *ioc);
+static enum bfa_status bfa_ioc_ct_pll_init(void __iomem *rb, bool fcmode);
+
+struct bfa_ioc_hwif nw_hwif_ct;
+
+/**
+ * Called from bfa_ioc_attach() to map asic specific calls.
+ */
+void
+bfa_nw_ioc_set_ct_hwif(struct bfa_ioc *ioc)
+{
+       nw_hwif_ct.ioc_pll_init = bfa_ioc_ct_pll_init;
+       nw_hwif_ct.ioc_firmware_lock = bfa_ioc_ct_firmware_lock;
+       nw_hwif_ct.ioc_firmware_unlock = bfa_ioc_ct_firmware_unlock;
+       nw_hwif_ct.ioc_reg_init = bfa_ioc_ct_reg_init;
+       nw_hwif_ct.ioc_map_port = bfa_ioc_ct_map_port;
+       nw_hwif_ct.ioc_isr_mode_set = bfa_ioc_ct_isr_mode_set;
+       nw_hwif_ct.ioc_notify_hbfail = bfa_ioc_ct_notify_hbfail;
+       nw_hwif_ct.ioc_ownership_reset = bfa_ioc_ct_ownership_reset;
+
+       ioc->ioc_hwif = &nw_hwif_ct;
+}
+
+/**
+ * Return true if firmware of current driver matches the running firmware.
+ */
+static bool
+bfa_ioc_ct_firmware_lock(struct bfa_ioc *ioc)
+{
+       enum bfi_ioc_state ioc_fwstate;
+       u32 usecnt;
+       struct bfi_ioc_image_hdr fwhdr;
+
+       /**
+        * Firmware match check is relevant only for CNA.
+        */
+       if (!ioc->cna)
+               return true;
+
+       /**
+        * If bios boot (flash based) -- do not increment usage count
+        */
+       if (bfa_cb_image_get_size(BFA_IOC_FWIMG_TYPE(ioc)) <
+                                               BFA_IOC_FWIMG_MINSZ)
+               return true;
+
+       bfa_nw_ioc_sem_get(ioc->ioc_regs.ioc_usage_sem_reg);
+       usecnt = readl(ioc->ioc_regs.ioc_usage_reg);
+
+       /**
+        * If usage count is 0, always return TRUE.
+        */
+       if (usecnt == 0) {
+               writel(1, ioc->ioc_regs.ioc_usage_reg);
+               bfa_nw_ioc_sem_release(ioc->ioc_regs.ioc_usage_sem_reg);
+               return true;
+       }
+
+       ioc_fwstate = readl(ioc->ioc_regs.ioc_fwstate);
+
+       /**
+        * Use count cannot be non-zero and chip in uninitialized state.
+        */
+       BUG_ON(!(ioc_fwstate != BFI_IOC_UNINIT));
+
+       /**
+        * Check if another driver with a different firmware is active
+        */
+       bfa_nw_ioc_fwver_get(ioc, &fwhdr);
+       if (!bfa_nw_ioc_fwver_cmp(ioc, &fwhdr)) {
+               bfa_nw_ioc_sem_release(ioc->ioc_regs.ioc_usage_sem_reg);
+               return false;
+       }
+
+       /**
+        * Same firmware version. Increment the reference count.
+        */
+       usecnt++;
+       writel(usecnt, ioc->ioc_regs.ioc_usage_reg);
+       bfa_nw_ioc_sem_release(ioc->ioc_regs.ioc_usage_sem_reg);
+       return true;
+}
+
+static void
+bfa_ioc_ct_firmware_unlock(struct bfa_ioc *ioc)
+{
+       u32 usecnt;
+
+       /**
+        * Firmware lock is relevant only for CNA.
+        */
+       if (!ioc->cna)
+               return;
+
+       /**
+        * If bios boot (flash based) -- do not decrement usage count
+        */
+       if (bfa_cb_image_get_size(BFA_IOC_FWIMG_TYPE(ioc)) <
+                                               BFA_IOC_FWIMG_MINSZ)
+               return;
+
+       /**
+        * decrement usage count
+        */
+       bfa_nw_ioc_sem_get(ioc->ioc_regs.ioc_usage_sem_reg);
+       usecnt = readl(ioc->ioc_regs.ioc_usage_reg);
+       BUG_ON(!(usecnt > 0));
+
+       usecnt--;
+       writel(usecnt, ioc->ioc_regs.ioc_usage_reg);
+
+       bfa_nw_ioc_sem_release(ioc->ioc_regs.ioc_usage_sem_reg);
+}
+
+/**
+ * Notify other functions on HB failure.
+ */
+static void
+bfa_ioc_ct_notify_hbfail(struct bfa_ioc *ioc)
+{
+       if (ioc->cna) {
+               writel(__FW_INIT_HALT_P, ioc->ioc_regs.ll_halt);
+               /* Wait for halt to take effect */
+               readl(ioc->ioc_regs.ll_halt);
+       } else {
+               writel(__PSS_ERR_STATUS_SET, ioc->ioc_regs.err_set);
+               readl(ioc->ioc_regs.err_set);
+       }
+}
+
+/**
+ * Host to LPU mailbox message addresses
+ */
+static struct { u32 hfn_mbox, lpu_mbox, hfn_pgn; } iocreg_fnreg[] = {
+       { HOSTFN0_LPU_MBOX0_0, LPU_HOSTFN0_MBOX0_0, HOST_PAGE_NUM_FN0 },
+       { HOSTFN1_LPU_MBOX0_8, LPU_HOSTFN1_MBOX0_8, HOST_PAGE_NUM_FN1 },
+       { HOSTFN2_LPU_MBOX0_0, LPU_HOSTFN2_MBOX0_0, HOST_PAGE_NUM_FN2 },
+       { HOSTFN3_LPU_MBOX0_8, LPU_HOSTFN3_MBOX0_8, HOST_PAGE_NUM_FN3 }
+};
+
+/**
+ * Host <-> LPU mailbox command/status registers - port 0
+ */
+static struct { u32 hfn, lpu; } iocreg_mbcmd_p0[] = {
+       { HOSTFN0_LPU0_MBOX0_CMD_STAT, LPU0_HOSTFN0_MBOX0_CMD_STAT },
+       { HOSTFN1_LPU0_MBOX0_CMD_STAT, LPU0_HOSTFN1_MBOX0_CMD_STAT },
+       { HOSTFN2_LPU0_MBOX0_CMD_STAT, LPU0_HOSTFN2_MBOX0_CMD_STAT },
+       { HOSTFN3_LPU0_MBOX0_CMD_STAT, LPU0_HOSTFN3_MBOX0_CMD_STAT }
+};
+
+/**
+ * Host <-> LPU mailbox command/status registers - port 1
+ */
+static struct { u32 hfn, lpu; } iocreg_mbcmd_p1[] = {
+       { HOSTFN0_LPU1_MBOX0_CMD_STAT, LPU1_HOSTFN0_MBOX0_CMD_STAT },
+       { HOSTFN1_LPU1_MBOX0_CMD_STAT, LPU1_HOSTFN1_MBOX0_CMD_STAT },
+       { HOSTFN2_LPU1_MBOX0_CMD_STAT, LPU1_HOSTFN2_MBOX0_CMD_STAT },
+       { HOSTFN3_LPU1_MBOX0_CMD_STAT, LPU1_HOSTFN3_MBOX0_CMD_STAT }
+};
+
+static void
+bfa_ioc_ct_reg_init(struct bfa_ioc *ioc)
+{
+       void __iomem *rb;
+       int             pcifn = bfa_ioc_pcifn(ioc);
+
+       rb = bfa_ioc_bar0(ioc);
+
+       ioc->ioc_regs.hfn_mbox = rb + iocreg_fnreg[pcifn].hfn_mbox;
+       ioc->ioc_regs.lpu_mbox = rb + iocreg_fnreg[pcifn].lpu_mbox;
+       ioc->ioc_regs.host_page_num_fn = rb + iocreg_fnreg[pcifn].hfn_pgn;
+
+       if (ioc->port_id == 0) {
+               ioc->ioc_regs.heartbeat = rb + BFA_IOC0_HBEAT_REG;
+               ioc->ioc_regs.ioc_fwstate = rb + BFA_IOC0_STATE_REG;
+               ioc->ioc_regs.hfn_mbox_cmd = rb + iocreg_mbcmd_p0[pcifn].hfn;
+               ioc->ioc_regs.lpu_mbox_cmd = rb + iocreg_mbcmd_p0[pcifn].lpu;
+               ioc->ioc_regs.ll_halt = rb + FW_INIT_HALT_P0;
+       } else {
+               ioc->ioc_regs.heartbeat = (rb + BFA_IOC1_HBEAT_REG);
+               ioc->ioc_regs.ioc_fwstate = (rb + BFA_IOC1_STATE_REG);
+               ioc->ioc_regs.hfn_mbox_cmd = rb + iocreg_mbcmd_p1[pcifn].hfn;
+               ioc->ioc_regs.lpu_mbox_cmd = rb + iocreg_mbcmd_p1[pcifn].lpu;
+               ioc->ioc_regs.ll_halt = rb + FW_INIT_HALT_P1;
+       }
+
+       /*
+        * PSS control registers
+        */
+       ioc->ioc_regs.pss_ctl_reg = (rb + PSS_CTL_REG);
+       ioc->ioc_regs.pss_err_status_reg = (rb + PSS_ERR_STATUS_REG);
+       ioc->ioc_regs.app_pll_fast_ctl_reg = (rb + APP_PLL_425_CTL_REG);
+       ioc->ioc_regs.app_pll_slow_ctl_reg = (rb + APP_PLL_312_CTL_REG);
+
+       /*
+        * IOC semaphore registers and serialization
+        */
+       ioc->ioc_regs.ioc_sem_reg = (rb + HOST_SEM0_REG);
+       ioc->ioc_regs.ioc_usage_sem_reg = (rb + HOST_SEM1_REG);
+       ioc->ioc_regs.ioc_init_sem_reg = (rb + HOST_SEM2_REG);
+       ioc->ioc_regs.ioc_usage_reg = (rb + BFA_FW_USE_COUNT);
+
+       /**
+        * sram memory access
+        */
+       ioc->ioc_regs.smem_page_start = (rb + PSS_SMEM_PAGE_START);
+       ioc->ioc_regs.smem_pg0 = BFI_IOC_SMEM_PG0_CT;
+
+       /*
+        * err set reg : for notification of hb failure in fcmode
+        */
+       ioc->ioc_regs.err_set = (rb + ERR_SET_REG);
+}
+
+/**
+ * Initialize IOC to port mapping.
+ */
+
+#define FNC_PERS_FN_SHIFT(__fn)        ((__fn) * 8)
+static void
+bfa_ioc_ct_map_port(struct bfa_ioc *ioc)
+{
+       void __iomem *rb = ioc->pcidev.pci_bar_kva;
+       u32     r32;
+
+       /**
+        * For catapult, base port id on personality register and IOC type
+        */
+       r32 = readl(rb + FNC_PERS_REG);
+       r32 >>= FNC_PERS_FN_SHIFT(bfa_ioc_pcifn(ioc));
+       ioc->port_id = (r32 & __F0_PORT_MAP_MK) >> __F0_PORT_MAP_SH;
+
+}
+
+/**
+ * Set interrupt mode for a function: INTX or MSIX
+ */
+static void
+bfa_ioc_ct_isr_mode_set(struct bfa_ioc *ioc, bool msix)
+{
+       void __iomem *rb = ioc->pcidev.pci_bar_kva;
+       u32     r32, mode;
+
+       r32 = readl(rb + FNC_PERS_REG);
+
+       mode = (r32 >> FNC_PERS_FN_SHIFT(bfa_ioc_pcifn(ioc))) &
+               __F0_INTX_STATUS;
+
+       /**
+        * If already in desired mode, do not change anything
+        */
+       if (!msix && mode)
+               return;
+
+       if (msix)
+               mode = __F0_INTX_STATUS_MSIX;
+       else
+               mode = __F0_INTX_STATUS_INTA;
+
+       r32 &= ~(__F0_INTX_STATUS << FNC_PERS_FN_SHIFT(bfa_ioc_pcifn(ioc)));
+       r32 |= (mode << FNC_PERS_FN_SHIFT(bfa_ioc_pcifn(ioc)));
+
+       writel(r32, rb + FNC_PERS_REG);
+}
+
+/**
+ * Cleanup hw semaphore and usecnt registers
+ */
+static void
+bfa_ioc_ct_ownership_reset(struct bfa_ioc *ioc)
+{
+       if (ioc->cna) {
+               bfa_nw_ioc_sem_get(ioc->ioc_regs.ioc_usage_sem_reg);
+               writel(0, ioc->ioc_regs.ioc_usage_reg);
+               bfa_nw_ioc_sem_release(ioc->ioc_regs.ioc_usage_sem_reg);
+       }
+
+       /*
+        * Read the hw sem reg to make sure that it is locked
+        * before we clear it. If it is not locked, writing 1
+        * will lock it instead of clearing it.
+        */
+       readl(ioc->ioc_regs.ioc_sem_reg);
+       bfa_nw_ioc_hw_sem_release(ioc);
+}
+
+static enum bfa_status
+bfa_ioc_ct_pll_init(void __iomem *rb, bool fcmode)
+{
+       u32     pll_sclk, pll_fclk, r32;
+
+       pll_sclk = __APP_PLL_312_LRESETN | __APP_PLL_312_ENARST |
+               __APP_PLL_312_RSEL200500 | __APP_PLL_312_P0_1(3U) |
+               __APP_PLL_312_JITLMT0_1(3U) |
+               __APP_PLL_312_CNTLMT0_1(1U);
+       pll_fclk = __APP_PLL_425_LRESETN | __APP_PLL_425_ENARST |
+               __APP_PLL_425_RSEL200500 | __APP_PLL_425_P0_1(3U) |
+               __APP_PLL_425_JITLMT0_1(3U) |
+               __APP_PLL_425_CNTLMT0_1(1U);
+       if (fcmode) {
+               writel(0, (rb + OP_MODE));
+               writel(__APP_EMS_CMLCKSEL |
+                               __APP_EMS_REFCKBUFEN2 |
+                               __APP_EMS_CHANNEL_SEL,
+                               (rb + ETH_MAC_SER_REG));
+       } else {
+               writel(__GLOBAL_FCOE_MODE, (rb + OP_MODE));
+               writel(__APP_EMS_REFCKBUFEN1,
+                               (rb + ETH_MAC_SER_REG));
+       }
+       writel(BFI_IOC_UNINIT, (rb + BFA_IOC0_STATE_REG));
+       writel(BFI_IOC_UNINIT, (rb + BFA_IOC1_STATE_REG));
+       writel(0xffffffffU, (rb + HOSTFN0_INT_MSK));
+       writel(0xffffffffU, (rb + HOSTFN1_INT_MSK));
+       writel(0xffffffffU, (rb + HOSTFN0_INT_STATUS));
+       writel(0xffffffffU, (rb + HOSTFN1_INT_STATUS));
+       writel(0xffffffffU, (rb + HOSTFN0_INT_MSK));
+       writel(0xffffffffU, (rb + HOSTFN1_INT_MSK));
+       writel(pll_sclk |
+               __APP_PLL_312_LOGIC_SOFT_RESET,
+               rb + APP_PLL_312_CTL_REG);
+       writel(pll_fclk |
+               __APP_PLL_425_LOGIC_SOFT_RESET,
+               rb + APP_PLL_425_CTL_REG);
+       writel(pll_sclk |
+               __APP_PLL_312_LOGIC_SOFT_RESET | __APP_PLL_312_ENABLE,
+               rb + APP_PLL_312_CTL_REG);
+       writel(pll_fclk |
+               __APP_PLL_425_LOGIC_SOFT_RESET | __APP_PLL_425_ENABLE,
+               rb + APP_PLL_425_CTL_REG);
+       readl(rb + HOSTFN0_INT_MSK);
+       udelay(2000);
+       writel(0xffffffffU, (rb + HOSTFN0_INT_STATUS));
+       writel(0xffffffffU, (rb + HOSTFN1_INT_STATUS));
+       writel(pll_sclk |
+               __APP_PLL_312_ENABLE,
+               rb + APP_PLL_312_CTL_REG);
+       writel(pll_fclk |
+               __APP_PLL_425_ENABLE,
+               rb + APP_PLL_425_CTL_REG);
+       if (!fcmode) {
+               writel(__PMM_1T_RESET_P, (rb + PMM_1T_RESET_REG_P0));
+               writel(__PMM_1T_RESET_P, (rb + PMM_1T_RESET_REG_P1));
+       }
+       r32 = readl((rb + PSS_CTL_REG));
+       r32 &= ~__PSS_LMEM_RESET;
+       writel(r32, (rb + PSS_CTL_REG));
+       udelay(1000);
+       if (!fcmode) {
+               writel(0, (rb + PMM_1T_RESET_REG_P0));
+               writel(0, (rb + PMM_1T_RESET_REG_P1));
+       }
+
+       writel(__EDRAM_BISTR_START, (rb + MBIST_CTL_REG));
+       udelay(1000);
+       r32 = readl((rb + MBIST_STAT_REG));
+       writel(0, (rb + MBIST_CTL_REG));
+       return BFA_STATUS_OK;
+}
diff --git a/drivers/net/bna/bfa_sm.h b/drivers/net/bna/bfa_sm.h
new file mode 100644 (file)
index 0000000..1d3d975
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * 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.
+ */
+/*
+ * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+
+/**
+ * @file bfasm.h State machine defines
+ */
+
+#ifndef __BFA_SM_H__
+#define __BFA_SM_H__
+
+#include "cna.h"
+
+typedef void (*bfa_sm_t)(void *sm, int event);
+
+/**
+ * oc - object class eg. bfa_ioc
+ * st - state, eg. reset
+ * otype - object type, eg. struct bfa_ioc
+ * etype - object type, eg. enum ioc_event
+ */
+#define bfa_sm_state_decl(oc, st, otype, etype)                \
+       static void oc ## _sm_ ## st(otype * fsm, etype event)
+
+#define bfa_sm_set_state(_sm, _state)  ((_sm)->sm = (bfa_sm_t)(_state))
+#define bfa_sm_send_event(_sm, _event) ((_sm)->sm((_sm), (_event)))
+#define bfa_sm_get_state(_sm)          ((_sm)->sm)
+#define bfa_sm_cmp_state(_sm, _state)  ((_sm)->sm == (bfa_sm_t)(_state))
+
+/**
+ * For converting from state machine function to state encoding.
+ */
+struct bfa_sm_table {
+       bfa_sm_t        sm;     /*!< state machine function     */
+       int             state;  /*!< state machine encoding     */
+       char            *name;  /*!< state name for display     */
+};
+#define BFA_SM(_sm)    ((bfa_sm_t)(_sm))
+
+/**
+ * State machine with entry actions.
+ */
+typedef void (*bfa_fsm_t)(void *fsm, int event);
+
+/**
+ * oc - object class eg. bfa_ioc
+ * st - state, eg. reset
+ * otype - object type, eg. struct bfa_ioc
+ * etype - object type, eg. enum ioc_event
+ */
+#define bfa_fsm_state_decl(oc, st, otype, etype)               \
+       static void oc ## _sm_ ## st(otype * fsm, etype event); \
+       static void oc ## _sm_ ## st ## _entry(otype * fsm)
+
+#define bfa_fsm_set_state(_fsm, _state) do {   \
+       (_fsm)->fsm = (bfa_fsm_t)(_state);      \
+       _state ## _entry(_fsm);                 \
+} while (0)
+
+#define bfa_fsm_send_event(_fsm, _event)       ((_fsm)->fsm((_fsm), (_event)))
+#define bfa_fsm_get_state(_fsm)                        ((_fsm)->fsm)
+#define bfa_fsm_cmp_state(_fsm, _state)                \
+       ((_fsm)->fsm == (bfa_fsm_t)(_state))
+
+static inline int
+bfa_sm_to_state(struct bfa_sm_table *smt, bfa_sm_t sm)
+{
+       int     i = 0;
+
+       while (smt[i].sm && smt[i].sm != sm)
+               i++;
+       return smt[i].state;
+}
+#endif
diff --git a/drivers/net/bna/bfa_wc.h b/drivers/net/bna/bfa_wc.h
new file mode 100644 (file)
index 0000000..d0e4cae
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * 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.
+ */
+/*
+ * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+
+/**
+ * @file bfa_wc.h Generic wait counter.
+ */
+
+#ifndef __BFA_WC_H__
+#define __BFA_WC_H__
+
+typedef void (*bfa_wc_resume_t) (void *cbarg);
+
+struct bfa_wc {
+       bfa_wc_resume_t wc_resume;
+       void            *wc_cbarg;
+       int             wc_count;
+};
+
+static inline void
+bfa_wc_up(struct bfa_wc *wc)
+{
+       wc->wc_count++;
+}
+
+static inline void
+bfa_wc_down(struct bfa_wc *wc)
+{
+       wc->wc_count--;
+       if (wc->wc_count == 0)
+               wc->wc_resume(wc->wc_cbarg);
+}
+
+/**
+ * Initialize a waiting counter.
+ */
+static inline void
+bfa_wc_init(struct bfa_wc *wc, bfa_wc_resume_t wc_resume, void *wc_cbarg)
+{
+       wc->wc_resume = wc_resume;
+       wc->wc_cbarg = wc_cbarg;
+       wc->wc_count = 0;
+       bfa_wc_up(wc);
+}
+
+/**
+ * Wait for counter to reach zero
+ */
+static inline void
+bfa_wc_wait(struct bfa_wc *wc)
+{
+       bfa_wc_down(wc);
+}
+
+#endif
diff --git a/drivers/net/bna/bfi.h b/drivers/net/bna/bfi.h
new file mode 100644 (file)
index 0000000..a973968
--- /dev/null
@@ -0,0 +1,392 @@
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * 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.
+ */
+/*
+ * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+
+#ifndef __BFI_H__
+#define __BFI_H__
+
+#include "bfa_defs.h"
+
+#pragma pack(1)
+
+/**
+ * BFI FW image type
+ */
+#define        BFI_FLASH_CHUNK_SZ                      256     /*!< Flash chunk size */
+#define        BFI_FLASH_CHUNK_SZ_WORDS        (BFI_FLASH_CHUNK_SZ/sizeof(u32))
+enum {
+       BFI_IMAGE_CB_FC,
+       BFI_IMAGE_CT_FC,
+       BFI_IMAGE_CT_CNA,
+       BFI_IMAGE_MAX,
+};
+
+/**
+ * Msg header common to all msgs
+ */
+struct bfi_mhdr {
+       u8              msg_class;      /*!< @ref enum bfi_mclass           */
+       u8              msg_id;         /*!< msg opcode with in the class   */
+       union {
+               struct {
+                       u8      rsvd;
+                       u8      lpu_id; /*!< msg destination                */
+               } h2i;
+               u16     i2htok; /*!< token in msgs to host          */
+       } mtag;
+};
+
+#define bfi_h2i_set(_mh, _mc, _op, _lpuid) do {                \
+       (_mh).msg_class                 = (_mc);                \
+       (_mh).msg_id                    = (_op);                \
+       (_mh).mtag.h2i.lpu_id   = (_lpuid);                     \
+} while (0)
+
+#define bfi_i2h_set(_mh, _mc, _op, _i2htok) do {               \
+       (_mh).msg_class                 = (_mc);                \
+       (_mh).msg_id                    = (_op);                \
+       (_mh).mtag.i2htok               = (_i2htok);            \
+} while (0)
+
+/*
+ * Message opcodes: 0-127 to firmware, 128-255 to host
+ */
+#define BFI_I2H_OPCODE_BASE    128
+#define BFA_I2HM(_x)                   ((_x) + BFI_I2H_OPCODE_BASE)
+
+/**
+ ****************************************************************************
+ *
+ * Scatter Gather Element and Page definition
+ *
+ ****************************************************************************
+ */
+
+#define BFI_SGE_INLINE 1
+#define BFI_SGE_INLINE_MAX     (BFI_SGE_INLINE + 1)
+
+/**
+ * SG Flags
+ */
+enum {
+       BFI_SGE_DATA            = 0,    /*!< data address, not last          */
+       BFI_SGE_DATA_CPL        = 1,    /*!< data addr, last in current page */
+       BFI_SGE_DATA_LAST       = 3,    /*!< data address, last              */
+       BFI_SGE_LINK            = 2,    /*!< link address                    */
+       BFI_SGE_PGDLEN          = 2,    /*!< cumulative data length for page */
+};
+
+/**
+ * DMA addresses
+ */
+union bfi_addr_u {
+       struct {
+               u32     addr_lo;
+               u32     addr_hi;
+       } a32;
+};
+
+/**
+ * Scatter Gather Element
+ */
+struct bfi_sge {
+#ifdef __BIGENDIAN
+       u32     flags:2,
+                       rsvd:2,
+                       sg_len:28;
+#else
+       u32     sg_len:28,
+                       rsvd:2,
+                       flags:2;
+#endif
+       union bfi_addr_u sga;
+};
+
+/**
+ * Scatter Gather Page
+ */
+#define BFI_SGPG_DATA_SGES             7
+#define BFI_SGPG_SGES_MAX              (BFI_SGPG_DATA_SGES + 1)
+#define BFI_SGPG_RSVD_WD_LEN   8
+struct bfi_sgpg {
+       struct bfi_sge sges[BFI_SGPG_SGES_MAX];
+       u32     rsvd[BFI_SGPG_RSVD_WD_LEN];
+};
+
+/*
+ * Large Message structure - 128 Bytes size Msgs
+ */
+#define BFI_LMSG_SZ            128
+#define BFI_LMSG_PL_WSZ        \
+                       ((BFI_LMSG_SZ - sizeof(struct bfi_mhdr)) / 4)
+
+struct bfi_msg {
+       struct bfi_mhdr mhdr;
+       u32     pl[BFI_LMSG_PL_WSZ];
+};
+
+/**
+ * Mailbox message structure
+ */
+#define BFI_MBMSG_SZ           7
+struct bfi_mbmsg {
+       struct bfi_mhdr mh;
+       u32             pl[BFI_MBMSG_SZ];
+};
+
+/**
+ * Message Classes
+ */
+enum bfi_mclass {
+       BFI_MC_IOC              = 1,    /*!< IO Controller (IOC)            */
+       BFI_MC_DIAG             = 2,    /*!< Diagnostic Msgs                */
+       BFI_MC_FLASH            = 3,    /*!< Flash message class            */
+       BFI_MC_CEE              = 4,    /*!< CEE                            */
+       BFI_MC_FCPORT           = 5,    /*!< FC port                        */
+       BFI_MC_IOCFC            = 6,    /*!< FC - IO Controller (IOC)       */
+       BFI_MC_LL               = 7,    /*!< Link Layer                     */
+       BFI_MC_UF               = 8,    /*!< Unsolicited frame receive      */
+       BFI_MC_FCXP             = 9,    /*!< FC Transport                   */
+       BFI_MC_LPS              = 10,   /*!< lport fc login services        */
+       BFI_MC_RPORT            = 11,   /*!< Remote port                    */
+       BFI_MC_ITNIM            = 12,   /*!< I-T nexus (Initiator mode)     */
+       BFI_MC_IOIM_READ        = 13,   /*!< read IO (Initiator mode)       */
+       BFI_MC_IOIM_WRITE       = 14,   /*!< write IO (Initiator mode)      */
+       BFI_MC_IOIM_IO          = 15,   /*!< IO (Initiator mode)            */
+       BFI_MC_IOIM             = 16,   /*!< IO (Initiator mode)            */
+       BFI_MC_IOIM_IOCOM       = 17,   /*!< good IO completion             */
+       BFI_MC_TSKIM            = 18,   /*!< Initiator Task management      */
+       BFI_MC_SBOOT            = 19,   /*!< SAN boot services              */
+       BFI_MC_IPFC             = 20,   /*!< IP over FC Msgs                */
+       BFI_MC_PORT             = 21,   /*!< Physical port                  */
+       BFI_MC_SFP              = 22,   /*!< SFP module                     */
+       BFI_MC_MSGQ             = 23,   /*!< MSGQ                           */
+       BFI_MC_ENET             = 24,   /*!< ENET commands/responses        */
+       BFI_MC_MAX              = 32
+};
+
+#define BFI_IOC_MAX_CQS                4
+#define BFI_IOC_MAX_CQS_ASIC   8
+#define BFI_IOC_MSGLEN_MAX     32      /* 32 bytes */
+
+#define BFI_BOOT_TYPE_OFF              8
+#define BFI_BOOT_PARAM_OFF             12
+
+#define BFI_BOOT_TYPE_NORMAL           0       /* param is device id */
+#define        BFI_BOOT_TYPE_FLASH             1
+#define        BFI_BOOT_TYPE_MEMTEST           2
+
+#define BFI_BOOT_MEMTEST_RES_ADDR   0x900
+#define BFI_BOOT_MEMTEST_RES_SIG    0xA0A1A2A3
+
+/**
+ *----------------------------------------------------------------------
+ *                             IOC
+ *----------------------------------------------------------------------
+ */
+
+enum bfi_ioc_h2i_msgs {
+       BFI_IOC_H2I_ENABLE_REQ          = 1,
+       BFI_IOC_H2I_DISABLE_REQ         = 2,
+       BFI_IOC_H2I_GETATTR_REQ         = 3,
+       BFI_IOC_H2I_DBG_SYNC            = 4,
+       BFI_IOC_H2I_DBG_DUMP            = 5,
+};
+
+enum bfi_ioc_i2h_msgs {
+       BFI_IOC_I2H_ENABLE_REPLY        = BFA_I2HM(1),
+       BFI_IOC_I2H_DISABLE_REPLY       = BFA_I2HM(2),
+       BFI_IOC_I2H_GETATTR_REPLY       = BFA_I2HM(3),
+       BFI_IOC_I2H_READY_EVENT         = BFA_I2HM(4),
+       BFI_IOC_I2H_HBEAT               = BFA_I2HM(5),
+};
+
+/**
+ * BFI_IOC_H2I_GETATTR_REQ message
+ */
+struct bfi_ioc_getattr_req {
+       struct bfi_mhdr mh;
+       union bfi_addr_u        attr_addr;
+};
+
+struct bfi_ioc_attr {
+       u64             mfg_pwwn;       /*!< Mfg port wwn          */
+       u64             mfg_nwwn;       /*!< Mfg node wwn          */
+       mac_t           mfg_mac;        /*!< Mfg mac               */
+       u16     rsvd_a;
+       u64             pwwn;
+       u64             nwwn;
+       mac_t           mac;            /*!< PBC or Mfg mac        */
+       u16     rsvd_b;
+       mac_t           fcoe_mac;
+       u16     rsvd_c;
+       char            brcd_serialnum[STRSZ(BFA_MFG_SERIALNUM_SIZE)];
+       u8              pcie_gen;
+       u8              pcie_lanes_orig;
+       u8              pcie_lanes;
+       u8              rx_bbcredit;    /*!< receive buffer credits */
+       u32     adapter_prop;   /*!< adapter properties     */
+       u16     maxfrsize;      /*!< max receive frame size */
+       char            asic_rev;
+       u8              rsvd_d;
+       char            fw_version[BFA_VERSION_LEN];
+       char            optrom_version[BFA_VERSION_LEN];
+       struct bfa_mfg_vpd vpd;
+       u32     card_type;      /*!< card type                  */
+};
+
+/**
+ * BFI_IOC_I2H_GETATTR_REPLY message
+ */
+struct bfi_ioc_getattr_reply {
+       struct bfi_mhdr mh;     /*!< Common msg header          */
+       u8                      status; /*!< cfg reply status           */
+       u8                      rsvd[3];
+};
+
+/**
+ * Firmware memory page offsets
+ */
+#define BFI_IOC_SMEM_PG0_CB    (0x40)
+#define BFI_IOC_SMEM_PG0_CT    (0x180)
+
+/**
+ * Firmware statistic offset
+ */
+#define BFI_IOC_FWSTATS_OFF    (0x6B40)
+#define BFI_IOC_FWSTATS_SZ     (4096)
+
+/**
+ * Firmware trace offset
+ */
+#define BFI_IOC_TRC_OFF                (0x4b00)
+#define BFI_IOC_TRC_ENTS       256
+
+#define BFI_IOC_FW_SIGNATURE   (0xbfadbfad)
+#define BFI_IOC_MD5SUM_SZ      4
+struct bfi_ioc_image_hdr {
+       u32     signature;      /*!< constant signature */
+       u32     rsvd_a;
+       u32     exec;           /*!< exec vector        */
+       u32     param;          /*!< parameters         */
+       u32     rsvd_b[4];
+       u32     md5sum[BFI_IOC_MD5SUM_SZ];
+};
+
+/**
+ *  BFI_IOC_I2H_READY_EVENT message
+ */
+struct bfi_ioc_rdy_event {
+       struct bfi_mhdr mh;             /*!< common msg header */
+       u8                      init_status;    /*!< init event status */
+       u8                      rsvd[3];
+};
+
+struct bfi_ioc_hbeat {
+       struct bfi_mhdr mh;             /*!< common msg header          */
+       u32        hb_count;    /*!< current heart beat count   */
+};
+
+/**
+ * IOC hardware/firmware state
+ */
+enum bfi_ioc_state {
+       BFI_IOC_UNINIT          = 0,    /*!< not initialized                 */
+       BFI_IOC_INITING         = 1,    /*!< h/w is being initialized        */
+       BFI_IOC_HWINIT          = 2,    /*!< h/w is initialized              */
+       BFI_IOC_CFG             = 3,    /*!< IOC configuration in progress   */
+       BFI_IOC_OP              = 4,    /*!< IOC is operational              */
+       BFI_IOC_DISABLING       = 5,    /*!< IOC is being disabled           */
+       BFI_IOC_DISABLED        = 6,    /*!< IOC is disabled                 */
+       BFI_IOC_CFG_DISABLED    = 7,    /*!< IOC is being disabled;transient */
+       BFI_IOC_FAIL            = 8,    /*!< IOC heart-beat failure          */
+       BFI_IOC_MEMTEST         = 9,    /*!< IOC is doing memtest            */
+};
+
+#define BFI_IOC_ENDIAN_SIG  0x12345678
+
+enum {
+       BFI_ADAPTER_TYPE_FC     = 0x01,         /*!< FC adapters           */
+       BFI_ADAPTER_TYPE_MK     = 0x0f0000,     /*!< adapter type mask     */
+       BFI_ADAPTER_TYPE_SH     = 16,           /*!< adapter type shift    */
+       BFI_ADAPTER_NPORTS_MK   = 0xff00,       /*!< number of ports mask  */
+       BFI_ADAPTER_NPORTS_SH   = 8,            /*!< number of ports shift */
+       BFI_ADAPTER_SPEED_MK    = 0xff,         /*!< adapter speed mask    */
+       BFI_ADAPTER_SPEED_SH    = 0,            /*!< adapter speed shift   */
+       BFI_ADAPTER_PROTO       = 0x100000,     /*!< prototype adapaters   */
+       BFI_ADAPTER_TTV         = 0x200000,     /*!< TTV debug capable     */
+       BFI_ADAPTER_UNSUPP      = 0x400000,     /*!< unknown adapter type  */
+};
+
+#define BFI_ADAPTER_GETP(__prop, __adap_prop)                  \
+       (((__adap_prop) & BFI_ADAPTER_ ## __prop ## _MK) >>     \
+               BFI_ADAPTER_ ## __prop ## _SH)
+#define BFI_ADAPTER_SETP(__prop, __val)                                \
+       ((__val) << BFI_ADAPTER_ ## __prop ## _SH)
+#define BFI_ADAPTER_IS_PROTO(__adap_type)                      \
+       ((__adap_type) & BFI_ADAPTER_PROTO)
+#define BFI_ADAPTER_IS_TTV(__adap_type)                                \
+       ((__adap_type) & BFI_ADAPTER_TTV)
+#define BFI_ADAPTER_IS_UNSUPP(__adap_type)                     \
+       ((__adap_type) & BFI_ADAPTER_UNSUPP)
+#define BFI_ADAPTER_IS_SPECIAL(__adap_type)                    \
+       ((__adap_type) & (BFI_ADAPTER_TTV | BFI_ADAPTER_PROTO | \
+                       BFI_ADAPTER_UNSUPP))
+
+/**
+ * BFI_IOC_H2I_ENABLE_REQ & BFI_IOC_H2I_DISABLE_REQ messages
+ */
+struct bfi_ioc_ctrl_req {
+       struct bfi_mhdr mh;
+       u8                      ioc_class;
+       u8                      rsvd[3];
+       u32             tv_sec;
+};
+
+/**
+ * BFI_IOC_I2H_ENABLE_REPLY & BFI_IOC_I2H_DISABLE_REPLY messages
+ */
+struct bfi_ioc_ctrl_reply {
+       struct bfi_mhdr mh;             /*!< Common msg header     */
+       u8                      status;         /*!< enable/disable status */
+       u8                      rsvd[3];
+};
+
+#define BFI_IOC_MSGSZ   8
+/**
+ * H2I Messages
+ */
+union bfi_ioc_h2i_msg_u {
+       struct bfi_mhdr mh;
+       struct bfi_ioc_ctrl_req enable_req;
+       struct bfi_ioc_ctrl_req disable_req;
+       struct bfi_ioc_getattr_req getattr_req;
+       u32                     mboxmsg[BFI_IOC_MSGSZ];
+};
+
+/**
+ * I2H Messages
+ */
+union bfi_ioc_i2h_msg_u {
+       struct bfi_mhdr mh;
+       struct bfi_ioc_rdy_event rdy_event;
+       u32                     mboxmsg[BFI_IOC_MSGSZ];
+};
+
+#pragma pack()
+
+#endif /* __BFI_H__ */
diff --git a/drivers/net/bna/bfi_cna.h b/drivers/net/bna/bfi_cna.h
new file mode 100644 (file)
index 0000000..4eecabe
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * 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.
+ */
+/*
+ * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+#ifndef __BFI_CNA_H__
+#define __BFI_CNA_H__
+
+#include "bfi.h"
+#include "bfa_defs_cna.h"
+
+#pragma pack(1)
+
+enum bfi_port_h2i {
+       BFI_PORT_H2I_ENABLE_REQ         = (1),
+       BFI_PORT_H2I_DISABLE_REQ        = (2),
+       BFI_PORT_H2I_GET_STATS_REQ      = (3),
+       BFI_PORT_H2I_CLEAR_STATS_REQ    = (4),
+};
+
+enum bfi_port_i2h {
+       BFI_PORT_I2H_ENABLE_RSP         = BFA_I2HM(1),
+       BFI_PORT_I2H_DISABLE_RSP        = BFA_I2HM(2),
+       BFI_PORT_I2H_GET_STATS_RSP      = BFA_I2HM(3),
+       BFI_PORT_I2H_CLEAR_STATS_RSP    = BFA_I2HM(4),
+};
+
+/**
+ * Generic REQ type
+ */
+struct bfi_port_generic_req {
+       struct bfi_mhdr mh;             /*!< msg header                     */
+       u32     msgtag;         /*!< msgtag for reply               */
+       u32     rsvd;
+};
+
+/**
+ * Generic RSP type
+ */
+struct bfi_port_generic_rsp {
+       struct bfi_mhdr mh;             /*!< common msg header              */
+       u8              status;         /*!< port enable status             */
+       u8              rsvd[3];
+       u32     msgtag;         /*!< msgtag for reply               */
+};
+
+/**
+ * @todo
+ * BFI_PORT_H2I_ENABLE_REQ
+ */
+
+/**
+ * @todo
+ * BFI_PORT_I2H_ENABLE_RSP
+ */
+
+/**
+ * BFI_PORT_H2I_DISABLE_REQ
+ */
+
+/**
+ * BFI_PORT_I2H_DISABLE_RSP
+ */
+
+/**
+ * BFI_PORT_H2I_GET_STATS_REQ
+ */
+struct bfi_port_get_stats_req {
+       struct bfi_mhdr mh;             /*!< common msg header              */
+       union bfi_addr_u   dma_addr;
+};
+
+/**
+ * BFI_PORT_I2H_GET_STATS_RSP
+ */
+
+/**
+ * BFI_PORT_H2I_CLEAR_STATS_REQ
+ */
+
+/**
+ * BFI_PORT_I2H_CLEAR_STATS_RSP
+ */
+
+union bfi_port_h2i_msg_u {
+       struct bfi_mhdr mh;
+       struct bfi_port_generic_req enable_req;
+       struct bfi_port_generic_req disable_req;
+       struct bfi_port_get_stats_req getstats_req;
+       struct bfi_port_generic_req clearstats_req;
+};
+
+union bfi_port_i2h_msg_u {
+       struct bfi_mhdr mh;
+       struct bfi_port_generic_rsp enable_rsp;
+       struct bfi_port_generic_rsp disable_rsp;
+       struct bfi_port_generic_rsp getstats_rsp;
+       struct bfi_port_generic_rsp clearstats_rsp;
+};
+
+/* @brief Mailbox commands from host to (DCBX/LLDP) firmware */
+enum bfi_cee_h2i_msgs {
+       BFI_CEE_H2I_GET_CFG_REQ = 1,
+       BFI_CEE_H2I_RESET_STATS = 2,
+       BFI_CEE_H2I_GET_STATS_REQ = 3,
+};
+
+/* @brief Mailbox reply and AEN messages from DCBX/LLDP firmware to host */
+enum bfi_cee_i2h_msgs {
+       BFI_CEE_I2H_GET_CFG_RSP = BFA_I2HM(1),
+       BFI_CEE_I2H_RESET_STATS_RSP = BFA_I2HM(2),
+       BFI_CEE_I2H_GET_STATS_RSP = BFA_I2HM(3),
+};
+
+/* Data structures */
+
+/*
+ * @brief H2I command structure for resetting the stats.
+ * BFI_CEE_H2I_RESET_STATS
+ */
+struct bfi_lldp_reset_stats {
+       struct bfi_mhdr mh;
+};
+
+/*
+ * @brief H2I command structure for resetting the stats.
+ * BFI_CEE_H2I_RESET_STATS
+ */
+struct bfi_cee_reset_stats {
+       struct bfi_mhdr mh;
+};
+
+/*
+ * @brief  get configuration  command from host
+ * BFI_CEE_H2I_GET_CFG_REQ
+ */
+struct bfi_cee_get_req {
+       struct bfi_mhdr mh;
+       union bfi_addr_u   dma_addr;
+};
+
+/*
+ * @brief reply message from firmware
+ * BFI_CEE_I2H_GET_CFG_RSP
+ */
+struct bfi_cee_get_rsp {
+       struct bfi_mhdr mh;
+       u8                      cmd_status;
+       u8                      rsvd[3];
+};
+
+/*
+ * @brief  get configuration  command from host
+ * BFI_CEE_H2I_GET_STATS_REQ
+ */
+struct bfi_cee_stats_req {
+       struct bfi_mhdr mh;
+       union bfi_addr_u   dma_addr;
+};
+
+/*
+ * @brief reply message from firmware
+ * BFI_CEE_I2H_GET_STATS_RSP
+ */
+struct bfi_cee_stats_rsp {
+       struct bfi_mhdr mh;
+       u8                      cmd_status;
+       u8                      rsvd[3];
+};
+
+/* @brief mailbox command structures from host to firmware */
+union bfi_cee_h2i_msg_u {
+       struct bfi_mhdr mh;
+       struct bfi_cee_get_req get_req;
+       struct bfi_cee_stats_req stats_req;
+};
+
+/* @brief mailbox message structures from firmware to host     */
+union bfi_cee_i2h_msg_u {
+       struct bfi_mhdr mh;
+       struct bfi_cee_get_rsp get_rsp;
+       struct bfi_cee_stats_rsp stats_rsp;
+};
+
+#pragma pack()
+
+#endif /* __BFI_CNA_H__ */
diff --git a/drivers/net/bna/bfi_ctreg.h b/drivers/net/bna/bfi_ctreg.h
new file mode 100644 (file)
index 0000000..404ea35
--- /dev/null
@@ -0,0 +1,637 @@
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * 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.
+ */
+/*
+ * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+
+/*
+ * bfi_ctreg.h catapult host block register definitions
+ *
+ * !!! Do not edit. Auto generated. !!!
+ */
+
+#ifndef __BFI_CTREG_H__
+#define __BFI_CTREG_H__
+
+#define HOSTFN0_LPU_MBOX0_0            0x00019200
+#define HOSTFN1_LPU_MBOX0_8            0x00019260
+#define LPU_HOSTFN0_MBOX0_0            0x00019280
+#define LPU_HOSTFN1_MBOX0_8            0x000192e0
+#define HOSTFN2_LPU_MBOX0_0            0x00019400
+#define HOSTFN3_LPU_MBOX0_8            0x00019460
+#define LPU_HOSTFN2_MBOX0_0            0x00019480
+#define LPU_HOSTFN3_MBOX0_8            0x000194e0
+#define HOSTFN0_INT_STATUS             0x00014000
+#define __HOSTFN0_HALT_OCCURRED                0x01000000
+#define __HOSTFN0_INT_STATUS_LVL_MK    0x00f00000
+#define __HOSTFN0_INT_STATUS_LVL_SH    20
+#define __HOSTFN0_INT_STATUS_LVL(_v)   ((_v) << __HOSTFN0_INT_STATUS_LVL_SH)
+#define __HOSTFN0_INT_STATUS_P_MK      0x000f0000
+#define __HOSTFN0_INT_STATUS_P_SH      16
+#define __HOSTFN0_INT_STATUS_P(_v)     ((_v) << __HOSTFN0_INT_STATUS_P_SH)
+#define __HOSTFN0_INT_STATUS_F         0x0000ffff
+#define HOSTFN0_INT_MSK                        0x00014004
+#define HOST_PAGE_NUM_FN0              0x00014008
+#define __HOST_PAGE_NUM_FN             0x000001ff
+#define HOST_MSIX_ERR_INDEX_FN0                0x0001400c
+#define __MSIX_ERR_INDEX_FN            0x000001ff
+#define HOSTFN1_INT_STATUS             0x00014100
+#define __HOSTFN1_HALT_OCCURRED                0x01000000
+#define __HOSTFN1_INT_STATUS_LVL_MK    0x00f00000
+#define __HOSTFN1_INT_STATUS_LVL_SH    20
+#define __HOSTFN1_INT_STATUS_LVL(_v)   ((_v) << __HOSTFN1_INT_STATUS_LVL_SH)
+#define __HOSTFN1_INT_STATUS_P_MK      0x000f0000
+#define __HOSTFN1_INT_STATUS_P_SH      16
+#define __HOSTFN1_INT_STATUS_P(_v)     ((_v) << __HOSTFN1_INT_STATUS_P_SH)
+#define __HOSTFN1_INT_STATUS_F         0x0000ffff
+#define HOSTFN1_INT_MSK                        0x00014104
+#define HOST_PAGE_NUM_FN1              0x00014108
+#define HOST_MSIX_ERR_INDEX_FN1                0x0001410c
+#define APP_PLL_425_CTL_REG            0x00014204
+#define __P_425_PLL_LOCK               0x80000000
+#define __APP_PLL_425_SRAM_USE_100MHZ  0x00100000
+#define __APP_PLL_425_RESET_TIMER_MK   0x000e0000
+#define __APP_PLL_425_RESET_TIMER_SH   17
+#define __APP_PLL_425_RESET_TIMER(_v)  ((_v) << __APP_PLL_425_RESET_TIMER_SH)
+#define __APP_PLL_425_LOGIC_SOFT_RESET 0x00010000
+#define __APP_PLL_425_CNTLMT0_1_MK     0x0000c000
+#define __APP_PLL_425_CNTLMT0_1_SH     14
+#define __APP_PLL_425_CNTLMT0_1(_v)    ((_v) << __APP_PLL_425_CNTLMT0_1_SH)
+#define __APP_PLL_425_JITLMT0_1_MK     0x00003000
+#define __APP_PLL_425_JITLMT0_1_SH     12
+#define __APP_PLL_425_JITLMT0_1(_v)    ((_v) << __APP_PLL_425_JITLMT0_1_SH)
+#define __APP_PLL_425_HREF             0x00000800
+#define __APP_PLL_425_HDIV             0x00000400
+#define __APP_PLL_425_P0_1_MK          0x00000300
+#define __APP_PLL_425_P0_1_SH          8
+#define __APP_PLL_425_P0_1(_v)         ((_v) << __APP_PLL_425_P0_1_SH)
+#define __APP_PLL_425_Z0_2_MK          0x000000e0
+#define __APP_PLL_425_Z0_2_SH          5
+#define __APP_PLL_425_Z0_2(_v)         ((_v) << __APP_PLL_425_Z0_2_SH)
+#define __APP_PLL_425_RSEL200500       0x00000010
+#define __APP_PLL_425_ENARST           0x00000008
+#define __APP_PLL_425_BYPASS           0x00000004
+#define __APP_PLL_425_LRESETN          0x00000002
+#define __APP_PLL_425_ENABLE           0x00000001
+#define APP_PLL_312_CTL_REG            0x00014208
+#define __P_312_PLL_LOCK               0x80000000
+#define __ENABLE_MAC_AHB_1             0x00800000
+#define __ENABLE_MAC_AHB_0             0x00400000
+#define __ENABLE_MAC_1                 0x00200000
+#define __ENABLE_MAC_0                 0x00100000
+#define __APP_PLL_312_RESET_TIMER_MK   0x000e0000
+#define __APP_PLL_312_RESET_TIMER_SH   17
+#define __APP_PLL_312_RESET_TIMER(_v)  ((_v) << __APP_PLL_312_RESET_TIMER_SH)
+#define __APP_PLL_312_LOGIC_SOFT_RESET 0x00010000
+#define __APP_PLL_312_CNTLMT0_1_MK     0x0000c000
+#define __APP_PLL_312_CNTLMT0_1_SH     14
+#define __APP_PLL_312_CNTLMT0_1(_v)    ((_v) << __APP_PLL_312_CNTLMT0_1_SH)
+#define __APP_PLL_312_JITLMT0_1_MK     0x00003000
+#define __APP_PLL_312_JITLMT0_1_SH     12
+#define __APP_PLL_312_JITLMT0_1(_v)    ((_v) << __APP_PLL_312_JITLMT0_1_SH)
+#define __APP_PLL_312_HREF             0x00000800
+#define __APP_PLL_312_HDIV             0x00000400
+#define __APP_PLL_312_P0_1_MK          0x00000300
+#define __APP_PLL_312_P0_1_SH          8
+#define __APP_PLL_312_P0_1(_v)         ((_v) << __APP_PLL_312_P0_1_SH)
+#define __APP_PLL_312_Z0_2_MK          0x000000e0
+#define __APP_PLL_312_Z0_2_SH          5
+#define __APP_PLL_312_Z0_2(_v)         ((_v) << __APP_PLL_312_Z0_2_SH)
+#define __APP_PLL_312_RSEL200500       0x00000010
+#define __APP_PLL_312_ENARST           0x00000008
+#define __APP_PLL_312_BYPASS           0x00000004
+#define __APP_PLL_312_LRESETN          0x00000002
+#define __APP_PLL_312_ENABLE           0x00000001
+#define MBIST_CTL_REG                  0x00014220
+#define __EDRAM_BISTR_START            0x00000004
+#define __MBIST_RESET                  0x00000002
+#define __MBIST_START                  0x00000001
+#define MBIST_STAT_REG                 0x00014224
+#define __EDRAM_BISTR_STATUS           0x00000008
+#define __EDRAM_BISTR_DONE             0x00000004
+#define __MEM_BIT_STATUS               0x00000002
+#define __MBIST_DONE                   0x00000001
+#define HOST_SEM0_REG                  0x00014230
+#define __HOST_SEMAPHORE               0x00000001
+#define HOST_SEM1_REG                  0x00014234
+#define HOST_SEM2_REG                  0x00014238
+#define HOST_SEM3_REG                  0x0001423c
+#define HOST_SEM0_INFO_REG             0x00014240
+#define HOST_SEM1_INFO_REG             0x00014244
+#define HOST_SEM2_INFO_REG             0x00014248
+#define HOST_SEM3_INFO_REG             0x0001424c
+#define ETH_MAC_SER_REG                        0x00014288
+#define __APP_EMS_CKBUFAMPIN           0x00000020
+#define __APP_EMS_REFCLKSEL            0x00000010
+#define __APP_EMS_CMLCKSEL             0x00000008
+#define __APP_EMS_REFCKBUFEN2          0x00000004
+#define __APP_EMS_REFCKBUFEN1          0x00000002
+#define __APP_EMS_CHANNEL_SEL          0x00000001
+#define HOSTFN2_INT_STATUS             0x00014300
+#define __HOSTFN2_HALT_OCCURRED                0x01000000
+#define __HOSTFN2_INT_STATUS_LVL_MK    0x00f00000
+#define __HOSTFN2_INT_STATUS_LVL_SH    20
+#define __HOSTFN2_INT_STATUS_LVL(_v)   ((_v) << __HOSTFN2_INT_STATUS_LVL_SH)
+#define __HOSTFN2_INT_STATUS_P_MK      0x000f0000
+#define __HOSTFN2_INT_STATUS_P_SH      16
+#define __HOSTFN2_INT_STATUS_P(_v)     ((_v) << __HOSTFN2_INT_STATUS_P_SH)
+#define __HOSTFN2_INT_STATUS_F         0x0000ffff
+#define HOSTFN2_INT_MSK                        0x00014304
+#define HOST_PAGE_NUM_FN2              0x00014308
+#define HOST_MSIX_ERR_INDEX_FN2                0x0001430c
+#define HOSTFN3_INT_STATUS             0x00014400
+#define __HALT_OCCURRED                        0x01000000
+#define __HOSTFN3_INT_STATUS_LVL_MK    0x00f00000
+#define __HOSTFN3_INT_STATUS_LVL_SH    20
+#define __HOSTFN3_INT_STATUS_LVL(_v)   ((_v) << __HOSTFN3_INT_STATUS_LVL_SH)
+#define __HOSTFN3_INT_STATUS_P_MK      0x000f0000
+#define __HOSTFN3_INT_STATUS_P_SH      16
+#define __HOSTFN3_INT_STATUS_P(_v)     ((_v) << __HOSTFN3_INT_STATUS_P_SH)
+#define __HOSTFN3_INT_STATUS_F         0x0000ffff
+#define HOSTFN3_INT_MSK                        0x00014404
+#define HOST_PAGE_NUM_FN3              0x00014408
+#define HOST_MSIX_ERR_INDEX_FN3                0x0001440c
+#define FNC_ID_REG                     0x00014600
+#define __FUNCTION_NUMBER              0x00000007
+#define FNC_PERS_REG                   0x00014604
+#define __F3_FUNCTION_ACTIVE           0x80000000
+#define __F3_FUNCTION_MODE             0x40000000
+#define __F3_PORT_MAP_MK               0x30000000
+#define __F3_PORT_MAP_SH               28
+#define __F3_PORT_MAP(_v)              ((_v) << __F3_PORT_MAP_SH)
+#define __F3_VM_MODE                   0x08000000
+#define __F3_INTX_STATUS_MK            0x07000000
+#define __F3_INTX_STATUS_SH            24
+#define __F3_INTX_STATUS(_v)           ((_v) << __F3_INTX_STATUS_SH)
+#define __F2_FUNCTION_ACTIVE           0x00800000
+#define __F2_FUNCTION_MODE             0x00400000
+#define __F2_PORT_MAP_MK               0x00300000
+#define __F2_PORT_MAP_SH               20
+#define __F2_PORT_MAP(_v)              ((_v) << __F2_PORT_MAP_SH)
+#define __F2_VM_MODE                   0x00080000
+#define __F2_INTX_STATUS_MK            0x00070000
+#define __F2_INTX_STATUS_SH            16
+#define __F2_INTX_STATUS(_v)           ((_v) << __F2_INTX_STATUS_SH)
+#define __F1_FUNCTION_ACTIVE           0x00008000
+#define __F1_FUNCTION_MODE             0x00004000
+#define __F1_PORT_MAP_MK               0x00003000
+#define __F1_PORT_MAP_SH               12
+#define __F1_PORT_MAP(_v)              ((_v) << __F1_PORT_MAP_SH)
+#define __F1_VM_MODE                   0x00000800
+#define __F1_INTX_STATUS_MK            0x00000700
+#define __F1_INTX_STATUS_SH            8
+#define __F1_INTX_STATUS(_v)           ((_v) << __F1_INTX_STATUS_SH)
+#define __F0_FUNCTION_ACTIVE           0x00000080
+#define __F0_FUNCTION_MODE             0x00000040
+#define __F0_PORT_MAP_MK               0x00000030
+#define __F0_PORT_MAP_SH               4
+#define __F0_PORT_MAP(_v)              ((_v) << __F0_PORT_MAP_SH)
+#define __F0_VM_MODE           0x00000008
+#define __F0_INTX_STATUS               0x00000007
+enum {
+       __F0_INTX_STATUS_MSIX           = 0x0,
+       __F0_INTX_STATUS_INTA           = 0x1,
+       __F0_INTX_STATUS_INTB           = 0x2,
+       __F0_INTX_STATUS_INTC           = 0x3,
+       __F0_INTX_STATUS_INTD           = 0x4,
+};
+#define OP_MODE                                0x0001460c
+#define __APP_ETH_CLK_LOWSPEED         0x00000004
+#define __GLOBAL_CORECLK_HALFSPEED     0x00000002
+#define __GLOBAL_FCOE_MODE             0x00000001
+#define HOST_SEM4_REG                  0x00014610
+#define HOST_SEM5_REG                  0x00014614
+#define HOST_SEM6_REG                  0x00014618
+#define HOST_SEM7_REG                  0x0001461c
+#define HOST_SEM4_INFO_REG             0x00014620
+#define HOST_SEM5_INFO_REG             0x00014624
+#define HOST_SEM6_INFO_REG             0x00014628
+#define HOST_SEM7_INFO_REG             0x0001462c
+#define HOSTFN0_LPU0_MBOX0_CMD_STAT    0x00019000
+#define __HOSTFN0_LPU0_MBOX0_INFO_MK   0xfffffffe
+#define __HOSTFN0_LPU0_MBOX0_INFO_SH   1
+#define __HOSTFN0_LPU0_MBOX0_INFO(_v)  ((_v) << __HOSTFN0_LPU0_MBOX0_INFO_SH)
+#define __HOSTFN0_LPU0_MBOX0_CMD_STATUS 0x00000001
+#define HOSTFN0_LPU1_MBOX0_CMD_STAT    0x00019004
+#define __HOSTFN0_LPU1_MBOX0_INFO_MK   0xfffffffe
+#define __HOSTFN0_LPU1_MBOX0_INFO_SH   1
+#define __HOSTFN0_LPU1_MBOX0_INFO(_v)  ((_v) << __HOSTFN0_LPU1_MBOX0_INFO_SH)
+#define __HOSTFN0_LPU1_MBOX0_CMD_STATUS 0x00000001
+#define LPU0_HOSTFN0_MBOX0_CMD_STAT    0x00019008
+#define __LPU0_HOSTFN0_MBOX0_INFO_MK   0xfffffffe
+#define __LPU0_HOSTFN0_MBOX0_INFO_SH   1
+#define __LPU0_HOSTFN0_MBOX0_INFO(_v)  ((_v) << __LPU0_HOSTFN0_MBOX0_INFO_SH)
+#define __LPU0_HOSTFN0_MBOX0_CMD_STATUS 0x00000001
+#define LPU1_HOSTFN0_MBOX0_CMD_STAT    0x0001900c
+#define __LPU1_HOSTFN0_MBOX0_INFO_MK   0xfffffffe
+#define __LPU1_HOSTFN0_MBOX0_INFO_SH   1
+#define __LPU1_HOSTFN0_MBOX0_INFO(_v)  ((_v) << __LPU1_HOSTFN0_MBOX0_INFO_SH)
+#define __LPU1_HOSTFN0_MBOX0_CMD_STATUS 0x00000001
+#define HOSTFN1_LPU0_MBOX0_CMD_STAT    0x00019010
+#define __HOSTFN1_LPU0_MBOX0_INFO_MK   0xfffffffe
+#define __HOSTFN1_LPU0_MBOX0_INFO_SH   1
+#define __HOSTFN1_LPU0_MBOX0_INFO(_v)  ((_v) << __HOSTFN1_LPU0_MBOX0_INFO_SH)
+#define __HOSTFN1_LPU0_MBOX0_CMD_STATUS 0x00000001
+#define HOSTFN1_LPU1_MBOX0_CMD_STAT    0x00019014
+#define __HOSTFN1_LPU1_MBOX0_INFO_MK   0xfffffffe
+#define __HOSTFN1_LPU1_MBOX0_INFO_SH   1
+#define __HOSTFN1_LPU1_MBOX0_INFO(_v)  ((_v) << __HOSTFN1_LPU1_MBOX0_INFO_SH)
+#define __HOSTFN1_LPU1_MBOX0_CMD_STATUS 0x00000001
+#define LPU0_HOSTFN1_MBOX0_CMD_STAT    0x00019018
+#define __LPU0_HOSTFN1_MBOX0_INFO_MK   0xfffffffe
+#define __LPU0_HOSTFN1_MBOX0_INFO_SH   1
+#define __LPU0_HOSTFN1_MBOX0_INFO(_v)  ((_v) << __LPU0_HOSTFN1_MBOX0_INFO_SH)
+#define __LPU0_HOSTFN1_MBOX0_CMD_STATUS 0x00000001
+#define LPU1_HOSTFN1_MBOX0_CMD_STAT    0x0001901c
+#define __LPU1_HOSTFN1_MBOX0_INFO_MK   0xfffffffe
+#define __LPU1_HOSTFN1_MBOX0_INFO_SH   1
+#define __LPU1_HOSTFN1_MBOX0_INFO(_v)  ((_v) << __LPU1_HOSTFN1_MBOX0_INFO_SH)
+#define __LPU1_HOSTFN1_MBOX0_CMD_STATUS 0x00000001
+#define HOSTFN2_LPU0_MBOX0_CMD_STAT    0x00019150
+#define __HOSTFN2_LPU0_MBOX0_INFO_MK   0xfffffffe
+#define __HOSTFN2_LPU0_MBOX0_INFO_SH   1
+#define __HOSTFN2_LPU0_MBOX0_INFO(_v)  ((_v) << __HOSTFN2_LPU0_MBOX0_INFO_SH)
+#define __HOSTFN2_LPU0_MBOX0_CMD_STATUS 0x00000001
+#define HOSTFN2_LPU1_MBOX0_CMD_STAT    0x00019154
+#define __HOSTFN2_LPU1_MBOX0_INFO_MK   0xfffffffe
+#define __HOSTFN2_LPU1_MBOX0_INFO_SH   1
+#define __HOSTFN2_LPU1_MBOX0_INFO(_v)  ((_v) << __HOSTFN2_LPU1_MBOX0_INFO_SH)
+#define __HOSTFN2_LPU1_MBOX0BOX0_CMD_STATUS 0x00000001
+#define LPU0_HOSTFN2_MBOX0_CMD_STAT    0x00019158
+#define __LPU0_HOSTFN2_MBOX0_INFO_MK   0xfffffffe
+#define __LPU0_HOSTFN2_MBOX0_INFO_SH   1
+#define __LPU0_HOSTFN2_MBOX0_INFO(_v)  ((_v) << __LPU0_HOSTFN2_MBOX0_INFO_SH)
+#define __LPU0_HOSTFN2_MBOX0_CMD_STATUS 0x00000001
+#define LPU1_HOSTFN2_MBOX0_CMD_STAT    0x0001915c
+#define __LPU1_HOSTFN2_MBOX0_INFO_MK   0xfffffffe
+#define __LPU1_HOSTFN2_MBOX0_INFO_SH   1
+#define __LPU1_HOSTFN2_MBOX0_INFO(_v)  ((_v) << __LPU1_HOSTFN2_MBOX0_INFO_SH)
+#define __LPU1_HOSTFN2_MBOX0_CMD_STATUS 0x00000001
+#define HOSTFN3_LPU0_MBOX0_CMD_STAT    0x00019160
+#define __HOSTFN3_LPU0_MBOX0_INFO_MK   0xfffffffe
+#define __HOSTFN3_LPU0_MBOX0_INFO_SH   1
+#define __HOSTFN3_LPU0_MBOX0_INFO(_v)  ((_v) << __HOSTFN3_LPU0_MBOX0_INFO_SH)
+#define __HOSTFN3_LPU0_MBOX0_CMD_STATUS 0x00000001
+#define HOSTFN3_LPU1_MBOX0_CMD_STAT    0x00019164
+#define __HOSTFN3_LPU1_MBOX0_INFO_MK   0xfffffffe
+#define __HOSTFN3_LPU1_MBOX0_INFO_SH   1
+#define __HOSTFN3_LPU1_MBOX0_INFO(_v)  ((_v) << __HOSTFN3_LPU1_MBOX0_INFO_SH)
+#define __HOSTFN3_LPU1_MBOX0_CMD_STATUS 0x00000001
+#define LPU0_HOSTFN3_MBOX0_CMD_STAT    0x00019168
+#define __LPU0_HOSTFN3_MBOX0_INFO_MK   0xfffffffe
+#define __LPU0_HOSTFN3_MBOX0_INFO_SH   1
+#define __LPU0_HOSTFN3_MBOX0_INFO(_v)  ((_v) << __LPU0_HOSTFN3_MBOX0_INFO_SH)
+#define __LPU0_HOSTFN3_MBOX0_CMD_STATUS 0x00000001
+#define LPU1_HOSTFN3_MBOX0_CMD_STAT    0x0001916c
+#define __LPU1_HOSTFN3_MBOX0_INFO_MK   0xfffffffe
+#define __LPU1_HOSTFN3_MBOX0_INFO_SH   1
+#define __LPU1_HOSTFN3_MBOX0_INFO(_v)  ((_v) << __LPU1_HOSTFN3_MBOX0_INFO_SH)
+#define __LPU1_HOSTFN3_MBOX0_CMD_STATUS        0x00000001
+#define FW_INIT_HALT_P0                        0x000191ac
+#define __FW_INIT_HALT_P               0x00000001
+#define FW_INIT_HALT_P1                        0x000191bc
+#define CPE_PI_PTR_Q0                  0x00038000
+#define __CPE_PI_UNUSED_MK             0xffff0000
+#define __CPE_PI_UNUSED_SH             16
+#define __CPE_PI_UNUSED(_v)            ((_v) << __CPE_PI_UNUSED_SH)
+#define __CPE_PI_PTR                   0x0000ffff
+#define CPE_PI_PTR_Q1                  0x00038040
+#define CPE_CI_PTR_Q0                  0x00038004
+#define __CPE_CI_UNUSED_MK             0xffff0000
+#define __CPE_CI_UNUSED_SH             16
+#define __CPE_CI_UNUSED(_v)            ((_v) << __CPE_CI_UNUSED_SH)
+#define __CPE_CI_PTR                   0x0000ffff
+#define CPE_CI_PTR_Q1                  0x00038044
+#define CPE_DEPTH_Q0                   0x00038008
+#define __CPE_DEPTH_UNUSED_MK          0xf8000000
+#define __CPE_DEPTH_UNUSED_SH          27
+#define __CPE_DEPTH_UNUSED(_v)         ((_v) << __CPE_DEPTH_UNUSED_SH)
+#define __CPE_MSIX_VEC_INDEX_MK                0x07ff0000
+#define __CPE_MSIX_VEC_INDEX_SH                16
+#define __CPE_MSIX_VEC_INDEX(_v)       ((_v) << __CPE_MSIX_VEC_INDEX_SH)
+#define __CPE_DEPTH                    0x0000ffff
+#define CPE_DEPTH_Q1                   0x00038048
+#define CPE_QCTRL_Q0                   0x0003800c
+#define __CPE_CTRL_UNUSED30_MK         0xfc000000
+#define __CPE_CTRL_UNUSED30_SH         26
+#define __CPE_CTRL_UNUSED30(_v)                ((_v) << __CPE_CTRL_UNUSED30_SH)
+#define __CPE_FUNC_INT_CTRL_MK         0x03000000
+#define __CPE_FUNC_INT_CTRL_SH         24
+#define __CPE_FUNC_INT_CTRL(_v)                ((_v) << __CPE_FUNC_INT_CTRL_SH)
+enum {
+       __CPE_FUNC_INT_CTRL_DISABLE             = 0x0,
+       __CPE_FUNC_INT_CTRL_F2NF                = 0x1,
+       __CPE_FUNC_INT_CTRL_3QUART              = 0x2,
+       __CPE_FUNC_INT_CTRL_HALF                = 0x3,
+};
+#define __CPE_CTRL_UNUSED20_MK         0x00f00000
+#define __CPE_CTRL_UNUSED20_SH         20
+#define __CPE_CTRL_UNUSED20(_v)                ((_v) << __CPE_CTRL_UNUSED20_SH)
+#define __CPE_SCI_TH_MK                        0x000f0000
+#define __CPE_SCI_TH_SH                        16
+#define __CPE_SCI_TH(_v)               ((_v) << __CPE_SCI_TH_SH)
+#define __CPE_CTRL_UNUSED10_MK         0x0000c000
+#define __CPE_CTRL_UNUSED10_SH         14
+#define __CPE_CTRL_UNUSED10(_v)                ((_v) << __CPE_CTRL_UNUSED10_SH)
+#define __CPE_ACK_PENDING              0x00002000
+#define __CPE_CTRL_UNUSED40_MK         0x00001c00
+#define __CPE_CTRL_UNUSED40_SH         10
+#define __CPE_CTRL_UNUSED40(_v)                ((_v) << __CPE_CTRL_UNUSED40_SH)
+#define __CPE_PCIEID_MK                        0x00000300
+#define __CPE_PCIEID_SH                        8
+#define __CPE_PCIEID(_v)               ((_v) << __CPE_PCIEID_SH)
+#define __CPE_CTRL_UNUSED00_MK         0x000000fe
+#define __CPE_CTRL_UNUSED00_SH         1
+#define __CPE_CTRL_UNUSED00(_v)                ((_v) << __CPE_CTRL_UNUSED00_SH)
+#define __CPE_ESIZE                    0x00000001
+#define CPE_QCTRL_Q1                   0x0003804c
+#define __CPE_CTRL_UNUSED31_MK         0xfc000000
+#define __CPE_CTRL_UNUSED31_SH         26
+#define __CPE_CTRL_UNUSED31(_v)                ((_v) << __CPE_CTRL_UNUSED31_SH)
+#define __CPE_CTRL_UNUSED21_MK         0x00f00000
+#define __CPE_CTRL_UNUSED21_SH         20
+#define __CPE_CTRL_UNUSED21(_v)                ((_v) << __CPE_CTRL_UNUSED21_SH)
+#define __CPE_CTRL_UNUSED11_MK         0x0000c000
+#define __CPE_CTRL_UNUSED11_SH         14
+#define __CPE_CTRL_UNUSED11(_v)                ((_v) << __CPE_CTRL_UNUSED11_SH)
+#define __CPE_CTRL_UNUSED41_MK         0x00001c00
+#define __CPE_CTRL_UNUSED41_SH         10
+#define __CPE_CTRL_UNUSED41(_v)                ((_v) << __CPE_CTRL_UNUSED41_SH)
+#define __CPE_CTRL_UNUSED01_MK         0x000000fe
+#define __CPE_CTRL_UNUSED01_SH         1
+#define __CPE_CTRL_UNUSED01(_v)                ((_v) << __CPE_CTRL_UNUSED01_SH)
+#define RME_PI_PTR_Q0                  0x00038020
+#define __LATENCY_TIME_STAMP_MK                0xffff0000
+#define __LATENCY_TIME_STAMP_SH                16
+#define __LATENCY_TIME_STAMP(_v)       ((_v) << __LATENCY_TIME_STAMP_SH)
+#define __RME_PI_PTR                   0x0000ffff
+#define RME_PI_PTR_Q1                  0x00038060
+#define RME_CI_PTR_Q0                  0x00038024
+#define __DELAY_TIME_STAMP_MK          0xffff0000
+#define __DELAY_TIME_STAMP_SH          16
+#define __DELAY_TIME_STAMP(_v)         ((_v) << __DELAY_TIME_STAMP_SH)
+#define __RME_CI_PTR                   0x0000ffff
+#define RME_CI_PTR_Q1                  0x00038064
+#define RME_DEPTH_Q0                   0x00038028
+#define __RME_DEPTH_UNUSED_MK          0xf8000000
+#define __RME_DEPTH_UNUSED_SH          27
+#define __RME_DEPTH_UNUSED(_v)         ((_v) << __RME_DEPTH_UNUSED_SH)
+#define __RME_MSIX_VEC_INDEX_MK                0x07ff0000
+#define __RME_MSIX_VEC_INDEX_SH                16
+#define __RME_MSIX_VEC_INDEX(_v)       ((_v) << __RME_MSIX_VEC_INDEX_SH)
+#define __RME_DEPTH                    0x0000ffff
+#define RME_DEPTH_Q1                   0x00038068
+#define RME_QCTRL_Q0                   0x0003802c
+#define __RME_INT_LATENCY_TIMER_MK     0xff000000
+#define __RME_INT_LATENCY_TIMER_SH     24
+#define __RME_INT_LATENCY_TIMER(_v)    ((_v) << __RME_INT_LATENCY_TIMER_SH)
+#define __RME_INT_DELAY_TIMER_MK       0x00ff0000
+#define __RME_INT_DELAY_TIMER_SH       16
+#define __RME_INT_DELAY_TIMER(_v)      ((_v) << __RME_INT_DELAY_TIMER_SH)
+#define __RME_INT_DELAY_DISABLE                0x00008000
+#define __RME_DLY_DELAY_DISABLE                0x00004000
+#define __RME_ACK_PENDING              0x00002000
+#define __RME_FULL_INTERRUPT_DISABLE   0x00001000
+#define __RME_CTRL_UNUSED10_MK         0x00000c00
+#define __RME_CTRL_UNUSED10_SH         10
+#define __RME_CTRL_UNUSED10(_v)                ((_v) << __RME_CTRL_UNUSED10_SH)
+#define __RME_PCIEID_MK                        0x00000300
+#define __RME_PCIEID_SH                        8
+#define __RME_PCIEID(_v)               ((_v) << __RME_PCIEID_SH)
+#define __RME_CTRL_UNUSED00_MK         0x000000fe
+#define __RME_CTRL_UNUSED00_SH         1
+#define __RME_CTRL_UNUSED00(_v)                ((_v) << __RME_CTRL_UNUSED00_SH)
+#define __RME_ESIZE                    0x00000001
+#define RME_QCTRL_Q1                   0x0003806c
+#define __RME_CTRL_UNUSED11_MK         0x00000c00
+#define __RME_CTRL_UNUSED11_SH         10
+#define __RME_CTRL_UNUSED11(_v)                ((_v) << __RME_CTRL_UNUSED11_SH)
+#define __RME_CTRL_UNUSED01_MK         0x000000fe
+#define __RME_CTRL_UNUSED01_SH         1
+#define __RME_CTRL_UNUSED01(_v)                ((_v) << __RME_CTRL_UNUSED01_SH)
+#define PSS_CTL_REG                    0x00018800
+#define __PSS_I2C_CLK_DIV_MK           0x007f0000
+#define __PSS_I2C_CLK_DIV_SH           16
+#define __PSS_I2C_CLK_DIV(_v)          ((_v) << __PSS_I2C_CLK_DIV_SH)
+#define __PSS_LMEM_INIT_DONE           0x00001000
+#define __PSS_LMEM_RESET               0x00000200
+#define __PSS_LMEM_INIT_EN             0x00000100
+#define __PSS_LPU1_RESET               0x00000002
+#define __PSS_LPU0_RESET               0x00000001
+#define PSS_ERR_STATUS_REG             0x00018810
+#define __PSS_LPU1_TCM_READ_ERR                0x00200000
+#define __PSS_LPU0_TCM_READ_ERR                0x00100000
+#define __PSS_LMEM5_CORR_ERR           0x00080000
+#define __PSS_LMEM4_CORR_ERR           0x00040000
+#define __PSS_LMEM3_CORR_ERR           0x00020000
+#define __PSS_LMEM2_CORR_ERR           0x00010000
+#define __PSS_LMEM1_CORR_ERR           0x00008000
+#define __PSS_LMEM0_CORR_ERR           0x00004000
+#define __PSS_LMEM5_UNCORR_ERR         0x00002000
+#define __PSS_LMEM4_UNCORR_ERR         0x00001000
+#define __PSS_LMEM3_UNCORR_ERR         0x00000800
+#define __PSS_LMEM2_UNCORR_ERR         0x00000400
+#define __PSS_LMEM1_UNCORR_ERR         0x00000200
+#define __PSS_LMEM0_UNCORR_ERR         0x00000100
+#define __PSS_BAL_PERR                 0x00000080
+#define __PSS_DIP_IF_ERR               0x00000040
+#define __PSS_IOH_IF_ERR               0x00000020
+#define __PSS_TDS_IF_ERR               0x00000010
+#define __PSS_RDS_IF_ERR               0x00000008
+#define __PSS_SGM_IF_ERR               0x00000004
+#define __PSS_LPU1_RAM_ERR             0x00000002
+#define __PSS_LPU0_RAM_ERR             0x00000001
+#define ERR_SET_REG                    0x00018818
+#define __PSS_ERR_STATUS_SET           0x003fffff
+#define PMM_1T_RESET_REG_P0            0x0002381c
+#define __PMM_1T_RESET_P               0x00000001
+#define PMM_1T_RESET_REG_P1            0x00023c1c
+#define HQM_QSET0_RXQ_DRBL_P0          0x00038000
+#define __RXQ0_ADD_VECTORS_P           0x80000000
+#define __RXQ0_STOP_P                  0x40000000
+#define __RXQ0_PRD_PTR_P               0x0000ffff
+#define HQM_QSET1_RXQ_DRBL_P0          0x00038080
+#define __RXQ1_ADD_VECTORS_P           0x80000000
+#define __RXQ1_STOP_P                  0x40000000
+#define __RXQ1_PRD_PTR_P               0x0000ffff
+#define HQM_QSET0_RXQ_DRBL_P1          0x0003c000
+#define HQM_QSET1_RXQ_DRBL_P1          0x0003c080
+#define HQM_QSET0_TXQ_DRBL_P0          0x00038020
+#define __TXQ0_ADD_VECTORS_P           0x80000000
+#define __TXQ0_STOP_P                  0x40000000
+#define __TXQ0_PRD_PTR_P               0x0000ffff
+#define HQM_QSET1_TXQ_DRBL_P0          0x000380a0
+#define __TXQ1_ADD_VECTORS_P           0x80000000
+#define __TXQ1_STOP_P                  0x40000000
+#define __TXQ1_PRD_PTR_P               0x0000ffff
+#define HQM_QSET0_TXQ_DRBL_P1          0x0003c020
+#define HQM_QSET1_TXQ_DRBL_P1          0x0003c0a0
+#define HQM_QSET0_IB_DRBL_1_P0         0x00038040
+#define __IB1_0_ACK_P                  0x80000000
+#define __IB1_0_DISABLE_P              0x40000000
+#define __IB1_0_COALESCING_CFG_P_MK    0x00ff0000
+#define __IB1_0_COALESCING_CFG_P_SH    16
+#define __IB1_0_COALESCING_CFG_P(_v)   ((_v) << __IB1_0_COALESCING_CFG_P_SH)
+#define __IB1_0_NUM_OF_ACKED_EVENTS_P  0x0000ffff
+#define HQM_QSET1_IB_DRBL_1_P0         0x000380c0
+#define __IB1_1_ACK_P                  0x80000000
+#define __IB1_1_DISABLE_P              0x40000000
+#define __IB1_1_COALESCING_CFG_P_MK    0x00ff0000
+#define __IB1_1_COALESCING_CFG_P_SH    16
+#define __IB1_1_COALESCING_CFG_P(_v)   ((_v) << __IB1_1_COALESCING_CFG_P_SH)
+#define __IB1_1_NUM_OF_ACKED_EVENTS_P  0x0000ffff
+#define HQM_QSET0_IB_DRBL_1_P1         0x0003c040
+#define HQM_QSET1_IB_DRBL_1_P1         0x0003c0c0
+#define HQM_QSET0_IB_DRBL_2_P0         0x00038060
+#define __IB2_0_ACK_P                  0x80000000
+#define __IB2_0_DISABLE_P              0x40000000
+#define __IB2_0_COALESCING_CFG_P_MK    0x00ff0000
+#define __IB2_0_COALESCING_CFG_P_SH    16
+#define __IB2_0_COALESCING_CFG_P(_v)   ((_v) << __IB2_0_COALESCING_CFG_P_SH)
+#define __IB2_0_NUM_OF_ACKED_EVENTS_P  0x0000ffff
+#define HQM_QSET1_IB_DRBL_2_P0         0x000380e0
+#define __IB2_1_ACK_P                  0x80000000
+#define __IB2_1_DISABLE_P              0x40000000
+#define __IB2_1_COALESCING_CFG_P_MK    0x00ff0000
+#define __IB2_1_COALESCING_CFG_P_SH    16
+#define __IB2_1_COALESCING_CFG_P(_v)   ((_v) << __IB2_1_COALESCING_CFG_P_SH)
+#define __IB2_1_NUM_OF_ACKED_EVENTS_P  0x0000ffff
+#define HQM_QSET0_IB_DRBL_2_P1         0x0003c060
+#define HQM_QSET1_IB_DRBL_2_P1         0x0003c0e0
+
+/*
+ * These definitions are either in error/missing in spec. Its auto-generated
+ * from hard coded values in regparse.pl.
+ */
+#define __EMPHPOST_AT_4G_MK_FIX                0x0000001c
+#define __EMPHPOST_AT_4G_SH_FIX                0x00000002
+#define __EMPHPRE_AT_4G_FIX            0x00000003
+#define __SFP_TXRATE_EN_FIX            0x00000100
+#define __SFP_RXRATE_EN_FIX            0x00000080
+
+/*
+ * These register definitions are auto-generated from hard coded values
+ * in regparse.pl.
+ */
+
+/*
+ * These register mapping definitions are auto-generated from mapping tables
+ * in regparse.pl.
+ */
+#define BFA_IOC0_HBEAT_REG             HOST_SEM0_INFO_REG
+#define BFA_IOC0_STATE_REG             HOST_SEM1_INFO_REG
+#define BFA_IOC1_HBEAT_REG             HOST_SEM2_INFO_REG
+#define BFA_IOC1_STATE_REG             HOST_SEM3_INFO_REG
+#define BFA_FW_USE_COUNT                HOST_SEM4_INFO_REG
+
+#define CPE_DEPTH_Q(__n) \
+       (CPE_DEPTH_Q0 + (__n) * (CPE_DEPTH_Q1 - CPE_DEPTH_Q0))
+#define CPE_QCTRL_Q(__n) \
+       (CPE_QCTRL_Q0 + (__n) * (CPE_QCTRL_Q1 - CPE_QCTRL_Q0))
+#define CPE_PI_PTR_Q(__n) \
+       (CPE_PI_PTR_Q0 + (__n) * (CPE_PI_PTR_Q1 - CPE_PI_PTR_Q0))
+#define CPE_CI_PTR_Q(__n) \
+       (CPE_CI_PTR_Q0 + (__n) * (CPE_CI_PTR_Q1 - CPE_CI_PTR_Q0))
+#define RME_DEPTH_Q(__n) \
+       (RME_DEPTH_Q0 + (__n) * (RME_DEPTH_Q1 - RME_DEPTH_Q0))
+#define RME_QCTRL_Q(__n) \
+       (RME_QCTRL_Q0 + (__n) * (RME_QCTRL_Q1 - RME_QCTRL_Q0))
+#define RME_PI_PTR_Q(__n) \
+       (RME_PI_PTR_Q0 + (__n) * (RME_PI_PTR_Q1 - RME_PI_PTR_Q0))
+#define RME_CI_PTR_Q(__n) \
+       (RME_CI_PTR_Q0 + (__n) * (RME_CI_PTR_Q1 - RME_CI_PTR_Q0))
+#define HQM_QSET_RXQ_DRBL_P0(__n) (HQM_QSET0_RXQ_DRBL_P0 + (__n) \
+       * (HQM_QSET1_RXQ_DRBL_P0 - HQM_QSET0_RXQ_DRBL_P0))
+#define HQM_QSET_TXQ_DRBL_P0(__n) (HQM_QSET0_TXQ_DRBL_P0 + (__n) \
+       * (HQM_QSET1_TXQ_DRBL_P0 - HQM_QSET0_TXQ_DRBL_P0))
+#define HQM_QSET_IB_DRBL_1_P0(__n) (HQM_QSET0_IB_DRBL_1_P0 + (__n) \
+       * (HQM_QSET1_IB_DRBL_1_P0 - HQM_QSET0_IB_DRBL_1_P0))
+#define HQM_QSET_IB_DRBL_2_P0(__n) (HQM_QSET0_IB_DRBL_2_P0 + (__n) \
+       * (HQM_QSET1_IB_DRBL_2_P0 - HQM_QSET0_IB_DRBL_2_P0))
+#define HQM_QSET_RXQ_DRBL_P1(__n) (HQM_QSET0_RXQ_DRBL_P1 + (__n) \
+       * (HQM_QSET1_RXQ_DRBL_P1 - HQM_QSET0_RXQ_DRBL_P1))
+#define HQM_QSET_TXQ_DRBL_P1(__n) (HQM_QSET0_TXQ_DRBL_P1 + (__n) \
+       * (HQM_QSET1_TXQ_DRBL_P1 - HQM_QSET0_TXQ_DRBL_P1))
+#define HQM_QSET_IB_DRBL_1_P1(__n) (HQM_QSET0_IB_DRBL_1_P1 + (__n) \
+       * (HQM_QSET1_IB_DRBL_1_P1 - HQM_QSET0_IB_DRBL_1_P1))
+#define HQM_QSET_IB_DRBL_2_P1(__n) (HQM_QSET0_IB_DRBL_2_P1 + (__n) \
+       * (HQM_QSET1_IB_DRBL_2_P1 - HQM_QSET0_IB_DRBL_2_P1))
+
+#define CPE_Q_NUM(__fn, __q) (((__fn) << 2) + (__q))
+#define RME_Q_NUM(__fn, __q) (((__fn) << 2) + (__q))
+#define CPE_Q_MASK(__q) ((__q) & 0x3)
+#define RME_Q_MASK(__q) ((__q) & 0x3)
+
+/*
+ * PCI MSI-X vector defines
+ */
+enum {
+       BFA_MSIX_CPE_Q0 = 0,
+       BFA_MSIX_CPE_Q1 = 1,
+       BFA_MSIX_CPE_Q2 = 2,
+       BFA_MSIX_CPE_Q3 = 3,
+       BFA_MSIX_RME_Q0 = 4,
+       BFA_MSIX_RME_Q1 = 5,
+       BFA_MSIX_RME_Q2 = 6,
+       BFA_MSIX_RME_Q3 = 7,
+       BFA_MSIX_LPU_ERR = 8,
+       BFA_MSIX_CT_MAX = 9,
+};
+
+/*
+ * And corresponding host interrupt status bit field defines
+ */
+#define __HFN_INT_CPE_Q0               0x00000001U
+#define __HFN_INT_CPE_Q1               0x00000002U
+#define __HFN_INT_CPE_Q2               0x00000004U
+#define __HFN_INT_CPE_Q3               0x00000008U
+#define __HFN_INT_CPE_Q4               0x00000010U
+#define __HFN_INT_CPE_Q5               0x00000020U
+#define __HFN_INT_CPE_Q6               0x00000040U
+#define __HFN_INT_CPE_Q7               0x00000080U
+#define __HFN_INT_RME_Q0               0x00000100U
+#define __HFN_INT_RME_Q1               0x00000200U
+#define __HFN_INT_RME_Q2               0x00000400U
+#define __HFN_INT_RME_Q3               0x00000800U
+#define __HFN_INT_RME_Q4               0x00001000U
+#define __HFN_INT_RME_Q5               0x00002000U
+#define __HFN_INT_RME_Q6               0x00004000U
+#define __HFN_INT_RME_Q7               0x00008000U
+#define __HFN_INT_ERR_EMC              0x00010000U
+#define __HFN_INT_ERR_LPU0             0x00020000U
+#define __HFN_INT_ERR_LPU1             0x00040000U
+#define __HFN_INT_ERR_PSS              0x00080000U
+#define __HFN_INT_MBOX_LPU0            0x00100000U
+#define __HFN_INT_MBOX_LPU1            0x00200000U
+#define __HFN_INT_MBOX1_LPU0           0x00400000U
+#define __HFN_INT_MBOX1_LPU1           0x00800000U
+#define __HFN_INT_LL_HALT              0x01000000U
+#define __HFN_INT_CPE_MASK             0x000000ffU
+#define __HFN_INT_RME_MASK             0x0000ff00U
+
+/*
+ * catapult memory map.
+ */
+#define LL_PGN_HQM0            0x0096
+#define LL_PGN_HQM1            0x0097
+#define PSS_SMEM_PAGE_START    0x8000
+#define PSS_SMEM_PGNUM(_pg0, _ma)      ((_pg0) + ((_ma) >> 15))
+#define PSS_SMEM_PGOFF(_ma)    ((_ma) & 0x7fff)
+
+/*
+ * End of catapult memory map
+ */
+
+#endif /* __BFI_CTREG_H__ */
diff --git a/drivers/net/bna/bfi_ll.h b/drivers/net/bna/bfi_ll.h
new file mode 100644 (file)
index 0000000..bee4d05
--- /dev/null
@@ -0,0 +1,438 @@
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * 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.
+ */
+/*
+ * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+#ifndef __BFI_LL_H__
+#define __BFI_LL_H__
+
+#include "bfi.h"
+
+#pragma pack(1)
+
+/**
+ * @brief
+ *     "enums" for all LL mailbox messages other than IOC
+ */
+enum {
+       BFI_LL_H2I_MAC_UCAST_SET_REQ = 1,
+       BFI_LL_H2I_MAC_UCAST_ADD_REQ = 2,
+       BFI_LL_H2I_MAC_UCAST_DEL_REQ = 3,
+
+       BFI_LL_H2I_MAC_MCAST_ADD_REQ = 4,
+       BFI_LL_H2I_MAC_MCAST_DEL_REQ = 5,
+       BFI_LL_H2I_MAC_MCAST_FILTER_REQ = 6,
+       BFI_LL_H2I_MAC_MCAST_DEL_ALL_REQ = 7,
+
+       BFI_LL_H2I_PORT_ADMIN_REQ = 8,
+       BFI_LL_H2I_STATS_GET_REQ = 9,
+       BFI_LL_H2I_STATS_CLEAR_REQ = 10,
+
+       BFI_LL_H2I_RXF_PROMISCUOUS_SET_REQ = 11,
+       BFI_LL_H2I_RXF_DEFAULT_SET_REQ = 12,
+
+       BFI_LL_H2I_TXQ_STOP_REQ = 13,
+       BFI_LL_H2I_RXQ_STOP_REQ = 14,
+
+       BFI_LL_H2I_DIAG_LOOPBACK_REQ = 15,
+
+       BFI_LL_H2I_SET_PAUSE_REQ = 16,
+       BFI_LL_H2I_MTU_INFO_REQ = 17,
+
+       BFI_LL_H2I_RX_REQ = 18,
+} ;
+
+enum {
+       BFI_LL_I2H_MAC_UCAST_SET_RSP = BFA_I2HM(1),
+       BFI_LL_I2H_MAC_UCAST_ADD_RSP = BFA_I2HM(2),
+       BFI_LL_I2H_MAC_UCAST_DEL_RSP = BFA_I2HM(3),
+
+       BFI_LL_I2H_MAC_MCAST_ADD_RSP = BFA_I2HM(4),
+       BFI_LL_I2H_MAC_MCAST_DEL_RSP = BFA_I2HM(5),
+       BFI_LL_I2H_MAC_MCAST_FILTER_RSP = BFA_I2HM(6),
+       BFI_LL_I2H_MAC_MCAST_DEL_ALL_RSP = BFA_I2HM(7),
+
+       BFI_LL_I2H_PORT_ADMIN_RSP = BFA_I2HM(8),
+       BFI_LL_I2H_STATS_GET_RSP = BFA_I2HM(9),
+       BFI_LL_I2H_STATS_CLEAR_RSP = BFA_I2HM(10),
+
+       BFI_LL_I2H_RXF_PROMISCUOUS_SET_RSP = BFA_I2HM(11),
+       BFI_LL_I2H_RXF_DEFAULT_SET_RSP = BFA_I2HM(12),
+
+       BFI_LL_I2H_TXQ_STOP_RSP = BFA_I2HM(13),
+       BFI_LL_I2H_RXQ_STOP_RSP = BFA_I2HM(14),
+
+       BFI_LL_I2H_DIAG_LOOPBACK_RSP = BFA_I2HM(15),
+
+       BFI_LL_I2H_SET_PAUSE_RSP = BFA_I2HM(16),
+
+       BFI_LL_I2H_MTU_INFO_RSP = BFA_I2HM(17),
+       BFI_LL_I2H_RX_RSP = BFA_I2HM(18),
+
+       BFI_LL_I2H_LINK_DOWN_AEN = BFA_I2HM(19),
+       BFI_LL_I2H_LINK_UP_AEN = BFA_I2HM(20),
+
+       BFI_LL_I2H_PORT_ENABLE_AEN = BFA_I2HM(21),
+       BFI_LL_I2H_PORT_DISABLE_AEN = BFA_I2HM(22),
+} ;
+
+/**
+ * @brief bfi_ll_mac_addr_req is used by:
+ *        BFI_LL_H2I_MAC_UCAST_SET_REQ
+ *        BFI_LL_H2I_MAC_UCAST_ADD_REQ
+ *        BFI_LL_H2I_MAC_UCAST_DEL_REQ
+ *        BFI_LL_H2I_MAC_MCAST_ADD_REQ
+ *        BFI_LL_H2I_MAC_MCAST_DEL_REQ
+ */
+struct bfi_ll_mac_addr_req {
+       struct bfi_mhdr mh;             /*!< common msg header */
+       u8              rxf_id;
+       u8              rsvd1[3];
+       mac_t           mac_addr;
+       u8              rsvd2[2];
+};
+
+/**
+ * @brief bfi_ll_mcast_filter_req is used by:
+ *       BFI_LL_H2I_MAC_MCAST_FILTER_REQ
+ */
+struct bfi_ll_mcast_filter_req {
+       struct bfi_mhdr mh;             /*!< common msg header */
+       u8              rxf_id;
+       u8              enable;
+       u8              rsvd[2];
+};
+
+/**
+ * @brief bfi_ll_mcast_del_all is used by:
+ *       BFI_LL_H2I_MAC_MCAST_DEL_ALL_REQ
+ */
+struct bfi_ll_mcast_del_all_req {
+       struct bfi_mhdr mh;             /*!< common msg header */
+       u8                 rxf_id;
+       u8                 rsvd[3];
+};
+
+/**
+ * @brief bfi_ll_q_stop_req is used by:
+ *     BFI_LL_H2I_TXQ_STOP_REQ
+ *     BFI_LL_H2I_RXQ_STOP_REQ
+ */
+struct bfi_ll_q_stop_req {
+       struct bfi_mhdr mh;             /*!< common msg header */
+       u32     q_id_mask[2];   /* !< bit-mask for queue ids */
+};
+
+/**
+ * @brief bfi_ll_stats_req is used by:
+ *    BFI_LL_I2H_STATS_GET_REQ
+ *    BFI_LL_I2H_STATS_CLEAR_REQ
+ */
+struct bfi_ll_stats_req {
+       struct bfi_mhdr mh;     /*!< common msg header */
+       u16 stats_mask; /* !< bit-mask for non-function statistics */
+       u8      rsvd[2];
+       u32 rxf_id_mask[2];     /* !< bit-mask for RxF Statistics */
+       u32 txf_id_mask[2];     /* !< bit-mask for TxF Statistics */
+       union bfi_addr_u  host_buffer;  /* !< where statistics are returned */
+};
+
+/**
+ * @brief defines for "stats_mask" above.
+ */
+#define BFI_LL_STATS_MAC       (1 << 0)        /* !< MAC Statistics */
+#define BFI_LL_STATS_BPC       (1 << 1)        /* !< Pause Stats from BPC */
+#define BFI_LL_STATS_RAD       (1 << 2)        /* !< Rx Admission Statistics */
+#define BFI_LL_STATS_RX_FC     (1 << 3)        /* !< Rx FC Stats from RxA */
+#define BFI_LL_STATS_TX_FC     (1 << 4)        /* !< Tx FC Stats from TxA */
+
+#define BFI_LL_STATS_ALL       0x1f
+
+/**
+ * @brief bfi_ll_port_admin_req
+ */
+struct bfi_ll_port_admin_req {
+       struct bfi_mhdr mh;             /*!< common msg header */
+       u8               up;
+       u8               rsvd[3];
+};
+
+/**
+ * @brief bfi_ll_rxf_req is used by:
+ *      BFI_LL_H2I_RXF_PROMISCUOUS_SET_REQ
+ *      BFI_LL_H2I_RXF_DEFAULT_SET_REQ
+ */
+struct bfi_ll_rxf_req {
+       struct bfi_mhdr mh;             /*!< common msg header */
+       u8              rxf_id;
+       u8              enable;
+       u8              rsvd[2];
+};
+
+/**
+ * @brief bfi_ll_rxf_multi_req is used by:
+ *     BFI_LL_H2I_RX_REQ
+ */
+struct bfi_ll_rxf_multi_req {
+       struct bfi_mhdr mh;             /*!< common msg header */
+       u32     rxf_id_mask[2];
+       u8              enable;
+       u8              rsvd[3];
+};
+
+/**
+ * @brief enum for Loopback opmodes
+ */
+enum {
+       BFI_LL_DIAG_LB_OPMODE_EXT = 0,
+       BFI_LL_DIAG_LB_OPMODE_CBL = 1,
+};
+
+/**
+ * @brief bfi_ll_set_pause_req is used by:
+ *     BFI_LL_H2I_SET_PAUSE_REQ
+ */
+struct bfi_ll_set_pause_req {
+       struct bfi_mhdr mh;
+       u8              tx_pause; /* 1 = enable, 0 =  disable */
+       u8              rx_pause; /* 1 = enable, 0 =  disable */
+       u8              rsvd[2];
+};
+
+/**
+ * @brief bfi_ll_mtu_info_req is used by:
+ *     BFI_LL_H2I_MTU_INFO_REQ
+ */
+struct bfi_ll_mtu_info_req {
+       struct bfi_mhdr mh;
+       u16     mtu;
+       u8              rsvd[2];
+};
+
+/**
+ * @brief
+ *       Response header format used by all responses
+ *       For both responses and asynchronous notifications
+ */
+struct bfi_ll_rsp {
+       struct bfi_mhdr mh;             /*!< common msg header */
+       u8              error;
+       u8              rsvd[3];
+};
+
+/**
+ * @brief bfi_ll_cee_aen is used by:
+ *     BFI_LL_I2H_LINK_DOWN_AEN
+ *     BFI_LL_I2H_LINK_UP_AEN
+ */
+struct bfi_ll_aen {
+       struct bfi_mhdr mh;             /*!< common msg header */
+       u32     reason;
+       u8              cee_linkup;
+       u8              prio_map;    /*!< LL priority bit-map */
+       u8              rsvd[2];
+};
+
+/**
+ * @brief
+ *     The following error codes can be returned
+ *     by the mbox commands
+ */
+enum {
+       BFI_LL_CMD_OK           = 0,
+       BFI_LL_CMD_FAIL         = 1,
+       BFI_LL_CMD_DUP_ENTRY    = 2,    /* !< Duplicate entry in CAM */
+       BFI_LL_CMD_CAM_FULL     = 3,    /* !< CAM is full */
+       BFI_LL_CMD_NOT_OWNER    = 4,    /* !< Not permitted, b'cos not owner */
+       BFI_LL_CMD_NOT_EXEC     = 5,    /* !< Was not sent to f/w at all */
+       BFI_LL_CMD_WAITING      = 6,    /* !< Waiting for completion (VMware) */
+       BFI_LL_CMD_PORT_DISABLED        = 7,    /* !< port in disabled state */
+} ;
+
+/* Statistics */
+#define BFI_LL_TXF_ID_MAX      64
+#define BFI_LL_RXF_ID_MAX      64
+
+/* TxF Frame Statistics */
+struct bfi_ll_stats_txf {
+       u64 ucast_octets;
+       u64 ucast;
+       u64 ucast_vlan;
+
+       u64 mcast_octets;
+       u64 mcast;
+       u64 mcast_vlan;
+
+       u64 bcast_octets;
+       u64 bcast;
+       u64 bcast_vlan;
+
+       u64 errors;
+       u64 filter_vlan;      /* frames filtered due to VLAN */
+       u64 filter_mac_sa;    /* frames filtered due to SA check */
+};
+
+/* RxF Frame Statistics */
+struct bfi_ll_stats_rxf {
+       u64 ucast_octets;
+       u64 ucast;
+       u64 ucast_vlan;
+
+       u64 mcast_octets;
+       u64 mcast;
+       u64 mcast_vlan;
+
+       u64 bcast_octets;
+       u64 bcast;
+       u64 bcast_vlan;
+       u64 frame_drops;
+};
+
+/* FC Tx Frame Statistics */
+struct bfi_ll_stats_fc_tx {
+       u64 txf_ucast_octets;
+       u64 txf_ucast;
+       u64 txf_ucast_vlan;
+
+       u64 txf_mcast_octets;
+       u64 txf_mcast;
+       u64 txf_mcast_vlan;
+
+       u64 txf_bcast_octets;
+       u64 txf_bcast;
+       u64 txf_bcast_vlan;
+
+       u64 txf_parity_errors;
+       u64 txf_timeout;
+       u64 txf_fid_parity_errors;
+};
+
+/* FC Rx Frame Statistics */
+struct bfi_ll_stats_fc_rx {
+       u64 rxf_ucast_octets;
+       u64 rxf_ucast;
+       u64 rxf_ucast_vlan;
+
+       u64 rxf_mcast_octets;
+       u64 rxf_mcast;
+       u64 rxf_mcast_vlan;
+
+       u64 rxf_bcast_octets;
+       u64 rxf_bcast;
+       u64 rxf_bcast_vlan;
+};
+
+/* RAD Frame Statistics */
+struct bfi_ll_stats_rad {
+       u64 rx_frames;
+       u64 rx_octets;
+       u64 rx_vlan_frames;
+
+       u64 rx_ucast;
+       u64 rx_ucast_octets;
+       u64 rx_ucast_vlan;
+
+       u64 rx_mcast;
+       u64 rx_mcast_octets;
+       u64 rx_mcast_vlan;
+
+       u64 rx_bcast;
+       u64 rx_bcast_octets;
+       u64 rx_bcast_vlan;
+
+       u64 rx_drops;
+};
+
+/* BPC Tx Registers */
+struct bfi_ll_stats_bpc {
+       /* transmit stats */
+       u64 tx_pause[8];
+       u64 tx_zero_pause[8];   /*!< Pause cancellation */
+       /*!<Pause initiation rather than retention */
+       u64 tx_first_pause[8];
+
+       /* receive stats */
+       u64 rx_pause[8];
+       u64 rx_zero_pause[8];   /*!< Pause cancellation */
+       /*!<Pause initiation rather than retention */
+       u64 rx_first_pause[8];
+};
+
+/* MAC Rx Statistics */
+struct bfi_ll_stats_mac {
+       u64 frame_64;           /* both rx and tx counter */
+       u64 frame_65_127;               /* both rx and tx counter */
+       u64 frame_128_255;              /* both rx and tx counter */
+       u64 frame_256_511;              /* both rx and tx counter */
+       u64 frame_512_1023;     /* both rx and tx counter */
+       u64 frame_1024_1518;    /* both rx and tx counter */
+       u64 frame_1519_1522;    /* both rx and tx counter */
+
+       /* receive stats */
+       u64 rx_bytes;
+       u64 rx_packets;
+       u64 rx_fcs_error;
+       u64 rx_multicast;
+       u64 rx_broadcast;
+       u64 rx_control_frames;
+       u64 rx_pause;
+       u64 rx_unknown_opcode;
+       u64 rx_alignment_error;
+       u64 rx_frame_length_error;
+       u64 rx_code_error;
+       u64 rx_carrier_sense_error;
+       u64 rx_undersize;
+       u64 rx_oversize;
+       u64 rx_fragments;
+       u64 rx_jabber;
+       u64 rx_drop;
+
+       /* transmit stats */
+       u64 tx_bytes;
+       u64 tx_packets;
+       u64 tx_multicast;
+       u64 tx_broadcast;
+       u64 tx_pause;
+       u64 tx_deferral;
+       u64 tx_excessive_deferral;
+       u64 tx_single_collision;
+       u64 tx_muliple_collision;
+       u64 tx_late_collision;
+       u64 tx_excessive_collision;
+       u64 tx_total_collision;
+       u64 tx_pause_honored;
+       u64 tx_drop;
+       u64 tx_jabber;
+       u64 tx_fcs_error;
+       u64 tx_control_frame;
+       u64 tx_oversize;
+       u64 tx_undersize;
+       u64 tx_fragments;
+};
+
+/* Complete statistics */
+struct bfi_ll_stats {
+       struct bfi_ll_stats_mac         mac_stats;
+       struct bfi_ll_stats_bpc         bpc_stats;
+       struct bfi_ll_stats_rad         rad_stats;
+       struct bfi_ll_stats_fc_rx       fc_rx_stats;
+       struct bfi_ll_stats_fc_tx       fc_tx_stats;
+       struct bfi_ll_stats_rxf rxf_stats[BFI_LL_RXF_ID_MAX];
+       struct bfi_ll_stats_txf txf_stats[BFI_LL_TXF_ID_MAX];
+};
+
+#pragma pack()
+
+#endif  /* __BFI_LL_H__ */
diff --git a/drivers/net/bna/bna.h b/drivers/net/bna/bna.h
new file mode 100644 (file)
index 0000000..6a2b329
--- /dev/null
@@ -0,0 +1,654 @@
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * 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.
+ */
+#ifndef __BNA_H__
+#define __BNA_H__
+
+#include "bfa_wc.h"
+#include "bfa_ioc.h"
+#include "cna.h"
+#include "bfi_ll.h"
+#include "bna_types.h"
+
+extern u32 bna_dim_vector[][BNA_BIAS_T_MAX];
+extern u32 bna_napi_dim_vector[][BNA_BIAS_T_MAX];
+
+/**
+ *
+ *  Macros and constants
+ *
+ */
+
+#define BNA_IOC_TIMER_FREQ             200
+
+/* Log string size */
+#define BNA_MESSAGE_SIZE               256
+
+#define bna_device_timer(_dev)         bfa_timer_beat(&((_dev)->timer_mod))
+
+/* MBOX API for PORT, TX, RX */
+#define bna_mbox_qe_fill(_qe, _cmd, _cmd_len, _cbfn, _cbarg)           \
+do {                                                                   \
+       memcpy(&((_qe)->cmd.msg[0]), (_cmd), (_cmd_len));       \
+       (_qe)->cbfn = (_cbfn);                                          \
+       (_qe)->cbarg = (_cbarg);                                        \
+} while (0)
+
+#define bna_is_small_rxq(rcb) ((rcb)->id == 1)
+
+#define BNA_MAC_IS_EQUAL(_mac1, _mac2)                                 \
+       (!memcmp((_mac1), (_mac2), sizeof(mac_t)))
+
+#define BNA_POWER_OF_2(x) (((x) & ((x) - 1)) == 0)
+
+#define BNA_TO_POWER_OF_2(x)                                           \
+do {                                                                   \
+       int _shift = 0;                                                 \
+       while ((x) && (x) != 1) {                                       \
+               (x) >>= 1;                                              \
+               _shift++;                                               \
+       }                                                               \
+       (x) <<= _shift;                                                 \
+} while (0)
+
+#define BNA_TO_POWER_OF_2_HIGH(x)                                      \
+do {                                                                   \
+       int n = 1;                                                      \
+       while (n < (x))                                                 \
+               n <<= 1;                                                \
+       (x) = n;                                                        \
+} while (0)
+
+/*
+ * input : _addr-> os dma addr in host endian format,
+ * output : _bna_dma_addr-> pointer to hw dma addr
+ */
+#define BNA_SET_DMA_ADDR(_addr, _bna_dma_addr)                         \
+do {                                                                   \
+       u64 tmp_addr =                                          \
+       cpu_to_be64((u64)(_addr));                              \
+       (_bna_dma_addr)->msb = ((struct bna_dma_addr *)&tmp_addr)->msb; \
+       (_bna_dma_addr)->lsb = ((struct bna_dma_addr *)&tmp_addr)->lsb; \
+} while (0)
+
+/*
+ * input : _bna_dma_addr-> pointer to hw dma addr
+ * output : _addr-> os dma addr in host endian format
+ */
+#define BNA_GET_DMA_ADDR(_bna_dma_addr, _addr)                 \
+do {                                                           \
+       (_addr) = ((((u64)ntohl((_bna_dma_addr)->msb))) << 32)          \
+       | ((ntohl((_bna_dma_addr)->lsb) & 0xffffffff)); \
+} while (0)
+
+#define        containing_rec(addr, type, field)                               \
+       ((type *)((unsigned char *)(addr) -                             \
+       (unsigned char *)(&((type *)0)->field)))
+
+#define BNA_TXQ_WI_NEEDED(_vectors)    (((_vectors) + 3) >> 2)
+
+/* TxQ element is 64 bytes */
+#define BNA_TXQ_PAGE_INDEX_MAX         (PAGE_SIZE >> 6)
+#define BNA_TXQ_PAGE_INDEX_MAX_SHIFT   (PAGE_SHIFT - 6)
+
+#define BNA_TXQ_QPGE_PTR_GET(_qe_idx, _qpt_ptr, _qe_ptr, _qe_ptr_range) \
+{                                                                      \
+       unsigned int page_index;        /* index within a page */       \
+       void *page_addr;                                                \
+       page_index = (_qe_idx) & (BNA_TXQ_PAGE_INDEX_MAX - 1);          \
+       (_qe_ptr_range) = (BNA_TXQ_PAGE_INDEX_MAX - page_index);        \
+       page_addr = (_qpt_ptr)[((_qe_idx) >>  BNA_TXQ_PAGE_INDEX_MAX_SHIFT)];\
+       (_qe_ptr) = &((struct bna_txq_entry *)(page_addr))[page_index]; \
+}
+
+/* RxQ element is 8 bytes */
+#define BNA_RXQ_PAGE_INDEX_MAX         (PAGE_SIZE >> 3)
+#define BNA_RXQ_PAGE_INDEX_MAX_SHIFT   (PAGE_SHIFT - 3)
+
+#define BNA_RXQ_QPGE_PTR_GET(_qe_idx, _qpt_ptr, _qe_ptr, _qe_ptr_range) \
+{                                                                      \
+       unsigned int page_index;        /* index within a page */       \
+       void *page_addr;                                                \
+       page_index = (_qe_idx) & (BNA_RXQ_PAGE_INDEX_MAX - 1);          \
+       (_qe_ptr_range) = (BNA_RXQ_PAGE_INDEX_MAX - page_index);        \
+       page_addr = (_qpt_ptr)[((_qe_idx) >>                            \
+                               BNA_RXQ_PAGE_INDEX_MAX_SHIFT)];         \
+       (_qe_ptr) = &((struct bna_rxq_entry *)(page_addr))[page_index]; \
+}
+
+/* CQ element is 16 bytes */
+#define BNA_CQ_PAGE_INDEX_MAX          (PAGE_SIZE >> 4)
+#define BNA_CQ_PAGE_INDEX_MAX_SHIFT    (PAGE_SHIFT - 4)
+
+#define BNA_CQ_QPGE_PTR_GET(_qe_idx, _qpt_ptr, _qe_ptr, _qe_ptr_range) \
+{                                                                      \
+       unsigned int page_index;          /* index within a page */     \
+       void *page_addr;                                                \
+                                                                       \
+       page_index = (_qe_idx) & (BNA_CQ_PAGE_INDEX_MAX - 1);           \
+       (_qe_ptr_range) = (BNA_CQ_PAGE_INDEX_MAX - page_index);         \
+       page_addr = (_qpt_ptr)[((_qe_idx) >>                            \
+                                   BNA_CQ_PAGE_INDEX_MAX_SHIFT)];      \
+       (_qe_ptr) = &((struct bna_cq_entry *)(page_addr))[page_index];\
+}
+
+#define BNA_QE_INDX_2_PTR(_cast, _qe_idx, _q_base)                     \
+       (&((_cast *)(_q_base))[(_qe_idx)])
+
+#define BNA_QE_INDX_RANGE(_qe_idx, _q_depth) ((_q_depth) - (_qe_idx))
+
+#define BNA_QE_INDX_ADD(_qe_idx, _qe_num, _q_depth)                    \
+       ((_qe_idx) = ((_qe_idx) + (_qe_num)) & ((_q_depth) - 1))
+
+#define BNA_Q_INDEX_CHANGE(_old_idx, _updated_idx, _q_depth)           \
+       (((_updated_idx) - (_old_idx)) & ((_q_depth) - 1))
+
+#define BNA_QE_FREE_CNT(_q_ptr, _q_depth)                              \
+       (((_q_ptr)->consumer_index - (_q_ptr)->producer_index - 1) &    \
+        ((_q_depth) - 1))
+
+#define BNA_QE_IN_USE_CNT(_q_ptr, _q_depth)                            \
+       ((((_q_ptr)->producer_index - (_q_ptr)->consumer_index)) &      \
+        (_q_depth - 1))
+
+#define BNA_Q_GET_CI(_q_ptr)           ((_q_ptr)->q.consumer_index)
+
+#define BNA_Q_GET_PI(_q_ptr)           ((_q_ptr)->q.producer_index)
+
+#define BNA_Q_PI_ADD(_q_ptr, _num)                                     \
+       (_q_ptr)->q.producer_index =                                    \
+               (((_q_ptr)->q.producer_index + (_num)) &                \
+               ((_q_ptr)->q.q_depth - 1))
+
+#define BNA_Q_CI_ADD(_q_ptr, _num)                                     \
+       (_q_ptr)->q.consumer_index =                                    \
+               (((_q_ptr)->q.consumer_index + (_num))                  \
+               & ((_q_ptr)->q.q_depth - 1))
+
+#define BNA_Q_FREE_COUNT(_q_ptr)                                       \
+       (BNA_QE_FREE_CNT(&((_q_ptr)->q), (_q_ptr)->q.q_depth))
+
+#define BNA_Q_IN_USE_COUNT(_q_ptr)                                     \
+       (BNA_QE_IN_USE_CNT(&(_q_ptr)->q, (_q_ptr)->q.q_depth))
+
+/* These macros build the data portion of the TxQ/RxQ doorbell */
+#define BNA_DOORBELL_Q_PRD_IDX(_pi)    (0x80000000 | (_pi))
+#define BNA_DOORBELL_Q_STOP            (0x40000000)
+
+/* These macros build the data portion of the IB doorbell */
+#define BNA_DOORBELL_IB_INT_ACK(_timeout, _events) \
+       (0x80000000 | ((_timeout) << 16) | (_events))
+#define BNA_DOORBELL_IB_INT_DISABLE    (0x40000000)
+
+/* Set the coalescing timer for the given ib */
+#define bna_ib_coalescing_timer_set(_i_dbell, _cls_timer)              \
+       ((_i_dbell)->doorbell_ack = BNA_DOORBELL_IB_INT_ACK((_cls_timer), 0));
+
+/* Acks 'events' # of events for a given ib */
+#define bna_ib_ack(_i_dbell, _events)                                  \
+       (writel(((_i_dbell)->doorbell_ack | (_events)), \
+               (_i_dbell)->doorbell_addr));
+
+#define bna_txq_prod_indx_doorbell(_tcb)                               \
+       (writel(BNA_DOORBELL_Q_PRD_IDX((_tcb)->producer_index), \
+               (_tcb)->q_dbell));
+
+#define bna_rxq_prod_indx_doorbell(_rcb)                               \
+       (writel(BNA_DOORBELL_Q_PRD_IDX((_rcb)->producer_index), \
+               (_rcb)->q_dbell));
+
+#define BNA_LARGE_PKT_SIZE             1000
+
+#define BNA_UPDATE_PKT_CNT(_pkt, _len)                                 \
+do {                                                                   \
+       if ((_len) > BNA_LARGE_PKT_SIZE) {                              \
+               (_pkt)->large_pkt_cnt++;                                \
+       } else {                                                        \
+               (_pkt)->small_pkt_cnt++;                                \
+       }                                                               \
+} while (0)
+
+#define        call_rxf_stop_cbfn(rxf, status)                                 \
+       if ((rxf)->stop_cbfn) {                                         \
+               (*(rxf)->stop_cbfn)((rxf)->stop_cbarg, (status));       \
+               (rxf)->stop_cbfn = NULL;                                \
+               (rxf)->stop_cbarg = NULL;                               \
+       }
+
+#define        call_rxf_start_cbfn(rxf, status)                                \
+       if ((rxf)->start_cbfn) {                                        \
+               (*(rxf)->start_cbfn)((rxf)->start_cbarg, (status));     \
+               (rxf)->start_cbfn = NULL;                               \
+               (rxf)->start_cbarg = NULL;                              \
+       }
+
+#define        call_rxf_cam_fltr_cbfn(rxf, status)                             \
+       if ((rxf)->cam_fltr_cbfn) {                                     \
+               (*(rxf)->cam_fltr_cbfn)((rxf)->cam_fltr_cbarg, rxf->rx, \
+                                       (status));                      \
+               (rxf)->cam_fltr_cbfn = NULL;                            \
+               (rxf)->cam_fltr_cbarg = NULL;                           \
+       }
+
+#define        call_rxf_pause_cbfn(rxf, status)                                \
+       if ((rxf)->oper_state_cbfn) {                                   \
+               (*(rxf)->oper_state_cbfn)((rxf)->oper_state_cbarg, rxf->rx,\
+                                       (status));                      \
+               (rxf)->rxf_flags &= ~BNA_RXF_FL_OPERSTATE_CHANGED;      \
+               (rxf)->oper_state_cbfn = NULL;                          \
+               (rxf)->oper_state_cbarg = NULL;                         \
+       }
+
+#define        call_rxf_resume_cbfn(rxf, status) call_rxf_pause_cbfn(rxf, status)
+
+#define is_xxx_enable(mode, bitmask, xxx) ((bitmask & xxx) && (mode & xxx))
+
+#define is_xxx_disable(mode, bitmask, xxx) ((bitmask & xxx) && !(mode & xxx))
+
+#define xxx_enable(mode, bitmask, xxx)                                 \
+do {                                                                   \
+       bitmask |= xxx;                                                 \
+       mode |= xxx;                                                    \
+} while (0)
+
+#define xxx_disable(mode, bitmask, xxx)                                        \
+do {                                                                   \
+       bitmask |= xxx;                                                 \
+       mode &= ~xxx;                                                   \
+} while (0)
+
+#define xxx_inactive(mode, bitmask, xxx)                               \
+do {                                                                   \
+       bitmask &= ~xxx;                                                \
+       mode &= ~xxx;                                                   \
+} while (0)
+
+#define is_promisc_enable(mode, bitmask)                               \
+       is_xxx_enable(mode, bitmask, BNA_RXMODE_PROMISC)
+
+#define is_promisc_disable(mode, bitmask)                              \
+       is_xxx_disable(mode, bitmask, BNA_RXMODE_PROMISC)
+
+#define promisc_enable(mode, bitmask)                                  \
+       xxx_enable(mode, bitmask, BNA_RXMODE_PROMISC)
+
+#define promisc_disable(mode, bitmask)                                 \
+       xxx_disable(mode, bitmask, BNA_RXMODE_PROMISC)
+
+#define promisc_inactive(mode, bitmask)                                        \
+       xxx_inactive(mode, bitmask, BNA_RXMODE_PROMISC)
+
+#define is_default_enable(mode, bitmask)                               \
+       is_xxx_enable(mode, bitmask, BNA_RXMODE_DEFAULT)
+
+#define is_default_disable(mode, bitmask)                              \
+       is_xxx_disable(mode, bitmask, BNA_RXMODE_DEFAULT)
+
+#define default_enable(mode, bitmask)                                  \
+       xxx_enable(mode, bitmask, BNA_RXMODE_DEFAULT)
+
+#define default_disable(mode, bitmask)                                 \
+       xxx_disable(mode, bitmask, BNA_RXMODE_DEFAULT)
+
+#define default_inactive(mode, bitmask)                                        \
+       xxx_inactive(mode, bitmask, BNA_RXMODE_DEFAULT)
+
+#define is_allmulti_enable(mode, bitmask)                              \
+       is_xxx_enable(mode, bitmask, BNA_RXMODE_ALLMULTI)
+
+#define is_allmulti_disable(mode, bitmask)                             \
+       is_xxx_disable(mode, bitmask, BNA_RXMODE_ALLMULTI)
+
+#define allmulti_enable(mode, bitmask)                                 \
+       xxx_enable(mode, bitmask, BNA_RXMODE_ALLMULTI)
+
+#define allmulti_disable(mode, bitmask)                                        \
+       xxx_disable(mode, bitmask, BNA_RXMODE_ALLMULTI)
+
+#define allmulti_inactive(mode, bitmask)                               \
+       xxx_inactive(mode, bitmask, BNA_RXMODE_ALLMULTI)
+
+#define        GET_RXQS(rxp, q0, q1)   do {                                    \
+       switch ((rxp)->type) {                                          \
+       case BNA_RXP_SINGLE:                                            \
+               (q0) = rxp->rxq.single.only;                            \
+               (q1) = NULL;                                            \
+               break;                                                  \
+       case BNA_RXP_SLR:                                               \
+               (q0) = rxp->rxq.slr.large;                              \
+               (q1) = rxp->rxq.slr.small;                              \
+               break;                                                  \
+       case BNA_RXP_HDS:                                               \
+               (q0) = rxp->rxq.hds.data;                               \
+               (q1) = rxp->rxq.hds.hdr;                                \
+               break;                                                  \
+       }                                                               \
+} while (0)
+
+/**
+ *
+ * Function prototypes
+ *
+ */
+
+/**
+ * BNA
+ */
+
+/* Internal APIs */
+void bna_adv_res_req(struct bna_res_info *res_info);
+
+/* APIs for BNAD */
+void bna_res_req(struct bna_res_info *res_info);
+void bna_init(struct bna *bna, struct bnad *bnad,
+                       struct bfa_pcidev *pcidev,
+                       struct bna_res_info *res_info);
+void bna_uninit(struct bna *bna);
+void bna_stats_get(struct bna *bna);
+void bna_stats_clr(struct bna *bna);
+void bna_get_perm_mac(struct bna *bna, u8 *mac);
+
+/* APIs for Rx */
+int bna_rit_mod_can_satisfy(struct bna_rit_mod *rit_mod, int seg_size);
+
+/* APIs for RxF */
+struct bna_mac *bna_ucam_mod_mac_get(struct bna_ucam_mod *ucam_mod);
+void bna_ucam_mod_mac_put(struct bna_ucam_mod *ucam_mod,
+                         struct bna_mac *mac);
+struct bna_mac *bna_mcam_mod_mac_get(struct bna_mcam_mod *mcam_mod);
+void bna_mcam_mod_mac_put(struct bna_mcam_mod *mcam_mod,
+                         struct bna_mac *mac);
+struct bna_rit_segment *
+bna_rit_mod_seg_get(struct bna_rit_mod *rit_mod, int seg_size);
+void bna_rit_mod_seg_put(struct bna_rit_mod *rit_mod,
+                       struct bna_rit_segment *seg);
+
+/**
+ * DEVICE
+ */
+
+/* Interanl APIs */
+void bna_adv_device_init(struct bna_device *device, struct bna *bna,
+                       struct bna_res_info *res_info);
+
+/* APIs for BNA */
+void bna_device_init(struct bna_device *device, struct bna *bna,
+                    struct bna_res_info *res_info);
+void bna_device_uninit(struct bna_device *device);
+void bna_device_cb_port_stopped(void *arg, enum bna_cb_status status);
+int bna_device_status_get(struct bna_device *device);
+int bna_device_state_get(struct bna_device *device);
+
+/* APIs for BNAD */
+void bna_device_enable(struct bna_device *device);
+void bna_device_disable(struct bna_device *device,
+                       enum bna_cleanup_type type);
+
+/**
+ * MBOX
+ */
+
+/* APIs for DEVICE */
+void bna_mbox_mod_init(struct bna_mbox_mod *mbox_mod, struct bna *bna);
+void bna_mbox_mod_uninit(struct bna_mbox_mod *mbox_mod);
+void bna_mbox_mod_start(struct bna_mbox_mod *mbox_mod);
+void bna_mbox_mod_stop(struct bna_mbox_mod *mbox_mod);
+
+/* APIs for PORT, TX, RX */
+void bna_mbox_handler(struct bna *bna, u32 intr_status);
+void bna_mbox_send(struct bna *bna, struct bna_mbox_qe *mbox_qe);
+
+/**
+ * PORT
+ */
+
+/* APIs for BNA */
+void bna_port_init(struct bna_port *port, struct bna *bna);
+void bna_port_uninit(struct bna_port *port);
+int bna_port_state_get(struct bna_port *port);
+int bna_llport_state_get(struct bna_llport *llport);
+
+/* APIs for DEVICE */
+void bna_port_start(struct bna_port *port);
+void bna_port_stop(struct bna_port *port);
+void bna_port_fail(struct bna_port *port);
+
+/* API for RX */
+int bna_port_mtu_get(struct bna_port *port);
+void bna_llport_admin_up(struct bna_llport *llport);
+void bna_llport_admin_down(struct bna_llport *llport);
+
+/* API for BNAD */
+void bna_port_enable(struct bna_port *port);
+void bna_port_disable(struct bna_port *port, enum bna_cleanup_type type,
+                     void (*cbfn)(void *, enum bna_cb_status));
+void bna_port_pause_config(struct bna_port *port,
+                          struct bna_pause_config *pause_config,
+                          void (*cbfn)(struct bnad *, enum bna_cb_status));
+void bna_port_mtu_set(struct bna_port *port, int mtu,
+                     void (*cbfn)(struct bnad *, enum bna_cb_status));
+void bna_port_mac_get(struct bna_port *port, mac_t *mac);
+void bna_port_type_set(struct bna_port *port, enum bna_port_type type);
+void bna_port_linkcbfn_set(struct bna_port *port,
+                          void (*linkcbfn)(struct bnad *,
+                                           enum bna_link_status));
+void bna_port_admin_up(struct bna_port *port);
+void bna_port_admin_down(struct bna_port *port);
+
+/* Callbacks for TX, RX */
+void bna_port_cb_tx_stopped(struct bna_port *port,
+                           enum bna_cb_status status);
+void bna_port_cb_rx_stopped(struct bna_port *port,
+                           enum bna_cb_status status);
+
+/* Callbacks for MBOX */
+void bna_port_cb_link_up(struct bna_port *port, struct bfi_ll_aen *aen,
+                        int status);
+void bna_port_cb_link_down(struct bna_port *port, int status);
+
+/**
+ * IB
+ */
+
+/* APIs for BNA */
+void bna_ib_mod_init(struct bna_ib_mod *ib_mod, struct bna *bna,
+                    struct bna_res_info *res_info);
+void bna_ib_mod_uninit(struct bna_ib_mod *ib_mod);
+
+/* APIs for TX, RX */
+struct bna_ib *bna_ib_get(struct bna_ib_mod *ib_mod,
+                           enum bna_intr_type intr_type, int vector);
+void bna_ib_put(struct bna_ib_mod *ib_mod, struct bna_ib *ib);
+int bna_ib_reserve_idx(struct bna_ib *ib);
+void bna_ib_release_idx(struct bna_ib *ib, int idx);
+int bna_ib_config(struct bna_ib *ib, struct bna_ib_config *ib_config);
+void bna_ib_start(struct bna_ib *ib);
+void bna_ib_stop(struct bna_ib *ib);
+void bna_ib_fail(struct bna_ib *ib);
+void bna_ib_coalescing_timeo_set(struct bna_ib *ib, u8 coalescing_timeo);
+
+/**
+ * TX MODULE AND TX
+ */
+
+/* Internal APIs */
+void bna_tx_prio_changed(struct bna_tx *tx, int prio);
+
+/* APIs for BNA */
+void bna_tx_mod_init(struct bna_tx_mod *tx_mod, struct bna *bna,
+                    struct bna_res_info *res_info);
+void bna_tx_mod_uninit(struct bna_tx_mod *tx_mod);
+int bna_tx_state_get(struct bna_tx *tx);
+
+/* APIs for PORT */
+void bna_tx_mod_start(struct bna_tx_mod *tx_mod, enum bna_tx_type type);
+void bna_tx_mod_stop(struct bna_tx_mod *tx_mod, enum bna_tx_type type);
+void bna_tx_mod_fail(struct bna_tx_mod *tx_mod);
+void bna_tx_mod_prio_changed(struct bna_tx_mod *tx_mod, int prio);
+void bna_tx_mod_cee_link_status(struct bna_tx_mod *tx_mod, int cee_link);
+
+/* APIs for BNAD */
+void bna_tx_res_req(int num_txq, int txq_depth,
+                   struct bna_res_info *res_info);
+struct bna_tx *bna_tx_create(struct bna *bna, struct bnad *bnad,
+                              struct bna_tx_config *tx_cfg,
+                              struct bna_tx_event_cbfn *tx_cbfn,
+                              struct bna_res_info *res_info, void *priv);
+void bna_tx_destroy(struct bna_tx *tx);
+void bna_tx_enable(struct bna_tx *tx);
+void bna_tx_disable(struct bna_tx *tx, enum bna_cleanup_type type,
+                   void (*cbfn)(void *, struct bna_tx *,
+                                enum bna_cb_status));
+enum bna_cb_status
+bna_tx_prio_set(struct bna_tx *tx, int prio,
+               void (*cbfn)(struct bnad *, struct bna_tx *,
+                            enum bna_cb_status));
+void bna_tx_coalescing_timeo_set(struct bna_tx *tx, int coalescing_timeo);
+
+/**
+ * RX MODULE, RX, RXF
+ */
+
+/* Internal APIs */
+void rxf_cb_cam_fltr_mbox_cmd(void *arg, int status);
+void rxf_cam_mbox_cmd(struct bna_rxf *rxf, u8 cmd,
+               const struct bna_mac *mac_addr);
+void __rxf_vlan_filter_set(struct bna_rxf *rxf, enum bna_status status);
+void bna_rxf_adv_init(struct bna_rxf *rxf,
+               struct bna_rx *rx,
+               struct bna_rx_config *q_config);
+int rxf_process_packet_filter_ucast(struct bna_rxf *rxf);
+int rxf_process_packet_filter_promisc(struct bna_rxf *rxf);
+int rxf_process_packet_filter_default(struct bna_rxf *rxf);
+int rxf_process_packet_filter_allmulti(struct bna_rxf *rxf);
+int rxf_clear_packet_filter_ucast(struct bna_rxf *rxf);
+int rxf_clear_packet_filter_promisc(struct bna_rxf *rxf);
+int rxf_clear_packet_filter_default(struct bna_rxf *rxf);
+int rxf_clear_packet_filter_allmulti(struct bna_rxf *rxf);
+void rxf_reset_packet_filter_ucast(struct bna_rxf *rxf);
+void rxf_reset_packet_filter_promisc(struct bna_rxf *rxf);
+void rxf_reset_packet_filter_default(struct bna_rxf *rxf);
+void rxf_reset_packet_filter_allmulti(struct bna_rxf *rxf);
+
+/* APIs for BNA */
+void bna_rx_mod_init(struct bna_rx_mod *rx_mod, struct bna *bna,
+                    struct bna_res_info *res_info);
+void bna_rx_mod_uninit(struct bna_rx_mod *rx_mod);
+int bna_rx_state_get(struct bna_rx *rx);
+int bna_rxf_state_get(struct bna_rxf *rxf);
+
+/* APIs for PORT */
+void bna_rx_mod_start(struct bna_rx_mod *rx_mod, enum bna_rx_type type);
+void bna_rx_mod_stop(struct bna_rx_mod *rx_mod, enum bna_rx_type type);
+void bna_rx_mod_fail(struct bna_rx_mod *rx_mod);
+
+/* APIs for BNAD */
+void bna_rx_res_req(struct bna_rx_config *rx_config,
+                   struct bna_res_info *res_info);
+struct bna_rx *bna_rx_create(struct bna *bna, struct bnad *bnad,
+                              struct bna_rx_config *rx_cfg,
+                              struct bna_rx_event_cbfn *rx_cbfn,
+                              struct bna_res_info *res_info, void *priv);
+void bna_rx_destroy(struct bna_rx *rx);
+void bna_rx_enable(struct bna_rx *rx);
+void bna_rx_disable(struct bna_rx *rx, enum bna_cleanup_type type,
+                   void (*cbfn)(void *, struct bna_rx *,
+                                enum bna_cb_status));
+void bna_rx_coalescing_timeo_set(struct bna_rx *rx, int coalescing_timeo);
+void bna_rx_dim_reconfig(struct bna *bna, u32 vector[][BNA_BIAS_T_MAX]);
+void bna_rx_dim_update(struct bna_ccb *ccb);
+enum bna_cb_status
+bna_rx_ucast_set(struct bna_rx *rx, u8 *ucmac,
+                void (*cbfn)(struct bnad *, struct bna_rx *,
+                             enum bna_cb_status));
+enum bna_cb_status
+bna_rx_ucast_add(struct bna_rx *rx, u8* ucmac,
+                void (*cbfn)(struct bnad *, struct bna_rx *,
+                             enum bna_cb_status));
+enum bna_cb_status
+bna_rx_ucast_del(struct bna_rx *rx, u8 *ucmac,
+                void (*cbfn)(struct bnad *, struct bna_rx *,
+                             enum bna_cb_status));
+enum bna_cb_status
+bna_rx_mcast_add(struct bna_rx *rx, u8 *mcmac,
+                void (*cbfn)(struct bnad *, struct bna_rx *,
+                             enum bna_cb_status));
+enum bna_cb_status
+bna_rx_mcast_del(struct bna_rx *rx, u8 *mcmac,
+                void (*cbfn)(struct bnad *, struct bna_rx *,
+                             enum bna_cb_status));
+enum bna_cb_status
+bna_rx_mcast_listset(struct bna_rx *rx, int count, u8 *mcmac,
+                    void (*cbfn)(struct bnad *, struct bna_rx *,
+                                 enum bna_cb_status));
+void bna_rx_mcast_delall(struct bna_rx *rx,
+                        void (*cbfn)(struct bnad *, struct bna_rx *,
+                                     enum bna_cb_status));
+enum bna_cb_status
+bna_rx_mode_set(struct bna_rx *rx, enum bna_rxmode rxmode,
+               enum bna_rxmode bitmask,
+               void (*cbfn)(struct bnad *, struct bna_rx *,
+                            enum bna_cb_status));
+void bna_rx_vlan_add(struct bna_rx *rx, int vlan_id);
+void bna_rx_vlan_del(struct bna_rx *rx, int vlan_id);
+void bna_rx_vlanfilter_enable(struct bna_rx *rx);
+void bna_rx_vlanfilter_disable(struct bna_rx *rx);
+void bna_rx_rss_enable(struct bna_rx *rx);
+void bna_rx_rss_disable(struct bna_rx *rx);
+void bna_rx_rss_reconfig(struct bna_rx *rx, struct bna_rxf_rss *rss_config);
+void bna_rx_rss_rit_set(struct bna_rx *rx, unsigned int *vectors,
+                       int nvectors);
+void bna_rx_hds_enable(struct bna_rx *rx, struct bna_rxf_hds *hds_config,
+                      void (*cbfn)(struct bnad *, struct bna_rx *,
+                                   enum bna_cb_status));
+void bna_rx_hds_disable(struct bna_rx *rx,
+                       void (*cbfn)(struct bnad *, struct bna_rx *,
+                                    enum bna_cb_status));
+void bna_rx_receive_pause(struct bna_rx *rx,
+                         void (*cbfn)(struct bnad *, struct bna_rx *,
+                                      enum bna_cb_status));
+void bna_rx_receive_resume(struct bna_rx *rx,
+                          void (*cbfn)(struct bnad *, struct bna_rx *,
+                                       enum bna_cb_status));
+
+/* RxF APIs for RX */
+void bna_rxf_start(struct bna_rxf *rxf);
+void bna_rxf_stop(struct bna_rxf *rxf);
+void bna_rxf_fail(struct bna_rxf *rxf);
+void bna_rxf_init(struct bna_rxf *rxf, struct bna_rx *rx,
+                 struct bna_rx_config *q_config);
+void bna_rxf_uninit(struct bna_rxf *rxf);
+
+/* Callback from RXF to RX */
+void bna_rx_cb_rxf_stopped(struct bna_rx *rx, enum bna_cb_status);
+void bna_rx_cb_rxf_started(struct bna_rx *rx, enum bna_cb_status);
+
+/**
+ * BNAD
+ */
+
+/* Callbacks for BNA */
+void bnad_cb_stats_get(struct bnad *bnad, enum bna_cb_status status,
+                      struct bna_stats *stats);
+void bnad_cb_stats_clr(struct bnad *bnad);
+
+/* Callbacks for DEVICE */
+void bnad_cb_device_enabled(struct bnad *bnad, enum bna_cb_status status);
+void bnad_cb_device_disabled(struct bnad *bnad, enum bna_cb_status status);
+void bnad_cb_device_enable_mbox_intr(struct bnad *bnad);
+void bnad_cb_device_disable_mbox_intr(struct bnad *bnad);
+
+/* Callbacks for port */
+void bnad_cb_port_link_status(struct bnad *bnad,
+                             enum bna_link_status status);
+
+#endif  /* __BNA_H__ */
diff --git a/drivers/net/bna/bna_ctrl.c b/drivers/net/bna/bna_ctrl.c
new file mode 100644 (file)
index 0000000..f3034d6
--- /dev/null
@@ -0,0 +1,3624 @@
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * 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.
+ */
+/*
+ * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+#include "bna.h"
+#include "bfa_sm.h"
+#include "bfa_wc.h"
+
+/**
+ * MBOX
+ */
+static int
+bna_is_aen(u8 msg_id)
+{
+       return (msg_id == BFI_LL_I2H_LINK_DOWN_AEN ||
+               msg_id == BFI_LL_I2H_LINK_UP_AEN);
+}
+
+static void
+bna_mbox_aen_callback(struct bna *bna, struct bfi_mbmsg *msg)
+{
+       struct bfi_ll_aen *aen = (struct bfi_ll_aen *)(msg);
+
+       switch (aen->mh.msg_id) {
+       case BFI_LL_I2H_LINK_UP_AEN:
+               bna_port_cb_link_up(&bna->port, aen, aen->reason);
+               break;
+       case BFI_LL_I2H_LINK_DOWN_AEN:
+               bna_port_cb_link_down(&bna->port, aen->reason);
+               break;
+       default:
+               break;
+       }
+}
+
+static void
+bna_ll_isr(void *llarg, struct bfi_mbmsg *msg)
+{
+       struct bna *bna = (struct bna *)(llarg);
+       struct bfi_ll_rsp *mb_rsp = (struct bfi_ll_rsp *)(msg);
+       struct bfi_mhdr *cmd_h, *rsp_h;
+       struct bna_mbox_qe *mb_qe = NULL;
+       int to_post = 0;
+       u8 aen = 0;
+       char message[BNA_MESSAGE_SIZE];
+
+       aen = bna_is_aen(mb_rsp->mh.msg_id);
+
+       if (!aen) {
+               mb_qe = bfa_q_first(&bna->mbox_mod.posted_q);
+               cmd_h = (struct bfi_mhdr *)(&mb_qe->cmd.msg[0]);
+               rsp_h = (struct bfi_mhdr *)(&mb_rsp->mh);
+
+               if ((BFA_I2HM(cmd_h->msg_id) == rsp_h->msg_id) &&
+                   (cmd_h->mtag.i2htok == rsp_h->mtag.i2htok)) {
+                       /* Remove the request from posted_q, update state  */
+                       list_del(&mb_qe->qe);
+                       bna->mbox_mod.msg_pending--;
+                       if (list_empty(&bna->mbox_mod.posted_q))
+                               bna->mbox_mod.state = BNA_MBOX_FREE;
+                       else
+                               to_post = 1;
+
+                       /* Dispatch the cbfn */
+                       if (mb_qe->cbfn)
+                               mb_qe->cbfn(mb_qe->cbarg, mb_rsp->error);
+
+                       /* Post the next entry, if needed */
+                       if (to_post) {
+                               mb_qe = bfa_q_first(&bna->mbox_mod.posted_q);
+                               bfa_nw_ioc_mbox_queue(&bna->device.ioc,
+                                                       &mb_qe->cmd);
+                       }
+               } else {
+                       snprintf(message, BNA_MESSAGE_SIZE,
+                                      "No matching rsp for [%d:%d:%d]\n",
+                                      mb_rsp->mh.msg_class, mb_rsp->mh.msg_id,
+                                      mb_rsp->mh.mtag.i2htok);
+               pr_info("%s", message);
+               }
+
+       } else
+               bna_mbox_aen_callback(bna, msg);
+}
+
+void
+bna_err_handler(struct bna *bna, u32 intr_status)
+{
+       u32 init_halt;
+
+       if (intr_status & __HALT_STATUS_BITS) {
+               init_halt = readl(bna->device.ioc.ioc_regs.ll_halt);
+               init_halt &= ~__FW_INIT_HALT_P;
+               writel(init_halt, bna->device.ioc.ioc_regs.ll_halt);
+       }
+
+       bfa_nw_ioc_error_isr(&bna->device.ioc);
+}
+
+void
+bna_mbox_handler(struct bna *bna, u32 intr_status)
+{
+       if (BNA_IS_ERR_INTR(intr_status)) {
+               bna_err_handler(bna, intr_status);
+               return;
+       }
+       if (BNA_IS_MBOX_INTR(intr_status))
+               bfa_nw_ioc_mbox_isr(&bna->device.ioc);
+}
+
+void
+bna_mbox_send(struct bna *bna, struct bna_mbox_qe *mbox_qe)
+{
+       struct bfi_mhdr *mh;
+
+       mh = (struct bfi_mhdr *)(&mbox_qe->cmd.msg[0]);
+
+       mh->mtag.i2htok = htons(bna->mbox_mod.msg_ctr);
+       bna->mbox_mod.msg_ctr++;
+       bna->mbox_mod.msg_pending++;
+       if (bna->mbox_mod.state == BNA_MBOX_FREE) {
+               list_add_tail(&mbox_qe->qe, &bna->mbox_mod.posted_q);
+               bfa_nw_ioc_mbox_queue(&bna->device.ioc, &mbox_qe->cmd);
+               bna->mbox_mod.state = BNA_MBOX_POSTED;
+       } else {
+               list_add_tail(&mbox_qe->qe, &bna->mbox_mod.posted_q);
+       }
+}
+
+void
+bna_mbox_flush_q(struct bna *bna, struct list_head *q)
+{
+       struct bna_mbox_qe *mb_qe = NULL;
+       struct bfi_mhdr *cmd_h;
+       struct list_head                        *mb_q;
+       void                    (*cbfn)(void *arg, int status);
+       void                    *cbarg;
+
+       mb_q = &bna->mbox_mod.posted_q;
+
+       while (!list_empty(mb_q)) {
+               bfa_q_deq(mb_q, &mb_qe);
+               cbfn = mb_qe->cbfn;
+               cbarg = mb_qe->cbarg;
+               bfa_q_qe_init(mb_qe);
+               bna->mbox_mod.msg_pending--;
+
+               cmd_h = (struct bfi_mhdr *)(&mb_qe->cmd.msg[0]);
+               if (cbfn)
+                       cbfn(cbarg, BNA_CB_NOT_EXEC);
+       }
+
+       bna->mbox_mod.state = BNA_MBOX_FREE;
+}
+
+void
+bna_mbox_mod_start(struct bna_mbox_mod *mbox_mod)
+{
+}
+
+void
+bna_mbox_mod_stop(struct bna_mbox_mod *mbox_mod)
+{
+       bna_mbox_flush_q(mbox_mod->bna, &mbox_mod->posted_q);
+}
+
+void
+bna_mbox_mod_init(struct bna_mbox_mod *mbox_mod, struct bna *bna)
+{
+       bfa_nw_ioc_mbox_regisr(&bna->device.ioc, BFI_MC_LL, bna_ll_isr, bna);
+       mbox_mod->state = BNA_MBOX_FREE;
+       mbox_mod->msg_ctr = mbox_mod->msg_pending = 0;
+       INIT_LIST_HEAD(&mbox_mod->posted_q);
+       mbox_mod->bna = bna;
+}
+
+void
+bna_mbox_mod_uninit(struct bna_mbox_mod *mbox_mod)
+{
+       mbox_mod->bna = NULL;
+}
+
+/**
+ * LLPORT
+ */
+#define call_llport_stop_cbfn(llport, status)\
+do {\
+       if ((llport)->stop_cbfn)\
+               (llport)->stop_cbfn(&(llport)->bna->port, status);\
+       (llport)->stop_cbfn = NULL;\
+} while (0)
+
+static void bna_fw_llport_up(struct bna_llport *llport);
+static void bna_fw_cb_llport_up(void *arg, int status);
+static void bna_fw_llport_down(struct bna_llport *llport);
+static void bna_fw_cb_llport_down(void *arg, int status);
+static void bna_llport_start(struct bna_llport *llport);
+static void bna_llport_stop(struct bna_llport *llport);
+static void bna_llport_fail(struct bna_llport *llport);
+
+enum bna_llport_event {
+       LLPORT_E_START                  = 1,
+       LLPORT_E_STOP                   = 2,
+       LLPORT_E_FAIL                   = 3,
+       LLPORT_E_UP                     = 4,
+       LLPORT_E_DOWN                   = 5,
+       LLPORT_E_FWRESP_UP              = 6,
+       LLPORT_E_FWRESP_DOWN            = 7
+};
+
+enum bna_llport_state {
+       BNA_LLPORT_STOPPED              = 1,
+       BNA_LLPORT_DOWN                 = 2,
+       BNA_LLPORT_UP_RESP_WAIT         = 3,
+       BNA_LLPORT_DOWN_RESP_WAIT       = 4,
+       BNA_LLPORT_UP                   = 5,
+       BNA_LLPORT_LAST_RESP_WAIT       = 6
+};
+
+bfa_fsm_state_decl(bna_llport, stopped, struct bna_llport,
+                       enum bna_llport_event);
+bfa_fsm_state_decl(bna_llport, down, struct bna_llport,
+                       enum bna_llport_event);
+bfa_fsm_state_decl(bna_llport, up_resp_wait, struct bna_llport,
+                       enum bna_llport_event);
+bfa_fsm_state_decl(bna_llport, down_resp_wait, struct bna_llport,
+                       enum bna_llport_event);
+bfa_fsm_state_decl(bna_llport, up, struct bna_llport,
+                       enum bna_llport_event);
+bfa_fsm_state_decl(bna_llport, last_resp_wait, struct bna_llport,
+                       enum bna_llport_event);
+
+static struct bfa_sm_table llport_sm_table[] = {
+       {BFA_SM(bna_llport_sm_stopped), BNA_LLPORT_STOPPED},
+       {BFA_SM(bna_llport_sm_down), BNA_LLPORT_DOWN},
+       {BFA_SM(bna_llport_sm_up_resp_wait), BNA_LLPORT_UP_RESP_WAIT},
+       {BFA_SM(bna_llport_sm_down_resp_wait), BNA_LLPORT_DOWN_RESP_WAIT},
+       {BFA_SM(bna_llport_sm_up), BNA_LLPORT_UP},
+       {BFA_SM(bna_llport_sm_last_resp_wait), BNA_LLPORT_LAST_RESP_WAIT}
+};
+
+static void
+bna_llport_sm_stopped_entry(struct bna_llport *llport)
+{
+       llport->bna->port.link_cbfn((llport)->bna->bnad, BNA_LINK_DOWN);
+       call_llport_stop_cbfn(llport, BNA_CB_SUCCESS);
+}
+
+static void
+bna_llport_sm_stopped(struct bna_llport *llport,
+                       enum bna_llport_event event)
+{
+       switch (event) {
+       case LLPORT_E_START:
+               bfa_fsm_set_state(llport, bna_llport_sm_down);
+               break;
+
+       case LLPORT_E_STOP:
+               call_llport_stop_cbfn(llport, BNA_CB_SUCCESS);
+               break;
+
+       case LLPORT_E_FAIL:
+               break;
+
+       case LLPORT_E_DOWN:
+               /* This event is received due to Rx objects failing */
+               /* No-op */
+               break;
+
+       case LLPORT_E_FWRESP_UP:
+       case LLPORT_E_FWRESP_DOWN:
+               /**
+                * These events are received due to flushing of mbox when
+                * device fails
+                */
+               /* No-op */
+               break;
+
+       default:
+               bfa_sm_fault(llport->bna, event);
+       }
+}
+
+static void
+bna_llport_sm_down_entry(struct bna_llport *llport)
+{
+       bnad_cb_port_link_status((llport)->bna->bnad, BNA_LINK_DOWN);
+}
+
+static void
+bna_llport_sm_down(struct bna_llport *llport,
+                       enum bna_llport_event event)
+{
+       switch (event) {
+       case LLPORT_E_STOP:
+               bfa_fsm_set_state(llport, bna_llport_sm_stopped);
+               break;
+
+       case LLPORT_E_FAIL:
+               bfa_fsm_set_state(llport, bna_llport_sm_stopped);
+               break;
+
+       case LLPORT_E_UP:
+               bfa_fsm_set_state(llport, bna_llport_sm_up_resp_wait);
+               bna_fw_llport_up(llport);
+               break;
+
+       default:
+               bfa_sm_fault(llport->bna, event);
+       }
+}
+
+static void
+bna_llport_sm_up_resp_wait_entry(struct bna_llport *llport)
+{
+       /**
+        * NOTE: Do not call bna_fw_llport_up() here. That will over step
+        * mbox due to down_resp_wait -> up_resp_wait transition on event
+        * LLPORT_E_UP
+        */
+}
+
+static void
+bna_llport_sm_up_resp_wait(struct bna_llport *llport,
+                       enum bna_llport_event event)
+{
+       switch (event) {
+       case LLPORT_E_STOP:
+               bfa_fsm_set_state(llport, bna_llport_sm_last_resp_wait);
+               break;
+
+       case LLPORT_E_FAIL:
+               bfa_fsm_set_state(llport, bna_llport_sm_stopped);
+               break;
+
+       case LLPORT_E_DOWN:
+               bfa_fsm_set_state(llport, bna_llport_sm_down_resp_wait);
+               break;
+
+       case LLPORT_E_FWRESP_UP:
+               bfa_fsm_set_state(llport, bna_llport_sm_up);
+               break;
+
+       case LLPORT_E_FWRESP_DOWN:
+               /* down_resp_wait -> up_resp_wait transition on LLPORT_E_UP */
+               bna_fw_llport_up(llport);
+               break;
+
+       default:
+               bfa_sm_fault(llport->bna, event);
+       }
+}
+
+static void
+bna_llport_sm_down_resp_wait_entry(struct bna_llport *llport)
+{
+       /**
+        * NOTE: Do not call bna_fw_llport_down() here. That will over step
+        * mbox due to up_resp_wait -> down_resp_wait transition on event
+        * LLPORT_E_DOWN
+        */
+}
+
+static void
+bna_llport_sm_down_resp_wait(struct bna_llport *llport,
+                       enum bna_llport_event event)
+{
+       switch (event) {
+       case LLPORT_E_STOP:
+               bfa_fsm_set_state(llport, bna_llport_sm_last_resp_wait);
+               break;
+
+       case LLPORT_E_FAIL:
+               bfa_fsm_set_state(llport, bna_llport_sm_stopped);
+               break;
+
+       case LLPORT_E_UP:
+               bfa_fsm_set_state(llport, bna_llport_sm_up_resp_wait);
+               break;
+
+       case LLPORT_E_FWRESP_UP:
+               /* up_resp_wait->down_resp_wait transition on LLPORT_E_DOWN */
+               bna_fw_llport_down(llport);
+               break;
+
+       case LLPORT_E_FWRESP_DOWN:
+               bfa_fsm_set_state(llport, bna_llport_sm_down);
+               break;
+
+       default:
+               bfa_sm_fault(llport->bna, event);
+       }
+}
+
+static void
+bna_llport_sm_up_entry(struct bna_llport *llport)
+{
+}
+
+static void
+bna_llport_sm_up(struct bna_llport *llport,
+                       enum bna_llport_event event)
+{
+       switch (event) {
+       case LLPORT_E_STOP:
+               bfa_fsm_set_state(llport, bna_llport_sm_last_resp_wait);
+               bna_fw_llport_down(llport);
+               break;
+
+       case LLPORT_E_FAIL:
+               bfa_fsm_set_state(llport, bna_llport_sm_stopped);
+               break;
+
+       case LLPORT_E_DOWN:
+               bfa_fsm_set_state(llport, bna_llport_sm_down_resp_wait);
+               bna_fw_llport_down(llport);
+               break;
+
+       default:
+               bfa_sm_fault(llport->bna, event);
+       }
+}
+
+static void
+bna_llport_sm_last_resp_wait_entry(struct bna_llport *llport)
+{
+}
+
+static void
+bna_llport_sm_last_resp_wait(struct bna_llport *llport,
+                       enum bna_llport_event event)
+{
+       switch (event) {
+       case LLPORT_E_FAIL:
+               bfa_fsm_set_state(llport, bna_llport_sm_stopped);
+               break;
+
+       case LLPORT_E_DOWN:
+               /**
+                * This event is received due to Rx objects stopping in
+                * parallel to llport
+                */
+               /* No-op */
+               break;
+
+       case LLPORT_E_FWRESP_UP:
+               /* up_resp_wait->last_resp_wait transition on LLPORT_T_STOP */
+               bna_fw_llport_down(llport);
+               break;
+
+       case LLPORT_E_FWRESP_DOWN:
+               bfa_fsm_set_state(llport, bna_llport_sm_stopped);
+               break;
+
+       default:
+               bfa_sm_fault(llport->bna, event);
+       }
+}
+
+static void
+bna_fw_llport_admin_up(struct bna_llport *llport)
+{
+       struct bfi_ll_port_admin_req ll_req;
+
+       memset(&ll_req, 0, sizeof(ll_req));
+       ll_req.mh.msg_class = BFI_MC_LL;
+       ll_req.mh.msg_id = BFI_LL_H2I_PORT_ADMIN_REQ;
+       ll_req.mh.mtag.h2i.lpu_id = 0;
+
+       ll_req.up = BNA_STATUS_T_ENABLED;
+
+       bna_mbox_qe_fill(&llport->mbox_qe, &ll_req, sizeof(ll_req),
+                       bna_fw_cb_llport_up, llport);
+
+       bna_mbox_send(llport->bna, &llport->mbox_qe);
+}
+
+static void
+bna_fw_llport_up(struct bna_llport *llport)
+{
+       if (llport->type == BNA_PORT_T_REGULAR)
+               bna_fw_llport_admin_up(llport);
+}
+
+static void
+bna_fw_cb_llport_up(void *arg, int status)
+{
+       struct bna_llport *llport = (struct bna_llport *)arg;
+
+       bfa_q_qe_init(&llport->mbox_qe.qe);
+       bfa_fsm_send_event(llport, LLPORT_E_FWRESP_UP);
+}
+
+static void
+bna_fw_llport_admin_down(struct bna_llport *llport)
+{
+       struct bfi_ll_port_admin_req ll_req;
+
+       memset(&ll_req, 0, sizeof(ll_req));
+       ll_req.mh.msg_class = BFI_MC_LL;
+       ll_req.mh.msg_id = BFI_LL_H2I_PORT_ADMIN_REQ;
+       ll_req.mh.mtag.h2i.lpu_id = 0;
+
+       ll_req.up = BNA_STATUS_T_DISABLED;
+
+       bna_mbox_qe_fill(&llport->mbox_qe, &ll_req, sizeof(ll_req),
+                       bna_fw_cb_llport_down, llport);
+
+       bna_mbox_send(llport->bna, &llport->mbox_qe);
+}
+
+static void
+bna_fw_llport_down(struct bna_llport *llport)
+{
+       if (llport->type == BNA_PORT_T_REGULAR)
+               bna_fw_llport_admin_down(llport);
+}
+
+static void
+bna_fw_cb_llport_down(void *arg, int status)
+{
+       struct bna_llport *llport = (struct bna_llport *)arg;
+
+       bfa_q_qe_init(&llport->mbox_qe.qe);
+       bfa_fsm_send_event(llport, LLPORT_E_FWRESP_DOWN);
+}
+
+void
+bna_port_cb_llport_stopped(struct bna_port *port,
+                               enum bna_cb_status status)
+{
+       bfa_wc_down(&port->chld_stop_wc);
+}
+
+static void
+bna_llport_init(struct bna_llport *llport, struct bna *bna)
+{
+       llport->flags |= BNA_LLPORT_F_ENABLED;
+       llport->type = BNA_PORT_T_REGULAR;
+       llport->bna = bna;
+
+       llport->link_status = BNA_LINK_DOWN;
+
+       llport->admin_up_count = 0;
+
+       llport->stop_cbfn = NULL;
+
+       bfa_q_qe_init(&llport->mbox_qe.qe);
+
+       bfa_fsm_set_state(llport, bna_llport_sm_stopped);
+}
+
+static void
+bna_llport_uninit(struct bna_llport *llport)
+{
+       llport->flags &= ~BNA_LLPORT_F_ENABLED;
+
+       llport->bna = NULL;
+}
+
+static void
+bna_llport_start(struct bna_llport *llport)
+{
+       bfa_fsm_send_event(llport, LLPORT_E_START);
+}
+
+static void
+bna_llport_stop(struct bna_llport *llport)
+{
+       llport->stop_cbfn = bna_port_cb_llport_stopped;
+
+       bfa_fsm_send_event(llport, LLPORT_E_STOP);
+}
+
+static void
+bna_llport_fail(struct bna_llport *llport)
+{
+       bfa_fsm_send_event(llport, LLPORT_E_FAIL);
+}
+
+int
+bna_llport_state_get(struct bna_llport *llport)
+{
+       return bfa_sm_to_state(llport_sm_table, llport->fsm);
+}
+
+void
+bna_llport_admin_up(struct bna_llport *llport)
+{
+       llport->admin_up_count++;
+
+       if (llport->admin_up_count == 1) {
+               llport->flags |= BNA_LLPORT_F_RX_ENABLED;
+               if (llport->flags & BNA_LLPORT_F_ENABLED)
+                       bfa_fsm_send_event(llport, LLPORT_E_UP);
+       }
+}
+
+void
+bna_llport_admin_down(struct bna_llport *llport)
+{
+       llport->admin_up_count--;
+
+       if (llport->admin_up_count == 0) {
+               llport->flags &= ~BNA_LLPORT_F_RX_ENABLED;
+               if (llport->flags & BNA_LLPORT_F_ENABLED)
+                       bfa_fsm_send_event(llport, LLPORT_E_DOWN);
+       }
+}
+
+/**
+ * PORT
+ */
+#define bna_port_chld_start(port)\
+do {\
+       enum bna_tx_type tx_type = ((port)->type == BNA_PORT_T_REGULAR) ?\
+                                       BNA_TX_T_REGULAR : BNA_TX_T_LOOPBACK;\
+       enum bna_rx_type rx_type = ((port)->type == BNA_PORT_T_REGULAR) ?\
+                                       BNA_RX_T_REGULAR : BNA_RX_T_LOOPBACK;\
+       bna_llport_start(&(port)->llport);\
+       bna_tx_mod_start(&(port)->bna->tx_mod, tx_type);\
+       bna_rx_mod_start(&(port)->bna->rx_mod, rx_type);\
+} while (0)
+
+#define bna_port_chld_stop(port)\
+do {\
+       enum bna_tx_type tx_type = ((port)->type == BNA_PORT_T_REGULAR) ?\
+                                       BNA_TX_T_REGULAR : BNA_TX_T_LOOPBACK;\
+       enum bna_rx_type rx_type = ((port)->type == BNA_PORT_T_REGULAR) ?\
+                                       BNA_RX_T_REGULAR : BNA_RX_T_LOOPBACK;\
+       bfa_wc_up(&(port)->chld_stop_wc);\
+       bfa_wc_up(&(port)->chld_stop_wc);\
+       bfa_wc_up(&(port)->chld_stop_wc);\
+       bna_llport_stop(&(port)->llport);\
+       bna_tx_mod_stop(&(port)->bna->tx_mod, tx_type);\
+       bna_rx_mod_stop(&(port)->bna->rx_mod, rx_type);\
+} while (0)
+
+#define bna_port_chld_fail(port)\
+do {\
+       bna_llport_fail(&(port)->llport);\
+       bna_tx_mod_fail(&(port)->bna->tx_mod);\
+       bna_rx_mod_fail(&(port)->bna->rx_mod);\
+} while (0)
+
+#define bna_port_rx_start(port)\
+do {\
+       enum bna_rx_type rx_type = ((port)->type == BNA_PORT_T_REGULAR) ?\
+                                       BNA_RX_T_REGULAR : BNA_RX_T_LOOPBACK;\
+       bna_rx_mod_start(&(port)->bna->rx_mod, rx_type);\
+} while (0)
+
+#define bna_port_rx_stop(port)\
+do {\
+       enum bna_rx_type rx_type = ((port)->type == BNA_PORT_T_REGULAR) ?\
+                                       BNA_RX_T_REGULAR : BNA_RX_T_LOOPBACK;\
+       bfa_wc_up(&(port)->chld_stop_wc);\
+       bna_rx_mod_stop(&(port)->bna->rx_mod, rx_type);\
+} while (0)
+
+#define call_port_stop_cbfn(port, status)\
+do {\
+       if ((port)->stop_cbfn)\
+               (port)->stop_cbfn((port)->stop_cbarg, status);\
+       (port)->stop_cbfn = NULL;\
+       (port)->stop_cbarg = NULL;\
+} while (0)
+
+#define call_port_pause_cbfn(port, status)\
+do {\
+       if ((port)->pause_cbfn)\
+               (port)->pause_cbfn((port)->bna->bnad, status);\
+       (port)->pause_cbfn = NULL;\
+} while (0)
+
+#define call_port_mtu_cbfn(port, status)\
+do {\
+       if ((port)->mtu_cbfn)\
+               (port)->mtu_cbfn((port)->bna->bnad, status);\
+       (port)->mtu_cbfn = NULL;\
+} while (0)
+
+static void bna_fw_pause_set(struct bna_port *port);
+static void bna_fw_cb_pause_set(void *arg, int status);
+static void bna_fw_mtu_set(struct bna_port *port);
+static void bna_fw_cb_mtu_set(void *arg, int status);
+
+enum bna_port_event {
+       PORT_E_START                    = 1,
+       PORT_E_STOP                     = 2,
+       PORT_E_FAIL                     = 3,
+       PORT_E_PAUSE_CFG                = 4,
+       PORT_E_MTU_CFG                  = 5,
+       PORT_E_CHLD_STOPPED             = 6,
+       PORT_E_FWRESP_PAUSE             = 7,
+       PORT_E_FWRESP_MTU               = 8
+};
+
+enum bna_port_state {
+       BNA_PORT_STOPPED                = 1,
+       BNA_PORT_MTU_INIT_WAIT          = 2,
+       BNA_PORT_PAUSE_INIT_WAIT        = 3,
+       BNA_PORT_LAST_RESP_WAIT         = 4,
+       BNA_PORT_STARTED                = 5,
+       BNA_PORT_PAUSE_CFG_WAIT         = 6,
+       BNA_PORT_RX_STOP_WAIT           = 7,
+       BNA_PORT_MTU_CFG_WAIT           = 8,
+       BNA_PORT_CHLD_STOP_WAIT         = 9
+};
+
+bfa_fsm_state_decl(bna_port, stopped, struct bna_port,
+                       enum bna_port_event);
+bfa_fsm_state_decl(bna_port, mtu_init_wait, struct bna_port,
+                       enum bna_port_event);
+bfa_fsm_state_decl(bna_port, pause_init_wait, struct bna_port,
+                       enum bna_port_event);
+bfa_fsm_state_decl(bna_port, last_resp_wait, struct bna_port,
+                       enum bna_port_event);
+bfa_fsm_state_decl(bna_port, started, struct bna_port,
+                       enum bna_port_event);
+bfa_fsm_state_decl(bna_port, pause_cfg_wait, struct bna_port,
+                       enum bna_port_event);
+bfa_fsm_state_decl(bna_port, rx_stop_wait, struct bna_port,
+                       enum bna_port_event);
+bfa_fsm_state_decl(bna_port, mtu_cfg_wait, struct bna_port,
+                       enum bna_port_event);
+bfa_fsm_state_decl(bna_port, chld_stop_wait, struct bna_port,
+                       enum bna_port_event);
+
+static struct bfa_sm_table port_sm_table[] = {
+       {BFA_SM(bna_port_sm_stopped), BNA_PORT_STOPPED},
+       {BFA_SM(bna_port_sm_mtu_init_wait), BNA_PORT_MTU_INIT_WAIT},
+       {BFA_SM(bna_port_sm_pause_init_wait), BNA_PORT_PAUSE_INIT_WAIT},
+       {BFA_SM(bna_port_sm_last_resp_wait), BNA_PORT_LAST_RESP_WAIT},
+       {BFA_SM(bna_port_sm_started), BNA_PORT_STARTED},
+       {BFA_SM(bna_port_sm_pause_cfg_wait), BNA_PORT_PAUSE_CFG_WAIT},
+       {BFA_SM(bna_port_sm_rx_stop_wait), BNA_PORT_RX_STOP_WAIT},
+       {BFA_SM(bna_port_sm_mtu_cfg_wait), BNA_PORT_MTU_CFG_WAIT},
+       {BFA_SM(bna_port_sm_chld_stop_wait), BNA_PORT_CHLD_STOP_WAIT}
+};
+
+static void
+bna_port_sm_stopped_entry(struct bna_port *port)
+{
+       call_port_pause_cbfn(port, BNA_CB_SUCCESS);
+       call_port_mtu_cbfn(port, BNA_CB_SUCCESS);
+       call_port_stop_cbfn(port, BNA_CB_SUCCESS);
+}
+
+static void
+bna_port_sm_stopped(struct bna_port *port, enum bna_port_event event)
+{
+       switch (event) {
+       case PORT_E_START:
+               bfa_fsm_set_state(port, bna_port_sm_mtu_init_wait);
+               break;
+
+       case PORT_E_STOP:
+               call_port_stop_cbfn(port, BNA_CB_SUCCESS);
+               break;
+
+       case PORT_E_FAIL:
+               /* No-op */
+               break;
+
+       case PORT_E_PAUSE_CFG:
+               call_port_pause_cbfn(port, BNA_CB_SUCCESS);
+               break;
+
+       case PORT_E_MTU_CFG:
+               call_port_mtu_cbfn(port, BNA_CB_SUCCESS);
+               break;
+
+       case PORT_E_CHLD_STOPPED:
+               /**
+                * This event is received due to LLPort, Tx and Rx objects
+                * failing
+                */
+               /* No-op */
+               break;
+
+       case PORT_E_FWRESP_PAUSE:
+       case PORT_E_FWRESP_MTU:
+               /**
+                * These events are received due to flushing of mbox when
+                * device fails
+                */
+               /* No-op */
+               break;
+
+       default:
+               bfa_sm_fault(port->bna, event);
+       }
+}
+
+static void
+bna_port_sm_mtu_init_wait_entry(struct bna_port *port)
+{
+       bna_fw_mtu_set(port);
+}
+
+static void
+bna_port_sm_mtu_init_wait(struct bna_port *port, enum bna_port_event event)
+{
+       switch (event) {
+       case PORT_E_STOP:
+               bfa_fsm_set_state(port, bna_port_sm_last_resp_wait);
+               break;
+
+       case PORT_E_FAIL:
+               bfa_fsm_set_state(port, bna_port_sm_stopped);
+               break;
+
+       case PORT_E_PAUSE_CFG:
+               /* No-op */
+               break;
+
+       case PORT_E_MTU_CFG:
+               port->flags |= BNA_PORT_F_MTU_CHANGED;
+               break;
+
+       case PORT_E_FWRESP_MTU:
+               if (port->flags & BNA_PORT_F_MTU_CHANGED) {
+                       port->flags &= ~BNA_PORT_F_MTU_CHANGED;
+                       bna_fw_mtu_set(port);
+               } else {
+                       bfa_fsm_set_state(port, bna_port_sm_pause_init_wait);
+               }
+               break;
+
+       default:
+               bfa_sm_fault(port->bna, event);
+       }
+}
+
+static void
+bna_port_sm_pause_init_wait_entry(struct bna_port *port)
+{
+       bna_fw_pause_set(port);
+}
+
+static void
+bna_port_sm_pause_init_wait(struct bna_port *port,
+                               enum bna_port_event event)
+{
+       switch (event) {
+       case PORT_E_STOP:
+               bfa_fsm_set_state(port, bna_port_sm_last_resp_wait);
+               break;
+
+       case PORT_E_FAIL:
+               bfa_fsm_set_state(port, bna_port_sm_stopped);
+               break;
+
+       case PORT_E_PAUSE_CFG:
+               port->flags |= BNA_PORT_F_PAUSE_CHANGED;
+               break;
+
+       case PORT_E_MTU_CFG:
+               port->flags |= BNA_PORT_F_MTU_CHANGED;
+               break;
+
+       case PORT_E_FWRESP_PAUSE:
+               if (port->flags & BNA_PORT_F_PAUSE_CHANGED) {
+                       port->flags &= ~BNA_PORT_F_PAUSE_CHANGED;
+                       bna_fw_pause_set(port);
+               } else if (port->flags & BNA_PORT_F_MTU_CHANGED) {
+                       port->flags &= ~BNA_PORT_F_MTU_CHANGED;
+                       bfa_fsm_set_state(port, bna_port_sm_mtu_init_wait);
+               } else {
+                       bfa_fsm_set_state(port, bna_port_sm_started);
+                       bna_port_chld_start(port);
+               }
+               break;
+
+       default:
+               bfa_sm_fault(port->bna, event);
+       }
+}
+
+static void
+bna_port_sm_last_resp_wait_entry(struct bna_port *port)
+{
+}
+
+static void
+bna_port_sm_last_resp_wait(struct bna_port *port,
+                               enum bna_port_event event)
+{
+       switch (event) {
+       case PORT_E_FAIL:
+       case PORT_E_FWRESP_PAUSE:
+       case PORT_E_FWRESP_MTU:
+               bfa_fsm_set_state(port, bna_port_sm_stopped);
+               break;
+
+       default:
+               bfa_sm_fault(port->bna, event);
+       }
+}
+
+static void
+bna_port_sm_started_entry(struct bna_port *port)
+{
+       /**
+        * NOTE: Do not call bna_port_chld_start() here, since it will be
+        * inadvertently called during pause_cfg_wait->started transition
+        * as well
+        */
+       call_port_pause_cbfn(port, BNA_CB_SUCCESS);
+       call_port_mtu_cbfn(port, BNA_CB_SUCCESS);
+}
+
+static void
+bna_port_sm_started(struct bna_port *port,
+                       enum bna_port_event event)
+{
+       switch (event) {
+       case PORT_E_STOP:
+               bfa_fsm_set_state(port, bna_port_sm_chld_stop_wait);
+               break;
+
+       case PORT_E_FAIL:
+               bfa_fsm_set_state(port, bna_port_sm_stopped);
+               bna_port_chld_fail(port);
+               break;
+
+       case PORT_E_PAUSE_CFG:
+               bfa_fsm_set_state(port, bna_port_sm_pause_cfg_wait);
+               break;
+
+       case PORT_E_MTU_CFG:
+               bfa_fsm_set_state(port, bna_port_sm_rx_stop_wait);
+               break;
+
+       default:
+               bfa_sm_fault(port->bna, event);
+       }
+}
+
+static void
+bna_port_sm_pause_cfg_wait_entry(struct bna_port *port)
+{
+       bna_fw_pause_set(port);
+}
+
+static void
+bna_port_sm_pause_cfg_wait(struct bna_port *port,
+                               enum bna_port_event event)
+{
+       switch (event) {
+       case PORT_E_FAIL:
+               bfa_fsm_set_state(port, bna_port_sm_stopped);
+               bna_port_chld_fail(port);
+               break;
+
+       case PORT_E_FWRESP_PAUSE:
+               bfa_fsm_set_state(port, bna_port_sm_started);
+               break;
+
+       default:
+               bfa_sm_fault(port->bna, event);
+       }
+}
+
+static void
+bna_port_sm_rx_stop_wait_entry(struct bna_port *port)
+{
+       bna_port_rx_stop(port);
+}
+
+static void
+bna_port_sm_rx_stop_wait(struct bna_port *port,
+                               enum bna_port_event event)
+{
+       switch (event) {
+       case PORT_E_FAIL:
+               bfa_fsm_set_state(port, bna_port_sm_stopped);
+               bna_port_chld_fail(port);
+               break;
+
+       case PORT_E_CHLD_STOPPED:
+               bfa_fsm_set_state(port, bna_port_sm_mtu_cfg_wait);
+               break;
+
+       default:
+               bfa_sm_fault(port->bna, event);
+       }
+}
+
+static void
+bna_port_sm_mtu_cfg_wait_entry(struct bna_port *port)
+{
+       bna_fw_mtu_set(port);
+}
+
+static void
+bna_port_sm_mtu_cfg_wait(struct bna_port *port, enum bna_port_event event)
+{
+       switch (event) {
+       case PORT_E_FAIL:
+               bfa_fsm_set_state(port, bna_port_sm_stopped);
+               bna_port_chld_fail(port);
+               break;
+
+       case PORT_E_FWRESP_MTU:
+               bfa_fsm_set_state(port, bna_port_sm_started);
+               bna_port_rx_start(port);
+               break;
+
+       default:
+               bfa_sm_fault(port->bna, event);
+       }
+}
+
+static void
+bna_port_sm_chld_stop_wait_entry(struct bna_port *port)
+{
+       bna_port_chld_stop(port);
+}
+
+static void
+bna_port_sm_chld_stop_wait(struct bna_port *port,
+                               enum bna_port_event event)
+{
+       switch (event) {
+       case PORT_E_FAIL:
+               bfa_fsm_set_state(port, bna_port_sm_stopped);
+               bna_port_chld_fail(port);
+               break;
+
+       case PORT_E_CHLD_STOPPED:
+               bfa_fsm_set_state(port, bna_port_sm_stopped);
+               break;
+
+       default:
+               bfa_sm_fault(port->bna, event);
+       }
+}
+
+static void
+bna_fw_pause_set(struct bna_port *port)
+{
+       struct bfi_ll_set_pause_req ll_req;
+
+       memset(&ll_req, 0, sizeof(ll_req));
+       ll_req.mh.msg_class = BFI_MC_LL;
+       ll_req.mh.msg_id = BFI_LL_H2I_SET_PAUSE_REQ;
+       ll_req.mh.mtag.h2i.lpu_id = 0;
+
+       ll_req.tx_pause = port->pause_config.tx_pause;
+       ll_req.rx_pause = port->pause_config.rx_pause;
+
+       bna_mbox_qe_fill(&port->mbox_qe, &ll_req, sizeof(ll_req),
+                       bna_fw_cb_pause_set, port);
+
+       bna_mbox_send(port->bna, &port->mbox_qe);
+}
+
+static void
+bna_fw_cb_pause_set(void *arg, int status)
+{
+       struct bna_port *port = (struct bna_port *)arg;
+
+       bfa_q_qe_init(&port->mbox_qe.qe);
+       bfa_fsm_send_event(port, PORT_E_FWRESP_PAUSE);
+}
+
+void
+bna_fw_mtu_set(struct bna_port *port)
+{
+       struct bfi_ll_mtu_info_req ll_req;
+
+       bfi_h2i_set(ll_req.mh, BFI_MC_LL, BFI_LL_H2I_MTU_INFO_REQ, 0);
+       ll_req.mtu = htons((u16)port->mtu);
+
+       bna_mbox_qe_fill(&port->mbox_qe, &ll_req, sizeof(ll_req),
+                               bna_fw_cb_mtu_set, port);
+       bna_mbox_send(port->bna, &port->mbox_qe);
+}
+
+void
+bna_fw_cb_mtu_set(void *arg, int status)
+{
+       struct bna_port *port = (struct bna_port *)arg;
+
+       bfa_q_qe_init(&port->mbox_qe.qe);
+       bfa_fsm_send_event(port, PORT_E_FWRESP_MTU);
+}
+
+static void
+bna_port_cb_chld_stopped(void *arg)
+{
+       struct bna_port *port = (struct bna_port *)arg;
+
+       bfa_fsm_send_event(port, PORT_E_CHLD_STOPPED);
+}
+
+void
+bna_port_init(struct bna_port *port, struct bna *bna)
+{
+       port->bna = bna;
+       port->flags = 0;
+       port->mtu = 0;
+       port->type = BNA_PORT_T_REGULAR;
+
+       port->link_cbfn = bnad_cb_port_link_status;
+
+       port->chld_stop_wc.wc_resume = bna_port_cb_chld_stopped;
+       port->chld_stop_wc.wc_cbarg = port;
+       port->chld_stop_wc.wc_count = 0;
+
+       port->stop_cbfn = NULL;
+       port->stop_cbarg = NULL;
+
+       port->pause_cbfn = NULL;
+
+       port->mtu_cbfn = NULL;
+
+       bfa_q_qe_init(&port->mbox_qe.qe);
+
+       bfa_fsm_set_state(port, bna_port_sm_stopped);
+
+       bna_llport_init(&port->llport, bna);
+}
+
+void
+bna_port_uninit(struct bna_port *port)
+{
+       bna_llport_uninit(&port->llport);
+
+       port->flags = 0;
+
+       port->bna = NULL;
+}
+
+int
+bna_port_state_get(struct bna_port *port)
+{
+       return bfa_sm_to_state(port_sm_table, port->fsm);
+}
+
+void
+bna_port_start(struct bna_port *port)
+{
+       port->flags |= BNA_PORT_F_DEVICE_READY;
+       if (port->flags & BNA_PORT_F_ENABLED)
+               bfa_fsm_send_event(port, PORT_E_START);
+}
+
+void
+bna_port_stop(struct bna_port *port)
+{
+       port->stop_cbfn = bna_device_cb_port_stopped;
+       port->stop_cbarg = &port->bna->device;
+
+       port->flags &= ~BNA_PORT_F_DEVICE_READY;
+       bfa_fsm_send_event(port, PORT_E_STOP);
+}
+
+void
+bna_port_fail(struct bna_port *port)
+{
+       port->flags &= ~BNA_PORT_F_DEVICE_READY;
+       bfa_fsm_send_event(port, PORT_E_FAIL);
+}
+
+void
+bna_port_cb_tx_stopped(struct bna_port *port, enum bna_cb_status status)
+{
+       bfa_wc_down(&port->chld_stop_wc);
+}
+
+void
+bna_port_cb_rx_stopped(struct bna_port *port, enum bna_cb_status status)
+{
+       bfa_wc_down(&port->chld_stop_wc);
+}
+
+void
+bna_port_cb_link_up(struct bna_port *port, struct bfi_ll_aen *aen,
+                       int status)
+{
+       int i;
+       u8 prio_map;
+
+       port->llport.link_status = BNA_LINK_UP;
+       if (aen->cee_linkup)
+               port->llport.link_status = BNA_CEE_UP;
+
+       /* Compute the priority */
+       prio_map = aen->prio_map;
+       if (prio_map) {
+               for (i = 0; i < 8; i++) {
+                       if ((prio_map >> i) & 0x1)
+                               break;
+               }
+               port->priority = i;
+       } else
+               port->priority = 0;
+
+       /* Dispatch events */
+       bna_tx_mod_cee_link_status(&port->bna->tx_mod, aen->cee_linkup);
+       bna_tx_mod_prio_changed(&port->bna->tx_mod, port->priority);
+       port->link_cbfn(port->bna->bnad, port->llport.link_status);
+}
+
+void
+bna_port_cb_link_down(struct bna_port *port, int status)
+{
+       port->llport.link_status = BNA_LINK_DOWN;
+
+       /* Dispatch events */
+       bna_tx_mod_cee_link_status(&port->bna->tx_mod, BNA_LINK_DOWN);
+       port->link_cbfn(port->bna->bnad, BNA_LINK_DOWN);
+}
+
+int
+bna_port_mtu_get(struct bna_port *port)
+{
+       return port->mtu;
+}
+
+void
+bna_port_enable(struct bna_port *port)
+{
+       if (port->fsm != (bfa_sm_t)bna_port_sm_stopped)
+               return;
+
+       port->flags |= BNA_PORT_F_ENABLED;
+
+       if (port->flags & BNA_PORT_F_DEVICE_READY)
+               bfa_fsm_send_event(port, PORT_E_START);
+}
+
+void
+bna_port_disable(struct bna_port *port, enum bna_cleanup_type type,
+                void (*cbfn)(void *, enum bna_cb_status))
+{
+       if (type == BNA_SOFT_CLEANUP) {
+               (*cbfn)(port->bna->bnad, BNA_CB_SUCCESS);
+               return;
+       }
+
+       port->stop_cbfn = cbfn;
+       port->stop_cbarg = port->bna->bnad;
+
+       port->flags &= ~BNA_PORT_F_ENABLED;
+
+       bfa_fsm_send_event(port, PORT_E_STOP);
+}
+
+void
+bna_port_pause_config(struct bna_port *port,
+                     struct bna_pause_config *pause_config,
+                     void (*cbfn)(struct bnad *, enum bna_cb_status))
+{
+       port->pause_config = *pause_config;
+
+       port->pause_cbfn = cbfn;
+
+       bfa_fsm_send_event(port, PORT_E_PAUSE_CFG);
+}
+
+void
+bna_port_mtu_set(struct bna_port *port, int mtu,
+                void (*cbfn)(struct bnad *, enum bna_cb_status))
+{
+       port->mtu = mtu;
+
+       port->mtu_cbfn = cbfn;
+
+       bfa_fsm_send_event(port, PORT_E_MTU_CFG);
+}
+
+void
+bna_port_mac_get(struct bna_port *port, mac_t *mac)
+{
+       *mac = bfa_nw_ioc_get_mac(&port->bna->device.ioc);
+}
+
+/**
+ * Should be called only when port is disabled
+ */
+void
+bna_port_type_set(struct bna_port *port, enum bna_port_type type)
+{
+       port->type = type;
+       port->llport.type = type;
+}
+
+/**
+ * Should be called only when port is disabled
+ */
+void
+bna_port_linkcbfn_set(struct bna_port *port,
+                     void (*linkcbfn)(struct bnad *, enum bna_link_status))
+{
+       port->link_cbfn = linkcbfn;
+}
+
+void
+bna_port_admin_up(struct bna_port *port)
+{
+       struct bna_llport *llport = &port->llport;
+
+       if (llport->flags & BNA_LLPORT_F_ENABLED)
+               return;
+
+       llport->flags |= BNA_LLPORT_F_ENABLED;
+
+       if (llport->flags & BNA_LLPORT_F_RX_ENABLED)
+               bfa_fsm_send_event(llport, LLPORT_E_UP);
+}
+
+void
+bna_port_admin_down(struct bna_port *port)
+{
+       struct bna_llport *llport = &port->llport;
+
+       if (!(llport->flags & BNA_LLPORT_F_ENABLED))
+               return;
+
+       llport->flags &= ~BNA_LLPORT_F_ENABLED;
+
+       if (llport->flags & BNA_LLPORT_F_RX_ENABLED)
+               bfa_fsm_send_event(llport, LLPORT_E_DOWN);
+}
+
+/**
+ * DEVICE
+ */
+#define enable_mbox_intr(_device)\
+do {\
+       u32 intr_status;\
+       bna_intr_status_get((_device)->bna, intr_status);\
+       bnad_cb_device_enable_mbox_intr((_device)->bna->bnad);\
+       bna_mbox_intr_enable((_device)->bna);\
+} while (0)
+
+#define disable_mbox_intr(_device)\
+do {\
+       bna_mbox_intr_disable((_device)->bna);\
+       bnad_cb_device_disable_mbox_intr((_device)->bna->bnad);\
+} while (0)
+
+const struct bna_chip_regs_offset reg_offset[] =
+{{HOST_PAGE_NUM_FN0, HOSTFN0_INT_STATUS,
+       HOSTFN0_INT_MASK, HOST_MSIX_ERR_INDEX_FN0},
+{HOST_PAGE_NUM_FN1, HOSTFN1_INT_STATUS,
+       HOSTFN1_INT_MASK, HOST_MSIX_ERR_INDEX_FN1},
+{HOST_PAGE_NUM_FN2, HOSTFN2_INT_STATUS,
+       HOSTFN2_INT_MASK, HOST_MSIX_ERR_INDEX_FN2},
+{HOST_PAGE_NUM_FN3, HOSTFN3_INT_STATUS,
+       HOSTFN3_INT_MASK, HOST_MSIX_ERR_INDEX_FN3},
+};
+
+enum bna_device_event {
+       DEVICE_E_ENABLE                 = 1,
+       DEVICE_E_DISABLE                = 2,
+       DEVICE_E_IOC_READY              = 3,
+       DEVICE_E_IOC_FAILED             = 4,
+       DEVICE_E_IOC_DISABLED           = 5,
+       DEVICE_E_IOC_RESET              = 6,
+       DEVICE_E_PORT_STOPPED           = 7,
+};
+
+enum bna_device_state {
+       BNA_DEVICE_STOPPED              = 1,
+       BNA_DEVICE_IOC_READY_WAIT       = 2,
+       BNA_DEVICE_READY                = 3,
+       BNA_DEVICE_PORT_STOP_WAIT       = 4,
+       BNA_DEVICE_IOC_DISABLE_WAIT     = 5,
+       BNA_DEVICE_FAILED               = 6
+};
+
+bfa_fsm_state_decl(bna_device, stopped, struct bna_device,
+                       enum bna_device_event);
+bfa_fsm_state_decl(bna_device, ioc_ready_wait, struct bna_device,
+                       enum bna_device_event);
+bfa_fsm_state_decl(bna_device, ready, struct bna_device,
+                       enum bna_device_event);
+bfa_fsm_state_decl(bna_device, port_stop_wait, struct bna_device,
+                       enum bna_device_event);
+bfa_fsm_state_decl(bna_device, ioc_disable_wait, struct bna_device,
+                       enum bna_device_event);
+bfa_fsm_state_decl(bna_device, failed, struct bna_device,
+                       enum bna_device_event);
+
+static struct bfa_sm_table device_sm_table[] = {
+       {BFA_SM(bna_device_sm_stopped), BNA_DEVICE_STOPPED},
+       {BFA_SM(bna_device_sm_ioc_ready_wait), BNA_DEVICE_IOC_READY_WAIT},
+       {BFA_SM(bna_device_sm_ready), BNA_DEVICE_READY},
+       {BFA_SM(bna_device_sm_port_stop_wait), BNA_DEVICE_PORT_STOP_WAIT},
+       {BFA_SM(bna_device_sm_ioc_disable_wait), BNA_DEVICE_IOC_DISABLE_WAIT},
+       {BFA_SM(bna_device_sm_failed), BNA_DEVICE_FAILED},
+};
+
+static void
+bna_device_sm_stopped_entry(struct bna_device *device)
+{
+       if (device->stop_cbfn)
+               device->stop_cbfn(device->stop_cbarg, BNA_CB_SUCCESS);
+
+       device->stop_cbfn = NULL;
+       device->stop_cbarg = NULL;
+}
+
+static void
+bna_device_sm_stopped(struct bna_device *device,
+                       enum bna_device_event event)
+{
+       switch (event) {
+       case DEVICE_E_ENABLE:
+               if (device->intr_type == BNA_INTR_T_MSIX)
+                       bna_mbox_msix_idx_set(device);
+               bfa_nw_ioc_enable(&device->ioc);
+               bfa_fsm_set_state(device, bna_device_sm_ioc_ready_wait);
+               break;
+
+       case DEVICE_E_DISABLE:
+               bfa_fsm_set_state(device, bna_device_sm_stopped);
+               break;
+
+       case DEVICE_E_IOC_RESET:
+               enable_mbox_intr(device);
+               break;
+
+       case DEVICE_E_IOC_FAILED:
+               bfa_fsm_set_state(device, bna_device_sm_failed);
+               break;
+
+       default:
+               bfa_sm_fault(device->bna, event);
+       }
+}
+
+static void
+bna_device_sm_ioc_ready_wait_entry(struct bna_device *device)
+{
+       /**
+        * Do not call bfa_ioc_enable() here. It must be called in the
+        * previous state due to failed -> ioc_ready_wait transition.
+        */
+}
+
+static void
+bna_device_sm_ioc_ready_wait(struct bna_device *device,
+                               enum bna_device_event event)
+{
+       switch (event) {
+       case DEVICE_E_DISABLE:
+               if (device->ready_cbfn)
+                       device->ready_cbfn(device->ready_cbarg,
+                                               BNA_CB_INTERRUPT);
+               device->ready_cbfn = NULL;
+               device->ready_cbarg = NULL;
+               bfa_fsm_set_state(device, bna_device_sm_ioc_disable_wait);
+               break;
+
+       case DEVICE_E_IOC_READY:
+               bfa_fsm_set_state(device, bna_device_sm_ready);
+               break;
+
+       case DEVICE_E_IOC_FAILED:
+               bfa_fsm_set_state(device, bna_device_sm_failed);
+               break;
+
+       case DEVICE_E_IOC_RESET:
+               enable_mbox_intr(device);
+               break;
+
+       default:
+               bfa_sm_fault(device->bna, event);
+       }
+}
+
+static void
+bna_device_sm_ready_entry(struct bna_device *device)
+{
+       bna_mbox_mod_start(&device->bna->mbox_mod);
+       bna_port_start(&device->bna->port);
+
+       if (device->ready_cbfn)
+               device->ready_cbfn(device->ready_cbarg,
+                                       BNA_CB_SUCCESS);
+       device->ready_cbfn = NULL;
+       device->ready_cbarg = NULL;
+}
+
+static void
+bna_device_sm_ready(struct bna_device *device, enum bna_device_event event)
+{
+       switch (event) {
+       case DEVICE_E_DISABLE:
+               bfa_fsm_set_state(device, bna_device_sm_port_stop_wait);
+               break;
+
+       case DEVICE_E_IOC_FAILED:
+               bfa_fsm_set_state(device, bna_device_sm_failed);
+               break;
+
+       default:
+               bfa_sm_fault(device->bna, event);
+       }
+}
+
+static void
+bna_device_sm_port_stop_wait_entry(struct bna_device *device)
+{
+       bna_port_stop(&device->bna->port);
+}
+
+static void
+bna_device_sm_port_stop_wait(struct bna_device *device,
+                               enum bna_device_event event)
+{
+       switch (event) {
+       case DEVICE_E_PORT_STOPPED:
+               bna_mbox_mod_stop(&device->bna->mbox_mod);
+               bfa_fsm_set_state(device, bna_device_sm_ioc_disable_wait);
+               break;
+
+       case DEVICE_E_IOC_FAILED:
+               disable_mbox_intr(device);
+               bna_port_fail(&device->bna->port);
+               break;
+
+       default:
+               bfa_sm_fault(device->bna, event);
+       }
+}
+
+static void
+bna_device_sm_ioc_disable_wait_entry(struct bna_device *device)
+{
+       bfa_nw_ioc_disable(&device->ioc);
+}
+
+static void
+bna_device_sm_ioc_disable_wait(struct bna_device *device,
+                               enum bna_device_event event)
+{
+       switch (event) {
+       case DEVICE_E_IOC_DISABLED:
+               disable_mbox_intr(device);
+               bfa_fsm_set_state(device, bna_device_sm_stopped);
+               break;
+
+       default:
+               bfa_sm_fault(device->bna, event);
+       }
+}
+
+static void
+bna_device_sm_failed_entry(struct bna_device *device)
+{
+       disable_mbox_intr(device);
+       bna_port_fail(&device->bna->port);
+       bna_mbox_mod_stop(&device->bna->mbox_mod);
+
+       if (device->ready_cbfn)
+               device->ready_cbfn(device->ready_cbarg,
+                                       BNA_CB_FAIL);
+       device->ready_cbfn = NULL;
+       device->ready_cbarg = NULL;
+}
+
+static void
+bna_device_sm_failed(struct bna_device *device,
+                       enum bna_device_event event)
+{
+       switch (event) {
+       case DEVICE_E_DISABLE:
+               bfa_fsm_set_state(device, bna_device_sm_ioc_disable_wait);
+               break;
+
+       case DEVICE_E_IOC_RESET:
+               enable_mbox_intr(device);
+               bfa_fsm_set_state(device, bna_device_sm_ioc_ready_wait);
+               break;
+
+       default:
+               bfa_sm_fault(device->bna, event);
+       }
+}
+
+/* IOC callback functions */
+
+static void
+bna_device_cb_iocll_ready(void *dev, enum bfa_status error)
+{
+       struct bna_device *device = (struct bna_device *)dev;
+
+       if (error)
+               bfa_fsm_send_event(device, DEVICE_E_IOC_FAILED);
+       else
+               bfa_fsm_send_event(device, DEVICE_E_IOC_READY);
+}
+
+static void
+bna_device_cb_iocll_disabled(void *dev)
+{
+       struct bna_device *device = (struct bna_device *)dev;
+
+       bfa_fsm_send_event(device, DEVICE_E_IOC_DISABLED);
+}
+
+static void
+bna_device_cb_iocll_failed(void *dev)
+{
+       struct bna_device *device = (struct bna_device *)dev;
+
+       bfa_fsm_send_event(device, DEVICE_E_IOC_FAILED);
+}
+
+static void
+bna_device_cb_iocll_reset(void *dev)
+{
+       struct bna_device *device = (struct bna_device *)dev;
+
+       bfa_fsm_send_event(device, DEVICE_E_IOC_RESET);
+}
+
+static struct bfa_ioc_cbfn bfa_iocll_cbfn = {
+       bna_device_cb_iocll_ready,
+       bna_device_cb_iocll_disabled,
+       bna_device_cb_iocll_failed,
+       bna_device_cb_iocll_reset
+};
+
+void
+bna_device_init(struct bna_device *device, struct bna *bna,
+               struct bna_res_info *res_info)
+{
+       u64 dma;
+
+       device->bna = bna;
+
+       /**
+        * Attach IOC and claim:
+        *      1. DMA memory for IOC attributes
+        *      2. Kernel memory for FW trace
+        */
+       bfa_nw_ioc_attach(&device->ioc, device, &bfa_iocll_cbfn);
+       bfa_nw_ioc_pci_init(&device->ioc, &bna->pcidev, BFI_MC_LL);
+
+       BNA_GET_DMA_ADDR(
+               &res_info[BNA_RES_MEM_T_ATTR].res_u.mem_info.mdl[0].dma, dma);
+       bfa_nw_ioc_mem_claim(&device->ioc,
+               res_info[BNA_RES_MEM_T_ATTR].res_u.mem_info.mdl[0].kva,
+                         dma);
+
+       bna_adv_device_init(device, bna, res_info);
+       /*
+        * Initialize mbox_mod only after IOC, so that mbox handler
+        * registration goes through
+        */
+       device->intr_type =
+               res_info[BNA_RES_INTR_T_MBOX].res_u.intr_info.intr_type;
+       device->vector =
+               res_info[BNA_RES_INTR_T_MBOX].res_u.intr_info.idl[0].vector;
+       bna_mbox_mod_init(&bna->mbox_mod, bna);
+
+       device->ready_cbfn = device->stop_cbfn = NULL;
+       device->ready_cbarg = device->stop_cbarg = NULL;
+
+       bfa_fsm_set_state(device, bna_device_sm_stopped);
+}
+
+void
+bna_device_uninit(struct bna_device *device)
+{
+       bna_mbox_mod_uninit(&device->bna->mbox_mod);
+
+       bfa_nw_ioc_detach(&device->ioc);
+
+       device->bna = NULL;
+}
+
+void
+bna_device_cb_port_stopped(void *arg, enum bna_cb_status status)
+{
+       struct bna_device *device = (struct bna_device *)arg;
+
+       bfa_fsm_send_event(device, DEVICE_E_PORT_STOPPED);
+}
+
+int
+bna_device_status_get(struct bna_device *device)
+{
+       return (device->fsm == (bfa_fsm_t)bna_device_sm_ready);
+}
+
+void
+bna_device_enable(struct bna_device *device)
+{
+       if (device->fsm != (bfa_fsm_t)bna_device_sm_stopped) {
+               bnad_cb_device_enabled(device->bna->bnad, BNA_CB_BUSY);
+               return;
+       }
+
+       device->ready_cbfn = bnad_cb_device_enabled;
+       device->ready_cbarg = device->bna->bnad;
+
+       bfa_fsm_send_event(device, DEVICE_E_ENABLE);
+}
+
+void
+bna_device_disable(struct bna_device *device, enum bna_cleanup_type type)
+{
+       if (type == BNA_SOFT_CLEANUP) {
+               bnad_cb_device_disabled(device->bna->bnad, BNA_CB_SUCCESS);
+               return;
+       }
+
+       device->stop_cbfn = bnad_cb_device_disabled;
+       device->stop_cbarg = device->bna->bnad;
+
+       bfa_fsm_send_event(device, DEVICE_E_DISABLE);
+}
+
+int
+bna_device_state_get(struct bna_device *device)
+{
+       return bfa_sm_to_state(device_sm_table, device->fsm);
+}
+
+u32 bna_dim_vector[BNA_LOAD_T_MAX][BNA_BIAS_T_MAX] = {
+       {12, 20},
+       {10, 18},
+       {8, 16},
+       {6, 12},
+       {4, 8},
+       {3, 6},
+       {2, 4},
+       {1, 2},
+};
+
+u32 bna_napi_dim_vector[BNA_LOAD_T_MAX][BNA_BIAS_T_MAX] = {
+       {12, 12},
+       {6, 10},
+       {5, 10},
+       {4, 8},
+       {3, 6},
+       {3, 6},
+       {2, 4},
+       {1, 2},
+};
+
+/* device */
+void
+bna_adv_device_init(struct bna_device *device, struct bna *bna,
+               struct bna_res_info *res_info)
+{
+       u8 *kva;
+       u64 dma;
+
+       device->bna = bna;
+
+       kva = res_info[BNA_RES_MEM_T_FWTRC].res_u.mem_info.mdl[0].kva;
+
+       /**
+        * Attach common modules (Diag, SFP, CEE, Port) and claim respective
+        * DMA memory.
+        */
+       BNA_GET_DMA_ADDR(
+               &res_info[BNA_RES_MEM_T_COM].res_u.mem_info.mdl[0].dma, dma);
+       kva = res_info[BNA_RES_MEM_T_COM].res_u.mem_info.mdl[0].kva;
+
+       bfa_nw_cee_attach(&bna->cee, &device->ioc, bna);
+       bfa_nw_cee_mem_claim(&bna->cee, kva, dma);
+       kva += bfa_nw_cee_meminfo();
+       dma += bfa_nw_cee_meminfo();
+
+}
+
+/* utils */
+
+void
+bna_adv_res_req(struct bna_res_info *res_info)
+{
+       /* DMA memory for COMMON_MODULE */
+       res_info[BNA_RES_MEM_T_COM].res_type = BNA_RES_T_MEM;
+       res_info[BNA_RES_MEM_T_COM].res_u.mem_info.mem_type = BNA_MEM_T_DMA;
+       res_info[BNA_RES_MEM_T_COM].res_u.mem_info.num = 1;
+       res_info[BNA_RES_MEM_T_COM].res_u.mem_info.len = ALIGN(
+                               bfa_nw_cee_meminfo(), PAGE_SIZE);
+
+       /* Virtual memory for retreiving fw_trc */
+       res_info[BNA_RES_MEM_T_FWTRC].res_type = BNA_RES_T_MEM;
+       res_info[BNA_RES_MEM_T_FWTRC].res_u.mem_info.mem_type = BNA_MEM_T_KVA;
+       res_info[BNA_RES_MEM_T_FWTRC].res_u.mem_info.num = 0;
+       res_info[BNA_RES_MEM_T_FWTRC].res_u.mem_info.len = 0;
+
+       /* DMA memory for retreiving stats */
+       res_info[BNA_RES_MEM_T_STATS].res_type = BNA_RES_T_MEM;
+       res_info[BNA_RES_MEM_T_STATS].res_u.mem_info.mem_type = BNA_MEM_T_DMA;
+       res_info[BNA_RES_MEM_T_STATS].res_u.mem_info.num = 1;
+       res_info[BNA_RES_MEM_T_STATS].res_u.mem_info.len =
+                               ALIGN(BFI_HW_STATS_SIZE, PAGE_SIZE);
+
+       /* Virtual memory for soft stats */
+       res_info[BNA_RES_MEM_T_SWSTATS].res_type = BNA_RES_T_MEM;
+       res_info[BNA_RES_MEM_T_SWSTATS].res_u.mem_info.mem_type = BNA_MEM_T_KVA;
+       res_info[BNA_RES_MEM_T_SWSTATS].res_u.mem_info.num = 1;
+       res_info[BNA_RES_MEM_T_SWSTATS].res_u.mem_info.len =
+                               sizeof(struct bna_sw_stats);
+}
+
+static void
+bna_sw_stats_get(struct bna *bna, struct bna_sw_stats *sw_stats)
+{
+       struct bna_tx *tx;
+       struct bna_txq *txq;
+       struct bna_rx *rx;
+       struct bna_rxp *rxp;
+       struct list_head *qe;
+       struct list_head *txq_qe;
+       struct list_head *rxp_qe;
+       struct list_head *mac_qe;
+       int i;
+
+       sw_stats->device_state = bna_device_state_get(&bna->device);
+       sw_stats->port_state = bna_port_state_get(&bna->port);
+       sw_stats->port_flags = bna->port.flags;
+       sw_stats->llport_state = bna_llport_state_get(&bna->port.llport);
+       sw_stats->priority = bna->port.priority;
+
+       i = 0;
+       list_for_each(qe, &bna->tx_mod.tx_active_q) {
+               tx = (struct bna_tx *)qe;
+               sw_stats->tx_stats[i].tx_state = bna_tx_state_get(tx);
+               sw_stats->tx_stats[i].tx_flags = tx->flags;
+
+               sw_stats->tx_stats[i].num_txqs = 0;
+               sw_stats->tx_stats[i].txq_bmap[0] = 0;
+               sw_stats->tx_stats[i].txq_bmap[1] = 0;
+               list_for_each(txq_qe, &tx->txq_q) {
+                       txq = (struct bna_txq *)txq_qe;
+                       if (txq->txq_id < 32)
+                               sw_stats->tx_stats[i].txq_bmap[0] |=
+                                               ((u32)1 << txq->txq_id);
+                       else
+                               sw_stats->tx_stats[i].txq_bmap[1] |=
+                                               ((u32)
+                                                1 << (txq->txq_id - 32));
+                       sw_stats->tx_stats[i].num_txqs++;
+               }
+
+               sw_stats->tx_stats[i].txf_id = tx->txf.txf_id;
+
+               i++;
+       }
+       sw_stats->num_active_tx = i;
+
+       i = 0;
+       list_for_each(qe, &bna->rx_mod.rx_active_q) {
+               rx = (struct bna_rx *)qe;
+               sw_stats->rx_stats[i].rx_state = bna_rx_state_get(rx);
+               sw_stats->rx_stats[i].rx_flags = rx->rx_flags;
+
+               sw_stats->rx_stats[i].num_rxps = 0;
+               sw_stats->rx_stats[i].num_rxqs = 0;
+               sw_stats->rx_stats[i].rxq_bmap[0] = 0;
+               sw_stats->rx_stats[i].rxq_bmap[1] = 0;
+               sw_stats->rx_stats[i].cq_bmap[0] = 0;
+               sw_stats->rx_stats[i].cq_bmap[1] = 0;
+               list_for_each(rxp_qe, &rx->rxp_q) {
+                       rxp = (struct bna_rxp *)rxp_qe;
+
+                       sw_stats->rx_stats[i].num_rxqs += 1;
+
+                       if (rxp->type == BNA_RXP_SINGLE) {
+                               if (rxp->rxq.single.only->rxq_id < 32) {
+                                       sw_stats->rx_stats[i].rxq_bmap[0] |=
+                                       ((u32)1 <<
+                                       rxp->rxq.single.only->rxq_id);
+                               } else {
+                                       sw_stats->rx_stats[i].rxq_bmap[1] |=
+                                       ((u32)1 <<
+                                       (rxp->rxq.single.only->rxq_id - 32));
+                               }
+                       } else {
+                               if (rxp->rxq.slr.large->rxq_id < 32) {
+                                       sw_stats->rx_stats[i].rxq_bmap[0] |=
+                                       ((u32)1 <<
+                                       rxp->rxq.slr.large->rxq_id);
+                               } else {
+                                       sw_stats->rx_stats[i].rxq_bmap[1] |=
+                                       ((u32)1 <<
+                                       (rxp->rxq.slr.large->rxq_id - 32));
+                               }
+
+                               if (rxp->rxq.slr.small->rxq_id < 32) {
+                                       sw_stats->rx_stats[i].rxq_bmap[0] |=
+                                       ((u32)1 <<
+                                       rxp->rxq.slr.small->rxq_id);
+                               } else {
+                                       sw_stats->rx_stats[i].rxq_bmap[1] |=
+                               ((u32)1 <<
+                                (rxp->rxq.slr.small->rxq_id - 32));
+                               }
+                               sw_stats->rx_stats[i].num_rxqs += 1;
+                       }
+
+                       if (rxp->cq.cq_id < 32)
+                               sw_stats->rx_stats[i].cq_bmap[0] |=
+                                       (1 << rxp->cq.cq_id);
+                       else
+                               sw_stats->rx_stats[i].cq_bmap[1] |=
+                                       (1 << (rxp->cq.cq_id - 32));
+
+                       sw_stats->rx_stats[i].num_rxps++;
+               }
+
+               sw_stats->rx_stats[i].rxf_id = rx->rxf.rxf_id;
+               sw_stats->rx_stats[i].rxf_state = bna_rxf_state_get(&rx->rxf);
+               sw_stats->rx_stats[i].rxf_oper_state = rx->rxf.rxf_oper_state;
+
+               sw_stats->rx_stats[i].num_active_ucast = 0;
+               if (rx->rxf.ucast_active_mac)
+                       sw_stats->rx_stats[i].num_active_ucast++;
+               list_for_each(mac_qe, &rx->rxf.ucast_active_q)
+                       sw_stats->rx_stats[i].num_active_ucast++;
+
+               sw_stats->rx_stats[i].num_active_mcast = 0;
+               list_for_each(mac_qe, &rx->rxf.mcast_active_q)
+                       sw_stats->rx_stats[i].num_active_mcast++;
+
+               sw_stats->rx_stats[i].rxmode_active = rx->rxf.rxmode_active;
+               sw_stats->rx_stats[i].vlan_filter_status =
+                                               rx->rxf.vlan_filter_status;
+               memcpy(sw_stats->rx_stats[i].vlan_filter_table,
+                               rx->rxf.vlan_filter_table,
+                               sizeof(u32) * ((BFI_MAX_VLAN + 1) / 32));
+
+               sw_stats->rx_stats[i].rss_status = rx->rxf.rss_status;
+               sw_stats->rx_stats[i].hds_status = rx->rxf.hds_status;
+
+               i++;
+       }
+       sw_stats->num_active_rx = i;
+}
+
+static void
+bna_fw_cb_stats_get(void *arg, int status)
+{
+       struct bna *bna = (struct bna *)arg;
+       u64 *p_stats;
+       int i, count;
+       int rxf_count, txf_count;
+       u64 rxf_bmap, txf_bmap;
+
+       bfa_q_qe_init(&bna->mbox_qe.qe);
+
+       if (status == 0) {
+               p_stats = (u64 *)bna->stats.hw_stats;
+               count = sizeof(struct bfi_ll_stats) / sizeof(u64);
+               for (i = 0; i < count; i++)
+                       p_stats[i] = cpu_to_be64(p_stats[i]);
+
+               rxf_count = 0;
+               rxf_bmap = (u64)bna->stats.rxf_bmap[0] |
+                       ((u64)bna->stats.rxf_bmap[1] << 32);
+               for (i = 0; i < BFI_LL_RXF_ID_MAX; i++)
+                       if (rxf_bmap & ((u64)1 << i))
+                               rxf_count++;
+
+               txf_count = 0;
+               txf_bmap = (u64)bna->stats.txf_bmap[0] |
+                       ((u64)bna->stats.txf_bmap[1] << 32);
+               for (i = 0; i < BFI_LL_TXF_ID_MAX; i++)
+                       if (txf_bmap & ((u64)1 << i))
+                               txf_count++;
+
+               p_stats = (u64 *)&bna->stats.hw_stats->rxf_stats[0] +
+                               ((rxf_count * sizeof(struct bfi_ll_stats_rxf) +
+                               txf_count * sizeof(struct bfi_ll_stats_txf))/
+                               sizeof(u64));
+
+               /* Populate the TXF stats from the firmware DMAed copy */
+               for (i = (BFI_LL_TXF_ID_MAX - 1); i >= 0; i--)
+                       if (txf_bmap & ((u64)1 << i)) {
+                               p_stats -= sizeof(struct bfi_ll_stats_txf)/
+                                               sizeof(u64);
+                               memcpy(&bna->stats.hw_stats->txf_stats[i],
+                                       p_stats,
+                                       sizeof(struct bfi_ll_stats_txf));
+                       }
+
+               /* Populate the RXF stats from the firmware DMAed copy */
+               for (i = (BFI_LL_RXF_ID_MAX - 1); i >= 0; i--)
+                       if (rxf_bmap & ((u64)1 << i)) {
+                               p_stats -= sizeof(struct bfi_ll_stats_rxf)/
+                                               sizeof(u64);
+                               memcpy(&bna->stats.hw_stats->rxf_stats[i],
+                                       p_stats,
+                                       sizeof(struct bfi_ll_stats_rxf));
+                       }
+
+               bna_sw_stats_get(bna, bna->stats.sw_stats);
+               bnad_cb_stats_get(bna->bnad, BNA_CB_SUCCESS, &bna->stats);
+       } else
+               bnad_cb_stats_get(bna->bnad, BNA_CB_FAIL, &bna->stats);
+}
+
+static void
+bna_fw_stats_get(struct bna *bna)
+{
+       struct bfi_ll_stats_req ll_req;
+
+       bfi_h2i_set(ll_req.mh, BFI_MC_LL, BFI_LL_H2I_STATS_GET_REQ, 0);
+       ll_req.stats_mask = htons(BFI_LL_STATS_ALL);
+
+       ll_req.rxf_id_mask[0] = htonl(bna->rx_mod.rxf_bmap[0]);
+       ll_req.rxf_id_mask[1] = htonl(bna->rx_mod.rxf_bmap[1]);
+       ll_req.txf_id_mask[0] = htonl(bna->tx_mod.txf_bmap[0]);
+       ll_req.txf_id_mask[1] = htonl(bna->tx_mod.txf_bmap[1]);
+
+       ll_req.host_buffer.a32.addr_hi = bna->hw_stats_dma.msb;
+       ll_req.host_buffer.a32.addr_lo = bna->hw_stats_dma.lsb;
+
+       bna_mbox_qe_fill(&bna->mbox_qe, &ll_req, sizeof(ll_req),
+                               bna_fw_cb_stats_get, bna);
+       bna_mbox_send(bna, &bna->mbox_qe);
+
+       bna->stats.rxf_bmap[0] = bna->rx_mod.rxf_bmap[0];
+       bna->stats.rxf_bmap[1] = bna->rx_mod.rxf_bmap[1];
+       bna->stats.txf_bmap[0] = bna->tx_mod.txf_bmap[0];
+       bna->stats.txf_bmap[1] = bna->tx_mod.txf_bmap[1];
+}
+
+static void
+bna_fw_cb_stats_clr(void *arg, int status)
+{
+       struct bna *bna = (struct bna *)arg;
+
+       bfa_q_qe_init(&bna->mbox_qe.qe);
+
+       memset(bna->stats.sw_stats, 0, sizeof(struct bna_sw_stats));
+       memset(bna->stats.hw_stats, 0, sizeof(struct bfi_ll_stats));
+
+       bnad_cb_stats_clr(bna->bnad);
+}
+
+static void
+bna_fw_stats_clr(struct bna *bna)
+{
+       struct bfi_ll_stats_req ll_req;
+
+       bfi_h2i_set(ll_req.mh, BFI_MC_LL, BFI_LL_H2I_STATS_CLEAR_REQ, 0);
+       ll_req.stats_mask = htons(BFI_LL_STATS_ALL);
+       ll_req.rxf_id_mask[0] = htonl(0xffffffff);
+       ll_req.rxf_id_mask[1] = htonl(0xffffffff);
+       ll_req.txf_id_mask[0] = htonl(0xffffffff);
+       ll_req.txf_id_mask[1] = htonl(0xffffffff);
+
+       bna_mbox_qe_fill(&bna->mbox_qe, &ll_req, sizeof(ll_req),
+                               bna_fw_cb_stats_clr, bna);
+       bna_mbox_send(bna, &bna->mbox_qe);
+}
+
+void
+bna_stats_get(struct bna *bna)
+{
+       if (bna_device_status_get(&bna->device))
+               bna_fw_stats_get(bna);
+       else
+               bnad_cb_stats_get(bna->bnad, BNA_CB_FAIL, &bna->stats);
+}
+
+void
+bna_stats_clr(struct bna *bna)
+{
+       if (bna_device_status_get(&bna->device))
+               bna_fw_stats_clr(bna);
+       else {
+               memset(&bna->stats.sw_stats, 0,
+                               sizeof(struct bna_sw_stats));
+               memset(bna->stats.hw_stats, 0,
+                               sizeof(struct bfi_ll_stats));
+               bnad_cb_stats_clr(bna->bnad);
+       }
+}
+
+/* IB */
+void
+bna_ib_coalescing_timeo_set(struct bna_ib *ib, u8 coalescing_timeo)
+{
+       ib->ib_config.coalescing_timeo = coalescing_timeo;
+
+       if (ib->start_count)
+               ib->door_bell.doorbell_ack = BNA_DOORBELL_IB_INT_ACK(
+                               (u32)ib->ib_config.coalescing_timeo, 0);
+}
+
+/* RxF */
+void
+bna_rxf_adv_init(struct bna_rxf *rxf,
+               struct bna_rx *rx,
+               struct bna_rx_config *q_config)
+{
+       switch (q_config->rxp_type) {
+       case BNA_RXP_SINGLE:
+               /* No-op */
+               break;
+       case BNA_RXP_SLR:
+               rxf->ctrl_flags |= BNA_RXF_CF_SM_LG_RXQ;
+               break;
+       case BNA_RXP_HDS:
+               rxf->hds_cfg.hdr_type = q_config->hds_config.hdr_type;
+               rxf->hds_cfg.header_size =
+                               q_config->hds_config.header_size;
+               rxf->forced_offset = 0;
+               break;
+       default:
+               break;
+       }
+
+       if (q_config->rss_status == BNA_STATUS_T_ENABLED) {
+               rxf->ctrl_flags |= BNA_RXF_CF_RSS_ENABLE;
+               rxf->rss_cfg.hash_type = q_config->rss_config.hash_type;
+               rxf->rss_cfg.hash_mask = q_config->rss_config.hash_mask;
+               memcpy(&rxf->rss_cfg.toeplitz_hash_key[0],
+                       &q_config->rss_config.toeplitz_hash_key[0],
+                       sizeof(rxf->rss_cfg.toeplitz_hash_key));
+       }
+}
+
+static void
+rxf_fltr_mbox_cmd(struct bna_rxf *rxf, u8 cmd, enum bna_status status)
+{
+       struct bfi_ll_rxf_req req;
+
+       bfi_h2i_set(req.mh, BFI_MC_LL, cmd, 0);
+
+       req.rxf_id = rxf->rxf_id;
+       req.enable = status;
+
+       bna_mbox_qe_fill(&rxf->mbox_qe, &req, sizeof(req),
+                       rxf_cb_cam_fltr_mbox_cmd, rxf);
+
+       bna_mbox_send(rxf->rx->bna, &rxf->mbox_qe);
+}
+
+void
+__rxf_default_function_config(struct bna_rxf *rxf, enum bna_status status)
+{
+       struct bna_rx_fndb_ram *rx_fndb_ram;
+       u32 ctrl_flags;
+       int i;
+
+       rx_fndb_ram = (struct bna_rx_fndb_ram *)
+                       BNA_GET_MEM_BASE_ADDR(rxf->rx->bna->pcidev.pci_bar_kva,
+                       RX_FNDB_RAM_BASE_OFFSET);
+
+       for (i = 0; i < BFI_MAX_RXF; i++) {
+               if (status == BNA_STATUS_T_ENABLED) {
+                       if (i == rxf->rxf_id)
+                               continue;
+
+                       ctrl_flags =
+                               readl(&rx_fndb_ram[i].control_flags);
+                       ctrl_flags |= BNA_RXF_CF_DEFAULT_FUNCTION_ENABLE;
+                       writel(ctrl_flags,
+                                               &rx_fndb_ram[i].control_flags);
+               } else {
+                       ctrl_flags =
+                               readl(&rx_fndb_ram[i].control_flags);
+                       ctrl_flags &= ~BNA_RXF_CF_DEFAULT_FUNCTION_ENABLE;
+                       writel(ctrl_flags,
+                                               &rx_fndb_ram[i].control_flags);
+               }
+       }
+}
+
+int
+rxf_process_packet_filter_ucast(struct bna_rxf *rxf)
+{
+       struct bna_mac *mac = NULL;
+       struct list_head *qe;
+
+       /* Add additional MAC entries */
+       if (!list_empty(&rxf->ucast_pending_add_q)) {
+               bfa_q_deq(&rxf->ucast_pending_add_q, &qe);
+               bfa_q_qe_init(qe);
+               mac = (struct bna_mac *)qe;
+               rxf_cam_mbox_cmd(rxf, BFI_LL_H2I_MAC_UCAST_ADD_REQ, mac);
+               list_add_tail(&mac->qe, &rxf->ucast_active_q);
+               return 1;
+       }
+
+       /* Delete MAC addresses previousely added */
+       if (!list_empty(&rxf->ucast_pending_del_q)) {
+               bfa_q_deq(&rxf->ucast_pending_del_q, &qe);
+               bfa_q_qe_init(qe);
+               mac = (struct bna_mac *)qe;
+               rxf_cam_mbox_cmd(rxf, BFI_LL_H2I_MAC_UCAST_DEL_REQ, mac);
+               bna_ucam_mod_mac_put(&rxf->rx->bna->ucam_mod, mac);
+               return 1;
+       }
+
+       return 0;
+}
+
+int
+rxf_process_packet_filter_promisc(struct bna_rxf *rxf)
+{
+       struct bna *bna = rxf->rx->bna;
+
+       /* Enable/disable promiscuous mode */
+       if (is_promisc_enable(rxf->rxmode_pending,
+                               rxf->rxmode_pending_bitmask)) {
+               /* move promisc configuration from pending -> active */
+               promisc_inactive(rxf->rxmode_pending,
+                               rxf->rxmode_pending_bitmask);
+               rxf->rxmode_active |= BNA_RXMODE_PROMISC;
+
+               /* Disable VLAN filter to allow all VLANs */
+               __rxf_vlan_filter_set(rxf, BNA_STATUS_T_DISABLED);
+               rxf_fltr_mbox_cmd(rxf, BFI_LL_H2I_RXF_PROMISCUOUS_SET_REQ,
+                               BNA_STATUS_T_ENABLED);
+               return 1;
+       } else if (is_promisc_disable(rxf->rxmode_pending,
+                               rxf->rxmode_pending_bitmask)) {
+               /* move promisc configuration from pending -> active */
+               promisc_inactive(rxf->rxmode_pending,
+                               rxf->rxmode_pending_bitmask);
+               rxf->rxmode_active &= ~BNA_RXMODE_PROMISC;
+               bna->rxf_promisc_id = BFI_MAX_RXF;
+
+               /* Revert VLAN filter */
+               __rxf_vlan_filter_set(rxf, rxf->vlan_filter_status);
+               rxf_fltr_mbox_cmd(rxf, BFI_LL_H2I_RXF_PROMISCUOUS_SET_REQ,
+                               BNA_STATUS_T_DISABLED);
+               return 1;
+       }
+
+       return 0;
+}
+
+int
+rxf_process_packet_filter_default(struct bna_rxf *rxf)
+{
+       struct bna *bna = rxf->rx->bna;
+
+       /* Enable/disable default mode */
+       if (is_default_enable(rxf->rxmode_pending,
+                               rxf->rxmode_pending_bitmask)) {
+               /* move default configuration from pending -> active */
+               default_inactive(rxf->rxmode_pending,
+                               rxf->rxmode_pending_bitmask);
+               rxf->rxmode_active |= BNA_RXMODE_DEFAULT;
+
+               /* Disable VLAN filter to allow all VLANs */
+               __rxf_vlan_filter_set(rxf, BNA_STATUS_T_DISABLED);
+               /* Redirect all other RxF vlan filtering to this one */
+               __rxf_default_function_config(rxf, BNA_STATUS_T_ENABLED);
+               rxf_fltr_mbox_cmd(rxf, BFI_LL_H2I_RXF_DEFAULT_SET_REQ,
+                               BNA_STATUS_T_ENABLED);
+               return 1;
+       } else if (is_default_disable(rxf->rxmode_pending,
+                               rxf->rxmode_pending_bitmask)) {
+               /* move default configuration from pending -> active */
+               default_inactive(rxf->rxmode_pending,
+                               rxf->rxmode_pending_bitmask);
+               rxf->rxmode_active &= ~BNA_RXMODE_DEFAULT;
+               bna->rxf_default_id = BFI_MAX_RXF;
+
+               /* Revert VLAN filter */
+               __rxf_vlan_filter_set(rxf, rxf->vlan_filter_status);
+               /* Stop RxF vlan filter table redirection */
+               __rxf_default_function_config(rxf, BNA_STATUS_T_DISABLED);
+               rxf_fltr_mbox_cmd(rxf, BFI_LL_H2I_RXF_DEFAULT_SET_REQ,
+                               BNA_STATUS_T_DISABLED);
+               return 1;
+       }
+
+       return 0;
+}
+
+int
+rxf_process_packet_filter_allmulti(struct bna_rxf *rxf)
+{
+       /* Enable/disable allmulti mode */
+       if (is_allmulti_enable(rxf->rxmode_pending,
+                               rxf->rxmode_pending_bitmask)) {
+               /* move allmulti configuration from pending -> active */
+               allmulti_inactive(rxf->rxmode_pending,
+                               rxf->rxmode_pending_bitmask);
+               rxf->rxmode_active |= BNA_RXMODE_ALLMULTI;
+
+               rxf_fltr_mbox_cmd(rxf, BFI_LL_H2I_MAC_MCAST_FILTER_REQ,
+                               BNA_STATUS_T_ENABLED);
+               return 1;
+       } else if (is_allmulti_disable(rxf->rxmode_pending,
+                                       rxf->rxmode_pending_bitmask)) {
+               /* move allmulti configuration from pending -> active */
+               allmulti_inactive(rxf->rxmode_pending,
+                               rxf->rxmode_pending_bitmask);
+               rxf->rxmode_active &= ~BNA_RXMODE_ALLMULTI;
+
+               rxf_fltr_mbox_cmd(rxf, BFI_LL_H2I_MAC_MCAST_FILTER_REQ,
+                               BNA_STATUS_T_DISABLED);
+               return 1;
+       }
+
+       return 0;
+}
+
+int
+rxf_clear_packet_filter_ucast(struct bna_rxf *rxf)
+{
+       struct bna_mac *mac = NULL;
+       struct list_head *qe;
+
+       /* 1. delete pending ucast entries */
+       if (!list_empty(&rxf->ucast_pending_del_q)) {
+               bfa_q_deq(&rxf->ucast_pending_del_q, &qe);
+               bfa_q_qe_init(qe);
+               mac = (struct bna_mac *)qe;
+               rxf_cam_mbox_cmd(rxf, BFI_LL_H2I_MAC_UCAST_DEL_REQ, mac);
+               bna_ucam_mod_mac_put(&rxf->rx->bna->ucam_mod, mac);
+               return 1;
+       }
+
+       /* 2. clear active ucast entries; move them to pending_add_q */
+       if (!list_empty(&rxf->ucast_active_q)) {
+               bfa_q_deq(&rxf->ucast_active_q, &qe);
+               bfa_q_qe_init(qe);
+               mac = (struct bna_mac *)qe;
+               rxf_cam_mbox_cmd(rxf, BFI_LL_H2I_MAC_UCAST_DEL_REQ, mac);
+               list_add_tail(&mac->qe, &rxf->ucast_pending_add_q);
+               return 1;
+       }
+
+       return 0;
+}
+
+int
+rxf_clear_packet_filter_promisc(struct bna_rxf *rxf)
+{
+       struct bna *bna = rxf->rx->bna;
+
+       /* 6. Execute pending promisc mode disable command */
+       if (is_promisc_disable(rxf->rxmode_pending,
+                               rxf->rxmode_pending_bitmask)) {
+               /* move promisc configuration from pending -> active */
+               promisc_inactive(rxf->rxmode_pending,
+                               rxf->rxmode_pending_bitmask);
+               rxf->rxmode_active &= ~BNA_RXMODE_PROMISC;
+               bna->rxf_promisc_id = BFI_MAX_RXF;
+
+               /* Revert VLAN filter */
+               __rxf_vlan_filter_set(rxf, rxf->vlan_filter_status);
+               rxf_fltr_mbox_cmd(rxf, BFI_LL_H2I_RXF_PROMISCUOUS_SET_REQ,
+                               BNA_STATUS_T_DISABLED);
+               return 1;
+       }
+
+       /* 7. Clear active promisc mode; move it to pending enable */
+       if (rxf->rxmode_active & BNA_RXMODE_PROMISC) {
+               /* move promisc configuration from active -> pending */
+               promisc_enable(rxf->rxmode_pending,
+                               rxf->rxmode_pending_bitmask);
+               rxf->rxmode_active &= ~BNA_RXMODE_PROMISC;
+
+               /* Revert VLAN filter */
+               __rxf_vlan_filter_set(rxf, rxf->vlan_filter_status);
+               rxf_fltr_mbox_cmd(rxf, BFI_LL_H2I_RXF_PROMISCUOUS_SET_REQ,
+                               BNA_STATUS_T_DISABLED);
+               return 1;
+       }
+
+       return 0;
+}
+
+int
+rxf_clear_packet_filter_default(struct bna_rxf *rxf)
+{
+       struct bna *bna = rxf->rx->bna;
+
+       /* 8. Execute pending default mode disable command */
+       if (is_default_disable(rxf->rxmode_pending,
+                               rxf->rxmode_pending_bitmask)) {
+               /* move default configuration from pending -> active */
+               default_inactive(rxf->rxmode_pending,
+                               rxf->rxmode_pending_bitmask);
+               rxf->rxmode_active &= ~BNA_RXMODE_DEFAULT;
+               bna->rxf_default_id = BFI_MAX_RXF;
+
+               /* Revert VLAN filter */
+               __rxf_vlan_filter_set(rxf, rxf->vlan_filter_status);
+               /* Stop RxF vlan filter table redirection */
+               __rxf_default_function_config(rxf, BNA_STATUS_T_DISABLED);
+               rxf_fltr_mbox_cmd(rxf, BFI_LL_H2I_RXF_DEFAULT_SET_REQ,
+                               BNA_STATUS_T_DISABLED);
+               return 1;
+       }
+
+       /* 9. Clear active default mode; move it to pending enable */
+       if (rxf->rxmode_active & BNA_RXMODE_DEFAULT) {
+               /* move default configuration from active -> pending */
+               default_enable(rxf->rxmode_pending,
+                               rxf->rxmode_pending_bitmask);
+               rxf->rxmode_active &= ~BNA_RXMODE_DEFAULT;
+
+               /* Revert VLAN filter */
+               __rxf_vlan_filter_set(rxf, rxf->vlan_filter_status);
+               /* Stop RxF vlan filter table redirection */
+               __rxf_default_function_config(rxf, BNA_STATUS_T_DISABLED);
+               rxf_fltr_mbox_cmd(rxf, BFI_LL_H2I_RXF_DEFAULT_SET_REQ,
+                               BNA_STATUS_T_DISABLED);
+               return 1;
+       }
+
+       return 0;
+}
+
+int
+rxf_clear_packet_filter_allmulti(struct bna_rxf *rxf)
+{
+       /* 10. Execute pending allmulti mode disable command */
+       if (is_allmulti_disable(rxf->rxmode_pending,
+                               rxf->rxmode_pending_bitmask)) {
+               /* move allmulti configuration from pending -> active */
+               allmulti_inactive(rxf->rxmode_pending,
+                               rxf->rxmode_pending_bitmask);
+               rxf->rxmode_active &= ~BNA_RXMODE_ALLMULTI;
+               rxf_fltr_mbox_cmd(rxf, BFI_LL_H2I_MAC_MCAST_FILTER_REQ,
+                               BNA_STATUS_T_DISABLED);
+               return 1;
+       }
+
+       /* 11. Clear active allmulti mode; move it to pending enable */
+       if (rxf->rxmode_active & BNA_RXMODE_ALLMULTI) {
+               /* move allmulti configuration from active -> pending */
+               allmulti_enable(rxf->rxmode_pending,
+                               rxf->rxmode_pending_bitmask);
+               rxf->rxmode_active &= ~BNA_RXMODE_ALLMULTI;
+               rxf_fltr_mbox_cmd(rxf, BFI_LL_H2I_MAC_MCAST_FILTER_REQ,
+                               BNA_STATUS_T_DISABLED);
+               return 1;
+       }
+
+       return 0;
+}
+
+void
+rxf_reset_packet_filter_ucast(struct bna_rxf *rxf)
+{
+       struct list_head *qe;
+       struct bna_mac *mac;
+
+       /* 1. Move active ucast entries to pending_add_q */
+       while (!list_empty(&rxf->ucast_active_q)) {
+               bfa_q_deq(&rxf->ucast_active_q, &qe);
+               bfa_q_qe_init(qe);
+               list_add_tail(qe, &rxf->ucast_pending_add_q);
+       }
+
+       /* 2. Throw away delete pending ucast entries */
+       while (!list_empty(&rxf->ucast_pending_del_q)) {
+               bfa_q_deq(&rxf->ucast_pending_del_q, &qe);
+               bfa_q_qe_init(qe);
+               mac = (struct bna_mac *)qe;
+               bna_ucam_mod_mac_put(&rxf->rx->bna->ucam_mod, mac);
+       }
+}
+
+void
+rxf_reset_packet_filter_promisc(struct bna_rxf *rxf)
+{
+       struct bna *bna = rxf->rx->bna;
+
+       /* 6. Clear pending promisc mode disable */
+       if (is_promisc_disable(rxf->rxmode_pending,
+                               rxf->rxmode_pending_bitmask)) {
+               promisc_inactive(rxf->rxmode_pending,
+                               rxf->rxmode_pending_bitmask);
+               rxf->rxmode_active &= ~BNA_RXMODE_PROMISC;
+               bna->rxf_promisc_id = BFI_MAX_RXF;
+       }
+
+       /* 7. Move promisc mode config from active -> pending */
+       if (rxf->rxmode_active & BNA_RXMODE_PROMISC) {
+               promisc_enable(rxf->rxmode_pending,
+                               rxf->rxmode_pending_bitmask);
+               rxf->rxmode_active &= ~BNA_RXMODE_PROMISC;
+       }
+
+}
+
+void
+rxf_reset_packet_filter_default(struct bna_rxf *rxf)
+{
+       struct bna *bna = rxf->rx->bna;
+
+       /* 8. Clear pending default mode disable */
+       if (is_default_disable(rxf->rxmode_pending,
+                               rxf->rxmode_pending_bitmask)) {
+               default_inactive(rxf->rxmode_pending,
+                               rxf->rxmode_pending_bitmask);
+               rxf->rxmode_active &= ~BNA_RXMODE_DEFAULT;
+               bna->rxf_default_id = BFI_MAX_RXF;
+       }
+
+       /* 9. Move default mode config from active -> pending */
+       if (rxf->rxmode_active & BNA_RXMODE_DEFAULT) {
+               default_enable(rxf->rxmode_pending,
+                               rxf->rxmode_pending_bitmask);
+               rxf->rxmode_active &= ~BNA_RXMODE_DEFAULT;
+       }
+}
+
+void
+rxf_reset_packet_filter_allmulti(struct bna_rxf *rxf)
+{
+       /* 10. Clear pending allmulti mode disable */
+       if (is_allmulti_disable(rxf->rxmode_pending,
+                               rxf->rxmode_pending_bitmask)) {
+               allmulti_inactive(rxf->rxmode_pending,
+                               rxf->rxmode_pending_bitmask);
+               rxf->rxmode_active &= ~BNA_RXMODE_ALLMULTI;
+       }
+
+       /* 11. Move allmulti mode config from active -> pending */
+       if (rxf->rxmode_active & BNA_RXMODE_ALLMULTI) {
+               allmulti_enable(rxf->rxmode_pending,
+                               rxf->rxmode_pending_bitmask);
+               rxf->rxmode_active &= ~BNA_RXMODE_ALLMULTI;
+       }
+}
+
+/**
+ * Should only be called by bna_rxf_mode_set.
+ * Helps deciding if h/w configuration is needed or not.
+ *  Returns:
+ *     0 = no h/w change
+ *     1 = need h/w change
+ */
+int
+rxf_promisc_enable(struct bna_rxf *rxf)
+{
+       struct bna *bna = rxf->rx->bna;
+       int ret = 0;
+
+       /* There can not be any pending disable command */
+
+       /* Do nothing if pending enable or already enabled */
+       if (is_promisc_enable(rxf->rxmode_pending,
+                       rxf->rxmode_pending_bitmask) ||
+                       (rxf->rxmode_active & BNA_RXMODE_PROMISC)) {
+               /* Schedule enable */
+       } else {
+               /* Promisc mode should not be active in the system */
+               promisc_enable(rxf->rxmode_pending,
+                               rxf->rxmode_pending_bitmask);
+               bna->rxf_promisc_id = rxf->rxf_id;
+               ret = 1;
+       }
+
+       return ret;
+}
+
+/**
+ * Should only be called by bna_rxf_mode_set.
+ * Helps deciding if h/w configuration is needed or not.
+ *  Returns:
+ *     0 = no h/w change
+ *     1 = need h/w change
+ */
+int
+rxf_promisc_disable(struct bna_rxf *rxf)
+{
+       struct bna *bna = rxf->rx->bna;
+       int ret = 0;
+
+       /* There can not be any pending disable */
+
+       /* Turn off pending enable command , if any */
+       if (is_promisc_enable(rxf->rxmode_pending,
+                               rxf->rxmode_pending_bitmask)) {
+               /* Promisc mode should not be active */
+               /* system promisc state should be pending */
+               promisc_inactive(rxf->rxmode_pending,
+                               rxf->rxmode_pending_bitmask);
+               /* Remove the promisc state from the system */
+               bna->rxf_promisc_id = BFI_MAX_RXF;
+
+               /* Schedule disable */
+       } else if (rxf->rxmode_active & BNA_RXMODE_PROMISC) {
+               /* Promisc mode should be active in the system */
+               promisc_disable(rxf->rxmode_pending,
+                               rxf->rxmode_pending_bitmask);
+               ret = 1;
+
+       /* Do nothing if already disabled */
+       } else {
+       }
+
+       return ret;
+}
+
+/**
+ * Should only be called by bna_rxf_mode_set.
+ * Helps deciding if h/w configuration is needed or not.
+ *  Returns:
+ *     0 = no h/w change
+ *     1 = need h/w change
+ */
+int
+rxf_default_enable(struct bna_rxf *rxf)
+{
+       struct bna *bna = rxf->rx->bna;
+       int ret = 0;
+
+       /* There can not be any pending disable command */
+
+       /* Do nothing if pending enable or already enabled */
+       if (is_default_enable(rxf->rxmode_pending,
+               rxf->rxmode_pending_bitmask) ||
+               (rxf->rxmode_active & BNA_RXMODE_DEFAULT)) {
+               /* Schedule enable */
+       } else {
+               /* Default mode should not be active in the system */
+               default_enable(rxf->rxmode_pending,
+                               rxf->rxmode_pending_bitmask);
+               bna->rxf_default_id = rxf->rxf_id;
+               ret = 1;
+       }
+
+       return ret;
+}
+
+/**
+ * Should only be called by bna_rxf_mode_set.
+ * Helps deciding if h/w configuration is needed or not.
+ *  Returns:
+ *     0 = no h/w change
+ *     1 = need h/w change
+ */
+int
+rxf_default_disable(struct bna_rxf *rxf)
+{
+       struct bna *bna = rxf->rx->bna;
+       int ret = 0;
+
+       /* There can not be any pending disable */
+
+       /* Turn off pending enable command , if any */
+       if (is_default_enable(rxf->rxmode_pending,
+                               rxf->rxmode_pending_bitmask)) {
+               /* Promisc mode should not be active */
+               /* system default state should be pending */
+               default_inactive(rxf->rxmode_pending,
+                               rxf->rxmode_pending_bitmask);
+               /* Remove the default state from the system */
+               bna->rxf_default_id = BFI_MAX_RXF;
+
+       /* Schedule disable */
+       } else if (rxf->rxmode_active & BNA_RXMODE_DEFAULT) {
+               /* Default mode should be active in the system */
+               default_disable(rxf->rxmode_pending,
+                               rxf->rxmode_pending_bitmask);
+               ret = 1;
+
+       /* Do nothing if already disabled */
+       } else {
+       }
+
+       return ret;
+}
+
+/**
+ * Should only be called by bna_rxf_mode_set.
+ * Helps deciding if h/w configuration is needed or not.
+ *  Returns:
+ *     0 = no h/w change
+ *     1 = need h/w change
+ */
+int
+rxf_allmulti_enable(struct bna_rxf *rxf)
+{
+       int ret = 0;
+
+       /* There can not be any pending disable command */
+
+       /* Do nothing if pending enable or already enabled */
+       if (is_allmulti_enable(rxf->rxmode_pending,
+                       rxf->rxmode_pending_bitmask) ||
+                       (rxf->rxmode_active & BNA_RXMODE_ALLMULTI)) {
+               /* Schedule enable */
+       } else {
+               allmulti_enable(rxf->rxmode_pending,
+                               rxf->rxmode_pending_bitmask);
+               ret = 1;
+       }
+
+       return ret;
+}
+
+/**
+ * Should only be called by bna_rxf_mode_set.
+ * Helps deciding if h/w configuration is needed or not.
+ *  Returns:
+ *     0 = no h/w change
+ *     1 = need h/w change
+ */
+int
+rxf_allmulti_disable(struct bna_rxf *rxf)
+{
+       int ret = 0;
+
+       /* There can not be any pending disable */
+
+       /* Turn off pending enable command , if any */
+       if (is_allmulti_enable(rxf->rxmode_pending,
+                               rxf->rxmode_pending_bitmask)) {
+               /* Allmulti mode should not be active */
+               allmulti_inactive(rxf->rxmode_pending,
+                               rxf->rxmode_pending_bitmask);
+
+       /* Schedule disable */
+       } else if (rxf->rxmode_active & BNA_RXMODE_ALLMULTI) {
+               allmulti_disable(rxf->rxmode_pending,
+                               rxf->rxmode_pending_bitmask);
+               ret = 1;
+       }
+
+       return ret;
+}
+
+/* RxF <- bnad */
+void
+bna_rx_mcast_delall(struct bna_rx *rx,
+                   void (*cbfn)(struct bnad *, struct bna_rx *,
+                                enum bna_cb_status))
+{
+       struct bna_rxf *rxf = &rx->rxf;
+       struct list_head *qe;
+       struct bna_mac *mac;
+       int need_hw_config = 0;
+
+       /* Purge all entries from pending_add_q */
+       while (!list_empty(&rxf->mcast_pending_add_q)) {
+               bfa_q_deq(&rxf->mcast_pending_add_q, &qe);
+               mac = (struct bna_mac *)qe;
+               bfa_q_qe_init(&mac->qe);
+               bna_mcam_mod_mac_put(&rxf->rx->bna->mcam_mod, mac);
+       }
+
+       /* Schedule all entries in active_q for deletion */
+       while (!list_empty(&rxf->mcast_active_q)) {
+               bfa_q_deq(&rxf->mcast_active_q, &qe);
+               mac = (struct bna_mac *)qe;
+               bfa_q_qe_init(&mac->qe);
+               list_add_tail(&mac->qe, &rxf->mcast_pending_del_q);
+               need_hw_config = 1;
+       }
+
+       if (need_hw_config) {
+               rxf->cam_fltr_cbfn = cbfn;
+               rxf->cam_fltr_cbarg = rx->bna->bnad;
+               bfa_fsm_send_event(rxf, RXF_E_CAM_FLTR_MOD);
+               return;
+       }
+
+       if (cbfn)
+               (*cbfn)(rx->bna->bnad, rx, BNA_CB_SUCCESS);
+}
+
+/* RxF <- Rx */
+void
+bna_rx_receive_resume(struct bna_rx *rx,
+                     void (*cbfn)(struct bnad *, struct bna_rx *,
+                                  enum bna_cb_status))
+{
+       struct bna_rxf *rxf = &rx->rxf;
+
+       if (rxf->rxf_oper_state == BNA_RXF_OPER_STATE_PAUSED) {
+               rxf->oper_state_cbfn = cbfn;
+               rxf->oper_state_cbarg = rx->bna->bnad;
+               bfa_fsm_send_event(rxf, RXF_E_RESUME);
+       } else if (cbfn)
+               (*cbfn)(rx->bna->bnad, rx, BNA_CB_SUCCESS);
+}
+
+void
+bna_rx_receive_pause(struct bna_rx *rx,
+                    void (*cbfn)(struct bnad *, struct bna_rx *,
+                                 enum bna_cb_status))
+{
+       struct bna_rxf *rxf = &rx->rxf;
+
+       if (rxf->rxf_oper_state == BNA_RXF_OPER_STATE_RUNNING) {
+               rxf->oper_state_cbfn = cbfn;
+               rxf->oper_state_cbarg = rx->bna->bnad;
+               bfa_fsm_send_event(rxf, RXF_E_PAUSE);
+       } else if (cbfn)
+               (*cbfn)(rx->bna->bnad, rx, BNA_CB_SUCCESS);
+}
+
+/* RxF <- bnad */
+enum bna_cb_status
+bna_rx_ucast_add(struct bna_rx *rx, u8 *addr,
+                void (*cbfn)(struct bnad *, struct bna_rx *,
+                             enum bna_cb_status))
+{
+       struct bna_rxf *rxf = &rx->rxf;
+       struct list_head *qe;
+       struct bna_mac *mac;
+
+       /* Check if already added */
+       list_for_each(qe, &rxf->ucast_active_q) {
+               mac = (struct bna_mac *)qe;
+               if (BNA_MAC_IS_EQUAL(mac->addr, addr)) {
+                       if (cbfn)
+                               (*cbfn)(rx->bna->bnad, rx, BNA_CB_SUCCESS);
+                       return BNA_CB_SUCCESS;
+               }
+       }
+
+       /* Check if pending addition */
+       list_for_each(qe, &rxf->ucast_pending_add_q) {
+               mac = (struct bna_mac *)qe;
+               if (BNA_MAC_IS_EQUAL(mac->addr, addr)) {
+                       if (cbfn)
+                               (*cbfn)(rx->bna->bnad, rx, BNA_CB_SUCCESS);
+                       return BNA_CB_SUCCESS;
+               }
+       }
+
+       mac = bna_ucam_mod_mac_get(&rxf->rx->bna->ucam_mod);
+       if (mac == NULL)
+               return BNA_CB_UCAST_CAM_FULL;
+       bfa_q_qe_init(&mac->qe);
+       memcpy(mac->addr, addr, ETH_ALEN);
+       list_add_tail(&mac->qe, &rxf->ucast_pending_add_q);
+
+       rxf->cam_fltr_cbfn = cbfn;
+       rxf->cam_fltr_cbarg = rx->bna->bnad;
+
+       bfa_fsm_send_event(rxf, RXF_E_CAM_FLTR_MOD);
+
+       return BNA_CB_SUCCESS;
+}
+
+/* RxF <- bnad */
+enum bna_cb_status
+bna_rx_ucast_del(struct bna_rx *rx, u8 *addr,
+                void (*cbfn)(struct bnad *, struct bna_rx *,
+                             enum bna_cb_status))
+{
+       struct bna_rxf *rxf = &rx->rxf;
+       struct list_head *qe;
+       struct bna_mac *mac;
+
+       list_for_each(qe, &rxf->ucast_pending_add_q) {
+               mac = (struct bna_mac *)qe;
+               if (BNA_MAC_IS_EQUAL(mac->addr, addr)) {
+                       list_del(qe);
+                       bfa_q_qe_init(qe);
+                       bna_ucam_mod_mac_put(&rxf->rx->bna->ucam_mod, mac);
+                       if (cbfn)
+                               (*cbfn)(rx->bna->bnad, rx, BNA_CB_SUCCESS);
+                       return BNA_CB_SUCCESS;
+               }
+       }
+
+       list_for_each(qe, &rxf->ucast_active_q) {
+               mac = (struct bna_mac *)qe;
+               if (BNA_MAC_IS_EQUAL(mac->addr, addr)) {
+                       list_del(qe);
+                       bfa_q_qe_init(qe);
+                       list_add_tail(qe, &rxf->ucast_pending_del_q);
+                       rxf->cam_fltr_cbfn = cbfn;
+                       rxf->cam_fltr_cbarg = rx->bna->bnad;
+                       bfa_fsm_send_event(rxf, RXF_E_CAM_FLTR_MOD);
+                       return BNA_CB_SUCCESS;
+               }
+       }
+
+       return BNA_CB_INVALID_MAC;
+}
+
+/* RxF <- bnad */
+enum bna_cb_status
+bna_rx_mode_set(struct bna_rx *rx, enum bna_rxmode new_mode,
+               enum bna_rxmode bitmask,
+               void (*cbfn)(struct bnad *, struct bna_rx *,
+                            enum bna_cb_status))
+{
+       struct bna_rxf *rxf = &rx->rxf;
+       int need_hw_config = 0;
+
+       /* Error checks */
+
+       if (is_promisc_enable(new_mode, bitmask)) {
+               /* If promisc mode is already enabled elsewhere in the system */
+               if ((rx->bna->rxf_promisc_id != BFI_MAX_RXF) &&
+                       (rx->bna->rxf_promisc_id != rxf->rxf_id))
+                       goto err_return;
+
+               /* If default mode is already enabled in the system */
+               if (rx->bna->rxf_default_id != BFI_MAX_RXF)
+                       goto err_return;
+
+               /* Trying to enable promiscuous and default mode together */
+               if (is_default_enable(new_mode, bitmask))
+                       goto err_return;
+       }
+
+       if (is_default_enable(new_mode, bitmask)) {
+               /* If default mode is already enabled elsewhere in the system */
+               if ((rx->bna->rxf_default_id != BFI_MAX_RXF) &&
+                       (rx->bna->rxf_default_id != rxf->rxf_id)) {
+                               goto err_return;
+               }
+
+               /* If promiscuous mode is already enabled in the system */
+               if (rx->bna->rxf_promisc_id != BFI_MAX_RXF)
+                       goto err_return;
+       }
+
+       /* Process the commands */
+
+       if (is_promisc_enable(new_mode, bitmask)) {
+               if (rxf_promisc_enable(rxf))
+                       need_hw_config = 1;
+       } else if (is_promisc_disable(new_mode, bitmask)) {
+               if (rxf_promisc_disable(rxf))
+                       need_hw_config = 1;
+       }
+
+       if (is_default_enable(new_mode, bitmask)) {
+               if (rxf_default_enable(rxf))
+                       need_hw_config = 1;
+       } else if (is_default_disable(new_mode, bitmask)) {
+               if (rxf_default_disable(rxf))
+                       need_hw_config = 1;
+       }
+
+       if (is_allmulti_enable(new_mode, bitmask)) {
+               if (rxf_allmulti_enable(rxf))
+                       need_hw_config = 1;
+       } else if (is_allmulti_disable(new_mode, bitmask)) {
+               if (rxf_allmulti_disable(rxf))
+                       need_hw_config = 1;
+       }
+
+       /* Trigger h/w if needed */
+
+       if (need_hw_config) {
+               rxf->cam_fltr_cbfn = cbfn;
+               rxf->cam_fltr_cbarg = rx->bna->bnad;
+               bfa_fsm_send_event(rxf, RXF_E_CAM_FLTR_MOD);
+       } else if (cbfn)
+               (*cbfn)(rx->bna->bnad, rx, BNA_CB_SUCCESS);
+
+       return BNA_CB_SUCCESS;
+
+err_return:
+       return BNA_CB_FAIL;
+}
+
+/* RxF <- bnad */
+void
+bna_rx_rss_enable(struct bna_rx *rx)
+{
+       struct bna_rxf *rxf = &rx->rxf;
+
+       rxf->rxf_flags |= BNA_RXF_FL_RSS_CONFIG_PENDING;
+       rxf->rss_status = BNA_STATUS_T_ENABLED;
+       bfa_fsm_send_event(rxf, RXF_E_CAM_FLTR_MOD);
+}
+
+/* RxF <- bnad */
+void
+bna_rx_rss_disable(struct bna_rx *rx)
+{
+       struct bna_rxf *rxf = &rx->rxf;
+
+       rxf->rxf_flags |= BNA_RXF_FL_RSS_CONFIG_PENDING;
+       rxf->rss_status = BNA_STATUS_T_DISABLED;
+       bfa_fsm_send_event(rxf, RXF_E_CAM_FLTR_MOD);
+}
+
+/* RxF <- bnad */
+void
+bna_rx_rss_reconfig(struct bna_rx *rx, struct bna_rxf_rss *rss_config)
+{
+       struct bna_rxf *rxf = &rx->rxf;
+       rxf->rxf_flags |= BNA_RXF_FL_RSS_CONFIG_PENDING;
+       rxf->rss_status = BNA_STATUS_T_ENABLED;
+       rxf->rss_cfg = *rss_config;
+       bfa_fsm_send_event(rxf, RXF_E_CAM_FLTR_MOD);
+}
+
+void
+/* RxF <- bnad */
+bna_rx_vlanfilter_enable(struct bna_rx *rx)
+{
+       struct bna_rxf *rxf = &rx->rxf;
+
+       if (rxf->vlan_filter_status == BNA_STATUS_T_DISABLED) {
+               rxf->rxf_flags |= BNA_RXF_FL_VLAN_CONFIG_PENDING;
+               rxf->vlan_filter_status = BNA_STATUS_T_ENABLED;
+               bfa_fsm_send_event(rxf, RXF_E_CAM_FLTR_MOD);
+       }
+}
+
+/* RxF <- bnad */
+void
+bna_rx_vlanfilter_disable(struct bna_rx *rx)
+{
+       struct bna_rxf *rxf = &rx->rxf;
+
+       if (rxf->vlan_filter_status == BNA_STATUS_T_ENABLED) {
+               rxf->rxf_flags |= BNA_RXF_FL_VLAN_CONFIG_PENDING;
+               rxf->vlan_filter_status = BNA_STATUS_T_DISABLED;
+               bfa_fsm_send_event(rxf, RXF_E_CAM_FLTR_MOD);
+       }
+}
+
+/* Rx */
+
+struct bna_rxp *
+bna_rx_get_rxp(struct bna_rx *rx, int vector)
+{
+       struct bna_rxp *rxp;
+       struct list_head *qe;
+
+       list_for_each(qe, &rx->rxp_q) {
+               rxp = (struct bna_rxp *)qe;
+               if (rxp->vector == vector)
+                       return rxp;
+       }
+       return NULL;
+}
+
+/*
+ * bna_rx_rss_rit_set()
+ * Sets the Q ids for the specified msi-x vectors in the RIT.
+ * Maximum rit size supported is 64, which should be the max size of the
+ * vectors array.
+ */
+
+void
+bna_rx_rss_rit_set(struct bna_rx *rx, unsigned int *vectors, int nvectors)
+{
+       int i;
+       struct bna_rxp *rxp;
+       struct bna_rxq *q0 = NULL, *q1 = NULL;
+       struct bna *bna;
+       struct bna_rxf *rxf;
+
+       /* Build the RIT contents for this RX */
+       bna = rx->bna;
+
+       rxf = &rx->rxf;
+       for (i = 0; i < nvectors; i++) {
+               rxp = bna_rx_get_rxp(rx, vectors[i]);
+
+               GET_RXQS(rxp, q0, q1);
+               rxf->rit_segment->rit[i].large_rxq_id = q0->rxq_id;
+               rxf->rit_segment->rit[i].small_rxq_id = (q1 ? q1->rxq_id : 0);
+       }
+
+       rxf->rit_segment->rit_size = nvectors;
+
+       /* Subsequent call to enable/reconfig RSS will update the RIT in h/w */
+}
+
+/* Rx <- bnad */
+void
+bna_rx_coalescing_timeo_set(struct bna_rx *rx, int coalescing_timeo)
+{
+       struct bna_rxp *rxp;
+       struct list_head *qe;
+
+       list_for_each(qe, &rx->rxp_q) {
+               rxp = (struct bna_rxp *)qe;
+               rxp->cq.ccb->rx_coalescing_timeo = coalescing_timeo;
+               bna_ib_coalescing_timeo_set(rxp->cq.ib, coalescing_timeo);
+       }
+}
+
+/* Rx <- bnad */
+void
+bna_rx_dim_reconfig(struct bna *bna, u32 vector[][BNA_BIAS_T_MAX])
+{
+       int i, j;
+
+       for (i = 0; i < BNA_LOAD_T_MAX; i++)
+               for (j = 0; j < BNA_BIAS_T_MAX; j++)
+                       bna->rx_mod.dim_vector[i][j] = vector[i][j];
+}
+
+/* Rx <- bnad */
+void
+bna_rx_dim_update(struct bna_ccb *ccb)
+{
+       struct bna *bna = ccb->cq->rx->bna;
+       u32 load, bias;
+       u32 pkt_rt, small_rt, large_rt;
+       u8 coalescing_timeo;
+
+       if ((ccb->pkt_rate.small_pkt_cnt == 0) &&
+               (ccb->pkt_rate.large_pkt_cnt == 0))
+               return;
+
+       /* Arrive at preconfigured coalescing timeo value based on pkt rate */
+
+       small_rt = ccb->pkt_rate.small_pkt_cnt;
+       large_rt = ccb->pkt_rate.large_pkt_cnt;
+
+       pkt_rt = small_rt + large_rt;
+
+       if (pkt_rt < BNA_PKT_RATE_10K)
+               load = BNA_LOAD_T_LOW_4;
+       else if (pkt_rt < BNA_PKT_RATE_20K)
+               load = BNA_LOAD_T_LOW_3;
+       else if (pkt_rt < BNA_PKT_RATE_30K)
+               load = BNA_LOAD_T_LOW_2;
+       else if (pkt_rt < BNA_PKT_RATE_40K)
+               load = BNA_LOAD_T_LOW_1;
+       else if (pkt_rt < BNA_PKT_RATE_50K)
+               load = BNA_LOAD_T_HIGH_1;
+       else if (pkt_rt < BNA_PKT_RATE_60K)
+               load = BNA_LOAD_T_HIGH_2;
+       else if (pkt_rt < BNA_PKT_RATE_80K)
+               load = BNA_LOAD_T_HIGH_3;
+       else
+               load = BNA_LOAD_T_HIGH_4;
+
+       if (small_rt > (large_rt << 1))
+               bias = 0;
+       else
+               bias = 1;
+
+       ccb->pkt_rate.small_pkt_cnt = 0;
+       ccb->pkt_rate.large_pkt_cnt = 0;
+
+       coalescing_timeo = bna->rx_mod.dim_vector[load][bias];
+       ccb->rx_coalescing_timeo = coalescing_timeo;
+
+       /* Set it to IB */
+       bna_ib_coalescing_timeo_set(ccb->cq->ib, coalescing_timeo);
+}
+
+/* Tx */
+/* TX <- bnad */
+enum bna_cb_status
+bna_tx_prio_set(struct bna_tx *tx, int prio,
+               void (*cbfn)(struct bnad *, struct bna_tx *,
+                            enum bna_cb_status))
+{
+       if (tx->flags & BNA_TX_F_PRIO_LOCK)
+               return BNA_CB_FAIL;
+       else {
+               tx->prio_change_cbfn = cbfn;
+               bna_tx_prio_changed(tx, prio);
+       }
+
+       return BNA_CB_SUCCESS;
+}
+
+/* TX <- bnad */
+void
+bna_tx_coalescing_timeo_set(struct bna_tx *tx, int coalescing_timeo)
+{
+       struct bna_txq *txq;
+       struct list_head *qe;
+
+       list_for_each(qe, &tx->txq_q) {
+               txq = (struct bna_txq *)qe;
+               bna_ib_coalescing_timeo_set(txq->ib, coalescing_timeo);
+       }
+}
+
+/*
+ * Private data
+ */
+
+struct bna_ritseg_pool_cfg {
+       u32     pool_size;
+       u32     pool_entry_size;
+};
+init_ritseg_pool(ritseg_pool_cfg);
+
+/*
+ * Private functions
+ */
+static void
+bna_ucam_mod_init(struct bna_ucam_mod *ucam_mod, struct bna *bna,
+                 struct bna_res_info *res_info)
+{
+       int i;
+
+       ucam_mod->ucmac = (struct bna_mac *)
+               res_info[BNA_RES_MEM_T_UCMAC_ARRAY].res_u.mem_info.mdl[0].kva;
+
+       INIT_LIST_HEAD(&ucam_mod->free_q);
+       for (i = 0; i < BFI_MAX_UCMAC; i++) {
+               bfa_q_qe_init(&ucam_mod->ucmac[i].qe);
+               list_add_tail(&ucam_mod->ucmac[i].qe, &ucam_mod->free_q);
+       }
+
+       ucam_mod->bna = bna;
+}
+
+static void
+bna_ucam_mod_uninit(struct bna_ucam_mod *ucam_mod)
+{
+       struct list_head *qe;
+       int i = 0;
+
+       list_for_each(qe, &ucam_mod->free_q)
+               i++;
+
+       ucam_mod->bna = NULL;
+}
+
+static void
+bna_mcam_mod_init(struct bna_mcam_mod *mcam_mod, struct bna *bna,
+                 struct bna_res_info *res_info)
+{
+       int i;
+
+       mcam_mod->mcmac = (struct bna_mac *)
+               res_info[BNA_RES_MEM_T_MCMAC_ARRAY].res_u.mem_info.mdl[0].kva;
+
+       INIT_LIST_HEAD(&mcam_mod->free_q);
+       for (i = 0; i < BFI_MAX_MCMAC; i++) {
+               bfa_q_qe_init(&mcam_mod->mcmac[i].qe);
+               list_add_tail(&mcam_mod->mcmac[i].qe, &mcam_mod->free_q);
+       }
+
+       mcam_mod->bna = bna;
+}
+
+static void
+bna_mcam_mod_uninit(struct bna_mcam_mod *mcam_mod)
+{
+       struct list_head *qe;
+       int i = 0;
+
+       list_for_each(qe, &mcam_mod->free_q)
+               i++;
+
+       mcam_mod->bna = NULL;
+}
+
+static void
+bna_rit_mod_init(struct bna_rit_mod *rit_mod,
+               struct bna_res_info *res_info)
+{
+       int i;
+       int j;
+       int count;
+       int offset;
+
+       rit_mod->rit = (struct bna_rit_entry *)
+               res_info[BNA_RES_MEM_T_RIT_ENTRY].res_u.mem_info.mdl[0].kva;
+       rit_mod->rit_segment = (struct bna_rit_segment *)
+               res_info[BNA_RES_MEM_T_RIT_SEGMENT].res_u.mem_info.mdl[0].kva;
+
+       count = 0;
+       offset = 0;
+       for (i = 0; i < BFI_RIT_SEG_TOTAL_POOLS; i++) {
+               INIT_LIST_HEAD(&rit_mod->rit_seg_pool[i]);
+               for (j = 0; j < ritseg_pool_cfg[i].pool_size; j++) {
+                       bfa_q_qe_init(&rit_mod->rit_segment[count].qe);
+                       rit_mod->rit_segment[count].max_rit_size =
+                                       ritseg_pool_cfg[i].pool_entry_size;
+                       rit_mod->rit_segment[count].rit_offset = offset;
+                       rit_mod->rit_segment[count].rit =
+                                       &rit_mod->rit[offset];
+                       list_add_tail(&rit_mod->rit_segment[count].qe,
+                               &rit_mod->rit_seg_pool[i]);
+                       count++;
+                       offset += ritseg_pool_cfg[i].pool_entry_size;
+               }
+       }
+}
+
+static void
+bna_rit_mod_uninit(struct bna_rit_mod *rit_mod)
+{
+       struct bna_rit_segment *rit_segment;
+       struct list_head *qe;
+       int i;
+       int j;
+
+       for (i = 0; i < BFI_RIT_SEG_TOTAL_POOLS; i++) {
+               j = 0;
+               list_for_each(qe, &rit_mod->rit_seg_pool[i]) {
+                       rit_segment = (struct bna_rit_segment *)qe;
+                       j++;
+               }
+       }
+}
+
+/*
+ * Public functions
+ */
+
+/* Called during probe(), before calling bna_init() */
+void
+bna_res_req(struct bna_res_info *res_info)
+{
+       bna_adv_res_req(res_info);
+
+       /* DMA memory for retrieving IOC attributes */
+       res_info[BNA_RES_MEM_T_ATTR].res_type = BNA_RES_T_MEM;
+       res_info[BNA_RES_MEM_T_ATTR].res_u.mem_info.mem_type = BNA_MEM_T_DMA;
+       res_info[BNA_RES_MEM_T_ATTR].res_u.mem_info.num = 1;
+       res_info[BNA_RES_MEM_T_ATTR].res_u.mem_info.len =
+                               ALIGN(bfa_nw_ioc_meminfo(), PAGE_SIZE);
+
+       /* DMA memory for index segment of an IB */
+       res_info[BNA_RES_MEM_T_IBIDX].res_type = BNA_RES_T_MEM;
+       res_info[BNA_RES_MEM_T_IBIDX].res_u.mem_info.mem_type = BNA_MEM_T_DMA;
+       res_info[BNA_RES_MEM_T_IBIDX].res_u.mem_info.len =
+                               BFI_IBIDX_SIZE * BFI_IBIDX_MAX_SEGSIZE;
+       res_info[BNA_RES_MEM_T_IBIDX].res_u.mem_info.num = BFI_MAX_IB;
+
+       /* Virtual memory for IB objects - stored by IB module */
+       res_info[BNA_RES_MEM_T_IB_ARRAY].res_type = BNA_RES_T_MEM;
+       res_info[BNA_RES_MEM_T_IB_ARRAY].res_u.mem_info.mem_type =
+                                                               BNA_MEM_T_KVA;
+       res_info[BNA_RES_MEM_T_IB_ARRAY].res_u.mem_info.num = 1;
+       res_info[BNA_RES_MEM_T_IB_ARRAY].res_u.mem_info.len =
+                               BFI_MAX_IB * sizeof(struct bna_ib);
+
+       /* Virtual memory for intr objects - stored by IB module */
+       res_info[BNA_RES_MEM_T_INTR_ARRAY].res_type = BNA_RES_T_MEM;
+       res_info[BNA_RES_MEM_T_INTR_ARRAY].res_u.mem_info.mem_type =
+                                                               BNA_MEM_T_KVA;
+       res_info[BNA_RES_MEM_T_INTR_ARRAY].res_u.mem_info.num = 1;
+       res_info[BNA_RES_MEM_T_INTR_ARRAY].res_u.mem_info.len =
+                               BFI_MAX_IB * sizeof(struct bna_intr);
+
+       /* Virtual memory for idx_seg objects - stored by IB module */
+       res_info[BNA_RES_MEM_T_IDXSEG_ARRAY].res_type = BNA_RES_T_MEM;
+       res_info[BNA_RES_MEM_T_IDXSEG_ARRAY].res_u.mem_info.mem_type =
+                                                               BNA_MEM_T_KVA;
+       res_info[BNA_RES_MEM_T_IDXSEG_ARRAY].res_u.mem_info.num = 1;
+       res_info[BNA_RES_MEM_T_IDXSEG_ARRAY].res_u.mem_info.len =
+                       BFI_IBIDX_TOTAL_SEGS * sizeof(struct bna_ibidx_seg);
+
+       /* Virtual memory for Tx objects - stored by Tx module */
+       res_info[BNA_RES_MEM_T_TX_ARRAY].res_type = BNA_RES_T_MEM;
+       res_info[BNA_RES_MEM_T_TX_ARRAY].res_u.mem_info.mem_type =
+                                                               BNA_MEM_T_KVA;
+       res_info[BNA_RES_MEM_T_TX_ARRAY].res_u.mem_info.num = 1;
+       res_info[BNA_RES_MEM_T_TX_ARRAY].res_u.mem_info.len =
+                       BFI_MAX_TXQ * sizeof(struct bna_tx);
+
+       /* Virtual memory for TxQ - stored by Tx module */
+       res_info[BNA_RES_MEM_T_TXQ_ARRAY].res_type = BNA_RES_T_MEM;
+       res_info[BNA_RES_MEM_T_TXQ_ARRAY].res_u.mem_info.mem_type =
+                                                               BNA_MEM_T_KVA;
+       res_info[BNA_RES_MEM_T_TXQ_ARRAY].res_u.mem_info.num = 1;
+       res_info[BNA_RES_MEM_T_TXQ_ARRAY].res_u.mem_info.len =
+                       BFI_MAX_TXQ * sizeof(struct bna_txq);
+
+       /* Virtual memory for Rx objects - stored by Rx module */
+       res_info[BNA_RES_MEM_T_RX_ARRAY].res_type = BNA_RES_T_MEM;
+       res_info[BNA_RES_MEM_T_RX_ARRAY].res_u.mem_info.mem_type =
+                                                               BNA_MEM_T_KVA;
+       res_info[BNA_RES_MEM_T_RX_ARRAY].res_u.mem_info.num = 1;
+       res_info[BNA_RES_MEM_T_RX_ARRAY].res_u.mem_info.len =
+                       BFI_MAX_RXQ * sizeof(struct bna_rx);
+
+       /* Virtual memory for RxPath - stored by Rx module */
+       res_info[BNA_RES_MEM_T_RXP_ARRAY].res_type = BNA_RES_T_MEM;
+       res_info[BNA_RES_MEM_T_RXP_ARRAY].res_u.mem_info.mem_type =
+                                                               BNA_MEM_T_KVA;
+       res_info[BNA_RES_MEM_T_RXP_ARRAY].res_u.mem_info.num = 1;
+       res_info[BNA_RES_MEM_T_RXP_ARRAY].res_u.mem_info.len =
+                       BFI_MAX_RXQ * sizeof(struct bna_rxp);
+
+       /* Virtual memory for RxQ - stored by Rx module */
+       res_info[BNA_RES_MEM_T_RXQ_ARRAY].res_type = BNA_RES_T_MEM;
+       res_info[BNA_RES_MEM_T_RXQ_ARRAY].res_u.mem_info.mem_type =
+                                                               BNA_MEM_T_KVA;
+       res_info[BNA_RES_MEM_T_RXQ_ARRAY].res_u.mem_info.num = 1;
+       res_info[BNA_RES_MEM_T_RXQ_ARRAY].res_u.mem_info.len =
+                       BFI_MAX_RXQ * sizeof(struct bna_rxq);
+
+       /* Virtual memory for Unicast MAC address - stored by ucam module */
+       res_info[BNA_RES_MEM_T_UCMAC_ARRAY].res_type = BNA_RES_T_MEM;
+       res_info[BNA_RES_MEM_T_UCMAC_ARRAY].res_u.mem_info.mem_type =
+                                                               BNA_MEM_T_KVA;
+       res_info[BNA_RES_MEM_T_UCMAC_ARRAY].res_u.mem_info.num = 1;
+       res_info[BNA_RES_MEM_T_UCMAC_ARRAY].res_u.mem_info.len =
+                       BFI_MAX_UCMAC * sizeof(struct bna_mac);
+
+       /* Virtual memory for Multicast MAC address - stored by mcam module */
+       res_info[BNA_RES_MEM_T_MCMAC_ARRAY].res_type = BNA_RES_T_MEM;
+       res_info[BNA_RES_MEM_T_MCMAC_ARRAY].res_u.mem_info.mem_type =
+                                                               BNA_MEM_T_KVA;
+       res_info[BNA_RES_MEM_T_MCMAC_ARRAY].res_u.mem_info.num = 1;
+       res_info[BNA_RES_MEM_T_MCMAC_ARRAY].res_u.mem_info.len =
+                       BFI_MAX_MCMAC * sizeof(struct bna_mac);
+
+       /* Virtual memory for RIT entries */
+       res_info[BNA_RES_MEM_T_RIT_ENTRY].res_type = BNA_RES_T_MEM;
+       res_info[BNA_RES_MEM_T_RIT_ENTRY].res_u.mem_info.mem_type =
+                                                               BNA_MEM_T_KVA;
+       res_info[BNA_RES_MEM_T_RIT_ENTRY].res_u.mem_info.num = 1;
+       res_info[BNA_RES_MEM_T_RIT_ENTRY].res_u.mem_info.len =
+                       BFI_MAX_RIT_SIZE * sizeof(struct bna_rit_entry);
+
+       /* Virtual memory for RIT segment table */
+       res_info[BNA_RES_MEM_T_RIT_SEGMENT].res_type = BNA_RES_T_MEM;
+       res_info[BNA_RES_MEM_T_RIT_SEGMENT].res_u.mem_info.mem_type =
+                                                               BNA_MEM_T_KVA;
+       res_info[BNA_RES_MEM_T_RIT_SEGMENT].res_u.mem_info.num = 1;
+       res_info[BNA_RES_MEM_T_RIT_SEGMENT].res_u.mem_info.len =
+                       BFI_RIT_TOTAL_SEGS * sizeof(struct bna_rit_segment);
+
+       /* Interrupt resource for mailbox interrupt */
+       res_info[BNA_RES_INTR_T_MBOX].res_type = BNA_RES_T_INTR;
+       res_info[BNA_RES_INTR_T_MBOX].res_u.intr_info.intr_type =
+                                                       BNA_INTR_T_MSIX;
+       res_info[BNA_RES_INTR_T_MBOX].res_u.intr_info.num = 1;
+}
+
+/* Called during probe() */
+void
+bna_init(struct bna *bna, struct bnad *bnad, struct bfa_pcidev *pcidev,
+               struct bna_res_info *res_info)
+{
+       bna->bnad = bnad;
+       bna->pcidev = *pcidev;
+
+       bna->stats.hw_stats = (struct bfi_ll_stats *)
+               res_info[BNA_RES_MEM_T_STATS].res_u.mem_info.mdl[0].kva;
+       bna->hw_stats_dma.msb =
+               res_info[BNA_RES_MEM_T_STATS].res_u.mem_info.mdl[0].dma.msb;
+       bna->hw_stats_dma.lsb =
+               res_info[BNA_RES_MEM_T_STATS].res_u.mem_info.mdl[0].dma.lsb;
+       bna->stats.sw_stats = (struct bna_sw_stats *)
+               res_info[BNA_RES_MEM_T_SWSTATS].res_u.mem_info.mdl[0].kva;
+
+       bna->regs.page_addr = bna->pcidev.pci_bar_kva +
+                               reg_offset[bna->pcidev.pci_func].page_addr;
+       bna->regs.fn_int_status = bna->pcidev.pci_bar_kva +
+                               reg_offset[bna->pcidev.pci_func].fn_int_status;
+       bna->regs.fn_int_mask = bna->pcidev.pci_bar_kva +
+                               reg_offset[bna->pcidev.pci_func].fn_int_mask;
+
+       if (bna->pcidev.pci_func < 3)
+               bna->port_num = 0;
+       else
+               bna->port_num = 1;
+
+       /* Also initializes diag, cee, sfp, phy_port and mbox_mod */
+       bna_device_init(&bna->device, bna, res_info);
+
+       bna_port_init(&bna->port, bna);
+
+       bna_tx_mod_init(&bna->tx_mod, bna, res_info);
+
+       bna_rx_mod_init(&bna->rx_mod, bna, res_info);
+
+       bna_ib_mod_init(&bna->ib_mod, bna, res_info);
+
+       bna_rit_mod_init(&bna->rit_mod, res_info);
+
+       bna_ucam_mod_init(&bna->ucam_mod, bna, res_info);
+
+       bna_mcam_mod_init(&bna->mcam_mod, bna, res_info);
+
+       bna->rxf_default_id = BFI_MAX_RXF;
+       bna->rxf_promisc_id = BFI_MAX_RXF;
+
+       /* Mbox q element for posting stat request to f/w */
+       bfa_q_qe_init(&bna->mbox_qe.qe);
+}
+
+void
+bna_uninit(struct bna *bna)
+{
+       bna_mcam_mod_uninit(&bna->mcam_mod);
+
+       bna_ucam_mod_uninit(&bna->ucam_mod);
+
+       bna_rit_mod_uninit(&bna->rit_mod);
+
+       bna_ib_mod_uninit(&bna->ib_mod);
+
+       bna_rx_mod_uninit(&bna->rx_mod);
+
+       bna_tx_mod_uninit(&bna->tx_mod);
+
+       bna_port_uninit(&bna->port);
+
+       bna_device_uninit(&bna->device);
+
+       bna->bnad = NULL;
+}
+
+struct bna_mac *
+bna_ucam_mod_mac_get(struct bna_ucam_mod *ucam_mod)
+{
+       struct list_head *qe;
+
+       if (list_empty(&ucam_mod->free_q))
+               return NULL;
+
+       bfa_q_deq(&ucam_mod->free_q, &qe);
+
+       return (struct bna_mac *)qe;
+}
+
+void
+bna_ucam_mod_mac_put(struct bna_ucam_mod *ucam_mod, struct bna_mac *mac)
+{
+       list_add_tail(&mac->qe, &ucam_mod->free_q);
+}
+
+struct bna_mac *
+bna_mcam_mod_mac_get(struct bna_mcam_mod *mcam_mod)
+{
+       struct list_head *qe;
+
+       if (list_empty(&mcam_mod->free_q))
+               return NULL;
+
+       bfa_q_deq(&mcam_mod->free_q, &qe);
+
+       return (struct bna_mac *)qe;
+}
+
+void
+bna_mcam_mod_mac_put(struct bna_mcam_mod *mcam_mod, struct bna_mac *mac)
+{
+       list_add_tail(&mac->qe, &mcam_mod->free_q);
+}
+
+/**
+ * Note: This should be called in the same locking context as the call to
+ * bna_rit_mod_seg_get()
+ */
+int
+bna_rit_mod_can_satisfy(struct bna_rit_mod *rit_mod, int seg_size)
+{
+       int i;
+
+       /* Select the pool for seg_size */
+       for (i = 0; i < BFI_RIT_SEG_TOTAL_POOLS; i++) {
+               if (seg_size <= ritseg_pool_cfg[i].pool_entry_size)
+                       break;
+       }
+
+       if (i == BFI_RIT_SEG_TOTAL_POOLS)
+               return 0;
+
+       if (list_empty(&rit_mod->rit_seg_pool[i]))
+               return 0;
+
+       return 1;
+}
+
+struct bna_rit_segment *
+bna_rit_mod_seg_get(struct bna_rit_mod *rit_mod, int seg_size)
+{
+       struct bna_rit_segment *seg;
+       struct list_head *qe;
+       int i;
+
+       /* Select the pool for seg_size */
+       for (i = 0; i < BFI_RIT_SEG_TOTAL_POOLS; i++) {
+               if (seg_size <= ritseg_pool_cfg[i].pool_entry_size)
+                       break;
+       }
+
+       if (i == BFI_RIT_SEG_TOTAL_POOLS)
+               return NULL;
+
+       if (list_empty(&rit_mod->rit_seg_pool[i]))
+               return NULL;
+
+       bfa_q_deq(&rit_mod->rit_seg_pool[i], &qe);
+       seg = (struct bna_rit_segment *)qe;
+       bfa_q_qe_init(&seg->qe);
+       seg->rit_size = seg_size;
+
+       return seg;
+}
+
+void
+bna_rit_mod_seg_put(struct bna_rit_mod *rit_mod,
+                       struct bna_rit_segment *seg)
+{
+       int i;
+
+       /* Select the pool for seg->max_rit_size */
+       for (i = 0; i < BFI_RIT_SEG_TOTAL_POOLS; i++) {
+               if (seg->max_rit_size == ritseg_pool_cfg[i].pool_entry_size)
+                       break;
+       }
+
+       seg->rit_size = 0;
+       list_add_tail(&seg->qe, &rit_mod->rit_seg_pool[i]);
+}
diff --git a/drivers/net/bna/bna_hw.h b/drivers/net/bna/bna_hw.h
new file mode 100644 (file)
index 0000000..67eb376
--- /dev/null
@@ -0,0 +1,1491 @@
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * 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.
+ */
+/*
+ * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * File for interrupt macros and functions
+ */
+
+#ifndef __BNA_HW_H__
+#define __BNA_HW_H__
+
+#include "bfi_ctreg.h"
+
+/**
+ *
+ * SW imposed limits
+ *
+ */
+
+#ifndef BNA_BIOS_BUILD
+
+#define BFI_MAX_TXQ                    64
+#define BFI_MAX_RXQ                    64
+#define        BFI_MAX_RXF                     64
+#define BFI_MAX_IB                     128
+#define        BFI_MAX_RIT_SIZE                256
+#define        BFI_RSS_RIT_SIZE                64
+#define        BFI_NONRSS_RIT_SIZE             1
+#define BFI_MAX_UCMAC                  256
+#define BFI_MAX_MCMAC                  512
+#define BFI_IBIDX_SIZE                 4
+#define BFI_MAX_VLAN                   4095
+
+/**
+ * There are 2 free IB index pools:
+ *     pool1: 120 segments of 1 index each
+ *     pool8: 1 segment of 8 indexes
+ */
+#define BFI_IBIDX_POOL1_SIZE           116
+#define        BFI_IBIDX_POOL1_ENTRY_SIZE      1
+#define BFI_IBIDX_POOL2_SIZE           2
+#define        BFI_IBIDX_POOL2_ENTRY_SIZE      2
+#define        BFI_IBIDX_POOL8_SIZE            1
+#define        BFI_IBIDX_POOL8_ENTRY_SIZE      8
+#define        BFI_IBIDX_TOTAL_POOLS           3
+#define        BFI_IBIDX_TOTAL_SEGS            119 /* (POOL1 + POOL2 + POOL8)_SIZE */
+#define        BFI_IBIDX_MAX_SEGSIZE           8
+#define init_ibidx_pool(name)                                          \
+static struct bna_ibidx_pool name[BFI_IBIDX_TOTAL_POOLS] =             \
+{                                                                      \
+       { BFI_IBIDX_POOL1_SIZE, BFI_IBIDX_POOL1_ENTRY_SIZE },           \
+       { BFI_IBIDX_POOL2_SIZE, BFI_IBIDX_POOL2_ENTRY_SIZE },           \
+       { BFI_IBIDX_POOL8_SIZE, BFI_IBIDX_POOL8_ENTRY_SIZE }            \
+}
+
+/**
+ * There are 2 free RIT segment pools:
+ *     Pool1: 192 segments of 1 RIT entry each
+ *     Pool2: 1 segment of 64 RIT entry
+ */
+#define BFI_RIT_SEG_POOL1_SIZE         192
+#define BFI_RIT_SEG_POOL1_ENTRY_SIZE   1
+#define BFI_RIT_SEG_POOLRSS_SIZE       1
+#define BFI_RIT_SEG_POOLRSS_ENTRY_SIZE 64
+#define BFI_RIT_SEG_TOTAL_POOLS                2
+#define BFI_RIT_TOTAL_SEGS             193 /* POOL1_SIZE + POOLRSS_SIZE */
+#define init_ritseg_pool(name)                                         \
+static struct bna_ritseg_pool_cfg name[BFI_RIT_SEG_TOTAL_POOLS] =      \
+{                                                                      \
+       { BFI_RIT_SEG_POOL1_SIZE, BFI_RIT_SEG_POOL1_ENTRY_SIZE },       \
+       { BFI_RIT_SEG_POOLRSS_SIZE, BFI_RIT_SEG_POOLRSS_ENTRY_SIZE }    \
+}
+
+#else /* BNA_BIOS_BUILD */
+
+#define BFI_MAX_TXQ                    1
+#define BFI_MAX_RXQ                    1
+#define        BFI_MAX_RXF                     1
+#define BFI_MAX_IB                     2
+#define        BFI_MAX_RIT_SIZE                2
+#define        BFI_RSS_RIT_SIZE                64
+#define        BFI_NONRSS_RIT_SIZE             1
+#define BFI_MAX_UCMAC                  1
+#define BFI_MAX_MCMAC                  8
+#define BFI_IBIDX_SIZE                 4
+#define BFI_MAX_VLAN                   4095
+/* There is one free pool: 2 segments of 1 index each */
+#define BFI_IBIDX_POOL1_SIZE           2
+#define        BFI_IBIDX_POOL1_ENTRY_SIZE      1
+#define        BFI_IBIDX_TOTAL_POOLS           1
+#define        BFI_IBIDX_TOTAL_SEGS            2 /* POOL1_SIZE */
+#define        BFI_IBIDX_MAX_SEGSIZE           1
+#define init_ibidx_pool(name)                                          \
+static struct bna_ibidx_pool name[BFI_IBIDX_TOTAL_POOLS] =             \
+{                                                                      \
+       { BFI_IBIDX_POOL1_SIZE, BFI_IBIDX_POOL1_ENTRY_SIZE }            \
+}
+
+#define BFI_RIT_SEG_POOL1_SIZE         1
+#define BFI_RIT_SEG_POOL1_ENTRY_SIZE   1
+#define BFI_RIT_SEG_TOTAL_POOLS                1
+#define BFI_RIT_TOTAL_SEGS             1 /* POOL1_SIZE */
+#define init_ritseg_pool(name)                                         \
+static struct bna_ritseg_pool_cfg name[BFI_RIT_SEG_TOTAL_POOLS] =      \
+{                                                                      \
+       { BFI_RIT_SEG_POOL1_SIZE, BFI_RIT_SEG_POOL1_ENTRY_SIZE }        \
+}
+
+#endif /* BNA_BIOS_BUILD */
+
+#define BFI_RSS_HASH_KEY_LEN           10
+
+#define BFI_COALESCING_TIMER_UNIT      5       /* 5us */
+#define BFI_MAX_COALESCING_TIMEO       0xFF    /* in 5us units */
+#define BFI_MAX_INTERPKT_COUNT         0xFF
+#define BFI_MAX_INTERPKT_TIMEO         0xF     /* in 0.5us units */
+#define BFI_TX_COALESCING_TIMEO                20      /* 20 * 5 = 100us */
+#define BFI_TX_INTERPKT_COUNT          32
+#define        BFI_RX_COALESCING_TIMEO         12      /* 12 * 5 = 60us */
+#define        BFI_RX_INTERPKT_COUNT           6       /* Pkt Cnt = 6 */
+#define        BFI_RX_INTERPKT_TIMEO           3       /* 3 * 0.5 = 1.5us */
+
+#define BFI_TXQ_WI_SIZE                        64      /* bytes */
+#define BFI_RXQ_WI_SIZE                        8       /* bytes */
+#define BFI_CQ_WI_SIZE                 16      /* bytes */
+#define BFI_TX_MAX_WRR_QUOTA           0xFFF
+
+#define BFI_TX_MAX_VECTORS_PER_WI      4
+#define BFI_TX_MAX_VECTORS_PER_PKT     0xFF
+#define BFI_TX_MAX_DATA_PER_VECTOR     0xFFFF
+#define BFI_TX_MAX_DATA_PER_PKT                0xFFFFFF
+
+/* Small Q buffer size */
+#define BFI_SMALL_RXBUF_SIZE           128
+
+/* Defined separately since BFA_FLASH_DMA_BUF_SZ is in bfa_flash.c */
+#define BFI_FLASH_DMA_BUF_SZ           0x010000 /* 64K DMA */
+#define BFI_HW_STATS_SIZE              0x4000 /* 16K DMA */
+
+/**
+ *
+ * HW register offsets, macros
+ *
+ */
+
+/* DMA Block Register Host Window Start Address */
+#define DMA_BLK_REG_ADDR               0x00013000
+
+/* DMA Block Internal Registers */
+#define DMA_CTRL_REG0                  (DMA_BLK_REG_ADDR + 0x000)
+#define DMA_CTRL_REG1                  (DMA_BLK_REG_ADDR + 0x004)
+#define DMA_ERR_INT_STATUS             (DMA_BLK_REG_ADDR + 0x008)
+#define DMA_ERR_INT_ENABLE             (DMA_BLK_REG_ADDR + 0x00c)
+#define DMA_ERR_INT_STATUS_SET         (DMA_BLK_REG_ADDR + 0x010)
+
+/* APP Block Register Address Offset from BAR0 */
+#define APP_BLK_REG_ADDR               0x00014000
+
+/* Host Function Interrupt Mask Registers */
+#define HOSTFN0_INT_MASK               (APP_BLK_REG_ADDR + 0x004)
+#define HOSTFN1_INT_MASK               (APP_BLK_REG_ADDR + 0x104)
+#define HOSTFN2_INT_MASK               (APP_BLK_REG_ADDR + 0x304)
+#define HOSTFN3_INT_MASK               (APP_BLK_REG_ADDR + 0x404)
+
+/**
+ * Host Function PCIe Error Registers
+ * Duplicates "Correctable" & "Uncorrectable"
+ * registers in PCIe Config space.
+ */
+#define FN0_PCIE_ERR_REG               (APP_BLK_REG_ADDR + 0x014)
+#define FN1_PCIE_ERR_REG               (APP_BLK_REG_ADDR + 0x114)
+#define FN2_PCIE_ERR_REG               (APP_BLK_REG_ADDR + 0x314)
+#define FN3_PCIE_ERR_REG               (APP_BLK_REG_ADDR + 0x414)
+
+/* Host Function Error Type Status Registers */
+#define FN0_ERR_TYPE_STATUS_REG                (APP_BLK_REG_ADDR + 0x018)
+#define FN1_ERR_TYPE_STATUS_REG                (APP_BLK_REG_ADDR + 0x118)
+#define FN2_ERR_TYPE_STATUS_REG                (APP_BLK_REG_ADDR + 0x318)
+#define FN3_ERR_TYPE_STATUS_REG                (APP_BLK_REG_ADDR + 0x418)
+
+/* Host Function Error Type Mask Registers */
+#define FN0_ERR_TYPE_MSK_STATUS_REG    (APP_BLK_REG_ADDR + 0x01c)
+#define FN1_ERR_TYPE_MSK_STATUS_REG    (APP_BLK_REG_ADDR + 0x11c)
+#define FN2_ERR_TYPE_MSK_STATUS_REG    (APP_BLK_REG_ADDR + 0x31c)
+#define FN3_ERR_TYPE_MSK_STATUS_REG    (APP_BLK_REG_ADDR + 0x41c)
+
+/* Catapult Host Semaphore Status Registers (App block) */
+#define HOST_SEM_STS0_REG              (APP_BLK_REG_ADDR + 0x630)
+#define HOST_SEM_STS1_REG              (APP_BLK_REG_ADDR + 0x634)
+#define HOST_SEM_STS2_REG              (APP_BLK_REG_ADDR + 0x638)
+#define HOST_SEM_STS3_REG              (APP_BLK_REG_ADDR + 0x63c)
+#define HOST_SEM_STS4_REG              (APP_BLK_REG_ADDR + 0x640)
+#define HOST_SEM_STS5_REG              (APP_BLK_REG_ADDR + 0x644)
+#define HOST_SEM_STS6_REG              (APP_BLK_REG_ADDR + 0x648)
+#define HOST_SEM_STS7_REG              (APP_BLK_REG_ADDR + 0x64c)
+
+/* PCIe Misc Register */
+#define PCIE_MISC_REG                  (APP_BLK_REG_ADDR + 0x200)
+
+/* Temp Sensor Control Registers */
+#define TEMPSENSE_CNTL_REG             (APP_BLK_REG_ADDR + 0x250)
+#define TEMPSENSE_STAT_REG             (APP_BLK_REG_ADDR + 0x254)
+
+/* APP Block local error registers */
+#define APP_LOCAL_ERR_STAT             (APP_BLK_REG_ADDR + 0x258)
+#define APP_LOCAL_ERR_MSK              (APP_BLK_REG_ADDR + 0x25c)
+
+/* PCIe Link Error registers */
+#define PCIE_LNK_ERR_STAT              (APP_BLK_REG_ADDR + 0x260)
+#define PCIE_LNK_ERR_MSK               (APP_BLK_REG_ADDR + 0x264)
+
+/**
+ * FCoE/FIP Ethertype Register
+ * 31:16 -- Chip wide value for FIP type
+ * 15:0  -- Chip wide value for FCoE type
+ */
+#define FCOE_FIP_ETH_TYPE              (APP_BLK_REG_ADDR + 0x280)
+
+/**
+ * Reserved Ethertype Register
+ * 31:16 -- Reserved
+ * 15:0  -- Other ethertype
+ */
+#define RESV_ETH_TYPE                  (APP_BLK_REG_ADDR + 0x284)
+
+/**
+ * Host Command Status Registers
+ * Each set consists of 3 registers :
+ * clear, set, cmd
+ * 16 such register sets in all
+ * See catapult_spec.pdf for detailed functionality
+ * Put each type in a single macro accessed by _num ?
+ */
+#define HOST_CMDSTS0_CLR_REG           (APP_BLK_REG_ADDR + 0x500)
+#define HOST_CMDSTS0_SET_REG           (APP_BLK_REG_ADDR + 0x504)
+#define HOST_CMDSTS0_REG               (APP_BLK_REG_ADDR + 0x508)
+#define HOST_CMDSTS1_CLR_REG           (APP_BLK_REG_ADDR + 0x510)
+#define HOST_CMDSTS1_SET_REG           (APP_BLK_REG_ADDR + 0x514)
+#define HOST_CMDSTS1_REG               (APP_BLK_REG_ADDR + 0x518)
+#define HOST_CMDSTS2_CLR_REG           (APP_BLK_REG_ADDR + 0x520)
+#define HOST_CMDSTS2_SET_REG           (APP_BLK_REG_ADDR + 0x524)
+#define HOST_CMDSTS2_REG               (APP_BLK_REG_ADDR + 0x528)
+#define HOST_CMDSTS3_CLR_REG           (APP_BLK_REG_ADDR + 0x530)
+#define HOST_CMDSTS3_SET_REG           (APP_BLK_REG_ADDR + 0x534)
+#define HOST_CMDSTS3_REG               (APP_BLK_REG_ADDR + 0x538)
+#define HOST_CMDSTS4_CLR_REG           (APP_BLK_REG_ADDR + 0x540)
+#define HOST_CMDSTS4_SET_REG           (APP_BLK_REG_ADDR + 0x544)
+#define HOST_CMDSTS4_REG               (APP_BLK_REG_ADDR + 0x548)
+#define HOST_CMDSTS5_CLR_REG           (APP_BLK_REG_ADDR + 0x550)
+#define HOST_CMDSTS5_SET_REG           (APP_BLK_REG_ADDR + 0x554)
+#define HOST_CMDSTS5_REG               (APP_BLK_REG_ADDR + 0x558)
+#define HOST_CMDSTS6_CLR_REG           (APP_BLK_REG_ADDR + 0x560)
+#define HOST_CMDSTS6_SET_REG           (APP_BLK_REG_ADDR + 0x564)
+#define HOST_CMDSTS6_REG               (APP_BLK_REG_ADDR + 0x568)
+#define HOST_CMDSTS7_CLR_REG           (APP_BLK_REG_ADDR + 0x570)
+#define HOST_CMDSTS7_SET_REG           (APP_BLK_REG_ADDR + 0x574)
+#define HOST_CMDSTS7_REG               (APP_BLK_REG_ADDR + 0x578)
+#define HOST_CMDSTS8_CLR_REG           (APP_BLK_REG_ADDR + 0x580)
+#define HOST_CMDSTS8_SET_REG           (APP_BLK_REG_ADDR + 0x584)
+#define HOST_CMDSTS8_REG               (APP_BLK_REG_ADDR + 0x588)
+#define HOST_CMDSTS9_CLR_REG           (APP_BLK_REG_ADDR + 0x590)
+#define HOST_CMDSTS9_SET_REG           (APP_BLK_REG_ADDR + 0x594)
+#define HOST_CMDSTS9_REG               (APP_BLK_REG_ADDR + 0x598)
+#define HOST_CMDSTS10_CLR_REG          (APP_BLK_REG_ADDR + 0x5A0)
+#define HOST_CMDSTS10_SET_REG          (APP_BLK_REG_ADDR + 0x5A4)
+#define HOST_CMDSTS10_REG              (APP_BLK_REG_ADDR + 0x5A8)
+#define HOST_CMDSTS11_CLR_REG          (APP_BLK_REG_ADDR + 0x5B0)
+#define HOST_CMDSTS11_SET_REG          (APP_BLK_REG_ADDR + 0x5B4)
+#define HOST_CMDSTS11_REG              (APP_BLK_REG_ADDR + 0x5B8)
+#define HOST_CMDSTS12_CLR_REG          (APP_BLK_REG_ADDR + 0x5C0)
+#define HOST_CMDSTS12_SET_REG          (APP_BLK_REG_ADDR + 0x5C4)
+#define HOST_CMDSTS12_REG              (APP_BLK_REG_ADDR + 0x5C8)
+#define HOST_CMDSTS13_CLR_REG          (APP_BLK_REG_ADDR + 0x5D0)
+#define HOST_CMDSTS13_SET_REG          (APP_BLK_REG_ADDR + 0x5D4)
+#define HOST_CMDSTS13_REG              (APP_BLK_REG_ADDR + 0x5D8)
+#define HOST_CMDSTS14_CLR_REG          (APP_BLK_REG_ADDR + 0x5E0)
+#define HOST_CMDSTS14_SET_REG          (APP_BLK_REG_ADDR + 0x5E4)
+#define HOST_CMDSTS14_REG              (APP_BLK_REG_ADDR + 0x5E8)
+#define HOST_CMDSTS15_CLR_REG          (APP_BLK_REG_ADDR + 0x5F0)
+#define HOST_CMDSTS15_SET_REG          (APP_BLK_REG_ADDR + 0x5F4)
+#define HOST_CMDSTS15_REG              (APP_BLK_REG_ADDR + 0x5F8)
+
+/**
+ * LPU0 Block Register Address Offset from BAR0
+ * Range 0x18000 - 0x18033
+ */
+#define LPU0_BLK_REG_ADDR              0x00018000
+
+/**
+ * LPU0 Registers
+ * Should they be directly used from host,
+ * except for diagnostics ?
+ * CTL_REG : Control register
+ * CMD_REG : Triggers exec. of cmd. in
+ *           Mailbox memory
+ */
+#define LPU0_MBOX_CTL_REG              (LPU0_BLK_REG_ADDR + 0x000)
+#define LPU0_MBOX_CMD_REG              (LPU0_BLK_REG_ADDR + 0x004)
+#define LPU0_MBOX_LINK_0REG            (LPU0_BLK_REG_ADDR + 0x008)
+#define LPU1_MBOX_LINK_0REG            (LPU0_BLK_REG_ADDR + 0x00c)
+#define LPU0_MBOX_STATUS_0REG          (LPU0_BLK_REG_ADDR + 0x010)
+#define LPU1_MBOX_STATUS_0REG          (LPU0_BLK_REG_ADDR + 0x014)
+#define LPU0_ERR_STATUS_REG            (LPU0_BLK_REG_ADDR + 0x018)
+#define LPU0_ERR_SET_REG               (LPU0_BLK_REG_ADDR + 0x020)
+
+/**
+ * LPU1 Block Register Address Offset from BAR0
+ * Range 0x18400 - 0x18433
+ */
+#define LPU1_BLK_REG_ADDR              0x00018400
+
+/**
+ * LPU1 Registers
+ * Same as LPU0 registers above
+ */
+#define LPU1_MBOX_CTL_REG              (LPU1_BLK_REG_ADDR + 0x000)
+#define LPU1_MBOX_CMD_REG              (LPU1_BLK_REG_ADDR + 0x004)
+#define LPU0_MBOX_LINK_1REG            (LPU1_BLK_REG_ADDR + 0x008)
+#define LPU1_MBOX_LINK_1REG            (LPU1_BLK_REG_ADDR + 0x00c)
+#define LPU0_MBOX_STATUS_1REG          (LPU1_BLK_REG_ADDR + 0x010)
+#define LPU1_MBOX_STATUS_1REG          (LPU1_BLK_REG_ADDR + 0x014)
+#define LPU1_ERR_STATUS_REG            (LPU1_BLK_REG_ADDR + 0x018)
+#define LPU1_ERR_SET_REG               (LPU1_BLK_REG_ADDR + 0x020)
+
+/**
+ * PSS Block Register Address Offset from BAR0
+ * Range 0x18800 - 0x188DB
+ */
+#define PSS_BLK_REG_ADDR               0x00018800
+
+/**
+ * PSS Registers
+ * For details, see catapult_spec.pdf
+ * ERR_STATUS_REG : Indicates error in PSS module
+ * RAM_ERR_STATUS_REG : Indicates RAM module that detected error
+ */
+#define ERR_STATUS_SET                 (PSS_BLK_REG_ADDR + 0x018)
+#define PSS_RAM_ERR_STATUS_REG         (PSS_BLK_REG_ADDR + 0x01C)
+
+/**
+ * PSS Semaphore Lock Registers, total 16
+ * First read when unlocked returns 0,
+ * and is set to 1, atomically.
+ * Subsequent reads returns 1.
+ * To clear set the value to 0.
+ * Range : 0x20 to 0x5c
+ */
+#define PSS_SEM_LOCK_REG(_num)                 \
+       (PSS_BLK_REG_ADDR + 0x020 + ((_num) << 2))
+
+/**
+ * PSS Semaphore Status Registers,
+ * corresponding to the lock registers above
+ */
+#define PSS_SEM_STATUS_REG(_num)               \
+       (PSS_BLK_REG_ADDR + 0x060 + ((_num) << 2))
+
+/**
+ * Catapult CPQ Registers
+ * Defines for Mailbox Registers
+ * Used to send mailbox commands to firmware from
+ * host. The data part is written to the MBox
+ * memory, registers are used to indicate that
+ * a commnad is resident in memory.
+ *
+ * Note : LPU0<->LPU1 mailboxes are not listed here
+ */
+#define CPQ_BLK_REG_ADDR               0x00019000
+
+#define HOSTFN0_LPU0_MBOX1_CMD_STAT    (CPQ_BLK_REG_ADDR + 0x130)
+#define HOSTFN0_LPU1_MBOX1_CMD_STAT    (CPQ_BLK_REG_ADDR + 0x134)
+#define LPU0_HOSTFN0_MBOX1_CMD_STAT    (CPQ_BLK_REG_ADDR + 0x138)
+#define LPU1_HOSTFN0_MBOX1_CMD_STAT    (CPQ_BLK_REG_ADDR + 0x13C)
+
+#define HOSTFN1_LPU0_MBOX1_CMD_STAT    (CPQ_BLK_REG_ADDR + 0x140)
+#define HOSTFN1_LPU1_MBOX1_CMD_STAT    (CPQ_BLK_REG_ADDR + 0x144)
+#define LPU0_HOSTFN1_MBOX1_CMD_STAT    (CPQ_BLK_REG_ADDR + 0x148)
+#define LPU1_HOSTFN1_MBOX1_CMD_STAT    (CPQ_BLK_REG_ADDR + 0x14C)
+
+#define HOSTFN2_LPU0_MBOX1_CMD_STAT    (CPQ_BLK_REG_ADDR + 0x170)
+#define HOSTFN2_LPU1_MBOX1_CMD_STAT    (CPQ_BLK_REG_ADDR + 0x174)
+#define LPU0_HOSTFN2_MBOX1_CMD_STAT    (CPQ_BLK_REG_ADDR + 0x178)
+#define LPU1_HOSTFN2_MBOX1_CMD_STAT    (CPQ_BLK_REG_ADDR + 0x17C)
+
+#define HOSTFN3_LPU0_MBOX1_CMD_STAT    (CPQ_BLK_REG_ADDR + 0x180)
+#define HOSTFN3_LPU1_MBOX1_CMD_STAT    (CPQ_BLK_REG_ADDR + 0x184)
+#define LPU0_HOSTFN3_MBOX1_CMD_STAT    (CPQ_BLK_REG_ADDR + 0x188)
+#define LPU1_HOSTFN3_MBOX1_CMD_STAT    (CPQ_BLK_REG_ADDR + 0x18C)
+
+/* Host Function Force Parity Error Registers */
+#define HOSTFN0_LPU_FORCE_PERR         (CPQ_BLK_REG_ADDR + 0x120)
+#define HOSTFN1_LPU_FORCE_PERR         (CPQ_BLK_REG_ADDR + 0x124)
+#define HOSTFN2_LPU_FORCE_PERR         (CPQ_BLK_REG_ADDR + 0x128)
+#define HOSTFN3_LPU_FORCE_PERR         (CPQ_BLK_REG_ADDR + 0x12C)
+
+/* LL Port[0|1] Halt Mask Registers */
+#define LL_HALT_MSK_P0                 (CPQ_BLK_REG_ADDR + 0x1A0)
+#define LL_HALT_MSK_P1                 (CPQ_BLK_REG_ADDR + 0x1B0)
+
+/* LL Port[0|1] Error Mask Registers */
+#define LL_ERR_MSK_P0                  (CPQ_BLK_REG_ADDR + 0x1D0)
+#define LL_ERR_MSK_P1                  (CPQ_BLK_REG_ADDR + 0x1D4)
+
+/* EMC FLI (Flash Controller) Block Register Address Offset from BAR0 */
+#define FLI_BLK_REG_ADDR               0x0001D000
+
+/* EMC FLI Registers */
+#define FLI_CMD_REG                    (FLI_BLK_REG_ADDR + 0x000)
+#define FLI_ADDR_REG                   (FLI_BLK_REG_ADDR + 0x004)
+#define FLI_CTL_REG                    (FLI_BLK_REG_ADDR + 0x008)
+#define FLI_WRDATA_REG                 (FLI_BLK_REG_ADDR + 0x00C)
+#define FLI_RDDATA_REG                 (FLI_BLK_REG_ADDR + 0x010)
+#define FLI_DEV_STATUS_REG             (FLI_BLK_REG_ADDR + 0x014)
+#define FLI_SIG_WD_REG                 (FLI_BLK_REG_ADDR + 0x018)
+
+/**
+ * RO register
+ * 31:16 -- Vendor Id
+ * 15:0  -- Device Id
+ */
+#define FLI_DEV_VENDOR_REG             (FLI_BLK_REG_ADDR + 0x01C)
+#define FLI_ERR_STATUS_REG             (FLI_BLK_REG_ADDR + 0x020)
+
+/**
+ * RAD (RxAdm) Block Register Address Offset from BAR0
+ * RAD0 Range : 0x20000 - 0x203FF
+ * RAD1 Range : 0x20400 - 0x207FF
+ */
+#define RAD0_BLK_REG_ADDR              0x00020000
+#define RAD1_BLK_REG_ADDR              0x00020400
+
+/* RAD0 Registers */
+#define RAD0_CTL_REG                   (RAD0_BLK_REG_ADDR + 0x000)
+#define RAD0_PE_PARM_REG               (RAD0_BLK_REG_ADDR + 0x004)
+#define RAD0_BCN_REG                   (RAD0_BLK_REG_ADDR + 0x008)
+
+/* Default function ID register */
+#define RAD0_DEFAULT_REG               (RAD0_BLK_REG_ADDR + 0x00C)
+
+/* Default promiscuous ID register */
+#define RAD0_PROMISC_REG               (RAD0_BLK_REG_ADDR + 0x010)
+
+#define RAD0_BCNQ_REG                  (RAD0_BLK_REG_ADDR + 0x014)
+
+/*
+ * This register selects 1 of 8 PM Q's using
+ * VLAN pri, for non-BCN packets without a VLAN tag
+ */
+#define RAD0_DEFAULTQ_REG              (RAD0_BLK_REG_ADDR + 0x018)
+
+#define RAD0_ERR_STS                   (RAD0_BLK_REG_ADDR + 0x01C)
+#define RAD0_SET_ERR_STS               (RAD0_BLK_REG_ADDR + 0x020)
+#define RAD0_ERR_INT_EN                        (RAD0_BLK_REG_ADDR + 0x024)
+#define RAD0_FIRST_ERR                 (RAD0_BLK_REG_ADDR + 0x028)
+#define RAD0_FORCE_ERR                 (RAD0_BLK_REG_ADDR + 0x02C)
+
+#define RAD0_IF_RCVD                   (RAD0_BLK_REG_ADDR + 0x030)
+#define RAD0_IF_RCVD_OCTETS_HIGH       (RAD0_BLK_REG_ADDR + 0x034)
+#define RAD0_IF_RCVD_OCTETS_LOW                (RAD0_BLK_REG_ADDR + 0x038)
+#define RAD0_IF_RCVD_VLAN              (RAD0_BLK_REG_ADDR + 0x03C)
+#define RAD0_IF_RCVD_UCAST             (RAD0_BLK_REG_ADDR + 0x040)
+#define RAD0_IF_RCVD_UCAST_OCTETS_HIGH (RAD0_BLK_REG_ADDR + 0x044)
+#define RAD0_IF_RCVD_UCAST_OCTETS_LOW   (RAD0_BLK_REG_ADDR + 0x048)
+#define RAD0_IF_RCVD_UCAST_VLAN                (RAD0_BLK_REG_ADDR + 0x04C)
+#define RAD0_IF_RCVD_MCAST             (RAD0_BLK_REG_ADDR + 0x050)
+#define RAD0_IF_RCVD_MCAST_OCTETS_HIGH  (RAD0_BLK_REG_ADDR + 0x054)
+#define RAD0_IF_RCVD_MCAST_OCTETS_LOW   (RAD0_BLK_REG_ADDR + 0x058)
+#define RAD0_IF_RCVD_MCAST_VLAN                (RAD0_BLK_REG_ADDR + 0x05C)
+#define RAD0_IF_RCVD_BCAST             (RAD0_BLK_REG_ADDR + 0x060)
+#define RAD0_IF_RCVD_BCAST_OCTETS_HIGH  (RAD0_BLK_REG_ADDR + 0x064)
+#define RAD0_IF_RCVD_BCAST_OCTETS_LOW   (RAD0_BLK_REG_ADDR + 0x068)
+#define RAD0_IF_RCVD_BCAST_VLAN                (RAD0_BLK_REG_ADDR + 0x06C)
+#define RAD0_DROPPED_FRAMES            (RAD0_BLK_REG_ADDR + 0x070)
+
+#define RAD0_MAC_MAN_1H                        (RAD0_BLK_REG_ADDR + 0x080)
+#define RAD0_MAC_MAN_1L                        (RAD0_BLK_REG_ADDR + 0x084)
+#define RAD0_MAC_MAN_2H                        (RAD0_BLK_REG_ADDR + 0x088)
+#define RAD0_MAC_MAN_2L                        (RAD0_BLK_REG_ADDR + 0x08C)
+#define RAD0_MAC_MAN_3H                        (RAD0_BLK_REG_ADDR + 0x090)
+#define RAD0_MAC_MAN_3L                        (RAD0_BLK_REG_ADDR + 0x094)
+#define RAD0_MAC_MAN_4H                        (RAD0_BLK_REG_ADDR + 0x098)
+#define RAD0_MAC_MAN_4L                        (RAD0_BLK_REG_ADDR + 0x09C)
+
+#define RAD0_LAST4_IP                  (RAD0_BLK_REG_ADDR + 0x100)
+
+/* RAD1 Registers */
+#define RAD1_CTL_REG                   (RAD1_BLK_REG_ADDR + 0x000)
+#define RAD1_PE_PARM_REG               (RAD1_BLK_REG_ADDR + 0x004)
+#define RAD1_BCN_REG                   (RAD1_BLK_REG_ADDR + 0x008)
+
+/* Default function ID register */
+#define RAD1_DEFAULT_REG               (RAD1_BLK_REG_ADDR + 0x00C)
+
+/* Promiscuous function ID register */
+#define RAD1_PROMISC_REG               (RAD1_BLK_REG_ADDR + 0x010)
+
+#define RAD1_BCNQ_REG                  (RAD1_BLK_REG_ADDR + 0x014)
+
+/*
+ * This register selects 1 of 8 PM Q's using
+ * VLAN pri, for non-BCN packets without a VLAN tag
+ */
+#define RAD1_DEFAULTQ_REG              (RAD1_BLK_REG_ADDR + 0x018)
+
+#define RAD1_ERR_STS                   (RAD1_BLK_REG_ADDR + 0x01C)
+#define RAD1_SET_ERR_STS               (RAD1_BLK_REG_ADDR + 0x020)
+#define RAD1_ERR_INT_EN                        (RAD1_BLK_REG_ADDR + 0x024)
+
+/**
+ * TXA Block Register Address Offset from BAR0
+ * TXA0 Range : 0x21000 - 0x213FF
+ * TXA1 Range : 0x21400 - 0x217FF
+ */
+#define TXA0_BLK_REG_ADDR              0x00021000
+#define TXA1_BLK_REG_ADDR              0x00021400
+
+/* TXA Registers */
+#define TXA0_CTRL_REG                  (TXA0_BLK_REG_ADDR + 0x000)
+#define TXA1_CTRL_REG                  (TXA1_BLK_REG_ADDR + 0x000)
+
+/**
+ * TSO Sequence # Registers (RO)
+ * Total 8 (for 8 queues)
+ * Holds the last seq.# for TSO frames
+ * See catapult_spec.pdf for more details
+ */
+#define TXA0_TSO_TCP_SEQ_REG(_num)             \
+       (TXA0_BLK_REG_ADDR + 0x020 + ((_num) << 2))
+
+#define TXA1_TSO_TCP_SEQ_REG(_num)             \
+       (TXA1_BLK_REG_ADDR + 0x020 + ((_num) << 2))
+
+/**
+ * TSO IP ID # Registers (RO)
+ * Total 8 (for 8 queues)
+ * Holds the last IP ID for TSO frames
+ * See catapult_spec.pdf for more details
+ */
+#define TXA0_TSO_IP_INFO_REG(_num)             \
+       (TXA0_BLK_REG_ADDR + 0x040 + ((_num) << 2))
+
+#define TXA1_TSO_IP_INFO_REG(_num)             \
+       (TXA1_BLK_REG_ADDR + 0x040 + ((_num) << 2))
+
+/**
+ * RXA Block Register Address Offset from BAR0
+ * RXA0 Range : 0x21800 - 0x21BFF
+ * RXA1 Range : 0x21C00 - 0x21FFF
+ */
+#define RXA0_BLK_REG_ADDR              0x00021800
+#define RXA1_BLK_REG_ADDR              0x00021C00
+
+/* RXA Registers */
+#define RXA0_CTL_REG                   (RXA0_BLK_REG_ADDR + 0x040)
+#define RXA1_CTL_REG                   (RXA1_BLK_REG_ADDR + 0x040)
+
+/**
+ * PPLB Block Register Address Offset from BAR0
+ * PPLB0 Range : 0x22000 - 0x223FF
+ * PPLB1 Range : 0x22400 - 0x227FF
+ */
+#define PLB0_BLK_REG_ADDR              0x00022000
+#define PLB1_BLK_REG_ADDR              0x00022400
+
+/**
+ * PLB Registers
+ * Holds RL timer used time stamps in RLT tagged frames
+ */
+#define PLB0_ECM_TIMER_REG             (PLB0_BLK_REG_ADDR + 0x05C)
+#define PLB1_ECM_TIMER_REG             (PLB1_BLK_REG_ADDR + 0x05C)
+
+/* Controls the rate-limiter on each of the priority class */
+#define PLB0_RL_CTL                    (PLB0_BLK_REG_ADDR + 0x060)
+#define PLB1_RL_CTL                    (PLB1_BLK_REG_ADDR + 0x060)
+
+/**
+ * Max byte register, total 8, 0-7
+ * see catapult_spec.pdf for details
+ */
+#define PLB0_RL_MAX_BC(_num)                   \
+       (PLB0_BLK_REG_ADDR + 0x064 + ((_num) << 2))
+#define PLB1_RL_MAX_BC(_num)                   \
+       (PLB1_BLK_REG_ADDR + 0x064 + ((_num) << 2))
+
+/**
+ * RL Time Unit Register for priority 0-7
+ * 4 bits per priority
+ * (2^rl_unit)*1us is the actual time period
+ */
+#define PLB0_RL_TU_PRIO                        (PLB0_BLK_REG_ADDR + 0x084)
+#define PLB1_RL_TU_PRIO                        (PLB1_BLK_REG_ADDR + 0x084)
+
+/**
+ * RL byte count register,
+ * bytes transmitted in (rl_unit*1)us time period
+ * 1 per priority, 8 in all, 0-7.
+ */
+#define PLB0_RL_BYTE_CNT(_num)                 \
+       (PLB0_BLK_REG_ADDR + 0x088 + ((_num) << 2))
+#define PLB1_RL_BYTE_CNT(_num)                 \
+       (PLB1_BLK_REG_ADDR + 0x088 + ((_num) << 2))
+
+/**
+ * RL Min factor register
+ * 2 bits per priority,
+ * 4 factors possible: 1, 0.5, 0.25, 0
+ * 2'b00 - 0; 2'b01 - 0.25; 2'b10 - 0.5; 2'b11 - 1
+ */
+#define PLB0_RL_MIN_REG                        (PLB0_BLK_REG_ADDR + 0x0A8)
+#define PLB1_RL_MIN_REG                        (PLB1_BLK_REG_ADDR + 0x0A8)
+
+/**
+ * RL Max factor register
+ * 2 bits per priority,
+ * 4 factors possible: 1, 0.5, 0.25, 0
+ * 2'b00 - 0; 2'b01 - 0.25; 2'b10 - 0.5; 2'b11 - 1
+ */
+#define PLB0_RL_MAX_REG                        (PLB0_BLK_REG_ADDR + 0x0AC)
+#define PLB1_RL_MAX_REG                        (PLB1_BLK_REG_ADDR + 0x0AC)
+
+/* MAC SERDES Address Paging register */
+#define PLB0_EMS_ADD_REG               (PLB0_BLK_REG_ADDR + 0xD0)
+#define PLB1_EMS_ADD_REG               (PLB1_BLK_REG_ADDR + 0xD0)
+
+/* LL EMS Registers */
+#define LL_EMS0_BLK_REG_ADDR           0x00026800
+#define LL_EMS1_BLK_REG_ADDR           0x00026C00
+
+/**
+ * BPC Block Register Address Offset from BAR0
+ * BPC0 Range : 0x23000 - 0x233FF
+ * BPC1 Range : 0x23400 - 0x237FF
+ */
+#define BPC0_BLK_REG_ADDR              0x00023000
+#define BPC1_BLK_REG_ADDR              0x00023400
+
+/**
+ * PMM Block Register Address Offset from BAR0
+ * PMM0 Range : 0x23800 - 0x23BFF
+ * PMM1 Range : 0x23C00 - 0x23FFF
+ */
+#define PMM0_BLK_REG_ADDR              0x00023800
+#define PMM1_BLK_REG_ADDR              0x00023C00
+
+/**
+ * HQM Block Register Address Offset from BAR0
+ * HQM0 Range : 0x24000 - 0x243FF
+ * HQM1 Range : 0x24400 - 0x247FF
+ */
+#define HQM0_BLK_REG_ADDR              0x00024000
+#define HQM1_BLK_REG_ADDR              0x00024400
+
+/**
+ * HQM Control Register
+ * Controls some aspects of IB
+ * See catapult_spec.pdf for details
+ */
+#define HQM0_CTL_REG                   (HQM0_BLK_REG_ADDR + 0x000)
+#define HQM1_CTL_REG                   (HQM1_BLK_REG_ADDR + 0x000)
+
+/**
+ * HQM Stop Q Semaphore Registers.
+ * Only one Queue resource can be stopped at
+ * any given time. This register controls access
+ * to the single stop Q resource.
+ * See catapult_spec.pdf for details
+ */
+#define HQM0_RXQ_STOP_SEM              (HQM0_BLK_REG_ADDR + 0x028)
+#define HQM0_TXQ_STOP_SEM              (HQM0_BLK_REG_ADDR + 0x02C)
+#define HQM1_RXQ_STOP_SEM              (HQM1_BLK_REG_ADDR + 0x028)
+#define HQM1_TXQ_STOP_SEM              (HQM1_BLK_REG_ADDR + 0x02C)
+
+/**
+ * LUT Block Register Address Offset from BAR0
+ * LUT0 Range : 0x25800 - 0x25BFF
+ * LUT1 Range : 0x25C00 - 0x25FFF
+ */
+#define LUT0_BLK_REG_ADDR              0x00025800
+#define LUT1_BLK_REG_ADDR              0x00025C00
+
+/**
+ * LUT Registers
+ * See catapult_spec.pdf for details
+ */
+#define LUT0_ERR_STS                   (LUT0_BLK_REG_ADDR + 0x000)
+#define LUT1_ERR_STS                   (LUT1_BLK_REG_ADDR + 0x000)
+#define LUT0_SET_ERR_STS               (LUT0_BLK_REG_ADDR + 0x004)
+#define LUT1_SET_ERR_STS               (LUT1_BLK_REG_ADDR + 0x004)
+
+/**
+ * TRC (Debug/Trace) Register Offset from BAR0
+ * Range : 0x26000 -- 0x263FFF
+ */
+#define TRC_BLK_REG_ADDR               0x00026000
+
+/**
+ * TRC Registers
+ * See catapult_spec.pdf for details of each
+ */
+#define TRC_CTL_REG                    (TRC_BLK_REG_ADDR + 0x000)
+#define TRC_MODS_REG                   (TRC_BLK_REG_ADDR + 0x004)
+#define TRC_TRGC_REG                   (TRC_BLK_REG_ADDR + 0x008)
+#define TRC_CNT1_REG                   (TRC_BLK_REG_ADDR + 0x010)
+#define TRC_CNT2_REG                   (TRC_BLK_REG_ADDR + 0x014)
+#define TRC_NXTS_REG                   (TRC_BLK_REG_ADDR + 0x018)
+#define TRC_DIRR_REG                   (TRC_BLK_REG_ADDR + 0x01C)
+
+/**
+ * TRC Trigger match filters, total 10
+ * Determines the trigger condition
+ */
+#define TRC_TRGM_REG(_num)             \
+       (TRC_BLK_REG_ADDR + 0x040 + ((_num) << 2))
+
+/**
+ * TRC Next State filters, total 10
+ * Determines the next state conditions
+ */
+#define TRC_NXTM_REG(_num)             \
+       (TRC_BLK_REG_ADDR + 0x080 + ((_num) << 2))
+
+/**
+ * TRC Store Match filters, total 10
+ * Determines the store conditions
+ */
+#define TRC_STRM_REG(_num)             \
+       (TRC_BLK_REG_ADDR + 0x0C0 + ((_num) << 2))
+
+/* DOORBELLS ACCESS */
+
+/**
+ * Catapult doorbells
+ * Each doorbell-queue set has
+ * 1 RxQ, 1 TxQ, 2 IBs in that order
+ * Size of each entry in 32 bytes, even though only 1 word
+ * is used. For Non-VM case each doorbell-q set is
+ * separated by 128 bytes, for VM case it is separated
+ * by 4K bytes
+ * Non VM case Range : 0x38000 - 0x39FFF
+ * VM case Range     : 0x100000 - 0x11FFFF
+ * The range applies to both HQMs
+ */
+#define HQM_DOORBELL_BLK_BASE_ADDR     0x00038000
+#define HQM_DOORBELL_VM_BLK_BASE_ADDR  0x00100000
+
+/* MEMORY ACCESS */
+
+/**
+ * Catapult H/W Block Memory Access Address
+ * To the host a memory space of 32K (page) is visible
+ * at a time. The address range is from 0x08000 to 0x0FFFF
+ */
+#define HW_BLK_HOST_MEM_ADDR           0x08000
+
+/**
+ * Catapult LUT Memory Access Page Numbers
+ * Range : LUT0 0xa0-0xa1
+ *         LUT1 0xa2-0xa3
+ */
+#define LUT0_MEM_BLK_BASE_PG_NUM       0x000000A0
+#define LUT1_MEM_BLK_BASE_PG_NUM       0x000000A2
+
+/**
+ * Catapult RxFn Database Memory Block Base Offset
+ *
+ * The Rx function database exists in LUT block.
+ * In PCIe space this is accessible as a 256x32
+ * bit block. Each entry in this database is 4
+ * (4 byte) words. Max. entries is 64.
+ * Address of an entry corresponding to a function
+ * = base_addr + (function_no. * 16)
+ */
+#define RX_FNDB_RAM_BASE_OFFSET                0x0000B400
+
+/**
+ * Catapult TxFn Database Memory Block Base Offset Address
+ *
+ * The Tx function database exists in LUT block.
+ * In PCIe space this is accessible as a 64x32
+ * bit block. Each entry in this database is 1
+ * (4 byte) word. Max. entries is 64.
+ * Address of an entry corresponding to a function
+ * = base_addr + (function_no. * 4)
+ */
+#define TX_FNDB_RAM_BASE_OFFSET                0x0000B800
+
+/**
+ * Catapult Unicast CAM Base Offset Address
+ *
+ * Exists in LUT memory space.
+ * Shared by both the LL & FCoE driver.
+ * Size is 256x48 bits; mapped to PCIe space
+ * 512x32 bit blocks. For each address, bits
+ * are written in the order : [47:32] and then
+ * [31:0].
+ */
+#define UCAST_CAM_BASE_OFFSET          0x0000A800
+
+/**
+ * Catapult Unicast RAM Base Offset Address
+ *
+ * Exists in LUT memory space.
+ * Shared by both the LL & FCoE driver.
+ * Size is 256x9 bits.
+ */
+#define UCAST_RAM_BASE_OFFSET          0x0000B000
+
+/**
+ * Catapult Mulicast CAM Base Offset Address
+ *
+ * Exists in LUT memory space.
+ * Shared by both the LL & FCoE driver.
+ * Size is 256x48 bits; mapped to PCIe space
+ * 512x32 bit blocks. For each address, bits
+ * are written in the order : [47:32] and then
+ * [31:0].
+ */
+#define MCAST_CAM_BASE_OFFSET          0x0000A000
+
+/**
+ * Catapult VLAN RAM Base Offset Address
+ *
+ * Exists in LUT memory space.
+ * Size is 4096x66 bits; mapped to PCIe space as
+ * 8192x32 bit blocks.
+ * All the 4K entries are within the address range
+ * 0x0000 to 0x8000, so in the first LUT page.
+ */
+#define VLAN_RAM_BASE_OFFSET           0x00000000
+
+/**
+ * Catapult Tx Stats RAM Base Offset Address
+ *
+ * Exists in LUT memory space.
+ * Size is 1024x33 bits;
+ * Each Tx function has 64 bytes of space
+ */
+#define TX_STATS_RAM_BASE_OFFSET       0x00009000
+
+/**
+ * Catapult Rx Stats RAM Base Offset Address
+ *
+ * Exists in LUT memory space.
+ * Size is 1024x33 bits;
+ * Each Rx function has 64 bytes of space
+ */
+#define RX_STATS_RAM_BASE_OFFSET       0x00008000
+
+/* Catapult RXA Memory Access Page Numbers */
+#define RXA0_MEM_BLK_BASE_PG_NUM       0x0000008C
+#define RXA1_MEM_BLK_BASE_PG_NUM       0x0000008D
+
+/**
+ * Catapult Multicast Vector Table Base Offset Address
+ *
+ * Exists in RxA memory space.
+ * Organized as 512x65 bit block.
+ * However for each entry 16 bytes allocated (power of 2)
+ * Total size 512*16 bytes.
+ * There are two logical divisions, 256 entries each :
+ * a) Entries 0x00 to 0xff (256) -- Approx. MVT
+ *    Offset 0x000 to 0xFFF
+ * b) Entries 0x100 to 0x1ff (256) -- Exact MVT
+ *    Offsets 0x1000 to 0x1FFF
+ */
+#define MCAST_APPROX_MVT_BASE_OFFSET   0x00000000
+#define MCAST_EXACT_MVT_BASE_OFFSET    0x00001000
+
+/**
+ * Catapult RxQ Translate Table (RIT) Base Offset Address
+ *
+ * Exists in RxA memory space
+ * Total no. of entries 64
+ * Each entry is 1 (4 byte) word.
+ * 31:12 -- Reserved
+ * 11:0  -- Two 6 bit RxQ Ids
+ */
+#define FUNCTION_TO_RXQ_TRANSLATE      0x00002000
+
+/* Catapult RxAdm (RAD) Memory Access Page Numbers */
+#define RAD0_MEM_BLK_BASE_PG_NUM       0x00000086
+#define RAD1_MEM_BLK_BASE_PG_NUM       0x00000087
+
+/**
+ * Catapult RSS Table Base Offset Address
+ *
+ * Exists in RAD memory space.
+ * Each entry is 352 bits, but alligned on
+ * 64 byte (512 bit) boundary. Accessed
+ * 4 byte words, the whole entry can be
+ * broken into 11 word accesses.
+ */
+#define RSS_TABLE_BASE_OFFSET          0x00000800
+
+/**
+ * Catapult CPQ Block Page Number
+ * This value is written to the page number registers
+ * to access the memory associated with the mailboxes.
+ */
+#define CPQ_BLK_PG_NUM                 0x00000005
+
+/**
+ * Clarification :
+ * LL functions are 2 & 3; can HostFn0/HostFn1
+ * <-> LPU0/LPU1 memories be used ?
+ */
+/**
+ * Catapult HostFn0/HostFn1 to LPU0/LPU1 Mbox memory
+ * Per catapult_spec.pdf, the offset of the mbox
+ * memory is in the register space at an offset of 0x200
+ */
+#define CPQ_BLK_REG_MBOX_ADDR          (CPQ_BLK_REG_ADDR + 0x200)
+
+#define HOSTFN_LPU_MBOX                        (CPQ_BLK_REG_MBOX_ADDR + 0x000)
+
+/* Catapult LPU0/LPU1 to HostFn0/HostFn1 Mbox memory */
+#define LPU_HOSTFN_MBOX                        (CPQ_BLK_REG_MBOX_ADDR + 0x080)
+
+/**
+ * Catapult HQM Block Page Number
+ * This is written to the page number register for
+ * the appropriate function to access the memory
+ * associated with HQM
+ */
+#define HQM0_BLK_PG_NUM                        0x00000096
+#define HQM1_BLK_PG_NUM                        0x00000097
+
+/**
+ * Note that TxQ and RxQ entries are interlaced
+ * the HQM memory, i.e RXQ0, TXQ0, RXQ1, TXQ1.. etc.
+ */
+
+#define HQM_RXTX_Q_RAM_BASE_OFFSET     0x00004000
+
+/**
+ * CQ Memory
+ * Exists in HQM Memory space
+ * Each entry is 16 (4 byte) words of which
+ * only 12 words are used for configuration
+ * Total 64 entries per HQM memory space
+ */
+#define HQM_CQ_RAM_BASE_OFFSET         0x00006000
+
+/**
+ * Interrupt Block (IB) Memory
+ * Exists in HQM Memory space
+ * Each entry is 8 (4 byte) words of which
+ * only 5 words are used for configuration
+ * Total 128 entries per HQM memory space
+ */
+#define HQM_IB_RAM_BASE_OFFSET         0x00001000
+
+/**
+ * Index Table (IT) Memory
+ * Exists in HQM Memory space
+ * Each entry is 1 (4 byte) word which
+ * is used for configuration
+ * Total 128 entries per HQM memory space
+ */
+#define HQM_INDX_TBL_RAM_BASE_OFFSET   0x00002000
+
+/**
+ * PSS Block Memory Page Number
+ * This is written to the appropriate page number
+ * register to access the CPU memory.
+ * Also known as the PSS secondary memory (SMEM).
+ * Range : 0x180 to 0x1CF
+ * See catapult_spec.pdf for details
+ */
+#define PSS_BLK_PG_NUM                 0x00000180
+
+/**
+ * Offsets of different instances of PSS SMEM
+ * 2.5M of continuous 1T memory space : 2 blocks
+ * of 1M each (32 pages each, page=32KB) and 4 smaller
+ * blocks of 128K each (4 pages each, page=32KB)
+ * PSS_LMEM_INST0 is used for firmware download
+ */
+#define PSS_LMEM_INST0                 0x00000000
+#define PSS_LMEM_INST1                 0x00100000
+#define PSS_LMEM_INST2                 0x00200000
+#define PSS_LMEM_INST3                 0x00220000
+#define PSS_LMEM_INST4                 0x00240000
+#define PSS_LMEM_INST5                 0x00260000
+
+#define BNA_PCI_REG_CT_ADDRSZ          (0x40000)
+
+#define BNA_GET_PAGE_NUM(_base_page, _offset)   \
+       ((_base_page) + ((_offset) >> 15))
+
+#define BNA_GET_PAGE_OFFSET(_offset)    \
+       ((_offset) & 0x7fff)
+
+#define BNA_GET_MEM_BASE_ADDR(_bar0, _base_offset)     \
+       ((_bar0) + HW_BLK_HOST_MEM_ADDR         \
+         + BNA_GET_PAGE_OFFSET((_base_offset)))
+
+#define BNA_GET_VLAN_MEM_ENTRY_ADDR(_bar0, _fn_id, _vlan_id)\
+       (_bar0 + (HW_BLK_HOST_MEM_ADDR)  \
+       + (BNA_GET_PAGE_OFFSET(VLAN_RAM_BASE_OFFSET))   \
+       + (((_fn_id) & 0x3f) << 9)        \
+       + (((_vlan_id) & 0xfe0) >> 3))
+
+/**
+ *
+ *  Interrupt related bits, flags and macros
+ *
+ */
+
+#define __LPU02HOST_MBOX0_STATUS_BITS 0x00100000
+#define __LPU12HOST_MBOX0_STATUS_BITS 0x00200000
+#define __LPU02HOST_MBOX1_STATUS_BITS 0x00400000
+#define __LPU12HOST_MBOX1_STATUS_BITS 0x00800000
+
+#define __LPU02HOST_MBOX0_MASK_BITS    0x00100000
+#define __LPU12HOST_MBOX0_MASK_BITS    0x00200000
+#define __LPU02HOST_MBOX1_MASK_BITS    0x00400000
+#define __LPU12HOST_MBOX1_MASK_BITS    0x00800000
+
+#define __LPU2HOST_MBOX_MASK_BITS                       \
+       (__LPU02HOST_MBOX0_MASK_BITS | __LPU02HOST_MBOX1_MASK_BITS |    \
+         __LPU12HOST_MBOX0_MASK_BITS | __LPU12HOST_MBOX1_MASK_BITS)
+
+#define __LPU2HOST_IB_STATUS_BITS      0x0000ffff
+
+#define BNA_IS_LPU0_MBOX_INTR(_intr_status) \
+       ((_intr_status) & (__LPU02HOST_MBOX0_STATUS_BITS | \
+                       __LPU02HOST_MBOX1_STATUS_BITS))
+
+#define BNA_IS_LPU1_MBOX_INTR(_intr_status) \
+       ((_intr_status) & (__LPU12HOST_MBOX0_STATUS_BITS | \
+               __LPU12HOST_MBOX1_STATUS_BITS))
+
+#define BNA_IS_MBOX_INTR(_intr_status)         \
+       ((_intr_status) &                       \
+       (__LPU02HOST_MBOX0_STATUS_BITS |        \
+        __LPU02HOST_MBOX1_STATUS_BITS |        \
+        __LPU12HOST_MBOX0_STATUS_BITS |        \
+        __LPU12HOST_MBOX1_STATUS_BITS))
+
+#define __EMC_ERROR_STATUS_BITS                0x00010000
+#define __LPU0_ERROR_STATUS_BITS       0x00020000
+#define __LPU1_ERROR_STATUS_BITS       0x00040000
+#define __PSS_ERROR_STATUS_BITS                0x00080000
+
+#define __HALT_STATUS_BITS             0x01000000
+
+#define __EMC_ERROR_MASK_BITS          0x00010000
+#define __LPU0_ERROR_MASK_BITS         0x00020000
+#define __LPU1_ERROR_MASK_BITS         0x00040000
+#define __PSS_ERROR_MASK_BITS          0x00080000
+
+#define __HALT_MASK_BITS               0x01000000
+
+#define __ERROR_MASK_BITS              \
+       (__EMC_ERROR_MASK_BITS | __LPU0_ERROR_MASK_BITS | \
+         __LPU1_ERROR_MASK_BITS | __PSS_ERROR_MASK_BITS | \
+         __HALT_MASK_BITS)
+
+#define BNA_IS_ERR_INTR(_intr_status)  \
+       ((_intr_status) &               \
+       (__EMC_ERROR_STATUS_BITS |      \
+        __LPU0_ERROR_STATUS_BITS |     \
+        __LPU1_ERROR_STATUS_BITS |     \
+        __PSS_ERROR_STATUS_BITS  |     \
+        __HALT_STATUS_BITS))
+
+#define BNA_IS_MBOX_ERR_INTR(_intr_status)     \
+       (BNA_IS_MBOX_INTR((_intr_status)) |     \
+        BNA_IS_ERR_INTR((_intr_status)))
+
+#define BNA_IS_INTX_DATA_INTR(_intr_status)    \
+       ((_intr_status) & __LPU2HOST_IB_STATUS_BITS)
+
+#define BNA_INTR_STATUS_MBOX_CLR(_intr_status)                 \
+do {                                                           \
+       (_intr_status) &= ~(__LPU02HOST_MBOX0_STATUS_BITS |     \
+                       __LPU02HOST_MBOX1_STATUS_BITS |         \
+                       __LPU12HOST_MBOX0_STATUS_BITS |         \
+                       __LPU12HOST_MBOX1_STATUS_BITS);         \
+} while (0)
+
+#define BNA_INTR_STATUS_ERR_CLR(_intr_status)          \
+do {                                                   \
+       (_intr_status) &= ~(__EMC_ERROR_STATUS_BITS |   \
+               __LPU0_ERROR_STATUS_BITS |              \
+               __LPU1_ERROR_STATUS_BITS |              \
+               __PSS_ERROR_STATUS_BITS  |              \
+               __HALT_STATUS_BITS);                    \
+} while (0)
+
+#define bna_intx_disable(_bna, _cur_mask)              \
+{                                                      \
+       (_cur_mask) = readl((_bna)->regs.fn_int_mask);\
+       writel(0xffffffff, (_bna)->regs.fn_int_mask);\
+}
+
+#define bna_intx_enable(bna, new_mask)                         \
+       writel((new_mask), (bna)->regs.fn_int_mask)
+
+#define bna_mbox_intr_disable(bna)             \
+       writel((readl((bna)->regs.fn_int_mask) | \
+            (__LPU2HOST_MBOX_MASK_BITS | __ERROR_MASK_BITS)), \
+            (bna)->regs.fn_int_mask)
+
+#define bna_mbox_intr_enable(bna)              \
+       writel((readl((bna)->regs.fn_int_mask) & \
+            ~(__LPU2HOST_MBOX_MASK_BITS | __ERROR_MASK_BITS)), \
+            (bna)->regs.fn_int_mask)
+
+#define bna_intr_status_get(_bna, _status)                             \
+{                                                                      \
+       (_status) = readl((_bna)->regs.fn_int_status);          \
+       if ((_status)) {                                                \
+               writel((_status) & ~(__LPU02HOST_MBOX0_STATUS_BITS |\
+                                         __LPU02HOST_MBOX1_STATUS_BITS |\
+                                         __LPU12HOST_MBOX0_STATUS_BITS |\
+                                         __LPU12HOST_MBOX1_STATUS_BITS), \
+                             (_bna)->regs.fn_int_status);\
+       }                                                               \
+}
+
+#define bna_intr_status_get_no_clr(_bna, _status)              \
+       (_status) = readl((_bna)->regs.fn_int_status)
+
+#define bna_intr_mask_get(bna, mask)           \
+       (*mask) = readl((bna)->regs.fn_int_mask)
+
+#define bna_intr_ack(bna, intr_bmap)           \
+       writel((intr_bmap), (bna)->regs.fn_int_status)
+
+#define bna_ib_intx_disable(bna, ib_id)                \
+       writel(readl((bna)->regs.fn_int_mask) | \
+           (1 << (ib_id)), \
+           (bna)->regs.fn_int_mask)
+
+#define bna_ib_intx_enable(bna, ib_id)         \
+       writel(readl((bna)->regs.fn_int_mask) & \
+           ~(1 << (ib_id)), \
+           (bna)->regs.fn_int_mask)
+
+#define bna_mbox_msix_idx_set(_device) \
+do {\
+       writel(((_device)->vector & 0x000001FF), \
+               (_device)->bna->pcidev.pci_bar_kva + \
+               reg_offset[(_device)->bna->pcidev.pci_func].msix_idx);\
+} while (0)
+
+/**
+ *
+ * TxQ, RxQ, CQ related bits, offsets, macros
+ *
+ */
+
+#define        BNA_Q_IDLE_STATE        0x00008001
+
+#define BNA_GET_DOORBELL_BASE_ADDR(_bar0)      \
+       ((_bar0) + HQM_DOORBELL_BLK_BASE_ADDR)
+
+#define BNA_GET_DOORBELL_ENTRY_OFFSET(_entry)          \
+       ((HQM_DOORBELL_BLK_BASE_ADDR)           \
+       + (_entry << 7))
+
+#define BNA_DOORBELL_IB_INT_ACK(_timeout, _events) \
+               (0x80000000 | ((_timeout) << 16) | (_events))
+
+#define BNA_DOORBELL_IB_INT_DISABLE            (0x40000000)
+
+/* TxQ Entry Opcodes */
+#define BNA_TXQ_WI_SEND                (0x402) /* Single Frame Transmission */
+#define BNA_TXQ_WI_SEND_LSO            (0x403) /* Multi-Frame Transmission */
+#define BNA_TXQ_WI_EXTENSION           (0x104) /* Extension WI */
+
+/* TxQ Entry Control Flags */
+#define BNA_TXQ_WI_CF_FCOE_CRC         (1 << 8)
+#define BNA_TXQ_WI_CF_IPID_MODE        (1 << 5)
+#define BNA_TXQ_WI_CF_INS_PRIO         (1 << 4)
+#define BNA_TXQ_WI_CF_INS_VLAN         (1 << 3)
+#define BNA_TXQ_WI_CF_UDP_CKSUM        (1 << 2)
+#define BNA_TXQ_WI_CF_TCP_CKSUM        (1 << 1)
+#define BNA_TXQ_WI_CF_IP_CKSUM         (1 << 0)
+
+#define BNA_TXQ_WI_L4_HDR_N_OFFSET(_hdr_size, _offset) \
+               (((_hdr_size) << 10) | ((_offset) & 0x3FF))
+
+/*
+ * Completion Q defines
+ */
+/* CQ Entry Flags */
+#define        BNA_CQ_EF_MAC_ERROR     (1 <<  0)
+#define        BNA_CQ_EF_FCS_ERROR     (1 <<  1)
+#define        BNA_CQ_EF_TOO_LONG      (1 <<  2)
+#define        BNA_CQ_EF_FC_CRC_OK     (1 <<  3)
+
+#define        BNA_CQ_EF_RSVD1         (1 <<  4)
+#define        BNA_CQ_EF_L4_CKSUM_OK   (1 <<  5)
+#define        BNA_CQ_EF_L3_CKSUM_OK   (1 <<  6)
+#define        BNA_CQ_EF_HDS_HEADER    (1 <<  7)
+
+#define        BNA_CQ_EF_UDP           (1 <<  8)
+#define        BNA_CQ_EF_TCP           (1 <<  9)
+#define        BNA_CQ_EF_IP_OPTIONS    (1 << 10)
+#define        BNA_CQ_EF_IPV6          (1 << 11)
+
+#define        BNA_CQ_EF_IPV4          (1 << 12)
+#define        BNA_CQ_EF_VLAN          (1 << 13)
+#define        BNA_CQ_EF_RSS           (1 << 14)
+#define        BNA_CQ_EF_RSVD2         (1 << 15)
+
+#define        BNA_CQ_EF_MCAST_MATCH   (1 << 16)
+#define        BNA_CQ_EF_MCAST         (1 << 17)
+#define BNA_CQ_EF_BCAST        (1 << 18)
+#define        BNA_CQ_EF_REMOTE        (1 << 19)
+
+#define        BNA_CQ_EF_LOCAL         (1 << 20)
+
+/**
+ *
+ * Data structures
+ *
+ */
+
+enum txf_flags {
+       BFI_TXF_CF_ENABLE               = 1 << 0,
+       BFI_TXF_CF_VLAN_FILTER          = 1 << 8,
+       BFI_TXF_CF_VLAN_ADMIT           = 1 << 9,
+       BFI_TXF_CF_VLAN_INSERT          = 1 << 10,
+       BFI_TXF_CF_RSVD1                = 1 << 11,
+       BFI_TXF_CF_MAC_SA_CHECK         = 1 << 12,
+       BFI_TXF_CF_VLAN_WI_BASED        = 1 << 13,
+       BFI_TXF_CF_VSWITCH_MCAST        = 1 << 14,
+       BFI_TXF_CF_VSWITCH_UCAST        = 1 << 15,
+       BFI_TXF_CF_RSVD2                = 0x7F << 1
+};
+
+enum ib_flags {
+       BFI_IB_CF_MASTER_ENABLE         = (1 << 0),
+       BFI_IB_CF_MSIX_MODE             = (1 << 1),
+       BFI_IB_CF_COALESCING_MODE       = (1 << 2),
+       BFI_IB_CF_INTER_PKT_ENABLE      = (1 << 3),
+       BFI_IB_CF_INT_ENABLE            = (1 << 4),
+       BFI_IB_CF_INTER_PKT_DMA         = (1 << 5),
+       BFI_IB_CF_ACK_PENDING           = (1 << 6),
+       BFI_IB_CF_RESERVED1             = (1 << 7)
+};
+
+enum rss_hash_type {
+       BFI_RSS_T_V4_TCP                = (1 << 11),
+       BFI_RSS_T_V4_IP                 = (1 << 10),
+       BFI_RSS_T_V6_TCP                = (1 <<  9),
+       BFI_RSS_T_V6_IP                 = (1 <<  8)
+};
+enum hds_header_type {
+       BNA_HDS_T_V4_TCP        = (1 << 11),
+       BNA_HDS_T_V4_UDP        = (1 << 10),
+       BNA_HDS_T_V6_TCP        = (1 << 9),
+       BNA_HDS_T_V6_UDP        = (1 << 8),
+       BNA_HDS_FORCED          = (1 << 7),
+};
+enum rxf_flags {
+       BNA_RXF_CF_SM_LG_RXQ                    = (1 << 15),
+       BNA_RXF_CF_DEFAULT_VLAN                 = (1 << 14),
+       BNA_RXF_CF_DEFAULT_FUNCTION_ENABLE      = (1 << 13),
+       BNA_RXF_CF_VLAN_STRIP                   = (1 << 12),
+       BNA_RXF_CF_RSS_ENABLE                   = (1 <<  8)
+};
+struct bna_chip_regs_offset {
+       u32 page_addr;
+       u32 fn_int_status;
+       u32 fn_int_mask;
+       u32 msix_idx;
+};
+extern const struct bna_chip_regs_offset reg_offset[];
+
+struct bna_chip_regs {
+       void __iomem *page_addr;
+       void __iomem *fn_int_status;
+       void __iomem *fn_int_mask;
+};
+
+struct bna_txq_mem {
+       u32 pg_tbl_addr_lo;
+       u32 pg_tbl_addr_hi;
+       u32 cur_q_entry_lo;
+       u32 cur_q_entry_hi;
+       u32 reserved1;
+       u32 reserved2;
+       u32 pg_cnt_n_prd_ptr;   /* 31:16->total page count */
+                                       /* 15:0 ->producer pointer (index?) */
+       u32 entry_n_pg_size;    /* 31:16->entry size */
+                                       /* 15:0 ->page size */
+       u32 int_blk_n_cns_ptr;  /* 31:24->Int Blk Id;  */
+                                       /* 23:16->Int Blk Offset */
+                                       /* 15:0 ->consumer pointer(index?) */
+       u32 cns_ptr2_n_q_state; /* 31:16->cons. ptr 2; 15:0-> Q state */
+       u32 nxt_qid_n_fid_n_pri;        /* 17:10->next */
+                                       /* QId;9:3->FID;2:0->Priority */
+       u32 wvc_n_cquota_n_rquota; /* 31:24->WI Vector Count; */
+                                       /* 23:12->Cfg Quota; */
+                                       /* 11:0 ->Run Quota */
+       u32 reserved3[4];
+};
+
+struct bna_rxq_mem {
+       u32 pg_tbl_addr_lo;
+       u32 pg_tbl_addr_hi;
+       u32 cur_q_entry_lo;
+       u32 cur_q_entry_hi;
+       u32 reserved1;
+       u32 reserved2;
+       u32 pg_cnt_n_prd_ptr;   /* 31:16->total page count */
+                                       /* 15:0 ->producer pointer (index?) */
+       u32 entry_n_pg_size;    /* 31:16->entry size */
+                                       /* 15:0 ->page size */
+       u32 sg_n_cq_n_cns_ptr;  /* 31:28->reserved; 27:24->sg count */
+                                       /* 23:16->CQ; */
+                                       /* 15:0->consumer pointer(index?) */
+       u32 buf_sz_n_q_state;   /* 31:16->buffer size; 15:0-> Q state */
+       u32 next_qid;           /* 17:10->next QId */
+       u32 reserved3;
+       u32 reserved4[4];
+};
+
+struct bna_rxtx_q_mem {
+       struct bna_rxq_mem rxq;
+       struct bna_txq_mem txq;
+};
+
+struct bna_cq_mem {
+       u32 pg_tbl_addr_lo;
+       u32 pg_tbl_addr_hi;
+       u32 cur_q_entry_lo;
+       u32 cur_q_entry_hi;
+
+       u32 reserved1;
+       u32 reserved2;
+       u32 pg_cnt_n_prd_ptr;   /* 31:16->total page count */
+                                       /* 15:0 ->producer pointer (index?) */
+       u32 entry_n_pg_size;    /* 31:16->entry size */
+                                       /* 15:0 ->page size */
+       u32 int_blk_n_cns_ptr;  /* 31:24->Int Blk Id; */
+                                       /* 23:16->Int Blk Offset */
+                                       /* 15:0 ->consumer pointer(index?) */
+       u32 q_state;            /* 31:16->reserved; 15:0-> Q state */
+       u32 reserved3[2];
+       u32 reserved4[4];
+};
+
+struct bna_ib_blk_mem {
+       u32 host_addr_lo;
+       u32 host_addr_hi;
+       u32 clsc_n_ctrl_n_msix; /* 31:24->coalescing; */
+                                       /* 23:16->coalescing cfg; */
+                                       /* 15:8 ->control; */
+                                       /* 7:0 ->msix; */
+       u32 ipkt_n_ent_n_idxof;
+       u32 ipkt_cnt_cfg_n_unacked;
+
+       u32 reserved[3];
+};
+
+struct bna_idx_tbl_mem {
+       u32 idx;          /* !< 31:16->res;15:0->idx; */
+};
+
+struct bna_doorbell_qset {
+       u32 rxq[0x20 >> 2];
+       u32 txq[0x20 >> 2];
+       u32 ib0[0x20 >> 2];
+       u32 ib1[0x20 >> 2];
+};
+
+struct bna_rx_fndb_ram {
+       u32 rss_prop;
+       u32 size_routing_props;
+       u32 rit_hds_mcastq;
+       u32 control_flags;
+};
+
+struct bna_tx_fndb_ram {
+       u32 vlan_n_ctrl_flags;
+};
+
+/**
+ * @brief
+ *  Structure which maps to RxFn Indirection Table (RIT)
+ *  Size : 1 word
+ *  See catapult_spec.pdf, RxA for details
+ */
+struct bna_rit_mem {
+       u32 rxq_ids;    /* !< 31:12->res;11:0->two 6 bit RxQ Ids */
+};
+
+/**
+ * @brief
+ *  Structure which maps to RSS Table entry
+ *  Size : 16 words
+ *  See catapult_spec.pdf, RAD for details
+ */
+struct bna_rss_mem {
+       /*
+        * 31:12-> res
+        * 11:8 -> protocol type
+        *  7:0 -> hash index
+        */
+       u32 type_n_hash;
+       u32 hash_key[10];  /* !< 40 byte Toeplitz hash key */
+       u32 reserved[5];
+};
+
+/* TxQ Vector (a.k.a. Tx-Buffer Descriptor) */
+struct bna_dma_addr {
+       u32             msb;
+       u32             lsb;
+};
+
+struct bna_txq_wi_vector {
+       u16             reserved;
+       u16             length;         /* Only 14 LSB are valid */
+       struct bna_dma_addr host_addr; /* Tx-Buf DMA addr */
+};
+
+typedef u16 bna_txq_wi_opcode_t;
+
+typedef u16 bna_txq_wi_ctrl_flag_t;
+
+/**
+ *  TxQ Entry Structure
+ *
+ *  BEWARE:  Load values into this structure with correct endianess.
+ */
+struct bna_txq_entry {
+       union {
+               struct {
+                       u8 reserved;
+                       u8 num_vectors; /* number of vectors present */
+                       bna_txq_wi_opcode_t opcode; /* Either */
+                                                   /* BNA_TXQ_WI_SEND or */
+                                                   /* BNA_TXQ_WI_SEND_LSO */
+                       bna_txq_wi_ctrl_flag_t flags; /* OR of all the flags */
+                       u16 l4_hdr_size_n_offset;
+                       u16 vlan_tag;
+                       u16 lso_mss;    /* Only 14 LSB are valid */
+                       u32 frame_length;       /* Only 24 LSB are valid */
+               } wi;
+
+               struct {
+                       u16 reserved;
+                       bna_txq_wi_opcode_t opcode; /* Must be */
+                                                   /* BNA_TXQ_WI_EXTENSION */
+                       u32 reserved2[3];       /* Place holder for */
+                                               /* removed vector (12 bytes) */
+               } wi_ext;
+       } hdr;
+       struct bna_txq_wi_vector vector[4];
+};
+#define wi_hdr         hdr.wi
+#define wi_ext_hdr  hdr.wi_ext
+
+/* RxQ Entry Structure */
+struct bna_rxq_entry {         /* Rx-Buffer */
+       struct bna_dma_addr host_addr; /* Rx-Buffer DMA address */
+};
+
+typedef u32 bna_cq_e_flag_t;
+
+/* CQ Entry Structure */
+struct bna_cq_entry {
+       bna_cq_e_flag_t flags;
+       u16 vlan_tag;
+       u16 length;
+       u32 rss_hash;
+       u8 valid;
+       u8 reserved1;
+       u8 reserved2;
+       u8 rxq_id;
+};
+
+#endif /* __BNA_HW_H__ */
diff --git a/drivers/net/bna/bna_txrx.c b/drivers/net/bna/bna_txrx.c
new file mode 100644 (file)
index 0000000..890846d
--- /dev/null
@@ -0,0 +1,4209 @@
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * 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.
+  */
+/*
+ * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+#include "bna.h"
+#include "bfa_sm.h"
+#include "bfi.h"
+
+/**
+ * IB
+ */
+#define bna_ib_find_free_ibidx(_mask, _pos)\
+do {\
+       (_pos) = 0;\
+       while (((_pos) < (BFI_IBIDX_MAX_SEGSIZE)) &&\
+               ((1 << (_pos)) & (_mask)))\
+               (_pos)++;\
+} while (0)
+
+#define bna_ib_count_ibidx(_mask, _count)\
+do {\
+       int pos = 0;\
+       (_count) = 0;\
+       while (pos < (BFI_IBIDX_MAX_SEGSIZE)) {\
+               if ((1 << pos) & (_mask))\
+                       (_count) = pos + 1;\
+               pos++;\
+       } \
+} while (0)
+
+#define bna_ib_select_segpool(_count, _q_idx)\
+do {\
+       int i;\
+       (_q_idx) = -1;\
+       for (i = 0; i < BFI_IBIDX_TOTAL_POOLS; i++) {\
+               if ((_count <= ibidx_pool[i].pool_entry_size)) {\
+                       (_q_idx) = i;\
+                       break;\
+               } \
+       } \
+} while (0)
+
+struct bna_ibidx_pool {
+       int     pool_size;
+       int     pool_entry_size;
+};
+init_ibidx_pool(ibidx_pool);
+
+static struct bna_intr *
+bna_intr_get(struct bna_ib_mod *ib_mod, enum bna_intr_type intr_type,
+               int vector)
+{
+       struct bna_intr *intr;
+       struct list_head *qe;
+
+       list_for_each(qe, &ib_mod->intr_active_q) {
+               intr = (struct bna_intr *)qe;
+
+               if ((intr->intr_type == intr_type) &&
+                       (intr->vector == vector)) {
+                       intr->ref_count++;
+                       return intr;
+               }
+       }
+
+       if (list_empty(&ib_mod->intr_free_q))
+               return NULL;
+
+       bfa_q_deq(&ib_mod->intr_free_q, &intr);
+       bfa_q_qe_init(&intr->qe);
+
+       intr->ref_count = 1;
+       intr->intr_type = intr_type;
+       intr->vector = vector;
+
+       list_add_tail(&intr->qe, &ib_mod->intr_active_q);
+
+       return intr;
+}
+
+static void
+bna_intr_put(struct bna_ib_mod *ib_mod,
+               struct bna_intr *intr)
+{
+       intr->ref_count--;
+
+       if (intr->ref_count == 0) {
+               intr->ib = NULL;
+               list_del(&intr->qe);
+               bfa_q_qe_init(&intr->qe);
+               list_add_tail(&intr->qe, &ib_mod->intr_free_q);
+       }
+}
+
+void
+bna_ib_mod_init(struct bna_ib_mod *ib_mod, struct bna *bna,
+               struct bna_res_info *res_info)
+{
+       int i;
+       int j;
+       int count;
+       u8 offset;
+       struct bna_doorbell_qset *qset;
+       unsigned long off;
+
+       ib_mod->bna = bna;
+
+       ib_mod->ib = (struct bna_ib *)
+               res_info[BNA_RES_MEM_T_IB_ARRAY].res_u.mem_info.mdl[0].kva;
+       ib_mod->intr = (struct bna_intr *)
+               res_info[BNA_RES_MEM_T_INTR_ARRAY].res_u.mem_info.mdl[0].kva;
+       ib_mod->idx_seg = (struct bna_ibidx_seg *)
+               res_info[BNA_RES_MEM_T_IDXSEG_ARRAY].res_u.mem_info.mdl[0].kva;
+
+       INIT_LIST_HEAD(&ib_mod->ib_free_q);
+       INIT_LIST_HEAD(&ib_mod->intr_free_q);
+       INIT_LIST_HEAD(&ib_mod->intr_active_q);
+
+       for (i = 0; i < BFI_IBIDX_TOTAL_POOLS; i++)
+               INIT_LIST_HEAD(&ib_mod->ibidx_seg_pool[i]);
+
+       for (i = 0; i < BFI_MAX_IB; i++) {
+               ib_mod->ib[i].ib_id = i;
+
+               ib_mod->ib[i].ib_seg_host_addr_kva =
+               res_info[BNA_RES_MEM_T_IBIDX].res_u.mem_info.mdl[i].kva;
+               ib_mod->ib[i].ib_seg_host_addr.lsb =
+               res_info[BNA_RES_MEM_T_IBIDX].res_u.mem_info.mdl[i].dma.lsb;
+               ib_mod->ib[i].ib_seg_host_addr.msb =
+               res_info[BNA_RES_MEM_T_IBIDX].res_u.mem_info.mdl[i].dma.msb;
+
+               qset = (struct bna_doorbell_qset *)0;
+               off = (unsigned long)(&qset[i >> 1].ib0[(i & 0x1)
+                                       * (0x20 >> 2)]);
+               ib_mod->ib[i].door_bell.doorbell_addr = off +
+                       BNA_GET_DOORBELL_BASE_ADDR(bna->pcidev.pci_bar_kva);
+
+               bfa_q_qe_init(&ib_mod->ib[i].qe);
+               list_add_tail(&ib_mod->ib[i].qe, &ib_mod->ib_free_q);
+
+               bfa_q_qe_init(&ib_mod->intr[i].qe);
+               list_add_tail(&ib_mod->intr[i].qe, &ib_mod->intr_free_q);
+       }
+
+       count = 0;
+       offset = 0;
+       for (i = 0; i < BFI_IBIDX_TOTAL_POOLS; i++) {
+               for (j = 0; j < ibidx_pool[i].pool_size; j++) {
+                       bfa_q_qe_init(&ib_mod->idx_seg[count]);
+                       ib_mod->idx_seg[count].ib_seg_size =
+                                       ibidx_pool[i].pool_entry_size;
+                       ib_mod->idx_seg[count].ib_idx_tbl_offset = offset;
+                       list_add_tail(&ib_mod->idx_seg[count].qe,
+                               &ib_mod->ibidx_seg_pool[i]);
+                       count++;
+                       offset += ibidx_pool[i].pool_entry_size;
+               }
+       }
+}
+
+void
+bna_ib_mod_uninit(struct bna_ib_mod *ib_mod)
+{
+       int i;
+       int j;
+       struct list_head *qe;
+
+       i = 0;
+       list_for_each(qe, &ib_mod->ib_free_q)
+               i++;
+
+       i = 0;
+       list_for_each(qe, &ib_mod->intr_free_q)
+               i++;
+
+       for (i = 0; i < BFI_IBIDX_TOTAL_POOLS; i++) {
+               j = 0;
+               list_for_each(qe, &ib_mod->ibidx_seg_pool[i])
+                       j++;
+       }
+
+       ib_mod->bna = NULL;
+}
+
+struct bna_ib *
+bna_ib_get(struct bna_ib_mod *ib_mod,
+               enum bna_intr_type intr_type,
+               int vector)
+{
+       struct bna_ib *ib;
+       struct bna_intr *intr;
+
+       if (intr_type == BNA_INTR_T_INTX)
+               vector = (1 << vector);
+
+       intr = bna_intr_get(ib_mod, intr_type, vector);
+       if (intr == NULL)
+               return NULL;
+
+       if (intr->ib) {
+               if (intr->ib->ref_count == BFI_IBIDX_MAX_SEGSIZE) {
+                       bna_intr_put(ib_mod, intr);
+                       return NULL;
+               }
+               intr->ib->ref_count++;
+               return intr->ib;
+       }
+
+       if (list_empty(&ib_mod->ib_free_q)) {
+               bna_intr_put(ib_mod, intr);
+               return NULL;
+       }
+
+       bfa_q_deq(&ib_mod->ib_free_q, &ib);
+       bfa_q_qe_init(&ib->qe);
+
+       ib->ref_count = 1;
+       ib->start_count = 0;
+       ib->idx_mask = 0;
+
+       ib->intr = intr;
+       ib->idx_seg = NULL;
+       intr->ib = ib;
+
+       ib->bna = ib_mod->bna;
+
+       return ib;
+}
+
+void
+bna_ib_put(struct bna_ib_mod *ib_mod, struct bna_ib *ib)
+{
+       bna_intr_put(ib_mod, ib->intr);
+
+       ib->ref_count--;
+
+       if (ib->ref_count == 0) {
+               ib->intr = NULL;
+               ib->bna = NULL;
+               list_add_tail(&ib->qe, &ib_mod->ib_free_q);
+       }
+}
+
+/* Returns index offset - starting from 0 */
+int
+bna_ib_reserve_idx(struct bna_ib *ib)
+{
+       struct bna_ib_mod *ib_mod = &ib->bna->ib_mod;
+       struct bna_ibidx_seg *idx_seg;
+       int idx;
+       int num_idx;
+       int q_idx;
+
+       /* Find the first free index position */
+       bna_ib_find_free_ibidx(ib->idx_mask, idx);
+       if (idx == BFI_IBIDX_MAX_SEGSIZE)
+               return -1;
+
+       /*
+        * Calculate the total number of indexes held by this IB,
+        * including the index newly reserved above.
+        */
+       bna_ib_count_ibidx((ib->idx_mask | (1 << idx)), num_idx);
+
+       /* See if there is a free space in the index segment held by this IB */
+       if (ib->idx_seg && (num_idx <= ib->idx_seg->ib_seg_size)) {
+               ib->idx_mask |= (1 << idx);
+               return idx;
+       }
+
+       if (ib->start_count)
+               return -1;
+
+       /* Allocate a new segment */
+       bna_ib_select_segpool(num_idx, q_idx);
+       while (1) {
+               if (q_idx == BFI_IBIDX_TOTAL_POOLS)
+                       return -1;
+               if (!list_empty(&ib_mod->ibidx_seg_pool[q_idx]))
+                       break;
+               q_idx++;
+       }
+       bfa_q_deq(&ib_mod->ibidx_seg_pool[q_idx], &idx_seg);
+       bfa_q_qe_init(&idx_seg->qe);
+
+       /* Free the old segment */
+       if (ib->idx_seg) {
+               bna_ib_select_segpool(ib->idx_seg->ib_seg_size, q_idx);
+               list_add_tail(&ib->idx_seg->qe, &ib_mod->ibidx_seg_pool[q_idx]);
+       }
+
+       ib->idx_seg = idx_seg;
+
+       ib->idx_mask |= (1 << idx);
+
+       return idx;
+}
+
+void
+bna_ib_release_idx(struct bna_ib *ib, int idx)
+{
+       struct bna_ib_mod *ib_mod = &ib->bna->ib_mod;
+       struct bna_ibidx_seg *idx_seg;
+       int num_idx;
+       int cur_q_idx;
+       int new_q_idx;
+
+       ib->idx_mask &= ~(1 << idx);
+
+       if (ib->start_count)
+               return;
+
+       bna_ib_count_ibidx(ib->idx_mask, num_idx);
+
+       /*
+        * Free the segment, if there are no more indexes in the segment
+        * held by this IB
+        */
+       if (!num_idx) {
+               bna_ib_select_segpool(ib->idx_seg->ib_seg_size, cur_q_idx);
+               list_add_tail(&ib->idx_seg->qe,
+                       &ib_mod->ibidx_seg_pool[cur_q_idx]);
+               ib->idx_seg = NULL;
+               return;
+       }
+
+       /* See if we can move to a smaller segment */
+       bna_ib_select_segpool(num_idx, new_q_idx);
+       bna_ib_select_segpool(ib->idx_seg->ib_seg_size, cur_q_idx);
+       while (new_q_idx < cur_q_idx) {
+               if (!list_empty(&ib_mod->ibidx_seg_pool[new_q_idx]))
+                       break;
+               new_q_idx++;
+       }
+       if (new_q_idx < cur_q_idx) {
+               /* Select the new smaller segment */
+               bfa_q_deq(&ib_mod->ibidx_seg_pool[new_q_idx], &idx_seg);
+               bfa_q_qe_init(&idx_seg->qe);
+               /* Free the old segment */
+               list_add_tail(&ib->idx_seg->qe,
+                       &ib_mod->ibidx_seg_pool[cur_q_idx]);
+               ib->idx_seg = idx_seg;
+       }
+}
+
+int
+bna_ib_config(struct bna_ib *ib, struct bna_ib_config *ib_config)
+{
+       if (ib->start_count)
+               return -1;
+
+       ib->ib_config.coalescing_timeo = ib_config->coalescing_timeo;
+       ib->ib_config.interpkt_timeo = ib_config->interpkt_timeo;
+       ib->ib_config.interpkt_count = ib_config->interpkt_count;
+       ib->ib_config.ctrl_flags = ib_config->ctrl_flags;
+
+       ib->ib_config.ctrl_flags |= BFI_IB_CF_MASTER_ENABLE;
+       if (ib->intr->intr_type == BNA_INTR_T_MSIX)
+               ib->ib_config.ctrl_flags |= BFI_IB_CF_MSIX_MODE;
+
+       return 0;
+}
+
+void
+bna_ib_start(struct bna_ib *ib)
+{
+       struct bna_ib_blk_mem ib_cfg;
+       struct bna_ib_blk_mem *ib_mem;
+       u32 pg_num;
+       u32 intx_mask;
+       int i;
+       void __iomem *base_addr;
+       unsigned long off;
+
+       ib->start_count++;
+
+       if (ib->start_count > 1)
+               return;
+
+       ib_cfg.host_addr_lo = (u32)(ib->ib_seg_host_addr.lsb);
+       ib_cfg.host_addr_hi = (u32)(ib->ib_seg_host_addr.msb);
+
+       ib_cfg.clsc_n_ctrl_n_msix = (((u32)
+                                    ib->ib_config.coalescing_timeo << 16) |
+                               ((u32)ib->ib_config.ctrl_flags << 8) |
+                               (ib->intr->vector));
+       ib_cfg.ipkt_n_ent_n_idxof =
+                               ((u32)
+                                (ib->ib_config.interpkt_timeo & 0xf) << 16) |
+                               ((u32)ib->idx_seg->ib_seg_size << 8) |
+                               (ib->idx_seg->ib_idx_tbl_offset);
+       ib_cfg.ipkt_cnt_cfg_n_unacked = ((u32)
+                                        ib->ib_config.interpkt_count << 24);
+
+       pg_num = BNA_GET_PAGE_NUM(HQM0_BLK_PG_NUM + ib->bna->port_num,
+                               HQM_IB_RAM_BASE_OFFSET);
+       writel(pg_num, ib->bna->regs.page_addr);
+
+       base_addr = BNA_GET_MEM_BASE_ADDR(ib->bna->pcidev.pci_bar_kva,
+                                       HQM_IB_RAM_BASE_OFFSET);
+
+       ib_mem = (struct bna_ib_blk_mem *)0;
+       off = (unsigned long)&ib_mem[ib->ib_id].host_addr_lo;
+       writel(htonl(ib_cfg.host_addr_lo), base_addr + off);
+
+       off = (unsigned long)&ib_mem[ib->ib_id].host_addr_hi;
+       writel(htonl(ib_cfg.host_addr_hi), base_addr + off);
+
+       off = (unsigned long)&ib_mem[ib->ib_id].clsc_n_ctrl_n_msix;
+       writel(ib_cfg.clsc_n_ctrl_n_msix, base_addr + off);
+
+       off = (unsigned long)&ib_mem[ib->ib_id].ipkt_n_ent_n_idxof;
+       writel(ib_cfg.ipkt_n_ent_n_idxof, base_addr + off);
+
+       off = (unsigned long)&ib_mem[ib->ib_id].ipkt_cnt_cfg_n_unacked;
+       writel(ib_cfg.ipkt_cnt_cfg_n_unacked, base_addr + off);
+
+       ib->door_bell.doorbell_ack = BNA_DOORBELL_IB_INT_ACK(
+                               (u32)ib->ib_config.coalescing_timeo, 0);
+
+       pg_num = BNA_GET_PAGE_NUM(HQM0_BLK_PG_NUM + ib->bna->port_num,
+                               HQM_INDX_TBL_RAM_BASE_OFFSET);
+       writel(pg_num, ib->bna->regs.page_addr);
+
+       base_addr = BNA_GET_MEM_BASE_ADDR(ib->bna->pcidev.pci_bar_kva,
+                                       HQM_INDX_TBL_RAM_BASE_OFFSET);
+       for (i = 0; i < ib->idx_seg->ib_seg_size; i++) {
+               off = (unsigned long)
+               ((ib->idx_seg->ib_idx_tbl_offset + i) * BFI_IBIDX_SIZE);
+               writel(0, base_addr + off);
+       }
+
+       if (ib->intr->intr_type == BNA_INTR_T_INTX) {
+               bna_intx_disable(ib->bna, intx_mask);
+               intx_mask &= ~(ib->intr->vector);
+               bna_intx_enable(ib->bna, intx_mask);
+       }
+}
+
+void
+bna_ib_stop(struct bna_ib *ib)
+{
+       u32 intx_mask;
+
+       ib->start_count--;
+
+       if (ib->start_count == 0) {
+               writel(BNA_DOORBELL_IB_INT_DISABLE,
+                               ib->door_bell.doorbell_addr);
+               if (ib->intr->intr_type == BNA_INTR_T_INTX) {
+                       bna_intx_disable(ib->bna, intx_mask);
+                       intx_mask |= (ib->intr->vector);
+                       bna_intx_enable(ib->bna, intx_mask);
+               }
+       }
+}
+
+void
+bna_ib_fail(struct bna_ib *ib)
+{
+       ib->start_count = 0;
+}
+
+/**
+ * RXF
+ */
+static void rxf_enable(struct bna_rxf *rxf);
+static void rxf_disable(struct bna_rxf *rxf);
+static void __rxf_config_set(struct bna_rxf *rxf);
+static void __rxf_rit_set(struct bna_rxf *rxf);
+static void __bna_rxf_stat_clr(struct bna_rxf *rxf);
+static int rxf_process_packet_filter(struct bna_rxf *rxf);
+static int rxf_clear_packet_filter(struct bna_rxf *rxf);
+static void rxf_reset_packet_filter(struct bna_rxf *rxf);
+static void rxf_cb_enabled(void *arg, int status);
+static void rxf_cb_disabled(void *arg, int status);
+static void bna_rxf_cb_stats_cleared(void *arg, int status);
+static void __rxf_enable(struct bna_rxf *rxf);
+static void __rxf_disable(struct bna_rxf *rxf);
+
+bfa_fsm_state_decl(bna_rxf, stopped, struct bna_rxf,
+                       enum bna_rxf_event);
+bfa_fsm_state_decl(bna_rxf, start_wait, struct bna_rxf,
+                       enum bna_rxf_event);
+bfa_fsm_state_decl(bna_rxf, cam_fltr_mod_wait, struct bna_rxf,
+                       enum bna_rxf_event);
+bfa_fsm_state_decl(bna_rxf, started, struct bna_rxf,
+                       enum bna_rxf_event);
+bfa_fsm_state_decl(bna_rxf, cam_fltr_clr_wait, struct bna_rxf,
+                       enum bna_rxf_event);
+bfa_fsm_state_decl(bna_rxf, stop_wait, struct bna_rxf,
+                       enum bna_rxf_event);
+bfa_fsm_state_decl(bna_rxf, pause_wait, struct bna_rxf,
+                       enum bna_rxf_event);
+bfa_fsm_state_decl(bna_rxf, resume_wait, struct bna_rxf,
+                       enum bna_rxf_event);
+bfa_fsm_state_decl(bna_rxf, stat_clr_wait, struct bna_rxf,
+                       enum bna_rxf_event);
+
+static struct bfa_sm_table rxf_sm_table[] = {
+       {BFA_SM(bna_rxf_sm_stopped), BNA_RXF_STOPPED},
+       {BFA_SM(bna_rxf_sm_start_wait), BNA_RXF_START_WAIT},
+       {BFA_SM(bna_rxf_sm_cam_fltr_mod_wait), BNA_RXF_CAM_FLTR_MOD_WAIT},
+       {BFA_SM(bna_rxf_sm_started), BNA_RXF_STARTED},
+       {BFA_SM(bna_rxf_sm_cam_fltr_clr_wait), BNA_RXF_CAM_FLTR_CLR_WAIT},
+       {BFA_SM(bna_rxf_sm_stop_wait), BNA_RXF_STOP_WAIT},
+       {BFA_SM(bna_rxf_sm_pause_wait), BNA_RXF_PAUSE_WAIT},
+       {BFA_SM(bna_rxf_sm_resume_wait), BNA_RXF_RESUME_WAIT},
+       {BFA_SM(bna_rxf_sm_stat_clr_wait), BNA_RXF_STAT_CLR_WAIT}
+};
+
+static void
+bna_rxf_sm_stopped_entry(struct bna_rxf *rxf)
+{
+       call_rxf_stop_cbfn(rxf, BNA_CB_SUCCESS);
+}
+
+static void
+bna_rxf_sm_stopped(struct bna_rxf *rxf, enum bna_rxf_event event)
+{
+       switch (event) {
+       case RXF_E_START:
+               bfa_fsm_set_state(rxf, bna_rxf_sm_start_wait);
+               break;
+
+       case RXF_E_STOP:
+               bfa_fsm_set_state(rxf, bna_rxf_sm_stopped);
+               break;
+
+       case RXF_E_FAIL:
+               /* No-op */
+               break;
+
+       case RXF_E_CAM_FLTR_MOD:
+               call_rxf_cam_fltr_cbfn(rxf, BNA_CB_SUCCESS);
+               break;
+
+       case RXF_E_STARTED:
+       case RXF_E_STOPPED:
+       case RXF_E_CAM_FLTR_RESP:
+               /**
+                * These events are received due to flushing of mbox
+                * when device fails
+                */
+               /* No-op */
+               break;
+
+       case RXF_E_PAUSE:
+               rxf->rxf_oper_state = BNA_RXF_OPER_STATE_PAUSED;
+               call_rxf_pause_cbfn(rxf, BNA_CB_SUCCESS);
+               break;
+
+       case RXF_E_RESUME:
+               rxf->rxf_oper_state = BNA_RXF_OPER_STATE_RUNNING;
+               call_rxf_resume_cbfn(rxf, BNA_CB_SUCCESS);
+               break;
+
+       default:
+               bfa_sm_fault(rxf->rx->bna, event);
+       }
+}
+
+static void
+bna_rxf_sm_start_wait_entry(struct bna_rxf *rxf)
+{
+       __rxf_config_set(rxf);
+       __rxf_rit_set(rxf);
+       rxf_enable(rxf);
+}
+
+static void
+bna_rxf_sm_start_wait(struct bna_rxf *rxf, enum bna_rxf_event event)
+{
+       switch (event) {
+       case RXF_E_STOP:
+               /**
+                * STOP is originated from bnad. When this happens,
+                * it can not be waiting for filter update
+                */
+               call_rxf_start_cbfn(rxf, BNA_CB_INTERRUPT);
+               bfa_fsm_set_state(rxf, bna_rxf_sm_stop_wait);
+               break;
+
+       case RXF_E_FAIL:
+               call_rxf_cam_fltr_cbfn(rxf, BNA_CB_SUCCESS);
+               call_rxf_start_cbfn(rxf, BNA_CB_FAIL);
+               bfa_fsm_set_state(rxf, bna_rxf_sm_stopped);
+               break;
+
+       case RXF_E_CAM_FLTR_MOD:
+               /* No-op */
+               break;
+
+       case RXF_E_STARTED:
+               /**
+                * Force rxf_process_filter() to go through initial
+                * config
+                */
+               if ((rxf->ucast_active_mac != NULL) &&
+                       (rxf->ucast_pending_set == 0))
+                       rxf->ucast_pending_set = 1;
+
+               if (rxf->rss_status == BNA_STATUS_T_ENABLED)
+                       rxf->rxf_flags |= BNA_RXF_FL_RSS_CONFIG_PENDING;
+
+               rxf->rxf_flags |= BNA_RXF_FL_VLAN_CONFIG_PENDING;
+
+               bfa_fsm_set_state(rxf, bna_rxf_sm_cam_fltr_mod_wait);
+               break;
+
+       case RXF_E_PAUSE:
+       case RXF_E_RESUME:
+               rxf->rxf_flags |= BNA_RXF_FL_OPERSTATE_CHANGED;
+               break;
+
+       default:
+               bfa_sm_fault(rxf->rx->bna, event);
+       }
+}
+
+static void
+bna_rxf_sm_cam_fltr_mod_wait_entry(struct bna_rxf *rxf)
+{
+       if (!rxf_process_packet_filter(rxf)) {
+               /* No more pending CAM entries to update */
+               bfa_fsm_set_state(rxf, bna_rxf_sm_started);
+       }
+}
+
+static void
+bna_rxf_sm_cam_fltr_mod_wait(struct bna_rxf *rxf, enum bna_rxf_event event)
+{
+       switch (event) {
+       case RXF_E_STOP:
+               /**
+                * STOP is originated from bnad. When this happens,
+                * it can not be waiting for filter update
+                */
+               call_rxf_start_cbfn(rxf, BNA_CB_INTERRUPT);
+               bfa_fsm_set_state(rxf, bna_rxf_sm_cam_fltr_clr_wait);
+               break;
+
+       case RXF_E_FAIL:
+               rxf_reset_packet_filter(rxf);
+               call_rxf_cam_fltr_cbfn(rxf, BNA_CB_SUCCESS);
+               call_rxf_start_cbfn(rxf, BNA_CB_FAIL);
+               bfa_fsm_set_state(rxf, bna_rxf_sm_stopped);
+               break;
+
+       case RXF_E_CAM_FLTR_MOD:
+               /* No-op */
+               break;
+
+       case RXF_E_CAM_FLTR_RESP:
+               if (!rxf_process_packet_filter(rxf)) {
+                       /* No more pending CAM entries to update */
+                       call_rxf_cam_fltr_cbfn(rxf, BNA_CB_SUCCESS);
+                       bfa_fsm_set_state(rxf, bna_rxf_sm_started);
+               }
+               break;
+
+       case RXF_E_PAUSE:
+       case RXF_E_RESUME:
+               rxf->rxf_flags |= BNA_RXF_FL_OPERSTATE_CHANGED;
+               break;
+
+       default:
+               bfa_sm_fault(rxf->rx->bna, event);
+       }
+}
+
+static void
+bna_rxf_sm_started_entry(struct bna_rxf *rxf)
+{
+       call_rxf_start_cbfn(rxf, BNA_CB_SUCCESS);
+
+       if (rxf->rxf_flags & BNA_RXF_FL_OPERSTATE_CHANGED) {
+               if (rxf->rxf_oper_state == BNA_RXF_OPER_STATE_PAUSED)
+                       bfa_fsm_send_event(rxf, RXF_E_PAUSE);
+               else
+                       bfa_fsm_send_event(rxf, RXF_E_RESUME);
+       }
+
+}
+
+static void
+bna_rxf_sm_started(struct bna_rxf *rxf, enum bna_rxf_event event)
+{
+       switch (event) {
+       case RXF_E_STOP:
+               bfa_fsm_set_state(rxf, bna_rxf_sm_cam_fltr_clr_wait);
+               /* Hack to get FSM start clearing CAM entries */
+               bfa_fsm_send_event(rxf, RXF_E_CAM_FLTR_RESP);
+               break;
+
+       case RXF_E_FAIL:
+               rxf_reset_packet_filter(rxf);
+               bfa_fsm_set_state(rxf, bna_rxf_sm_stopped);
+               break;
+
+       case RXF_E_CAM_FLTR_MOD:
+               bfa_fsm_set_state(rxf, bna_rxf_sm_cam_fltr_mod_wait);
+               break;
+
+       case RXF_E_PAUSE:
+               bfa_fsm_set_state(rxf, bna_rxf_sm_pause_wait);
+               break;
+
+       case RXF_E_RESUME:
+               bfa_fsm_set_state(rxf, bna_rxf_sm_resume_wait);
+               break;
+
+       default:
+               bfa_sm_fault(rxf->rx->bna, event);
+       }
+}
+
+static void
+bna_rxf_sm_cam_fltr_clr_wait_entry(struct bna_rxf *rxf)
+{
+       /**
+        *  Note: Do not add rxf_clear_packet_filter here.
+        * It will overstep mbox when this transition happens:
+        *      cam_fltr_mod_wait -> cam_fltr_clr_wait on RXF_E_STOP event
+        */
+}
+
+static void
+bna_rxf_sm_cam_fltr_clr_wait(struct bna_rxf *rxf, enum bna_rxf_event event)
+{
+       switch (event) {
+       case RXF_E_FAIL:
+               /**
+                * FSM was in the process of stopping, initiated by
+                * bnad. When this happens, no one can be waiting for
+                * start or filter update
+                */
+               rxf_reset_packet_filter(rxf);
+               bfa_fsm_set_state(rxf, bna_rxf_sm_stopped);
+               break;
+
+       case RXF_E_CAM_FLTR_RESP:
+               if (!rxf_clear_packet_filter(rxf)) {
+                       /* No more pending CAM entries to clear */
+                       bfa_fsm_set_state(rxf, bna_rxf_sm_stop_wait);
+                       rxf_disable(rxf);
+               }
+               break;
+
+       default:
+               bfa_sm_fault(rxf->rx->bna, event);
+       }
+}
+
+static void
+bna_rxf_sm_stop_wait_entry(struct bna_rxf *rxf)
+{
+       /**
+        * NOTE: Do not add  rxf_disable here.
+        * It will overstep mbox when this transition happens:
+        *      start_wait -> stop_wait on RXF_E_STOP event
+        */
+}
+
+static void
+bna_rxf_sm_stop_wait(struct bna_rxf *rxf, enum bna_rxf_event event)
+{
+       switch (event) {
+       case RXF_E_FAIL:
+               /**
+                * FSM was in the process of stopping, initiated by
+                * bnad. When this happens, no one can be waiting for
+                * start or filter update
+                */
+               bfa_fsm_set_state(rxf, bna_rxf_sm_stopped);
+               break;
+
+       case RXF_E_STARTED:
+               /**
+                * This event is received due to abrupt transition from
+                * bna_rxf_sm_start_wait state on receiving
+                * RXF_E_STOP event
+                */
+               rxf_disable(rxf);
+               break;
+
+       case RXF_E_STOPPED:
+               /**
+                * FSM was in the process of stopping, initiated by
+                * bnad. When this happens, no one can be waiting for
+                * start or filter update
+                */
+               bfa_fsm_set_state(rxf, bna_rxf_sm_stat_clr_wait);
+               break;
+
+       case RXF_E_PAUSE:
+               rxf->rxf_oper_state = BNA_RXF_OPER_STATE_PAUSED;
+               break;
+
+       case RXF_E_RESUME:
+               rxf->rxf_oper_state = BNA_RXF_OPER_STATE_RUNNING;
+               break;
+
+       default:
+               bfa_sm_fault(rxf->rx->bna, event);
+       }
+}
+
+static void
+bna_rxf_sm_pause_wait_entry(struct bna_rxf *rxf)
+{
+       rxf->rxf_flags &=
+               ~(BNA_RXF_FL_OPERSTATE_CHANGED | BNA_RXF_FL_RXF_ENABLED);
+       __rxf_disable(rxf);
+}
+
+static void
+bna_rxf_sm_pause_wait(struct bna_rxf *rxf, enum bna_rxf_event event)
+{
+       switch (event) {
+       case RXF_E_FAIL:
+               /**
+                * FSM was in the process of disabling rxf, initiated by
+                * bnad.
+                */
+               call_rxf_pause_cbfn(rxf, BNA_CB_FAIL);
+               bfa_fsm_set_state(rxf, bna_rxf_sm_stopped);
+               break;
+
+       case RXF_E_STOPPED:
+               rxf->rxf_oper_state = BNA_RXF_OPER_STATE_PAUSED;
+               call_rxf_pause_cbfn(rxf, BNA_CB_SUCCESS);
+               bfa_fsm_set_state(rxf, bna_rxf_sm_started);
+               break;
+
+       /*
+        * Since PAUSE/RESUME can only be sent by bnad, we don't expect
+        * any other event during these states
+        */
+       default:
+               bfa_sm_fault(rxf->rx->bna, event);
+       }
+}
+
+static void
+bna_rxf_sm_resume_wait_entry(struct bna_rxf *rxf)
+{
+       rxf->rxf_flags &= ~(BNA_RXF_FL_OPERSTATE_CHANGED);
+       rxf->rxf_flags |= BNA_RXF_FL_RXF_ENABLED;
+       __rxf_enable(rxf);
+}
+
+static void
+bna_rxf_sm_resume_wait(struct bna_rxf *rxf, enum bna_rxf_event event)
+{
+       switch (event) {
+       case RXF_E_FAIL:
+               /**
+                * FSM was in the process of disabling rxf, initiated by
+                * bnad.
+                */
+               call_rxf_resume_cbfn(rxf, BNA_CB_FAIL);
+               bfa_fsm_set_state(rxf, bna_rxf_sm_stopped);
+               break;
+
+       case RXF_E_STARTED:
+               rxf->rxf_oper_state = BNA_RXF_OPER_STATE_RUNNING;
+               call_rxf_resume_cbfn(rxf, BNA_CB_SUCCESS);
+               bfa_fsm_set_state(rxf, bna_rxf_sm_started);
+               break;
+
+       /*
+        * Since PAUSE/RESUME can only be sent by bnad, we don't expect
+        * any other event during these states
+        */
+       default:
+               bfa_sm_fault(rxf->rx->bna, event);
+       }
+}
+
+static void
+bna_rxf_sm_stat_clr_wait_entry(struct bna_rxf *rxf)
+{
+       __bna_rxf_stat_clr(rxf);
+}
+
+static void
+bna_rxf_sm_stat_clr_wait(struct bna_rxf *rxf, enum bna_rxf_event event)
+{
+       switch (event) {
+       case RXF_E_FAIL:
+       case RXF_E_STAT_CLEARED:
+               bfa_fsm_set_state(rxf, bna_rxf_sm_stopped);
+               break;
+
+       default:
+               bfa_sm_fault(rxf->rx->bna, event);
+       }
+}
+
+static void
+__rxf_enable(struct bna_rxf *rxf)
+{
+       struct bfi_ll_rxf_multi_req ll_req;
+       u32 bm[2] = {0, 0};
+
+       if (rxf->rxf_id < 32)
+               bm[0] = 1 << rxf->rxf_id;
+       else
+               bm[1] = 1 << (rxf->rxf_id - 32);
+
+       bfi_h2i_set(ll_req.mh, BFI_MC_LL, BFI_LL_H2I_RX_REQ, 0);
+       ll_req.rxf_id_mask[0] = htonl(bm[0]);
+       ll_req.rxf_id_mask[1] = htonl(bm[1]);
+       ll_req.enable = 1;
+
+       bna_mbox_qe_fill(&rxf->mbox_qe, &ll_req, sizeof(ll_req),
+                       rxf_cb_enabled, rxf);
+
+       bna_mbox_send(rxf->rx->bna, &rxf->mbox_qe);
+}
+
+static void
+__rxf_disable(struct bna_rxf *rxf)
+{
+       struct bfi_ll_rxf_multi_req ll_req;
+       u32 bm[2] = {0, 0};
+
+       if (rxf->rxf_id < 32)
+               bm[0] = 1 << rxf->rxf_id;
+       else
+               bm[1] = 1 << (rxf->rxf_id - 32);
+
+       bfi_h2i_set(ll_req.mh, BFI_MC_LL, BFI_LL_H2I_RX_REQ, 0);
+       ll_req.rxf_id_mask[0] = htonl(bm[0]);
+       ll_req.rxf_id_mask[1] = htonl(bm[1]);
+       ll_req.enable = 0;
+
+       bna_mbox_qe_fill(&rxf->mbox_qe, &ll_req, sizeof(ll_req),
+                       rxf_cb_disabled, rxf);
+
+       bna_mbox_send(rxf->rx->bna, &rxf->mbox_qe);
+}
+
+static void
+__rxf_config_set(struct bna_rxf *rxf)
+{
+       u32 i;
+       struct bna_rss_mem *rss_mem;
+       struct bna_rx_fndb_ram *rx_fndb_ram;
+       struct bna *bna = rxf->rx->bna;
+       void __iomem *base_addr;
+       unsigned long off;
+
+       base_addr = BNA_GET_MEM_BASE_ADDR(bna->pcidev.pci_bar_kva,
+                       RSS_TABLE_BASE_OFFSET);
+
+       rss_mem = (struct bna_rss_mem *)0;
+
+       /* Configure RSS if required */
+       if (rxf->ctrl_flags & BNA_RXF_CF_RSS_ENABLE) {
+               /* configure RSS Table */
+               writel(BNA_GET_PAGE_NUM(RAD0_MEM_BLK_BASE_PG_NUM +
+                       bna->port_num, RSS_TABLE_BASE_OFFSET),
+                                       bna->regs.page_addr);
+
+               /* temporarily disable RSS, while hash value is written */
+               off = (unsigned long)&rss_mem[0].type_n_hash;
+               writel(0, base_addr + off);
+
+               for (i = 0; i < BFI_RSS_HASH_KEY_LEN; i++) {
+                       off = (unsigned long)
+                       &rss_mem[0].hash_key[(BFI_RSS_HASH_KEY_LEN - 1) - i];
+                       writel(htonl(rxf->rss_cfg.toeplitz_hash_key[i]),
+                       base_addr + off);
+               }
+
+               off = (unsigned long)&rss_mem[0].type_n_hash;
+               writel(rxf->rss_cfg.hash_type | rxf->rss_cfg.hash_mask,
+                       base_addr + off);
+       }
+
+       /* Configure RxF */
+       writel(BNA_GET_PAGE_NUM(
+               LUT0_MEM_BLK_BASE_PG_NUM + (bna->port_num * 2),
+               RX_FNDB_RAM_BASE_OFFSET),
+               bna->regs.page_addr);
+
+       base_addr = BNA_GET_MEM_BASE_ADDR(bna->pcidev.pci_bar_kva,
+               RX_FNDB_RAM_BASE_OFFSET);
+
+       rx_fndb_ram = (struct bna_rx_fndb_ram *)0;
+
+       /* We always use RSS table 0 */
+       off = (unsigned long)&rx_fndb_ram[rxf->rxf_id].rss_prop;
+       writel(rxf->ctrl_flags & BNA_RXF_CF_RSS_ENABLE,
+               base_addr + off);
+
+       /* small large buffer enable/disable */
+       off = (unsigned long)&rx_fndb_ram[rxf->rxf_id].size_routing_props;
+       writel((rxf->ctrl_flags & BNA_RXF_CF_SM_LG_RXQ) | 0x80,
+               base_addr + off);
+
+       /* RIT offset,  HDS forced offset, multicast RxQ Id */
+       off = (unsigned long)&rx_fndb_ram[rxf->rxf_id].rit_hds_mcastq;
+       writel((rxf->rit_segment->rit_offset << 16) |
+               (rxf->forced_offset << 8) |
+               (rxf->hds_cfg.hdr_type & BNA_HDS_FORCED) | rxf->mcast_rxq_id,
+               base_addr + off);
+
+       /*
+        * default vlan tag, default function enable, strip vlan bytes,
+        * HDS type, header size
+        */
+
+       off = (unsigned long)&rx_fndb_ram[rxf->rxf_id].control_flags;
+        writel(((u32)rxf->default_vlan_tag << 16) |
+               (rxf->ctrl_flags &
+                       (BNA_RXF_CF_DEFAULT_VLAN |
+                       BNA_RXF_CF_DEFAULT_FUNCTION_ENABLE |
+                       BNA_RXF_CF_VLAN_STRIP)) |
+               (rxf->hds_cfg.hdr_type & ~BNA_HDS_FORCED) |
+               rxf->hds_cfg.header_size,
+               base_addr + off);
+}
+
+void
+__rxf_vlan_filter_set(struct bna_rxf *rxf, enum bna_status status)
+{
+       struct bna *bna = rxf->rx->bna;
+       int i;
+
+       writel(BNA_GET_PAGE_NUM(LUT0_MEM_BLK_BASE_PG_NUM +
+                       (bna->port_num * 2), VLAN_RAM_BASE_OFFSET),
+                       bna->regs.page_addr);
+
+       if (status == BNA_STATUS_T_ENABLED) {
+               /* enable VLAN filtering on this function */
+               for (i = 0; i <= BFI_MAX_VLAN / 32; i++) {
+                       writel(rxf->vlan_filter_table[i],
+                                       BNA_GET_VLAN_MEM_ENTRY_ADDR
+                                       (bna->pcidev.pci_bar_kva, rxf->rxf_id,
+                                               i * 32));
+               }
+       } else {
+               /* disable VLAN filtering on this function */
+               for (i = 0; i <= BFI_MAX_VLAN / 32; i++) {
+                       writel(0xffffffff,
+                                       BNA_GET_VLAN_MEM_ENTRY_ADDR
+                                       (bna->pcidev.pci_bar_kva, rxf->rxf_id,
+                                               i * 32));
+               }
+       }
+}
+
+static void
+__rxf_rit_set(struct bna_rxf *rxf)
+{
+       struct bna *bna = rxf->rx->bna;
+       struct bna_rit_mem *rit_mem;
+       int i;
+       void __iomem *base_addr;
+       unsigned long off;
+
+       base_addr = BNA_GET_MEM_BASE_ADDR(bna->pcidev.pci_bar_kva,
+                       FUNCTION_TO_RXQ_TRANSLATE);
+
+       rit_mem = (struct bna_rit_mem *)0;
+
+       writel(BNA_GET_PAGE_NUM(RXA0_MEM_BLK_BASE_PG_NUM + bna->port_num,
+               FUNCTION_TO_RXQ_TRANSLATE),
+               bna->regs.page_addr);
+
+       for (i = 0; i < rxf->rit_segment->rit_size; i++) {
+               off = (unsigned long)&rit_mem[i + rxf->rit_segment->rit_offset];
+               writel(rxf->rit_segment->rit[i].large_rxq_id << 6 |
+                       rxf->rit_segment->rit[i].small_rxq_id,
+                       base_addr + off);
+       }
+}
+
+static void
+__bna_rxf_stat_clr(struct bna_rxf *rxf)
+{
+       struct bfi_ll_stats_req ll_req;
+       u32 bm[2] = {0, 0};
+
+       if (rxf->rxf_id < 32)
+               bm[0] = 1 << rxf->rxf_id;
+       else
+               bm[1] = 1 << (rxf->rxf_id - 32);
+
+       bfi_h2i_set(ll_req.mh, BFI_MC_LL, BFI_LL_H2I_STATS_CLEAR_REQ, 0);
+       ll_req.stats_mask = 0;
+       ll_req.txf_id_mask[0] = 0;
+       ll_req.txf_id_mask[1] = 0;
+
+       ll_req.rxf_id_mask[0] = htonl(bm[0]);
+       ll_req.rxf_id_mask[1] = htonl(bm[1]);
+
+       bna_mbox_qe_fill(&rxf->mbox_qe, &ll_req, sizeof(ll_req),
+                       bna_rxf_cb_stats_cleared, rxf);
+       bna_mbox_send(rxf->rx->bna, &rxf->mbox_qe);
+}
+
+static void
+rxf_enable(struct bna_rxf *rxf)
+{
+       if (rxf->rxf_oper_state == BNA_RXF_OPER_STATE_PAUSED)
+               bfa_fsm_send_event(rxf, RXF_E_STARTED);
+       else {
+               rxf->rxf_flags |= BNA_RXF_FL_RXF_ENABLED;
+               __rxf_enable(rxf);
+       }
+}
+
+static void
+rxf_cb_enabled(void *arg, int status)
+{
+       struct bna_rxf *rxf = (struct bna_rxf *)arg;
+
+       bfa_q_qe_init(&rxf->mbox_qe.qe);
+       bfa_fsm_send_event(rxf, RXF_E_STARTED);
+}
+
+static void
+rxf_disable(struct bna_rxf *rxf)
+{
+       if (rxf->rxf_oper_state == BNA_RXF_OPER_STATE_PAUSED)
+               bfa_fsm_send_event(rxf, RXF_E_STOPPED);
+       else
+               rxf->rxf_flags &= ~BNA_RXF_FL_RXF_ENABLED;
+               __rxf_disable(rxf);
+}
+
+static void
+rxf_cb_disabled(void *arg, int status)
+{
+       struct bna_rxf *rxf = (struct bna_rxf *)arg;
+
+       bfa_q_qe_init(&rxf->mbox_qe.qe);
+       bfa_fsm_send_event(rxf, RXF_E_STOPPED);
+}
+
+void
+rxf_cb_cam_fltr_mbox_cmd(void *arg, int status)
+{
+       struct bna_rxf *rxf = (struct bna_rxf *)arg;
+
+       bfa_q_qe_init(&rxf->mbox_qe.qe);
+
+       bfa_fsm_send_event(rxf, RXF_E_CAM_FLTR_RESP);
+}
+
+static void
+bna_rxf_cb_stats_cleared(void *arg, int status)
+{
+       struct bna_rxf *rxf = (struct bna_rxf *)arg;
+
+       bfa_q_qe_init(&rxf->mbox_qe.qe);
+       bfa_fsm_send_event(rxf, RXF_E_STAT_CLEARED);
+}
+
+void
+rxf_cam_mbox_cmd(struct bna_rxf *rxf, u8 cmd,
+               const struct bna_mac *mac_addr)
+{
+       struct bfi_ll_mac_addr_req req;
+
+       bfi_h2i_set(req.mh, BFI_MC_LL, cmd, 0);
+
+       req.rxf_id = rxf->rxf_id;
+       memcpy(&req.mac_addr, (void *)&mac_addr->addr, ETH_ALEN);
+
+       bna_mbox_qe_fill(&rxf->mbox_qe, &req, sizeof(req),
+                               rxf_cb_cam_fltr_mbox_cmd, rxf);
+
+       bna_mbox_send(rxf->rx->bna, &rxf->mbox_qe);
+}
+
+static int
+rxf_process_packet_filter_mcast(struct bna_rxf *rxf)
+{
+       struct bna_mac *mac = NULL;
+       struct list_head *qe;
+
+       /* Add multicast entries */
+       if (!list_empty(&rxf->mcast_pending_add_q)) {
+               bfa_q_deq(&rxf->mcast_pending_add_q, &qe);
+               bfa_q_qe_init(qe);
+               mac = (struct bna_mac *)qe;
+               rxf_cam_mbox_cmd(rxf, BFI_LL_H2I_MAC_MCAST_ADD_REQ, mac);
+               list_add_tail(&mac->qe, &rxf->mcast_active_q);
+               return 1;
+       }
+
+       /* Delete multicast entries previousely added */
+       if (!list_empty(&rxf->mcast_pending_del_q)) {
+               bfa_q_deq(&rxf->mcast_pending_del_q, &qe);
+               bfa_q_qe_init(qe);
+               mac = (struct bna_mac *)qe;
+               rxf_cam_mbox_cmd(rxf, BFI_LL_H2I_MAC_MCAST_DEL_REQ, mac);
+               bna_mcam_mod_mac_put(&rxf->rx->bna->mcam_mod, mac);
+               return 1;
+       }
+
+       return 0;
+}
+
+static int
+rxf_process_packet_filter_vlan(struct bna_rxf *rxf)
+{
+       /* Apply the VLAN filter */
+       if (rxf->rxf_flags & BNA_RXF_FL_VLAN_CONFIG_PENDING) {
+               rxf->rxf_flags &= ~BNA_RXF_FL_VLAN_CONFIG_PENDING;
+               if (!(rxf->rxmode_active & BNA_RXMODE_PROMISC) &&
+                       !(rxf->rxmode_active & BNA_RXMODE_DEFAULT))
+                       __rxf_vlan_filter_set(rxf, rxf->vlan_filter_status);
+       }
+
+       /* Apply RSS configuration */
+       if (rxf->rxf_flags & BNA_RXF_FL_RSS_CONFIG_PENDING) {
+               rxf->rxf_flags &= ~BNA_RXF_FL_RSS_CONFIG_PENDING;
+               if (rxf->rss_status == BNA_STATUS_T_DISABLED) {
+                       /* RSS is being disabled */
+                       rxf->ctrl_flags &= ~BNA_RXF_CF_RSS_ENABLE;
+                       __rxf_rit_set(rxf);
+                       __rxf_config_set(rxf);
+               } else {
+                       /* RSS is being enabled or reconfigured */
+                       rxf->ctrl_flags |= BNA_RXF_CF_RSS_ENABLE;
+                       __rxf_rit_set(rxf);
+                       __rxf_config_set(rxf);
+               }
+       }
+
+       return 0;
+}
+
+/**
+ * Processes pending ucast, mcast entry addition/deletion and issues mailbox
+ * command. Also processes pending filter configuration - promiscuous mode,
+ * default mode, allmutli mode and issues mailbox command or directly applies
+ * to h/w
+ */
+static int
+rxf_process_packet_filter(struct bna_rxf *rxf)
+{
+       /* Set the default MAC first */
+       if (rxf->ucast_pending_set > 0) {
+               rxf_cam_mbox_cmd(rxf, BFI_LL_H2I_MAC_UCAST_SET_REQ,
+                               rxf->ucast_active_mac);
+               rxf->ucast_pending_set--;
+               return 1;
+       }
+
+       if (rxf_process_packet_filter_ucast(rxf))
+               return 1;
+
+       if (rxf_process_packet_filter_mcast(rxf))
+               return 1;
+
+       if (rxf_process_packet_filter_promisc(rxf))
+               return 1;
+
+       if (rxf_process_packet_filter_default(rxf))
+               return 1;
+
+       if (rxf_process_packet_filter_allmulti(rxf))
+               return 1;
+
+       if (rxf_process_packet_filter_vlan(rxf))
+               return 1;
+
+       return 0;
+}
+
+static int
+rxf_clear_packet_filter_mcast(struct bna_rxf *rxf)
+{
+       struct bna_mac *mac = NULL;
+       struct list_head *qe;
+
+       /* 3. delete pending mcast entries */
+       if (!list_empty(&rxf->mcast_pending_del_q)) {
+               bfa_q_deq(&rxf->mcast_pending_del_q, &qe);
+               bfa_q_qe_init(qe);
+               mac = (struct bna_mac *)qe;
+               rxf_cam_mbox_cmd(rxf, BFI_LL_H2I_MAC_MCAST_DEL_REQ, mac);
+               bna_mcam_mod_mac_put(&rxf->rx->bna->mcam_mod, mac);
+               return 1;
+       }
+
+       /* 4. clear active mcast entries; move them to pending_add_q */
+       if (!list_empty(&rxf->mcast_active_q)) {
+               bfa_q_deq(&rxf->mcast_active_q, &qe);
+               bfa_q_qe_init(qe);
+               mac = (struct bna_mac *)qe;
+               rxf_cam_mbox_cmd(rxf, BFI_LL_H2I_MAC_MCAST_DEL_REQ, mac);
+               list_add_tail(&mac->qe, &rxf->mcast_pending_add_q);
+               return 1;
+       }
+
+       return 0;
+}
+
+/**
+ * In the rxf stop path, processes pending ucast/mcast delete queue and issues
+ * the mailbox command. Moves the active ucast/mcast entries to pending add q,
+ * so that they are added to CAM again in the rxf start path. Moves the current
+ * filter settings - promiscuous, default, allmutli - to pending filter
+ * configuration
+ */
+static int
+rxf_clear_packet_filter(struct bna_rxf *rxf)
+{
+       if (rxf_clear_packet_filter_ucast(rxf))
+               return 1;
+
+       if (rxf_clear_packet_filter_mcast(rxf))
+               return 1;
+
+       /* 5. clear active default MAC in the CAM */
+       if (rxf->ucast_pending_set > 0)
+               rxf->ucast_pending_set = 0;
+
+       if (rxf_clear_packet_filter_promisc(rxf))
+               return 1;
+
+       if (rxf_clear_packet_filter_default(rxf))
+               return 1;
+
+       if (rxf_clear_packet_filter_allmulti(rxf))
+               return 1;
+
+       return 0;
+}
+
+static void
+rxf_reset_packet_filter_mcast(struct bna_rxf *rxf)
+{
+       struct list_head *qe;
+       struct bna_mac *mac;
+
+       /* 3. Move active mcast entries to pending_add_q */
+       while (!list_empty(&rxf->mcast_active_q)) {
+               bfa_q_deq(&rxf->mcast_active_q, &qe);
+               bfa_q_qe_init(qe);
+               list_add_tail(qe, &rxf->mcast_pending_add_q);
+       }
+
+       /* 4. Throw away delete pending mcast entries */
+       while (!list_empty(&rxf->mcast_pending_del_q)) {
+               bfa_q_deq(&rxf->mcast_pending_del_q, &qe);
+               bfa_q_qe_init(qe);
+               mac = (struct bna_mac *)qe;
+               bna_mcam_mod_mac_put(&rxf->rx->bna->mcam_mod, mac);
+       }
+}
+
+/**
+ * In the rxf fail path, throws away the ucast/mcast entries pending for
+ * deletion, moves all active ucast/mcast entries to pending queue so that
+ * they are added back to CAM in the rxf start path. Also moves the current
+ * filter configuration to pending filter configuration.
+ */
+static void
+rxf_reset_packet_filter(struct bna_rxf *rxf)
+{
+       rxf_reset_packet_filter_ucast(rxf);
+
+       rxf_reset_packet_filter_mcast(rxf);
+
+       /* 5. Turn off ucast set flag */
+       rxf->ucast_pending_set = 0;
+
+       rxf_reset_packet_filter_promisc(rxf);
+
+       rxf_reset_packet_filter_default(rxf);
+
+       rxf_reset_packet_filter_allmulti(rxf);
+}
+
+void
+bna_rxf_init(struct bna_rxf *rxf,
+               struct bna_rx *rx,
+               struct bna_rx_config *q_config)
+{
+       struct list_head *qe;
+       struct bna_rxp *rxp;
+
+       /* rxf_id is initialized during rx_mod init */
+       rxf->rx = rx;
+
+       INIT_LIST_HEAD(&rxf->ucast_pending_add_q);
+       INIT_LIST_HEAD(&rxf->ucast_pending_del_q);
+       rxf->ucast_pending_set = 0;
+       INIT_LIST_HEAD(&rxf->ucast_active_q);
+       rxf->ucast_active_mac = NULL;
+
+       INIT_LIST_HEAD(&rxf->mcast_pending_add_q);
+       INIT_LIST_HEAD(&rxf->mcast_pending_del_q);
+       INIT_LIST_HEAD(&rxf->mcast_active_q);
+
+       bfa_q_qe_init(&rxf->mbox_qe.qe);
+
+       if (q_config->vlan_strip_status == BNA_STATUS_T_ENABLED)
+               rxf->ctrl_flags |= BNA_RXF_CF_VLAN_STRIP;
+
+       rxf->rxf_oper_state = (q_config->paused) ?
+               BNA_RXF_OPER_STATE_PAUSED : BNA_RXF_OPER_STATE_RUNNING;
+
+       bna_rxf_adv_init(rxf, rx, q_config);
+
+       rxf->rit_segment = bna_rit_mod_seg_get(&rxf->rx->bna->rit_mod,
+                                       q_config->num_paths);
+
+       list_for_each(qe, &rx->rxp_q) {
+               rxp = (struct bna_rxp *)qe;
+               if (q_config->rxp_type == BNA_RXP_SINGLE)
+                       rxf->mcast_rxq_id = rxp->rxq.single.only->rxq_id;
+               else
+                       rxf->mcast_rxq_id = rxp->rxq.slr.large->rxq_id;
+               break;
+       }
+
+       rxf->vlan_filter_status = BNA_STATUS_T_DISABLED;
+       memset(rxf->vlan_filter_table, 0,
+                       (sizeof(u32) * ((BFI_MAX_VLAN + 1) / 32)));
+
+       bfa_fsm_set_state(rxf, bna_rxf_sm_stopped);
+}
+
+void
+bna_rxf_uninit(struct bna_rxf *rxf)
+{
+       struct bna_mac *mac;
+
+       bna_rit_mod_seg_put(&rxf->rx->bna->rit_mod, rxf->rit_segment);
+       rxf->rit_segment = NULL;
+
+       rxf->ucast_pending_set = 0;
+
+       while (!list_empty(&rxf->ucast_pending_add_q)) {
+               bfa_q_deq(&rxf->ucast_pending_add_q, &mac);
+               bfa_q_qe_init(&mac->qe);
+               bna_ucam_mod_mac_put(&rxf->rx->bna->ucam_mod, mac);
+       }
+
+       if (rxf->ucast_active_mac) {
+               bfa_q_qe_init(&rxf->ucast_active_mac->qe);
+               bna_ucam_mod_mac_put(&rxf->rx->bna->ucam_mod,
+                       rxf->ucast_active_mac);
+               rxf->ucast_active_mac = NULL;
+       }
+
+       while (!list_empty(&rxf->mcast_pending_add_q)) {
+               bfa_q_deq(&rxf->mcast_pending_add_q, &mac);
+               bfa_q_qe_init(&mac->qe);
+               bna_mcam_mod_mac_put(&rxf->rx->bna->mcam_mod, mac);
+       }
+
+       rxf->rx = NULL;
+}
+
+void
+bna_rxf_start(struct bna_rxf *rxf)
+{
+       rxf->start_cbfn = bna_rx_cb_rxf_started;
+       rxf->start_cbarg = rxf->rx;
+       rxf->rxf_flags &= ~BNA_RXF_FL_FAILED;
+       bfa_fsm_send_event(rxf, RXF_E_START);
+}
+
+void
+bna_rxf_stop(struct bna_rxf *rxf)
+{
+       rxf->stop_cbfn = bna_rx_cb_rxf_stopped;
+       rxf->stop_cbarg = rxf->rx;
+       bfa_fsm_send_event(rxf, RXF_E_STOP);
+}
+
+void
+bna_rxf_fail(struct bna_rxf *rxf)
+{
+       rxf->rxf_flags |= BNA_RXF_FL_FAILED;
+       bfa_fsm_send_event(rxf, RXF_E_FAIL);
+}
+
+int
+bna_rxf_state_get(struct bna_rxf *rxf)
+{
+       return bfa_sm_to_state(rxf_sm_table, rxf->fsm);
+}
+
+enum bna_cb_status
+bna_rx_ucast_set(struct bna_rx *rx, u8 *ucmac,
+                void (*cbfn)(struct bnad *, struct bna_rx *,
+                             enum bna_cb_status))
+{
+       struct bna_rxf *rxf = &rx->rxf;
+
+       if (rxf->ucast_active_mac == NULL) {
+               rxf->ucast_active_mac =
+                               bna_ucam_mod_mac_get(&rxf->rx->bna->ucam_mod);
+               if (rxf->ucast_active_mac == NULL)
+                       return BNA_CB_UCAST_CAM_FULL;
+               bfa_q_qe_init(&rxf->ucast_active_mac->qe);
+       }
+
+       memcpy(rxf->ucast_active_mac->addr, ucmac, ETH_ALEN);
+       rxf->ucast_pending_set++;
+       rxf->cam_fltr_cbfn = cbfn;
+       rxf->cam_fltr_cbarg = rx->bna->bnad;
+
+       bfa_fsm_send_event(rxf, RXF_E_CAM_FLTR_MOD);
+
+       return BNA_CB_SUCCESS;
+}
+
+enum bna_cb_status
+bna_rx_mcast_add(struct bna_rx *rx, u8 *addr,
+                void (*cbfn)(struct bnad *, struct bna_rx *,
+                             enum bna_cb_status))
+{
+       struct bna_rxf *rxf = &rx->rxf;
+       struct list_head        *qe;
+       struct bna_mac *mac;
+
+       /* Check if already added */
+       list_for_each(qe, &rxf->mcast_active_q) {
+               mac = (struct bna_mac *)qe;
+               if (BNA_MAC_IS_EQUAL(mac->addr, addr)) {
+                       if (cbfn)
+                               (*cbfn)(rx->bna->bnad, rx, BNA_CB_SUCCESS);
+                       return BNA_CB_SUCCESS;
+               }
+       }
+
+       /* Check if pending addition */
+       list_for_each(qe, &rxf->mcast_pending_add_q) {
+               mac = (struct bna_mac *)qe;
+               if (BNA_MAC_IS_EQUAL(mac->addr, addr)) {
+                       if (cbfn)
+                               (*cbfn)(rx->bna->bnad, rx, BNA_CB_SUCCESS);
+                       return BNA_CB_SUCCESS;
+               }
+       }
+
+       mac = bna_mcam_mod_mac_get(&rxf->rx->bna->mcam_mod);
+       if (mac == NULL)
+               return BNA_CB_MCAST_LIST_FULL;
+       bfa_q_qe_init(&mac->qe);
+       memcpy(mac->addr, addr, ETH_ALEN);
+       list_add_tail(&mac->qe, &rxf->mcast_pending_add_q);
+
+       rxf->cam_fltr_cbfn = cbfn;
+       rxf->cam_fltr_cbarg = rx->bna->bnad;
+
+       bfa_fsm_send_event(rxf, RXF_E_CAM_FLTR_MOD);
+
+       return BNA_CB_SUCCESS;
+}
+
+enum bna_cb_status
+bna_rx_mcast_del(struct bna_rx *rx, u8 *addr,
+                void (*cbfn)(struct bnad *, struct bna_rx *,
+                             enum bna_cb_status))
+{
+       struct bna_rxf *rxf = &rx->rxf;
+       struct list_head *qe;
+       struct bna_mac *mac;
+
+       list_for_each(qe, &rxf->mcast_pending_add_q) {
+               mac = (struct bna_mac *)qe;
+               if (BNA_MAC_IS_EQUAL(mac->addr, addr)) {
+                       list_del(qe);
+                       bfa_q_qe_init(qe);
+                       bna_mcam_mod_mac_put(&rxf->rx->bna->mcam_mod, mac);
+                       if (cbfn)
+                               (*cbfn)(rx->bna->bnad, rx, BNA_CB_SUCCESS);
+                       return BNA_CB_SUCCESS;
+               }
+       }
+
+       list_for_each(qe, &rxf->mcast_active_q) {
+               mac = (struct bna_mac *)qe;
+               if (BNA_MAC_IS_EQUAL(mac->addr, addr)) {
+                       list_del(qe);
+                       bfa_q_qe_init(qe);
+                       list_add_tail(qe, &rxf->mcast_pending_del_q);
+                       rxf->cam_fltr_cbfn = cbfn;
+                       rxf->cam_fltr_cbarg = rx->bna->bnad;
+                       bfa_fsm_send_event(rxf, RXF_E_CAM_FLTR_MOD);
+                       return BNA_CB_SUCCESS;
+               }
+       }
+
+       return BNA_CB_INVALID_MAC;
+}
+
+enum bna_cb_status
+bna_rx_mcast_listset(struct bna_rx *rx, int count, u8 *mclist,
+                    void (*cbfn)(struct bnad *, struct bna_rx *,
+                                 enum bna_cb_status))
+{
+       struct bna_rxf *rxf = &rx->rxf;
+       struct list_head list_head;
+       struct list_head *qe;
+       u8 *mcaddr;
+       struct bna_mac *mac;
+       struct bna_mac *mac1;
+       int skip;
+       int delete;
+       int need_hw_config = 0;
+       int i;
+
+       /* Allocate nodes */
+       INIT_LIST_HEAD(&list_head);
+       for (i = 0, mcaddr = mclist; i < count; i++) {
+               mac = bna_mcam_mod_mac_get(&rxf->rx->bna->mcam_mod);
+               if (mac == NULL)
+                       goto err_return;
+               bfa_q_qe_init(&mac->qe);
+               memcpy(mac->addr, mcaddr, ETH_ALEN);
+               list_add_tail(&mac->qe, &list_head);
+
+               mcaddr += ETH_ALEN;
+       }
+
+       /* Schedule for addition */
+       while (!list_empty(&list_head)) {
+               bfa_q_deq(&list_head, &qe);
+               mac = (struct bna_mac *)qe;
+               bfa_q_qe_init(&mac->qe);
+
+               skip = 0;
+
+               /* Skip if already added */
+               list_for_each(qe, &rxf->mcast_active_q) {
+                       mac1 = (struct bna_mac *)qe;
+                       if (BNA_MAC_IS_EQUAL(mac1->addr, mac->addr)) {
+                               bna_mcam_mod_mac_put(&rxf->rx->bna->mcam_mod,
+                                                       mac);
+                               skip = 1;
+                               break;
+                       }
+               }
+
+               if (skip)
+                       continue;
+
+               /* Skip if pending addition */
+               list_for_each(qe, &rxf->mcast_pending_add_q) {
+                       mac1 = (struct bna_mac *)qe;
+                       if (BNA_MAC_IS_EQUAL(mac1->addr, mac->addr)) {
+                               bna_mcam_mod_mac_put(&rxf->rx->bna->mcam_mod,
+                                                       mac);
+                               skip = 1;
+                               break;
+                       }
+               }
+
+               if (skip)
+                       continue;
+
+               need_hw_config = 1;
+               list_add_tail(&mac->qe, &rxf->mcast_pending_add_q);
+       }
+
+       /**
+        * Delete the entries that are in the pending_add_q but not
+        * in the new list
+        */
+       while (!list_empty(&rxf->mcast_pending_add_q)) {
+               bfa_q_deq(&rxf->mcast_pending_add_q, &qe);
+               mac = (struct bna_mac *)qe;
+               bfa_q_qe_init(&mac->qe);
+               for (i = 0, mcaddr = mclist, delete = 1; i < count; i++) {
+                       if (BNA_MAC_IS_EQUAL(mcaddr, mac->addr)) {
+                               delete = 0;
+                               break;
+                       }
+                       mcaddr += ETH_ALEN;
+               }
+               if (delete)
+                       bna_mcam_mod_mac_put(&rxf->rx->bna->mcam_mod, mac);
+               else
+                       list_add_tail(&mac->qe, &list_head);
+       }
+       while (!list_empty(&list_head)) {
+               bfa_q_deq(&list_head, &qe);
+               mac = (struct bna_mac *)qe;
+               bfa_q_qe_init(&mac->qe);
+               list_add_tail(&mac->qe, &rxf->mcast_pending_add_q);
+       }
+
+       /**
+        * Schedule entries for deletion that are in the active_q but not
+        * in the new list
+        */
+       while (!list_empty(&rxf->mcast_active_q)) {
+               bfa_q_deq(&rxf->mcast_active_q, &qe);
+               mac = (struct bna_mac *)qe;
+               bfa_q_qe_init(&mac->qe);
+               for (i = 0, mcaddr = mclist, delete = 1; i < count; i++) {
+                       if (BNA_MAC_IS_EQUAL(mcaddr, mac->addr)) {
+                               delete = 0;
+                               break;
+                       }
+                       mcaddr += ETH_ALEN;
+               }
+               if (delete) {
+                       list_add_tail(&mac->qe, &rxf->mcast_pending_del_q);
+                       need_hw_config = 1;
+               } else {
+                       list_add_tail(&mac->qe, &list_head);
+               }
+       }
+       while (!list_empty(&list_head)) {
+               bfa_q_deq(&list_head, &qe);
+               mac = (struct bna_mac *)qe;
+               bfa_q_qe_init(&mac->qe);
+               list_add_tail(&mac->qe, &rxf->mcast_active_q);
+       }
+
+       if (need_hw_config) {
+               rxf->cam_fltr_cbfn = cbfn;
+               rxf->cam_fltr_cbarg = rx->bna->bnad;
+               bfa_fsm_send_event(rxf, RXF_E_CAM_FLTR_MOD);
+       } else if (cbfn)
+               (*cbfn)(rx->bna->bnad, rx, BNA_CB_SUCCESS);
+
+       return BNA_CB_SUCCESS;
+
+err_return:
+       while (!list_empty(&list_head)) {
+               bfa_q_deq(&list_head, &qe);
+               mac = (struct bna_mac *)qe;
+               bfa_q_qe_init(&mac->qe);
+               bna_mcam_mod_mac_put(&rxf->rx->bna->mcam_mod, mac);
+       }
+
+       return BNA_CB_MCAST_LIST_FULL;
+}
+
+void
+bna_rx_vlan_add(struct bna_rx *rx, int vlan_id)
+{
+       struct bna_rxf *rxf = &rx->rxf;
+       int index = (vlan_id >> 5);
+       int bit = (1 << (vlan_id & 0x1F));
+
+       rxf->vlan_filter_table[index] |= bit;
+       if (rxf->vlan_filter_status == BNA_STATUS_T_ENABLED) {
+               rxf->rxf_flags |= BNA_RXF_FL_VLAN_CONFIG_PENDING;
+               bfa_fsm_send_event(rxf, RXF_E_CAM_FLTR_MOD);
+       }
+}
+
+void
+bna_rx_vlan_del(struct bna_rx *rx, int vlan_id)
+{
+       struct bna_rxf *rxf = &rx->rxf;
+       int index = (vlan_id >> 5);
+       int bit = (1 << (vlan_id & 0x1F));
+
+       rxf->vlan_filter_table[index] &= ~bit;
+       if (rxf->vlan_filter_status == BNA_STATUS_T_ENABLED) {
+               rxf->rxf_flags |= BNA_RXF_FL_VLAN_CONFIG_PENDING;
+               bfa_fsm_send_event(rxf, RXF_E_CAM_FLTR_MOD);
+       }
+}
+
+/**
+ * RX
+ */
+#define        RXQ_RCB_INIT(q, rxp, qdepth, bna, _id, unmapq_mem)      do {    \
+       struct bna_doorbell_qset *_qset;                                \
+       unsigned long off;                                              \
+       (q)->rcb->producer_index = (q)->rcb->consumer_index = 0;        \
+       (q)->rcb->q_depth = (qdepth);                                   \
+       (q)->rcb->unmap_q = unmapq_mem;                                 \
+       (q)->rcb->rxq = (q);                                            \
+       (q)->rcb->cq = &(rxp)->cq;                                      \
+       (q)->rcb->bnad = (bna)->bnad;                                   \
+       _qset = (struct bna_doorbell_qset *)0;                  \
+       off = (unsigned long)&_qset[(q)->rxq_id].rxq[0];                \
+       (q)->rcb->q_dbell = off +                                       \
+               BNA_GET_DOORBELL_BASE_ADDR((bna)->pcidev.pci_bar_kva);  \
+       (q)->rcb->id = _id;                                             \
+} while (0)
+
+#define        BNA_GET_RXQS(qcfg)      (((qcfg)->rxp_type == BNA_RXP_SINGLE) ? \
+       (qcfg)->num_paths : ((qcfg)->num_paths * 2))
+
+#define        SIZE_TO_PAGES(size)     (((size) >> PAGE_SHIFT) + ((((size) &\
+       (PAGE_SIZE - 1)) + (PAGE_SIZE - 1)) >> PAGE_SHIFT))
+
+#define        call_rx_stop_callback(rx, status)                               \
+       if ((rx)->stop_cbfn) {                                          \
+               (*(rx)->stop_cbfn)((rx)->stop_cbarg, rx, (status));     \
+               (rx)->stop_cbfn = NULL;                                 \
+               (rx)->stop_cbarg = NULL;                                \
+       }
+
+/*
+ * Since rx_enable is synchronous callback, there is no start_cbfn required.
+ * Instead, we'll call bnad_rx_post(rxp) so that bnad can post the buffers
+ * for each rxpath.
+ */
+
+#define        call_rx_disable_cbfn(rx, status)                                \
+               if ((rx)->disable_cbfn) {                               \
+                       (*(rx)->disable_cbfn)((rx)->disable_cbarg,      \
+                                       status);                        \
+                       (rx)->disable_cbfn = NULL;                      \
+                       (rx)->disable_cbarg = NULL;                     \
+               }                                                       \
+
+#define        rxqs_reqd(type, num_rxqs)                                       \
+       (((type) == BNA_RXP_SINGLE) ? (num_rxqs) : ((num_rxqs) * 2))
+
+#define rx_ib_fail(rx)                                         \
+do {                                                           \
+       struct bna_rxp *rxp;                                    \
+       struct list_head *qe;                                           \
+       list_for_each(qe, &(rx)->rxp_q) {                               \
+               rxp = (struct bna_rxp *)qe;                     \
+               bna_ib_fail(rxp->cq.ib);                        \
+       }                                                       \
+} while (0)
+
+static void __bna_multi_rxq_stop(struct bna_rxp *, u32 *);
+static void __bna_rxq_start(struct bna_rxq *rxq);
+static void __bna_cq_start(struct bna_cq *cq);
+static void bna_rit_create(struct bna_rx *rx);
+static void bna_rx_cb_multi_rxq_stopped(void *arg, int status);
+static void bna_rx_cb_rxq_stopped_all(void *arg);
+
+bfa_fsm_state_decl(bna_rx, stopped,
+       struct bna_rx, enum bna_rx_event);
+bfa_fsm_state_decl(bna_rx, rxf_start_wait,
+       struct bna_rx, enum bna_rx_event);
+bfa_fsm_state_decl(bna_rx, started,
+       struct bna_rx, enum bna_rx_event);
+bfa_fsm_state_decl(bna_rx, rxf_stop_wait,
+       struct bna_rx, enum bna_rx_event);
+bfa_fsm_state_decl(bna_rx, rxq_stop_wait,
+       struct bna_rx, enum bna_rx_event);
+
+static struct bfa_sm_table rx_sm_table[] = {
+       {BFA_SM(bna_rx_sm_stopped), BNA_RX_STOPPED},
+       {BFA_SM(bna_rx_sm_rxf_start_wait), BNA_RX_RXF_START_WAIT},
+       {BFA_SM(bna_rx_sm_started), BNA_RX_STARTED},
+       {BFA_SM(bna_rx_sm_rxf_stop_wait), BNA_RX_RXF_STOP_WAIT},
+       {BFA_SM(bna_rx_sm_rxq_stop_wait), BNA_RX_RXQ_STOP_WAIT},
+};
+
+static void bna_rx_sm_stopped_entry(struct bna_rx *rx)
+{
+       struct bna_rxp *rxp;
+       struct list_head *qe_rxp;
+
+       list_for_each(qe_rxp, &rx->rxp_q) {
+               rxp = (struct bna_rxp *)qe_rxp;
+               rx->rx_cleanup_cbfn(rx->bna->bnad, rxp->cq.ccb);
+       }
+
+       call_rx_stop_callback(rx, BNA_CB_SUCCESS);
+}
+
+static void bna_rx_sm_stopped(struct bna_rx *rx,
+                               enum bna_rx_event event)
+{
+       switch (event) {
+       case RX_E_START:
+               bfa_fsm_set_state(rx, bna_rx_sm_rxf_start_wait);
+               break;
+       case RX_E_STOP:
+               call_rx_stop_callback(rx, BNA_CB_SUCCESS);
+               break;
+       case RX_E_FAIL:
+               /* no-op */
+               break;
+       default:
+               bfa_sm_fault(rx->bna, event);
+               break;
+       }
+
+}
+
+static void bna_rx_sm_rxf_start_wait_entry(struct bna_rx *rx)
+{
+       struct bna_rxp *rxp;
+       struct list_head *qe_rxp;
+       struct bna_rxq *q0 = NULL, *q1 = NULL;
+
+       /* Setup the RIT */
+       bna_rit_create(rx);
+
+       list_for_each(qe_rxp, &rx->rxp_q) {
+               rxp = (struct bna_rxp *)qe_rxp;
+               bna_ib_start(rxp->cq.ib);
+               GET_RXQS(rxp, q0, q1);
+               q0->buffer_size = bna_port_mtu_get(&rx->bna->port);
+               __bna_rxq_start(q0);
+               rx->rx_post_cbfn(rx->bna->bnad, q0->rcb);
+               if (q1)  {
+                       __bna_rxq_start(q1);
+                       rx->rx_post_cbfn(rx->bna->bnad, q1->rcb);
+               }
+               __bna_cq_start(&rxp->cq);
+       }
+
+       bna_rxf_start(&rx->rxf);
+}
+
+static void bna_rx_sm_rxf_start_wait(struct bna_rx *rx,
+                               enum bna_rx_event event)
+{
+       switch (event) {
+       case RX_E_STOP:
+               bfa_fsm_set_state(rx, bna_rx_sm_rxf_stop_wait);
+               break;
+       case RX_E_FAIL:
+               bfa_fsm_set_state(rx, bna_rx_sm_stopped);
+               rx_ib_fail(rx);
+               bna_rxf_fail(&rx->rxf);
+               break;
+       case RX_E_RXF_STARTED:
+               bfa_fsm_set_state(rx, bna_rx_sm_started);
+               break;
+       default:
+               bfa_sm_fault(rx->bna, event);
+               break;
+       }
+}
+
+void
+bna_rx_sm_started_entry(struct bna_rx *rx)
+{
+       struct bna_rxp *rxp;
+       struct list_head *qe_rxp;
+
+       /* Start IB */
+       list_for_each(qe_rxp, &rx->rxp_q) {
+               rxp = (struct bna_rxp *)qe_rxp;
+               bna_ib_ack(&rxp->cq.ib->door_bell, 0);
+       }
+
+       bna_llport_admin_up(&rx->bna->port.llport);
+}
+
+void
+bna_rx_sm_started(struct bna_rx *rx, enum bna_rx_event event)
+{
+       switch (event) {
+       case RX_E_FAIL:
+               bna_llport_admin_down(&rx->bna->port.llport);
+               bfa_fsm_set_state(rx, bna_rx_sm_stopped);
+               rx_ib_fail(rx);
+               bna_rxf_fail(&rx->rxf);
+               break;
+       case RX_E_STOP:
+               bna_llport_admin_down(&rx->bna->port.llport);
+               bfa_fsm_set_state(rx, bna_rx_sm_rxf_stop_wait);
+               break;
+       default:
+               bfa_sm_fault(rx->bna, event);
+               break;
+       }
+}
+
+void
+bna_rx_sm_rxf_stop_wait_entry(struct bna_rx *rx)
+{
+       bna_rxf_stop(&rx->rxf);
+}
+
+void
+bna_rx_sm_rxf_stop_wait(struct bna_rx *rx, enum bna_rx_event event)
+{
+       switch (event) {
+       case RX_E_RXF_STOPPED:
+               bfa_fsm_set_state(rx, bna_rx_sm_rxq_stop_wait);
+               break;
+       case RX_E_RXF_STARTED:
+               /**
+                * RxF was in the process of starting up when
+                * RXF_E_STOP was issued. Ignore this event
+                */
+               break;
+       case RX_E_FAIL:
+               bfa_fsm_set_state(rx, bna_rx_sm_stopped);
+               rx_ib_fail(rx);
+               bna_rxf_fail(&rx->rxf);
+               break;
+       default:
+               bfa_sm_fault(rx->bna, event);
+               break;
+       }
+
+}
+
+void
+bna_rx_sm_rxq_stop_wait_entry(struct bna_rx *rx)
+{
+       struct bna_rxp *rxp = NULL;
+       struct bna_rxq *q0 = NULL;
+       struct bna_rxq *q1 = NULL;
+       struct list_head        *qe;
+       u32 rxq_mask[2] = {0, 0};
+
+       /* Only one call to multi-rxq-stop for all RXPs in this RX */
+       bfa_wc_up(&rx->rxq_stop_wc);
+       list_for_each(qe, &rx->rxp_q) {
+               rxp = (struct bna_rxp *)qe;
+               GET_RXQS(rxp, q0, q1);
+               if (q0->rxq_id < 32)
+                       rxq_mask[0] |= ((u32)1 << q0->rxq_id);
+               else
+                       rxq_mask[1] |= ((u32)1 << (q0->rxq_id - 32));
+               if (q1) {
+                       if (q1->rxq_id < 32)
+                               rxq_mask[0] |= ((u32)1 << q1->rxq_id);
+                       else
+                               rxq_mask[1] |= ((u32)
+                                               1 << (q1->rxq_id - 32));
+               }
+       }
+
+       __bna_multi_rxq_stop(rxp, rxq_mask);
+}
+
+void
+bna_rx_sm_rxq_stop_wait(struct bna_rx *rx, enum bna_rx_event event)
+{
+       struct bna_rxp *rxp = NULL;
+       struct list_head        *qe;
+
+       switch (event) {
+       case RX_E_RXQ_STOPPED:
+               list_for_each(qe, &rx->rxp_q) {
+                       rxp = (struct bna_rxp *)qe;
+                       bna_ib_stop(rxp->cq.ib);
+               }
+               /* Fall through */
+       case RX_E_FAIL:
+               bfa_fsm_set_state(rx, bna_rx_sm_stopped);
+               break;
+       default:
+               bfa_sm_fault(rx->bna, event);
+               break;
+       }
+}
+
+void
+__bna_multi_rxq_stop(struct bna_rxp *rxp, u32 * rxq_id_mask)
+{
+       struct bfi_ll_q_stop_req ll_req;
+
+       bfi_h2i_set(ll_req.mh, BFI_MC_LL, BFI_LL_H2I_RXQ_STOP_REQ, 0);
+       ll_req.q_id_mask[0] = htonl(rxq_id_mask[0]);
+       ll_req.q_id_mask[1] = htonl(rxq_id_mask[1]);
+       bna_mbox_qe_fill(&rxp->mbox_qe, &ll_req, sizeof(ll_req),
+               bna_rx_cb_multi_rxq_stopped, rxp);
+       bna_mbox_send(rxp->rx->bna, &rxp->mbox_qe);
+}
+
+void
+__bna_rxq_start(struct bna_rxq *rxq)
+{
+       struct bna_rxtx_q_mem *q_mem;
+       struct bna_rxq_mem rxq_cfg, *rxq_mem;
+       struct bna_dma_addr cur_q_addr;
+       /* struct bna_doorbell_qset *qset; */
+       struct bna_qpt *qpt;
+       u32 pg_num;
+       struct bna *bna = rxq->rx->bna;
+       void __iomem *base_addr;
+       unsigned long off;
+
+       qpt = &rxq->qpt;
+       cur_q_addr = *((struct bna_dma_addr *)(qpt->kv_qpt_ptr));
+
+       rxq_cfg.pg_tbl_addr_lo = qpt->hw_qpt_ptr.lsb;
+       rxq_cfg.pg_tbl_addr_hi = qpt->hw_qpt_ptr.msb;
+       rxq_cfg.cur_q_entry_lo = cur_q_addr.lsb;
+       rxq_cfg.cur_q_entry_hi = cur_q_addr.msb;
+
+       rxq_cfg.pg_cnt_n_prd_ptr = ((u32)qpt->page_count << 16) | 0x0;
+       rxq_cfg.entry_n_pg_size = ((u32)(BFI_RXQ_WI_SIZE >> 2) << 16) |
+               (qpt->page_size >> 2);
+       rxq_cfg.sg_n_cq_n_cns_ptr =
+               ((u32)(rxq->rxp->cq.cq_id & 0xff) << 16) | 0x0;
+       rxq_cfg.buf_sz_n_q_state = ((u32)rxq->buffer_size << 16) |
+               BNA_Q_IDLE_STATE;
+       rxq_cfg.next_qid = 0x0 | (0x3 << 8);
+
+       /* Write the page number register */
+       pg_num = BNA_GET_PAGE_NUM(HQM0_BLK_PG_NUM + bna->port_num,
+                       HQM_RXTX_Q_RAM_BASE_OFFSET);
+       writel(pg_num, bna->regs.page_addr);
+
+       /* Write to h/w */
+       base_addr = BNA_GET_MEM_BASE_ADDR(bna->pcidev.pci_bar_kva,
+                                       HQM_RXTX_Q_RAM_BASE_OFFSET);
+
+       q_mem = (struct bna_rxtx_q_mem *)0;
+       rxq_mem = &q_mem[rxq->rxq_id].rxq;
+
+       off = (unsigned long)&rxq_mem->pg_tbl_addr_lo;
+       writel(htonl(rxq_cfg.pg_tbl_addr_lo), base_addr + off);
+
+       off = (unsigned long)&rxq_mem->pg_tbl_addr_hi;
+       writel(htonl(rxq_cfg.pg_tbl_addr_hi), base_addr + off);
+
+       off = (unsigned long)&rxq_mem->cur_q_entry_lo;
+       writel(htonl(rxq_cfg.cur_q_entry_lo), base_addr + off);
+
+       off = (unsigned long)&rxq_mem->cur_q_entry_hi;
+       writel(htonl(rxq_cfg.cur_q_entry_hi), base_addr + off);
+
+       off = (unsigned long)&rxq_mem->pg_cnt_n_prd_ptr;
+       writel(rxq_cfg.pg_cnt_n_prd_ptr, base_addr + off);
+
+       off = (unsigned long)&rxq_mem->entry_n_pg_size;
+       writel(rxq_cfg.entry_n_pg_size, base_addr + off);
+
+       off = (unsigned long)&rxq_mem->sg_n_cq_n_cns_ptr;
+       writel(rxq_cfg.sg_n_cq_n_cns_ptr, base_addr + off);
+
+       off = (unsigned long)&rxq_mem->buf_sz_n_q_state;
+       writel(rxq_cfg.buf_sz_n_q_state, base_addr + off);
+
+       off = (unsigned long)&rxq_mem->next_qid;
+       writel(rxq_cfg.next_qid, base_addr + off);
+
+       rxq->rcb->producer_index = 0;
+       rxq->rcb->consumer_index = 0;
+}
+
+void
+__bna_cq_start(struct bna_cq *cq)
+{
+       struct bna_cq_mem cq_cfg, *cq_mem;
+       const struct bna_qpt *qpt;
+       struct bna_dma_addr cur_q_addr;
+       u32 pg_num;
+       struct bna *bna = cq->rx->bna;
+       void __iomem *base_addr;
+       unsigned long off;
+
+       qpt = &cq->qpt;
+       cur_q_addr = *((struct bna_dma_addr *)(qpt->kv_qpt_ptr));
+
+       /*
+        * Fill out structure, to be subsequently written
+        * to hardware
+        */
+       cq_cfg.pg_tbl_addr_lo = qpt->hw_qpt_ptr.lsb;
+       cq_cfg.pg_tbl_addr_hi = qpt->hw_qpt_ptr.msb;
+       cq_cfg.cur_q_entry_lo = cur_q_addr.lsb;
+       cq_cfg.cur_q_entry_hi = cur_q_addr.msb;
+
+       cq_cfg.pg_cnt_n_prd_ptr = (qpt->page_count << 16) | 0x0;
+       cq_cfg.entry_n_pg_size =
+               ((u32)(BFI_CQ_WI_SIZE >> 2) << 16) | (qpt->page_size >> 2);
+       cq_cfg.int_blk_n_cns_ptr = ((((u32)cq->ib_seg_offset) << 24) |
+                       ((u32)(cq->ib->ib_id & 0xff)  << 16) | 0x0);
+       cq_cfg.q_state = BNA_Q_IDLE_STATE;
+
+       /* Write the page number register */
+       pg_num = BNA_GET_PAGE_NUM(HQM0_BLK_PG_NUM + bna->port_num,
+                                 HQM_CQ_RAM_BASE_OFFSET);
+
+       writel(pg_num, bna->regs.page_addr);
+
+       /* H/W write */
+       base_addr = BNA_GET_MEM_BASE_ADDR(bna->pcidev.pci_bar_kva,
+                                       HQM_CQ_RAM_BASE_OFFSET);
+
+       cq_mem = (struct bna_cq_mem *)0;
+
+       off = (unsigned long)&cq_mem[cq->cq_id].pg_tbl_addr_lo;
+       writel(htonl(cq_cfg.pg_tbl_addr_lo), base_addr + off);
+
+       off = (unsigned long)&cq_mem[cq->cq_id].pg_tbl_addr_hi;
+       writel(htonl(cq_cfg.pg_tbl_addr_hi), base_addr + off);
+
+       off = (unsigned long)&cq_mem[cq->cq_id].cur_q_entry_lo;
+       writel(htonl(cq_cfg.cur_q_entry_lo), base_addr + off);
+
+       off = (unsigned long)&cq_mem[cq->cq_id].cur_q_entry_hi;
+       writel(htonl(cq_cfg.cur_q_entry_hi), base_addr + off);
+
+       off = (unsigned long)&cq_mem[cq->cq_id].pg_cnt_n_prd_ptr;
+       writel(cq_cfg.pg_cnt_n_prd_ptr, base_addr + off);
+
+       off = (unsigned long)&cq_mem[cq->cq_id].entry_n_pg_size;
+       writel(cq_cfg.entry_n_pg_size, base_addr + off);
+
+       off = (unsigned long)&cq_mem[cq->cq_id].int_blk_n_cns_ptr;
+       writel(cq_cfg.int_blk_n_cns_ptr, base_addr + off);
+
+       off = (unsigned long)&cq_mem[cq->cq_id].q_state;
+       writel(cq_cfg.q_state, base_addr + off);
+
+       cq->ccb->producer_index = 0;
+       *(cq->ccb->hw_producer_index) = 0;
+}
+
+void
+bna_rit_create(struct bna_rx *rx)
+{
+       struct list_head        *qe_rxp;
+       struct bna *bna;
+       struct bna_rxp *rxp;
+       struct bna_rxq *q0 = NULL;
+       struct bna_rxq *q1 = NULL;
+       int offset;
+
+       bna = rx->bna;
+
+       offset = 0;
+       list_for_each(qe_rxp, &rx->rxp_q) {
+               rxp = (struct bna_rxp *)qe_rxp;
+               GET_RXQS(rxp, q0, q1);
+               rx->rxf.rit_segment->rit[offset].large_rxq_id = q0->rxq_id;
+               rx->rxf.rit_segment->rit[offset].small_rxq_id =
+                                               (q1 ? q1->rxq_id : 0);
+               offset++;
+       }
+}
+
+int
+_rx_can_satisfy(struct bna_rx_mod *rx_mod,
+               struct bna_rx_config *rx_cfg)
+{
+       if ((rx_mod->rx_free_count == 0) ||
+               (rx_mod->rxp_free_count == 0) ||
+               (rx_mod->rxq_free_count == 0))
+               return 0;
+
+       if (rx_cfg->rxp_type == BNA_RXP_SINGLE) {
+               if ((rx_mod->rxp_free_count < rx_cfg->num_paths) ||
+                       (rx_mod->rxq_free_count < rx_cfg->num_paths))
+                               return 0;
+       } else {
+               if ((rx_mod->rxp_free_count < rx_cfg->num_paths) ||
+                       (rx_mod->rxq_free_count < (2 * rx_cfg->num_paths)))
+                       return 0;
+       }
+
+       if (!bna_rit_mod_can_satisfy(&rx_mod->bna->rit_mod, rx_cfg->num_paths))
+               return 0;
+
+       return 1;
+}
+
+struct bna_rxq *
+_get_free_rxq(struct bna_rx_mod *rx_mod)
+{
+       struct bna_rxq *rxq = NULL;
+       struct list_head        *qe = NULL;
+
+       bfa_q_deq(&rx_mod->rxq_free_q, &qe);
+       if (qe) {
+               rx_mod->rxq_free_count--;
+               rxq = (struct bna_rxq *)qe;
+       }
+       return rxq;
+}
+
+void
+_put_free_rxq(struct bna_rx_mod *rx_mod, struct bna_rxq *rxq)
+{
+       bfa_q_qe_init(&rxq->qe);
+       list_add_tail(&rxq->qe, &rx_mod->rxq_free_q);
+       rx_mod->rxq_free_count++;
+}
+
+struct bna_rxp *
+_get_free_rxp(struct bna_rx_mod *rx_mod)
+{
+       struct list_head        *qe = NULL;
+       struct bna_rxp *rxp = NULL;
+
+       bfa_q_deq(&rx_mod->rxp_free_q, &qe);
+       if (qe) {
+               rx_mod->rxp_free_count--;
+
+               rxp = (struct bna_rxp *)qe;
+       }
+
+       return rxp;
+}
+
+void
+_put_free_rxp(struct bna_rx_mod *rx_mod, struct bna_rxp *rxp)
+{
+       bfa_q_qe_init(&rxp->qe);
+       list_add_tail(&rxp->qe, &rx_mod->rxp_free_q);
+       rx_mod->rxp_free_count++;
+}
+
+struct bna_rx *
+_get_free_rx(struct bna_rx_mod *rx_mod)
+{
+       struct list_head        *qe = NULL;
+       struct bna_rx *rx = NULL;
+
+       bfa_q_deq(&rx_mod->rx_free_q, &qe);
+       if (qe) {
+               rx_mod->rx_free_count--;
+
+               rx = (struct bna_rx *)qe;
+               bfa_q_qe_init(qe);
+               list_add_tail(&rx->qe, &rx_mod->rx_active_q);
+       }
+
+       return rx;
+}
+
+void
+_put_free_rx(struct bna_rx_mod *rx_mod, struct bna_rx *rx)
+{
+       bfa_q_qe_init(&rx->qe);
+       list_add_tail(&rx->qe, &rx_mod->rx_free_q);
+       rx_mod->rx_free_count++;
+}
+
+void
+_rx_init(struct bna_rx *rx, struct bna *bna)
+{
+       rx->bna = bna;
+       rx->rx_flags = 0;
+
+       INIT_LIST_HEAD(&rx->rxp_q);
+
+       rx->rxq_stop_wc.wc_resume = bna_rx_cb_rxq_stopped_all;
+       rx->rxq_stop_wc.wc_cbarg = rx;
+       rx->rxq_stop_wc.wc_count = 0;
+
+       rx->stop_cbfn = NULL;
+       rx->stop_cbarg = NULL;
+}
+
+void
+_rxp_add_rxqs(struct bna_rxp *rxp,
+               struct bna_rxq *q0,
+               struct bna_rxq *q1)
+{
+       switch (rxp->type) {
+       case BNA_RXP_SINGLE:
+               rxp->rxq.single.only = q0;
+               rxp->rxq.single.reserved = NULL;
+               break;
+       case BNA_RXP_SLR:
+               rxp->rxq.slr.large = q0;
+               rxp->rxq.slr.small = q1;
+               break;
+       case BNA_RXP_HDS:
+               rxp->rxq.hds.data = q0;
+               rxp->rxq.hds.hdr = q1;
+               break;
+       default:
+               break;
+       }
+}
+
+void
+_rxq_qpt_init(struct bna_rxq *rxq,
+               struct bna_rxp *rxp,
+               u32 page_count,
+               u32 page_size,
+               struct bna_mem_descr *qpt_mem,
+               struct bna_mem_descr *swqpt_mem,
+               struct bna_mem_descr *page_mem)
+{
+       int     i;
+
+       rxq->qpt.hw_qpt_ptr.lsb = qpt_mem->dma.lsb;
+       rxq->qpt.hw_qpt_ptr.msb = qpt_mem->dma.msb;
+       rxq->qpt.kv_qpt_ptr = qpt_mem->kva;
+       rxq->qpt.page_count = page_count;
+       rxq->qpt.page_size = page_size;
+
+       rxq->rcb->sw_qpt = (void **) swqpt_mem->kva;
+
+       for (i = 0; i < rxq->qpt.page_count; i++) {
+               rxq->rcb->sw_qpt[i] = page_mem[i].kva;
+               ((struct bna_dma_addr *)rxq->qpt.kv_qpt_ptr)[i].lsb =
+                       page_mem[i].dma.lsb;
+               ((struct bna_dma_addr *)rxq->qpt.kv_qpt_ptr)[i].msb =
+                       page_mem[i].dma.msb;
+
+       }
+}
+
+void
+_rxp_cqpt_setup(struct bna_rxp *rxp,
+               u32 page_count,
+               u32 page_size,
+               struct bna_mem_descr *qpt_mem,
+               struct bna_mem_descr *swqpt_mem,
+               struct bna_mem_descr *page_mem)
+{
+       int     i;
+
+       rxp->cq.qpt.hw_qpt_ptr.lsb = qpt_mem->dma.lsb;
+       rxp->cq.qpt.hw_qpt_ptr.msb = qpt_mem->dma.msb;
+       rxp->cq.qpt.kv_qpt_ptr = qpt_mem->kva;
+       rxp->cq.qpt.page_count = page_count;
+       rxp->cq.qpt.page_size = page_size;
+
+       rxp->cq.ccb->sw_qpt = (void **) swqpt_mem->kva;
+
+       for (i = 0; i < rxp->cq.qpt.page_count; i++) {
+               rxp->cq.ccb->sw_qpt[i] = page_mem[i].kva;
+
+               ((struct bna_dma_addr *)rxp->cq.qpt.kv_qpt_ptr)[i].lsb =
+                       page_mem[i].dma.lsb;
+               ((struct bna_dma_addr *)rxp->cq.qpt.kv_qpt_ptr)[i].msb =
+                       page_mem[i].dma.msb;
+
+       }
+}
+
+void
+_rx_add_rxp(struct bna_rx *rx, struct bna_rxp *rxp)
+{
+       list_add_tail(&rxp->qe, &rx->rxp_q);
+}
+
+void
+_init_rxmod_queues(struct bna_rx_mod *rx_mod)
+{
+       INIT_LIST_HEAD(&rx_mod->rx_free_q);
+       INIT_LIST_HEAD(&rx_mod->rxq_free_q);
+       INIT_LIST_HEAD(&rx_mod->rxp_free_q);
+       INIT_LIST_HEAD(&rx_mod->rx_active_q);
+
+       rx_mod->rx_free_count = 0;
+       rx_mod->rxq_free_count = 0;
+       rx_mod->rxp_free_count = 0;
+}
+
+void
+_rx_ctor(struct bna_rx *rx, int id)
+{
+       bfa_q_qe_init(&rx->qe);
+       INIT_LIST_HEAD(&rx->rxp_q);
+       rx->bna = NULL;
+
+       rx->rxf.rxf_id = id;
+
+       /* FIXME: mbox_qe ctor()?? */
+       bfa_q_qe_init(&rx->mbox_qe.qe);
+
+       rx->stop_cbfn = NULL;
+       rx->stop_cbarg = NULL;
+}
+
+void
+bna_rx_cb_multi_rxq_stopped(void *arg, int status)
+{
+       struct bna_rxp *rxp = (struct bna_rxp *)arg;
+
+       bfa_wc_down(&rxp->rx->rxq_stop_wc);
+}
+
+void
+bna_rx_cb_rxq_stopped_all(void *arg)
+{
+       struct bna_rx *rx = (struct bna_rx *)arg;
+
+       bfa_fsm_send_event(rx, RX_E_RXQ_STOPPED);
+}
+
+void
+bna_rx_mod_cb_rx_stopped(void *arg, struct bna_rx *rx,
+                        enum bna_cb_status status)
+{
+       struct bna_rx_mod *rx_mod = (struct bna_rx_mod *)arg;
+
+       bfa_wc_down(&rx_mod->rx_stop_wc);
+}
+
+void
+bna_rx_mod_cb_rx_stopped_all(void *arg)
+{
+       struct bna_rx_mod *rx_mod = (struct bna_rx_mod *)arg;
+
+       if (rx_mod->stop_cbfn)
+               rx_mod->stop_cbfn(&rx_mod->bna->port, BNA_CB_SUCCESS);
+       rx_mod->stop_cbfn = NULL;
+}
+
+void
+bna_rx_start(struct bna_rx *rx)
+{
+       rx->rx_flags |= BNA_RX_F_PORT_ENABLED;
+       if (rx->rx_flags & BNA_RX_F_ENABLE)
+               bfa_fsm_send_event(rx, RX_E_START);
+}
+
+void
+bna_rx_stop(struct bna_rx *rx)
+{
+       rx->rx_flags &= ~BNA_RX_F_PORT_ENABLED;
+       if (rx->fsm == (bfa_fsm_t) bna_rx_sm_stopped)
+               bna_rx_mod_cb_rx_stopped(&rx->bna->rx_mod, rx, BNA_CB_SUCCESS);
+       else {
+               rx->stop_cbfn = bna_rx_mod_cb_rx_stopped;
+               rx->stop_cbarg = &rx->bna->rx_mod;
+               bfa_fsm_send_event(rx, RX_E_STOP);
+       }
+}
+
+void
+bna_rx_fail(struct bna_rx *rx)
+{
+       /* Indicate port is not enabled, and failed */
+       rx->rx_flags &= ~BNA_RX_F_PORT_ENABLED;
+       rx->rx_flags |= BNA_RX_F_PORT_FAILED;
+       bfa_fsm_send_event(rx, RX_E_FAIL);
+}
+
+void
+bna_rx_cb_rxf_started(struct bna_rx *rx, enum bna_cb_status status)
+{
+       bfa_fsm_send_event(rx, RX_E_RXF_STARTED);
+       if (rx->rxf.rxf_id < 32)
+               rx->bna->rx_mod.rxf_bmap[0] |= ((u32)1 << rx->rxf.rxf_id);
+       else
+               rx->bna->rx_mod.rxf_bmap[1] |= ((u32)
+                               1 << (rx->rxf.rxf_id - 32));
+}
+
+void
+bna_rx_cb_rxf_stopped(struct bna_rx *rx, enum bna_cb_status status)
+{
+       bfa_fsm_send_event(rx, RX_E_RXF_STOPPED);
+       if (rx->rxf.rxf_id < 32)
+               rx->bna->rx_mod.rxf_bmap[0] &= ~(u32)1 << rx->rxf.rxf_id;
+       else
+               rx->bna->rx_mod.rxf_bmap[1] &= ~(u32)
+                               1 << (rx->rxf.rxf_id - 32);
+}
+
+void
+bna_rx_mod_start(struct bna_rx_mod *rx_mod, enum bna_rx_type type)
+{
+       struct bna_rx *rx;
+       struct list_head *qe;
+
+       rx_mod->flags |= BNA_RX_MOD_F_PORT_STARTED;
+       if (type == BNA_RX_T_LOOPBACK)
+               rx_mod->flags |= BNA_RX_MOD_F_PORT_LOOPBACK;
+
+       list_for_each(qe, &rx_mod->rx_active_q) {
+               rx = (struct bna_rx *)qe;
+               if (rx->type == type)
+                       bna_rx_start(rx);
+       }
+}
+
+void
+bna_rx_mod_stop(struct bna_rx_mod *rx_mod, enum bna_rx_type type)
+{
+       struct bna_rx *rx;
+       struct list_head *qe;
+
+       rx_mod->flags &= ~BNA_RX_MOD_F_PORT_STARTED;
+       rx_mod->flags &= ~BNA_RX_MOD_F_PORT_LOOPBACK;
+
+       rx_mod->stop_cbfn = bna_port_cb_rx_stopped;
+
+       /**
+        * Before calling bna_rx_stop(), increment rx_stop_wc as many times
+        * as we are going to call bna_rx_stop
+        */
+       list_for_each(qe, &rx_mod->rx_active_q) {
+               rx = (struct bna_rx *)qe;
+               if (rx->type == type)
+                       bfa_wc_up(&rx_mod->rx_stop_wc);
+       }
+
+       if (rx_mod->rx_stop_wc.wc_count == 0) {
+               rx_mod->stop_cbfn(&rx_mod->bna->port, BNA_CB_SUCCESS);
+               rx_mod->stop_cbfn = NULL;
+               return;
+       }
+
+       list_for_each(qe, &rx_mod->rx_active_q) {
+               rx = (struct bna_rx *)qe;
+               if (rx->type == type)
+                       bna_rx_stop(rx);
+       }
+}
+
+void
+bna_rx_mod_fail(struct bna_rx_mod *rx_mod)
+{
+       struct bna_rx *rx;
+       struct list_head *qe;
+
+       rx_mod->flags &= ~BNA_RX_MOD_F_PORT_STARTED;
+       rx_mod->flags &= ~BNA_RX_MOD_F_PORT_LOOPBACK;
+
+       list_for_each(qe, &rx_mod->rx_active_q) {
+               rx = (struct bna_rx *)qe;
+               bna_rx_fail(rx);
+       }
+}
+
+void bna_rx_mod_init(struct bna_rx_mod *rx_mod, struct bna *bna,
+                       struct bna_res_info *res_info)
+{
+       int     index;
+       struct bna_rx *rx_ptr;
+       struct bna_rxp *rxp_ptr;
+       struct bna_rxq *rxq_ptr;
+
+       rx_mod->bna = bna;
+       rx_mod->flags = 0;
+
+       rx_mod->rx = (struct bna_rx *)
+               res_info[BNA_RES_MEM_T_RX_ARRAY].res_u.mem_info.mdl[0].kva;
+       rx_mod->rxp = (struct bna_rxp *)
+               res_info[BNA_RES_MEM_T_RXP_ARRAY].res_u.mem_info.mdl[0].kva;
+       rx_mod->rxq = (struct bna_rxq *)
+               res_info[BNA_RES_MEM_T_RXQ_ARRAY].res_u.mem_info.mdl[0].kva;
+
+       /* Initialize the queues */
+       _init_rxmod_queues(rx_mod);
+
+       /* Build RX queues */
+       for (index = 0; index < BFI_MAX_RXQ; index++) {
+               rx_ptr = &rx_mod->rx[index];
+               _rx_ctor(rx_ptr, index);
+               list_add_tail(&rx_ptr->qe, &rx_mod->rx_free_q);
+               rx_mod->rx_free_count++;
+       }
+
+       /* build RX-path queue */
+       for (index = 0; index < BFI_MAX_RXQ; index++) {
+               rxp_ptr = &rx_mod->rxp[index];
+               rxp_ptr->cq.cq_id = index;
+               bfa_q_qe_init(&rxp_ptr->qe);
+               list_add_tail(&rxp_ptr->qe, &rx_mod->rxp_free_q);
+               rx_mod->rxp_free_count++;
+       }
+
+       /* build RXQ queue */
+       for (index = 0; index < BFI_MAX_RXQ; index++) {
+               rxq_ptr = &rx_mod->rxq[index];
+               rxq_ptr->rxq_id = index;
+
+               bfa_q_qe_init(&rxq_ptr->qe);
+               list_add_tail(&rxq_ptr->qe, &rx_mod->rxq_free_q);
+               rx_mod->rxq_free_count++;
+       }
+
+       rx_mod->rx_stop_wc.wc_resume = bna_rx_mod_cb_rx_stopped_all;
+       rx_mod->rx_stop_wc.wc_cbarg = rx_mod;
+       rx_mod->rx_stop_wc.wc_count = 0;
+}
+
+void
+bna_rx_mod_uninit(struct bna_rx_mod *rx_mod)
+{
+       struct list_head                *qe;
+       int i;
+
+       i = 0;
+       list_for_each(qe, &rx_mod->rx_free_q)
+               i++;
+
+       i = 0;
+       list_for_each(qe, &rx_mod->rxp_free_q)
+               i++;
+
+       i = 0;
+       list_for_each(qe, &rx_mod->rxq_free_q)
+               i++;
+
+       rx_mod->bna = NULL;
+}
+
+int
+bna_rx_state_get(struct bna_rx *rx)
+{
+       return bfa_sm_to_state(rx_sm_table, rx->fsm);
+}
+
+void
+bna_rx_res_req(struct bna_rx_config *q_cfg, struct bna_res_info *res_info)
+{
+       u32 cq_size, hq_size, dq_size;
+       u32 cpage_count, hpage_count, dpage_count;
+       struct bna_mem_info *mem_info;
+       u32 cq_depth;
+       u32 hq_depth;
+       u32 dq_depth;
+
+       dq_depth = q_cfg->q_depth;
+       hq_depth = ((q_cfg->rxp_type == BNA_RXP_SINGLE) ? 0 : q_cfg->q_depth);
+       cq_depth = dq_depth + hq_depth;
+
+       BNA_TO_POWER_OF_2_HIGH(cq_depth);
+       cq_size = cq_depth * BFI_CQ_WI_SIZE;
+       cq_size = ALIGN(cq_size, PAGE_SIZE);
+       cpage_count = SIZE_TO_PAGES(cq_size);
+
+       BNA_TO_POWER_OF_2_HIGH(dq_depth);
+       dq_size = dq_depth * BFI_RXQ_WI_SIZE;
+       dq_size = ALIGN(dq_size, PAGE_SIZE);
+       dpage_count = SIZE_TO_PAGES(dq_size);
+
+       if (BNA_RXP_SINGLE != q_cfg->rxp_type) {
+               BNA_TO_POWER_OF_2_HIGH(hq_depth);
+               hq_size = hq_depth * BFI_RXQ_WI_SIZE;
+               hq_size = ALIGN(hq_size, PAGE_SIZE);
+               hpage_count = SIZE_TO_PAGES(hq_size);
+       } else {
+               hpage_count = 0;
+       }
+
+       /* CCB structures */
+       res_info[BNA_RX_RES_MEM_T_CCB].res_type = BNA_RES_T_MEM;
+       mem_info = &res_info[BNA_RX_RES_MEM_T_CCB].res_u.mem_info;
+       mem_info->mem_type = BNA_MEM_T_KVA;
+       mem_info->len = sizeof(struct bna_ccb);
+       mem_info->num = q_cfg->num_paths;
+
+       /* RCB structures */
+       res_info[BNA_RX_RES_MEM_T_RCB].res_type = BNA_RES_T_MEM;
+       mem_info = &res_info[BNA_RX_RES_MEM_T_RCB].res_u.mem_info;
+       mem_info->mem_type = BNA_MEM_T_KVA;
+       mem_info->len = sizeof(struct bna_rcb);
+       mem_info->num = BNA_GET_RXQS(q_cfg);
+
+       /* Completion QPT */
+       res_info[BNA_RX_RES_MEM_T_CQPT].res_type = BNA_RES_T_MEM;
+       mem_info = &res_info[BNA_RX_RES_MEM_T_CQPT].res_u.mem_info;
+       mem_info->mem_type = BNA_MEM_T_DMA;
+       mem_info->len = cpage_count * sizeof(struct bna_dma_addr);
+       mem_info->num = q_cfg->num_paths;
+
+       /* Completion s/w QPT */
+       res_info[BNA_RX_RES_MEM_T_CSWQPT].res_type = BNA_RES_T_MEM;
+       mem_info = &res_info[BNA_RX_RES_MEM_T_CSWQPT].res_u.mem_info;
+       mem_info->mem_type = BNA_MEM_T_KVA;
+       mem_info->len = cpage_count * sizeof(void *);
+       mem_info->num = q_cfg->num_paths;
+
+       /* Completion QPT pages */
+       res_info[BNA_RX_RES_MEM_T_CQPT_PAGE].res_type = BNA_RES_T_MEM;
+       mem_info = &res_info[BNA_RX_RES_MEM_T_CQPT_PAGE].res_u.mem_info;
+       mem_info->mem_type = BNA_MEM_T_DMA;
+       mem_info->len = PAGE_SIZE;
+       mem_info->num = cpage_count * q_cfg->num_paths;
+
+       /* Data QPTs */
+       res_info[BNA_RX_RES_MEM_T_DQPT].res_type = BNA_RES_T_MEM;
+       mem_info = &res_info[BNA_RX_RES_MEM_T_DQPT].res_u.mem_info;
+       mem_info->mem_type = BNA_MEM_T_DMA;
+       mem_info->len = dpage_count * sizeof(struct bna_dma_addr);
+       mem_info->num = q_cfg->num_paths;
+
+       /* Data s/w QPTs */
+       res_info[BNA_RX_RES_MEM_T_DSWQPT].res_type = BNA_RES_T_MEM;
+       mem_info = &res_info[BNA_RX_RES_MEM_T_DSWQPT].res_u.mem_info;
+       mem_info->mem_type = BNA_MEM_T_KVA;
+       mem_info->len = dpage_count * sizeof(void *);
+       mem_info->num = q_cfg->num_paths;
+
+       /* Data QPT pages */
+       res_info[BNA_RX_RES_MEM_T_DPAGE].res_type = BNA_RES_T_MEM;
+       mem_info = &res_info[BNA_RX_RES_MEM_T_DPAGE].res_u.mem_info;
+       mem_info->mem_type = BNA_MEM_T_DMA;
+       mem_info->len = PAGE_SIZE;
+       mem_info->num = dpage_count * q_cfg->num_paths;
+
+       /* Hdr QPTs */
+       res_info[BNA_RX_RES_MEM_T_HQPT].res_type = BNA_RES_T_MEM;
+       mem_info = &res_info[BNA_RX_RES_MEM_T_HQPT].res_u.mem_info;
+       mem_info->mem_type = BNA_MEM_T_DMA;
+       mem_info->len = hpage_count * sizeof(struct bna_dma_addr);
+       mem_info->num = (hpage_count ? q_cfg->num_paths : 0);
+
+       /* Hdr s/w QPTs */
+       res_info[BNA_RX_RES_MEM_T_HSWQPT].res_type = BNA_RES_T_MEM;
+       mem_info = &res_info[BNA_RX_RES_MEM_T_HSWQPT].res_u.mem_info;
+       mem_info->mem_type = BNA_MEM_T_KVA;
+       mem_info->len = hpage_count * sizeof(void *);
+       mem_info->num = (hpage_count ? q_cfg->num_paths : 0);
+
+       /* Hdr QPT pages */
+       res_info[BNA_RX_RES_MEM_T_HPAGE].res_type = BNA_RES_T_MEM;
+       mem_info = &res_info[BNA_RX_RES_MEM_T_HPAGE].res_u.mem_info;
+       mem_info->mem_type = BNA_MEM_T_DMA;
+       mem_info->len = (hpage_count ? PAGE_SIZE : 0);
+       mem_info->num = (hpage_count ? (hpage_count * q_cfg->num_paths) : 0);
+
+       /* RX Interrupts */
+       res_info[BNA_RX_RES_T_INTR].res_type = BNA_RES_T_INTR;
+       res_info[BNA_RX_RES_T_INTR].res_u.intr_info.intr_type = BNA_INTR_T_MSIX;
+       res_info[BNA_RX_RES_T_INTR].res_u.intr_info.num = q_cfg->num_paths;
+}
+
+struct bna_rx *
+bna_rx_create(struct bna *bna, struct bnad *bnad,
+               struct bna_rx_config *rx_cfg,
+               struct bna_rx_event_cbfn *rx_cbfn,
+               struct bna_res_info *res_info,
+               void *priv)
+{
+       struct bna_rx_mod *rx_mod = &bna->rx_mod;
+       struct bna_rx *rx;
+       struct bna_rxp *rxp;
+       struct bna_rxq *q0;
+       struct bna_rxq *q1;
+       struct bna_intr_info *intr_info;
+       u32 page_count;
+       struct bna_mem_descr *ccb_mem;
+       struct bna_mem_descr *rcb_mem;
+       struct bna_mem_descr *unmapq_mem;
+       struct bna_mem_descr *cqpt_mem;
+       struct bna_mem_descr *cswqpt_mem;
+       struct bna_mem_descr *cpage_mem;
+       struct bna_mem_descr *hqpt_mem; /* Header/Small Q qpt */
+       struct bna_mem_descr *dqpt_mem; /* Data/Large Q qpt */
+       struct bna_mem_descr *hsqpt_mem;        /* s/w qpt for hdr */
+       struct bna_mem_descr *dsqpt_mem;        /* s/w qpt for data */
+       struct bna_mem_descr *hpage_mem;        /* hdr page mem */
+       struct bna_mem_descr *dpage_mem;        /* data page mem */
+       int i, cpage_idx = 0, dpage_idx = 0, hpage_idx = 0, ret;
+       int dpage_count, hpage_count, rcb_idx;
+       struct bna_ib_config ibcfg;
+       /* Fail if we don't have enough RXPs, RXQs */
+       if (!_rx_can_satisfy(rx_mod, rx_cfg))
+               return NULL;
+
+       /* Initialize resource pointers */
+       intr_info = &res_info[BNA_RX_RES_T_INTR].res_u.intr_info;
+       ccb_mem = &res_info[BNA_RX_RES_MEM_T_CCB].res_u.mem_info.mdl[0];
+       rcb_mem = &res_info[BNA_RX_RES_MEM_T_RCB].res_u.mem_info.mdl[0];
+       unmapq_mem = &res_info[BNA_RX_RES_MEM_T_UNMAPQ].res_u.mem_info.mdl[0];
+       cqpt_mem = &res_info[BNA_RX_RES_MEM_T_CQPT].res_u.mem_info.mdl[0];
+       cswqpt_mem = &res_info[BNA_RX_RES_MEM_T_CSWQPT].res_u.mem_info.mdl[0];
+       cpage_mem = &res_info[BNA_RX_RES_MEM_T_CQPT_PAGE].res_u.mem_info.mdl[0];
+       hqpt_mem = &res_info[BNA_RX_RES_MEM_T_HQPT].res_u.mem_info.mdl[0];
+       dqpt_mem = &res_info[BNA_RX_RES_MEM_T_DQPT].res_u.mem_info.mdl[0];
+       hsqpt_mem = &res_info[BNA_RX_RES_MEM_T_HSWQPT].res_u.mem_info.mdl[0];
+       dsqpt_mem = &res_info[BNA_RX_RES_MEM_T_DSWQPT].res_u.mem_info.mdl[0];
+       hpage_mem = &res_info[BNA_RX_RES_MEM_T_HPAGE].res_u.mem_info.mdl[0];
+       dpage_mem = &res_info[BNA_RX_RES_MEM_T_DPAGE].res_u.mem_info.mdl[0];
+
+       /* Compute q depth & page count */
+       page_count = res_info[BNA_RX_RES_MEM_T_CQPT_PAGE].res_u.mem_info.num /
+                       rx_cfg->num_paths;
+
+       dpage_count = res_info[BNA_RX_RES_MEM_T_DPAGE].res_u.mem_info.num /
+                       rx_cfg->num_paths;
+
+       hpage_count = res_info[BNA_RX_RES_MEM_T_HPAGE].res_u.mem_info.num /
+                       rx_cfg->num_paths;
+       /* Get RX pointer */
+       rx = _get_free_rx(rx_mod);
+       _rx_init(rx, bna);
+       rx->priv = priv;
+       rx->type = rx_cfg->rx_type;
+
+       rx->rcb_setup_cbfn = rx_cbfn->rcb_setup_cbfn;
+       rx->rcb_destroy_cbfn = rx_cbfn->rcb_destroy_cbfn;
+       rx->ccb_setup_cbfn = rx_cbfn->ccb_setup_cbfn;
+       rx->ccb_destroy_cbfn = rx_cbfn->ccb_destroy_cbfn;
+       /* Following callbacks are mandatory */
+       rx->rx_cleanup_cbfn = rx_cbfn->rx_cleanup_cbfn;
+       rx->rx_post_cbfn = rx_cbfn->rx_post_cbfn;
+
+       if (rx->bna->rx_mod.flags & BNA_RX_MOD_F_PORT_STARTED) {
+               switch (rx->type) {
+               case BNA_RX_T_REGULAR:
+                       if (!(rx->bna->rx_mod.flags &
+                               BNA_RX_MOD_F_PORT_LOOPBACK))
+                               rx->rx_flags |= BNA_RX_F_PORT_ENABLED;
+                       break;
+               case BNA_RX_T_LOOPBACK:
+                       if (rx->bna->rx_mod.flags & BNA_RX_MOD_F_PORT_LOOPBACK)
+                               rx->rx_flags |= BNA_RX_F_PORT_ENABLED;
+                       break;
+               }
+       }
+
+       for (i = 0, rcb_idx = 0; i < rx_cfg->num_paths; i++) {
+               rxp = _get_free_rxp(rx_mod);
+               rxp->type = rx_cfg->rxp_type;
+               rxp->rx = rx;
+               rxp->cq.rx = rx;
+
+               /* Get required RXQs, and queue them to rx-path */
+               q0 = _get_free_rxq(rx_mod);
+               if (BNA_RXP_SINGLE == rx_cfg->rxp_type)
+                       q1 = NULL;
+               else
+                       q1 = _get_free_rxq(rx_mod);
+
+               /* Initialize IB */
+               if (1 == intr_info->num) {
+                       rxp->cq.ib = bna_ib_get(&bna->ib_mod,
+                                       intr_info->intr_type,
+                                       intr_info->idl[0].vector);
+                       rxp->vector = intr_info->idl[0].vector;
+               } else {
+                       rxp->cq.ib = bna_ib_get(&bna->ib_mod,
+                                       intr_info->intr_type,
+                                       intr_info->idl[i].vector);
+
+                       /* Map the MSI-x vector used for this RXP */
+                       rxp->vector = intr_info->idl[i].vector;
+               }
+
+               rxp->cq.ib_seg_offset = bna_ib_reserve_idx(rxp->cq.ib);
+
+               ibcfg.coalescing_timeo = BFI_RX_COALESCING_TIMEO;
+               ibcfg.interpkt_count = BFI_RX_INTERPKT_COUNT;
+               ibcfg.interpkt_timeo = BFI_RX_INTERPKT_TIMEO;
+               ibcfg.ctrl_flags = BFI_IB_CF_INT_ENABLE;
+
+               ret = bna_ib_config(rxp->cq.ib, &ibcfg);
+
+               /* Link rxqs to rxp */
+               _rxp_add_rxqs(rxp, q0, q1);
+
+               /* Link rxp to rx */
+               _rx_add_rxp(rx, rxp);
+
+               q0->rx = rx;
+               q0->rxp = rxp;
+
+               /* Initialize RCB for the large / data q */
+               q0->rcb = (struct bna_rcb *) rcb_mem[rcb_idx].kva;
+               RXQ_RCB_INIT(q0, rxp, rx_cfg->q_depth, bna, 0,
+                       (void *)unmapq_mem[rcb_idx].kva);
+               rcb_idx++;
+               (q0)->rx_packets = (q0)->rx_bytes = 0;
+               (q0)->rx_packets_with_error = (q0)->rxbuf_alloc_failed = 0;
+
+               /* Initialize RXQs */
+               _rxq_qpt_init(q0, rxp, dpage_count, PAGE_SIZE,
+                       &dqpt_mem[i], &dsqpt_mem[i], &dpage_mem[dpage_idx]);
+               q0->rcb->page_idx = dpage_idx;
+               q0->rcb->page_count = dpage_count;
+               dpage_idx += dpage_count;
+
+               /* Call bnad to complete rcb setup */
+               if (rx->rcb_setup_cbfn)
+                       rx->rcb_setup_cbfn(bnad, q0->rcb);
+
+               if (q1) {
+                       q1->rx = rx;
+                       q1->rxp = rxp;
+
+                       q1->rcb = (struct bna_rcb *) rcb_mem[rcb_idx].kva;
+                       RXQ_RCB_INIT(q1, rxp, rx_cfg->q_depth, bna, 1,
+                               (void *)unmapq_mem[rcb_idx].kva);
+                       rcb_idx++;
+                       (q1)->buffer_size = (rx_cfg)->small_buff_size;
+                       (q1)->rx_packets = (q1)->rx_bytes = 0;
+                       (q1)->rx_packets_with_error =
+                               (q1)->rxbuf_alloc_failed = 0;
+
+                       _rxq_qpt_init(q1, rxp, hpage_count, PAGE_SIZE,
+                               &hqpt_mem[i], &hsqpt_mem[i],
+                               &hpage_mem[hpage_idx]);
+                       q1->rcb->page_idx = hpage_idx;
+                       q1->rcb->page_count = hpage_count;
+                       hpage_idx += hpage_count;
+
+                       /* Call bnad to complete rcb setup */
+                       if (rx->rcb_setup_cbfn)
+                               rx->rcb_setup_cbfn(bnad, q1->rcb);
+               }
+               /* Setup RXP::CQ */
+               rxp->cq.ccb = (struct bna_ccb *) ccb_mem[i].kva;
+               _rxp_cqpt_setup(rxp, page_count, PAGE_SIZE,
+                       &cqpt_mem[i], &cswqpt_mem[i], &cpage_mem[cpage_idx]);
+               rxp->cq.ccb->page_idx = cpage_idx;
+               rxp->cq.ccb->page_count = page_count;
+               cpage_idx += page_count;
+
+               rxp->cq.ccb->pkt_rate.small_pkt_cnt = 0;
+               rxp->cq.ccb->pkt_rate.large_pkt_cnt = 0;
+
+               rxp->cq.ccb->producer_index = 0;
+               rxp->cq.ccb->q_depth =  rx_cfg->q_depth +
+                                       ((rx_cfg->rxp_type == BNA_RXP_SINGLE) ?
+                                       0 : rx_cfg->q_depth);
+               rxp->cq.ccb->i_dbell = &rxp->cq.ib->door_bell;
+               rxp->cq.ccb->rcb[0] = q0->rcb;
+               if (q1)
+                       rxp->cq.ccb->rcb[1] = q1->rcb;
+               rxp->cq.ccb->cq = &rxp->cq;
+               rxp->cq.ccb->bnad = bna->bnad;
+               rxp->cq.ccb->hw_producer_index =
+                       ((volatile u32 *)rxp->cq.ib->ib_seg_host_addr_kva +
+                                     (rxp->cq.ib_seg_offset * BFI_IBIDX_SIZE));
+               *(rxp->cq.ccb->hw_producer_index) = 0;
+               rxp->cq.ccb->intr_type = intr_info->intr_type;
+               rxp->cq.ccb->intr_vector = (intr_info->num == 1) ?
+                                               intr_info->idl[0].vector :
+                                               intr_info->idl[i].vector;
+               rxp->cq.ccb->rx_coalescing_timeo =
+                                       rxp->cq.ib->ib_config.coalescing_timeo;
+               rxp->cq.ccb->id = i;
+
+               /* Call bnad to complete CCB setup */
+               if (rx->ccb_setup_cbfn)
+                       rx->ccb_setup_cbfn(bnad, rxp->cq.ccb);
+
+       } /* for each rx-path */
+
+       bna_rxf_init(&rx->rxf, rx, rx_cfg);
+
+       bfa_fsm_set_state(rx, bna_rx_sm_stopped);
+
+       return rx;
+}
+
+void
+bna_rx_destroy(struct bna_rx *rx)
+{
+       struct bna_rx_mod *rx_mod = &rx->bna->rx_mod;
+       struct bna_ib_mod *ib_mod = &rx->bna->ib_mod;
+       struct bna_rxq *q0 = NULL;
+       struct bna_rxq *q1 = NULL;
+       struct bna_rxp *rxp;
+       struct list_head *qe;
+
+       bna_rxf_uninit(&rx->rxf);
+
+       while (!list_empty(&rx->rxp_q)) {
+               bfa_q_deq(&rx->rxp_q, &rxp);
+               GET_RXQS(rxp, q0, q1);
+               /* Callback to bnad for destroying RCB */
+               if (rx->rcb_destroy_cbfn)
+                       rx->rcb_destroy_cbfn(rx->bna->bnad, q0->rcb);
+               q0->rcb = NULL;
+               q0->rxp = NULL;
+               q0->rx = NULL;
+               _put_free_rxq(rx_mod, q0);
+               if (q1) {
+                       /* Callback to bnad for destroying RCB */
+                       if (rx->rcb_destroy_cbfn)
+                               rx->rcb_destroy_cbfn(rx->bna->bnad, q1->rcb);
+                       q1->rcb = NULL;
+                       q1->rxp = NULL;
+                       q1->rx = NULL;
+                       _put_free_rxq(rx_mod, q1);
+               }
+               rxp->rxq.slr.large = NULL;
+               rxp->rxq.slr.small = NULL;
+               if (rxp->cq.ib) {
+                       if (rxp->cq.ib_seg_offset != 0xff)
+                               bna_ib_release_idx(rxp->cq.ib,
+                                               rxp->cq.ib_seg_offset);
+                       bna_ib_put(ib_mod, rxp->cq.ib);
+                       rxp->cq.ib = NULL;
+               }
+               /* Callback to bnad for destroying CCB */
+               if (rx->ccb_destroy_cbfn)
+                       rx->ccb_destroy_cbfn(rx->bna->bnad, rxp->cq.ccb);
+               rxp->cq.ccb = NULL;
+               rxp->rx = NULL;
+               _put_free_rxp(rx_mod, rxp);
+       }
+
+       list_for_each(qe, &rx_mod->rx_active_q) {
+               if (qe == &rx->qe) {
+                       list_del(&rx->qe);
+                       bfa_q_qe_init(&rx->qe);
+                       break;
+               }
+       }
+
+       rx->bna = NULL;
+       rx->priv = NULL;
+       _put_free_rx(rx_mod, rx);
+}
+
+void
+bna_rx_enable(struct bna_rx *rx)
+{
+       if (rx->fsm != (bfa_sm_t)bna_rx_sm_stopped)
+               return;
+
+       rx->rx_flags |= BNA_RX_F_ENABLE;
+       if (rx->rx_flags & BNA_RX_F_PORT_ENABLED)
+               bfa_fsm_send_event(rx, RX_E_START);
+}
+
+void
+bna_rx_disable(struct bna_rx *rx, enum bna_cleanup_type type,
+               void (*cbfn)(void *, struct bna_rx *,
+                               enum bna_cb_status))
+{
+       if (type == BNA_SOFT_CLEANUP) {
+               /* h/w should not be accessed. Treat we're stopped */
+               (*cbfn)(rx->bna->bnad, rx, BNA_CB_SUCCESS);
+       } else {
+               rx->stop_cbfn = cbfn;
+               rx->stop_cbarg = rx->bna->bnad;
+
+               rx->rx_flags &= ~BNA_RX_F_ENABLE;
+
+               bfa_fsm_send_event(rx, RX_E_STOP);
+       }
+}
+
+/**
+ * TX
+ */
+#define call_tx_stop_cbfn(tx, status)\
+do {\
+       if ((tx)->stop_cbfn)\
+               (tx)->stop_cbfn((tx)->stop_cbarg, (tx), status);\
+       (tx)->stop_cbfn = NULL;\
+       (tx)->stop_cbarg = NULL;\
+} while (0)
+
+#define call_tx_prio_change_cbfn(tx, status)\
+do {\
+       if ((tx)->prio_change_cbfn)\
+               (tx)->prio_change_cbfn((tx)->bna->bnad, (tx), status);\
+       (tx)->prio_change_cbfn = NULL;\
+} while (0)
+
+static void bna_tx_mod_cb_tx_stopped(void *tx_mod, struct bna_tx *tx,
+                                       enum bna_cb_status status);
+static void bna_tx_cb_txq_stopped(void *arg, int status);
+static void bna_tx_cb_stats_cleared(void *arg, int status);
+static void __bna_tx_stop(struct bna_tx *tx);
+static void __bna_tx_start(struct bna_tx *tx);
+static void __bna_txf_stat_clr(struct bna_tx *tx);
+
+enum bna_tx_event {
+       TX_E_START                      = 1,
+       TX_E_STOP                       = 2,
+       TX_E_FAIL                       = 3,
+       TX_E_TXQ_STOPPED                = 4,
+       TX_E_PRIO_CHANGE                = 5,
+       TX_E_STAT_CLEARED               = 6,
+};
+
+enum bna_tx_state {
+       BNA_TX_STOPPED                  = 1,
+       BNA_TX_STARTED                  = 2,
+       BNA_TX_TXQ_STOP_WAIT            = 3,
+       BNA_TX_PRIO_STOP_WAIT           = 4,
+       BNA_TX_STAT_CLR_WAIT            = 5,
+};
+
+bfa_fsm_state_decl(bna_tx, stopped, struct bna_tx,
+                       enum bna_tx_event);
+bfa_fsm_state_decl(bna_tx, started, struct bna_tx,
+                       enum bna_tx_event);
+bfa_fsm_state_decl(bna_tx, txq_stop_wait, struct bna_tx,
+                       enum bna_tx_event);
+bfa_fsm_state_decl(bna_tx, prio_stop_wait, struct bna_tx,
+                       enum bna_tx_event);
+bfa_fsm_state_decl(bna_tx, stat_clr_wait, struct bna_tx,
+                       enum bna_tx_event);
+
+static struct bfa_sm_table tx_sm_table[] = {
+       {BFA_SM(bna_tx_sm_stopped), BNA_TX_STOPPED},
+       {BFA_SM(bna_tx_sm_started), BNA_TX_STARTED},
+       {BFA_SM(bna_tx_sm_txq_stop_wait), BNA_TX_TXQ_STOP_WAIT},
+       {BFA_SM(bna_tx_sm_prio_stop_wait), BNA_TX_PRIO_STOP_WAIT},
+       {BFA_SM(bna_tx_sm_stat_clr_wait), BNA_TX_STAT_CLR_WAIT},
+};
+
+static void
+bna_tx_sm_stopped_entry(struct bna_tx *tx)
+{
+       struct bna_txq *txq;
+       struct list_head                 *qe;
+
+       list_for_each(qe, &tx->txq_q) {
+               txq = (struct bna_txq *)qe;
+               (tx->tx_cleanup_cbfn)(tx->bna->bnad, txq->tcb);
+       }
+
+       call_tx_stop_cbfn(tx, BNA_CB_SUCCESS);
+}
+
+static void
+bna_tx_sm_stopped(struct bna_tx *tx, enum bna_tx_event event)
+{
+       switch (event) {
+       case TX_E_START:
+               bfa_fsm_set_state(tx, bna_tx_sm_started);
+               break;
+
+       case TX_E_STOP:
+               bfa_fsm_set_state(tx, bna_tx_sm_stopped);
+               break;
+
+       case TX_E_FAIL:
+               /* No-op */
+               break;
+
+       case TX_E_PRIO_CHANGE:
+               call_tx_prio_change_cbfn(tx, BNA_CB_SUCCESS);
+               break;
+
+       case TX_E_TXQ_STOPPED:
+               /**
+                * This event is received due to flushing of mbox when
+                * device fails
+                */
+               /* No-op */
+               break;
+
+       default:
+               bfa_sm_fault(tx->bna, event);
+       }
+}
+
+static void
+bna_tx_sm_started_entry(struct bna_tx *tx)
+{
+       struct bna_txq *txq;
+       struct list_head                 *qe;
+
+       __bna_tx_start(tx);
+
+       /* Start IB */
+       list_for_each(qe, &tx->txq_q) {
+               txq = (struct bna_txq *)qe;
+               bna_ib_ack(&txq->ib->door_bell, 0);
+       }
+}
+
+static void
+bna_tx_sm_started(struct bna_tx *tx, enum bna_tx_event event)
+{
+       struct bna_txq *txq;
+       struct list_head                 *qe;
+
+       switch (event) {
+       case TX_E_STOP:
+               bfa_fsm_set_state(tx, bna_tx_sm_txq_stop_wait);
+               __bna_tx_stop(tx);
+               break;
+
+       case TX_E_FAIL:
+               list_for_each(qe, &tx->txq_q) {
+                       txq = (struct bna_txq *)qe;
+                       bna_ib_fail(txq->ib);
+                       (tx->tx_stall_cbfn)(tx->bna->bnad, txq->tcb);
+               }
+               bfa_fsm_set_state(tx, bna_tx_sm_stopped);
+               break;
+
+       case TX_E_PRIO_CHANGE:
+               bfa_fsm_set_state(tx, bna_tx_sm_prio_stop_wait);
+               break;
+
+       default:
+               bfa_sm_fault(tx->bna, event);
+       }
+}
+
+static void
+bna_tx_sm_txq_stop_wait_entry(struct bna_tx *tx)
+{
+}
+
+static void
+bna_tx_sm_txq_stop_wait(struct bna_tx *tx, enum bna_tx_event event)
+{
+       struct bna_txq *txq;
+       struct list_head                 *qe;
+
+       switch (event) {
+       case TX_E_FAIL:
+               bfa_fsm_set_state(tx, bna_tx_sm_stopped);
+               break;
+
+       case TX_E_TXQ_STOPPED:
+               list_for_each(qe, &tx->txq_q) {
+                       txq = (struct bna_txq *)qe;
+                       bna_ib_stop(txq->ib);
+               }
+               bfa_fsm_set_state(tx, bna_tx_sm_stat_clr_wait);
+               break;
+
+       case TX_E_PRIO_CHANGE:
+               /* No-op */
+               break;
+
+       default:
+               bfa_sm_fault(tx->bna, event);
+       }
+}
+
+static void
+bna_tx_sm_prio_stop_wait_entry(struct bna_tx *tx)
+{
+       __bna_tx_stop(tx);
+}
+
+static void
+bna_tx_sm_prio_stop_wait(struct bna_tx *tx, enum bna_tx_event event)
+{
+       struct bna_txq *txq;
+       struct list_head                 *qe;
+
+       switch (event) {
+       case TX_E_STOP:
+               bfa_fsm_set_state(tx, bna_tx_sm_txq_stop_wait);
+               break;
+
+       case TX_E_FAIL:
+               call_tx_prio_change_cbfn(tx, BNA_CB_FAIL);
+               bfa_fsm_set_state(tx, bna_tx_sm_stopped);
+               break;
+
+       case TX_E_TXQ_STOPPED:
+               list_for_each(qe, &tx->txq_q) {
+                       txq = (struct bna_txq *)qe;
+                       bna_ib_stop(txq->ib);
+                       (tx->tx_cleanup_cbfn)(tx->bna->bnad, txq->tcb);
+               }
+               call_tx_prio_change_cbfn(tx, BNA_CB_SUCCESS);
+               bfa_fsm_set_state(tx, bna_tx_sm_started);
+               break;
+
+       case TX_E_PRIO_CHANGE:
+               /* No-op */
+               break;
+
+       default:
+               bfa_sm_fault(tx->bna, event);
+       }
+}
+
+static void
+bna_tx_sm_stat_clr_wait_entry(struct bna_tx *tx)
+{
+       __bna_txf_stat_clr(tx);
+}
+
+static void
+bna_tx_sm_stat_clr_wait(struct bna_tx *tx, enum bna_tx_event event)
+{
+       switch (event) {
+       case TX_E_FAIL:
+       case TX_E_STAT_CLEARED:
+               bfa_fsm_set_state(tx, bna_tx_sm_stopped);
+               break;
+
+       default:
+               bfa_sm_fault(tx->bna, event);
+       }
+}
+
+static void
+__bna_txq_start(struct bna_tx *tx, struct bna_txq *txq)
+{
+       struct bna_rxtx_q_mem *q_mem;
+       struct bna_txq_mem txq_cfg;
+       struct bna_txq_mem *txq_mem;
+       struct bna_dma_addr cur_q_addr;
+       u32 pg_num;
+       void __iomem *base_addr;
+       unsigned long off;
+
+       /* Fill out structure, to be subsequently written to hardware */
+       txq_cfg.pg_tbl_addr_lo = txq->qpt.hw_qpt_ptr.lsb;
+       txq_cfg.pg_tbl_addr_hi = txq->qpt.hw_qpt_ptr.msb;
+       cur_q_addr = *((struct bna_dma_addr *)(txq->qpt.kv_qpt_ptr));
+       txq_cfg.cur_q_entry_lo = cur_q_addr.lsb;
+       txq_cfg.cur_q_entry_hi = cur_q_addr.msb;
+
+       txq_cfg.pg_cnt_n_prd_ptr = (txq->qpt.page_count << 16) | 0x0;
+
+       txq_cfg.entry_n_pg_size = ((u32)(BFI_TXQ_WI_SIZE >> 2) << 16) |
+                       (txq->qpt.page_size >> 2);
+       txq_cfg.int_blk_n_cns_ptr = ((((u32)txq->ib_seg_offset) << 24) |
+                       ((u32)(txq->ib->ib_id & 0xff) << 16) | 0x0);
+
+       txq_cfg.cns_ptr2_n_q_state = BNA_Q_IDLE_STATE;
+       txq_cfg.nxt_qid_n_fid_n_pri = (((tx->txf.txf_id & 0x3f) << 3) |
+                       (txq->priority & 0x3));
+       txq_cfg.wvc_n_cquota_n_rquota =
+                       ((((u32)BFI_TX_MAX_WRR_QUOTA & 0xfff) << 12) |
+                       (BFI_TX_MAX_WRR_QUOTA & 0xfff));
+
+       /* Setup the page and write to H/W */
+
+       pg_num = BNA_GET_PAGE_NUM(HQM0_BLK_PG_NUM + tx->bna->port_num,
+                       HQM_RXTX_Q_RAM_BASE_OFFSET);
+       writel(pg_num, tx->bna->regs.page_addr);
+
+       base_addr = BNA_GET_MEM_BASE_ADDR(tx->bna->pcidev.pci_bar_kva,
+                                       HQM_RXTX_Q_RAM_BASE_OFFSET);
+       q_mem = (struct bna_rxtx_q_mem *)0;
+       txq_mem = &q_mem[txq->txq_id].txq;
+
+       /*
+        * The following 4 lines, is a hack b'cos the H/W needs to read
+        * these DMA addresses as little endian
+        */
+
+       off = (unsigned long)&txq_mem->pg_tbl_addr_lo;
+       writel(htonl(txq_cfg.pg_tbl_addr_lo), base_addr + off);
+
+       off = (unsigned long)&txq_mem->pg_tbl_addr_hi;
+       writel(htonl(txq_cfg.pg_tbl_addr_hi), base_addr + off);
+
+       off = (unsigned long)&txq_mem->cur_q_entry_lo;
+       writel(htonl(txq_cfg.cur_q_entry_lo), base_addr + off);
+
+       off = (unsigned long)&txq_mem->cur_q_entry_hi;
+       writel(htonl(txq_cfg.cur_q_entry_hi), base_addr + off);
+
+       off = (unsigned long)&txq_mem->pg_cnt_n_prd_ptr;
+       writel(txq_cfg.pg_cnt_n_prd_ptr, base_addr + off);
+
+       off = (unsigned long)&txq_mem->entry_n_pg_size;
+       writel(txq_cfg.entry_n_pg_size, base_addr + off);
+
+       off = (unsigned long)&txq_mem->int_blk_n_cns_ptr;
+       writel(txq_cfg.int_blk_n_cns_ptr, base_addr + off);
+
+       off = (unsigned long)&txq_mem->cns_ptr2_n_q_state;
+       writel(txq_cfg.cns_ptr2_n_q_state, base_addr + off);
+
+       off = (unsigned long)&txq_mem->nxt_qid_n_fid_n_pri;
+       writel(txq_cfg.nxt_qid_n_fid_n_pri, base_addr + off);
+
+       off = (unsigned long)&txq_mem->wvc_n_cquota_n_rquota;
+       writel(txq_cfg.wvc_n_cquota_n_rquota, base_addr + off);
+
+       txq->tcb->producer_index = 0;
+       txq->tcb->consumer_index = 0;
+       *(txq->tcb->hw_consumer_index) = 0;
+
+}
+
+static void
+__bna_txq_stop(struct bna_tx *tx, struct bna_txq *txq)
+{
+       struct bfi_ll_q_stop_req ll_req;
+       u32 bit_mask[2] = {0, 0};
+       if (txq->txq_id < 32)
+               bit_mask[0] = (u32)1 << txq->txq_id;
+       else
+               bit_mask[1] = (u32)1 << (txq->txq_id - 32);
+
+       memset(&ll_req, 0, sizeof(ll_req));
+       ll_req.mh.msg_class = BFI_MC_LL;
+       ll_req.mh.msg_id = BFI_LL_H2I_TXQ_STOP_REQ;
+       ll_req.mh.mtag.h2i.lpu_id = 0;
+       ll_req.q_id_mask[0] = htonl(bit_mask[0]);
+       ll_req.q_id_mask[1] = htonl(bit_mask[1]);
+
+       bna_mbox_qe_fill(&tx->mbox_qe, &ll_req, sizeof(ll_req),
+                       bna_tx_cb_txq_stopped, tx);
+
+       bna_mbox_send(tx->bna, &tx->mbox_qe);
+}
+
+static void
+__bna_txf_start(struct bna_tx *tx)
+{
+       struct bna_tx_fndb_ram *tx_fndb;
+       struct bna_txf *txf = &tx->txf;
+       void __iomem *base_addr;
+       unsigned long off;
+
+       writel(BNA_GET_PAGE_NUM(LUT0_MEM_BLK_BASE_PG_NUM +
+                       (tx->bna->port_num * 2), TX_FNDB_RAM_BASE_OFFSET),
+                       tx->bna->regs.page_addr);
+
+       base_addr = BNA_GET_MEM_BASE_ADDR(tx->bna->pcidev.pci_bar_kva,
+                                       TX_FNDB_RAM_BASE_OFFSET);
+
+       tx_fndb = (struct bna_tx_fndb_ram *)0;
+       off = (unsigned long)&tx_fndb[txf->txf_id].vlan_n_ctrl_flags;
+
+       writel(((u32)txf->vlan << 16) | txf->ctrl_flags,
+                       base_addr + off);
+
+       if (tx->txf.txf_id < 32)
+               tx->bna->tx_mod.txf_bmap[0] |= ((u32)1 << tx->txf.txf_id);
+       else
+               tx->bna->tx_mod.txf_bmap[1] |= ((u32)
+                                                1 << (tx->txf.txf_id - 32));
+}
+
+static void
+__bna_txf_stop(struct bna_tx *tx)
+{
+       struct bna_tx_fndb_ram *tx_fndb;
+       u32 page_num;
+       u32 ctl_flags;
+       struct bna_txf *txf = &tx->txf;
+       void __iomem *base_addr;
+       unsigned long off;
+
+       /* retrieve the running txf_flags & turn off enable bit */
+       page_num = BNA_GET_PAGE_NUM(LUT0_MEM_BLK_BASE_PG_NUM +
+                       (tx->bna->port_num * 2), TX_FNDB_RAM_BASE_OFFSET);
+       writel(page_num, tx->bna->regs.page_addr);
+
+       base_addr = BNA_GET_MEM_BASE_ADDR(tx->bna->pcidev.pci_bar_kva,
+                                       TX_FNDB_RAM_BASE_OFFSET);
+       tx_fndb = (struct bna_tx_fndb_ram *)0;
+       off = (unsigned long)&tx_fndb[txf->txf_id].vlan_n_ctrl_flags;
+
+       ctl_flags = readl(base_addr + off);
+       ctl_flags &= ~BFI_TXF_CF_ENABLE;
+
+       writel(ctl_flags, base_addr + off);
+
+       if (tx->txf.txf_id < 32)
+               tx->bna->tx_mod.txf_bmap[0] &= ~((u32)1 << tx->txf.txf_id);
+       else
+               tx->bna->tx_mod.txf_bmap[0] &= ~((u32)
+                                                1 << (tx->txf.txf_id - 32));
+}
+
+static void
+__bna_txf_stat_clr(struct bna_tx *tx)
+{
+       struct bfi_ll_stats_req ll_req;
+       u32 txf_bmap[2] = {0, 0};
+       if (tx->txf.txf_id < 32)
+               txf_bmap[0] = ((u32)1 << tx->txf.txf_id);
+       else
+               txf_bmap[1] = ((u32)1 << (tx->txf.txf_id - 32));
+       bfi_h2i_set(ll_req.mh, BFI_MC_LL, BFI_LL_H2I_STATS_CLEAR_REQ, 0);
+       ll_req.stats_mask = 0;
+       ll_req.rxf_id_mask[0] = 0;
+       ll_req.rxf_id_mask[1] = 0;
+       ll_req.txf_id_mask[0] = htonl(txf_bmap[0]);
+       ll_req.txf_id_mask[1] = htonl(txf_bmap[1]);
+
+       bna_mbox_qe_fill(&tx->mbox_qe, &ll_req, sizeof(ll_req),
+                       bna_tx_cb_stats_cleared, tx);
+       bna_mbox_send(tx->bna, &tx->mbox_qe);
+}
+
+static void
+__bna_tx_start(struct bna_tx *tx)
+{
+       struct bna_txq *txq;
+       struct list_head                 *qe;
+
+       list_for_each(qe, &tx->txq_q) {
+               txq = (struct bna_txq *)qe;
+               bna_ib_start(txq->ib);
+               __bna_txq_start(tx, txq);
+       }
+
+       __bna_txf_start(tx);
+
+       list_for_each(qe, &tx->txq_q) {
+               txq = (struct bna_txq *)qe;
+               txq->tcb->priority = txq->priority;
+               (tx->tx_resume_cbfn)(tx->bna->bnad, txq->tcb);
+       }
+}
+
+static void
+__bna_tx_stop(struct bna_tx *tx)
+{
+       struct bna_txq *txq;
+       struct list_head                 *qe;
+
+       list_for_each(qe, &tx->txq_q) {
+               txq = (struct bna_txq *)qe;
+               (tx->tx_stall_cbfn)(tx->bna->bnad, txq->tcb);
+       }
+
+       __bna_txf_stop(tx);
+
+       list_for_each(qe, &tx->txq_q) {
+               txq = (struct bna_txq *)qe;
+               bfa_wc_up(&tx->txq_stop_wc);
+       }
+
+       list_for_each(qe, &tx->txq_q) {
+               txq = (struct bna_txq *)qe;
+               __bna_txq_stop(tx, txq);
+       }
+}
+
+static void
+bna_txq_qpt_setup(struct bna_txq *txq, int page_count, int page_size,
+               struct bna_mem_descr *qpt_mem,
+               struct bna_mem_descr *swqpt_mem,
+               struct bna_mem_descr *page_mem)
+{
+       int i;
+
+       txq->qpt.hw_qpt_ptr.lsb = qpt_mem->dma.lsb;
+       txq->qpt.hw_qpt_ptr.msb = qpt_mem->dma.msb;
+       txq->qpt.kv_qpt_ptr = qpt_mem->kva;
+       txq->qpt.page_count = page_count;
+       txq->qpt.page_size = page_size;
+
+       txq->tcb->sw_qpt = (void **) swqpt_mem->kva;
+
+       for (i = 0; i < page_count; i++) {
+               txq->tcb->sw_qpt[i] = page_mem[i].kva;
+
+               ((struct bna_dma_addr *)txq->qpt.kv_qpt_ptr)[i].lsb =
+                       page_mem[i].dma.lsb;
+               ((struct bna_dma_addr *)txq->qpt.kv_qpt_ptr)[i].msb =
+                       page_mem[i].dma.msb;
+
+       }
+}
+
+static void
+bna_tx_free(struct bna_tx *tx)
+{
+       struct bna_tx_mod *tx_mod = &tx->bna->tx_mod;
+       struct bna_txq *txq;
+       struct bna_ib_mod *ib_mod = &tx->bna->ib_mod;
+       struct list_head *qe;
+
+       while (!list_empty(&tx->txq_q)) {
+               bfa_q_deq(&tx->txq_q, &txq);
+               bfa_q_qe_init(&txq->qe);
+               if (txq->ib) {
+                       if (txq->ib_seg_offset != -1)
+                               bna_ib_release_idx(txq->ib,
+                                               txq->ib_seg_offset);
+                       bna_ib_put(ib_mod, txq->ib);
+                       txq->ib = NULL;
+               }
+               txq->tcb = NULL;
+               txq->tx = NULL;
+               list_add_tail(&txq->qe, &tx_mod->txq_free_q);
+       }
+
+       list_for_each(qe, &tx_mod->tx_active_q) {
+               if (qe == &tx->qe) {
+                       list_del(&tx->qe);
+                       bfa_q_qe_init(&tx->qe);
+                       break;
+               }
+       }
+
+       tx->bna = NULL;
+       tx->priv = NULL;
+       list_add_tail(&tx->qe, &tx_mod->tx_free_q);
+}
+
+static void
+bna_tx_cb_txq_stopped(void *arg, int status)
+{
+       struct bna_tx *tx = (struct bna_tx *)arg;
+
+       bfa_q_qe_init(&tx->mbox_qe.qe);
+       bfa_wc_down(&tx->txq_stop_wc);
+}
+
+static void
+bna_tx_cb_txq_stopped_all(void *arg)
+{
+       struct bna_tx *tx = (struct bna_tx *)arg;
+
+       bfa_fsm_send_event(tx, TX_E_TXQ_STOPPED);
+}
+
+static void
+bna_tx_cb_stats_cleared(void *arg, int status)
+{
+       struct bna_tx *tx = (struct bna_tx *)arg;
+
+       bfa_q_qe_init(&tx->mbox_qe.qe);
+
+       bfa_fsm_send_event(tx, TX_E_STAT_CLEARED);
+}
+
+static void
+bna_tx_start(struct bna_tx *tx)
+{
+       tx->flags |= BNA_TX_F_PORT_STARTED;
+       if (tx->flags & BNA_TX_F_ENABLED)
+               bfa_fsm_send_event(tx, TX_E_START);
+}
+
+static void
+bna_tx_stop(struct bna_tx *tx)
+{
+       tx->stop_cbfn = bna_tx_mod_cb_tx_stopped;
+       tx->stop_cbarg = &tx->bna->tx_mod;
+
+       tx->flags &= ~BNA_TX_F_PORT_STARTED;
+       bfa_fsm_send_event(tx, TX_E_STOP);
+}
+
+static void
+bna_tx_fail(struct bna_tx *tx)
+{
+       tx->flags &= ~BNA_TX_F_PORT_STARTED;
+       bfa_fsm_send_event(tx, TX_E_FAIL);
+}
+
+void
+bna_tx_prio_changed(struct bna_tx *tx, int prio)
+{
+       struct bna_txq *txq;
+       struct list_head                 *qe;
+
+       list_for_each(qe, &tx->txq_q) {
+               txq = (struct bna_txq *)qe;
+               txq->priority = prio;
+       }
+
+       bfa_fsm_send_event(tx, TX_E_PRIO_CHANGE);
+}
+
+static void
+bna_tx_cee_link_status(struct bna_tx *tx, int cee_link)
+{
+       if (cee_link)
+               tx->flags |= BNA_TX_F_PRIO_LOCK;
+       else
+               tx->flags &= ~BNA_TX_F_PRIO_LOCK;
+}
+
+static void
+bna_tx_mod_cb_tx_stopped(void *arg, struct bna_tx *tx,
+                       enum bna_cb_status status)
+{
+       struct bna_tx_mod *tx_mod = (struct bna_tx_mod *)arg;
+
+       bfa_wc_down(&tx_mod->tx_stop_wc);
+}
+
+static void
+bna_tx_mod_cb_tx_stopped_all(void *arg)
+{
+       struct bna_tx_mod *tx_mod = (struct bna_tx_mod *)arg;
+
+       if (tx_mod->stop_cbfn)
+               tx_mod->stop_cbfn(&tx_mod->bna->port, BNA_CB_SUCCESS);
+       tx_mod->stop_cbfn = NULL;
+}
+
+void
+bna_tx_res_req(int num_txq, int txq_depth, struct bna_res_info *res_info)
+{
+       u32 q_size;
+       u32 page_count;
+       struct bna_mem_info *mem_info;
+
+       res_info[BNA_TX_RES_MEM_T_TCB].res_type = BNA_RES_T_MEM;
+       mem_info = &res_info[BNA_TX_RES_MEM_T_TCB].res_u.mem_info;
+       mem_info->mem_type = BNA_MEM_T_KVA;
+       mem_info->len = sizeof(struct bna_tcb);
+       mem_info->num = num_txq;
+
+       q_size = txq_depth * BFI_TXQ_WI_SIZE;
+       q_size = ALIGN(q_size, PAGE_SIZE);
+       page_count = q_size >> PAGE_SHIFT;
+
+       res_info[BNA_TX_RES_MEM_T_QPT].res_type = BNA_RES_T_MEM;
+       mem_info = &res_info[BNA_TX_RES_MEM_T_QPT].res_u.mem_info;
+       mem_info->mem_type = BNA_MEM_T_DMA;
+       mem_info->len = page_count * sizeof(struct bna_dma_addr);
+       mem_info->num = num_txq;
+
+       res_info[BNA_TX_RES_MEM_T_SWQPT].res_type = BNA_RES_T_MEM;
+       mem_info = &res_info[BNA_TX_RES_MEM_T_SWQPT].res_u.mem_info;
+       mem_info->mem_type = BNA_MEM_T_KVA;
+       mem_info->len = page_count * sizeof(void *);
+       mem_info->num = num_txq;
+
+       res_info[BNA_TX_RES_MEM_T_PAGE].res_type = BNA_RES_T_MEM;
+       mem_info = &res_info[BNA_TX_RES_MEM_T_PAGE].res_u.mem_info;
+       mem_info->mem_type = BNA_MEM_T_DMA;
+       mem_info->len = PAGE_SIZE;
+       mem_info->num = num_txq * page_count;
+
+       res_info[BNA_TX_RES_INTR_T_TXCMPL].res_type = BNA_RES_T_INTR;
+       res_info[BNA_TX_RES_INTR_T_TXCMPL].res_u.intr_info.intr_type =
+                       BNA_INTR_T_MSIX;
+       res_info[BNA_TX_RES_INTR_T_TXCMPL].res_u.intr_info.num = num_txq;
+}
+
+struct bna_tx *
+bna_tx_create(struct bna *bna, struct bnad *bnad,
+               struct bna_tx_config *tx_cfg,
+               struct bna_tx_event_cbfn *tx_cbfn,
+               struct bna_res_info *res_info, void *priv)
+{
+       struct bna_intr_info *intr_info;
+       struct bna_tx_mod *tx_mod = &bna->tx_mod;
+       struct bna_tx *tx;
+       struct bna_txq *txq;
+       struct list_head *qe;
+       struct bna_ib_mod *ib_mod = &bna->ib_mod;
+       struct bna_doorbell_qset *qset;
+       struct bna_ib_config ib_config;
+       int page_count;
+       int page_size;
+       int page_idx;
+       int i;
+       unsigned long off;
+
+       intr_info = &res_info[BNA_TX_RES_INTR_T_TXCMPL].res_u.intr_info;
+       page_count = (res_info[BNA_TX_RES_MEM_T_PAGE].res_u.mem_info.num) /
+                       tx_cfg->num_txq;
+       page_size = res_info[BNA_TX_RES_MEM_T_PAGE].res_u.mem_info.len;
+
+       /**
+        * Get resources
+        */
+
+       if ((intr_info->num != 1) && (intr_info->num != tx_cfg->num_txq))
+               return NULL;
+
+       /* Tx */
+
+       if (list_empty(&tx_mod->tx_free_q))
+               return NULL;
+       bfa_q_deq(&tx_mod->tx_free_q, &tx);
+       bfa_q_qe_init(&tx->qe);
+
+       /* TxQs */
+
+       INIT_LIST_HEAD(&tx->txq_q);
+       for (i = 0; i < tx_cfg->num_txq; i++) {
+               if (list_empty(&tx_mod->txq_free_q))
+                       goto err_return;
+
+               bfa_q_deq(&tx_mod->txq_free_q, &txq);
+               bfa_q_qe_init(&txq->qe);
+               list_add_tail(&txq->qe, &tx->txq_q);
+               txq->ib = NULL;
+               txq->ib_seg_offset = -1;
+               txq->tx = tx;
+       }
+
+       /* IBs */
+       i = 0;
+       list_for_each(qe, &tx->txq_q) {
+               txq = (struct bna_txq *)qe;
+
+               if (intr_info->num == 1)
+                       txq->ib = bna_ib_get(ib_mod, intr_info->intr_type,
+                                               intr_info->idl[0].vector);
+               else
+                       txq->ib = bna_ib_get(ib_mod, intr_info->intr_type,
+                                               intr_info->idl[i].vector);
+
+               if (txq->ib == NULL)
+                       goto err_return;
+
+               txq->ib_seg_offset = bna_ib_reserve_idx(txq->ib);
+               if (txq->ib_seg_offset == -1)
+                       goto err_return;
+
+               i++;
+       }
+
+       /*
+        * Initialize
+        */
+
+       /* Tx */
+
+       tx->tcb_setup_cbfn = tx_cbfn->tcb_setup_cbfn;
+       tx->tcb_destroy_cbfn = tx_cbfn->tcb_destroy_cbfn;
+       /* Following callbacks are mandatory */
+       tx->tx_stall_cbfn = tx_cbfn->tx_stall_cbfn;
+       tx->tx_resume_cbfn = tx_cbfn->tx_resume_cbfn;
+       tx->tx_cleanup_cbfn = tx_cbfn->tx_cleanup_cbfn;
+
+       list_add_tail(&tx->qe, &tx_mod->tx_active_q);
+       tx->bna = bna;
+       tx->priv = priv;
+       tx->txq_stop_wc.wc_resume = bna_tx_cb_txq_stopped_all;
+       tx->txq_stop_wc.wc_cbarg = tx;
+       tx->txq_stop_wc.wc_count = 0;
+
+       tx->type = tx_cfg->tx_type;
+
+       tx->flags = 0;
+       if (tx->bna->tx_mod.flags & BNA_TX_MOD_F_PORT_STARTED) {
+               switch (tx->type) {
+               case BNA_TX_T_REGULAR:
+                       if (!(tx->bna->tx_mod.flags &
+                               BNA_TX_MOD_F_PORT_LOOPBACK))
+                               tx->flags |= BNA_TX_F_PORT_STARTED;
+                       break;
+               case BNA_TX_T_LOOPBACK:
+                       if (tx->bna->tx_mod.flags & BNA_TX_MOD_F_PORT_LOOPBACK)
+                               tx->flags |= BNA_TX_F_PORT_STARTED;
+                       break;
+               }
+       }
+       if (tx->bna->tx_mod.cee_link)
+               tx->flags |= BNA_TX_F_PRIO_LOCK;
+
+       /* TxQ */
+
+       i = 0;
+       page_idx = 0;
+       list_for_each(qe, &tx->txq_q) {
+               txq = (struct bna_txq *)qe;
+               txq->priority = tx_mod->priority;
+               txq->tcb = (struct bna_tcb *)
+                 res_info[BNA_TX_RES_MEM_T_TCB].res_u.mem_info.mdl[i].kva;
+               txq->tx_packets = 0;
+               txq->tx_bytes = 0;
+
+               /* IB */
+
+               ib_config.coalescing_timeo = BFI_TX_COALESCING_TIMEO;
+               ib_config.interpkt_timeo = 0; /* Not used */
+               ib_config.interpkt_count = BFI_TX_INTERPKT_COUNT;
+               ib_config.ctrl_flags = (BFI_IB_CF_INTER_PKT_DMA |
+                                       BFI_IB_CF_INT_ENABLE |
+                                       BFI_IB_CF_COALESCING_MODE);
+               bna_ib_config(txq->ib, &ib_config);
+
+               /* TCB */
+
+               txq->tcb->producer_index = 0;
+               txq->tcb->consumer_index = 0;
+               txq->tcb->hw_consumer_index = (volatile u32 *)
+                       ((volatile u8 *)txq->ib->ib_seg_host_addr_kva +
+                        (txq->ib_seg_offset * BFI_IBIDX_SIZE));
+               *(txq->tcb->hw_consumer_index) = 0;
+               txq->tcb->q_depth = tx_cfg->txq_depth;
+               txq->tcb->unmap_q = (void *)
+               res_info[BNA_TX_RES_MEM_T_UNMAPQ].res_u.mem_info.mdl[i].kva;
+               qset = (struct bna_doorbell_qset *)0;
+               off = (unsigned long)&qset[txq->txq_id].txq[0];
+               txq->tcb->q_dbell = off +
+                       BNA_GET_DOORBELL_BASE_ADDR(bna->pcidev.pci_bar_kva);
+               txq->tcb->i_dbell = &txq->ib->door_bell;
+               txq->tcb->intr_type = intr_info->intr_type;
+               txq->tcb->intr_vector = (intr_info->num == 1) ?
+                                       intr_info->idl[0].vector :
+                                       intr_info->idl[i].vector;
+               txq->tcb->txq = txq;
+               txq->tcb->bnad = bnad;
+               txq->tcb->id = i;
+
+               /* QPT, SWQPT, Pages */
+               bna_txq_qpt_setup(txq, page_count, page_size,
+                       &res_info[BNA_TX_RES_MEM_T_QPT].res_u.mem_info.mdl[i],
+                       &res_info[BNA_TX_RES_MEM_T_SWQPT].res_u.mem_info.mdl[i],
+                       &res_info[BNA_TX_RES_MEM_T_PAGE].
+                                 res_u.mem_info.mdl[page_idx]);
+               txq->tcb->page_idx = page_idx;
+               txq->tcb->page_count = page_count;
+               page_idx += page_count;
+
+               /* Callback to bnad for setting up TCB */
+               if (tx->tcb_setup_cbfn)
+                       (tx->tcb_setup_cbfn)(bna->bnad, txq->tcb);
+
+               i++;
+       }
+
+       /* TxF */
+
+       tx->txf.ctrl_flags = BFI_TXF_CF_ENABLE | BFI_TXF_CF_VLAN_WI_BASED;
+       tx->txf.vlan = 0;
+
+       /* Mbox element */
+       bfa_q_qe_init(&tx->mbox_qe.qe);
+
+       bfa_fsm_set_state(tx, bna_tx_sm_stopped);
+
+       return tx;
+
+err_return:
+       bna_tx_free(tx);
+       return NULL;
+}
+
+void
+bna_tx_destroy(struct bna_tx *tx)
+{
+       /* Callback to bnad for destroying TCB */
+       if (tx->tcb_destroy_cbfn) {
+               struct bna_txq *txq;
+               struct list_head *qe;
+
+               list_for_each(qe, &tx->txq_q) {
+                       txq = (struct bna_txq *)qe;
+                       (tx->tcb_destroy_cbfn)(tx->bna->bnad, txq->tcb);
+               }
+       }
+
+       bna_tx_free(tx);
+}
+
+void
+bna_tx_enable(struct bna_tx *tx)
+{
+       if (tx->fsm != (bfa_sm_t)bna_tx_sm_stopped)
+               return;
+
+       tx->flags |= BNA_TX_F_ENABLED;
+
+       if (tx->flags & BNA_TX_F_PORT_STARTED)
+               bfa_fsm_send_event(tx, TX_E_START);
+}
+
+void
+bna_tx_disable(struct bna_tx *tx, enum bna_cleanup_type type,
+               void (*cbfn)(void *, struct bna_tx *, enum bna_cb_status))
+{
+       if (type == BNA_SOFT_CLEANUP) {
+               (*cbfn)(tx->bna->bnad, tx, BNA_CB_SUCCESS);
+               return;
+       }
+
+       tx->stop_cbfn = cbfn;
+       tx->stop_cbarg = tx->bna->bnad;
+
+       tx->flags &= ~BNA_TX_F_ENABLED;
+
+       bfa_fsm_send_event(tx, TX_E_STOP);
+}
+
+int
+bna_tx_state_get(struct bna_tx *tx)
+{
+       return bfa_sm_to_state(tx_sm_table, tx->fsm);
+}
+
+void
+bna_tx_mod_init(struct bna_tx_mod *tx_mod, struct bna *bna,
+               struct bna_res_info *res_info)
+{
+       int i;
+
+       tx_mod->bna = bna;
+       tx_mod->flags = 0;
+
+       tx_mod->tx = (struct bna_tx *)
+               res_info[BNA_RES_MEM_T_TX_ARRAY].res_u.mem_info.mdl[0].kva;
+       tx_mod->txq = (struct bna_txq *)
+               res_info[BNA_RES_MEM_T_TXQ_ARRAY].res_u.mem_info.mdl[0].kva;
+
+       INIT_LIST_HEAD(&tx_mod->tx_free_q);
+       INIT_LIST_HEAD(&tx_mod->tx_active_q);
+
+       INIT_LIST_HEAD(&tx_mod->txq_free_q);
+
+       for (i = 0; i < BFI_MAX_TXQ; i++) {
+               tx_mod->tx[i].txf.txf_id = i;
+               bfa_q_qe_init(&tx_mod->tx[i].qe);
+               list_add_tail(&tx_mod->tx[i].qe, &tx_mod->tx_free_q);
+
+               tx_mod->txq[i].txq_id = i;
+               bfa_q_qe_init(&tx_mod->txq[i].qe);
+               list_add_tail(&tx_mod->txq[i].qe, &tx_mod->txq_free_q);
+       }
+
+       tx_mod->tx_stop_wc.wc_resume = bna_tx_mod_cb_tx_stopped_all;
+       tx_mod->tx_stop_wc.wc_cbarg = tx_mod;
+       tx_mod->tx_stop_wc.wc_count = 0;
+}
+
+void
+bna_tx_mod_uninit(struct bna_tx_mod *tx_mod)
+{
+       struct list_head                *qe;
+       int i;
+
+       i = 0;
+       list_for_each(qe, &tx_mod->tx_free_q)
+               i++;
+
+       i = 0;
+       list_for_each(qe, &tx_mod->txq_free_q)
+               i++;
+
+       tx_mod->bna = NULL;
+}
+
+void
+bna_tx_mod_start(struct bna_tx_mod *tx_mod, enum bna_tx_type type)
+{
+       struct bna_tx *tx;
+       struct list_head                *qe;
+
+       tx_mod->flags |= BNA_TX_MOD_F_PORT_STARTED;
+       if (type == BNA_TX_T_LOOPBACK)
+               tx_mod->flags |= BNA_TX_MOD_F_PORT_LOOPBACK;
+
+       list_for_each(qe, &tx_mod->tx_active_q) {
+               tx = (struct bna_tx *)qe;
+               if (tx->type == type)
+                       bna_tx_start(tx);
+       }
+}
+
+void
+bna_tx_mod_stop(struct bna_tx_mod *tx_mod, enum bna_tx_type type)
+{
+       struct bna_tx *tx;
+       struct list_head                *qe;
+
+       tx_mod->flags &= ~BNA_TX_MOD_F_PORT_STARTED;
+       tx_mod->flags &= ~BNA_TX_MOD_F_PORT_LOOPBACK;
+
+       tx_mod->stop_cbfn = bna_port_cb_tx_stopped;
+
+       /**
+        * Before calling bna_tx_stop(), increment tx_stop_wc as many times
+        * as we are going to call bna_tx_stop
+        */
+       list_for_each(qe, &tx_mod->tx_active_q) {
+               tx = (struct bna_tx *)qe;
+               if (tx->type == type)
+                       bfa_wc_up(&tx_mod->tx_stop_wc);
+       }
+
+       if (tx_mod->tx_stop_wc.wc_count == 0) {
+               tx_mod->stop_cbfn(&tx_mod->bna->port, BNA_CB_SUCCESS);
+               tx_mod->stop_cbfn = NULL;
+               return;
+       }
+
+       list_for_each(qe, &tx_mod->tx_active_q) {
+               tx = (struct bna_tx *)qe;
+               if (tx->type == type)
+                       bna_tx_stop(tx);
+       }
+}
+
+void
+bna_tx_mod_fail(struct bna_tx_mod *tx_mod)
+{
+       struct bna_tx *tx;
+       struct list_head                *qe;
+
+       tx_mod->flags &= ~BNA_TX_MOD_F_PORT_STARTED;
+       tx_mod->flags &= ~BNA_TX_MOD_F_PORT_LOOPBACK;
+
+       list_for_each(qe, &tx_mod->tx_active_q) {
+               tx = (struct bna_tx *)qe;
+               bna_tx_fail(tx);
+       }
+}
+
+void
+bna_tx_mod_prio_changed(struct bna_tx_mod *tx_mod, int prio)
+{
+       struct bna_tx *tx;
+       struct list_head                *qe;
+
+       if (prio != tx_mod->priority) {
+               tx_mod->priority = prio;
+
+               list_for_each(qe, &tx_mod->tx_active_q) {
+                       tx = (struct bna_tx *)qe;
+                       bna_tx_prio_changed(tx, prio);
+               }
+       }
+}
+
+void
+bna_tx_mod_cee_link_status(struct bna_tx_mod *tx_mod, int cee_link)
+{
+       struct bna_tx *tx;
+       struct list_head                *qe;
+
+       tx_mod->cee_link = cee_link;
+
+       list_for_each(qe, &tx_mod->tx_active_q) {
+               tx = (struct bna_tx *)qe;
+               bna_tx_cee_link_status(tx, cee_link);
+       }
+}
diff --git a/drivers/net/bna/bna_types.h b/drivers/net/bna/bna_types.h
new file mode 100644 (file)
index 0000000..6877310
--- /dev/null
@@ -0,0 +1,1128 @@
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * 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.
+ */
+/*
+ * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+#ifndef __BNA_TYPES_H__
+#define __BNA_TYPES_H__
+
+#include "cna.h"
+#include "bna_hw.h"
+#include "bfa_cee.h"
+
+/**
+ *
+ * Forward declarations
+ *
+ */
+
+struct bna_txq;
+struct bna_tx;
+struct bna_rxq;
+struct bna_cq;
+struct bna_rx;
+struct bna_rxf;
+struct bna_port;
+struct bna;
+struct bnad;
+
+/**
+ *
+ * Enums, primitive data types
+ *
+ */
+
+enum bna_status {
+       BNA_STATUS_T_DISABLED   = 0,
+       BNA_STATUS_T_ENABLED    = 1
+};
+
+enum bna_cleanup_type {
+       BNA_HARD_CLEANUP        = 0,
+       BNA_SOFT_CLEANUP        = 1
+};
+
+enum bna_cb_status {
+       BNA_CB_SUCCESS          = 0,
+       BNA_CB_FAIL             = 1,
+       BNA_CB_INTERRUPT        = 2,
+       BNA_CB_BUSY             = 3,
+       BNA_CB_INVALID_MAC      = 4,
+       BNA_CB_MCAST_LIST_FULL  = 5,
+       BNA_CB_UCAST_CAM_FULL   = 6,
+       BNA_CB_WAITING          = 7,
+       BNA_CB_NOT_EXEC         = 8
+};
+
+enum bna_res_type {
+       BNA_RES_T_MEM           = 1,
+       BNA_RES_T_INTR          = 2
+};
+
+enum bna_mem_type {
+       BNA_MEM_T_KVA           = 1,
+       BNA_MEM_T_DMA           = 2
+};
+
+enum bna_intr_type {
+       BNA_INTR_T_INTX         = 1,
+       BNA_INTR_T_MSIX         = 2
+};
+
+enum bna_res_req_type {
+       BNA_RES_MEM_T_COM               = 0,
+       BNA_RES_MEM_T_ATTR              = 1,
+       BNA_RES_MEM_T_FWTRC             = 2,
+       BNA_RES_MEM_T_STATS             = 3,
+       BNA_RES_MEM_T_SWSTATS           = 4,
+       BNA_RES_MEM_T_IBIDX             = 5,
+       BNA_RES_MEM_T_IB_ARRAY          = 6,
+       BNA_RES_MEM_T_INTR_ARRAY        = 7,
+       BNA_RES_MEM_T_IDXSEG_ARRAY      = 8,
+       BNA_RES_MEM_T_TX_ARRAY          = 9,
+       BNA_RES_MEM_T_TXQ_ARRAY         = 10,
+       BNA_RES_MEM_T_RX_ARRAY          = 11,
+       BNA_RES_MEM_T_RXP_ARRAY         = 12,
+       BNA_RES_MEM_T_RXQ_ARRAY         = 13,
+       BNA_RES_MEM_T_UCMAC_ARRAY       = 14,
+       BNA_RES_MEM_T_MCMAC_ARRAY       = 15,
+       BNA_RES_MEM_T_RIT_ENTRY         = 16,
+       BNA_RES_MEM_T_RIT_SEGMENT       = 17,
+       BNA_RES_INTR_T_MBOX             = 18,
+       BNA_RES_T_MAX
+};
+
+enum bna_tx_res_req_type {
+       BNA_TX_RES_MEM_T_TCB    = 0,
+       BNA_TX_RES_MEM_T_UNMAPQ = 1,
+       BNA_TX_RES_MEM_T_QPT    = 2,
+       BNA_TX_RES_MEM_T_SWQPT  = 3,
+       BNA_TX_RES_MEM_T_PAGE   = 4,
+       BNA_TX_RES_INTR_T_TXCMPL = 5,
+       BNA_TX_RES_T_MAX,
+};
+
+enum bna_rx_mem_type {
+       BNA_RX_RES_MEM_T_CCB            = 0,    /* CQ context */
+       BNA_RX_RES_MEM_T_RCB            = 1,    /* CQ context */
+       BNA_RX_RES_MEM_T_UNMAPQ         = 2,    /* UnmapQ for RxQs */
+       BNA_RX_RES_MEM_T_CQPT           = 3,    /* CQ QPT */
+       BNA_RX_RES_MEM_T_CSWQPT         = 4,    /* S/W QPT */
+       BNA_RX_RES_MEM_T_CQPT_PAGE      = 5,    /* CQPT page */
+       BNA_RX_RES_MEM_T_HQPT           = 6,    /* RX QPT */
+       BNA_RX_RES_MEM_T_DQPT           = 7,    /* RX QPT */
+       BNA_RX_RES_MEM_T_HSWQPT         = 8,    /* RX s/w QPT */
+       BNA_RX_RES_MEM_T_DSWQPT         = 9,    /* RX s/w QPT */
+       BNA_RX_RES_MEM_T_DPAGE          = 10,   /* RX s/w QPT */
+       BNA_RX_RES_MEM_T_HPAGE          = 11,   /* RX s/w QPT */
+       BNA_RX_RES_T_INTR               = 12,   /* Rx interrupts */
+       BNA_RX_RES_T_MAX                = 13
+};
+
+enum bna_mbox_state {
+       BNA_MBOX_FREE           = 0,
+       BNA_MBOX_POSTED         = 1
+};
+
+enum bna_tx_type {
+       BNA_TX_T_REGULAR        = 0,
+       BNA_TX_T_LOOPBACK       = 1,
+};
+
+enum bna_tx_flags {
+       BNA_TX_F_PORT_STARTED   = 1,
+       BNA_TX_F_ENABLED        = 2,
+       BNA_TX_F_PRIO_LOCK      = 4,
+};
+
+enum bna_tx_mod_flags {
+       BNA_TX_MOD_F_PORT_STARTED       = 1,
+       BNA_TX_MOD_F_PORT_LOOPBACK      = 2,
+};
+
+enum bna_rx_type {
+       BNA_RX_T_REGULAR        = 0,
+       BNA_RX_T_LOOPBACK       = 1,
+};
+
+enum bna_rxp_type {
+       BNA_RXP_SINGLE          = 1,
+       BNA_RXP_SLR             = 2,
+       BNA_RXP_HDS             = 3
+};
+
+enum bna_rxmode {
+       BNA_RXMODE_PROMISC      = 1,
+       BNA_RXMODE_DEFAULT      = 2,
+       BNA_RXMODE_ALLMULTI     = 4
+};
+
+enum bna_rx_event {
+       RX_E_START                      = 1,
+       RX_E_STOP                       = 2,
+       RX_E_FAIL                       = 3,
+       RX_E_RXF_STARTED                = 4,
+       RX_E_RXF_STOPPED                = 5,
+       RX_E_RXQ_STOPPED                = 6,
+};
+
+enum bna_rx_state {
+       BNA_RX_STOPPED                  = 1,
+       BNA_RX_RXF_START_WAIT           = 2,
+       BNA_RX_STARTED                  = 3,
+       BNA_RX_RXF_STOP_WAIT            = 4,
+       BNA_RX_RXQ_STOP_WAIT            = 5,
+};
+
+enum bna_rx_flags {
+       BNA_RX_F_ENABLE         = 0x01,         /* bnad enabled rxf */
+       BNA_RX_F_PORT_ENABLED   = 0x02,         /* Port object is enabled */
+       BNA_RX_F_PORT_FAILED    = 0x04,         /* Port in failed state */
+};
+
+enum bna_rx_mod_flags {
+       BNA_RX_MOD_F_PORT_STARTED       = 1,
+       BNA_RX_MOD_F_PORT_LOOPBACK      = 2,
+};
+
+enum bna_rxf_oper_state {
+       BNA_RXF_OPER_STATE_RUNNING      = 0x01, /* rxf operational */
+       BNA_RXF_OPER_STATE_PAUSED       = 0x02, /* rxf in PAUSED state */
+};
+
+enum bna_rxf_flags {
+       BNA_RXF_FL_STOP_PENDING         = 0x01,
+       BNA_RXF_FL_FAILED               = 0x02,
+       BNA_RXF_FL_RSS_CONFIG_PENDING   = 0x04,
+       BNA_RXF_FL_OPERSTATE_CHANGED    = 0x08,
+       BNA_RXF_FL_RXF_ENABLED          = 0x10,
+       BNA_RXF_FL_VLAN_CONFIG_PENDING  = 0x20,
+};
+
+enum bna_rxf_event {
+       RXF_E_START                     = 1,
+       RXF_E_STOP                      = 2,
+       RXF_E_FAIL                      = 3,
+       RXF_E_CAM_FLTR_MOD              = 4,
+       RXF_E_STARTED                   = 5,
+       RXF_E_STOPPED                   = 6,
+       RXF_E_CAM_FLTR_RESP             = 7,
+       RXF_E_PAUSE                     = 8,
+       RXF_E_RESUME                    = 9,
+       RXF_E_STAT_CLEARED              = 10,
+};
+
+enum bna_rxf_state {
+       BNA_RXF_STOPPED                 = 1,
+       BNA_RXF_START_WAIT              = 2,
+       BNA_RXF_CAM_FLTR_MOD_WAIT       = 3,
+       BNA_RXF_STARTED                 = 4,
+       BNA_RXF_CAM_FLTR_CLR_WAIT       = 5,
+       BNA_RXF_STOP_WAIT               = 6,
+       BNA_RXF_PAUSE_WAIT              = 7,
+       BNA_RXF_RESUME_WAIT             = 8,
+       BNA_RXF_STAT_CLR_WAIT           = 9,
+};
+
+enum bna_port_type {
+       BNA_PORT_T_REGULAR              = 0,
+       BNA_PORT_T_LOOPBACK_INTERNAL    = 1,
+       BNA_PORT_T_LOOPBACK_EXTERNAL    = 2,
+};
+
+enum bna_link_status {
+       BNA_LINK_DOWN           = 0,
+       BNA_LINK_UP             = 1,
+       BNA_CEE_UP              = 2
+};
+
+enum bna_llport_flags {
+       BNA_LLPORT_F_ENABLED    = 1,
+       BNA_LLPORT_F_RX_ENABLED = 2
+};
+
+enum bna_port_flags {
+       BNA_PORT_F_DEVICE_READY = 1,
+       BNA_PORT_F_ENABLED      = 2,
+       BNA_PORT_F_PAUSE_CHANGED = 4,
+       BNA_PORT_F_MTU_CHANGED  = 8
+};
+
+enum bna_pkt_rates {
+       BNA_PKT_RATE_10K                = 10000,
+       BNA_PKT_RATE_20K                = 20000,
+       BNA_PKT_RATE_30K                = 30000,
+       BNA_PKT_RATE_40K                = 40000,
+       BNA_PKT_RATE_50K                = 50000,
+       BNA_PKT_RATE_60K                = 60000,
+       BNA_PKT_RATE_70K                = 70000,
+       BNA_PKT_RATE_80K                = 80000,
+};
+
+enum bna_dim_load_types {
+       BNA_LOAD_T_HIGH_4               = 0, /* 80K <= r */
+       BNA_LOAD_T_HIGH_3               = 1, /* 60K <= r < 80K */
+       BNA_LOAD_T_HIGH_2               = 2, /* 50K <= r < 60K */
+       BNA_LOAD_T_HIGH_1               = 3, /* 40K <= r < 50K */
+       BNA_LOAD_T_LOW_1                = 4, /* 30K <= r < 40K */
+       BNA_LOAD_T_LOW_2                = 5, /* 20K <= r < 30K */
+       BNA_LOAD_T_LOW_3                = 6, /* 10K <= r < 20K */
+       BNA_LOAD_T_LOW_4                = 7, /* r < 10K */
+       BNA_LOAD_T_MAX                  = 8
+};
+
+enum bna_dim_bias_types {
+       BNA_BIAS_T_SMALL                = 0, /* small pkts > (large pkts * 2) */
+       BNA_BIAS_T_LARGE                = 1, /* Not BNA_BIAS_T_SMALL */
+       BNA_BIAS_T_MAX                  = 2
+};
+
+struct bna_mac {
+       /* This should be the first one */
+       struct list_head                        qe;
+       u8                      addr[ETH_ALEN];
+};
+
+struct bna_mem_descr {
+       u32             len;
+       void            *kva;
+       struct bna_dma_addr dma;
+};
+
+struct bna_mem_info {
+       enum bna_mem_type mem_type;
+       u32             len;
+       u32             num;
+       u32             align_sz; /* 0/1 = no alignment */
+       struct bna_mem_descr *mdl;
+       void                    *cookie; /* For bnad to unmap dma later */
+};
+
+struct bna_intr_descr {
+       int                     vector;
+};
+
+struct bna_intr_info {
+       enum bna_intr_type intr_type;
+       int                     num;
+       struct bna_intr_descr *idl;
+};
+
+union bna_res_u {
+       struct bna_mem_info mem_info;
+       struct bna_intr_info intr_info;
+};
+
+struct bna_res_info {
+       enum bna_res_type res_type;
+       union bna_res_u         res_u;
+};
+
+/* HW QPT */
+struct bna_qpt {
+       struct bna_dma_addr hw_qpt_ptr;
+       void            *kv_qpt_ptr;
+       u32             page_count;
+       u32             page_size;
+};
+
+/**
+ *
+ * Device
+ *
+ */
+
+struct bna_device {
+       bfa_fsm_t               fsm;
+       struct bfa_ioc ioc;
+
+       enum bna_intr_type intr_type;
+       int                     vector;
+
+       void (*ready_cbfn)(struct bnad *bnad, enum bna_cb_status status);
+       struct bnad *ready_cbarg;
+
+       void (*stop_cbfn)(struct bnad *bnad, enum bna_cb_status status);
+       struct bnad *stop_cbarg;
+
+       struct bna *bna;
+};
+
+/**
+ *
+ * Mail box
+ *
+ */
+
+struct bna_mbox_qe {
+       /* This should be the first one */
+       struct list_head                        qe;
+
+       struct bfa_mbox_cmd cmd;
+       u32             cmd_len;
+       /* Callback for port, tx, rx, rxf */
+       void (*cbfn)(void *arg, int status);
+       void                    *cbarg;
+};
+
+struct bna_mbox_mod {
+       enum bna_mbox_state state;
+       struct list_head                        posted_q;
+       u32             msg_pending;
+       u32             msg_ctr;
+       struct bna *bna;
+};
+
+/**
+ *
+ * Port
+ *
+ */
+
+/* Pause configuration */
+struct bna_pause_config {
+       enum bna_status tx_pause;
+       enum bna_status rx_pause;
+};
+
+struct bna_llport {
+       bfa_fsm_t               fsm;
+       enum bna_llport_flags flags;
+
+       enum bna_port_type type;
+
+       enum bna_link_status link_status;
+
+       int                     admin_up_count;
+
+       void (*stop_cbfn)(struct bna_port *, enum bna_cb_status);
+
+       struct bna_mbox_qe mbox_qe;
+
+       struct bna *bna;
+};
+
+struct bna_port {
+       bfa_fsm_t               fsm;
+       enum bna_port_flags flags;
+
+       enum bna_port_type type;
+
+       struct bna_llport llport;
+
+       struct bna_pause_config pause_config;
+       u8                      priority;
+       int                     mtu;
+
+       /* Callback for bna_port_disable(), port_stop() */
+       void (*stop_cbfn)(void *, enum bna_cb_status);
+       void                    *stop_cbarg;
+
+       /* Callback for bna_port_pause_config() */
+       void (*pause_cbfn)(struct bnad *, enum bna_cb_status);
+
+       /* Callback for bna_port_mtu_set() */
+       void (*mtu_cbfn)(struct bnad *, enum bna_cb_status);
+
+       void (*link_cbfn)(struct bnad *, enum bna_link_status);
+
+       struct bfa_wc           chld_stop_wc;
+
+       struct bna_mbox_qe mbox_qe;
+
+       struct bna *bna;
+};
+
+/**
+ *
+ * Interrupt Block
+ *
+ */
+
+/* IB index segment structure */
+struct bna_ibidx_seg {
+       /* This should be the first one */
+       struct list_head                        qe;
+
+       u8                      ib_seg_size;
+       u8                      ib_idx_tbl_offset;
+};
+
+/* Interrupt structure */
+struct bna_intr {
+       /* This should be the first one */
+       struct list_head                        qe;
+       int                     ref_count;
+
+       enum bna_intr_type intr_type;
+       int                     vector;
+
+       struct bna_ib *ib;
+};
+
+/* Doorbell structure */
+struct bna_ib_dbell {
+       void *__iomem doorbell_addr;
+       u32             doorbell_ack;
+};
+
+/* Interrupt timer configuration */
+struct bna_ib_config {
+       u8              coalescing_timeo;    /* Unit is 5usec. */
+
+       int                     interpkt_count;
+       int                     interpkt_timeo;
+
+       enum ib_flags ctrl_flags;
+};
+
+/* IB structure */
+struct bna_ib {
+       /* This should be the first one */
+       struct list_head                        qe;
+
+       int                     ib_id;
+
+       int                     ref_count;
+       int                     start_count;
+
+       struct bna_dma_addr ib_seg_host_addr;
+       void            *ib_seg_host_addr_kva;
+       u32             idx_mask; /* Size >= BNA_IBIDX_MAX_SEGSIZE */
+
+       struct bna_ibidx_seg *idx_seg;
+
+       struct bna_ib_dbell door_bell;
+
+       struct bna_intr *intr;
+
+       struct bna_ib_config ib_config;
+
+       struct bna *bna;
+};
+
+/* IB module - keeps track of IBs and interrupts */
+struct bna_ib_mod {
+       struct bna_ib *ib;              /* BFI_MAX_IB entries */
+       struct bna_intr *intr;          /* BFI_MAX_IB entries */
+       struct bna_ibidx_seg *idx_seg;  /* BNA_IBIDX_TOTAL_SEGS */
+
+       struct list_head                        ib_free_q;
+
+       struct list_head                ibidx_seg_pool[BFI_IBIDX_TOTAL_POOLS];
+
+       struct list_head                        intr_free_q;
+       struct list_head                        intr_active_q;
+
+       struct bna *bna;
+};
+
+/**
+ *
+ * Tx object
+ *
+ */
+
+/* Tx datapath control structure */
+#define BNA_Q_NAME_SIZE                16
+struct bna_tcb {
+       /* Fast path */
+       void                    **sw_qpt;
+       void                    *unmap_q;
+       u32             producer_index;
+       u32             consumer_index;
+       volatile u32    *hw_consumer_index;
+       u32             q_depth;
+       void *__iomem q_dbell;
+       struct bna_ib_dbell *i_dbell;
+       int                     page_idx;
+       int                     page_count;
+       /* Control path */
+       struct bna_txq *txq;
+       struct bnad *bnad;
+       enum bna_intr_type intr_type;
+       int                     intr_vector;
+       u8                      priority; /* Current priority */
+       unsigned long           flags; /* Used by bnad as required */
+       int                     id;
+       char                    name[BNA_Q_NAME_SIZE];
+};
+
+/* TxQ QPT and configuration */
+struct bna_txq {
+       /* This should be the first one */
+       struct list_head                        qe;
+
+       int                     txq_id;
+
+       u8                      priority;
+
+       struct bna_qpt qpt;
+       struct bna_tcb *tcb;
+       struct bna_ib *ib;
+       int                     ib_seg_offset;
+
+       struct bna_tx *tx;
+
+       u64             tx_packets;
+       u64             tx_bytes;
+};
+
+/* TxF structure (hardware Tx Function) */
+struct bna_txf {
+       int                     txf_id;
+       enum txf_flags ctrl_flags;
+       u16             vlan;
+};
+
+/* Tx object */
+struct bna_tx {
+       /* This should be the first one */
+       struct list_head                        qe;
+
+       bfa_fsm_t               fsm;
+       enum bna_tx_flags flags;
+
+       enum bna_tx_type type;
+
+       struct list_head                        txq_q;
+       struct bna_txf txf;
+
+       /* Tx event handlers */
+       void (*tcb_setup_cbfn)(struct bnad *, struct bna_tcb *);
+       void (*tcb_destroy_cbfn)(struct bnad *, struct bna_tcb *);
+       void (*tx_stall_cbfn)(struct bnad *, struct bna_tcb *);
+       void (*tx_resume_cbfn)(struct bnad *, struct bna_tcb *);
+       void (*tx_cleanup_cbfn)(struct bnad *, struct bna_tcb *);
+
+       /* callback for bna_tx_disable(), bna_tx_stop() */
+       void (*stop_cbfn)(void *arg, struct bna_tx *tx,
+                               enum bna_cb_status status);
+       void                    *stop_cbarg;
+
+       /* callback for bna_tx_prio_set() */
+       void (*prio_change_cbfn)(struct bnad *bnad, struct bna_tx *tx,
+                               enum bna_cb_status status);
+
+       struct bfa_wc           txq_stop_wc;
+
+       struct bna_mbox_qe mbox_qe;
+
+       struct bna *bna;
+       void                    *priv;  /* bnad's cookie */
+};
+
+struct bna_tx_config {
+       int                     num_txq;
+       int                     txq_depth;
+       enum bna_tx_type tx_type;
+};
+
+struct bna_tx_event_cbfn {
+       /* Optional */
+       void (*tcb_setup_cbfn)(struct bnad *, struct bna_tcb *);
+       void (*tcb_destroy_cbfn)(struct bnad *, struct bna_tcb *);
+       /* Mandatory */
+       void (*tx_stall_cbfn)(struct bnad *, struct bna_tcb *);
+       void (*tx_resume_cbfn)(struct bnad *, struct bna_tcb *);
+       void (*tx_cleanup_cbfn)(struct bnad *, struct bna_tcb *);
+};
+
+/* Tx module - keeps track of free, active tx objects */
+struct bna_tx_mod {
+       struct bna_tx *tx;              /* BFI_MAX_TXQ entries */
+       struct bna_txq *txq;            /* BFI_MAX_TXQ entries */
+
+       struct list_head                        tx_free_q;
+       struct list_head                        tx_active_q;
+
+       struct list_head                        txq_free_q;
+
+       /* callback for bna_tx_mod_stop() */
+       void (*stop_cbfn)(struct bna_port *port,
+                               enum bna_cb_status status);
+
+       struct bfa_wc           tx_stop_wc;
+
+       enum bna_tx_mod_flags flags;
+
+       int                     priority;
+       int                     cee_link;
+
+       u32             txf_bmap[2];
+
+       struct bna *bna;
+};
+
+/**
+ *
+ * Receive Indirection Table
+ *
+ */
+
+/* One row of RIT table */
+struct bna_rit_entry {
+       u8 large_rxq_id;        /* used for either large or data buffers */
+       u8 small_rxq_id;        /* used for either small or header buffers */
+};
+
+/* RIT segment */
+struct bna_rit_segment {
+       struct list_head                        qe;
+
+       u32             rit_offset;
+       u32             rit_size;
+       /**
+        * max_rit_size: Varies per RIT segment depending on how RIT is
+        * partitioned
+        */
+       u32             max_rit_size;
+
+       struct bna_rit_entry *rit;
+};
+
+struct bna_rit_mod {
+       struct bna_rit_entry *rit;
+       struct bna_rit_segment *rit_segment;
+
+       struct list_head                rit_seg_pool[BFI_RIT_SEG_TOTAL_POOLS];
+};
+
+/**
+ *
+ * Rx object
+ *
+ */
+
+/* Rx datapath control structure */
+struct bna_rcb {
+       /* Fast path */
+       void                    **sw_qpt;
+       void                    *unmap_q;
+       u32             producer_index;
+       u32             consumer_index;
+       u32             q_depth;
+       void *__iomem q_dbell;
+       int                     page_idx;
+       int                     page_count;
+       /* Control path */
+       struct bna_rxq *rxq;
+       struct bna_cq *cq;
+       struct bnad *bnad;
+       unsigned long           flags;
+       int                     id;
+};
+
+/* RxQ structure - QPT, configuration */
+struct bna_rxq {
+       struct list_head                        qe;
+       int                     rxq_id;
+
+       int                     buffer_size;
+       int                     q_depth;
+
+       struct bna_qpt qpt;
+       struct bna_rcb *rcb;
+
+       struct bna_rxp *rxp;
+       struct bna_rx *rx;
+
+       u64             rx_packets;
+       u64             rx_bytes;
+       u64             rx_packets_with_error;
+       u64             rxbuf_alloc_failed;
+};
+
+/* RxQ pair */
+union bna_rxq_u {
+       struct {
+               struct bna_rxq *hdr;
+               struct bna_rxq *data;
+       } hds;
+       struct {
+               struct bna_rxq *small;
+               struct bna_rxq *large;
+       } slr;
+       struct {
+               struct bna_rxq *only;
+               struct bna_rxq *reserved;
+       } single;
+};
+
+/* Packet rate for Dynamic Interrupt Moderation */
+struct bna_pkt_rate {
+       u32             small_pkt_cnt;
+       u32             large_pkt_cnt;
+};
+
+/* Completion control structure */
+struct bna_ccb {
+       /* Fast path */
+       void                    **sw_qpt;
+       u32             producer_index;
+       volatile u32    *hw_producer_index;
+       u32             q_depth;
+       struct bna_ib_dbell *i_dbell;
+       struct bna_rcb *rcb[2];
+       void                    *ctrl; /* For bnad */
+       struct bna_pkt_rate pkt_rate;
+       int                     page_idx;
+       int                     page_count;
+
+       /* Control path */
+       struct bna_cq *cq;
+       struct bnad *bnad;
+       enum bna_intr_type intr_type;
+       int                     intr_vector;
+       u8                      rx_coalescing_timeo; /* For NAPI */
+       int                     id;
+       char                    name[BNA_Q_NAME_SIZE];
+};
+
+/* CQ QPT, configuration  */
+struct bna_cq {
+       int                     cq_id;
+
+       struct bna_qpt qpt;
+       struct bna_ccb *ccb;
+
+       struct bna_ib *ib;
+       u8                      ib_seg_offset;
+
+       struct bna_rx *rx;
+};
+
+struct bna_rss_config {
+       enum rss_hash_type hash_type;
+       u8                      hash_mask;
+       u32             toeplitz_hash_key[BFI_RSS_HASH_KEY_LEN];
+};
+
+struct bna_hds_config {
+       enum hds_header_type hdr_type;
+       int                     header_size;
+};
+
+/* This structure is used during RX creation */
+struct bna_rx_config {
+       enum bna_rx_type rx_type;
+       int                     num_paths;
+       enum bna_rxp_type rxp_type;
+       int                     paused;
+       int                     q_depth;
+       /*
+        * Small/Large (or Header/Data) buffer size to be configured
+        * for SLR and HDS queue type. Large buffer size comes from
+        * port->mtu.
+        */
+       int                     small_buff_size;
+
+       enum bna_status rss_status;
+       struct bna_rss_config rss_config;
+
+       enum bna_status hds_status;
+       struct bna_hds_config hds_config;
+
+       enum bna_status vlan_strip_status;
+};
+
+/* Rx Path structure - one per MSIX vector/CPU */
+struct bna_rxp {
+       /* This should be the first one */
+       struct list_head                        qe;
+
+       enum bna_rxp_type type;
+       union   bna_rxq_u       rxq;
+       struct bna_cq cq;
+
+       struct bna_rx *rx;
+
+       /* MSI-x vector number for configuring RSS */
+       int                     vector;
+
+       struct bna_mbox_qe mbox_qe;
+};
+
+/* HDS configuration structure */
+struct bna_rxf_hds {
+       enum hds_header_type hdr_type;
+       int                     header_size;
+};
+
+/* RSS configuration structure */
+struct bna_rxf_rss {
+       enum rss_hash_type hash_type;
+       u8                      hash_mask;
+       u32             toeplitz_hash_key[BFI_RSS_HASH_KEY_LEN];
+};
+
+/* RxF structure (hardware Rx Function) */
+struct bna_rxf {
+       bfa_fsm_t               fsm;
+       int                     rxf_id;
+       enum rxf_flags ctrl_flags;
+       u16             default_vlan_tag;
+       enum bna_rxf_oper_state rxf_oper_state;
+       enum bna_status hds_status;
+       struct bna_rxf_hds hds_cfg;
+       enum bna_status rss_status;
+       struct bna_rxf_rss rss_cfg;
+       struct bna_rit_segment *rit_segment;
+       struct bna_rx *rx;
+       u32             forced_offset;
+       struct bna_mbox_qe mbox_qe;
+       int                     mcast_rxq_id;
+
+       /* callback for bna_rxf_start() */
+       void (*start_cbfn) (struct bna_rx *rx, enum bna_cb_status status);
+       struct bna_rx *start_cbarg;
+
+       /* callback for bna_rxf_stop() */
+       void (*stop_cbfn) (struct bna_rx *rx, enum bna_cb_status status);
+       struct bna_rx *stop_cbarg;
+
+       /* callback for bna_rxf_receive_enable() / bna_rxf_receive_disable() */
+       void (*oper_state_cbfn) (struct bnad *bnad, struct bna_rx *rx,
+                       enum bna_cb_status status);
+       struct bnad *oper_state_cbarg;
+
+       /**
+        * callback for:
+        *      bna_rxf_ucast_set()
+        *      bna_rxf_{ucast/mcast}_add(),
+        *      bna_rxf_{ucast/mcast}_del(),
+        *      bna_rxf_mode_set()
+        */
+       void (*cam_fltr_cbfn)(struct bnad *bnad, struct bna_rx *rx,
+                               enum bna_cb_status status);
+       struct bnad *cam_fltr_cbarg;
+
+       enum bna_rxf_flags rxf_flags;
+
+       /* List of unicast addresses yet to be applied to h/w */
+       struct list_head                        ucast_pending_add_q;
+       struct list_head                        ucast_pending_del_q;
+       int                     ucast_pending_set;
+       /* ucast addresses applied to the h/w */
+       struct list_head                        ucast_active_q;
+       struct bna_mac *ucast_active_mac;
+
+       /* List of multicast addresses yet to be applied to h/w */
+       struct list_head                        mcast_pending_add_q;
+       struct list_head                        mcast_pending_del_q;
+       /* multicast addresses applied to the h/w */
+       struct list_head                        mcast_active_q;
+
+       /* Rx modes yet to be applied to h/w */
+       enum bna_rxmode rxmode_pending;
+       enum bna_rxmode rxmode_pending_bitmask;
+       /* Rx modes applied to h/w */
+       enum bna_rxmode rxmode_active;
+
+       enum bna_status vlan_filter_status;
+       u32             vlan_filter_table[(BFI_MAX_VLAN + 1) / 32];
+};
+
+/* Rx object */
+struct bna_rx {
+       /* This should be the first one */
+       struct list_head                        qe;
+
+       bfa_fsm_t               fsm;
+
+       enum bna_rx_type type;
+
+       /* list-head for RX path objects */
+       struct list_head                        rxp_q;
+
+       struct bna_rxf rxf;
+
+       enum bna_rx_flags rx_flags;
+
+       struct bna_mbox_qe mbox_qe;
+
+       struct bfa_wc           rxq_stop_wc;
+
+       /* Rx event handlers */
+       void (*rcb_setup_cbfn)(struct bnad *, struct bna_rcb *);
+       void (*rcb_destroy_cbfn)(struct bnad *, struct bna_rcb *);
+       void (*ccb_setup_cbfn)(struct bnad *, struct bna_ccb *);
+       void (*ccb_destroy_cbfn)(struct bnad *, struct bna_ccb *);
+       void (*rx_cleanup_cbfn)(struct bnad *, struct bna_ccb *);
+       void (*rx_post_cbfn)(struct bnad *, struct bna_rcb *);
+
+       /* callback for bna_rx_disable(), bna_rx_stop() */
+       void (*stop_cbfn)(void *arg, struct bna_rx *rx,
+                               enum bna_cb_status status);
+       void                    *stop_cbarg;
+
+       struct bna *bna;
+       void                    *priv; /* bnad's cookie */
+};
+
+struct bna_rx_event_cbfn {
+       /* Optional */
+       void (*rcb_setup_cbfn)(struct bnad *, struct bna_rcb *);
+       void (*rcb_destroy_cbfn)(struct bnad *, struct bna_rcb *);
+       void (*ccb_setup_cbfn)(struct bnad *, struct bna_ccb *);
+       void (*ccb_destroy_cbfn)(struct bnad *, struct bna_ccb *);
+       /* Mandatory */
+       void (*rx_cleanup_cbfn)(struct bnad *, struct bna_ccb *);
+       void (*rx_post_cbfn)(struct bnad *, struct bna_rcb *);
+};
+
+/* Rx module - keeps track of free, active rx objects */
+struct bna_rx_mod {
+       struct bna *bna;                /* back pointer to parent */
+       struct bna_rx *rx;              /* BFI_MAX_RXQ entries */
+       struct bna_rxp *rxp;            /* BFI_MAX_RXQ entries */
+       struct bna_rxq *rxq;            /* BFI_MAX_RXQ entries */
+
+       struct list_head                        rx_free_q;
+       struct list_head                        rx_active_q;
+       int                     rx_free_count;
+
+       struct list_head                        rxp_free_q;
+       int                     rxp_free_count;
+
+       struct list_head                        rxq_free_q;
+       int                     rxq_free_count;
+
+       enum bna_rx_mod_flags flags;
+
+       /* callback for bna_rx_mod_stop() */
+       void (*stop_cbfn)(struct bna_port *port,
+                               enum bna_cb_status status);
+
+       struct bfa_wc           rx_stop_wc;
+       u32             dim_vector[BNA_LOAD_T_MAX][BNA_BIAS_T_MAX];
+       u32             rxf_bmap[2];
+};
+
+/**
+ *
+ * CAM
+ *
+ */
+
+struct bna_ucam_mod {
+       struct bna_mac *ucmac;          /* BFI_MAX_UCMAC entries */
+       struct list_head                        free_q;
+
+       struct bna *bna;
+};
+
+struct bna_mcam_mod {
+       struct bna_mac *mcmac;          /* BFI_MAX_MCMAC entries */
+       struct list_head                        free_q;
+
+       struct bna *bna;
+};
+
+/**
+ *
+ * Statistics
+ *
+ */
+
+struct bna_tx_stats {
+       int                     tx_state;
+       int                     tx_flags;
+       int                     num_txqs;
+       u32             txq_bmap[2];
+       int                     txf_id;
+};
+
+struct bna_rx_stats {
+       int                     rx_state;
+       int                     rx_flags;
+       int                     num_rxps;
+       int                     num_rxqs;
+       u32             rxq_bmap[2];
+       u32             cq_bmap[2];
+       int                     rxf_id;
+       int                     rxf_state;
+       int                     rxf_oper_state;
+       int                     num_active_ucast;
+       int                     num_active_mcast;
+       int                     rxmode_active;
+       int                     vlan_filter_status;
+       u32             vlan_filter_table[(BFI_MAX_VLAN + 1) / 32];
+       int                     rss_status;
+       int                     hds_status;
+};
+
+struct bna_sw_stats {
+       int                     device_state;
+       int                     port_state;
+       int                     port_flags;
+       int                     llport_state;
+       int                     priority;
+       int                     num_active_tx;
+       int                     num_active_rx;
+       struct bna_tx_stats tx_stats[BFI_MAX_TXQ];
+       struct bna_rx_stats rx_stats[BFI_MAX_RXQ];
+};
+
+struct bna_stats {
+       u32             txf_bmap[2];
+       u32             rxf_bmap[2];
+       struct bfi_ll_stats     *hw_stats;
+       struct bna_sw_stats *sw_stats;
+};
+
+/**
+ *
+ * BNA
+ *
+ */
+
+struct bna {
+       struct bfa_pcidev pcidev;
+
+       int                     port_num;
+
+       struct bna_chip_regs regs;
+
+       struct bna_dma_addr hw_stats_dma;
+       struct bna_stats stats;
+
+       struct bna_device device;
+       struct bfa_cee cee;
+
+       struct bna_mbox_mod mbox_mod;
+
+       struct bna_port port;
+
+       struct bna_tx_mod tx_mod;
+
+       struct bna_rx_mod rx_mod;
+
+       struct bna_ib_mod ib_mod;
+
+       struct bna_ucam_mod ucam_mod;
+       struct bna_mcam_mod mcam_mod;
+
+       struct bna_rit_mod rit_mod;
+
+       int                     rxf_default_id;
+       int                     rxf_promisc_id;
+
+       struct bna_mbox_qe mbox_qe;
+
+       struct bnad *bnad;
+};
+
+#endif /* __BNA_TYPES_H__ */
diff --git a/drivers/net/bna/bnad.c b/drivers/net/bna/bnad.c
new file mode 100644 (file)
index 0000000..8158fb9
--- /dev/null
@@ -0,0 +1,3266 @@
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * 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.
+ */
+/*
+ * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/etherdevice.h>
+#include <linux/in.h>
+#include <linux/ethtool.h>
+#include <linux/if_vlan.h>
+#include <linux/if_ether.h>
+#include <linux/ip.h>
+
+#include "bnad.h"
+#include "bna.h"
+#include "cna.h"
+
+DEFINE_MUTEX(bnad_fwimg_mutex);
+
+/*
+ * Module params
+ */
+static uint bnad_msix_disable;
+module_param(bnad_msix_disable, uint, 0444);
+MODULE_PARM_DESC(bnad_msix_disable, "Disable MSIX mode");
+
+static uint bnad_ioc_auto_recover = 1;
+module_param(bnad_ioc_auto_recover, uint, 0444);
+MODULE_PARM_DESC(bnad_ioc_auto_recover, "Enable / Disable auto recovery");
+
+/*
+ * Global variables
+ */
+u32 bnad_rxqs_per_cq = 2;
+
+const u8 bnad_bcast_addr[] =  {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+/*
+ * Local MACROS
+ */
+#define BNAD_TX_UNMAPQ_DEPTH (bnad->txq_depth * 2)
+
+#define BNAD_RX_UNMAPQ_DEPTH (bnad->rxq_depth)
+
+#define BNAD_GET_MBOX_IRQ(_bnad)                               \
+       (((_bnad)->cfg_flags & BNAD_CF_MSIX) ?                  \
+        ((_bnad)->msix_table[(_bnad)->msix_num - 1].vector) :  \
+        ((_bnad)->pcidev->irq))
+
+#define BNAD_FILL_UNMAPQ_MEM_REQ(_res_info, _num, _depth)      \
+do {                                                           \
+       (_res_info)->res_type = BNA_RES_T_MEM;                  \
+       (_res_info)->res_u.mem_info.mem_type = BNA_MEM_T_KVA;   \
+       (_res_info)->res_u.mem_info.num = (_num);               \
+       (_res_info)->res_u.mem_info.len =                       \
+       sizeof(struct bnad_unmap_q) +                           \
+       (sizeof(struct bnad_skb_unmap) * ((_depth) - 1));       \
+} while (0)
+
+/*
+ * Reinitialize completions in CQ, once Rx is taken down
+ */
+static void
+bnad_cq_cmpl_init(struct bnad *bnad, struct bna_ccb *ccb)
+{
+       struct bna_cq_entry *cmpl, *next_cmpl;
+       unsigned int wi_range, wis = 0, ccb_prod = 0;
+       int i;
+
+       BNA_CQ_QPGE_PTR_GET(ccb_prod, ccb->sw_qpt, cmpl,
+                           wi_range);
+
+       for (i = 0; i < ccb->q_depth; i++) {
+               wis++;
+               if (likely(--wi_range))
+                       next_cmpl = cmpl + 1;
+               else {
+                       BNA_QE_INDX_ADD(ccb_prod, wis, ccb->q_depth);
+                       wis = 0;
+                       BNA_CQ_QPGE_PTR_GET(ccb_prod, ccb->sw_qpt,
+                                               next_cmpl, wi_range);
+               }
+               cmpl->valid = 0;
+               cmpl = next_cmpl;
+       }
+}
+
+/*
+ * Frees all pending Tx Bufs
+ * At this point no activity is expected on the Q,
+ * so DMA unmap & freeing is fine.
+ */
+static void
+bnad_free_all_txbufs(struct bnad *bnad,
+                struct bna_tcb *tcb)
+{
+       u16             unmap_cons;
+       struct bnad_unmap_q *unmap_q = tcb->unmap_q;
+       struct bnad_skb_unmap *unmap_array;
+       struct sk_buff          *skb = NULL;
+       int                     i;
+
+       unmap_array = unmap_q->unmap_array;
+
+       unmap_cons = 0;
+       while (unmap_cons < unmap_q->q_depth) {
+               skb = unmap_array[unmap_cons].skb;
+               if (!skb) {
+                       unmap_cons++;
+                       continue;
+               }
+               unmap_array[unmap_cons].skb = NULL;
+
+               pci_unmap_single(bnad->pcidev,
+                                pci_unmap_addr(&unmap_array[unmap_cons],
+                                               dma_addr), skb_headlen(skb),
+                                               PCI_DMA_TODEVICE);
+
+               pci_unmap_addr_set(&unmap_array[unmap_cons], dma_addr, 0);
+               unmap_cons++;
+               for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+                       pci_unmap_page(bnad->pcidev,
+                                      pci_unmap_addr(&unmap_array[unmap_cons],
+                                                     dma_addr),
+                                      skb_shinfo(skb)->frags[i].size,
+                                      PCI_DMA_TODEVICE);
+                       pci_unmap_addr_set(&unmap_array[unmap_cons], dma_addr,
+                                          0);
+                       unmap_cons++;
+               }
+               dev_kfree_skb_any(skb);
+       }
+}
+
+/* Data Path Handlers */
+
+/*
+ * bnad_free_txbufs : Frees the Tx bufs on Tx completion
+ * Can be called in a) Interrupt context
+ *                 b) Sending context
+ *                 c) Tasklet context
+ */
+static u32
+bnad_free_txbufs(struct bnad *bnad,
+                struct bna_tcb *tcb)
+{
+       u32             sent_packets = 0, sent_bytes = 0;
+       u16             wis, unmap_cons, updated_hw_cons;
+       struct bnad_unmap_q *unmap_q = tcb->unmap_q;
+       struct bnad_skb_unmap *unmap_array;
+       struct sk_buff          *skb;
+       int i;
+
+       /*
+        * Just return if TX is stopped. This check is useful
+        * when bnad_free_txbufs() runs out of a tasklet scheduled
+        * before bnad_cb_tx_cleanup() cleared BNAD_RF_TX_STARTED bit
+        * but this routine runs actually after the cleanup has been
+        * executed.
+        */
+       if (!test_bit(BNAD_RF_TX_STARTED, &bnad->run_flags))
+               return 0;
+
+       updated_hw_cons = *(tcb->hw_consumer_index);
+
+       wis = BNA_Q_INDEX_CHANGE(tcb->consumer_index,
+                                 updated_hw_cons, tcb->q_depth);
+
+       BUG_ON(!(wis <= BNA_QE_IN_USE_CNT(tcb, tcb->q_depth)));
+
+       unmap_array = unmap_q->unmap_array;
+       unmap_cons = unmap_q->consumer_index;
+
+       prefetch(&unmap_array[unmap_cons + 1]);
+       while (wis) {
+               skb = unmap_array[unmap_cons].skb;
+
+               unmap_array[unmap_cons].skb = NULL;
+
+               sent_packets++;
+               sent_bytes += skb->len;
+               wis -= BNA_TXQ_WI_NEEDED(1 + skb_shinfo(skb)->nr_frags);
+
+               pci_unmap_single(bnad->pcidev,
+                                pci_unmap_addr(&unmap_array[unmap_cons],
+                                               dma_addr), skb_headlen(skb),
+                                PCI_DMA_TODEVICE);
+               pci_unmap_addr_set(&unmap_array[unmap_cons], dma_addr, 0);
+               BNA_QE_INDX_ADD(unmap_cons, 1, unmap_q->q_depth);
+
+               prefetch(&unmap_array[unmap_cons + 1]);
+               for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+                       prefetch(&unmap_array[unmap_cons + 1]);
+
+                       pci_unmap_page(bnad->pcidev,
+                                      pci_unmap_addr(&unmap_array[unmap_cons],
+                                                     dma_addr),
+                                      skb_shinfo(skb)->frags[i].size,
+                                      PCI_DMA_TODEVICE);
+                       pci_unmap_addr_set(&unmap_array[unmap_cons], dma_addr,
+                                          0);
+                       BNA_QE_INDX_ADD(unmap_cons, 1, unmap_q->q_depth);
+               }
+               dev_kfree_skb_any(skb);
+       }
+
+       /* Update consumer pointers. */
+       tcb->consumer_index = updated_hw_cons;
+       unmap_q->consumer_index = unmap_cons;
+
+       tcb->txq->tx_packets += sent_packets;
+       tcb->txq->tx_bytes += sent_bytes;
+
+       return sent_packets;
+}
+
+/* Tx Free Tasklet function */
+/* Frees for all the tcb's in all the Tx's */
+/*
+ * Scheduled from sending context, so that
+ * the fat Tx lock is not held for too long
+ * in the sending context.
+ */
+static void
+bnad_tx_free_tasklet(unsigned long bnad_ptr)
+{
+       struct bnad *bnad = (struct bnad *)bnad_ptr;
+       struct bna_tcb *tcb;
+       u32             acked;
+       int                     i, j;
+
+       for (i = 0; i < bnad->num_tx; i++) {
+               for (j = 0; j < bnad->num_txq_per_tx; j++) {
+                       tcb = bnad->tx_info[i].tcb[j];
+                       if (!tcb)
+                               continue;
+                       if (((u16) (*tcb->hw_consumer_index) !=
+                               tcb->consumer_index) &&
+                               (!test_and_set_bit(BNAD_TXQ_FREE_SENT,
+                                                 &tcb->flags))) {
+                               acked = bnad_free_txbufs(bnad, tcb);
+                               bna_ib_ack(tcb->i_dbell, acked);
+                               smp_mb__before_clear_bit();
+                               clear_bit(BNAD_TXQ_FREE_SENT, &tcb->flags);
+                       }
+               }
+       }
+}
+
+static u32
+bnad_tx(struct bnad *bnad, struct bna_tcb *tcb)
+{
+       struct net_device *netdev = bnad->netdev;
+       u32 sent;
+
+       if (test_and_set_bit(BNAD_TXQ_FREE_SENT, &tcb->flags))
+               return 0;
+
+       sent = bnad_free_txbufs(bnad, tcb);
+       if (sent) {
+               if (netif_queue_stopped(netdev) &&
+                   netif_carrier_ok(netdev) &&
+                   BNA_QE_FREE_CNT(tcb, tcb->q_depth) >=
+                                   BNAD_NETIF_WAKE_THRESHOLD) {
+                       netif_wake_queue(netdev);
+                       BNAD_UPDATE_CTR(bnad, netif_queue_wakeup);
+               }
+               bna_ib_ack(tcb->i_dbell, sent);
+       } else
+               bna_ib_ack(tcb->i_dbell, 0);
+
+       smp_mb__before_clear_bit();
+       clear_bit(BNAD_TXQ_FREE_SENT, &tcb->flags);
+
+       return sent;
+}
+
+/* MSIX Tx Completion Handler */
+static irqreturn_t
+bnad_msix_tx(int irq, void *data)
+{
+       struct bna_tcb *tcb = (struct bna_tcb *)data;
+       struct bnad *bnad = tcb->bnad;
+
+       bnad_tx(bnad, tcb);
+
+       return IRQ_HANDLED;
+}
+
+static void
+bnad_reset_rcb(struct bnad *bnad, struct bna_rcb *rcb)
+{
+       struct bnad_unmap_q *unmap_q = rcb->unmap_q;
+
+       rcb->producer_index = 0;
+       rcb->consumer_index = 0;
+
+       unmap_q->producer_index = 0;
+       unmap_q->consumer_index = 0;
+}
+
+static void
+bnad_free_rxbufs(struct bnad *bnad, struct bna_rcb *rcb)
+{
+       struct bnad_unmap_q *unmap_q;
+       struct sk_buff *skb;
+
+       unmap_q = rcb->unmap_q;
+       while (BNA_QE_IN_USE_CNT(unmap_q, unmap_q->q_depth)) {
+               skb = unmap_q->unmap_array[unmap_q->consumer_index].skb;
+               BUG_ON(!(skb));
+               unmap_q->unmap_array[unmap_q->consumer_index].skb = NULL;
+               pci_unmap_single(bnad->pcidev, pci_unmap_addr(&unmap_q->
+                                       unmap_array[unmap_q->consumer_index],
+                                       dma_addr), rcb->rxq->buffer_size +
+                                       NET_IP_ALIGN, PCI_DMA_FROMDEVICE);
+               dev_kfree_skb(skb);
+               BNA_QE_INDX_ADD(unmap_q->consumer_index, 1, unmap_q->q_depth);
+               BNA_QE_INDX_ADD(rcb->consumer_index, 1, rcb->q_depth);
+       }
+
+       bnad_reset_rcb(bnad, rcb);
+}
+
+static void
+bnad_alloc_n_post_rxbufs(struct bnad *bnad, struct bna_rcb *rcb)
+{
+       u16 to_alloc, alloced, unmap_prod, wi_range;
+       struct bnad_unmap_q *unmap_q = rcb->unmap_q;
+       struct bnad_skb_unmap *unmap_array;
+       struct bna_rxq_entry *rxent;
+       struct sk_buff *skb;
+       dma_addr_t dma_addr;
+
+       alloced = 0;
+       to_alloc =
+               BNA_QE_FREE_CNT(unmap_q, unmap_q->q_depth);
+
+       unmap_array = unmap_q->unmap_array;
+       unmap_prod = unmap_q->producer_index;
+
+       BNA_RXQ_QPGE_PTR_GET(unmap_prod, rcb->sw_qpt, rxent, wi_range);
+
+       while (to_alloc--) {
+               if (!wi_range) {
+                       BNA_RXQ_QPGE_PTR_GET(unmap_prod, rcb->sw_qpt, rxent,
+                                            wi_range);
+               }
+               skb = alloc_skb(rcb->rxq->buffer_size + NET_IP_ALIGN,
+                                    GFP_ATOMIC);
+               if (unlikely(!skb)) {
+                       BNAD_UPDATE_CTR(bnad, rxbuf_alloc_failed);
+                       goto finishing;
+               }
+               skb->dev = bnad->netdev;
+               skb_reserve(skb, NET_IP_ALIGN);
+               unmap_array[unmap_prod].skb = skb;
+               dma_addr = pci_map_single(bnad->pcidev, skb->data,
+                       rcb->rxq->buffer_size, PCI_DMA_FROMDEVICE);
+               pci_unmap_addr_set(&unmap_array[unmap_prod], dma_addr,
+                                  dma_addr);
+               BNA_SET_DMA_ADDR(dma_addr, &rxent->host_addr);
+               BNA_QE_INDX_ADD(unmap_prod, 1, unmap_q->q_depth);
+
+               rxent++;
+               wi_range--;
+               alloced++;
+       }
+
+finishing:
+       if (likely(alloced)) {
+               unmap_q->producer_index = unmap_prod;
+               rcb->producer_index = unmap_prod;
+               smp_mb();
+               bna_rxq_prod_indx_doorbell(rcb);
+       }
+}
+
+/*
+ * Locking is required in the enable path
+ * because it is called from a napi poll
+ * context, where the bna_lock is not held
+ * unlike the IRQ context.
+ */
+static void
+bnad_enable_txrx_irqs(struct bnad *bnad)
+{
+       struct bna_tcb *tcb;
+       struct bna_ccb *ccb;
+       int i, j;
+       unsigned long flags;
+
+       spin_lock_irqsave(&bnad->bna_lock, flags);
+       for (i = 0; i < bnad->num_tx; i++) {
+               for (j = 0; j < bnad->num_txq_per_tx; j++) {
+                       tcb = bnad->tx_info[i].tcb[j];
+                       bna_ib_coalescing_timer_set(tcb->i_dbell,
+                               tcb->txq->ib->ib_config.coalescing_timeo);
+                       bna_ib_ack(tcb->i_dbell, 0);
+               }
+       }
+
+       for (i = 0; i < bnad->num_rx; i++) {
+               for (j = 0; j < bnad->num_rxp_per_rx; j++) {
+                       ccb = bnad->rx_info[i].rx_ctrl[j].ccb;
+                       bnad_enable_rx_irq_unsafe(ccb);
+               }
+       }
+       spin_unlock_irqrestore(&bnad->bna_lock, flags);
+}
+
+static inline void
+bnad_refill_rxq(struct bnad *bnad, struct bna_rcb *rcb)
+{
+       struct bnad_unmap_q *unmap_q = rcb->unmap_q;
+
+       if (!test_and_set_bit(BNAD_RXQ_REFILL, &rcb->flags)) {
+               if (BNA_QE_FREE_CNT(unmap_q, unmap_q->q_depth)
+                        >> BNAD_RXQ_REFILL_THRESHOLD_SHIFT)
+                       bnad_alloc_n_post_rxbufs(bnad, rcb);
+               smp_mb__before_clear_bit();
+               clear_bit(BNAD_RXQ_REFILL, &rcb->flags);
+       }
+}
+
+static u32
+bnad_poll_cq(struct bnad *bnad, struct bna_ccb *ccb, int budget)
+{
+       struct bna_cq_entry *cmpl, *next_cmpl;
+       struct bna_rcb *rcb = NULL;
+       unsigned int wi_range, packets = 0, wis = 0;
+       struct bnad_unmap_q *unmap_q;
+       struct sk_buff *skb;
+       u32 flags;
+       u32 qid0 = ccb->rcb[0]->rxq->rxq_id;
+       struct bna_pkt_rate *pkt_rt = &ccb->pkt_rate;
+
+       prefetch(bnad->netdev);
+       BNA_CQ_QPGE_PTR_GET(ccb->producer_index, ccb->sw_qpt, cmpl,
+                           wi_range);
+       BUG_ON(!(wi_range <= ccb->q_depth));
+       while (cmpl->valid && packets < budget) {
+               packets++;
+               BNA_UPDATE_PKT_CNT(pkt_rt, ntohs(cmpl->length));
+
+               if (qid0 == cmpl->rxq_id)
+                       rcb = ccb->rcb[0];
+               else
+                       rcb = ccb->rcb[1];
+
+               unmap_q = rcb->unmap_q;
+
+               skb = unmap_q->unmap_array[unmap_q->consumer_index].skb;
+               BUG_ON(!(skb));
+               unmap_q->unmap_array[unmap_q->consumer_index].skb = NULL;
+               pci_unmap_single(bnad->pcidev,
+                                pci_unmap_addr(&unmap_q->
+                                               unmap_array[unmap_q->
+                                                           consumer_index],
+                                               dma_addr),
+                                               rcb->rxq->buffer_size,
+                                               PCI_DMA_FROMDEVICE);
+               BNA_QE_INDX_ADD(unmap_q->consumer_index, 1, unmap_q->q_depth);
+
+               /* Should be more efficient ? Performance ? */
+               BNA_QE_INDX_ADD(rcb->consumer_index, 1, rcb->q_depth);
+
+               wis++;
+               if (likely(--wi_range))
+                       next_cmpl = cmpl + 1;
+               else {
+                       BNA_QE_INDX_ADD(ccb->producer_index, wis, ccb->q_depth);
+                       wis = 0;
+                       BNA_CQ_QPGE_PTR_GET(ccb->producer_index, ccb->sw_qpt,
+                                               next_cmpl, wi_range);
+                       BUG_ON(!(wi_range <= ccb->q_depth));
+               }
+               prefetch(next_cmpl);
+
+               flags = ntohl(cmpl->flags);
+               if (unlikely
+                   (flags &
+                    (BNA_CQ_EF_MAC_ERROR | BNA_CQ_EF_FCS_ERROR |
+                     BNA_CQ_EF_TOO_LONG))) {
+                       dev_kfree_skb_any(skb);
+                       rcb->rxq->rx_packets_with_error++;
+                       goto next;
+               }
+
+               skb_put(skb, ntohs(cmpl->length));
+               if (likely
+                   (bnad->rx_csum &&
+                    (((flags & BNA_CQ_EF_IPV4) &&
+                     (flags & BNA_CQ_EF_L3_CKSUM_OK)) ||
+                     (flags & BNA_CQ_EF_IPV6)) &&
+                     (flags & (BNA_CQ_EF_TCP | BNA_CQ_EF_UDP)) &&
+                     (flags & BNA_CQ_EF_L4_CKSUM_OK)))
+                       skb->ip_summed = CHECKSUM_UNNECESSARY;
+               else
+                       skb_checksum_none_assert(skb);
+
+               rcb->rxq->rx_packets++;
+               rcb->rxq->rx_bytes += skb->len;
+               skb->protocol = eth_type_trans(skb, bnad->netdev);
+
+               if (bnad->vlan_grp && (flags & BNA_CQ_EF_VLAN)) {
+                       struct bnad_rx_ctrl *rx_ctrl =
+                               (struct bnad_rx_ctrl *)ccb->ctrl;
+                       if (skb->ip_summed == CHECKSUM_UNNECESSARY)
+                               vlan_gro_receive(&rx_ctrl->napi, bnad->vlan_grp,
+                                               ntohs(cmpl->vlan_tag), skb);
+                       else
+                               vlan_hwaccel_receive_skb(skb,
+                                                        bnad->vlan_grp,
+                                                        ntohs(cmpl->vlan_tag));
+
+               } else { /* Not VLAN tagged/stripped */
+                       struct bnad_rx_ctrl *rx_ctrl =
+                               (struct bnad_rx_ctrl *)ccb->ctrl;
+                       if (skb->ip_summed == CHECKSUM_UNNECESSARY)
+                               napi_gro_receive(&rx_ctrl->napi, skb);
+                       else
+                               netif_receive_skb(skb);
+               }
+
+next:
+               cmpl->valid = 0;
+               cmpl = next_cmpl;
+       }
+
+       BNA_QE_INDX_ADD(ccb->producer_index, wis, ccb->q_depth);
+
+       if (likely(ccb)) {
+               bna_ib_ack(ccb->i_dbell, packets);
+               bnad_refill_rxq(bnad, ccb->rcb[0]);
+               if (ccb->rcb[1])
+                       bnad_refill_rxq(bnad, ccb->rcb[1]);
+       } else
+               bna_ib_ack(ccb->i_dbell, 0);
+
+       return packets;
+}
+
+static void
+bnad_disable_rx_irq(struct bnad *bnad, struct bna_ccb *ccb)
+{
+       bna_ib_coalescing_timer_set(ccb->i_dbell, 0);
+       bna_ib_ack(ccb->i_dbell, 0);
+}
+
+static void
+bnad_enable_rx_irq(struct bnad *bnad, struct bna_ccb *ccb)
+{
+       spin_lock_irq(&bnad->bna_lock); /* Because of polling context */
+       bnad_enable_rx_irq_unsafe(ccb);
+       spin_unlock_irq(&bnad->bna_lock);
+}
+
+static void
+bnad_netif_rx_schedule_poll(struct bnad *bnad, struct bna_ccb *ccb)
+{
+       struct bnad_rx_ctrl *rx_ctrl = (struct bnad_rx_ctrl *)(ccb->ctrl);
+       if (likely(napi_schedule_prep((&rx_ctrl->napi)))) {
+               bnad_disable_rx_irq(bnad, ccb);
+               __napi_schedule((&rx_ctrl->napi));
+       }
+       BNAD_UPDATE_CTR(bnad, netif_rx_schedule);
+}
+
+/* MSIX Rx Path Handler */
+static irqreturn_t
+bnad_msix_rx(int irq, void *data)
+{
+       struct bna_ccb *ccb = (struct bna_ccb *)data;
+       struct bnad *bnad = ccb->bnad;
+
+       bnad_netif_rx_schedule_poll(bnad, ccb);
+
+       return IRQ_HANDLED;
+}
+
+/* Interrupt handlers */
+
+/* Mbox Interrupt Handlers */
+static irqreturn_t
+bnad_msix_mbox_handler(int irq, void *data)
+{
+       u32 intr_status;
+       unsigned long  flags;
+       struct net_device *netdev = data;
+       struct bnad *bnad;
+
+       bnad = netdev_priv(netdev);
+
+       /* BNA_ISR_GET(bnad); Inc Ref count */
+       spin_lock_irqsave(&bnad->bna_lock, flags);
+
+       bna_intr_status_get(&bnad->bna, intr_status);
+
+       if (BNA_IS_MBOX_ERR_INTR(intr_status))
+               bna_mbox_handler(&bnad->bna, intr_status);
+
+       spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+       /* BNAD_ISR_PUT(bnad); Dec Ref count */
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t
+bnad_isr(int irq, void *data)
+{
+       int i, j;
+       u32 intr_status;
+       unsigned long flags;
+       struct net_device *netdev = data;
+       struct bnad *bnad = netdev_priv(netdev);
+       struct bnad_rx_info *rx_info;
+       struct bnad_rx_ctrl *rx_ctrl;
+
+       spin_lock_irqsave(&bnad->bna_lock, flags);
+
+       bna_intr_status_get(&bnad->bna, intr_status);
+       if (!intr_status) {
+               spin_unlock_irqrestore(&bnad->bna_lock, flags);
+               return IRQ_NONE;
+       }
+
+       if (BNA_IS_MBOX_ERR_INTR(intr_status)) {
+               bna_mbox_handler(&bnad->bna, intr_status);
+               if (!BNA_IS_INTX_DATA_INTR(intr_status)) {
+                       spin_unlock_irqrestore(&bnad->bna_lock, flags);
+                       goto done;
+               }
+       }
+       spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+       /* Process data interrupts */
+       for (i = 0; i < bnad->num_rx; i++) {
+               rx_info = &bnad->rx_info[i];
+               if (!rx_info->rx)
+                       continue;
+               for (j = 0; j < bnad->num_rxp_per_rx; j++) {
+                       rx_ctrl = &rx_info->rx_ctrl[j];
+                       if (rx_ctrl->ccb)
+                               bnad_netif_rx_schedule_poll(bnad,
+                                                           rx_ctrl->ccb);
+               }
+       }
+done:
+       return IRQ_HANDLED;
+}
+
+/*
+ * Called in interrupt / callback context
+ * with bna_lock held, so cfg_flags access is OK
+ */
+static void
+bnad_enable_mbox_irq(struct bnad *bnad)
+{
+       int irq = BNAD_GET_MBOX_IRQ(bnad);
+
+       if (!(bnad->cfg_flags & BNAD_CF_MSIX))
+               return;
+
+       if (test_and_clear_bit(BNAD_RF_MBOX_IRQ_DISABLED, &bnad->run_flags))
+               enable_irq(irq);
+       BNAD_UPDATE_CTR(bnad, mbox_intr_enabled);
+}
+
+/*
+ * Called with bnad->bna_lock held b'cos of
+ * bnad->cfg_flags access.
+ */
+void
+bnad_disable_mbox_irq(struct bnad *bnad)
+{
+       int irq = BNAD_GET_MBOX_IRQ(bnad);
+
+       if (!(bnad->cfg_flags & BNAD_CF_MSIX))
+               return;
+
+       if (!test_and_set_bit(BNAD_RF_MBOX_IRQ_DISABLED, &bnad->run_flags))
+               disable_irq_nosync(irq);
+       BNAD_UPDATE_CTR(bnad, mbox_intr_disabled);
+}
+
+/* Control Path Handlers */
+
+/* Callbacks */
+void
+bnad_cb_device_enable_mbox_intr(struct bnad *bnad)
+{
+       bnad_enable_mbox_irq(bnad);
+}
+
+void
+bnad_cb_device_disable_mbox_intr(struct bnad *bnad)
+{
+       bnad_disable_mbox_irq(bnad);
+}
+
+void
+bnad_cb_device_enabled(struct bnad *bnad, enum bna_cb_status status)
+{
+       complete(&bnad->bnad_completions.ioc_comp);
+       bnad->bnad_completions.ioc_comp_status = status;
+}
+
+void
+bnad_cb_device_disabled(struct bnad *bnad, enum bna_cb_status status)
+{
+       complete(&bnad->bnad_completions.ioc_comp);
+       bnad->bnad_completions.ioc_comp_status = status;
+}
+
+static void
+bnad_cb_port_disabled(void *arg, enum bna_cb_status status)
+{
+       struct bnad *bnad = (struct bnad *)arg;
+
+       complete(&bnad->bnad_completions.port_comp);
+
+       netif_carrier_off(bnad->netdev);
+}
+
+void
+bnad_cb_port_link_status(struct bnad *bnad,
+                       enum bna_link_status link_status)
+{
+       bool link_up = 0;
+
+       link_up = (link_status == BNA_LINK_UP) || (link_status == BNA_CEE_UP);
+
+       if (link_status == BNA_CEE_UP) {
+               set_bit(BNAD_RF_CEE_RUNNING, &bnad->run_flags);
+               BNAD_UPDATE_CTR(bnad, cee_up);
+       } else
+               clear_bit(BNAD_RF_CEE_RUNNING, &bnad->run_flags);
+
+       if (link_up) {
+               if (!netif_carrier_ok(bnad->netdev)) {
+                       pr_warn("bna: %s link up\n",
+                               bnad->netdev->name);
+                       netif_carrier_on(bnad->netdev);
+                       BNAD_UPDATE_CTR(bnad, link_toggle);
+                       if (test_bit(BNAD_RF_TX_STARTED, &bnad->run_flags)) {
+                               /* Force an immediate Transmit Schedule */
+                               pr_info("bna: %s TX_STARTED\n",
+                                       bnad->netdev->name);
+                               netif_wake_queue(bnad->netdev);
+                               BNAD_UPDATE_CTR(bnad, netif_queue_wakeup);
+                       } else {
+                               netif_stop_queue(bnad->netdev);
+                               BNAD_UPDATE_CTR(bnad, netif_queue_stop);
+                       }
+               }
+       } else {
+               if (netif_carrier_ok(bnad->netdev)) {
+                       pr_warn("bna: %s link down\n",
+                               bnad->netdev->name);
+                       netif_carrier_off(bnad->netdev);
+                       BNAD_UPDATE_CTR(bnad, link_toggle);
+               }
+       }
+}
+
+static void
+bnad_cb_tx_disabled(void *arg, struct bna_tx *tx,
+                       enum bna_cb_status status)
+{
+       struct bnad *bnad = (struct bnad *)arg;
+
+       complete(&bnad->bnad_completions.tx_comp);
+}
+
+static void
+bnad_cb_tcb_setup(struct bnad *bnad, struct bna_tcb *tcb)
+{
+       struct bnad_tx_info *tx_info =
+                       (struct bnad_tx_info *)tcb->txq->tx->priv;
+       struct bnad_unmap_q *unmap_q = tcb->unmap_q;
+
+       tx_info->tcb[tcb->id] = tcb;
+       unmap_q->producer_index = 0;
+       unmap_q->consumer_index = 0;
+       unmap_q->q_depth = BNAD_TX_UNMAPQ_DEPTH;
+}
+
+static void
+bnad_cb_tcb_destroy(struct bnad *bnad, struct bna_tcb *tcb)
+{
+       struct bnad_tx_info *tx_info =
+                       (struct bnad_tx_info *)tcb->txq->tx->priv;
+
+       tx_info->tcb[tcb->id] = NULL;
+}
+
+static void
+bnad_cb_rcb_setup(struct bnad *bnad, struct bna_rcb *rcb)
+{
+       struct bnad_unmap_q *unmap_q = rcb->unmap_q;
+
+       unmap_q->producer_index = 0;
+       unmap_q->consumer_index = 0;
+       unmap_q->q_depth = BNAD_RX_UNMAPQ_DEPTH;
+}
+
+static void
+bnad_cb_ccb_setup(struct bnad *bnad, struct bna_ccb *ccb)
+{
+       struct bnad_rx_info *rx_info =
+                       (struct bnad_rx_info *)ccb->cq->rx->priv;
+
+       rx_info->rx_ctrl[ccb->id].ccb = ccb;
+       ccb->ctrl = &rx_info->rx_ctrl[ccb->id];
+}
+
+static void
+bnad_cb_ccb_destroy(struct bnad *bnad, struct bna_ccb *ccb)
+{
+       struct bnad_rx_info *rx_info =
+                       (struct bnad_rx_info *)ccb->cq->rx->priv;
+
+       rx_info->rx_ctrl[ccb->id].ccb = NULL;
+}
+
+static void
+bnad_cb_tx_stall(struct bnad *bnad, struct bna_tcb *tcb)
+{
+       struct bnad_tx_info *tx_info =
+                       (struct bnad_tx_info *)tcb->txq->tx->priv;
+
+       if (tx_info != &bnad->tx_info[0])
+               return;
+
+       clear_bit(BNAD_RF_TX_STARTED, &bnad->run_flags);
+       netif_stop_queue(bnad->netdev);
+       pr_info("bna: %s TX_STOPPED\n", bnad->netdev->name);
+}
+
+static void
+bnad_cb_tx_resume(struct bnad *bnad, struct bna_tcb *tcb)
+{
+       if (test_and_set_bit(BNAD_RF_TX_STARTED, &bnad->run_flags))
+               return;
+
+       if (netif_carrier_ok(bnad->netdev)) {
+               pr_info("bna: %s TX_STARTED\n", bnad->netdev->name);
+               netif_wake_queue(bnad->netdev);
+               BNAD_UPDATE_CTR(bnad, netif_queue_wakeup);
+       }
+}
+
+static void
+bnad_cb_tx_cleanup(struct bnad *bnad, struct bna_tcb *tcb)
+{
+       struct bnad_unmap_q *unmap_q = tcb->unmap_q;
+
+       if (!tcb || (!tcb->unmap_q))
+               return;
+
+       if (!unmap_q->unmap_array)
+               return;
+
+       if (test_and_set_bit(BNAD_TXQ_FREE_SENT, &tcb->flags))
+               return;
+
+       bnad_free_all_txbufs(bnad, tcb);
+
+       unmap_q->producer_index = 0;
+       unmap_q->consumer_index = 0;
+
+       smp_mb__before_clear_bit();
+       clear_bit(BNAD_TXQ_FREE_SENT, &tcb->flags);
+}
+
+static void
+bnad_cb_rx_cleanup(struct bnad *bnad,
+                       struct bna_ccb *ccb)
+{
+       bnad_cq_cmpl_init(bnad, ccb);
+
+       bnad_free_rxbufs(bnad, ccb->rcb[0]);
+       clear_bit(BNAD_RXQ_STARTED, &ccb->rcb[0]->flags);
+
+       if (ccb->rcb[1]) {
+               bnad_free_rxbufs(bnad, ccb->rcb[1]);
+               clear_bit(BNAD_RXQ_STARTED, &ccb->rcb[1]->flags);
+       }
+}
+
+static void
+bnad_cb_rx_post(struct bnad *bnad, struct bna_rcb *rcb)
+{
+       struct bnad_unmap_q *unmap_q = rcb->unmap_q;
+
+       set_bit(BNAD_RXQ_STARTED, &rcb->flags);
+
+       /* Now allocate & post buffers for this RCB */
+       /* !!Allocation in callback context */
+       if (!test_and_set_bit(BNAD_RXQ_REFILL, &rcb->flags)) {
+               if (BNA_QE_FREE_CNT(unmap_q, unmap_q->q_depth)
+                        >> BNAD_RXQ_REFILL_THRESHOLD_SHIFT)
+                       bnad_alloc_n_post_rxbufs(bnad, rcb);
+               smp_mb__before_clear_bit();
+               clear_bit(BNAD_RXQ_REFILL, &rcb->flags);
+       }
+}
+
+static void
+bnad_cb_rx_disabled(void *arg, struct bna_rx *rx,
+                       enum bna_cb_status status)
+{
+       struct bnad *bnad = (struct bnad *)arg;
+
+       complete(&bnad->bnad_completions.rx_comp);
+}
+
+static void
+bnad_cb_rx_mcast_add(struct bnad *bnad, struct bna_rx *rx,
+                               enum bna_cb_status status)
+{
+       bnad->bnad_completions.mcast_comp_status = status;
+       complete(&bnad->bnad_completions.mcast_comp);
+}
+
+void
+bnad_cb_stats_get(struct bnad *bnad, enum bna_cb_status status,
+                      struct bna_stats *stats)
+{
+       if (status == BNA_CB_SUCCESS)
+               BNAD_UPDATE_CTR(bnad, hw_stats_updates);
+
+       if (!netif_running(bnad->netdev) ||
+               !test_bit(BNAD_RF_STATS_TIMER_RUNNING, &bnad->run_flags))
+               return;
+
+       mod_timer(&bnad->stats_timer,
+                 jiffies + msecs_to_jiffies(BNAD_STATS_TIMER_FREQ));
+}
+
+void
+bnad_cb_stats_clr(struct bnad *bnad)
+{
+}
+
+/* Resource allocation, free functions */
+
+static void
+bnad_mem_free(struct bnad *bnad,
+             struct bna_mem_info *mem_info)
+{
+       int i;
+       dma_addr_t dma_pa;
+
+       if (mem_info->mdl == NULL)
+               return;
+
+       for (i = 0; i < mem_info->num; i++) {
+               if (mem_info->mdl[i].kva != NULL) {
+                       if (mem_info->mem_type == BNA_MEM_T_DMA) {
+                               BNA_GET_DMA_ADDR(&(mem_info->mdl[i].dma),
+                                               dma_pa);
+                               pci_free_consistent(bnad->pcidev,
+                                               mem_info->mdl[i].len,
+                                               mem_info->mdl[i].kva, dma_pa);
+                       } else
+                               kfree(mem_info->mdl[i].kva);
+               }
+       }
+       kfree(mem_info->mdl);
+       mem_info->mdl = NULL;
+}
+
+static int
+bnad_mem_alloc(struct bnad *bnad,
+              struct bna_mem_info *mem_info)
+{
+       int i;
+       dma_addr_t dma_pa;
+
+       if ((mem_info->num == 0) || (mem_info->len == 0)) {
+               mem_info->mdl = NULL;
+               return 0;
+       }
+
+       mem_info->mdl = kcalloc(mem_info->num, sizeof(struct bna_mem_descr),
+                               GFP_KERNEL);
+       if (mem_info->mdl == NULL)
+               return -ENOMEM;
+
+       if (mem_info->mem_type == BNA_MEM_T_DMA) {
+               for (i = 0; i < mem_info->num; i++) {
+                       mem_info->mdl[i].len = mem_info->len;
+                       mem_info->mdl[i].kva =
+                               pci_alloc_consistent(bnad->pcidev,
+                                               mem_info->len, &dma_pa);
+
+                       if (mem_info->mdl[i].kva == NULL)
+                               goto err_return;
+
+                       BNA_SET_DMA_ADDR(dma_pa,
+                                        &(mem_info->mdl[i].dma));
+               }
+       } else {
+               for (i = 0; i < mem_info->num; i++) {
+                       mem_info->mdl[i].len = mem_info->len;
+                       mem_info->mdl[i].kva = kzalloc(mem_info->len,
+                                                       GFP_KERNEL);
+                       if (mem_info->mdl[i].kva == NULL)
+                               goto err_return;
+               }
+       }
+
+       return 0;
+
+err_return:
+       bnad_mem_free(bnad, mem_info);
+       return -ENOMEM;
+}
+
+/* Free IRQ for Mailbox */
+static void
+bnad_mbox_irq_free(struct bnad *bnad,
+                  struct bna_intr_info *intr_info)
+{
+       int irq;
+       unsigned long flags;
+
+       if (intr_info->idl == NULL)
+               return;
+
+       spin_lock_irqsave(&bnad->bna_lock, flags);
+
+       bnad_disable_mbox_irq(bnad);
+
+       irq = BNAD_GET_MBOX_IRQ(bnad);
+       free_irq(irq, bnad->netdev);
+
+       spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+       kfree(intr_info->idl);
+}
+
+/*
+ * Allocates IRQ for Mailbox, but keep it disabled
+ * This will be enabled once we get the mbox enable callback
+ * from bna
+ */
+static int
+bnad_mbox_irq_alloc(struct bnad *bnad,
+                   struct bna_intr_info *intr_info)
+{
+       int             err;
+       unsigned long   flags;
+       u32     irq;
+       irq_handler_t   irq_handler;
+
+       /* Mbox should use only 1 vector */
+
+       intr_info->idl = kzalloc(sizeof(*(intr_info->idl)), GFP_KERNEL);
+       if (!intr_info->idl)
+               return -ENOMEM;
+
+       spin_lock_irqsave(&bnad->bna_lock, flags);
+       if (bnad->cfg_flags & BNAD_CF_MSIX) {
+               irq_handler = (irq_handler_t)bnad_msix_mbox_handler;
+               irq = bnad->msix_table[bnad->msix_num - 1].vector;
+               flags = 0;
+               intr_info->intr_type = BNA_INTR_T_MSIX;
+               intr_info->idl[0].vector = bnad->msix_num - 1;
+       } else {
+               irq_handler = (irq_handler_t)bnad_isr;
+               irq = bnad->pcidev->irq;
+               flags = IRQF_SHARED;
+               intr_info->intr_type = BNA_INTR_T_INTX;
+               /* intr_info->idl.vector = 0 ? */
+       }
+       spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+       sprintf(bnad->mbox_irq_name, "%s", BNAD_NAME);
+
+       err = request_irq(irq, irq_handler, flags,
+                         bnad->mbox_irq_name, bnad->netdev);
+       if (err) {
+               kfree(intr_info->idl);
+               intr_info->idl = NULL;
+               return err;
+       }
+
+       spin_lock_irqsave(&bnad->bna_lock, flags);
+       bnad_disable_mbox_irq(bnad);
+       spin_unlock_irqrestore(&bnad->bna_lock, flags);
+       return 0;
+}
+
+static void
+bnad_txrx_irq_free(struct bnad *bnad, struct bna_intr_info *intr_info)
+{
+       kfree(intr_info->idl);
+       intr_info->idl = NULL;
+}
+
+/* Allocates Interrupt Descriptor List for MSIX/INT-X vectors */
+static int
+bnad_txrx_irq_alloc(struct bnad *bnad, enum bnad_intr_source src,
+                   uint txrx_id, struct bna_intr_info *intr_info)
+{
+       int i, vector_start = 0;
+       u32 cfg_flags;
+       unsigned long flags;
+
+       spin_lock_irqsave(&bnad->bna_lock, flags);
+       cfg_flags = bnad->cfg_flags;
+       spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+       if (cfg_flags & BNAD_CF_MSIX) {
+               intr_info->intr_type = BNA_INTR_T_MSIX;
+               intr_info->idl = kcalloc(intr_info->num,
+                                       sizeof(struct bna_intr_descr),
+                                       GFP_KERNEL);
+               if (!intr_info->idl)
+                       return -ENOMEM;
+
+               switch (src) {
+               case BNAD_INTR_TX:
+                       vector_start = txrx_id;
+                       break;
+
+               case BNAD_INTR_RX:
+                       vector_start = bnad->num_tx * bnad->num_txq_per_tx +
+                                       txrx_id;
+                       break;
+
+               default:
+                       BUG();
+               }
+
+               for (i = 0; i < intr_info->num; i++)
+                       intr_info->idl[i].vector = vector_start + i;
+       } else {
+               intr_info->intr_type = BNA_INTR_T_INTX;
+               intr_info->num = 1;
+               intr_info->idl = kcalloc(intr_info->num,
+                                       sizeof(struct bna_intr_descr),
+                                       GFP_KERNEL);
+               if (!intr_info->idl)
+                       return -ENOMEM;
+
+               switch (src) {
+               case BNAD_INTR_TX:
+                       intr_info->idl[0].vector = 0x1; /* Bit mask : Tx IB */
+                       break;
+
+               case BNAD_INTR_RX:
+                       intr_info->idl[0].vector = 0x2; /* Bit mask : Rx IB */
+                       break;
+               }
+       }
+       return 0;
+}
+
+/**
+ * NOTE: Should be called for MSIX only
+ * Unregisters Tx MSIX vector(s) from the kernel
+ */
+static void
+bnad_tx_msix_unregister(struct bnad *bnad, struct bnad_tx_info *tx_info,
+                       int num_txqs)
+{
+       int i;
+       int vector_num;
+
+       for (i = 0; i < num_txqs; i++) {
+               if (tx_info->tcb[i] == NULL)
+                       continue;
+
+               vector_num = tx_info->tcb[i]->intr_vector;
+               free_irq(bnad->msix_table[vector_num].vector, tx_info->tcb[i]);
+       }
+}
+
+/**
+ * NOTE: Should be called for MSIX only
+ * Registers Tx MSIX vector(s) and ISR(s), cookie with the kernel
+ */
+static int
+bnad_tx_msix_register(struct bnad *bnad, struct bnad_tx_info *tx_info,
+                       uint tx_id, int num_txqs)
+{
+       int i;
+       int err;
+       int vector_num;
+
+       for (i = 0; i < num_txqs; i++) {
+               vector_num = tx_info->tcb[i]->intr_vector;
+               sprintf(tx_info->tcb[i]->name, "%s TXQ %d", bnad->netdev->name,
+                               tx_id + tx_info->tcb[i]->id);
+               err = request_irq(bnad->msix_table[vector_num].vector,
+                                 (irq_handler_t)bnad_msix_tx, 0,
+                                 tx_info->tcb[i]->name,
+                                 tx_info->tcb[i]);
+               if (err)
+                       goto err_return;
+       }
+
+       return 0;
+
+err_return:
+       if (i > 0)
+               bnad_tx_msix_unregister(bnad, tx_info, (i - 1));
+       return -1;
+}
+
+/**
+ * NOTE: Should be called for MSIX only
+ * Unregisters Rx MSIX vector(s) from the kernel
+ */
+static void
+bnad_rx_msix_unregister(struct bnad *bnad, struct bnad_rx_info *rx_info,
+                       int num_rxps)
+{
+       int i;
+       int vector_num;
+
+       for (i = 0; i < num_rxps; i++) {
+               if (rx_info->rx_ctrl[i].ccb == NULL)
+                       continue;
+
+               vector_num = rx_info->rx_ctrl[i].ccb->intr_vector;
+               free_irq(bnad->msix_table[vector_num].vector,
+                        rx_info->rx_ctrl[i].ccb);
+       }
+}
+
+/**
+ * NOTE: Should be called for MSIX only
+ * Registers Tx MSIX vector(s) and ISR(s), cookie with the kernel
+ */
+static int
+bnad_rx_msix_register(struct bnad *bnad, struct bnad_rx_info *rx_info,
+                       uint rx_id, int num_rxps)
+{
+       int i;
+       int err;
+       int vector_num;
+
+       for (i = 0; i < num_rxps; i++) {
+               vector_num = rx_info->rx_ctrl[i].ccb->intr_vector;
+               sprintf(rx_info->rx_ctrl[i].ccb->name, "%s CQ %d",
+                       bnad->netdev->name,
+                       rx_id + rx_info->rx_ctrl[i].ccb->id);
+               err = request_irq(bnad->msix_table[vector_num].vector,
+                                 (irq_handler_t)bnad_msix_rx, 0,
+                                 rx_info->rx_ctrl[i].ccb->name,
+                                 rx_info->rx_ctrl[i].ccb);
+               if (err)
+                       goto err_return;
+       }
+
+       return 0;
+
+err_return:
+       if (i > 0)
+               bnad_rx_msix_unregister(bnad, rx_info, (i - 1));
+       return -1;
+}
+
+/* Free Tx object Resources */
+static void
+bnad_tx_res_free(struct bnad *bnad, struct bna_res_info *res_info)
+{
+       int i;
+
+       for (i = 0; i < BNA_TX_RES_T_MAX; i++) {
+               if (res_info[i].res_type == BNA_RES_T_MEM)
+                       bnad_mem_free(bnad, &res_info[i].res_u.mem_info);
+               else if (res_info[i].res_type == BNA_RES_T_INTR)
+                       bnad_txrx_irq_free(bnad, &res_info[i].res_u.intr_info);
+       }
+}
+
+/* Allocates memory and interrupt resources for Tx object */
+static int
+bnad_tx_res_alloc(struct bnad *bnad, struct bna_res_info *res_info,
+                 uint tx_id)
+{
+       int i, err = 0;
+
+       for (i = 0; i < BNA_TX_RES_T_MAX; i++) {
+               if (res_info[i].res_type == BNA_RES_T_MEM)
+                       err = bnad_mem_alloc(bnad,
+                                       &res_info[i].res_u.mem_info);
+               else if (res_info[i].res_type == BNA_RES_T_INTR)
+                       err = bnad_txrx_irq_alloc(bnad, BNAD_INTR_TX, tx_id,
+                                       &res_info[i].res_u.intr_info);
+               if (err)
+                       goto err_return;
+       }
+       return 0;
+
+err_return:
+       bnad_tx_res_free(bnad, res_info);
+       return err;
+}
+
+/* Free Rx object Resources */
+static void
+bnad_rx_res_free(struct bnad *bnad, struct bna_res_info *res_info)
+{
+       int i;
+
+       for (i = 0; i < BNA_RX_RES_T_MAX; i++) {
+               if (res_info[i].res_type == BNA_RES_T_MEM)
+                       bnad_mem_free(bnad, &res_info[i].res_u.mem_info);
+               else if (res_info[i].res_type == BNA_RES_T_INTR)
+                       bnad_txrx_irq_free(bnad, &res_info[i].res_u.intr_info);
+       }
+}
+
+/* Allocates memory and interrupt resources for Rx object */
+static int
+bnad_rx_res_alloc(struct bnad *bnad, struct bna_res_info *res_info,
+                 uint rx_id)
+{
+       int i, err = 0;
+
+       /* All memory needs to be allocated before setup_ccbs */
+       for (i = 0; i < BNA_RX_RES_T_MAX; i++) {
+               if (res_info[i].res_type == BNA_RES_T_MEM)
+                       err = bnad_mem_alloc(bnad,
+                                       &res_info[i].res_u.mem_info);
+               else if (res_info[i].res_type == BNA_RES_T_INTR)
+                       err = bnad_txrx_irq_alloc(bnad, BNAD_INTR_RX, rx_id,
+                                       &res_info[i].res_u.intr_info);
+               if (err)
+                       goto err_return;
+       }
+       return 0;
+
+err_return:
+       bnad_rx_res_free(bnad, res_info);
+       return err;
+}
+
+/* Timer callbacks */
+/* a) IOC timer */
+static void
+bnad_ioc_timeout(unsigned long data)
+{
+       struct bnad *bnad = (struct bnad *)data;
+       unsigned long flags;
+
+       spin_lock_irqsave(&bnad->bna_lock, flags);
+       bfa_nw_ioc_timeout((void *) &bnad->bna.device.ioc);
+       spin_unlock_irqrestore(&bnad->bna_lock, flags);
+}
+
+static void
+bnad_ioc_hb_check(unsigned long data)
+{
+       struct bnad *bnad = (struct bnad *)data;
+       unsigned long flags;
+
+       spin_lock_irqsave(&bnad->bna_lock, flags);
+       bfa_nw_ioc_hb_check((void *) &bnad->bna.device.ioc);
+       spin_unlock_irqrestore(&bnad->bna_lock, flags);
+}
+
+static void
+bnad_ioc_sem_timeout(unsigned long data)
+{
+       struct bnad *bnad = (struct bnad *)data;
+       unsigned long flags;
+
+       spin_lock_irqsave(&bnad->bna_lock, flags);
+       bfa_nw_ioc_sem_timeout((void *) &bnad->bna.device.ioc);
+       spin_unlock_irqrestore(&bnad->bna_lock, flags);
+}
+
+/*
+ * All timer routines use bnad->bna_lock to protect against
+ * the following race, which may occur in case of no locking:
+ *     Time    CPU m           CPU n
+ *     0       1 = test_bit
+ *     1                       clear_bit
+ *     2                       del_timer_sync
+ *     3       mod_timer
+ */
+
+/* b) Dynamic Interrupt Moderation Timer */
+static void
+bnad_dim_timeout(unsigned long data)
+{
+       struct bnad *bnad = (struct bnad *)data;
+       struct bnad_rx_info *rx_info;
+       struct bnad_rx_ctrl *rx_ctrl;
+       int i, j;
+       unsigned long flags;
+
+       if (!netif_carrier_ok(bnad->netdev))
+               return;
+
+       spin_lock_irqsave(&bnad->bna_lock, flags);
+       for (i = 0; i < bnad->num_rx; i++) {
+               rx_info = &bnad->rx_info[i];
+               if (!rx_info->rx)
+                       continue;
+               for (j = 0; j < bnad->num_rxp_per_rx; j++) {
+                       rx_ctrl = &rx_info->rx_ctrl[j];
+                       if (!rx_ctrl->ccb)
+                               continue;
+                       bna_rx_dim_update(rx_ctrl->ccb);
+               }
+       }
+
+       /* Check for BNAD_CF_DIM_ENABLED, does not eleminate a race */
+       if (test_bit(BNAD_RF_DIM_TIMER_RUNNING, &bnad->run_flags))
+               mod_timer(&bnad->dim_timer,
+                         jiffies + msecs_to_jiffies(BNAD_DIM_TIMER_FREQ));
+       spin_unlock_irqrestore(&bnad->bna_lock, flags);
+}
+
+/* c)  Statistics Timer */
+static void
+bnad_stats_timeout(unsigned long data)
+{
+       struct bnad *bnad = (struct bnad *)data;
+       unsigned long flags;
+
+       if (!netif_running(bnad->netdev) ||
+               !test_bit(BNAD_RF_STATS_TIMER_RUNNING, &bnad->run_flags))
+               return;
+
+       spin_lock_irqsave(&bnad->bna_lock, flags);
+       bna_stats_get(&bnad->bna);
+       spin_unlock_irqrestore(&bnad->bna_lock, flags);
+}
+
+/*
+ * Set up timer for DIM
+ * Called with bnad->bna_lock held
+ */
+void
+bnad_dim_timer_start(struct bnad *bnad)
+{
+       if (bnad->cfg_flags & BNAD_CF_DIM_ENABLED &&
+           !test_bit(BNAD_RF_DIM_TIMER_RUNNING, &bnad->run_flags)) {
+               setup_timer(&bnad->dim_timer, bnad_dim_timeout,
+                           (unsigned long)bnad);
+               set_bit(BNAD_RF_DIM_TIMER_RUNNING, &bnad->run_flags);
+               mod_timer(&bnad->dim_timer,
+                         jiffies + msecs_to_jiffies(BNAD_DIM_TIMER_FREQ));
+       }
+}
+
+/*
+ * Set up timer for statistics
+ * Called with mutex_lock(&bnad->conf_mutex) held
+ */
+static void
+bnad_stats_timer_start(struct bnad *bnad)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&bnad->bna_lock, flags);
+       if (!test_and_set_bit(BNAD_RF_STATS_TIMER_RUNNING, &bnad->run_flags)) {
+               setup_timer(&bnad->stats_timer, bnad_stats_timeout,
+                           (unsigned long)bnad);
+               mod_timer(&bnad->stats_timer,
+                         jiffies + msecs_to_jiffies(BNAD_STATS_TIMER_FREQ));
+       }
+       spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+}
+
+/*
+ * Stops the stats timer
+ * Called with mutex_lock(&bnad->conf_mutex) held
+ */
+static void
+bnad_stats_timer_stop(struct bnad *bnad)
+{
+       int to_del = 0;
+       unsigned long flags;
+
+       spin_lock_irqsave(&bnad->bna_lock, flags);
+       if (test_and_clear_bit(BNAD_RF_STATS_TIMER_RUNNING, &bnad->run_flags))
+               to_del = 1;
+       spin_unlock_irqrestore(&bnad->bna_lock, flags);
+       if (to_del)
+               del_timer_sync(&bnad->stats_timer);
+}
+
+/* Utilities */
+
+static void
+bnad_netdev_mc_list_get(struct net_device *netdev, u8 *mc_list)
+{
+       int i = 1; /* Index 0 has broadcast address */
+       struct netdev_hw_addr *mc_addr;
+
+       netdev_for_each_mc_addr(mc_addr, netdev) {
+               memcpy(&mc_list[i * ETH_ALEN], &mc_addr->addr[0],
+                                                       ETH_ALEN);
+               i++;
+       }
+}
+
+static int
+bnad_napi_poll_rx(struct napi_struct *napi, int budget)
+{
+       struct bnad_rx_ctrl *rx_ctrl =
+               container_of(napi, struct bnad_rx_ctrl, napi);
+       struct bna_ccb *ccb;
+       struct bnad *bnad;
+       int rcvd = 0;
+
+       ccb = rx_ctrl->ccb;
+
+       bnad = ccb->bnad;
+
+       if (!netif_carrier_ok(bnad->netdev))
+               goto poll_exit;
+
+       rcvd = bnad_poll_cq(bnad, ccb, budget);
+       if (rcvd == budget)
+               return rcvd;
+
+poll_exit:
+       napi_complete((napi));
+
+       BNAD_UPDATE_CTR(bnad, netif_rx_complete);
+
+       bnad_enable_rx_irq(bnad, ccb);
+       return rcvd;
+}
+
+static int
+bnad_napi_poll_txrx(struct napi_struct *napi, int budget)
+{
+       struct bnad_rx_ctrl *rx_ctrl =
+               container_of(napi, struct bnad_rx_ctrl, napi);
+       struct bna_ccb *ccb;
+       struct bnad *bnad;
+       int                     rcvd = 0;
+       int                     i, j;
+
+       ccb = rx_ctrl->ccb;
+
+       bnad = ccb->bnad;
+
+       if (!netif_carrier_ok(bnad->netdev))
+               goto poll_exit;
+
+       /* Handle Tx Completions, if any */
+       for (i = 0; i < bnad->num_tx; i++) {
+               for (j = 0; j < bnad->num_txq_per_tx; j++)
+                       bnad_tx(bnad, bnad->tx_info[i].tcb[j]);
+       }
+
+       /* Handle Rx Completions */
+       rcvd = bnad_poll_cq(bnad, ccb, budget);
+       if (rcvd == budget)
+               return rcvd;
+poll_exit:
+       napi_complete((napi));
+
+       BNAD_UPDATE_CTR(bnad, netif_rx_complete);
+
+       bnad_enable_txrx_irqs(bnad);
+       return rcvd;
+}
+
+static void
+bnad_napi_enable(struct bnad *bnad, u32 rx_id)
+{
+       int (*napi_poll) (struct napi_struct *, int);
+       struct bnad_rx_ctrl *rx_ctrl;
+       int i;
+       unsigned long flags;
+
+       spin_lock_irqsave(&bnad->bna_lock, flags);
+       if (bnad->cfg_flags & BNAD_CF_MSIX)
+               napi_poll = bnad_napi_poll_rx;
+       else
+               napi_poll = bnad_napi_poll_txrx;
+       spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+       /* Initialize & enable NAPI */
+       for (i = 0; i < bnad->num_rxp_per_rx; i++) {
+               rx_ctrl = &bnad->rx_info[rx_id].rx_ctrl[i];
+               netif_napi_add(bnad->netdev, &rx_ctrl->napi,
+                              napi_poll, 64);
+               napi_enable(&rx_ctrl->napi);
+       }
+}
+
+static void
+bnad_napi_disable(struct bnad *bnad, u32 rx_id)
+{
+       int i;
+
+       /* First disable and then clean up */
+       for (i = 0; i < bnad->num_rxp_per_rx; i++) {
+               napi_disable(&bnad->rx_info[rx_id].rx_ctrl[i].napi);
+               netif_napi_del(&bnad->rx_info[rx_id].rx_ctrl[i].napi);
+       }
+}
+
+/* Should be held with conf_lock held */
+void
+bnad_cleanup_tx(struct bnad *bnad, uint tx_id)
+{
+       struct bnad_tx_info *tx_info = &bnad->tx_info[tx_id];
+       struct bna_res_info *res_info = &bnad->tx_res_info[tx_id].res_info[0];
+       unsigned long flags;
+
+       if (!tx_info->tx)
+               return;
+
+       init_completion(&bnad->bnad_completions.tx_comp);
+       spin_lock_irqsave(&bnad->bna_lock, flags);
+       bna_tx_disable(tx_info->tx, BNA_HARD_CLEANUP, bnad_cb_tx_disabled);
+       spin_unlock_irqrestore(&bnad->bna_lock, flags);
+       wait_for_completion(&bnad->bnad_completions.tx_comp);
+
+       if (tx_info->tcb[0]->intr_type == BNA_INTR_T_MSIX)
+               bnad_tx_msix_unregister(bnad, tx_info,
+                       bnad->num_txq_per_tx);
+
+       spin_lock_irqsave(&bnad->bna_lock, flags);
+       bna_tx_destroy(tx_info->tx);
+       spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+       tx_info->tx = NULL;
+
+       if (0 == tx_id)
+               tasklet_kill(&bnad->tx_free_tasklet);
+
+       bnad_tx_res_free(bnad, res_info);
+}
+
+/* Should be held with conf_lock held */
+int
+bnad_setup_tx(struct bnad *bnad, uint tx_id)
+{
+       int err;
+       struct bnad_tx_info *tx_info = &bnad->tx_info[tx_id];
+       struct bna_res_info *res_info = &bnad->tx_res_info[tx_id].res_info[0];
+       struct bna_intr_info *intr_info =
+                       &res_info[BNA_TX_RES_INTR_T_TXCMPL].res_u.intr_info;
+       struct bna_tx_config *tx_config = &bnad->tx_config[tx_id];
+       struct bna_tx_event_cbfn tx_cbfn;
+       struct bna_tx *tx;
+       unsigned long flags;
+
+       /* Initialize the Tx object configuration */
+       tx_config->num_txq = bnad->num_txq_per_tx;
+       tx_config->txq_depth = bnad->txq_depth;
+       tx_config->tx_type = BNA_TX_T_REGULAR;
+
+       /* Initialize the tx event handlers */
+       tx_cbfn.tcb_setup_cbfn = bnad_cb_tcb_setup;
+       tx_cbfn.tcb_destroy_cbfn = bnad_cb_tcb_destroy;
+       tx_cbfn.tx_stall_cbfn = bnad_cb_tx_stall;
+       tx_cbfn.tx_resume_cbfn = bnad_cb_tx_resume;
+       tx_cbfn.tx_cleanup_cbfn = bnad_cb_tx_cleanup;
+
+       /* Get BNA's resource requirement for one tx object */
+       spin_lock_irqsave(&bnad->bna_lock, flags);
+       bna_tx_res_req(bnad->num_txq_per_tx,
+               bnad->txq_depth, res_info);
+       spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+       /* Fill Unmap Q memory requirements */
+       BNAD_FILL_UNMAPQ_MEM_REQ(
+                       &res_info[BNA_TX_RES_MEM_T_UNMAPQ],
+                       bnad->num_txq_per_tx,
+                       BNAD_TX_UNMAPQ_DEPTH);
+
+       /* Allocate resources */
+       err = bnad_tx_res_alloc(bnad, res_info, tx_id);
+       if (err)
+               return err;
+
+       /* Ask BNA to create one Tx object, supplying required resources */
+       spin_lock_irqsave(&bnad->bna_lock, flags);
+       tx = bna_tx_create(&bnad->bna, bnad, tx_config, &tx_cbfn, res_info,
+                       tx_info);
+       spin_unlock_irqrestore(&bnad->bna_lock, flags);
+       if (!tx)
+               goto err_return;
+       tx_info->tx = tx;
+
+       /* Register ISR for the Tx object */
+       if (intr_info->intr_type == BNA_INTR_T_MSIX) {
+               err = bnad_tx_msix_register(bnad, tx_info,
+                       tx_id, bnad->num_txq_per_tx);
+               if (err)
+                       goto err_return;
+       }
+
+       spin_lock_irqsave(&bnad->bna_lock, flags);
+       bna_tx_enable(tx);
+       spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+       return 0;
+
+err_return:
+       bnad_tx_res_free(bnad, res_info);
+       return err;
+}
+
+/* Setup the rx config for bna_rx_create */
+/* bnad decides the configuration */
+static void
+bnad_init_rx_config(struct bnad *bnad, struct bna_rx_config *rx_config)
+{
+       rx_config->rx_type = BNA_RX_T_REGULAR;
+       rx_config->num_paths = bnad->num_rxp_per_rx;
+
+       if (bnad->num_rxp_per_rx > 1) {
+               rx_config->rss_status = BNA_STATUS_T_ENABLED;
+               rx_config->rss_config.hash_type =
+                               (BFI_RSS_T_V4_TCP |
+                                BFI_RSS_T_V6_TCP |
+                                BFI_RSS_T_V4_IP  |
+                                BFI_RSS_T_V6_IP);
+               rx_config->rss_config.hash_mask =
+                               bnad->num_rxp_per_rx - 1;
+               get_random_bytes(rx_config->rss_config.toeplitz_hash_key,
+                       sizeof(rx_config->rss_config.toeplitz_hash_key));
+       } else {
+               rx_config->rss_status = BNA_STATUS_T_DISABLED;
+               memset(&rx_config->rss_config, 0,
+                      sizeof(rx_config->rss_config));
+       }
+       rx_config->rxp_type = BNA_RXP_SLR;
+       rx_config->q_depth = bnad->rxq_depth;
+
+       rx_config->small_buff_size = BFI_SMALL_RXBUF_SIZE;
+
+       rx_config->vlan_strip_status = BNA_STATUS_T_ENABLED;
+}
+
+/* Called with mutex_lock(&bnad->conf_mutex) held */
+void
+bnad_cleanup_rx(struct bnad *bnad, uint rx_id)
+{
+       struct bnad_rx_info *rx_info = &bnad->rx_info[rx_id];
+       struct bna_rx_config *rx_config = &bnad->rx_config[rx_id];
+       struct bna_res_info *res_info = &bnad->rx_res_info[rx_id].res_info[0];
+       unsigned long flags;
+       int dim_timer_del = 0;
+
+       if (!rx_info->rx)
+               return;
+
+       if (0 == rx_id) {
+               spin_lock_irqsave(&bnad->bna_lock, flags);
+               dim_timer_del = bnad_dim_timer_running(bnad);
+               if (dim_timer_del)
+                       clear_bit(BNAD_RF_DIM_TIMER_RUNNING, &bnad->run_flags);
+               spin_unlock_irqrestore(&bnad->bna_lock, flags);
+               if (dim_timer_del)
+                       del_timer_sync(&bnad->dim_timer);
+       }
+
+       bnad_napi_disable(bnad, rx_id);
+
+       init_completion(&bnad->bnad_completions.rx_comp);
+       spin_lock_irqsave(&bnad->bna_lock, flags);
+       bna_rx_disable(rx_info->rx, BNA_HARD_CLEANUP, bnad_cb_rx_disabled);
+       spin_unlock_irqrestore(&bnad->bna_lock, flags);
+       wait_for_completion(&bnad->bnad_completions.rx_comp);
+
+       if (rx_info->rx_ctrl[0].ccb->intr_type == BNA_INTR_T_MSIX)
+               bnad_rx_msix_unregister(bnad, rx_info, rx_config->num_paths);
+
+       spin_lock_irqsave(&bnad->bna_lock, flags);
+       bna_rx_destroy(rx_info->rx);
+       spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+       rx_info->rx = NULL;
+
+       bnad_rx_res_free(bnad, res_info);
+}
+
+/* Called with mutex_lock(&bnad->conf_mutex) held */
+int
+bnad_setup_rx(struct bnad *bnad, uint rx_id)
+{
+       int err;
+       struct bnad_rx_info *rx_info = &bnad->rx_info[rx_id];
+       struct bna_res_info *res_info = &bnad->rx_res_info[rx_id].res_info[0];
+       struct bna_intr_info *intr_info =
+                       &res_info[BNA_RX_RES_T_INTR].res_u.intr_info;
+       struct bna_rx_config *rx_config = &bnad->rx_config[rx_id];
+       struct bna_rx_event_cbfn rx_cbfn;
+       struct bna_rx *rx;
+       unsigned long flags;
+
+       /* Initialize the Rx object configuration */
+       bnad_init_rx_config(bnad, rx_config);
+
+       /* Initialize the Rx event handlers */
+       rx_cbfn.rcb_setup_cbfn = bnad_cb_rcb_setup;
+       rx_cbfn.rcb_destroy_cbfn = NULL;
+       rx_cbfn.ccb_setup_cbfn = bnad_cb_ccb_setup;
+       rx_cbfn.ccb_destroy_cbfn = bnad_cb_ccb_destroy;
+       rx_cbfn.rx_cleanup_cbfn = bnad_cb_rx_cleanup;
+       rx_cbfn.rx_post_cbfn = bnad_cb_rx_post;
+
+       /* Get BNA's resource requirement for one Rx object */
+       spin_lock_irqsave(&bnad->bna_lock, flags);
+       bna_rx_res_req(rx_config, res_info);
+       spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+       /* Fill Unmap Q memory requirements */
+       BNAD_FILL_UNMAPQ_MEM_REQ(
+                       &res_info[BNA_RX_RES_MEM_T_UNMAPQ],
+                       rx_config->num_paths +
+                       ((rx_config->rxp_type == BNA_RXP_SINGLE) ? 0 :
+                               rx_config->num_paths), BNAD_RX_UNMAPQ_DEPTH);
+
+       /* Allocate resource */
+       err = bnad_rx_res_alloc(bnad, res_info, rx_id);
+       if (err)
+               return err;
+
+       /* Ask BNA to create one Rx object, supplying required resources */
+       spin_lock_irqsave(&bnad->bna_lock, flags);
+       rx = bna_rx_create(&bnad->bna, bnad, rx_config, &rx_cbfn, res_info,
+                       rx_info);
+       spin_unlock_irqrestore(&bnad->bna_lock, flags);
+       if (!rx)
+               goto err_return;
+       rx_info->rx = rx;
+
+       /* Register ISR for the Rx object */
+       if (intr_info->intr_type == BNA_INTR_T_MSIX) {
+               err = bnad_rx_msix_register(bnad, rx_info, rx_id,
+                                               rx_config->num_paths);
+               if (err)
+                       goto err_return;
+       }
+
+       /* Enable NAPI */
+       bnad_napi_enable(bnad, rx_id);
+
+       spin_lock_irqsave(&bnad->bna_lock, flags);
+       if (0 == rx_id) {
+               /* Set up Dynamic Interrupt Moderation Vector */
+               if (bnad->cfg_flags & BNAD_CF_DIM_ENABLED)
+                       bna_rx_dim_reconfig(&bnad->bna, bna_napi_dim_vector);
+
+               /* Enable VLAN filtering only on the default Rx */
+               bna_rx_vlanfilter_enable(rx);
+
+               /* Start the DIM timer */
+               bnad_dim_timer_start(bnad);
+       }
+
+       bna_rx_enable(rx);
+       spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+       return 0;
+
+err_return:
+       bnad_cleanup_rx(bnad, rx_id);
+       return err;
+}
+
+/* Called with conf_lock & bnad->bna_lock held */
+void
+bnad_tx_coalescing_timeo_set(struct bnad *bnad)
+{
+       struct bnad_tx_info *tx_info;
+
+       tx_info = &bnad->tx_info[0];
+       if (!tx_info->tx)
+               return;
+
+       bna_tx_coalescing_timeo_set(tx_info->tx, bnad->tx_coalescing_timeo);
+}
+
+/* Called with conf_lock & bnad->bna_lock held */
+void
+bnad_rx_coalescing_timeo_set(struct bnad *bnad)
+{
+       struct bnad_rx_info *rx_info;
+       int     i;
+
+       for (i = 0; i < bnad->num_rx; i++) {
+               rx_info = &bnad->rx_info[i];
+               if (!rx_info->rx)
+                       continue;
+               bna_rx_coalescing_timeo_set(rx_info->rx,
+                               bnad->rx_coalescing_timeo);
+       }
+}
+
+/*
+ * Called with bnad->bna_lock held
+ */
+static int
+bnad_mac_addr_set_locked(struct bnad *bnad, u8 *mac_addr)
+{
+       int ret;
+
+       if (!is_valid_ether_addr(mac_addr))
+               return -EADDRNOTAVAIL;
+
+       /* If datapath is down, pretend everything went through */
+       if (!bnad->rx_info[0].rx)
+               return 0;
+
+       ret = bna_rx_ucast_set(bnad->rx_info[0].rx, mac_addr, NULL);
+       if (ret != BNA_CB_SUCCESS)
+               return -EADDRNOTAVAIL;
+
+       return 0;
+}
+
+/* Should be called with conf_lock held */
+static int
+bnad_enable_default_bcast(struct bnad *bnad)
+{
+       struct bnad_rx_info *rx_info = &bnad->rx_info[0];
+       int ret;
+       unsigned long flags;
+
+       init_completion(&bnad->bnad_completions.mcast_comp);
+
+       spin_lock_irqsave(&bnad->bna_lock, flags);
+       ret = bna_rx_mcast_add(rx_info->rx, (u8 *)bnad_bcast_addr,
+                               bnad_cb_rx_mcast_add);
+       spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+       if (ret == BNA_CB_SUCCESS)
+               wait_for_completion(&bnad->bnad_completions.mcast_comp);
+       else
+               return -ENODEV;
+
+       if (bnad->bnad_completions.mcast_comp_status != BNA_CB_SUCCESS)
+               return -ENODEV;
+
+       return 0;
+}
+
+/* Statistics utilities */
+void
+bnad_netdev_qstats_fill(struct bnad *bnad, struct rtnl_link_stats64 *stats)
+{
+       int i, j;
+
+       for (i = 0; i < bnad->num_rx; i++) {
+               for (j = 0; j < bnad->num_rxp_per_rx; j++) {
+                       if (bnad->rx_info[i].rx_ctrl[j].ccb) {
+                               stats->rx_packets += bnad->rx_info[i].
+                               rx_ctrl[j].ccb->rcb[0]->rxq->rx_packets;
+                               stats->rx_bytes += bnad->rx_info[i].
+                                       rx_ctrl[j].ccb->rcb[0]->rxq->rx_bytes;
+                               if (bnad->rx_info[i].rx_ctrl[j].ccb->rcb[1] &&
+                                       bnad->rx_info[i].rx_ctrl[j].ccb->
+                                       rcb[1]->rxq) {
+                                       stats->rx_packets +=
+                                               bnad->rx_info[i].rx_ctrl[j].
+                                               ccb->rcb[1]->rxq->rx_packets;
+                                       stats->rx_bytes +=
+                                               bnad->rx_info[i].rx_ctrl[j].
+                                               ccb->rcb[1]->rxq->rx_bytes;
+                               }
+                       }
+               }
+       }
+       for (i = 0; i < bnad->num_tx; i++) {
+               for (j = 0; j < bnad->num_txq_per_tx; j++) {
+                       if (bnad->tx_info[i].tcb[j]) {
+                               stats->tx_packets +=
+                               bnad->tx_info[i].tcb[j]->txq->tx_packets;
+                               stats->tx_bytes +=
+                                       bnad->tx_info[i].tcb[j]->txq->tx_bytes;
+                       }
+               }
+       }
+}
+
+/*
+ * Must be called with the bna_lock held.
+ */
+void
+bnad_netdev_hwstats_fill(struct bnad *bnad, struct rtnl_link_stats64 *stats)
+{
+       struct bfi_ll_stats_mac *mac_stats;
+       u64 bmap;
+       int i;
+
+       mac_stats = &bnad->stats.bna_stats->hw_stats->mac_stats;
+       stats->rx_errors =
+               mac_stats->rx_fcs_error + mac_stats->rx_alignment_error +
+               mac_stats->rx_frame_length_error + mac_stats->rx_code_error +
+               mac_stats->rx_undersize;
+       stats->tx_errors = mac_stats->tx_fcs_error +
+                                       mac_stats->tx_undersize;
+       stats->rx_dropped = mac_stats->rx_drop;
+       stats->tx_dropped = mac_stats->tx_drop;
+       stats->multicast = mac_stats->rx_multicast;
+       stats->collisions = mac_stats->tx_total_collision;
+
+       stats->rx_length_errors = mac_stats->rx_frame_length_error;
+
+       /* receive ring buffer overflow  ?? */
+
+       stats->rx_crc_errors = mac_stats->rx_fcs_error;
+       stats->rx_frame_errors = mac_stats->rx_alignment_error;
+       /* recv'r fifo overrun */
+       bmap = (u64)bnad->stats.bna_stats->rxf_bmap[0] |
+               ((u64)bnad->stats.bna_stats->rxf_bmap[1] << 32);
+       for (i = 0; bmap && (i < BFI_LL_RXF_ID_MAX); i++) {
+               if (bmap & 1) {
+                       stats->rx_fifo_errors +=
+                               bnad->stats.bna_stats->
+                                       hw_stats->rxf_stats[i].frame_drops;
+                       break;
+               }
+               bmap >>= 1;
+       }
+}
+
+static void
+bnad_mbox_irq_sync(struct bnad *bnad)
+{
+       u32 irq;
+       unsigned long flags;
+
+       spin_lock_irqsave(&bnad->bna_lock, flags);
+       if (bnad->cfg_flags & BNAD_CF_MSIX)
+               irq = bnad->msix_table[bnad->msix_num - 1].vector;
+       else
+               irq = bnad->pcidev->irq;
+       spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+       synchronize_irq(irq);
+}
+
+/* Utility used by bnad_start_xmit, for doing TSO */
+static int
+bnad_tso_prepare(struct bnad *bnad, struct sk_buff *skb)
+{
+       int err;
+
+       /* SKB_GSO_TCPV4 and SKB_GSO_TCPV6 is defined since 2.6.18. */
+       BUG_ON(!(skb_shinfo(skb)->gso_type == SKB_GSO_TCPV4 ||
+                  skb_shinfo(skb)->gso_type == SKB_GSO_TCPV6));
+       if (skb_header_cloned(skb)) {
+               err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
+               if (err) {
+                       BNAD_UPDATE_CTR(bnad, tso_err);
+                       return err;
+               }
+       }
+
+       /*
+        * For TSO, the TCP checksum field is seeded with pseudo-header sum
+        * excluding the length field.
+        */
+       if (skb->protocol == htons(ETH_P_IP)) {
+               struct iphdr *iph = ip_hdr(skb);
+
+               /* Do we really need these? */
+               iph->tot_len = 0;
+               iph->check = 0;
+
+               tcp_hdr(skb)->check =
+                       ~csum_tcpudp_magic(iph->saddr, iph->daddr, 0,
+                                          IPPROTO_TCP, 0);
+               BNAD_UPDATE_CTR(bnad, tso4);
+       } else {
+               struct ipv6hdr *ipv6h = ipv6_hdr(skb);
+
+               BUG_ON(!(skb->protocol == htons(ETH_P_IPV6)));
+               ipv6h->payload_len = 0;
+               tcp_hdr(skb)->check =
+                       ~csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr, 0,
+                                        IPPROTO_TCP, 0);
+               BNAD_UPDATE_CTR(bnad, tso6);
+       }
+
+       return 0;
+}
+
+/*
+ * Initialize Q numbers depending on Rx Paths
+ * Called with bnad->bna_lock held, because of cfg_flags
+ * access.
+ */
+static void
+bnad_q_num_init(struct bnad *bnad)
+{
+       int rxps;
+
+       rxps = min((uint)num_online_cpus(),
+                       (uint)(BNAD_MAX_RXS * BNAD_MAX_RXPS_PER_RX));
+
+       if (!(bnad->cfg_flags & BNAD_CF_MSIX))
+               rxps = 1;       /* INTx */
+
+       bnad->num_rx = 1;
+       bnad->num_tx = 1;
+       bnad->num_rxp_per_rx = rxps;
+       bnad->num_txq_per_tx = BNAD_TXQ_NUM;
+}
+
+/*
+ * Adjusts the Q numbers, given a number of msix vectors
+ * Give preference to RSS as opposed to Tx priority Queues,
+ * in such a case, just use 1 Tx Q
+ * Called with bnad->bna_lock held b'cos of cfg_flags access
+ */
+static void
+bnad_q_num_adjust(struct bnad *bnad, int msix_vectors)
+{
+       bnad->num_txq_per_tx = 1;
+       if ((msix_vectors >= (bnad->num_tx * bnad->num_txq_per_tx)  +
+            bnad_rxqs_per_cq + BNAD_MAILBOX_MSIX_VECTORS) &&
+           (bnad->cfg_flags & BNAD_CF_MSIX)) {
+               bnad->num_rxp_per_rx = msix_vectors -
+                       (bnad->num_tx * bnad->num_txq_per_tx) -
+                       BNAD_MAILBOX_MSIX_VECTORS;
+       } else
+               bnad->num_rxp_per_rx = 1;
+}
+
+static void
+bnad_set_netdev_perm_addr(struct bnad *bnad)
+{
+       struct net_device *netdev = bnad->netdev;
+
+       memcpy(netdev->perm_addr, &bnad->perm_addr, netdev->addr_len);
+       if (is_zero_ether_addr(netdev->dev_addr))
+               memcpy(netdev->dev_addr, &bnad->perm_addr, netdev->addr_len);
+}
+
+/* Enable / disable device */
+static void
+bnad_device_disable(struct bnad *bnad)
+{
+       unsigned long flags;
+
+       init_completion(&bnad->bnad_completions.ioc_comp);
+
+       spin_lock_irqsave(&bnad->bna_lock, flags);
+       bna_device_disable(&bnad->bna.device, BNA_HARD_CLEANUP);
+       spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+       wait_for_completion(&bnad->bnad_completions.ioc_comp);
+
+}
+
+static int
+bnad_device_enable(struct bnad *bnad)
+{
+       int err = 0;
+       unsigned long flags;
+
+       init_completion(&bnad->bnad_completions.ioc_comp);
+
+       spin_lock_irqsave(&bnad->bna_lock, flags);
+       bna_device_enable(&bnad->bna.device);
+       spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+       wait_for_completion(&bnad->bnad_completions.ioc_comp);
+
+       if (bnad->bnad_completions.ioc_comp_status)
+               err = bnad->bnad_completions.ioc_comp_status;
+
+       return err;
+}
+
+/* Free BNA resources */
+static void
+bnad_res_free(struct bnad *bnad)
+{
+       int i;
+       struct bna_res_info *res_info = &bnad->res_info[0];
+
+       for (i = 0; i < BNA_RES_T_MAX; i++) {
+               if (res_info[i].res_type == BNA_RES_T_MEM)
+                       bnad_mem_free(bnad, &res_info[i].res_u.mem_info);
+               else
+                       bnad_mbox_irq_free(bnad, &res_info[i].res_u.intr_info);
+       }
+}
+
+/* Allocates memory and interrupt resources for BNA */
+static int
+bnad_res_alloc(struct bnad *bnad)
+{
+       int i, err;
+       struct bna_res_info *res_info = &bnad->res_info[0];
+
+       for (i = 0; i < BNA_RES_T_MAX; i++) {
+               if (res_info[i].res_type == BNA_RES_T_MEM)
+                       err = bnad_mem_alloc(bnad, &res_info[i].res_u.mem_info);
+               else
+                       err = bnad_mbox_irq_alloc(bnad,
+                                                 &res_info[i].res_u.intr_info);
+               if (err)
+                       goto err_return;
+       }
+       return 0;
+
+err_return:
+       bnad_res_free(bnad);
+       return err;
+}
+
+/* Interrupt enable / disable */
+static void
+bnad_enable_msix(struct bnad *bnad)
+{
+       int i, ret;
+       u32 tot_msix_num;
+       unsigned long flags;
+
+       spin_lock_irqsave(&bnad->bna_lock, flags);
+       if (!(bnad->cfg_flags & BNAD_CF_MSIX)) {
+               spin_unlock_irqrestore(&bnad->bna_lock, flags);
+               return;
+       }
+       spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+       if (bnad->msix_table)
+               return;
+
+       tot_msix_num = bnad->msix_num + bnad->msix_diag_num;
+
+       bnad->msix_table =
+               kcalloc(tot_msix_num, sizeof(struct msix_entry), GFP_KERNEL);
+
+       if (!bnad->msix_table)
+               goto intx_mode;
+
+       for (i = 0; i < tot_msix_num; i++)
+               bnad->msix_table[i].entry = i;
+
+       ret = pci_enable_msix(bnad->pcidev, bnad->msix_table, tot_msix_num);
+       if (ret > 0) {
+               /* Not enough MSI-X vectors. */
+
+               spin_lock_irqsave(&bnad->bna_lock, flags);
+               /* ret = #of vectors that we got */
+               bnad_q_num_adjust(bnad, ret);
+               spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+               bnad->msix_num = (bnad->num_tx * bnad->num_txq_per_tx)
+                       + (bnad->num_rx
+                       * bnad->num_rxp_per_rx) +
+                        BNAD_MAILBOX_MSIX_VECTORS;
+               tot_msix_num = bnad->msix_num + bnad->msix_diag_num;
+
+               /* Try once more with adjusted numbers */
+               /* If this fails, fall back to INTx */
+               ret = pci_enable_msix(bnad->pcidev, bnad->msix_table,
+                                     tot_msix_num);
+               if (ret)
+                       goto intx_mode;
+
+       } else if (ret < 0)
+               goto intx_mode;
+       return;
+
+intx_mode:
+
+       kfree(bnad->msix_table);
+       bnad->msix_table = NULL;
+       bnad->msix_num = 0;
+       bnad->msix_diag_num = 0;
+       spin_lock_irqsave(&bnad->bna_lock, flags);
+       bnad->cfg_flags &= ~BNAD_CF_MSIX;
+       bnad_q_num_init(bnad);
+       spin_unlock_irqrestore(&bnad->bna_lock, flags);
+}
+
+static void
+bnad_disable_msix(struct bnad *bnad)
+{
+       u32 cfg_flags;
+       unsigned long flags;
+
+       spin_lock_irqsave(&bnad->bna_lock, flags);
+       cfg_flags = bnad->cfg_flags;
+       if (bnad->cfg_flags & BNAD_CF_MSIX)
+               bnad->cfg_flags &= ~BNAD_CF_MSIX;
+       spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+       if (cfg_flags & BNAD_CF_MSIX) {
+               pci_disable_msix(bnad->pcidev);
+               kfree(bnad->msix_table);
+               bnad->msix_table = NULL;
+       }
+}
+
+/* Netdev entry points */
+static int
+bnad_open(struct net_device *netdev)
+{
+       int err;
+       struct bnad *bnad = netdev_priv(netdev);
+       struct bna_pause_config pause_config;
+       int mtu;
+       unsigned long flags;
+
+       mutex_lock(&bnad->conf_mutex);
+
+       /* Tx */
+       err = bnad_setup_tx(bnad, 0);
+       if (err)
+               goto err_return;
+
+       /* Rx */
+       err = bnad_setup_rx(bnad, 0);
+       if (err)
+               goto cleanup_tx;
+
+       /* Port */
+       pause_config.tx_pause = 0;
+       pause_config.rx_pause = 0;
+
+       mtu = ETH_HLEN + bnad->netdev->mtu + ETH_FCS_LEN;
+
+       spin_lock_irqsave(&bnad->bna_lock, flags);
+       bna_port_mtu_set(&bnad->bna.port, mtu, NULL);
+       bna_port_pause_config(&bnad->bna.port, &pause_config, NULL);
+       bna_port_enable(&bnad->bna.port);
+       spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+       /* Enable broadcast */
+       bnad_enable_default_bcast(bnad);
+
+       /* Set the UCAST address */
+       spin_lock_irqsave(&bnad->bna_lock, flags);
+       bnad_mac_addr_set_locked(bnad, netdev->dev_addr);
+       spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+       /* Start the stats timer */
+       bnad_stats_timer_start(bnad);
+
+       mutex_unlock(&bnad->conf_mutex);
+
+       return 0;
+
+cleanup_tx:
+       bnad_cleanup_tx(bnad, 0);
+
+err_return:
+       mutex_unlock(&bnad->conf_mutex);
+       return err;
+}
+
+static int
+bnad_stop(struct net_device *netdev)
+{
+       struct bnad *bnad = netdev_priv(netdev);
+       unsigned long flags;
+
+       mutex_lock(&bnad->conf_mutex);
+
+       /* Stop the stats timer */
+       bnad_stats_timer_stop(bnad);
+
+       init_completion(&bnad->bnad_completions.port_comp);
+
+       spin_lock_irqsave(&bnad->bna_lock, flags);
+       bna_port_disable(&bnad->bna.port, BNA_HARD_CLEANUP,
+                       bnad_cb_port_disabled);
+       spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+       wait_for_completion(&bnad->bnad_completions.port_comp);
+
+       bnad_cleanup_tx(bnad, 0);
+       bnad_cleanup_rx(bnad, 0);
+
+       /* Synchronize mailbox IRQ */
+       bnad_mbox_irq_sync(bnad);
+
+       mutex_unlock(&bnad->conf_mutex);
+
+       return 0;
+}
+
+/* TX */
+/*
+ * bnad_start_xmit : Netdev entry point for Transmit
+ *                  Called under lock held by net_device
+ */
+static netdev_tx_t
+bnad_start_xmit(struct sk_buff *skb, struct net_device *netdev)
+{
+       struct bnad *bnad = netdev_priv(netdev);
+
+       u16             txq_prod, vlan_tag = 0;
+       u32             unmap_prod, wis, wis_used, wi_range;
+       u32             vectors, vect_id, i, acked;
+       u32             tx_id;
+       int                     err;
+
+       struct bnad_tx_info *tx_info;
+       struct bna_tcb *tcb;
+       struct bnad_unmap_q *unmap_q;
+       dma_addr_t              dma_addr;
+       struct bna_txq_entry *txqent;
+       bna_txq_wi_ctrl_flag_t  flags;
+
+       if (unlikely
+           (skb->len <= ETH_HLEN || skb->len > BFI_TX_MAX_DATA_PER_PKT)) {
+               dev_kfree_skb(skb);
+               return NETDEV_TX_OK;
+       }
+
+       /*
+        * Takes care of the Tx that is scheduled between clearing the flag
+        * and the netif_stop_queue() call.
+        */
+       if (unlikely(!test_bit(BNAD_RF_TX_STARTED, &bnad->run_flags))) {
+               dev_kfree_skb(skb);
+               return NETDEV_TX_OK;
+       }
+
+       tx_id = 0;
+
+       tx_info = &bnad->tx_info[tx_id];
+       tcb = tx_info->tcb[tx_id];
+       unmap_q = tcb->unmap_q;
+
+       vectors = 1 + skb_shinfo(skb)->nr_frags;
+       if (vectors > BFI_TX_MAX_VECTORS_PER_PKT) {
+               dev_kfree_skb(skb);
+               return NETDEV_TX_OK;
+       }
+       wis = BNA_TXQ_WI_NEEDED(vectors);       /* 4 vectors per work item */
+       acked = 0;
+       if (unlikely
+           (wis > BNA_QE_FREE_CNT(tcb, tcb->q_depth) ||
+            vectors > BNA_QE_FREE_CNT(unmap_q, unmap_q->q_depth))) {
+               if ((u16) (*tcb->hw_consumer_index) !=
+                   tcb->consumer_index &&
+                   !test_and_set_bit(BNAD_TXQ_FREE_SENT, &tcb->flags)) {
+                       acked = bnad_free_txbufs(bnad, tcb);
+                       bna_ib_ack(tcb->i_dbell, acked);
+                       smp_mb__before_clear_bit();
+                       clear_bit(BNAD_TXQ_FREE_SENT, &tcb->flags);
+               } else {
+                       netif_stop_queue(netdev);
+                       BNAD_UPDATE_CTR(bnad, netif_queue_stop);
+               }
+
+               smp_mb();
+               /*
+                * Check again to deal with race condition between
+                * netif_stop_queue here, and netif_wake_queue in
+                * interrupt handler which is not inside netif tx lock.
+                */
+               if (likely
+                   (wis > BNA_QE_FREE_CNT(tcb, tcb->q_depth) ||
+                    vectors > BNA_QE_FREE_CNT(unmap_q, unmap_q->q_depth))) {
+                       BNAD_UPDATE_CTR(bnad, netif_queue_stop);
+                       return NETDEV_TX_BUSY;
+               } else {
+                       netif_wake_queue(netdev);
+                       BNAD_UPDATE_CTR(bnad, netif_queue_wakeup);
+               }
+       }
+
+       unmap_prod = unmap_q->producer_index;
+       wis_used = 1;
+       vect_id = 0;
+       flags = 0;
+
+       txq_prod = tcb->producer_index;
+       BNA_TXQ_QPGE_PTR_GET(txq_prod, tcb->sw_qpt, txqent, wi_range);
+       BUG_ON(!(wi_range <= tcb->q_depth));
+       txqent->hdr.wi.reserved = 0;
+       txqent->hdr.wi.num_vectors = vectors;
+       txqent->hdr.wi.opcode =
+               htons((skb_is_gso(skb) ? BNA_TXQ_WI_SEND_LSO :
+                      BNA_TXQ_WI_SEND));
+
+       if (bnad->vlan_grp && vlan_tx_tag_present(skb)) {
+               vlan_tag = (u16) vlan_tx_tag_get(skb);
+               flags |= (BNA_TXQ_WI_CF_INS_PRIO | BNA_TXQ_WI_CF_INS_VLAN);
+       }
+       if (test_bit(BNAD_RF_CEE_RUNNING, &bnad->run_flags)) {
+               vlan_tag =
+                       (tcb->priority & 0x7) << 13 | (vlan_tag & 0x1fff);
+               flags |= (BNA_TXQ_WI_CF_INS_PRIO | BNA_TXQ_WI_CF_INS_VLAN);
+       }
+
+       txqent->hdr.wi.vlan_tag = htons(vlan_tag);
+
+       if (skb_is_gso(skb)) {
+               err = bnad_tso_prepare(bnad, skb);
+               if (err) {
+                       dev_kfree_skb(skb);
+                       return NETDEV_TX_OK;
+               }
+               txqent->hdr.wi.lso_mss = htons(skb_is_gso(skb));
+               flags |= (BNA_TXQ_WI_CF_IP_CKSUM | BNA_TXQ_WI_CF_TCP_CKSUM);
+               txqent->hdr.wi.l4_hdr_size_n_offset =
+                       htons(BNA_TXQ_WI_L4_HDR_N_OFFSET
+                             (tcp_hdrlen(skb) >> 2,
+                              skb_transport_offset(skb)));
+       } else if (skb->ip_summed == CHECKSUM_PARTIAL) {
+               u8 proto = 0;
+
+               txqent->hdr.wi.lso_mss = 0;
+
+               if (skb->protocol == htons(ETH_P_IP))
+                       proto = ip_hdr(skb)->protocol;
+               else if (skb->protocol == htons(ETH_P_IPV6)) {
+                       /* nexthdr may not be TCP immediately. */
+                       proto = ipv6_hdr(skb)->nexthdr;
+               }
+               if (proto == IPPROTO_TCP) {
+                       flags |= BNA_TXQ_WI_CF_TCP_CKSUM;
+                       txqent->hdr.wi.l4_hdr_size_n_offset =
+                               htons(BNA_TXQ_WI_L4_HDR_N_OFFSET
+                                     (0, skb_transport_offset(skb)));
+
+                       BNAD_UPDATE_CTR(bnad, tcpcsum_offload);
+
+                       BUG_ON(!(skb_headlen(skb) >=
+                               skb_transport_offset(skb) + tcp_hdrlen(skb)));
+
+               } else if (proto == IPPROTO_UDP) {
+                       flags |= BNA_TXQ_WI_CF_UDP_CKSUM;
+                       txqent->hdr.wi.l4_hdr_size_n_offset =
+                               htons(BNA_TXQ_WI_L4_HDR_N_OFFSET
+                                     (0, skb_transport_offset(skb)));
+
+                       BNAD_UPDATE_CTR(bnad, udpcsum_offload);
+
+                       BUG_ON(!(skb_headlen(skb) >=
+                                  skb_transport_offset(skb) +
+                                  sizeof(struct udphdr)));
+               } else {
+                       err = skb_checksum_help(skb);
+                       BNAD_UPDATE_CTR(bnad, csum_help);
+                       if (err) {
+                               dev_kfree_skb(skb);
+                               BNAD_UPDATE_CTR(bnad, csum_help_err);
+                               return NETDEV_TX_OK;
+                       }
+               }
+       } else {
+               txqent->hdr.wi.lso_mss = 0;
+               txqent->hdr.wi.l4_hdr_size_n_offset = 0;
+       }
+
+       txqent->hdr.wi.flags = htons(flags);
+
+       txqent->hdr.wi.frame_length = htonl(skb->len);
+
+       unmap_q->unmap_array[unmap_prod].skb = skb;
+       BUG_ON(!(skb_headlen(skb) <= BFI_TX_MAX_DATA_PER_VECTOR));
+       txqent->vector[vect_id].length = htons(skb_headlen(skb));
+       dma_addr = pci_map_single(bnad->pcidev, skb->data, skb_headlen(skb),
+               PCI_DMA_TODEVICE);
+       pci_unmap_addr_set(&unmap_q->unmap_array[unmap_prod], dma_addr,
+                          dma_addr);
+
+       BNA_SET_DMA_ADDR(dma_addr, &txqent->vector[vect_id].host_addr);
+       BNA_QE_INDX_ADD(unmap_prod, 1, unmap_q->q_depth);
+
+       for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+               struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i];
+               u32             size = frag->size;
+
+               if (++vect_id == BFI_TX_MAX_VECTORS_PER_WI) {
+                       vect_id = 0;
+                       if (--wi_range)
+                               txqent++;
+                       else {
+                               BNA_QE_INDX_ADD(txq_prod, wis_used,
+                                               tcb->q_depth);
+                               wis_used = 0;
+                               BNA_TXQ_QPGE_PTR_GET(txq_prod, tcb->sw_qpt,
+                                                    txqent, wi_range);
+                               BUG_ON(!(wi_range <= tcb->q_depth));
+                       }
+                       wis_used++;
+                       txqent->hdr.wi_ext.opcode = htons(BNA_TXQ_WI_EXTENSION);
+               }
+
+               BUG_ON(!(size <= BFI_TX_MAX_DATA_PER_VECTOR));
+               txqent->vector[vect_id].length = htons(size);
+               dma_addr =
+                       pci_map_page(bnad->pcidev, frag->page,
+                                    frag->page_offset, size,
+                                    PCI_DMA_TODEVICE);
+               pci_unmap_addr_set(&unmap_q->unmap_array[unmap_prod], dma_addr,
+                                  dma_addr);
+               BNA_SET_DMA_ADDR(dma_addr, &txqent->vector[vect_id].host_addr);
+               BNA_QE_INDX_ADD(unmap_prod, 1, unmap_q->q_depth);
+       }
+
+       unmap_q->producer_index = unmap_prod;
+       BNA_QE_INDX_ADD(txq_prod, wis_used, tcb->q_depth);
+       tcb->producer_index = txq_prod;
+
+       smp_mb();
+       bna_txq_prod_indx_doorbell(tcb);
+
+       if ((u16) (*tcb->hw_consumer_index) != tcb->consumer_index)
+               tasklet_schedule(&bnad->tx_free_tasklet);
+
+       return NETDEV_TX_OK;
+}
+
+/*
+ * Used spin_lock to synchronize reading of stats structures, which
+ * is written by BNA under the same lock.
+ */
+static struct rtnl_link_stats64 *
+bnad_get_stats64(struct net_device *netdev, struct rtnl_link_stats64 *stats)
+{
+       struct bnad *bnad = netdev_priv(netdev);
+       unsigned long flags;
+
+       spin_lock_irqsave(&bnad->bna_lock, flags);
+
+       bnad_netdev_qstats_fill(bnad, stats);
+       bnad_netdev_hwstats_fill(bnad, stats);
+
+       spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+       return stats;
+}
+
+static void
+bnad_set_rx_mode(struct net_device *netdev)
+{
+       struct bnad *bnad = netdev_priv(netdev);
+       u32     new_mask, valid_mask;
+       unsigned long flags;
+
+       spin_lock_irqsave(&bnad->bna_lock, flags);
+
+       new_mask = valid_mask = 0;
+
+       if (netdev->flags & IFF_PROMISC) {
+               if (!(bnad->cfg_flags & BNAD_CF_PROMISC)) {
+                       new_mask = BNAD_RXMODE_PROMISC_DEFAULT;
+                       valid_mask = BNAD_RXMODE_PROMISC_DEFAULT;
+                       bnad->cfg_flags |= BNAD_CF_PROMISC;
+               }
+       } else {
+               if (bnad->cfg_flags & BNAD_CF_PROMISC) {
+                       new_mask = ~BNAD_RXMODE_PROMISC_DEFAULT;
+                       valid_mask = BNAD_RXMODE_PROMISC_DEFAULT;
+                       bnad->cfg_flags &= ~BNAD_CF_PROMISC;
+               }
+       }
+
+       if (netdev->flags & IFF_ALLMULTI) {
+               if (!(bnad->cfg_flags & BNAD_CF_ALLMULTI)) {
+                       new_mask |= BNA_RXMODE_ALLMULTI;
+                       valid_mask |= BNA_RXMODE_ALLMULTI;
+                       bnad->cfg_flags |= BNAD_CF_ALLMULTI;
+               }
+       } else {
+               if (bnad->cfg_flags & BNAD_CF_ALLMULTI) {
+                       new_mask &= ~BNA_RXMODE_ALLMULTI;
+                       valid_mask |= BNA_RXMODE_ALLMULTI;
+                       bnad->cfg_flags &= ~BNAD_CF_ALLMULTI;
+               }
+       }
+
+       bna_rx_mode_set(bnad->rx_info[0].rx, new_mask, valid_mask, NULL);
+
+       if (!netdev_mc_empty(netdev)) {
+               u8 *mcaddr_list;
+               int mc_count = netdev_mc_count(netdev);
+
+               /* Index 0 holds the broadcast address */
+               mcaddr_list =
+                       kzalloc((mc_count + 1) * ETH_ALEN,
+                               GFP_ATOMIC);
+               if (!mcaddr_list)
+                       goto unlock;
+
+               memcpy(&mcaddr_list[0], &bnad_bcast_addr[0], ETH_ALEN);
+
+               /* Copy rest of the MC addresses */
+               bnad_netdev_mc_list_get(netdev, mcaddr_list);
+
+               bna_rx_mcast_listset(bnad->rx_info[0].rx, mc_count + 1,
+                                       mcaddr_list, NULL);
+
+               /* Should we enable BNAD_CF_ALLMULTI for err != 0 ? */
+               kfree(mcaddr_list);
+       }
+unlock:
+       spin_unlock_irqrestore(&bnad->bna_lock, flags);
+}
+
+/*
+ * bna_lock is used to sync writes to netdev->addr
+ * conf_lock cannot be used since this call may be made
+ * in a non-blocking context.
+ */
+static int
+bnad_set_mac_address(struct net_device *netdev, void *mac_addr)
+{
+       int err;
+       struct bnad *bnad = netdev_priv(netdev);
+       struct sockaddr *sa = (struct sockaddr *)mac_addr;
+       unsigned long flags;
+
+       spin_lock_irqsave(&bnad->bna_lock, flags);
+
+       err = bnad_mac_addr_set_locked(bnad, sa->sa_data);
+
+       if (!err)
+               memcpy(netdev->dev_addr, sa->sa_data, netdev->addr_len);
+
+       spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+       return err;
+}
+
+static int
+bnad_change_mtu(struct net_device *netdev, int new_mtu)
+{
+       int mtu, err = 0;
+       unsigned long flags;
+
+       struct bnad *bnad = netdev_priv(netdev);
+
+       if (new_mtu + ETH_HLEN < ETH_ZLEN || new_mtu > BNAD_JUMBO_MTU)
+               return -EINVAL;
+
+       mutex_lock(&bnad->conf_mutex);
+
+       netdev->mtu = new_mtu;
+
+       mtu = ETH_HLEN + new_mtu + ETH_FCS_LEN;
+
+       spin_lock_irqsave(&bnad->bna_lock, flags);
+       bna_port_mtu_set(&bnad->bna.port, mtu, NULL);
+       spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+       mutex_unlock(&bnad->conf_mutex);
+       return err;
+}
+
+static void
+bnad_vlan_rx_register(struct net_device *netdev,
+                                 struct vlan_group *vlan_grp)
+{
+       struct bnad *bnad = netdev_priv(netdev);
+
+       mutex_lock(&bnad->conf_mutex);
+       bnad->vlan_grp = vlan_grp;
+       mutex_unlock(&bnad->conf_mutex);
+}
+
+static void
+bnad_vlan_rx_add_vid(struct net_device *netdev,
+                                unsigned short vid)
+{
+       struct bnad *bnad = netdev_priv(netdev);
+       unsigned long flags;
+
+       if (!bnad->rx_info[0].rx)
+               return;
+
+       mutex_lock(&bnad->conf_mutex);
+
+       spin_lock_irqsave(&bnad->bna_lock, flags);
+       bna_rx_vlan_add(bnad->rx_info[0].rx, vid);
+       spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+       mutex_unlock(&bnad->conf_mutex);
+}
+
+static void
+bnad_vlan_rx_kill_vid(struct net_device *netdev,
+                                 unsigned short vid)
+{
+       struct bnad *bnad = netdev_priv(netdev);
+       unsigned long flags;
+
+       if (!bnad->rx_info[0].rx)
+               return;
+
+       mutex_lock(&bnad->conf_mutex);
+
+       spin_lock_irqsave(&bnad->bna_lock, flags);
+       bna_rx_vlan_del(bnad->rx_info[0].rx, vid);
+       spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+       mutex_unlock(&bnad->conf_mutex);
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void
+bnad_netpoll(struct net_device *netdev)
+{
+       struct bnad *bnad = netdev_priv(netdev);
+       struct bnad_rx_info *rx_info;
+       struct bnad_rx_ctrl *rx_ctrl;
+       u32 curr_mask;
+       int i, j;
+
+       if (!(bnad->cfg_flags & BNAD_CF_MSIX)) {
+               bna_intx_disable(&bnad->bna, curr_mask);
+               bnad_isr(bnad->pcidev->irq, netdev);
+               bna_intx_enable(&bnad->bna, curr_mask);
+       } else {
+               for (i = 0; i < bnad->num_rx; i++) {
+                       rx_info = &bnad->rx_info[i];
+                       if (!rx_info->rx)
+                               continue;
+                       for (j = 0; j < bnad->num_rxp_per_rx; j++) {
+                               rx_ctrl = &rx_info->rx_ctrl[j];
+                               if (rx_ctrl->ccb) {
+                                       bnad_disable_rx_irq(bnad,
+                                                           rx_ctrl->ccb);
+                                       bnad_netif_rx_schedule_poll(bnad,
+                                                           rx_ctrl->ccb);
+                               }
+                       }
+               }
+       }
+}
+#endif
+
+static const struct net_device_ops bnad_netdev_ops = {
+       .ndo_open               = bnad_open,
+       .ndo_stop               = bnad_stop,
+       .ndo_start_xmit         = bnad_start_xmit,
+       .ndo_get_stats64                = bnad_get_stats64,
+       .ndo_set_rx_mode        = bnad_set_rx_mode,
+       .ndo_set_multicast_list = bnad_set_rx_mode,
+       .ndo_validate_addr      = eth_validate_addr,
+       .ndo_set_mac_address    = bnad_set_mac_address,
+       .ndo_change_mtu         = bnad_change_mtu,
+       .ndo_vlan_rx_register   = bnad_vlan_rx_register,
+       .ndo_vlan_rx_add_vid    = bnad_vlan_rx_add_vid,
+       .ndo_vlan_rx_kill_vid   = bnad_vlan_rx_kill_vid,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       .ndo_poll_controller    = bnad_netpoll
+#endif
+};
+
+static void
+bnad_netdev_init(struct bnad *bnad, bool using_dac)
+{
+       struct net_device *netdev = bnad->netdev;
+
+       netdev->features |= NETIF_F_IPV6_CSUM;
+       netdev->features |= NETIF_F_TSO;
+       netdev->features |= NETIF_F_TSO6;
+
+       netdev->features |= NETIF_F_GRO;
+       pr_warn("bna: GRO enabled, using kernel stack GRO\n");
+
+       netdev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
+
+       if (using_dac)
+               netdev->features |= NETIF_F_HIGHDMA;
+
+       netdev->features |=
+               NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX |
+               NETIF_F_HW_VLAN_FILTER;
+
+       netdev->vlan_features = netdev->features;
+       netdev->mem_start = bnad->mmio_start;
+       netdev->mem_end = bnad->mmio_start + bnad->mmio_len - 1;
+
+       netdev->netdev_ops = &bnad_netdev_ops;
+       bnad_set_ethtool_ops(netdev);
+}
+
+/*
+ * 1. Initialize the bnad structure
+ * 2. Setup netdev pointer in pci_dev
+ * 3. Initialze Tx free tasklet
+ * 4. Initialize no. of TxQ & CQs & MSIX vectors
+ */
+static int
+bnad_init(struct bnad *bnad,
+         struct pci_dev *pdev, struct net_device *netdev)
+{
+       unsigned long flags;
+
+       SET_NETDEV_DEV(netdev, &pdev->dev);
+       pci_set_drvdata(pdev, netdev);
+
+       bnad->netdev = netdev;
+       bnad->pcidev = pdev;
+       bnad->mmio_start = pci_resource_start(pdev, 0);
+       bnad->mmio_len = pci_resource_len(pdev, 0);
+       bnad->bar0 = ioremap_nocache(bnad->mmio_start, bnad->mmio_len);
+       if (!bnad->bar0) {
+               dev_err(&pdev->dev, "ioremap for bar0 failed\n");
+               pci_set_drvdata(pdev, NULL);
+               return -ENOMEM;
+       }
+       pr_info("bar0 mapped to %p, len %llu\n", bnad->bar0,
+              (unsigned long long) bnad->mmio_len);
+
+       spin_lock_irqsave(&bnad->bna_lock, flags);
+       if (!bnad_msix_disable)
+               bnad->cfg_flags = BNAD_CF_MSIX;
+
+       bnad->cfg_flags |= BNAD_CF_DIM_ENABLED;
+
+       bnad_q_num_init(bnad);
+       spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+       bnad->msix_num = (bnad->num_tx * bnad->num_txq_per_tx) +
+               (bnad->num_rx * bnad->num_rxp_per_rx) +
+                        BNAD_MAILBOX_MSIX_VECTORS;
+       bnad->msix_diag_num = 2;        /* 1 for Tx, 1 for Rx */
+
+       bnad->txq_depth = BNAD_TXQ_DEPTH;
+       bnad->rxq_depth = BNAD_RXQ_DEPTH;
+       bnad->rx_csum = true;
+
+       bnad->tx_coalescing_timeo = BFI_TX_COALESCING_TIMEO;
+       bnad->rx_coalescing_timeo = BFI_RX_COALESCING_TIMEO;
+
+       tasklet_init(&bnad->tx_free_tasklet, bnad_tx_free_tasklet,
+                    (unsigned long)bnad);
+
+       return 0;
+}
+
+/*
+ * Must be called after bnad_pci_uninit()
+ * so that iounmap() and pci_set_drvdata(NULL)
+ * happens only after PCI uninitialization.
+ */
+static void
+bnad_uninit(struct bnad *bnad)
+{
+       if (bnad->bar0)
+               iounmap(bnad->bar0);
+       pci_set_drvdata(bnad->pcidev, NULL);
+}
+
+/*
+ * Initialize locks
+       a) Per device mutes used for serializing configuration
+          changes from OS interface
+       b) spin lock used to protect bna state machine
+ */
+static void
+bnad_lock_init(struct bnad *bnad)
+{
+       spin_lock_init(&bnad->bna_lock);
+       mutex_init(&bnad->conf_mutex);
+}
+
+static void
+bnad_lock_uninit(struct bnad *bnad)
+{
+       mutex_destroy(&bnad->conf_mutex);
+}
+
+/* PCI Initialization */
+static int
+bnad_pci_init(struct bnad *bnad,
+             struct pci_dev *pdev, bool *using_dac)
+{
+       int err;
+
+       err = pci_enable_device(pdev);
+       if (err)
+               return err;
+       err = pci_request_regions(pdev, BNAD_NAME);
+       if (err)
+               goto disable_device;
+       if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) &&
+           !pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) {
+               *using_dac = 1;
+       } else {
+               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)
+                               goto release_regions;
+               }
+               *using_dac = 0;
+       }
+       pci_set_master(pdev);
+       return 0;
+
+release_regions:
+       pci_release_regions(pdev);
+disable_device:
+       pci_disable_device(pdev);
+
+       return err;
+}
+
+static void
+bnad_pci_uninit(struct pci_dev *pdev)
+{
+       pci_release_regions(pdev);
+       pci_disable_device(pdev);
+}
+
+static int __devinit
+bnad_pci_probe(struct pci_dev *pdev,
+               const struct pci_device_id *pcidev_id)
+{
+       bool    using_dac;
+       int     err;
+       struct bnad *bnad;
+       struct bna *bna;
+       struct net_device *netdev;
+       struct bfa_pcidev pcidev_info;
+       unsigned long flags;
+
+       pr_info("bnad_pci_probe : (0x%p, 0x%p) PCI Func : (%d)\n",
+              pdev, pcidev_id, PCI_FUNC(pdev->devfn));
+
+       mutex_lock(&bnad_fwimg_mutex);
+       if (!cna_get_firmware_buf(pdev)) {
+               mutex_unlock(&bnad_fwimg_mutex);
+               pr_warn("Failed to load Firmware Image!\n");
+               return -ENODEV;
+       }
+       mutex_unlock(&bnad_fwimg_mutex);
+
+       /*
+        * Allocates sizeof(struct net_device + struct bnad)
+        * bnad = netdev->priv
+        */
+       netdev = alloc_etherdev(sizeof(struct bnad));
+       if (!netdev) {
+               dev_err(&pdev->dev, "alloc_etherdev failed\n");
+               err = -ENOMEM;
+               return err;
+       }
+       bnad = netdev_priv(netdev);
+
+       /*
+        * PCI initialization
+        *      Output : using_dac = 1 for 64 bit DMA
+        *                         = 0 for 32 bit DMA
+        */
+       err = bnad_pci_init(bnad, pdev, &using_dac);
+       if (err)
+               goto free_netdev;
+
+       bnad_lock_init(bnad);
+       /*
+        * Initialize bnad structure
+        * Setup relation between pci_dev & netdev
+        * Init Tx free tasklet
+        */
+       err = bnad_init(bnad, pdev, netdev);
+       if (err)
+               goto pci_uninit;
+       /* Initialize netdev structure, set up ethtool ops */
+       bnad_netdev_init(bnad, using_dac);
+
+       bnad_enable_msix(bnad);
+
+       /* Get resource requirement form bna */
+       bna_res_req(&bnad->res_info[0]);
+
+       /* Allocate resources from bna */
+       err = bnad_res_alloc(bnad);
+       if (err)
+               goto free_netdev;
+
+       bna = &bnad->bna;
+
+       /* Setup pcidev_info for bna_init() */
+       pcidev_info.pci_slot = PCI_SLOT(bnad->pcidev->devfn);
+       pcidev_info.pci_func = PCI_FUNC(bnad->pcidev->devfn);
+       pcidev_info.device_id = bnad->pcidev->device;
+       pcidev_info.pci_bar_kva = bnad->bar0;
+
+       mutex_lock(&bnad->conf_mutex);
+
+       spin_lock_irqsave(&bnad->bna_lock, flags);
+       bna_init(bna, bnad, &pcidev_info, &bnad->res_info[0]);
+
+       spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+       bnad->stats.bna_stats = &bna->stats;
+
+       /* Set up timers */
+       setup_timer(&bnad->bna.device.ioc.ioc_timer, bnad_ioc_timeout,
+                               ((unsigned long)bnad));
+       setup_timer(&bnad->bna.device.ioc.hb_timer, bnad_ioc_hb_check,
+                               ((unsigned long)bnad));
+       setup_timer(&bnad->bna.device.ioc.sem_timer, bnad_ioc_sem_timeout,
+                               ((unsigned long)bnad));
+
+       /* Now start the timer before calling IOC */
+       mod_timer(&bnad->bna.device.ioc.ioc_timer,
+                 jiffies + msecs_to_jiffies(BNA_IOC_TIMER_FREQ));
+
+       /*
+        * Start the chip
+        * Don't care even if err != 0, bna state machine will
+        * deal with it
+        */
+       err = bnad_device_enable(bnad);
+
+       /* Get the burnt-in mac */
+       spin_lock_irqsave(&bnad->bna_lock, flags);
+       bna_port_mac_get(&bna->port, &bnad->perm_addr);
+       bnad_set_netdev_perm_addr(bnad);
+       spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+       mutex_unlock(&bnad->conf_mutex);
+
+       /*
+        * Make sure the link appears down to the stack
+        */
+       netif_carrier_off(netdev);
+
+       /* Finally, reguister with net_device layer */
+       err = register_netdev(netdev);
+       if (err) {
+               pr_err("BNA : Registering with netdev failed\n");
+               goto disable_device;
+       }
+
+       return 0;
+
+disable_device:
+       mutex_lock(&bnad->conf_mutex);
+       bnad_device_disable(bnad);
+       del_timer_sync(&bnad->bna.device.ioc.ioc_timer);
+       del_timer_sync(&bnad->bna.device.ioc.sem_timer);
+       del_timer_sync(&bnad->bna.device.ioc.hb_timer);
+       spin_lock_irqsave(&bnad->bna_lock, flags);
+       bna_uninit(bna);
+       spin_unlock_irqrestore(&bnad->bna_lock, flags);
+       mutex_unlock(&bnad->conf_mutex);
+
+       bnad_res_free(bnad);
+       bnad_disable_msix(bnad);
+pci_uninit:
+       bnad_pci_uninit(pdev);
+       bnad_lock_uninit(bnad);
+       bnad_uninit(bnad);
+free_netdev:
+       free_netdev(netdev);
+       return err;
+}
+
+static void __devexit
+bnad_pci_remove(struct pci_dev *pdev)
+{
+       struct net_device *netdev = pci_get_drvdata(pdev);
+       struct bnad *bnad;
+       struct bna *bna;
+       unsigned long flags;
+
+       if (!netdev)
+               return;
+
+       pr_info("%s bnad_pci_remove\n", netdev->name);
+       bnad = netdev_priv(netdev);
+       bna = &bnad->bna;
+
+       unregister_netdev(netdev);
+
+       mutex_lock(&bnad->conf_mutex);
+       bnad_device_disable(bnad);
+       del_timer_sync(&bnad->bna.device.ioc.ioc_timer);
+       del_timer_sync(&bnad->bna.device.ioc.sem_timer);
+       del_timer_sync(&bnad->bna.device.ioc.hb_timer);
+       spin_lock_irqsave(&bnad->bna_lock, flags);
+       bna_uninit(bna);
+       spin_unlock_irqrestore(&bnad->bna_lock, flags);
+       mutex_unlock(&bnad->conf_mutex);
+
+       bnad_res_free(bnad);
+       bnad_disable_msix(bnad);
+       bnad_pci_uninit(pdev);
+       bnad_lock_uninit(bnad);
+       bnad_uninit(bnad);
+       free_netdev(netdev);
+}
+
+const struct pci_device_id bnad_pci_id_table[] = {
+       {
+               PCI_DEVICE(PCI_VENDOR_ID_BROCADE,
+                       PCI_DEVICE_ID_BROCADE_CT),
+               .class = PCI_CLASS_NETWORK_ETHERNET << 8,
+               .class_mask =  0xffff00
+       }, {0,  }
+};
+
+MODULE_DEVICE_TABLE(pci, bnad_pci_id_table);
+
+static struct pci_driver bnad_pci_driver = {
+       .name = BNAD_NAME,
+       .id_table = bnad_pci_id_table,
+       .probe = bnad_pci_probe,
+       .remove = __devexit_p(bnad_pci_remove),
+};
+
+static int __init
+bnad_module_init(void)
+{
+       int err;
+
+       pr_info("Brocade 10G Ethernet driver\n");
+
+       bfa_nw_ioc_auto_recover(bnad_ioc_auto_recover);
+
+       err = pci_register_driver(&bnad_pci_driver);
+       if (err < 0) {
+               pr_err("bna : PCI registration failed in module init "
+                      "(%d)\n", err);
+               return err;
+       }
+
+       return 0;
+}
+
+static void __exit
+bnad_module_exit(void)
+{
+       pci_unregister_driver(&bnad_pci_driver);
+
+       if (bfi_fw)
+               release_firmware(bfi_fw);
+}
+
+module_init(bnad_module_init);
+module_exit(bnad_module_exit);
+
+MODULE_AUTHOR("Brocade");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Brocade 10G PCIe Ethernet driver");
+MODULE_VERSION(BNAD_VERSION);
+MODULE_FIRMWARE(CNA_FW_FILE_CT);
diff --git a/drivers/net/bna/bnad.h b/drivers/net/bna/bnad.h
new file mode 100644 (file)
index 0000000..ee37788
--- /dev/null
@@ -0,0 +1,333 @@
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * 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.
+ */
+/*
+ * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+#ifndef __BNAD_H__
+#define __BNAD_H__
+
+#include <linux/rtnetlink.h>
+#include <linux/workqueue.h>
+#include <linux/ipv6.h>
+#include <linux/etherdevice.h>
+#include <linux/mutex.h>
+#include <linux/firmware.h>
+
+/* Fix for IA64 */
+#include <asm/checksum.h>
+#include <net/ip6_checksum.h>
+
+#include <net/ip.h>
+#include <net/tcp.h>
+
+#include "bna.h"
+
+#define BNAD_TXQ_DEPTH         2048
+#define BNAD_RXQ_DEPTH         2048
+
+#define BNAD_MAX_TXS           1
+#define BNAD_MAX_TXQ_PER_TX    8       /* 8 priority queues */
+#define BNAD_TXQ_NUM           1
+
+#define BNAD_MAX_RXS           1
+#define BNAD_MAX_RXPS_PER_RX   16
+
+/*
+ * Control structure pointed to ccb->ctrl, which
+ * determines the NAPI / LRO behavior CCB
+ * There is 1:1 corres. between ccb & ctrl
+ */
+struct bnad_rx_ctrl {
+       struct bna_ccb *ccb;
+       struct napi_struct      napi;
+};
+
+#define BNAD_RXMODE_PROMISC_DEFAULT    BNA_RXMODE_PROMISC
+
+#define BNAD_GET_TX_ID(_skb)   (0)
+
+/*
+ * GLOBAL #defines (CONSTANTS)
+ */
+#define BNAD_NAME                      "bna"
+#define BNAD_NAME_LEN                  64
+
+#define BNAD_VERSION                   "2.3.2.0"
+
+#define BNAD_MAILBOX_MSIX_VECTORS      1
+
+#define BNAD_STATS_TIMER_FREQ          1000    /* in msecs */
+#define BNAD_DIM_TIMER_FREQ            1000    /* in msecs */
+
+#define BNAD_MAX_Q_DEPTH               0x10000
+#define BNAD_MIN_Q_DEPTH               0x200
+
+#define BNAD_JUMBO_MTU                 9000
+
+#define BNAD_NETIF_WAKE_THRESHOLD      8
+
+#define BNAD_RXQ_REFILL_THRESHOLD_SHIFT        3
+
+/* Bit positions for tcb->flags */
+#define BNAD_TXQ_FREE_SENT             0
+
+/* Bit positions for rcb->flags */
+#define BNAD_RXQ_REFILL                        0
+#define BNAD_RXQ_STARTED               1
+
+/*
+ * DATA STRUCTURES
+ */
+
+/* enums */
+enum bnad_intr_source {
+       BNAD_INTR_TX            = 1,
+       BNAD_INTR_RX            = 2
+};
+
+enum bnad_link_state {
+       BNAD_LS_DOWN            = 0,
+       BNAD_LS_UP              = 1
+};
+
+struct bnad_completion {
+       struct completion       ioc_comp;
+       struct completion       ucast_comp;
+       struct completion       mcast_comp;
+       struct completion       tx_comp;
+       struct completion       rx_comp;
+       struct completion       stats_comp;
+       struct completion       port_comp;
+
+       u8                      ioc_comp_status;
+       u8                      ucast_comp_status;
+       u8                      mcast_comp_status;
+       u8                      tx_comp_status;
+       u8                      rx_comp_status;
+       u8                      stats_comp_status;
+       u8                      port_comp_status;
+};
+
+/* Tx Rx Control Stats */
+struct bnad_drv_stats {
+       u64             netif_queue_stop;
+       u64             netif_queue_wakeup;
+       u64             tso4;
+       u64             tso6;
+       u64             tso_err;
+       u64             tcpcsum_offload;
+       u64             udpcsum_offload;
+       u64             csum_help;
+       u64             csum_help_err;
+
+       u64             hw_stats_updates;
+       u64             netif_rx_schedule;
+       u64             netif_rx_complete;
+       u64             netif_rx_dropped;
+
+       u64             link_toggle;
+       u64             cee_up;
+
+       u64             rxp_info_alloc_failed;
+       u64             mbox_intr_disabled;
+       u64             mbox_intr_enabled;
+       u64             tx_unmap_q_alloc_failed;
+       u64             rx_unmap_q_alloc_failed;
+
+       u64             rxbuf_alloc_failed;
+};
+
+/* Complete driver stats */
+struct bnad_stats {
+       struct bnad_drv_stats drv_stats;
+       struct bna_stats *bna_stats;
+};
+
+/* Tx / Rx Resources */
+struct bnad_tx_res_info {
+       struct bna_res_info res_info[BNA_TX_RES_T_MAX];
+};
+
+struct bnad_rx_res_info {
+       struct bna_res_info res_info[BNA_RX_RES_T_MAX];
+};
+
+struct bnad_tx_info {
+       struct bna_tx *tx; /* 1:1 between tx_info & tx */
+       struct bna_tcb *tcb[BNAD_MAX_TXQ_PER_TX];
+} ____cacheline_aligned;
+
+struct bnad_rx_info {
+       struct bna_rx *rx; /* 1:1 between rx_info & rx */
+
+       struct bnad_rx_ctrl rx_ctrl[BNAD_MAX_RXPS_PER_RX];
+} ____cacheline_aligned;
+
+/* Unmap queues for Tx / Rx cleanup */
+struct bnad_skb_unmap {
+       struct sk_buff          *skb;
+       DECLARE_PCI_UNMAP_ADDR(dma_addr)
+};
+
+struct bnad_unmap_q {
+       u32             producer_index;
+       u32             consumer_index;
+       u32             q_depth;
+       /* This should be the last one */
+       struct bnad_skb_unmap unmap_array[1];
+};
+
+/* Bit mask values for bnad->cfg_flags */
+#define        BNAD_CF_DIM_ENABLED             0x01    /* DIM */
+#define        BNAD_CF_PROMISC                 0x02
+#define BNAD_CF_ALLMULTI               0x04
+#define        BNAD_CF_MSIX                    0x08    /* If in MSIx mode */
+
+/* Defines for run_flags bit-mask */
+/* Set, tested & cleared using xxx_bit() functions */
+/* Values indicated bit positions */
+#define        BNAD_RF_CEE_RUNNING             1
+#define BNAD_RF_HW_ERROR               2
+#define BNAD_RF_MBOX_IRQ_DISABLED      3
+#define BNAD_RF_TX_STARTED             4
+#define BNAD_RF_RX_STARTED             5
+#define BNAD_RF_DIM_TIMER_RUNNING      6
+#define BNAD_RF_STATS_TIMER_RUNNING    7
+
+struct bnad {
+       struct net_device       *netdev;
+
+       /* Data path */
+       struct bnad_tx_info tx_info[BNAD_MAX_TXS];
+       struct bnad_rx_info rx_info[BNAD_MAX_RXS];
+
+       struct vlan_group       *vlan_grp;
+       /*
+        * These q numbers are global only because
+        * they are used to calculate MSIx vectors.
+        * Actually the exact # of queues are per Tx/Rx
+        * object.
+        */
+       u32             num_tx;
+       u32             num_rx;
+       u32             num_txq_per_tx;
+       u32             num_rxp_per_rx;
+
+       u32             txq_depth;
+       u32             rxq_depth;
+
+       u8                      tx_coalescing_timeo;
+       u8                      rx_coalescing_timeo;
+
+       struct bna_rx_config rx_config[BNAD_MAX_RXS];
+       struct bna_tx_config tx_config[BNAD_MAX_TXS];
+
+       u32             rx_csum;
+
+       void __iomem            *bar0;  /* BAR0 address */
+
+       struct bna bna;
+
+       u32             cfg_flags;
+       unsigned long           run_flags;
+
+       struct pci_dev          *pcidev;
+       u64             mmio_start;
+       u64             mmio_len;
+
+       u32             msix_num;
+       u32             msix_diag_num;
+       struct msix_entry       *msix_table;
+
+       struct mutex            conf_mutex;
+       spinlock_t              bna_lock ____cacheline_aligned;
+
+       /* Timers */
+       struct timer_list       ioc_timer;
+       struct timer_list       dim_timer;
+       struct timer_list       stats_timer;
+
+       /* Control path resources, memory & irq */
+       struct bna_res_info res_info[BNA_RES_T_MAX];
+       struct bnad_tx_res_info tx_res_info[BNAD_MAX_TXS];
+       struct bnad_rx_res_info rx_res_info[BNAD_MAX_RXS];
+
+       struct bnad_completion bnad_completions;
+
+       /* Burnt in MAC address */
+       mac_t                   perm_addr;
+
+       struct tasklet_struct   tx_free_tasklet;
+
+       /* Statistics */
+       struct bnad_stats stats;
+
+       struct bnad_diag *diag;
+
+       char                    adapter_name[BNAD_NAME_LEN];
+       char                    port_name[BNAD_NAME_LEN];
+       char                    mbox_irq_name[BNAD_NAME_LEN];
+};
+
+/*
+ * EXTERN VARIABLES
+ */
+extern struct firmware *bfi_fw;
+extern u32             bnad_rxqs_per_cq;
+
+/*
+ * EXTERN PROTOTYPES
+ */
+extern u32 *cna_get_firmware_buf(struct pci_dev *pdev);
+/* Netdev entry point prototypes */
+extern void bnad_set_ethtool_ops(struct net_device *netdev);
+
+/* Configuration & setup */
+extern void bnad_tx_coalescing_timeo_set(struct bnad *bnad);
+extern void bnad_rx_coalescing_timeo_set(struct bnad *bnad);
+
+extern int bnad_setup_rx(struct bnad *bnad, uint rx_id);
+extern int bnad_setup_tx(struct bnad *bnad, uint tx_id);
+extern void bnad_cleanup_tx(struct bnad *bnad, uint tx_id);
+extern void bnad_cleanup_rx(struct bnad *bnad, uint rx_id);
+
+/* Timer start/stop protos */
+extern void bnad_dim_timer_start(struct bnad *bnad);
+
+/* Statistics */
+extern void bnad_netdev_qstats_fill(struct bnad *bnad, struct rtnl_link_stats64 *stats);
+extern void bnad_netdev_hwstats_fill(struct bnad *bnad, struct rtnl_link_stats64 *stats);
+
+/**
+ * MACROS
+ */
+/* To set & get the stats counters */
+#define BNAD_UPDATE_CTR(_bnad, _ctr)                           \
+                               (((_bnad)->stats.drv_stats._ctr)++)
+
+#define BNAD_GET_CTR(_bnad, _ctr) ((_bnad)->stats.drv_stats._ctr)
+
+#define bnad_enable_rx_irq_unsafe(_ccb)                        \
+{                                                      \
+       bna_ib_coalescing_timer_set((_ccb)->i_dbell,    \
+               (_ccb)->rx_coalescing_timeo);           \
+       bna_ib_ack((_ccb)->i_dbell, 0);                 \
+}
+
+#define bnad_dim_timer_running(_bnad)                          \
+       (((_bnad)->cfg_flags & BNAD_CF_DIM_ENABLED) &&          \
+       (test_bit(BNAD_RF_DIM_TIMER_RUNNING, &((_bnad)->run_flags))))
+
+#endif /* __BNAD_H__ */
diff --git a/drivers/net/bna/bnad_ethtool.c b/drivers/net/bna/bnad_ethtool.c
new file mode 100644 (file)
index 0000000..11fa2ea
--- /dev/null
@@ -0,0 +1,1277 @@
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * 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.
+ */
+/*
+ * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+
+#include "cna.h"
+
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/ethtool.h>
+#include <linux/rtnetlink.h>
+
+#include "bna.h"
+
+#include "bnad.h"
+
+#define BNAD_NUM_TXF_COUNTERS 12
+#define BNAD_NUM_RXF_COUNTERS 10
+#define BNAD_NUM_CQ_COUNTERS 3
+#define BNAD_NUM_RXQ_COUNTERS 6
+#define BNAD_NUM_TXQ_COUNTERS 5
+
+#define BNAD_ETHTOOL_STATS_NUM                                         \
+       (sizeof(struct rtnl_link_stats64) / sizeof(u64) +       \
+       sizeof(struct bnad_drv_stats) / sizeof(u64) +           \
+       offsetof(struct bfi_ll_stats, rxf_stats[0]) / sizeof(u64))
+
+static char *bnad_net_stats_strings[BNAD_ETHTOOL_STATS_NUM] = {
+       "rx_packets",
+       "tx_packets",
+       "rx_bytes",
+       "tx_bytes",
+       "rx_errors",
+       "tx_errors",
+       "rx_dropped",
+       "tx_dropped",
+       "multicast",
+       "collisions",
+
+       "rx_length_errors",
+       "rx_over_errors",
+       "rx_crc_errors",
+       "rx_frame_errors",
+       "rx_fifo_errors",
+       "rx_missed_errors",
+
+       "tx_aborted_errors",
+       "tx_carrier_errors",
+       "tx_fifo_errors",
+       "tx_heartbeat_errors",
+       "tx_window_errors",
+
+       "rx_compressed",
+       "tx_compressed",
+
+       "netif_queue_stop",
+       "netif_queue_wakeup",
+       "tso4",
+       "tso6",
+       "tso_err",
+       "tcpcsum_offload",
+       "udpcsum_offload",
+       "csum_help",
+       "csum_help_err",
+       "hw_stats_updates",
+       "netif_rx_schedule",
+       "netif_rx_complete",
+       "netif_rx_dropped",
+
+       "link_toggle",
+       "cee_up",
+
+       "rxp_info_alloc_failed",
+       "mbox_intr_disabled",
+       "mbox_intr_enabled",
+       "tx_unmap_q_alloc_failed",
+       "rx_unmap_q_alloc_failed",
+       "rxbuf_alloc_failed",
+
+       "mac_frame_64",
+       "mac_frame_65_127",
+       "mac_frame_128_255",
+       "mac_frame_256_511",
+       "mac_frame_512_1023",
+       "mac_frame_1024_1518",
+       "mac_frame_1518_1522",
+       "mac_rx_bytes",
+       "mac_rx_packets",
+       "mac_rx_fcs_error",
+       "mac_rx_multicast",
+       "mac_rx_broadcast",
+       "mac_rx_control_frames",
+       "mac_rx_pause",
+       "mac_rx_unknown_opcode",
+       "mac_rx_alignment_error",
+       "mac_rx_frame_length_error",
+       "mac_rx_code_error",
+       "mac_rx_carrier_sense_error",
+       "mac_rx_undersize",
+       "mac_rx_oversize",
+       "mac_rx_fragments",
+       "mac_rx_jabber",
+       "mac_rx_drop",
+
+       "mac_tx_bytes",
+       "mac_tx_packets",
+       "mac_tx_multicast",
+       "mac_tx_broadcast",
+       "mac_tx_pause",
+       "mac_tx_deferral",
+       "mac_tx_excessive_deferral",
+       "mac_tx_single_collision",
+       "mac_tx_muliple_collision",
+       "mac_tx_late_collision",
+       "mac_tx_excessive_collision",
+       "mac_tx_total_collision",
+       "mac_tx_pause_honored",
+       "mac_tx_drop",
+       "mac_tx_jabber",
+       "mac_tx_fcs_error",
+       "mac_tx_control_frame",
+       "mac_tx_oversize",
+       "mac_tx_undersize",
+       "mac_tx_fragments",
+
+       "bpc_tx_pause_0",
+       "bpc_tx_pause_1",
+       "bpc_tx_pause_2",
+       "bpc_tx_pause_3",
+       "bpc_tx_pause_4",
+       "bpc_tx_pause_5",
+       "bpc_tx_pause_6",
+       "bpc_tx_pause_7",
+       "bpc_tx_zero_pause_0",
+       "bpc_tx_zero_pause_1",
+       "bpc_tx_zero_pause_2",
+       "bpc_tx_zero_pause_3",
+       "bpc_tx_zero_pause_4",
+       "bpc_tx_zero_pause_5",
+       "bpc_tx_zero_pause_6",
+       "bpc_tx_zero_pause_7",
+       "bpc_tx_first_pause_0",
+       "bpc_tx_first_pause_1",
+       "bpc_tx_first_pause_2",
+       "bpc_tx_first_pause_3",
+       "bpc_tx_first_pause_4",
+       "bpc_tx_first_pause_5",
+       "bpc_tx_first_pause_6",
+       "bpc_tx_first_pause_7",
+
+       "bpc_rx_pause_0",
+       "bpc_rx_pause_1",
+       "bpc_rx_pause_2",
+       "bpc_rx_pause_3",
+       "bpc_rx_pause_4",
+       "bpc_rx_pause_5",
+       "bpc_rx_pause_6",
+       "bpc_rx_pause_7",
+       "bpc_rx_zero_pause_0",
+       "bpc_rx_zero_pause_1",
+       "bpc_rx_zero_pause_2",
+       "bpc_rx_zero_pause_3",
+       "bpc_rx_zero_pause_4",
+       "bpc_rx_zero_pause_5",
+       "bpc_rx_zero_pause_6",
+       "bpc_rx_zero_pause_7",
+       "bpc_rx_first_pause_0",
+       "bpc_rx_first_pause_1",
+       "bpc_rx_first_pause_2",
+       "bpc_rx_first_pause_3",
+       "bpc_rx_first_pause_4",
+       "bpc_rx_first_pause_5",
+       "bpc_rx_first_pause_6",
+       "bpc_rx_first_pause_7",
+
+       "rad_rx_frames",
+       "rad_rx_octets",
+       "rad_rx_vlan_frames",
+       "rad_rx_ucast",
+       "rad_rx_ucast_octets",
+       "rad_rx_ucast_vlan",
+       "rad_rx_mcast",
+       "rad_rx_mcast_octets",
+       "rad_rx_mcast_vlan",
+       "rad_rx_bcast",
+       "rad_rx_bcast_octets",
+       "rad_rx_bcast_vlan",
+       "rad_rx_drops",
+
+       "fc_rx_ucast_octets",
+       "fc_rx_ucast",
+       "fc_rx_ucast_vlan",
+       "fc_rx_mcast_octets",
+       "fc_rx_mcast",
+       "fc_rx_mcast_vlan",
+       "fc_rx_bcast_octets",
+       "fc_rx_bcast",
+       "fc_rx_bcast_vlan",
+
+       "fc_tx_ucast_octets",
+       "fc_tx_ucast",
+       "fc_tx_ucast_vlan",
+       "fc_tx_mcast_octets",
+       "fc_tx_mcast",
+       "fc_tx_mcast_vlan",
+       "fc_tx_bcast_octets",
+       "fc_tx_bcast",
+       "fc_tx_bcast_vlan",
+       "fc_tx_parity_errors",
+       "fc_tx_timeout",
+       "fc_tx_fid_parity_errors",
+};
+
+static int
+bnad_get_settings(struct net_device *netdev, struct ethtool_cmd *cmd)
+{
+       cmd->supported = SUPPORTED_10000baseT_Full;
+       cmd->advertising = ADVERTISED_10000baseT_Full;
+       cmd->autoneg = AUTONEG_DISABLE;
+       cmd->supported |= SUPPORTED_FIBRE;
+       cmd->advertising |= ADVERTISED_FIBRE;
+       cmd->port = PORT_FIBRE;
+       cmd->phy_address = 0;
+
+       if (netif_carrier_ok(netdev)) {
+               cmd->speed = SPEED_10000;
+               cmd->duplex = DUPLEX_FULL;
+       } else {
+               cmd->speed = -1;
+               cmd->duplex = -1;
+       }
+       cmd->transceiver = XCVR_EXTERNAL;
+       cmd->maxtxpkt = 0;
+       cmd->maxrxpkt = 0;
+
+       return 0;
+}
+
+static int
+bnad_set_settings(struct net_device *netdev, struct ethtool_cmd *cmd)
+{
+       /* 10G full duplex setting supported only */
+       if (cmd->autoneg == AUTONEG_ENABLE)
+               return -EOPNOTSUPP; else {
+               if ((cmd->speed == SPEED_10000) && (cmd->duplex == DUPLEX_FULL))
+                       return 0;
+       }
+
+       return -EOPNOTSUPP;
+}
+
+static void
+bnad_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo)
+{
+       struct bnad *bnad = netdev_priv(netdev);
+       struct bfa_ioc_attr *ioc_attr;
+       unsigned long flags;
+
+       strcpy(drvinfo->driver, BNAD_NAME);
+       strcpy(drvinfo->version, BNAD_VERSION);
+
+       ioc_attr = kzalloc(sizeof(*ioc_attr), GFP_KERNEL);
+       if (ioc_attr) {
+               memset(ioc_attr, 0, sizeof(*ioc_attr));
+               spin_lock_irqsave(&bnad->bna_lock, flags);
+               bfa_nw_ioc_get_attr(&bnad->bna.device.ioc, ioc_attr);
+               spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+               strncpy(drvinfo->fw_version, ioc_attr->adapter_attr.fw_ver,
+                       sizeof(drvinfo->fw_version) - 1);
+               kfree(ioc_attr);
+       }
+
+       strncpy(drvinfo->bus_info, pci_name(bnad->pcidev), ETHTOOL_BUSINFO_LEN);
+}
+
+static int
+get_regs(struct bnad *bnad, u32 * regs)
+{
+       int num = 0, i;
+       u32 reg_addr;
+       unsigned long flags;
+
+#define BNAD_GET_REG(addr)                                     \
+do {                                                           \
+       if (regs)                                               \
+               regs[num++] = readl(bnad->bar0 + (addr));       \
+       else                                                    \
+               num++;                                          \
+} while (0)
+
+       spin_lock_irqsave(&bnad->bna_lock, flags);
+
+       /* DMA Block Internal Registers */
+       BNAD_GET_REG(DMA_CTRL_REG0);
+       BNAD_GET_REG(DMA_CTRL_REG1);
+       BNAD_GET_REG(DMA_ERR_INT_STATUS);
+       BNAD_GET_REG(DMA_ERR_INT_ENABLE);
+       BNAD_GET_REG(DMA_ERR_INT_STATUS_SET);
+
+       /* APP Block Register Address Offset from BAR0 */
+       BNAD_GET_REG(HOSTFN0_INT_STATUS);
+       BNAD_GET_REG(HOSTFN0_INT_MASK);
+       BNAD_GET_REG(HOST_PAGE_NUM_FN0);
+       BNAD_GET_REG(HOST_MSIX_ERR_INDEX_FN0);
+       BNAD_GET_REG(FN0_PCIE_ERR_REG);
+       BNAD_GET_REG(FN0_ERR_TYPE_STATUS_REG);
+       BNAD_GET_REG(FN0_ERR_TYPE_MSK_STATUS_REG);
+
+       BNAD_GET_REG(HOSTFN1_INT_STATUS);
+       BNAD_GET_REG(HOSTFN1_INT_MASK);
+       BNAD_GET_REG(HOST_PAGE_NUM_FN1);
+       BNAD_GET_REG(HOST_MSIX_ERR_INDEX_FN1);
+       BNAD_GET_REG(FN1_PCIE_ERR_REG);
+       BNAD_GET_REG(FN1_ERR_TYPE_STATUS_REG);
+       BNAD_GET_REG(FN1_ERR_TYPE_MSK_STATUS_REG);
+
+       BNAD_GET_REG(PCIE_MISC_REG);
+
+       BNAD_GET_REG(HOST_SEM0_REG);
+       BNAD_GET_REG(HOST_SEM1_REG);
+       BNAD_GET_REG(HOST_SEM2_REG);
+       BNAD_GET_REG(HOST_SEM3_REG);
+       BNAD_GET_REG(HOST_SEM0_INFO_REG);
+       BNAD_GET_REG(HOST_SEM1_INFO_REG);
+       BNAD_GET_REG(HOST_SEM2_INFO_REG);
+       BNAD_GET_REG(HOST_SEM3_INFO_REG);
+
+       BNAD_GET_REG(TEMPSENSE_CNTL_REG);
+       BNAD_GET_REG(TEMPSENSE_STAT_REG);
+
+       BNAD_GET_REG(APP_LOCAL_ERR_STAT);
+       BNAD_GET_REG(APP_LOCAL_ERR_MSK);
+
+       BNAD_GET_REG(PCIE_LNK_ERR_STAT);
+       BNAD_GET_REG(PCIE_LNK_ERR_MSK);
+
+       BNAD_GET_REG(FCOE_FIP_ETH_TYPE);
+       BNAD_GET_REG(RESV_ETH_TYPE);
+
+       BNAD_GET_REG(HOSTFN2_INT_STATUS);
+       BNAD_GET_REG(HOSTFN2_INT_MASK);
+       BNAD_GET_REG(HOST_PAGE_NUM_FN2);
+       BNAD_GET_REG(HOST_MSIX_ERR_INDEX_FN2);
+       BNAD_GET_REG(FN2_PCIE_ERR_REG);
+       BNAD_GET_REG(FN2_ERR_TYPE_STATUS_REG);
+       BNAD_GET_REG(FN2_ERR_TYPE_MSK_STATUS_REG);
+
+       BNAD_GET_REG(HOSTFN3_INT_STATUS);
+       BNAD_GET_REG(HOSTFN3_INT_MASK);
+       BNAD_GET_REG(HOST_PAGE_NUM_FN3);
+       BNAD_GET_REG(HOST_MSIX_ERR_INDEX_FN3);
+       BNAD_GET_REG(FN3_PCIE_ERR_REG);
+       BNAD_GET_REG(FN3_ERR_TYPE_STATUS_REG);
+       BNAD_GET_REG(FN3_ERR_TYPE_MSK_STATUS_REG);
+
+       /* Host Command Status Registers */
+       reg_addr = HOST_CMDSTS0_CLR_REG;
+       for (i = 0; i < 16; i++) {
+               BNAD_GET_REG(reg_addr);
+               BNAD_GET_REG(reg_addr + 4);
+               BNAD_GET_REG(reg_addr + 8);
+               reg_addr += 0x10;
+       }
+
+       /* Function ID register */
+       BNAD_GET_REG(FNC_ID_REG);
+
+       /* Function personality register */
+       BNAD_GET_REG(FNC_PERS_REG);
+
+       /* Operation mode register */
+       BNAD_GET_REG(OP_MODE);
+
+       /* LPU0 Registers */
+       BNAD_GET_REG(LPU0_MBOX_CTL_REG);
+       BNAD_GET_REG(LPU0_MBOX_CMD_REG);
+       BNAD_GET_REG(LPU0_MBOX_LINK_0REG);
+       BNAD_GET_REG(LPU1_MBOX_LINK_0REG);
+       BNAD_GET_REG(LPU0_MBOX_STATUS_0REG);
+       BNAD_GET_REG(LPU1_MBOX_STATUS_0REG);
+       BNAD_GET_REG(LPU0_ERR_STATUS_REG);
+       BNAD_GET_REG(LPU0_ERR_SET_REG);
+
+       /* LPU1 Registers */
+       BNAD_GET_REG(LPU1_MBOX_CTL_REG);
+       BNAD_GET_REG(LPU1_MBOX_CMD_REG);
+       BNAD_GET_REG(LPU0_MBOX_LINK_1REG);
+       BNAD_GET_REG(LPU1_MBOX_LINK_1REG);
+       BNAD_GET_REG(LPU0_MBOX_STATUS_1REG);
+       BNAD_GET_REG(LPU1_MBOX_STATUS_1REG);
+       BNAD_GET_REG(LPU1_ERR_STATUS_REG);
+       BNAD_GET_REG(LPU1_ERR_SET_REG);
+
+       /* PSS Registers */
+       BNAD_GET_REG(PSS_CTL_REG);
+       BNAD_GET_REG(PSS_ERR_STATUS_REG);
+       BNAD_GET_REG(ERR_STATUS_SET);
+       BNAD_GET_REG(PSS_RAM_ERR_STATUS_REG);
+
+       /* Catapult CPQ Registers */
+       BNAD_GET_REG(HOSTFN0_LPU0_MBOX0_CMD_STAT);
+       BNAD_GET_REG(HOSTFN0_LPU1_MBOX0_CMD_STAT);
+       BNAD_GET_REG(LPU0_HOSTFN0_MBOX0_CMD_STAT);
+       BNAD_GET_REG(LPU1_HOSTFN0_MBOX0_CMD_STAT);
+
+       BNAD_GET_REG(HOSTFN0_LPU0_MBOX1_CMD_STAT);
+       BNAD_GET_REG(HOSTFN0_LPU1_MBOX1_CMD_STAT);
+       BNAD_GET_REG(LPU0_HOSTFN0_MBOX1_CMD_STAT);
+       BNAD_GET_REG(LPU1_HOSTFN0_MBOX1_CMD_STAT);
+
+       BNAD_GET_REG(HOSTFN1_LPU0_MBOX0_CMD_STAT);
+       BNAD_GET_REG(HOSTFN1_LPU1_MBOX0_CMD_STAT);
+       BNAD_GET_REG(LPU0_HOSTFN1_MBOX0_CMD_STAT);
+       BNAD_GET_REG(LPU1_HOSTFN1_MBOX0_CMD_STAT);
+
+       BNAD_GET_REG(HOSTFN1_LPU0_MBOX1_CMD_STAT);
+       BNAD_GET_REG(HOSTFN1_LPU1_MBOX1_CMD_STAT);
+       BNAD_GET_REG(LPU0_HOSTFN1_MBOX1_CMD_STAT);
+       BNAD_GET_REG(LPU1_HOSTFN1_MBOX1_CMD_STAT);
+
+       BNAD_GET_REG(HOSTFN2_LPU0_MBOX0_CMD_STAT);
+       BNAD_GET_REG(HOSTFN2_LPU1_MBOX0_CMD_STAT);
+       BNAD_GET_REG(LPU0_HOSTFN2_MBOX0_CMD_STAT);
+       BNAD_GET_REG(LPU1_HOSTFN2_MBOX0_CMD_STAT);
+
+       BNAD_GET_REG(HOSTFN2_LPU0_MBOX1_CMD_STAT);
+       BNAD_GET_REG(HOSTFN2_LPU1_MBOX1_CMD_STAT);
+       BNAD_GET_REG(LPU0_HOSTFN2_MBOX1_CMD_STAT);
+       BNAD_GET_REG(LPU1_HOSTFN2_MBOX1_CMD_STAT);
+
+       BNAD_GET_REG(HOSTFN3_LPU0_MBOX0_CMD_STAT);
+       BNAD_GET_REG(HOSTFN3_LPU1_MBOX0_CMD_STAT);
+       BNAD_GET_REG(LPU0_HOSTFN3_MBOX0_CMD_STAT);
+       BNAD_GET_REG(LPU1_HOSTFN3_MBOX0_CMD_STAT);
+
+       BNAD_GET_REG(HOSTFN3_LPU0_MBOX1_CMD_STAT);
+       BNAD_GET_REG(HOSTFN3_LPU1_MBOX1_CMD_STAT);
+       BNAD_GET_REG(LPU0_HOSTFN3_MBOX1_CMD_STAT);
+       BNAD_GET_REG(LPU1_HOSTFN3_MBOX1_CMD_STAT);
+
+       /* Host Function Force Parity Error Registers */
+       BNAD_GET_REG(HOSTFN0_LPU_FORCE_PERR);
+       BNAD_GET_REG(HOSTFN1_LPU_FORCE_PERR);
+       BNAD_GET_REG(HOSTFN2_LPU_FORCE_PERR);
+       BNAD_GET_REG(HOSTFN3_LPU_FORCE_PERR);
+
+       /* LL Port[0|1] Halt Mask Registers */
+       BNAD_GET_REG(LL_HALT_MSK_P0);
+       BNAD_GET_REG(LL_HALT_MSK_P1);
+
+       /* LL Port[0|1] Error Mask Registers */
+       BNAD_GET_REG(LL_ERR_MSK_P0);
+       BNAD_GET_REG(LL_ERR_MSK_P1);
+
+       /* EMC FLI Registers */
+       BNAD_GET_REG(FLI_CMD_REG);
+       BNAD_GET_REG(FLI_ADDR_REG);
+       BNAD_GET_REG(FLI_CTL_REG);
+       BNAD_GET_REG(FLI_WRDATA_REG);
+       BNAD_GET_REG(FLI_RDDATA_REG);
+       BNAD_GET_REG(FLI_DEV_STATUS_REG);
+       BNAD_GET_REG(FLI_SIG_WD_REG);
+
+       BNAD_GET_REG(FLI_DEV_VENDOR_REG);
+       BNAD_GET_REG(FLI_ERR_STATUS_REG);
+
+       /* RxAdm 0 Registers */
+       BNAD_GET_REG(RAD0_CTL_REG);
+       BNAD_GET_REG(RAD0_PE_PARM_REG);
+       BNAD_GET_REG(RAD0_BCN_REG);
+       BNAD_GET_REG(RAD0_DEFAULT_REG);
+       BNAD_GET_REG(RAD0_PROMISC_REG);
+       BNAD_GET_REG(RAD0_BCNQ_REG);
+       BNAD_GET_REG(RAD0_DEFAULTQ_REG);
+
+       BNAD_GET_REG(RAD0_ERR_STS);
+       BNAD_GET_REG(RAD0_SET_ERR_STS);
+       BNAD_GET_REG(RAD0_ERR_INT_EN);
+       BNAD_GET_REG(RAD0_FIRST_ERR);
+       BNAD_GET_REG(RAD0_FORCE_ERR);
+
+       BNAD_GET_REG(RAD0_MAC_MAN_1H);
+       BNAD_GET_REG(RAD0_MAC_MAN_1L);
+       BNAD_GET_REG(RAD0_MAC_MAN_2H);
+       BNAD_GET_REG(RAD0_MAC_MAN_2L);
+       BNAD_GET_REG(RAD0_MAC_MAN_3H);
+       BNAD_GET_REG(RAD0_MAC_MAN_3L);
+       BNAD_GET_REG(RAD0_MAC_MAN_4H);
+       BNAD_GET_REG(RAD0_MAC_MAN_4L);
+
+       BNAD_GET_REG(RAD0_LAST4_IP);
+
+       /* RxAdm 1 Registers */
+       BNAD_GET_REG(RAD1_CTL_REG);
+       BNAD_GET_REG(RAD1_PE_PARM_REG);
+       BNAD_GET_REG(RAD1_BCN_REG);
+       BNAD_GET_REG(RAD1_DEFAULT_REG);
+       BNAD_GET_REG(RAD1_PROMISC_REG);
+       BNAD_GET_REG(RAD1_BCNQ_REG);
+       BNAD_GET_REG(RAD1_DEFAULTQ_REG);
+
+       BNAD_GET_REG(RAD1_ERR_STS);
+       BNAD_GET_REG(RAD1_SET_ERR_STS);
+       BNAD_GET_REG(RAD1_ERR_INT_EN);
+
+       /* TxA0 Registers */
+       BNAD_GET_REG(TXA0_CTRL_REG);
+       /* TxA0 TSO Sequence # Registers (RO) */
+       for (i = 0; i < 8; i++) {
+               BNAD_GET_REG(TXA0_TSO_TCP_SEQ_REG(i));
+               BNAD_GET_REG(TXA0_TSO_IP_INFO_REG(i));
+       }
+
+       /* TxA1 Registers */
+       BNAD_GET_REG(TXA1_CTRL_REG);
+       /* TxA1 TSO Sequence # Registers (RO) */
+       for (i = 0; i < 8; i++) {
+               BNAD_GET_REG(TXA1_TSO_TCP_SEQ_REG(i));
+               BNAD_GET_REG(TXA1_TSO_IP_INFO_REG(i));
+       }
+
+       /* RxA Registers */
+       BNAD_GET_REG(RXA0_CTL_REG);
+       BNAD_GET_REG(RXA1_CTL_REG);
+
+       /* PLB0 Registers */
+       BNAD_GET_REG(PLB0_ECM_TIMER_REG);
+       BNAD_GET_REG(PLB0_RL_CTL);
+       for (i = 0; i < 8; i++)
+               BNAD_GET_REG(PLB0_RL_MAX_BC(i));
+       BNAD_GET_REG(PLB0_RL_TU_PRIO);
+       for (i = 0; i < 8; i++)
+               BNAD_GET_REG(PLB0_RL_BYTE_CNT(i));
+       BNAD_GET_REG(PLB0_RL_MIN_REG);
+       BNAD_GET_REG(PLB0_RL_MAX_REG);
+       BNAD_GET_REG(PLB0_EMS_ADD_REG);
+
+       /* PLB1 Registers */
+       BNAD_GET_REG(PLB1_ECM_TIMER_REG);
+       BNAD_GET_REG(PLB1_RL_CTL);
+       for (i = 0; i < 8; i++)
+               BNAD_GET_REG(PLB1_RL_MAX_BC(i));
+       BNAD_GET_REG(PLB1_RL_TU_PRIO);
+       for (i = 0; i < 8; i++)
+               BNAD_GET_REG(PLB1_RL_BYTE_CNT(i));
+       BNAD_GET_REG(PLB1_RL_MIN_REG);
+       BNAD_GET_REG(PLB1_RL_MAX_REG);
+       BNAD_GET_REG(PLB1_EMS_ADD_REG);
+
+       /* HQM Control Register */
+       BNAD_GET_REG(HQM0_CTL_REG);
+       BNAD_GET_REG(HQM0_RXQ_STOP_SEM);
+       BNAD_GET_REG(HQM0_TXQ_STOP_SEM);
+       BNAD_GET_REG(HQM1_CTL_REG);
+       BNAD_GET_REG(HQM1_RXQ_STOP_SEM);
+       BNAD_GET_REG(HQM1_TXQ_STOP_SEM);
+
+       /* LUT Registers */
+       BNAD_GET_REG(LUT0_ERR_STS);
+       BNAD_GET_REG(LUT0_SET_ERR_STS);
+       BNAD_GET_REG(LUT1_ERR_STS);
+       BNAD_GET_REG(LUT1_SET_ERR_STS);
+
+       /* TRC Registers */
+       BNAD_GET_REG(TRC_CTL_REG);
+       BNAD_GET_REG(TRC_MODS_REG);
+       BNAD_GET_REG(TRC_TRGC_REG);
+       BNAD_GET_REG(TRC_CNT1_REG);
+       BNAD_GET_REG(TRC_CNT2_REG);
+       BNAD_GET_REG(TRC_NXTS_REG);
+       BNAD_GET_REG(TRC_DIRR_REG);
+       for (i = 0; i < 10; i++)
+               BNAD_GET_REG(TRC_TRGM_REG(i));
+       for (i = 0; i < 10; i++)
+               BNAD_GET_REG(TRC_NXTM_REG(i));
+       for (i = 0; i < 10; i++)
+               BNAD_GET_REG(TRC_STRM_REG(i));
+
+       spin_unlock_irqrestore(&bnad->bna_lock, flags);
+#undef BNAD_GET_REG
+       return num;
+}
+static int
+bnad_get_regs_len(struct net_device *netdev)
+{
+       int ret = get_regs(netdev_priv(netdev), NULL) * sizeof(u32);
+       return ret;
+}
+
+static void
+bnad_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *buf)
+{
+       memset(buf, 0, bnad_get_regs_len(netdev));
+       get_regs(netdev_priv(netdev), buf);
+}
+
+static void
+bnad_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wolinfo)
+{
+       wolinfo->supported = 0;
+       wolinfo->wolopts = 0;
+}
+
+static int
+bnad_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce)
+{
+       struct bnad *bnad = netdev_priv(netdev);
+       unsigned long flags;
+
+       /* Lock rqd. to access bnad->bna_lock */
+       spin_lock_irqsave(&bnad->bna_lock, flags);
+       coalesce->use_adaptive_rx_coalesce =
+               (bnad->cfg_flags & BNAD_CF_DIM_ENABLED) ? true : false;
+       spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+       coalesce->rx_coalesce_usecs = bnad->rx_coalescing_timeo *
+                                       BFI_COALESCING_TIMER_UNIT;
+       coalesce->tx_coalesce_usecs = bnad->tx_coalescing_timeo *
+                                       BFI_COALESCING_TIMER_UNIT;
+       coalesce->tx_max_coalesced_frames = BFI_TX_INTERPKT_COUNT;
+
+       return 0;
+}
+
+static int
+bnad_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce)
+{
+       struct bnad *bnad = netdev_priv(netdev);
+       unsigned long flags;
+       int dim_timer_del = 0;
+
+       if (coalesce->rx_coalesce_usecs == 0 ||
+           coalesce->rx_coalesce_usecs >
+           BFI_MAX_COALESCING_TIMEO * BFI_COALESCING_TIMER_UNIT)
+               return -EINVAL;
+
+       if (coalesce->tx_coalesce_usecs == 0 ||
+           coalesce->tx_coalesce_usecs >
+           BFI_MAX_COALESCING_TIMEO * BFI_COALESCING_TIMER_UNIT)
+               return -EINVAL;
+
+       mutex_lock(&bnad->conf_mutex);
+       /*
+        * Do not need to store rx_coalesce_usecs here
+        * Every time DIM is disabled, we can get it from the
+        * stack.
+        */
+       spin_lock_irqsave(&bnad->bna_lock, flags);
+       if (coalesce->use_adaptive_rx_coalesce) {
+               if (!(bnad->cfg_flags & BNAD_CF_DIM_ENABLED)) {
+                       bnad->cfg_flags |= BNAD_CF_DIM_ENABLED;
+                       bnad_dim_timer_start(bnad);
+               }
+       } else {
+               if (bnad->cfg_flags & BNAD_CF_DIM_ENABLED) {
+                       bnad->cfg_flags &= ~BNAD_CF_DIM_ENABLED;
+                       dim_timer_del = bnad_dim_timer_running(bnad);
+                       if (dim_timer_del) {
+                               clear_bit(BNAD_RF_DIM_TIMER_RUNNING,
+                                                       &bnad->run_flags);
+                               spin_unlock_irqrestore(&bnad->bna_lock, flags);
+                               del_timer_sync(&bnad->dim_timer);
+                               spin_lock_irqsave(&bnad->bna_lock, flags);
+                       }
+                       bnad_rx_coalescing_timeo_set(bnad);
+               }
+       }
+       if (bnad->tx_coalescing_timeo != coalesce->tx_coalesce_usecs /
+                                       BFI_COALESCING_TIMER_UNIT) {
+               bnad->tx_coalescing_timeo = coalesce->tx_coalesce_usecs /
+                                               BFI_COALESCING_TIMER_UNIT;
+               bnad_tx_coalescing_timeo_set(bnad);
+       }
+
+       if (bnad->rx_coalescing_timeo != coalesce->rx_coalesce_usecs /
+                                       BFI_COALESCING_TIMER_UNIT) {
+               bnad->rx_coalescing_timeo = coalesce->rx_coalesce_usecs /
+                                               BFI_COALESCING_TIMER_UNIT;
+
+               if (!(bnad->cfg_flags & BNAD_CF_DIM_ENABLED))
+                       bnad_rx_coalescing_timeo_set(bnad);
+
+       }
+
+       /* Add Tx Inter-pkt DMA count?  */
+
+       spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+       mutex_unlock(&bnad->conf_mutex);
+       return 0;
+}
+
+static void
+bnad_get_ringparam(struct net_device *netdev,
+                  struct ethtool_ringparam *ringparam)
+{
+       struct bnad *bnad = netdev_priv(netdev);
+
+       ringparam->rx_max_pending = BNAD_MAX_Q_DEPTH / bnad_rxqs_per_cq;
+       ringparam->rx_mini_max_pending = 0;
+       ringparam->rx_jumbo_max_pending = 0;
+       ringparam->tx_max_pending = BNAD_MAX_Q_DEPTH;
+
+       ringparam->rx_pending = bnad->rxq_depth;
+       ringparam->rx_mini_max_pending = 0;
+       ringparam->rx_jumbo_max_pending = 0;
+       ringparam->tx_pending = bnad->txq_depth;
+}
+
+static int
+bnad_set_ringparam(struct net_device *netdev,
+                  struct ethtool_ringparam *ringparam)
+{
+       int i, current_err, err = 0;
+       struct bnad *bnad = netdev_priv(netdev);
+
+       mutex_lock(&bnad->conf_mutex);
+       if (ringparam->rx_pending == bnad->rxq_depth &&
+           ringparam->tx_pending == bnad->txq_depth) {
+               mutex_unlock(&bnad->conf_mutex);
+               return 0;
+       }
+
+       if (ringparam->rx_pending < BNAD_MIN_Q_DEPTH ||
+           ringparam->rx_pending > BNAD_MAX_Q_DEPTH / bnad_rxqs_per_cq ||
+           !BNA_POWER_OF_2(ringparam->rx_pending)) {
+               mutex_unlock(&bnad->conf_mutex);
+               return -EINVAL;
+       }
+       if (ringparam->tx_pending < BNAD_MIN_Q_DEPTH ||
+           ringparam->tx_pending > BNAD_MAX_Q_DEPTH ||
+           !BNA_POWER_OF_2(ringparam->tx_pending)) {
+               mutex_unlock(&bnad->conf_mutex);
+               return -EINVAL;
+       }
+
+       if (ringparam->rx_pending != bnad->rxq_depth) {
+               bnad->rxq_depth = ringparam->rx_pending;
+               for (i = 0; i < bnad->num_rx; i++) {
+                       if (!bnad->rx_info[i].rx)
+                               continue;
+                       bnad_cleanup_rx(bnad, i);
+                       current_err = bnad_setup_rx(bnad, i);
+                       if (current_err && !err)
+                               err = current_err;
+               }
+       }
+       if (ringparam->tx_pending != bnad->txq_depth) {
+               bnad->txq_depth = ringparam->tx_pending;
+               for (i = 0; i < bnad->num_tx; i++) {
+                       if (!bnad->tx_info[i].tx)
+                               continue;
+                       bnad_cleanup_tx(bnad, i);
+                       current_err = bnad_setup_tx(bnad, i);
+                       if (current_err && !err)
+                               err = current_err;
+               }
+       }
+
+       mutex_unlock(&bnad->conf_mutex);
+       return err;
+}
+
+static void
+bnad_get_pauseparam(struct net_device *netdev,
+                   struct ethtool_pauseparam *pauseparam)
+{
+       struct bnad *bnad = netdev_priv(netdev);
+
+       pauseparam->autoneg = 0;
+       pauseparam->rx_pause = bnad->bna.port.pause_config.rx_pause;
+       pauseparam->tx_pause = bnad->bna.port.pause_config.tx_pause;
+}
+
+static int
+bnad_set_pauseparam(struct net_device *netdev,
+                   struct ethtool_pauseparam *pauseparam)
+{
+       struct bnad *bnad = netdev_priv(netdev);
+       struct bna_pause_config pause_config;
+       unsigned long flags;
+
+       if (pauseparam->autoneg == AUTONEG_ENABLE)
+               return -EINVAL;
+
+       mutex_lock(&bnad->conf_mutex);
+       if (pauseparam->rx_pause != bnad->bna.port.pause_config.rx_pause ||
+           pauseparam->tx_pause != bnad->bna.port.pause_config.tx_pause) {
+               pause_config.rx_pause = pauseparam->rx_pause;
+               pause_config.tx_pause = pauseparam->tx_pause;
+               spin_lock_irqsave(&bnad->bna_lock, flags);
+               bna_port_pause_config(&bnad->bna.port, &pause_config, NULL);
+               spin_unlock_irqrestore(&bnad->bna_lock, flags);
+       }
+       mutex_unlock(&bnad->conf_mutex);
+       return 0;
+}
+
+static u32
+bnad_get_rx_csum(struct net_device *netdev)
+{
+       u32 rx_csum;
+       struct bnad *bnad = netdev_priv(netdev);
+
+       rx_csum = bnad->rx_csum;
+       return rx_csum;
+}
+
+static int
+bnad_set_rx_csum(struct net_device *netdev, u32 rx_csum)
+{
+       struct bnad *bnad = netdev_priv(netdev);
+
+       mutex_lock(&bnad->conf_mutex);
+       bnad->rx_csum = rx_csum;
+       mutex_unlock(&bnad->conf_mutex);
+       return 0;
+}
+
+static int
+bnad_set_tx_csum(struct net_device *netdev, u32 tx_csum)
+{
+       struct bnad *bnad = netdev_priv(netdev);
+
+       mutex_lock(&bnad->conf_mutex);
+       if (tx_csum) {
+               netdev->features |= NETIF_F_IP_CSUM;
+               netdev->features |= NETIF_F_IPV6_CSUM;
+       } else {
+               netdev->features &= ~NETIF_F_IP_CSUM;
+               netdev->features &= ~NETIF_F_IPV6_CSUM;
+       }
+       mutex_unlock(&bnad->conf_mutex);
+       return 0;
+}
+
+static int
+bnad_set_tso(struct net_device *netdev, u32 tso)
+{
+       struct bnad *bnad = netdev_priv(netdev);
+
+       mutex_lock(&bnad->conf_mutex);
+       if (tso) {
+               netdev->features |= NETIF_F_TSO;
+               netdev->features |= NETIF_F_TSO6;
+       } else {
+               netdev->features &= ~NETIF_F_TSO;
+               netdev->features &= ~NETIF_F_TSO6;
+       }
+       mutex_unlock(&bnad->conf_mutex);
+       return 0;
+}
+
+static void
+bnad_get_strings(struct net_device *netdev, u32 stringset, u8 * string)
+{
+       struct bnad *bnad = netdev_priv(netdev);
+       int i, j, q_num;
+       u64 bmap;
+
+       mutex_lock(&bnad->conf_mutex);
+
+       switch (stringset) {
+       case ETH_SS_STATS:
+               for (i = 0; i < BNAD_ETHTOOL_STATS_NUM; i++) {
+                       BUG_ON(!(strlen(bnad_net_stats_strings[i]) <
+                                  ETH_GSTRING_LEN));
+                       memcpy(string, bnad_net_stats_strings[i],
+                              ETH_GSTRING_LEN);
+                       string += ETH_GSTRING_LEN;
+               }
+               bmap = (u64)bnad->bna.tx_mod.txf_bmap[0] |
+                       ((u64)bnad->bna.tx_mod.txf_bmap[1] << 32);
+               for (i = 0; bmap && (i < BFI_LL_TXF_ID_MAX); i++) {
+                       if (bmap & 1) {
+                               sprintf(string, "txf%d_ucast_octets", i);
+                               string += ETH_GSTRING_LEN;
+                               sprintf(string, "txf%d_ucast", i);
+                               string += ETH_GSTRING_LEN;
+                               sprintf(string, "txf%d_ucast_vlan", i);
+                               string += ETH_GSTRING_LEN;
+                               sprintf(string, "txf%d_mcast_octets", i);
+                               string += ETH_GSTRING_LEN;
+                               sprintf(string, "txf%d_mcast", i);
+                               string += ETH_GSTRING_LEN;
+                               sprintf(string, "txf%d_mcast_vlan", i);
+                               string += ETH_GSTRING_LEN;
+                               sprintf(string, "txf%d_bcast_octets", i);
+                               string += ETH_GSTRING_LEN;
+                               sprintf(string, "txf%d_bcast", i);
+                               string += ETH_GSTRING_LEN;
+                               sprintf(string, "txf%d_bcast_vlan", i);
+                               string += ETH_GSTRING_LEN;
+                               sprintf(string, "txf%d_errors", i);
+                               string += ETH_GSTRING_LEN;
+                               sprintf(string, "txf%d_filter_vlan", i);
+                               string += ETH_GSTRING_LEN;
+                               sprintf(string, "txf%d_filter_mac_sa", i);
+                               string += ETH_GSTRING_LEN;
+                       }
+                       bmap >>= 1;
+               }
+
+               bmap = (u64)bnad->bna.rx_mod.rxf_bmap[0] |
+                       ((u64)bnad->bna.rx_mod.rxf_bmap[1] << 32);
+               for (i = 0; bmap && (i < BFI_LL_RXF_ID_MAX); i++) {
+                       if (bmap & 1) {
+                               sprintf(string, "rxf%d_ucast_octets", i);
+                               string += ETH_GSTRING_LEN;
+                               sprintf(string, "rxf%d_ucast", i);
+                               string += ETH_GSTRING_LEN;
+                               sprintf(string, "rxf%d_ucast_vlan", i);
+                               string += ETH_GSTRING_LEN;
+                               sprintf(string, "rxf%d_mcast_octets", i);
+                               string += ETH_GSTRING_LEN;
+                               sprintf(string, "rxf%d_mcast", i);
+                               string += ETH_GSTRING_LEN;
+                               sprintf(string, "rxf%d_mcast_vlan", i);
+                               string += ETH_GSTRING_LEN;
+                               sprintf(string, "rxf%d_bcast_octets", i);
+                               string += ETH_GSTRING_LEN;
+                               sprintf(string, "rxf%d_bcast", i);
+                               string += ETH_GSTRING_LEN;
+                               sprintf(string, "rxf%d_bcast_vlan", i);
+                               string += ETH_GSTRING_LEN;
+                               sprintf(string, "rxf%d_frame_drops", i);
+                               string += ETH_GSTRING_LEN;
+                       }
+                       bmap >>= 1;
+               }
+
+               q_num = 0;
+               for (i = 0; i < bnad->num_rx; i++) {
+                       if (!bnad->rx_info[i].rx)
+                               continue;
+                       for (j = 0; j < bnad->num_rxp_per_rx; j++) {
+                               sprintf(string, "cq%d_producer_index", q_num);
+                               string += ETH_GSTRING_LEN;
+                               sprintf(string, "cq%d_consumer_index", q_num);
+                               string += ETH_GSTRING_LEN;
+                               sprintf(string, "cq%d_hw_producer_index",
+                                       q_num);
+                               string += ETH_GSTRING_LEN;
+                               q_num++;
+                       }
+               }
+
+               q_num = 0;
+               for (i = 0; i < bnad->num_rx; i++) {
+                       if (!bnad->rx_info[i].rx)
+                               continue;
+                       for (j = 0; j < bnad->num_rxp_per_rx; j++) {
+                               sprintf(string, "rxq%d_packets", q_num);
+                               string += ETH_GSTRING_LEN;
+                               sprintf(string, "rxq%d_bytes", q_num);
+                               string += ETH_GSTRING_LEN;
+                               sprintf(string, "rxq%d_packets_with_error",
+                                                               q_num);
+                               string += ETH_GSTRING_LEN;
+                               sprintf(string, "rxq%d_allocbuf_failed", q_num);
+                               string += ETH_GSTRING_LEN;
+                               sprintf(string, "rxq%d_producer_index", q_num);
+                               string += ETH_GSTRING_LEN;
+                               sprintf(string, "rxq%d_consumer_index", q_num);
+                               string += ETH_GSTRING_LEN;
+                               q_num++;
+                               if (bnad->rx_info[i].rx_ctrl[j].ccb &&
+                                       bnad->rx_info[i].rx_ctrl[j].ccb->
+                                       rcb[1] &&
+                                       bnad->rx_info[i].rx_ctrl[j].ccb->
+                                       rcb[1]->rxq) {
+                                       sprintf(string, "rxq%d_packets", q_num);
+                                       string += ETH_GSTRING_LEN;
+                                       sprintf(string, "rxq%d_bytes", q_num);
+                                       string += ETH_GSTRING_LEN;
+                                       sprintf(string,
+                                       "rxq%d_packets_with_error", q_num);
+                                       string += ETH_GSTRING_LEN;
+                                       sprintf(string, "rxq%d_allocbuf_failed",
+                                                               q_num);
+                                       string += ETH_GSTRING_LEN;
+                                       sprintf(string, "rxq%d_producer_index",
+                                                               q_num);
+                                       string += ETH_GSTRING_LEN;
+                                       sprintf(string, "rxq%d_consumer_index",
+                                                               q_num);
+                                       string += ETH_GSTRING_LEN;
+                                       q_num++;
+                               }
+                       }
+               }
+
+               q_num = 0;
+               for (i = 0; i < bnad->num_tx; i++) {
+                       if (!bnad->tx_info[i].tx)
+                               continue;
+                       for (j = 0; j < bnad->num_txq_per_tx; j++) {
+                               sprintf(string, "txq%d_packets", q_num);
+                               string += ETH_GSTRING_LEN;
+                               sprintf(string, "txq%d_bytes", q_num);
+                               string += ETH_GSTRING_LEN;
+                               sprintf(string, "txq%d_producer_index", q_num);
+                               string += ETH_GSTRING_LEN;
+                               sprintf(string, "txq%d_consumer_index", q_num);
+                               string += ETH_GSTRING_LEN;
+                               sprintf(string, "txq%d_hw_consumer_index",
+                                                                       q_num);
+                               string += ETH_GSTRING_LEN;
+                               q_num++;
+                       }
+               }
+
+               break;
+
+       default:
+               break;
+       }
+
+       mutex_unlock(&bnad->conf_mutex);
+}
+
+static int
+bnad_get_stats_count_locked(struct net_device *netdev)
+{
+       struct bnad *bnad = netdev_priv(netdev);
+       int i, j, count, rxf_active_num = 0, txf_active_num = 0;
+       u64 bmap;
+
+       bmap = (u64)bnad->bna.tx_mod.txf_bmap[0] |
+                       ((u64)bnad->bna.tx_mod.txf_bmap[1] << 32);
+       for (i = 0; bmap && (i < BFI_LL_TXF_ID_MAX); i++) {
+               if (bmap & 1)
+                       txf_active_num++;
+               bmap >>= 1;
+       }
+       bmap = (u64)bnad->bna.rx_mod.rxf_bmap[0] |
+                       ((u64)bnad->bna.rx_mod.rxf_bmap[1] << 32);
+       for (i = 0; bmap && (i < BFI_LL_RXF_ID_MAX); i++) {
+               if (bmap & 1)
+                       rxf_active_num++;
+               bmap >>= 1;
+       }
+       count = BNAD_ETHTOOL_STATS_NUM +
+               txf_active_num * BNAD_NUM_TXF_COUNTERS +
+               rxf_active_num * BNAD_NUM_RXF_COUNTERS;
+
+       for (i = 0; i < bnad->num_rx; i++) {
+               if (!bnad->rx_info[i].rx)
+                       continue;
+               count += bnad->num_rxp_per_rx * BNAD_NUM_CQ_COUNTERS;
+               count += bnad->num_rxp_per_rx * BNAD_NUM_RXQ_COUNTERS;
+               for (j = 0; j < bnad->num_rxp_per_rx; j++)
+                       if (bnad->rx_info[i].rx_ctrl[j].ccb &&
+                               bnad->rx_info[i].rx_ctrl[j].ccb->rcb[1] &&
+                               bnad->rx_info[i].rx_ctrl[j].ccb->rcb[1]->rxq)
+                               count +=  BNAD_NUM_RXQ_COUNTERS;
+       }
+
+       for (i = 0; i < bnad->num_tx; i++) {
+               if (!bnad->tx_info[i].tx)
+                       continue;
+               count += bnad->num_txq_per_tx * BNAD_NUM_TXQ_COUNTERS;
+       }
+       return count;
+}
+
+static int
+bnad_per_q_stats_fill(struct bnad *bnad, u64 *buf, int bi)
+{
+       int i, j;
+       struct bna_rcb *rcb = NULL;
+       struct bna_tcb *tcb = NULL;
+
+       for (i = 0; i < bnad->num_rx; i++) {
+               if (!bnad->rx_info[i].rx)
+                       continue;
+               for (j = 0; j < bnad->num_rxp_per_rx; j++)
+                       if (bnad->rx_info[i].rx_ctrl[j].ccb &&
+                               bnad->rx_info[i].rx_ctrl[j].ccb->rcb[0] &&
+                               bnad->rx_info[i].rx_ctrl[j].ccb->rcb[0]->rxq) {
+                               buf[bi++] = bnad->rx_info[i].rx_ctrl[j].
+                                               ccb->producer_index;
+                               buf[bi++] = 0; /* ccb->consumer_index */
+                               buf[bi++] = *(bnad->rx_info[i].rx_ctrl[j].
+                                               ccb->hw_producer_index);
+                       }
+       }
+       for (i = 0; i < bnad->num_rx; i++) {
+               if (!bnad->rx_info[i].rx)
+                       continue;
+               for (j = 0; j < bnad->num_rxp_per_rx; j++)
+                       if (bnad->rx_info[i].rx_ctrl[j].ccb) {
+                               if (bnad->rx_info[i].rx_ctrl[j].ccb->rcb[0] &&
+                                       bnad->rx_info[i].rx_ctrl[j].ccb->
+                                       rcb[0]->rxq) {
+                                       rcb = bnad->rx_info[i].rx_ctrl[j].
+                                                       ccb->rcb[0];
+                                       buf[bi++] = rcb->rxq->rx_packets;
+                                       buf[bi++] = rcb->rxq->rx_bytes;
+                                       buf[bi++] = rcb->rxq->
+                                                       rx_packets_with_error;
+                                       buf[bi++] = rcb->rxq->
+                                                       rxbuf_alloc_failed;
+                                       buf[bi++] = rcb->producer_index;
+                                       buf[bi++] = rcb->consumer_index;
+                               }
+                               if (bnad->rx_info[i].rx_ctrl[j].ccb->rcb[1] &&
+                                       bnad->rx_info[i].rx_ctrl[j].ccb->
+                                       rcb[1]->rxq) {
+                                       rcb = bnad->rx_info[i].rx_ctrl[j].
+                                                               ccb->rcb[1];
+                                       buf[bi++] = rcb->rxq->rx_packets;
+                                       buf[bi++] = rcb->rxq->rx_bytes;
+                                       buf[bi++] = rcb->rxq->
+                                                       rx_packets_with_error;
+                                       buf[bi++] = rcb->rxq->
+                                                       rxbuf_alloc_failed;
+                                       buf[bi++] = rcb->producer_index;
+                                       buf[bi++] = rcb->consumer_index;
+                               }
+                       }
+       }
+
+       for (i = 0; i < bnad->num_tx; i++) {
+               if (!bnad->tx_info[i].tx)
+                       continue;
+               for (j = 0; j < bnad->num_txq_per_tx; j++)
+                       if (bnad->tx_info[i].tcb[j] &&
+                               bnad->tx_info[i].tcb[j]->txq) {
+                               tcb = bnad->tx_info[i].tcb[j];
+                               buf[bi++] = tcb->txq->tx_packets;
+                               buf[bi++] = tcb->txq->tx_bytes;
+                               buf[bi++] = tcb->producer_index;
+                               buf[bi++] = tcb->consumer_index;
+                               buf[bi++] = *(tcb->hw_consumer_index);
+                       }
+       }
+
+       return bi;
+}
+
+static void
+bnad_get_ethtool_stats(struct net_device *netdev, struct ethtool_stats *stats,
+                      u64 *buf)
+{
+       struct bnad *bnad = netdev_priv(netdev);
+       int i, j, bi;
+       unsigned long flags;
+       struct rtnl_link_stats64 *net_stats64;
+       u64 *stats64;
+       u64 bmap;
+
+       mutex_lock(&bnad->conf_mutex);
+       if (bnad_get_stats_count_locked(netdev) != stats->n_stats) {
+               mutex_unlock(&bnad->conf_mutex);
+               return;
+       }
+
+       /*
+        * Used bna_lock to sync reads from bna_stats, which is written
+        * under the same lock
+        */
+       spin_lock_irqsave(&bnad->bna_lock, flags);
+       bi = 0;
+       memset(buf, 0, stats->n_stats * sizeof(u64));
+
+       net_stats64 = (struct rtnl_link_stats64 *)buf;
+       bnad_netdev_qstats_fill(bnad, net_stats64);
+       bnad_netdev_hwstats_fill(bnad, net_stats64);
+
+       bi = sizeof(*net_stats64) / sizeof(u64);
+
+       /* Fill driver stats into ethtool buffers */
+       stats64 = (u64 *)&bnad->stats.drv_stats;
+       for (i = 0; i < sizeof(struct bnad_drv_stats) / sizeof(u64); i++)
+               buf[bi++] = stats64[i];
+
+       /* Fill hardware stats excluding the rxf/txf into ethtool bufs */
+       stats64 = (u64 *) bnad->stats.bna_stats->hw_stats;
+       for (i = 0;
+            i < offsetof(struct bfi_ll_stats, rxf_stats[0]) / sizeof(u64);
+            i++)
+               buf[bi++] = stats64[i];
+
+       /* Fill txf stats into ethtool buffers */
+       bmap = (u64)bnad->bna.tx_mod.txf_bmap[0] |
+                       ((u64)bnad->bna.tx_mod.txf_bmap[1] << 32);
+       for (i = 0; bmap && (i < BFI_LL_TXF_ID_MAX); i++) {
+               if (bmap & 1) {
+                       stats64 = (u64 *)&bnad->stats.bna_stats->
+                                               hw_stats->txf_stats[i];
+                       for (j = 0; j < sizeof(struct bfi_ll_stats_txf) /
+                                       sizeof(u64); j++)
+                               buf[bi++] = stats64[j];
+               }
+               bmap >>= 1;
+       }
+
+       /*  Fill rxf stats into ethtool buffers */
+       bmap = (u64)bnad->bna.rx_mod.rxf_bmap[0] |
+                       ((u64)bnad->bna.rx_mod.rxf_bmap[1] << 32);
+       for (i = 0; bmap && (i < BFI_LL_RXF_ID_MAX); i++) {
+               if (bmap & 1) {
+                       stats64 = (u64 *)&bnad->stats.bna_stats->
+                                               hw_stats->rxf_stats[i];
+                       for (j = 0; j < sizeof(struct bfi_ll_stats_rxf) /
+                                       sizeof(u64); j++)
+                               buf[bi++] = stats64[j];
+               }
+               bmap >>= 1;
+       }
+
+       /* Fill per Q stats into ethtool buffers */
+       bi = bnad_per_q_stats_fill(bnad, buf, bi);
+
+       spin_unlock_irqrestore(&bnad->bna_lock, flags);
+
+       mutex_unlock(&bnad->conf_mutex);
+}
+
+static int
+bnad_get_sset_count(struct net_device *netdev, int sset)
+{
+       switch (sset) {
+       case ETH_SS_STATS:
+               return bnad_get_stats_count_locked(netdev);
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
+static struct ethtool_ops bnad_ethtool_ops = {
+       .get_settings = bnad_get_settings,
+       .set_settings = bnad_set_settings,
+       .get_drvinfo = bnad_get_drvinfo,
+       .get_regs_len = bnad_get_regs_len,
+       .get_regs = bnad_get_regs,
+       .get_wol = bnad_get_wol,
+       .get_link = ethtool_op_get_link,
+       .get_coalesce = bnad_get_coalesce,
+       .set_coalesce = bnad_set_coalesce,
+       .get_ringparam = bnad_get_ringparam,
+       .set_ringparam = bnad_set_ringparam,
+       .get_pauseparam = bnad_get_pauseparam,
+       .set_pauseparam = bnad_set_pauseparam,
+       .get_rx_csum = bnad_get_rx_csum,
+       .set_rx_csum = bnad_set_rx_csum,
+       .get_tx_csum = ethtool_op_get_tx_csum,
+       .set_tx_csum = bnad_set_tx_csum,
+       .get_sg = ethtool_op_get_sg,
+       .set_sg = ethtool_op_set_sg,
+       .get_tso = ethtool_op_get_tso,
+       .set_tso = bnad_set_tso,
+       .get_strings = bnad_get_strings,
+       .get_ethtool_stats = bnad_get_ethtool_stats,
+       .get_sset_count = bnad_get_sset_count
+};
+
+void
+bnad_set_ethtool_ops(struct net_device *netdev)
+{
+       SET_ETHTOOL_OPS(netdev, &bnad_ethtool_ops);
+}
diff --git a/drivers/net/bna/cna.h b/drivers/net/bna/cna.h
new file mode 100644 (file)
index 0000000..bbd39dc
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * 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.
+ */
+/*
+ * Copyright (c) 2006-2010 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+
+#ifndef __CNA_H__
+#define __CNA_H__
+
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/bitops.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/if_ether.h>
+#include <asm/page.h>
+#include <asm/io.h>
+#include <asm/string.h>
+
+#include <linux/list.h>
+
+#define bfa_sm_fault(__mod, __event)    do {                            \
+       pr_err("SM Assertion failure: %s: %d: event = %d", __FILE__, __LINE__, \
+               __event); \
+} while (0)
+
+extern char bfa_version[];
+
+#define        CNA_FW_FILE_CT  "ctfw_cna.bin"
+#define FC_SYMNAME_MAX 256     /*!< max name server symbolic name size */
+
+#pragma pack(1)
+
+#define MAC_ADDRLEN    (6)
+typedef struct mac { u8 mac[MAC_ADDRLEN]; } mac_t;
+
+#pragma pack()
+
+#define bfa_q_first(_q) ((void *)(((struct list_head *) (_q))->next))
+#define bfa_q_next(_qe)        (((struct list_head *) (_qe))->next)
+#define bfa_q_prev(_qe) (((struct list_head *) (_qe))->prev)
+
+/*
+ * bfa_q_qe_init - to initialize a queue element
+ */
+#define bfa_q_qe_init(_qe) {                                           \
+       bfa_q_next(_qe) = (struct list_head *) NULL;                    \
+       bfa_q_prev(_qe) = (struct list_head *) NULL;                    \
+}
+
+/*
+ * bfa_q_deq - dequeue an element from head of the queue
+ */
+#define bfa_q_deq(_q, _qe) {                                           \
+       if (!list_empty(_q)) {                                          \
+               (*((struct list_head **) (_qe))) = bfa_q_next(_q);      \
+               bfa_q_prev(bfa_q_next(*((struct list_head **) _qe))) =  \
+                                               (struct list_head *) (_q); \
+               bfa_q_next(_q) = bfa_q_next(*((struct list_head **) _qe)); \
+               bfa_q_qe_init(*((struct list_head **) _qe));            \
+       } else {                                                        \
+               *((struct list_head **) (_qe)) = (struct list_head *) NULL; \
+       }                                                               \
+}
+
+#endif /* __CNA_H__ */
diff --git a/drivers/net/bna/cna_fwimg.c b/drivers/net/bna/cna_fwimg.c
new file mode 100644 (file)
index 0000000..0bd1d37
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * 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.
+ */
+/*
+ * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+#include <linux/firmware.h>
+#include "cna.h"
+
+const struct firmware *bfi_fw;
+static u32 *bfi_image_ct_cna;
+static u32 bfi_image_ct_cna_size;
+
+u32 *
+cna_read_firmware(struct pci_dev *pdev, u32 **bfi_image,
+                       u32 *bfi_image_size, char *fw_name)
+{
+       const struct firmware *fw;
+
+       if (request_firmware(&fw, fw_name, &pdev->dev)) {
+               pr_alert("Can't locate firmware %s\n", fw_name);
+               goto error;
+       }
+
+       *bfi_image = (u32 *)fw->data;
+       *bfi_image_size = fw->size/sizeof(u32);
+       bfi_fw = fw;
+
+       return *bfi_image;
+error:
+       return NULL;
+}
+
+u32 *
+cna_get_firmware_buf(struct pci_dev *pdev)
+{
+       if (bfi_image_ct_cna_size == 0)
+               cna_read_firmware(pdev, &bfi_image_ct_cna,
+                       &bfi_image_ct_cna_size, CNA_FW_FILE_CT);
+       return bfi_image_ct_cna;
+}
+
+u32 *
+bfa_cb_image_get_chunk(int type, u32 off)
+{
+       return (u32 *)(bfi_image_ct_cna + off);
+}
+
+u32
+bfa_cb_image_get_size(int type)
+{
+       return bfi_image_ct_cna_size;
+}
index e6a803f1c507f848ee8b4ac28ddb4ce8fc138c44..4ff76e38e788b4e12b6b53c496d6968e5a7d973b 100644 (file)
@@ -49,6 +49,7 @@
 #include <linux/cache.h>
 #include <linux/firmware.h>
 #include <linux/log2.h>
+#include <linux/aer.h>
 
 #if defined(CONFIG_CNIC) || defined(CONFIG_CNIC_MODULE)
 #define BCM_CNIC 1
@@ -3217,7 +3218,7 @@ bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
 
                }
 
-               skb->ip_summed = CHECKSUM_NONE;
+               skb_checksum_none_assert(skb);
                if (bp->rx_csum &&
                        (status & (L2_FHDR_STATUS_TCP_SEGMENT |
                        L2_FHDR_STATUS_UDP_DATAGRAM))) {
@@ -7890,6 +7891,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
        int rc, i, j;
        u32 reg;
        u64 dma_mask, persist_dma_mask;
+       int err;
 
        SET_NETDEV_DEV(dev, &pdev->dev);
        bp = netdev_priv(dev);
@@ -7925,6 +7927,14 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
                goto err_out_disable;
        }
 
+       /* AER (Advanced Error Reporting) hooks */
+       err = pci_enable_pcie_error_reporting(pdev);
+       if (err) {
+               dev_err(&pdev->dev, "pci_enable_pcie_error_reporting failed "
+                                   "0x%x\n", err);
+               /* non-fatal, continue */
+       }
+
        pci_set_master(pdev);
        pci_save_state(pdev);
 
@@ -8246,6 +8256,7 @@ err_out_unmap:
        }
 
 err_out_release:
+       pci_disable_pcie_error_reporting(pdev);
        pci_release_regions(pdev);
 
 err_out_disable:
@@ -8436,6 +8447,9 @@ bnx2_remove_one(struct pci_dev *pdev)
        kfree(bp->temp_stats_blk);
 
        free_netdev(dev);
+
+       pci_disable_pcie_error_reporting(pdev);
+
        pci_release_regions(pdev);
        pci_disable_device(pdev);
        pci_set_drvdata(pdev, NULL);
@@ -8527,25 +8541,35 @@ static pci_ers_result_t bnx2_io_slot_reset(struct pci_dev *pdev)
 {
        struct net_device *dev = pci_get_drvdata(pdev);
        struct bnx2 *bp = netdev_priv(dev);
+       pci_ers_result_t result;
+       int err;
 
        rtnl_lock();
        if (pci_enable_device(pdev)) {
                dev_err(&pdev->dev,
                        "Cannot re-enable PCI device after reset\n");
-               rtnl_unlock();
-               return PCI_ERS_RESULT_DISCONNECT;
+               result = PCI_ERS_RESULT_DISCONNECT;
+       } else {
+               pci_set_master(pdev);
+               pci_restore_state(pdev);
+               pci_save_state(pdev);
+
+               if (netif_running(dev)) {
+                       bnx2_set_power_state(bp, PCI_D0);
+                       bnx2_init_nic(bp, 1);
+               }
+               result = PCI_ERS_RESULT_RECOVERED;
        }
-       pci_set_master(pdev);
-       pci_restore_state(pdev);
-       pci_save_state(pdev);
+       rtnl_unlock();
 
-       if (netif_running(dev)) {
-               bnx2_set_power_state(bp, PCI_D0);
-               bnx2_init_nic(bp, 1);
+       err = pci_cleanup_aer_uncorrect_error_status(pdev);
+       if (err) {
+               dev_err(&pdev->dev,
+                       "pci_cleanup_aer_uncorrect_error_status failed 0x%0x\n",
+                        err); /* non-fatal, continue */
        }
 
-       rtnl_unlock();
-       return PCI_ERS_RESULT_RECOVERED;
+       return result;
 }
 
 /**
index 0c2d96ed561c46ebd63f3c03c119c0751b5204e1..b6aaf22a1b84045a52fed00b9dc6927fb059ebf7 100644 (file)
@@ -20,8 +20,8 @@
  * (you will need to reboot afterwards) */
 /* #define BNX2X_STOP_ON_ERROR */
 
-#define DRV_MODULE_VERSION      "1.52.53-4"
-#define DRV_MODULE_RELDATE      "2010/16/08"
+#define DRV_MODULE_VERSION      "1.52.53-6"
+#define DRV_MODULE_RELDATE      "2010/09/07"
 #define BNX2X_BC_VER            0x040200
 
 #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
@@ -566,13 +566,13 @@ struct bnx2x_common {
 struct bnx2x_port {
        u32                     pmf;
 
-       u32                     link_config;
+       u32                     link_config[LINK_CONFIG_SIZE];
 
-       u32                     supported;
+       u32                     supported[LINK_CONFIG_SIZE];
 /* link settings - missing defines */
 #define SUPPORTED_2500baseX_Full       (1 << 15)
 
-       u32                     advertising;
+       u32                     advertising[LINK_CONFIG_SIZE];
 /* link settings - missing defines */
 #define ADVERTISED_2500baseX_Full      (1 << 15)
 
@@ -931,7 +931,7 @@ void bnx2x_write_dmae(struct bnx2x *bp, dma_addr_t dma_addr, u32 dst_addr,
 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_gpio_int(struct bnx2x *bp, int gpio_num, u32 mode, u8 port);
-u32 bnx2x_fw_command(struct bnx2x *bp, u32 command);
+u32 bnx2x_fw_command(struct bnx2x *bp, u32 command, u32 param);
 void bnx2x_reg_wr_ind(struct bnx2x *bp, u32 addr, u32 val);
 void bnx2x_write_dmae_phys_len(struct bnx2x *bp, dma_addr_t phys_addr,
                               u32 addr, u32 len);
@@ -939,7 +939,7 @@ void bnx2x_calc_fc_adv(struct bnx2x *bp);
 int bnx2x_sp_post(struct bnx2x *bp, int command, int cid,
                  u32 data_hi, u32 data_lo, int common);
 void bnx2x_update_coalesce(struct bnx2x *bp);
-
+int bnx2x_get_link_cfg_idx(struct bnx2x *bp);
 static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms,
                           int wait)
 {
index 02bf710629a3eec2b4b05f17943c1565b3912144..7f1d291eaaa5134e2feb6c865eeb79a8d455db74 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/ip.h>
 #include <linux/ipv6.h>
 #include <net/ip6_checksum.h>
+#include <linux/firmware.h>
 #include "bnx2x_cmn.h"
 
 #ifdef BCM_VLAN
@@ -622,7 +623,7 @@ reuse_rx:
                        /* Set Toeplitz hash for a none-LRO skb */
                        bnx2x_set_skb_rxhash(bp, cqe, skb);
 
-                       skb->ip_summed = CHECKSUM_NONE;
+                       skb_checksum_none_assert(skb);
                        if (bp->rx_csum) {
                                if (likely(BNX2X_RX_CSUM_OK(cqe)))
                                        skb->ip_summed = CHECKSUM_UNNECESSARY;
@@ -1206,12 +1207,27 @@ static int bnx2x_set_num_queues(struct bnx2x *bp)
        return rc;
 }
 
+static void bnx2x_release_firmware(struct bnx2x *bp)
+{
+       kfree(bp->init_ops_offsets);
+       kfree(bp->init_ops);
+       kfree(bp->init_data);
+       release_firmware(bp->firmware);
+}
+
 /* must be called with rtnl_lock */
 int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
 {
        u32 load_code;
        int i, rc;
 
+       /* Set init arrays */
+       rc = bnx2x_init_firmware(bp);
+       if (rc) {
+               BNX2X_ERR("Error loading firmware\n");
+               return rc;
+       }
+
 #ifdef BNX2X_STOP_ON_ERROR
        if (unlikely(bp->panic))
                return -EPERM;
@@ -1267,7 +1283,7 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
           common blocks should be initialized, otherwise - not
        */
        if (!BP_NOMCP(bp)) {
-               load_code = bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_REQ);
+               load_code = bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_REQ, 0);
                if (!load_code) {
                        BNX2X_ERR("MCP response failure, aborting\n");
                        rc = -EBUSY;
@@ -1306,9 +1322,9 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
        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);
-               bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_REQ_WOL_MCP);
-               bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_DONE);
+               bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE, 0);
+               bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_REQ_WOL_MCP, 0);
+               bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_DONE, 0);
                goto load_error2;
        }
 
@@ -1323,7 +1339,7 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
 
        /* Send LOAD_DONE command to MCP */
        if (!BP_NOMCP(bp)) {
-               load_code = bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE);
+               load_code = bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE, 0);
                if (!load_code) {
                        BNX2X_ERR("MCP response failure, aborting\n");
                        rc = -EBUSY;
@@ -1427,6 +1443,8 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
 #endif
        bnx2x_inc_load_cnt(bp);
 
+       bnx2x_release_firmware(bp);
+
        return 0;
 
 #ifdef BCM_CNIC
@@ -1437,8 +1455,8 @@ load_error4:
 load_error3:
        bnx2x_int_disable_sync(bp, 1);
        if (!BP_NOMCP(bp)) {
-               bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_REQ_WOL_MCP);
-               bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_DONE);
+               bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_REQ_WOL_MCP, 0);
+               bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_DONE, 0);
        }
        bp->port.pmf = 0;
        /* Free SKBs, SGEs, TPA pool and driver internals */
@@ -1454,6 +1472,8 @@ load_error1:
                netif_napi_del(&bnx2x_fp(bp, i, napi));
        bnx2x_free_mem(bp);
 
+       bnx2x_release_firmware(bp);
+
        return rc;
 }
 
index d1979b1a7ed276f391d3a860aaf41a10449c139b..d1e6a8c977d1d5327b88344b6ff9e1691fabf6e9 100644 (file)
@@ -49,10 +49,11 @@ void bnx2x_link_set(struct bnx2x *bp);
  * Query link status
  *
  * @param bp
+ * @param is_serdes
  *
  * @return 0 - link is UP
  */
-u8 bnx2x_link_test(struct bnx2x *bp);
+u8 bnx2x_link_test(struct bnx2x *bp, u8 is_serdes);
 
 /**
  * Handles link status change
@@ -114,6 +115,15 @@ void bnx2x_int_enable(struct bnx2x *bp);
  */
 void bnx2x_int_disable_sync(struct bnx2x *bp, int disable_hw);
 
+/**
+ * Loads device firmware
+ *
+ * @param bp
+ *
+ * @return int
+ */
+int bnx2x_init_firmware(struct bnx2x *bp);
+
 /**
  * Init HW blocks according to current initialization stage:
  * COMMON, PORT or FUNCTION.
index 8b75b05e34c5a124d246a862ea6460ef80e6ec47..6f939c5a0089b046c3374c0d96d505664df44e89 100644 (file)
 static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
        struct bnx2x *bp = netdev_priv(dev);
-
-       cmd->supported = bp->port.supported;
-       cmd->advertising = bp->port.advertising;
+       int cfg_idx = bnx2x_get_link_cfg_idx(bp);
+       /* Dual Media boards present all available port types */
+       cmd->supported = bp->port.supported[cfg_idx] |
+               (bp->port.supported[cfg_idx ^ 1] &
+                (SUPPORTED_TP | SUPPORTED_FIBRE));
+       cmd->advertising = bp->port.advertising[cfg_idx];
 
        if ((bp->state == BNX2X_STATE_OPEN) &&
            !(bp->flags & MF_FUNC_DIS) &&
@@ -48,47 +51,21 @@ static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
                                cmd->speed = vn_max_rate;
                }
        } else {
-               cmd->speed = -1;
-               cmd->duplex = -1;
+               cmd->speed = bp->link_params.req_line_speed[cfg_idx];
+               cmd->duplex = bp->link_params.req_duplex[cfg_idx];
        }
 
-       if (bp->link_params.switch_cfg == SWITCH_CFG_10G) {
-               u32 ext_phy_type =
-                       XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config);
-
-               switch (ext_phy_type) {
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
-                       cmd->port = PORT_FIBRE;
-                       break;
-
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
-                       cmd->port = PORT_TP;
-                       break;
-
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
-                       BNX2X_ERR("XGXS PHY Failure detected 0x%x\n",
-                                 bp->link_params.ext_phy_config);
-                       break;
-
-               default:
-                       DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n",
-                          bp->link_params.ext_phy_config);
-                       break;
-               }
-       } else
+       if (bp->port.supported[cfg_idx] & SUPPORTED_TP)
                cmd->port = PORT_TP;
+       else if (bp->port.supported[cfg_idx] & SUPPORTED_FIBRE)
+               cmd->port = PORT_FIBRE;
+       else
+               BNX2X_ERR("XGXS PHY Failure detected\n");
 
        cmd->phy_address = bp->mdio.prtad;
        cmd->transceiver = XCVR_INTERNAL;
 
-       if (bp->link_params.req_line_speed == SPEED_AUTO_NEG)
+       if (bp->link_params.req_line_speed[cfg_idx] == SPEED_AUTO_NEG)
                cmd->autoneg = AUTONEG_ENABLE;
        else
                cmd->autoneg = AUTONEG_DISABLE;
@@ -110,7 +87,7 @@ static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
        struct bnx2x *bp = netdev_priv(dev);
-       u32 advertising;
+       u32 advertising, cfg_idx, old_multi_phy_config, new_multi_phy_config;
 
        if (IS_E1HMF(bp))
                return 0;
@@ -123,26 +100,81 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
           cmd->duplex, cmd->port, cmd->phy_address, cmd->transceiver,
           cmd->autoneg, cmd->maxtxpkt, cmd->maxrxpkt);
 
+       cfg_idx = bnx2x_get_link_cfg_idx(bp);
+       old_multi_phy_config = bp->link_params.multi_phy_config;
+       switch (cmd->port) {
+       case PORT_TP:
+               if (bp->port.supported[cfg_idx] & SUPPORTED_TP)
+                       break; /* no port change */
+
+               if (!(bp->port.supported[0] & SUPPORTED_TP ||
+                     bp->port.supported[1] & SUPPORTED_TP)) {
+                       DP(NETIF_MSG_LINK, "Unsupported port type\n");
+                       return -EINVAL;
+               }
+               bp->link_params.multi_phy_config &=
+                       ~PORT_HW_CFG_PHY_SELECTION_MASK;
+               if (bp->link_params.multi_phy_config &
+                   PORT_HW_CFG_PHY_SWAPPED_ENABLED)
+                       bp->link_params.multi_phy_config |=
+                       PORT_HW_CFG_PHY_SELECTION_SECOND_PHY;
+               else
+                       bp->link_params.multi_phy_config |=
+                       PORT_HW_CFG_PHY_SELECTION_FIRST_PHY;
+               break;
+       case PORT_FIBRE:
+               if (bp->port.supported[cfg_idx] & SUPPORTED_FIBRE)
+                       break; /* no port change */
+
+               if (!(bp->port.supported[0] & SUPPORTED_FIBRE ||
+                     bp->port.supported[1] & SUPPORTED_FIBRE)) {
+                       DP(NETIF_MSG_LINK, "Unsupported port type\n");
+                       return -EINVAL;
+               }
+               bp->link_params.multi_phy_config &=
+                       ~PORT_HW_CFG_PHY_SELECTION_MASK;
+               if (bp->link_params.multi_phy_config &
+                   PORT_HW_CFG_PHY_SWAPPED_ENABLED)
+                       bp->link_params.multi_phy_config |=
+                       PORT_HW_CFG_PHY_SELECTION_FIRST_PHY;
+               else
+                       bp->link_params.multi_phy_config |=
+                       PORT_HW_CFG_PHY_SELECTION_SECOND_PHY;
+               break;
+       default:
+               DP(NETIF_MSG_LINK, "Unsupported port type\n");
+               return -EINVAL;
+       }
+       /* Save new config in case command complete successuly */
+       new_multi_phy_config = bp->link_params.multi_phy_config;
+       /* Get the new cfg_idx */
+       cfg_idx = bnx2x_get_link_cfg_idx(bp);
+       /* Restore old config in case command failed */
+       bp->link_params.multi_phy_config = old_multi_phy_config;
+       DP(NETIF_MSG_LINK, "cfg_idx = %x\n", cfg_idx);
+
        if (cmd->autoneg == AUTONEG_ENABLE) {
-               if (!(bp->port.supported & SUPPORTED_Autoneg)) {
+               if (!(bp->port.supported[cfg_idx] & SUPPORTED_Autoneg)) {
                        DP(NETIF_MSG_LINK, "Autoneg not supported\n");
                        return -EINVAL;
                }
 
                /* advertise the requested speed and duplex if supported */
-               cmd->advertising &= bp->port.supported;
+               cmd->advertising &= bp->port.supported[cfg_idx];
 
-               bp->link_params.req_line_speed = SPEED_AUTO_NEG;
-               bp->link_params.req_duplex = DUPLEX_FULL;
-               bp->port.advertising |= (ADVERTISED_Autoneg |
+               bp->link_params.req_line_speed[cfg_idx] = SPEED_AUTO_NEG;
+               bp->link_params.req_duplex[cfg_idx] = DUPLEX_FULL;
+               bp->port.advertising[cfg_idx] |= (ADVERTISED_Autoneg |
                                         cmd->advertising);
 
        } else { /* forced speed */
                /* advertise the requested speed and duplex if supported */
-               switch (cmd->speed) {
+               u32 speed = cmd->speed;
+               speed |= (cmd->speed_hi << 16);
+               switch (speed) {
                case SPEED_10:
                        if (cmd->duplex == DUPLEX_FULL) {
-                               if (!(bp->port.supported &
+                               if (!(bp->port.supported[cfg_idx] &
                                      SUPPORTED_10baseT_Full)) {
                                        DP(NETIF_MSG_LINK,
                                           "10M full not supported\n");
@@ -152,7 +184,7 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
                                advertising = (ADVERTISED_10baseT_Full |
                                               ADVERTISED_TP);
                        } else {
-                               if (!(bp->port.supported &
+                               if (!(bp->port.supported[cfg_idx] &
                                      SUPPORTED_10baseT_Half)) {
                                        DP(NETIF_MSG_LINK,
                                           "10M half not supported\n");
@@ -166,7 +198,7 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 
                case SPEED_100:
                        if (cmd->duplex == DUPLEX_FULL) {
-                               if (!(bp->port.supported &
+                               if (!(bp->port.supported[cfg_idx] &
                                                SUPPORTED_100baseT_Full)) {
                                        DP(NETIF_MSG_LINK,
                                           "100M full not supported\n");
@@ -176,7 +208,7 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
                                advertising = (ADVERTISED_100baseT_Full |
                                               ADVERTISED_TP);
                        } else {
-                               if (!(bp->port.supported &
+                               if (!(bp->port.supported[cfg_idx] &
                                                SUPPORTED_100baseT_Half)) {
                                        DP(NETIF_MSG_LINK,
                                           "100M half not supported\n");
@@ -194,7 +226,8 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
                                return -EINVAL;
                        }
 
-                       if (!(bp->port.supported & SUPPORTED_1000baseT_Full)) {
+                       if (!(bp->port.supported[cfg_idx] &
+                             SUPPORTED_1000baseT_Full)) {
                                DP(NETIF_MSG_LINK, "1G full not supported\n");
                                return -EINVAL;
                        }
@@ -210,7 +243,8 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
                                return -EINVAL;
                        }
 
-                       if (!(bp->port.supported & SUPPORTED_2500baseX_Full)) {
+                       if (!(bp->port.supported[cfg_idx]
+                             & SUPPORTED_2500baseX_Full)) {
                                DP(NETIF_MSG_LINK,
                                   "2.5G full not supported\n");
                                return -EINVAL;
@@ -226,7 +260,8 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
                                return -EINVAL;
                        }
 
-                       if (!(bp->port.supported & SUPPORTED_10000baseT_Full)) {
+                       if (!(bp->port.supported[cfg_idx]
+                             & SUPPORTED_10000baseT_Full)) {
                                DP(NETIF_MSG_LINK, "10G full not supported\n");
                                return -EINVAL;
                        }
@@ -236,20 +271,23 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
                        break;
 
                default:
-                       DP(NETIF_MSG_LINK, "Unsupported speed\n");
+                       DP(NETIF_MSG_LINK, "Unsupported speed %d\n", speed);
                        return -EINVAL;
                }
 
-               bp->link_params.req_line_speed = cmd->speed;
-               bp->link_params.req_duplex = cmd->duplex;
-               bp->port.advertising = advertising;
+               bp->link_params.req_line_speed[cfg_idx] = speed;
+               bp->link_params.req_duplex[cfg_idx] = cmd->duplex;
+               bp->port.advertising[cfg_idx] = advertising;
        }
 
        DP(NETIF_MSG_LINK, "req_line_speed %d\n"
           DP_LEVEL "  req_duplex %d  advertising 0x%x\n",
-          bp->link_params.req_line_speed, bp->link_params.req_duplex,
-          bp->port.advertising);
+          bp->link_params.req_line_speed[cfg_idx],
+          bp->link_params.req_duplex[cfg_idx],
+          bp->port.advertising[cfg_idx]);
 
+       /* Set new config */
+       bp->link_params.multi_phy_config = new_multi_phy_config;
        if (netif_running(dev)) {
                bnx2x_stats_handle(bp, STATS_EVENT_STOP);
                bnx2x_link_set(bp);
@@ -811,7 +849,7 @@ static int bnx2x_set_eeprom(struct net_device *dev,
        struct bnx2x *bp = netdev_priv(dev);
        int port = BP_PORT(bp);
        int rc = 0;
-
+       u32 ext_phy_config;
        if (!netif_running(dev))
                return -EAGAIN;
 
@@ -827,6 +865,10 @@ static int bnx2x_set_eeprom(struct net_device *dev,
            !bp->port.pmf)
                return -EINVAL;
 
+       ext_phy_config =
+               SHMEM_RD(bp,
+                        dev_info.port_hw_config[port].external_phy_config);
+
        if (eeprom->magic == 0x50485950) {
                /* 'PHYP' (0x50485950): prepare phy for FW upgrade */
                bnx2x_stats_handle(bp, STATS_EVENT_STOP);
@@ -834,7 +876,7 @@ static int bnx2x_set_eeprom(struct net_device *dev,
                bnx2x_acquire_phy_lock(bp);
                rc |= bnx2x_link_reset(&bp->link_params,
                                       &bp->link_vars, 0);
-               if (XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config) ==
+               if (XGXS_EXT_PHY_TYPE(ext_phy_config) ==
                                        PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101)
                        bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
                                       MISC_REGISTERS_GPIO_HIGH, port);
@@ -855,10 +897,8 @@ static int bnx2x_set_eeprom(struct net_device *dev,
                }
        } else if (eeprom->magic == 0x53985943) {
                /* 'PHYC' (0x53985943): PHY FW upgrade completed */
-               if (XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config) ==
+               if (XGXS_EXT_PHY_TYPE(ext_phy_config) ==
                                       PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101) {
-                       u8 ext_phy_addr =
-                            XGXS_EXT_PHY_ADDR(bp->link_params.ext_phy_config);
 
                        /* DSP Remove Download Mode */
                        bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
@@ -866,7 +906,8 @@ static int bnx2x_set_eeprom(struct net_device *dev,
 
                        bnx2x_acquire_phy_lock(bp);
 
-                       bnx2x_sfx7101_sp_sw_reset(bp, port, ext_phy_addr);
+                       bnx2x_sfx7101_sp_sw_reset(bp,
+                                               &bp->link_params.phy[EXT_PHY1]);
 
                        /* wait 0.5 sec to allow it to run */
                        msleep(500);
@@ -959,10 +1000,9 @@ static void bnx2x_get_pauseparam(struct net_device *dev,
                                 struct ethtool_pauseparam *epause)
 {
        struct bnx2x *bp = netdev_priv(dev);
-
-       epause->autoneg = (bp->link_params.req_flow_ctrl ==
-                          BNX2X_FLOW_CTRL_AUTO) &&
-                         (bp->link_params.req_line_speed == SPEED_AUTO_NEG);
+       int cfg_idx = bnx2x_get_link_cfg_idx(bp);
+       epause->autoneg = (bp->link_params.req_flow_ctrl[cfg_idx] ==
+                          BNX2X_FLOW_CTRL_AUTO);
 
        epause->rx_pause = ((bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_RX) ==
                            BNX2X_FLOW_CTRL_RX);
@@ -978,7 +1018,7 @@ static int bnx2x_set_pauseparam(struct net_device *dev,
                                struct ethtool_pauseparam *epause)
 {
        struct bnx2x *bp = netdev_priv(dev);
-
+       u32 cfg_idx = bnx2x_get_link_cfg_idx(bp);
        if (IS_E1HMF(bp))
                return 0;
 
@@ -986,29 +1026,31 @@ static int bnx2x_set_pauseparam(struct net_device *dev,
           DP_LEVEL "  autoneg %d  rx_pause %d  tx_pause %d\n",
           epause->cmd, epause->autoneg, epause->rx_pause, epause->tx_pause);
 
-       bp->link_params.req_flow_ctrl = BNX2X_FLOW_CTRL_AUTO;
+       bp->link_params.req_flow_ctrl[cfg_idx] = BNX2X_FLOW_CTRL_AUTO;
 
        if (epause->rx_pause)
-               bp->link_params.req_flow_ctrl |= BNX2X_FLOW_CTRL_RX;
+               bp->link_params.req_flow_ctrl[cfg_idx] |= BNX2X_FLOW_CTRL_RX;
 
        if (epause->tx_pause)
-               bp->link_params.req_flow_ctrl |= BNX2X_FLOW_CTRL_TX;
+               bp->link_params.req_flow_ctrl[cfg_idx] |= BNX2X_FLOW_CTRL_TX;
 
-       if (bp->link_params.req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO)
-               bp->link_params.req_flow_ctrl = BNX2X_FLOW_CTRL_NONE;
+       if (bp->link_params.req_flow_ctrl[cfg_idx] == BNX2X_FLOW_CTRL_AUTO)
+               bp->link_params.req_flow_ctrl[cfg_idx] = BNX2X_FLOW_CTRL_NONE;
 
        if (epause->autoneg) {
-               if (!(bp->port.supported & SUPPORTED_Autoneg)) {
+               if (!(bp->port.supported[cfg_idx] & SUPPORTED_Autoneg)) {
                        DP(NETIF_MSG_LINK, "autoneg not supported\n");
                        return -EINVAL;
                }
 
-               if (bp->link_params.req_line_speed == SPEED_AUTO_NEG)
-                       bp->link_params.req_flow_ctrl = BNX2X_FLOW_CTRL_AUTO;
+               if (bp->link_params.req_line_speed[cfg_idx] == SPEED_AUTO_NEG) {
+                       bp->link_params.req_flow_ctrl[cfg_idx] =
+                               BNX2X_FLOW_CTRL_AUTO;
+               }
        }
 
        DP(NETIF_MSG_LINK,
-          "req_flow_ctrl 0x%x\n", bp->link_params.req_flow_ctrl);
+          "req_flow_ctrl 0x%x\n", bp->link_params.req_flow_ctrl[cfg_idx]);
 
        if (netif_running(dev)) {
                bnx2x_stats_handle(bp, STATS_EVENT_STOP);
@@ -1272,12 +1314,12 @@ test_mem_exit:
        return rc;
 }
 
-static void bnx2x_wait_for_link(struct bnx2x *bp, u8 link_up)
+static void bnx2x_wait_for_link(struct bnx2x *bp, u8 link_up, u8 is_serdes)
 {
        int cnt = 1000;
 
        if (link_up)
-               while (bnx2x_link_test(bp) && cnt--)
+               while (bnx2x_link_test(bp, is_serdes) && cnt--)
                        msleep(10);
 }
 
@@ -1304,7 +1346,7 @@ static int bnx2x_run_loopback(struct bnx2x *bp, int loopback_mode, u8 link_up)
        /* check the loopback mode */
        switch (loopback_mode) {
        case BNX2X_PHY_LOOPBACK:
-               if (bp->link_params.loopback_mode != LOOPBACK_XGXS_10)
+               if (bp->link_params.loopback_mode != LOOPBACK_XGXS)
                        return -EINVAL;
                break;
        case BNX2X_MAC_LOOPBACK:
@@ -1549,7 +1591,7 @@ static void bnx2x_self_test(struct net_device *dev,
                            struct ethtool_test *etest, u64 *buf)
 {
        struct bnx2x *bp = netdev_priv(dev);
-
+       u8 is_serdes;
        if (bp->recovery_state != BNX2X_RECOVERY_DONE) {
                printk(KERN_ERR "Handling parity error recovery. Try again later\n");
                etest->flags |= ETH_TEST_FL_FAILED;
@@ -1564,6 +1606,7 @@ static void bnx2x_self_test(struct net_device *dev,
        /* offline tests are not supported in MF mode */
        if (IS_E1HMF(bp))
                etest->flags &= ~ETH_TEST_FL_OFFLINE;
+       is_serdes = (bp->link_vars.link_status & LINK_STATUS_SERDES_LINK) > 0;
 
        if (etest->flags & ETH_TEST_FL_OFFLINE) {
                int port = BP_PORT(bp);
@@ -1575,11 +1618,12 @@ static void bnx2x_self_test(struct net_device *dev,
                /* disable input for TX port IF */
                REG_WR(bp, NIG_REG_EGRESS_UMP0_IN_EN + port*4, 0);
 
-               link_up = (bnx2x_link_test(bp) == 0);
+               link_up = bp->link_vars.link_up;
+
                bnx2x_nic_unload(bp, UNLOAD_NORMAL);
                bnx2x_nic_load(bp, LOAD_DIAG);
                /* wait until link state is restored */
-               bnx2x_wait_for_link(bp, link_up);
+               bnx2x_wait_for_link(bp, link_up, is_serdes);
 
                if (bnx2x_test_registers(bp) != 0) {
                        buf[0] = 1;
@@ -1600,7 +1644,7 @@ static void bnx2x_self_test(struct net_device *dev,
 
                bnx2x_nic_load(bp, LOAD_NORMAL);
                /* wait until link state is restored */
-               bnx2x_wait_for_link(bp, link_up);
+               bnx2x_wait_for_link(bp, link_up, is_serdes);
        }
        if (bnx2x_test_nvram(bp) != 0) {
                buf[3] = 1;
@@ -1611,7 +1655,7 @@ static void bnx2x_self_test(struct net_device *dev,
                etest->flags |= ETH_TEST_FL_FAILED;
        }
        if (bp->port.pmf)
-               if (bnx2x_link_test(bp) != 0) {
+               if (bnx2x_link_test(bp, is_serdes) != 0) {
                        buf[5] = 1;
                        etest->flags |= ETH_TEST_FL_FAILED;
                }
@@ -1910,10 +1954,11 @@ static int bnx2x_phys_id(struct net_device *dev, u32 data)
 
        for (i = 0; i < (data * 2); i++) {
                if ((i % 2) == 0)
-                       bnx2x_set_led(&bp->link_params, LED_MODE_OPER,
-                                     SPEED_1000);
+                       bnx2x_set_led(&bp->link_params, &bp->link_vars,
+                                     LED_MODE_OPER, SPEED_1000);
                else
-                       bnx2x_set_led(&bp->link_params, LED_MODE_OFF, 0);
+                       bnx2x_set_led(&bp->link_params, &bp->link_vars,
+                                     LED_MODE_OFF, 0);
 
                msleep_interruptible(500);
                if (signal_pending(current))
@@ -1921,7 +1966,7 @@ static int bnx2x_phys_id(struct net_device *dev, u32 data)
        }
 
        if (bp->link_vars.link_up)
-               bnx2x_set_led(&bp->link_params, LED_MODE_OPER,
+               bnx2x_set_led(&bp->link_params, &bp->link_vars, LED_MODE_OPER,
                              bp->link_vars.line_speed);
 
        return 0;
index fd1f29e0317d6b9c2c90798336d69073ad370a2d..60d141cd995047bcf6cc509752cfba03a7647cbe 100644 (file)
@@ -78,6 +78,8 @@ struct shared_hw_cfg {                                         /* NVRAM Offset */
 #define SHARED_HW_CFG_LED_PHY11                    0x000b0000
 #define SHARED_HW_CFG_LED_MAC4                     0x000c0000
 #define SHARED_HW_CFG_LED_PHY8                     0x000d0000
+#define SHARED_HW_CFG_LED_EXTPHY1                  0x000e0000
+
 
 #define SHARED_HW_CFG_AN_ENABLE_MASK               0x3f000000
 #define SHARED_HW_CFG_AN_ENABLE_SHIFT              24
@@ -120,6 +122,23 @@ struct shared_hw_cfg {                                      /* NVRAM Offset */
 #define SHARED_HW_CFG_FAN_FAILURE_DISABLED                   0x00080000
 #define SHARED_HW_CFG_FAN_FAILURE_ENABLED                    0x00100000
 
+       /* Set the MDC/MDIO access for the first external phy */
+#define SHARED_HW_CFG_MDC_MDIO_ACCESS1_MASK        0x1C000000
+#define SHARED_HW_CFG_MDC_MDIO_ACCESS1_SHIFT       26
+#define SHARED_HW_CFG_MDC_MDIO_ACCESS1_PHY_TYPE     0x00000000
+#define SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC0       0x04000000
+#define SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC1       0x08000000
+#define SHARED_HW_CFG_MDC_MDIO_ACCESS1_BOTH        0x0c000000
+#define SHARED_HW_CFG_MDC_MDIO_ACCESS1_SWAPPED     0x10000000
+
+       /* Set the MDC/MDIO access for the second external phy */
+#define SHARED_HW_CFG_MDC_MDIO_ACCESS2_MASK        0xE0000000
+#define SHARED_HW_CFG_MDC_MDIO_ACCESS2_SHIFT       29
+#define SHARED_HW_CFG_MDC_MDIO_ACCESS2_PHY_TYPE     0x00000000
+#define SHARED_HW_CFG_MDC_MDIO_ACCESS2_EMAC0       0x20000000
+#define SHARED_HW_CFG_MDC_MDIO_ACCESS2_EMAC1       0x40000000
+#define SHARED_HW_CFG_MDC_MDIO_ACCESS2_BOTH        0x60000000
+#define SHARED_HW_CFG_MDC_MDIO_ACCESS2_SWAPPED     0x80000000
        u32 power_dissipated;                                   /* 0x11c */
 #define SHARED_HW_CFG_POWER_DIS_CMN_MASK           0xff000000
 #define SHARED_HW_CFG_POWER_DIS_CMN_SHIFT          24
@@ -221,7 +240,88 @@ struct port_hw_cfg {                           /* port 0: 0x12c  port 1: 0x2bc */
 
        u16 xgxs_config_tx[4];                              /* 0x1A0 */
 
-       u32 Reserved1[64];                                  /* 0x1A8 */
+       u32 Reserved1[57];                                  /* 0x1A8 */
+       u32 speed_capability_mask2;                         /* 0x28C */
+#define PORT_HW_CFG_SPEED_CAPABILITY2_D3_MASK                0x0000FFFF
+#define PORT_HW_CFG_SPEED_CAPABILITY2_D3_SHIFT               0
+#define PORT_HW_CFG_SPEED_CAPABILITY2_D3_10M_FULL            0x00000001
+#define PORT_HW_CFG_SPEED_CAPABILITY2_D3__                   0x00000002
+#define PORT_HW_CFG_SPEED_CAPABILITY2_D3___                  0x00000004
+#define PORT_HW_CFG_SPEED_CAPABILITY2_D3_100M_FULL           0x00000008
+#define PORT_HW_CFG_SPEED_CAPABILITY2_D3_1G                  0x00000010
+#define PORT_HW_CFG_SPEED_CAPABILITY2_D3_2_DOT_5G            0x00000020
+#define PORT_HW_CFG_SPEED_CAPABILITY2_D3_10G                 0x00000040
+#define PORT_HW_CFG_SPEED_CAPABILITY2_D3_12G                 0x00000080
+#define PORT_HW_CFG_SPEED_CAPABILITY2_D3_12_DOT_5G           0x00000100
+#define PORT_HW_CFG_SPEED_CAPABILITY2_D3_13G                 0x00000200
+#define PORT_HW_CFG_SPEED_CAPABILITY2_D3_15G                 0x00000400
+#define PORT_HW_CFG_SPEED_CAPABILITY2_D3_16G                 0x00000800
+
+#define PORT_HW_CFG_SPEED_CAPABILITY2_D0_MASK                0xFFFF0000
+#define PORT_HW_CFG_SPEED_CAPABILITY2_D0_SHIFT               16
+#define PORT_HW_CFG_SPEED_CAPABILITY2_D0_10M_FULL            0x00010000
+#define PORT_HW_CFG_SPEED_CAPABILITY2_D0__                   0x00020000
+#define PORT_HW_CFG_SPEED_CAPABILITY2_D0___                  0x00040000
+#define PORT_HW_CFG_SPEED_CAPABILITY2_D0_100M_FULL           0x00080000
+#define PORT_HW_CFG_SPEED_CAPABILITY2_D0_1G                  0x00100000
+#define PORT_HW_CFG_SPEED_CAPABILITY2_D0_2_DOT_5G            0x00200000
+#define PORT_HW_CFG_SPEED_CAPABILITY2_D0_10G                 0x00400000
+#define PORT_HW_CFG_SPEED_CAPABILITY2_D0_12G                 0x00800000
+#define PORT_HW_CFG_SPEED_CAPABILITY2_D0_12_DOT_5G           0x01000000
+#define PORT_HW_CFG_SPEED_CAPABILITY2_D0_13G                 0x02000000
+#define PORT_HW_CFG_SPEED_CAPABILITY2_D0_15G                 0x04000000
+#define PORT_HW_CFG_SPEED_CAPABILITY2_D0_16G                 0x08000000
+
+       /* In the case where two media types (e.g. copper and fiber) are
+         present and electrically active at the same time, PHY Selection
+         will determine which of the two PHYs will be designated as the
+         Active PHY and used for a connection to the network.  */
+       u32 multi_phy_config;                           /* 0x290 */
+#define PORT_HW_CFG_PHY_SELECTION_MASK              0x00000007
+#define PORT_HW_CFG_PHY_SELECTION_SHIFT                     0
+#define PORT_HW_CFG_PHY_SELECTION_HARDWARE_DEFAULT   0x00000000
+#define PORT_HW_CFG_PHY_SELECTION_FIRST_PHY         0x00000001
+#define PORT_HW_CFG_PHY_SELECTION_SECOND_PHY        0x00000002
+#define PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY 0x00000003
+#define PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY 0x00000004
+
+       /* When enabled, all second phy nvram parameters will be swapped
+         with the first phy parameters */
+#define PORT_HW_CFG_PHY_SWAPPED_MASK                0x00000008
+#define PORT_HW_CFG_PHY_SWAPPED_SHIFT               3
+#define PORT_HW_CFG_PHY_SWAPPED_DISABLED            0x00000000
+#define PORT_HW_CFG_PHY_SWAPPED_ENABLED                     0x00000008
+
+
+       /* Address of the second external phy */
+       u32 external_phy_config2;                               /* 0x294 */
+#define PORT_HW_CFG_XGXS_EXT_PHY2_ADDR_MASK        0x000000FF
+#define PORT_HW_CFG_XGXS_EXT_PHY2_ADDR_SHIFT       0
+
+       /* The second XGXS external PHY type */
+#define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_MASK        0x0000FF00
+#define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_SHIFT       8
+#define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_DIRECT      0x00000000
+#define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM8071     0x00000100
+#define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM8072     0x00000200
+#define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM8073     0x00000300
+#define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM8705     0x00000400
+#define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM8706     0x00000500
+#define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM8726     0x00000600
+#define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM8481     0x00000700
+#define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_SFX7101     0x00000800
+#define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM8727     0x00000900
+#define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM8727_NOC  0x00000a00
+#define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM84823     0x00000b00
+#define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM54640     0x00000c00
+#define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM84833     0x00000d00
+#define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_FAILURE     0x0000fd00
+#define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_NOT_CONN     0x0000ff00
+
+       /* 4 times 16 bits for all 4 lanes. For some external PHYs (such as
+         8706, 8726 and 8727) not all 4 values are needed. */
+       u16 xgxs_config2_rx[4];                         /* 0x296 */
+       u16 xgxs_config2_tx[4];                         /* 0x2A0 */
 
        u32 lane_config;
 #define PORT_HW_CFG_LANE_SWAP_CFG_MASK             0x0000ffff
@@ -515,10 +615,17 @@ struct port_feat_cfg {                        /* port 0: 0x454  port 1: 0x4c8 */
 #define PORT_FEATURE_FLOW_CONTROL_NONE             0x00000400
 
        /* The default for MCP link configuration,
-          uses the same defines as link_config */
+       uses the same defines as link_config */
        u32 mfw_wol_link_cfg;
+       /* The default for the driver of the second external phy,
+       uses the same defines as link_config */
+       u32 link_config2;                                       /* 0x47C */
+
+       /* The default for MCP of the second external phy,
+       uses the same defines as link_config */
+       u32 mfw_wol_link_cfg2;                          /* 0x480 */
 
-       u32 reserved[19];
+       u32 Reserved2[17];                                      /* 0x484 */
 
 };
 
@@ -686,8 +793,14 @@ struct drv_func_mb {
         * The optic module verification commands require bootcode
         * v5.0.6 or later
         */
-#define DRV_MSG_CODE_VRFY_OPT_MDL                      0xa0000000
-#define REQ_BC_VER_4_VRFY_OPT_MDL                      0x00050006
+#define DRV_MSG_CODE_VRFY_FIRST_PHY_OPT_MDL    0xa0000000
+#define REQ_BC_VER_4_VRFY_FIRST_PHY_OPT_MDL    0x00050006
+       /*
+        * The specific optic module verification command requires bootcode
+        * v5.2.12 or later
+        */
+#define DRV_MSG_CODE_VRFY_SPECIFIC_PHY_OPT_MDL     0xa1000000
+#define REQ_BC_VER_4_VRFY_SPECIFIC_PHY_OPT_MDL     0x00050234
 
 #define BIOS_MSG_CODE_LIC_CHALLENGE                    0xff010000
 #define BIOS_MSG_CODE_LIC_RESPONSE                     0xff020000
@@ -922,7 +1035,12 @@ struct shmem2_region {
 #define SHMEM_DCC_SUPPORT_SET_PROTOCOL_TLV         0x00000040
 #define SHMEM_DCC_SUPPORT_SET_PRIORITY_TLV         0x00000080
 #define SHMEM_DCC_SUPPORT_DEFAULT                  SHMEM_DCC_SUPPORT_NONE
-
+       u32 ext_phy_fw_version2[PORT_MAX];
+       /*
+        * For backwards compatibility, if the mf_cfg_addr does not exist
+        * (the size filed is smaller than 0xc) the mf_cfg resides at the
+        * end of struct shmem_region
+        */
 };
 
 
index 0383e30663135355d9de8ea79bc7b926fe162a7d..a07a3a6abd40dc8cbce4a473988b4e6f2f98b007 100644 (file)
 /**********************************************************/
 /*                     INTERFACE                          */
 /**********************************************************/
-#define CL45_WR_OVER_CL22(_bp, _port, _phy_addr, _bank, _addr, _val) \
-       bnx2x_cl45_write(_bp, _port, 0, _phy_addr, \
-               DEFAULT_PHY_DEV_ADDR, \
+
+#define CL45_WR_OVER_CL22(_bp, _phy, _bank, _addr, _val) \
+       bnx2x_cl45_write(_bp, _phy, \
+               (_phy)->def_md_devad, \
                (_bank + (_addr & 0xf)), \
                _val)
 
-#define CL45_RD_OVER_CL22(_bp, _port, _phy_addr, _bank, _addr, _val) \
-       bnx2x_cl45_read(_bp, _port, 0, _phy_addr, \
-               DEFAULT_PHY_DEV_ADDR, \
+#define CL45_RD_OVER_CL22(_bp, _phy, _bank, _addr, _val) \
+       bnx2x_cl45_read(_bp, _phy, \
+               (_phy)->def_md_devad, \
                (_bank + (_addr & 0xf)), \
                _val)
 
-static void bnx2x_set_serdes_access(struct link_params *params)
-{
-       struct bnx2x *bp = params->bp;
-       u32 emac_base = (params->port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
-
-       /* Set Clause 22 */
-       REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_ST + params->port*0x10, 1);
-       REG_WR(bp, emac_base + EMAC_REG_EMAC_MDIO_COMM, 0x245f8000);
-       udelay(500);
-       REG_WR(bp, emac_base + EMAC_REG_EMAC_MDIO_COMM, 0x245d000f);
-       udelay(500);
-        /* Set Clause 45 */
-       REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_ST + params->port*0x10, 0);
-}
-static void bnx2x_set_phy_mdio(struct link_params *params, u8 phy_flags)
-{
-       struct bnx2x *bp = params->bp;
-
-       if (phy_flags & PHY_XGXS_FLAG) {
-               REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_ST +
-                          params->port*0x18, 0);
-               REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + params->port*0x18,
-                          DEFAULT_PHY_DEV_ADDR);
-       } else {
-               bnx2x_set_serdes_access(params);
-
-               REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_DEVAD +
-                          params->port*0x10,
-                          DEFAULT_PHY_DEV_ADDR);
-       }
-}
-
 static u32 bnx2x_bits_en(struct bnx2x *bp, u32 reg, u32 bits)
 {
        u32 val = REG_RD(bp, reg);
@@ -527,162 +496,6 @@ static u8 bnx2x_bmac_enable(struct link_params *params, struct link_vars *vars,
        return 0;
 }
 
-static void bnx2x_phy_deassert(struct link_params *params, u8 phy_flags)
-{
-       struct bnx2x *bp = params->bp;
-       u32 val;
-
-       if (phy_flags & PHY_XGXS_FLAG) {
-               DP(NETIF_MSG_LINK, "bnx2x_phy_deassert:XGXS\n");
-               val = XGXS_RESET_BITS;
-
-       } else { /* SerDes */
-               DP(NETIF_MSG_LINK, "bnx2x_phy_deassert:SerDes\n");
-               val = SERDES_RESET_BITS;
-       }
-
-       val = val << (params->port*16);
-
-       /* reset and unreset the SerDes/XGXS */
-       REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR,
-                   val);
-       udelay(500);
-       REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_SET,
-                   val);
-       bnx2x_set_phy_mdio(params, phy_flags);
-}
-
-void bnx2x_link_status_update(struct link_params *params,
-                           struct link_vars   *vars)
-{
-       struct bnx2x *bp = params->bp;
-       u8 link_10g;
-       u8 port = params->port;
-
-       if (params->switch_cfg ==  SWITCH_CFG_1G)
-               vars->phy_flags = PHY_SERDES_FLAG;
-       else
-               vars->phy_flags = PHY_XGXS_FLAG;
-       vars->link_status = REG_RD(bp, params->shmem_base +
-                                         offsetof(struct shmem_region,
-                                          port_mb[port].link_status));
-
-       vars->link_up = (vars->link_status & LINK_STATUS_LINK_UP);
-
-       if (vars->link_up) {
-               DP(NETIF_MSG_LINK, "phy link up\n");
-
-               vars->phy_link_up = 1;
-               vars->duplex = DUPLEX_FULL;
-               switch (vars->link_status &
-                                       LINK_STATUS_SPEED_AND_DUPLEX_MASK) {
-                       case LINK_10THD:
-                               vars->duplex = DUPLEX_HALF;
-                               /* fall thru */
-                       case LINK_10TFD:
-                               vars->line_speed = SPEED_10;
-                               break;
-
-                       case LINK_100TXHD:
-                               vars->duplex = DUPLEX_HALF;
-                               /* fall thru */
-                       case LINK_100T4:
-                       case LINK_100TXFD:
-                               vars->line_speed = SPEED_100;
-                               break;
-
-                       case LINK_1000THD:
-                               vars->duplex = DUPLEX_HALF;
-                               /* fall thru */
-                       case LINK_1000TFD:
-                               vars->line_speed = SPEED_1000;
-                               break;
-
-                       case LINK_2500THD:
-                               vars->duplex = DUPLEX_HALF;
-                               /* fall thru */
-                       case LINK_2500TFD:
-                               vars->line_speed = SPEED_2500;
-                               break;
-
-                       case LINK_10GTFD:
-                               vars->line_speed = SPEED_10000;
-                               break;
-
-                       case LINK_12GTFD:
-                               vars->line_speed = SPEED_12000;
-                               break;
-
-                       case LINK_12_5GTFD:
-                               vars->line_speed = SPEED_12500;
-                               break;
-
-                       case LINK_13GTFD:
-                               vars->line_speed = SPEED_13000;
-                               break;
-
-                       case LINK_15GTFD:
-                               vars->line_speed = SPEED_15000;
-                               break;
-
-                       case LINK_16GTFD:
-                               vars->line_speed = SPEED_16000;
-                               break;
-
-                       default:
-                               break;
-               }
-
-               if (vars->link_status & LINK_STATUS_TX_FLOW_CONTROL_ENABLED)
-                       vars->flow_ctrl |= BNX2X_FLOW_CTRL_TX;
-               else
-                       vars->flow_ctrl &= ~BNX2X_FLOW_CTRL_TX;
-
-               if (vars->link_status & LINK_STATUS_RX_FLOW_CONTROL_ENABLED)
-                       vars->flow_ctrl |= BNX2X_FLOW_CTRL_RX;
-               else
-                       vars->flow_ctrl &= ~BNX2X_FLOW_CTRL_RX;
-
-               if (vars->phy_flags & PHY_XGXS_FLAG) {
-                       if (vars->line_speed &&
-                           ((vars->line_speed == SPEED_10) ||
-                            (vars->line_speed == SPEED_100))) {
-                               vars->phy_flags |= PHY_SGMII_FLAG;
-                       } else {
-                               vars->phy_flags &= ~PHY_SGMII_FLAG;
-                       }
-               }
-
-               /* anything 10 and over uses the bmac */
-               link_10g = ((vars->line_speed == SPEED_10000) ||
-                           (vars->line_speed == SPEED_12000) ||
-                           (vars->line_speed == SPEED_12500) ||
-                           (vars->line_speed == SPEED_13000) ||
-                           (vars->line_speed == SPEED_15000) ||
-                           (vars->line_speed == SPEED_16000));
-               if (link_10g)
-                       vars->mac_type = MAC_TYPE_BMAC;
-               else
-                       vars->mac_type = MAC_TYPE_EMAC;
-
-       } else { /* link down */
-               DP(NETIF_MSG_LINK, "phy link down\n");
-
-               vars->phy_link_up = 0;
-
-               vars->line_speed = 0;
-               vars->duplex = DUPLEX_FULL;
-               vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
-
-               /* indicate no mac active */
-               vars->mac_type = MAC_TYPE_NONE;
-       }
-
-       DP(NETIF_MSG_LINK, "link_status 0x%x  phy_link_up %x\n",
-                vars->link_status, vars->phy_link_up);
-       DP(NETIF_MSG_LINK, "line_speed %x  duplex %x  flow_ctrl 0x%x\n",
-                vars->line_speed, vars->duplex, vars->flow_ctrl);
-}
 
 static void bnx2x_update_mng(struct link_params *params, u32 link_status)
 {
@@ -800,62 +613,69 @@ static u8 bnx2x_pbf_update(struct link_params *params, u32 flow_ctrl,
        return 0;
 }
 
-static u32 bnx2x_get_emac_base(struct bnx2x *bp, u32 ext_phy_type, u8 port)
+static u32 bnx2x_get_emac_base(struct bnx2x *bp,
+                              u32 mdc_mdio_access, u8 port)
 {
-       u32 emac_base;
-
-       switch (ext_phy_type) {
-       case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
-       case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
-       case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
-               /* All MDC/MDIO is directed through single EMAC */
+       u32 emac_base = 0;
+       switch (mdc_mdio_access) {
+       case SHARED_HW_CFG_MDC_MDIO_ACCESS1_PHY_TYPE:
+               break;
+       case SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC0:
+               if (REG_RD(bp, NIG_REG_PORT_SWAP))
+                       emac_base = GRCBASE_EMAC1;
+               else
+                       emac_base = GRCBASE_EMAC0;
+               break;
+       case SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC1:
                if (REG_RD(bp, NIG_REG_PORT_SWAP))
                        emac_base = GRCBASE_EMAC0;
                else
                        emac_base = GRCBASE_EMAC1;
                break;
-       case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
+       case SHARED_HW_CFG_MDC_MDIO_ACCESS1_BOTH:
+               emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
+               break;
+       case SHARED_HW_CFG_MDC_MDIO_ACCESS1_SWAPPED:
                emac_base = (port) ? GRCBASE_EMAC0 : GRCBASE_EMAC1;
                break;
        default:
-               emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
                break;
        }
        return emac_base;
 
 }
 
-u8 bnx2x_cl45_write(struct bnx2x *bp, u8 port, u32 ext_phy_type,
-                 u8 phy_addr, u8 devad, u16 reg, u16 val)
+u8 bnx2x_cl45_write(struct bnx2x *bp, struct bnx2x_phy *phy,
+                   u8 devad, u16 reg, u16 val)
 {
        u32 tmp, saved_mode;
        u8 i, rc = 0;
-       u32 mdio_ctrl = bnx2x_get_emac_base(bp, ext_phy_type, port);
 
        /* set clause 45 mode, slow down the MDIO clock to 2.5MHz
         * (a value of 49==0x31) and make sure that the AUTO poll is off
         */
 
-       saved_mode = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
+       saved_mode = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
        tmp = saved_mode & ~(EMAC_MDIO_MODE_AUTO_POLL |
                             EMAC_MDIO_MODE_CLOCK_CNT);
        tmp |= (EMAC_MDIO_MODE_CLAUSE_45 |
                (49 << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT));
-       REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, tmp);
-       REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
+       REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, tmp);
+       REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
        udelay(40);
 
        /* address */
 
-       tmp = ((phy_addr << 21) | (devad << 16) | reg |
+       tmp = ((phy->addr << 21) | (devad << 16) | reg |
               EMAC_MDIO_COMM_COMMAND_ADDRESS |
               EMAC_MDIO_COMM_START_BUSY);
-       REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
+       REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
 
        for (i = 0; i < 50; i++) {
                udelay(10);
 
-               tmp = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM);
+               tmp = REG_RD(bp, phy->mdio_ctrl +
+                                  EMAC_REG_EMAC_MDIO_COMM);
                if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
                        udelay(5);
                        break;
@@ -866,15 +686,15 @@ u8 bnx2x_cl45_write(struct bnx2x *bp, u8 port, u32 ext_phy_type,
                rc = -EFAULT;
        } else {
                /* data */
-               tmp = ((phy_addr << 21) | (devad << 16) | val |
+               tmp = ((phy->addr << 21) | (devad << 16) | val |
                       EMAC_MDIO_COMM_COMMAND_WRITE_45 |
                       EMAC_MDIO_COMM_START_BUSY);
-               REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
+               REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
 
                for (i = 0; i < 50; i++) {
                        udelay(10);
 
-                       tmp = REG_RD(bp, mdio_ctrl +
+                       tmp = REG_RD(bp, phy->mdio_ctrl +
                                         EMAC_REG_EMAC_MDIO_COMM);
                        if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
                                udelay(5);
@@ -888,42 +708,41 @@ u8 bnx2x_cl45_write(struct bnx2x *bp, u8 port, u32 ext_phy_type,
        }
 
        /* Restore the saved mode */
-       REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, saved_mode);
+       REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, saved_mode);
 
        return rc;
 }
 
-u8 bnx2x_cl45_read(struct bnx2x *bp, u8 port, u32 ext_phy_type,
-                u8 phy_addr, u8 devad, u16 reg, u16 *ret_val)
+u8 bnx2x_cl45_read(struct bnx2x *bp, struct bnx2x_phy *phy,
+                  u8 devad, u16 reg, u16 *ret_val)
 {
        u32 val, saved_mode;
        u16 i;
        u8 rc = 0;
 
-       u32 mdio_ctrl = bnx2x_get_emac_base(bp, ext_phy_type, port);
        /* set clause 45 mode, slow down the MDIO clock to 2.5MHz
         * (a value of 49==0x31) and make sure that the AUTO poll is off
         */
 
-       saved_mode = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
-       val = saved_mode & ((EMAC_MDIO_MODE_AUTO_POLL |
+       saved_mode = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
+       val = saved_mode & ~((EMAC_MDIO_MODE_AUTO_POLL |
                             EMAC_MDIO_MODE_CLOCK_CNT));
        val |= (EMAC_MDIO_MODE_CLAUSE_45 |
                (49L << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT));
-       REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, val);
-       REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
+       REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, val);
+       REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
        udelay(40);
 
        /* address */
-       val = ((phy_addr << 21) | (devad << 16) | reg |
+       val = ((phy->addr << 21) | (devad << 16) | reg |
               EMAC_MDIO_COMM_COMMAND_ADDRESS |
               EMAC_MDIO_COMM_START_BUSY);
-       REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
+       REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
 
        for (i = 0; i < 50; i++) {
                udelay(10);
 
-               val = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM);
+               val = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM);
                if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
                        udelay(5);
                        break;
@@ -937,15 +756,15 @@ u8 bnx2x_cl45_read(struct bnx2x *bp, u8 port, u32 ext_phy_type,
 
        } else {
                /* data */
-               val = ((phy_addr << 21) | (devad << 16) |
+               val = ((phy->addr << 21) | (devad << 16) |
                       EMAC_MDIO_COMM_COMMAND_READ_45 |
                       EMAC_MDIO_COMM_START_BUSY);
-               REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
+               REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
 
                for (i = 0; i < 50; i++) {
                        udelay(10);
 
-                       val = REG_RD(bp, mdio_ctrl +
+                       val = REG_RD(bp, phy->mdio_ctrl +
                                          EMAC_REG_EMAC_MDIO_COMM);
                        if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
                                *ret_val = (u16)(val & EMAC_MDIO_COMM_DATA);
@@ -961,13 +780,49 @@ u8 bnx2x_cl45_read(struct bnx2x *bp, u8 port, u32 ext_phy_type,
        }
 
        /* Restore the saved mode */
-       REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, saved_mode);
+       REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, saved_mode);
 
        return rc;
 }
 
+u8 bnx2x_phy_read(struct link_params *params, u8 phy_addr,
+                 u8 devad, u16 reg, u16 *ret_val)
+{
+       u8 phy_index;
+       /**
+        * Probe for the phy according to the given phy_addr, and execute
+        * the read request on it
+        */
+       for (phy_index = 0; phy_index < params->num_phys; phy_index++) {
+               if (params->phy[phy_index].addr == phy_addr) {
+                       return bnx2x_cl45_read(params->bp,
+                                              &params->phy[phy_index], devad,
+                                              reg, ret_val);
+               }
+       }
+       return -EINVAL;
+}
+
+u8 bnx2x_phy_write(struct link_params *params, u8 phy_addr,
+                  u8 devad, u16 reg, u16 val)
+{
+       u8 phy_index;
+       /**
+        * Probe for the phy according to the given phy_addr, and execute
+        * the write request on it
+        */
+       for (phy_index = 0; phy_index < params->num_phys; phy_index++) {
+               if (params->phy[phy_index].addr == phy_addr) {
+                       return bnx2x_cl45_write(params->bp,
+                                               &params->phy[phy_index], devad,
+                                               reg, val);
+               }
+       }
+       return -EINVAL;
+}
+
 static void bnx2x_set_aer_mmd(struct link_params *params,
-                           struct link_vars   *vars)
+                             struct bnx2x_phy *phy)
 {
        struct bnx2x *bp = params->bp;
        u32 ser_lane;
@@ -977,163 +832,338 @@ static void bnx2x_set_aer_mmd(struct link_params *params,
                     PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
                     PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
 
-       offset = (vars->phy_flags & PHY_XGXS_FLAG) ?
-               (params->phy_addr + ser_lane) : 0;
+       offset = (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) ?
+               (phy->addr + ser_lane) : 0;
 
-       CL45_WR_OVER_CL22(bp, params->port,
-                             params->phy_addr,
+       CL45_WR_OVER_CL22(bp, phy,
                              MDIO_REG_BANK_AER_BLOCK,
                              MDIO_AER_BLOCK_AER_REG, 0x3800 + offset);
 }
 
-static void bnx2x_set_master_ln(struct link_params *params)
-{
-       struct bnx2x *bp = params->bp;
-       u16 new_master_ln, ser_lane;
-       ser_lane =  ((params->lane_config &
-                    PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
-                    PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
+/******************************************************************/
+/*                     Internal phy section                      */
+/******************************************************************/
 
-       /* set the master_ln for AN */
-       CL45_RD_OVER_CL22(bp, params->port,
-                             params->phy_addr,
-                             MDIO_REG_BANK_XGXS_BLOCK2,
-                             MDIO_XGXS_BLOCK2_TEST_MODE_LANE,
-                             &new_master_ln);
+static void bnx2x_set_serdes_access(struct bnx2x *bp, u8 port)
+{
+       u32 emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
 
-       CL45_WR_OVER_CL22(bp, params->port,
-                             params->phy_addr,
-                             MDIO_REG_BANK_XGXS_BLOCK2 ,
-                             MDIO_XGXS_BLOCK2_TEST_MODE_LANE,
-                             (new_master_ln | ser_lane));
+       /* Set Clause 22 */
+       REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_ST + port*0x10, 1);
+       REG_WR(bp, emac_base + EMAC_REG_EMAC_MDIO_COMM, 0x245f8000);
+       udelay(500);
+       REG_WR(bp, emac_base + EMAC_REG_EMAC_MDIO_COMM, 0x245d000f);
+       udelay(500);
+        /* Set Clause 45 */
+       REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_ST + port*0x10, 0);
 }
 
-static u8 bnx2x_reset_unicore(struct link_params *params)
+static void bnx2x_serdes_deassert(struct bnx2x *bp, u8 port)
 {
-       struct bnx2x *bp = params->bp;
-       u16 mii_control;
-       u16 i;
+       u32 val;
 
-       CL45_RD_OVER_CL22(bp, params->port,
-                             params->phy_addr,
-                             MDIO_REG_BANK_COMBO_IEEE0,
-                             MDIO_COMBO_IEEE0_MII_CONTROL, &mii_control);
+       DP(NETIF_MSG_LINK, "bnx2x_serdes_deassert\n");
 
-       /* reset the unicore */
-       CL45_WR_OVER_CL22(bp, params->port,
-                             params->phy_addr,
-                             MDIO_REG_BANK_COMBO_IEEE0,
-                             MDIO_COMBO_IEEE0_MII_CONTROL,
-                             (mii_control |
-                              MDIO_COMBO_IEEO_MII_CONTROL_RESET));
-       if (params->switch_cfg == SWITCH_CFG_1G)
-               bnx2x_set_serdes_access(params);
+       val = SERDES_RESET_BITS << (port*16);
 
-       /* wait for the reset to self clear */
-       for (i = 0; i < MDIO_ACCESS_TIMEOUT; i++) {
-               udelay(5);
+       /* reset and unreset the SerDes/XGXS */
+       REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR, val);
+       udelay(500);
+       REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_SET, val);
 
-               /* the reset erased the previous bank value */
-               CL45_RD_OVER_CL22(bp, params->port,
-                                     params->phy_addr,
-                             MDIO_REG_BANK_COMBO_IEEE0,
-                             MDIO_COMBO_IEEE0_MII_CONTROL,
-                             &mii_control);
+       bnx2x_set_serdes_access(bp, port);
 
-               if (!(mii_control & MDIO_COMBO_IEEO_MII_CONTROL_RESET)) {
-                       udelay(5);
-                       return 0;
-               }
-       }
+       REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_DEVAD +
+                    port*0x10,
+                    DEFAULT_PHY_DEV_ADDR);
+}
 
-       DP(NETIF_MSG_LINK, "BUG! XGXS is still in reset!\n");
-       return -EINVAL;
+static void bnx2x_xgxs_deassert(struct link_params *params)
+{
+       struct bnx2x *bp = params->bp;
+       u8 port;
+       u32 val;
+       DP(NETIF_MSG_LINK, "bnx2x_xgxs_deassert\n");
+       port = params->port;
+
+       val = XGXS_RESET_BITS << (port*16);
 
+       /* reset and unreset the SerDes/XGXS */
+       REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR, val);
+       udelay(500);
+       REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_SET, val);
+
+       REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_ST +
+                    port*0x18, 0);
+       REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18,
+                    params->phy[INT_PHY].def_md_devad);
 }
 
-static void bnx2x_set_swap_lanes(struct link_params *params)
+
+void bnx2x_link_status_update(struct link_params *params,
+                           struct link_vars   *vars)
 {
        struct bnx2x *bp = params->bp;
-       /* Each two bits represents a lane number:
-          No swap is 0123 => 0x1b no need to enable the swap */
-       u16 ser_lane, rx_lane_swap, tx_lane_swap;
+       u8 link_10g;
+       u8 port = params->port;
 
-       ser_lane = ((params->lane_config &
-                        PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
-                       PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
-       rx_lane_swap = ((params->lane_config &
-                            PORT_HW_CFG_LANE_SWAP_CFG_RX_MASK) >>
-                           PORT_HW_CFG_LANE_SWAP_CFG_RX_SHIFT);
-       tx_lane_swap = ((params->lane_config &
-                            PORT_HW_CFG_LANE_SWAP_CFG_TX_MASK) >>
-                           PORT_HW_CFG_LANE_SWAP_CFG_TX_SHIFT);
+       vars->link_status = REG_RD(bp, params->shmem_base +
+                                         offsetof(struct shmem_region,
+                                          port_mb[port].link_status));
+
+       vars->link_up = (vars->link_status & LINK_STATUS_LINK_UP);
+
+       if (vars->link_up) {
+               DP(NETIF_MSG_LINK, "phy link up\n");
+
+               vars->phy_link_up = 1;
+               vars->duplex = DUPLEX_FULL;
+               switch (vars->link_status &
+                                       LINK_STATUS_SPEED_AND_DUPLEX_MASK) {
+                       case LINK_10THD:
+                               vars->duplex = DUPLEX_HALF;
+                               /* fall thru */
+                       case LINK_10TFD:
+                               vars->line_speed = SPEED_10;
+                               break;
+
+                       case LINK_100TXHD:
+                               vars->duplex = DUPLEX_HALF;
+                               /* fall thru */
+                       case LINK_100T4:
+                       case LINK_100TXFD:
+                               vars->line_speed = SPEED_100;
+                               break;
+
+                       case LINK_1000THD:
+                               vars->duplex = DUPLEX_HALF;
+                               /* fall thru */
+                       case LINK_1000TFD:
+                               vars->line_speed = SPEED_1000;
+                               break;
+
+                       case LINK_2500THD:
+                               vars->duplex = DUPLEX_HALF;
+                               /* fall thru */
+                       case LINK_2500TFD:
+                               vars->line_speed = SPEED_2500;
+                               break;
+
+                       case LINK_10GTFD:
+                               vars->line_speed = SPEED_10000;
+                               break;
+
+                       case LINK_12GTFD:
+                               vars->line_speed = SPEED_12000;
+                               break;
+
+                       case LINK_12_5GTFD:
+                               vars->line_speed = SPEED_12500;
+                               break;
+
+                       case LINK_13GTFD:
+                               vars->line_speed = SPEED_13000;
+                               break;
+
+                       case LINK_15GTFD:
+                               vars->line_speed = SPEED_15000;
+                               break;
+
+                       case LINK_16GTFD:
+                               vars->line_speed = SPEED_16000;
+                               break;
+
+                       default:
+                               break;
+               }
+               vars->flow_ctrl = 0;
+               if (vars->link_status & LINK_STATUS_TX_FLOW_CONTROL_ENABLED)
+                       vars->flow_ctrl |= BNX2X_FLOW_CTRL_TX;
+
+               if (vars->link_status & LINK_STATUS_RX_FLOW_CONTROL_ENABLED)
+                       vars->flow_ctrl |= BNX2X_FLOW_CTRL_RX;
+
+               if (!vars->flow_ctrl)
+                       vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
+
+               if (vars->line_speed &&
+                   ((vars->line_speed == SPEED_10) ||
+                    (vars->line_speed == SPEED_100))) {
+                       vars->phy_flags |= PHY_SGMII_FLAG;
+               } else {
+                       vars->phy_flags &= ~PHY_SGMII_FLAG;
+               }
+
+               /* anything 10 and over uses the bmac */
+               link_10g = ((vars->line_speed == SPEED_10000) ||
+                           (vars->line_speed == SPEED_12000) ||
+                           (vars->line_speed == SPEED_12500) ||
+                           (vars->line_speed == SPEED_13000) ||
+                           (vars->line_speed == SPEED_15000) ||
+                           (vars->line_speed == SPEED_16000));
+               if (link_10g)
+                       vars->mac_type = MAC_TYPE_BMAC;
+               else
+                       vars->mac_type = MAC_TYPE_EMAC;
+
+       } else { /* link down */
+               DP(NETIF_MSG_LINK, "phy link down\n");
+
+               vars->phy_link_up = 0;
+
+               vars->line_speed = 0;
+               vars->duplex = DUPLEX_FULL;
+               vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
+
+               /* indicate no mac active */
+               vars->mac_type = MAC_TYPE_NONE;
+       }
+
+       DP(NETIF_MSG_LINK, "link_status 0x%x  phy_link_up %x\n",
+                vars->link_status, vars->phy_link_up);
+       DP(NETIF_MSG_LINK, "line_speed %x  duplex %x  flow_ctrl 0x%x\n",
+                vars->line_speed, vars->duplex, vars->flow_ctrl);
+}
+
+
+static void bnx2x_set_master_ln(struct link_params *params,
+                               struct bnx2x_phy *phy)
+{
+       struct bnx2x *bp = params->bp;
+       u16 new_master_ln, ser_lane;
+       ser_lane =  ((params->lane_config &
+                    PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
+                    PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
+
+       /* set the master_ln for AN */
+       CL45_RD_OVER_CL22(bp, phy,
+                             MDIO_REG_BANK_XGXS_BLOCK2,
+                             MDIO_XGXS_BLOCK2_TEST_MODE_LANE,
+                             &new_master_ln);
+
+       CL45_WR_OVER_CL22(bp, phy,
+                             MDIO_REG_BANK_XGXS_BLOCK2 ,
+                             MDIO_XGXS_BLOCK2_TEST_MODE_LANE,
+                             (new_master_ln | ser_lane));
+}
+
+static u8 bnx2x_reset_unicore(struct link_params *params,
+                             struct bnx2x_phy *phy,
+                             u8 set_serdes)
+{
+       struct bnx2x *bp = params->bp;
+       u16 mii_control;
+       u16 i;
+
+       CL45_RD_OVER_CL22(bp, phy,
+                             MDIO_REG_BANK_COMBO_IEEE0,
+                             MDIO_COMBO_IEEE0_MII_CONTROL, &mii_control);
+
+       /* reset the unicore */
+       CL45_WR_OVER_CL22(bp, phy,
+                             MDIO_REG_BANK_COMBO_IEEE0,
+                             MDIO_COMBO_IEEE0_MII_CONTROL,
+                             (mii_control |
+                              MDIO_COMBO_IEEO_MII_CONTROL_RESET));
+       if (set_serdes)
+               bnx2x_set_serdes_access(bp, params->port);
+
+       /* wait for the reset to self clear */
+       for (i = 0; i < MDIO_ACCESS_TIMEOUT; i++) {
+               udelay(5);
+
+               /* the reset erased the previous bank value */
+               CL45_RD_OVER_CL22(bp, phy,
+                             MDIO_REG_BANK_COMBO_IEEE0,
+                             MDIO_COMBO_IEEE0_MII_CONTROL,
+                             &mii_control);
+
+               if (!(mii_control & MDIO_COMBO_IEEO_MII_CONTROL_RESET)) {
+                       udelay(5);
+                       return 0;
+               }
+       }
+
+       DP(NETIF_MSG_LINK, "BUG! XGXS is still in reset!\n");
+       return -EINVAL;
+
+}
+
+static void bnx2x_set_swap_lanes(struct link_params *params,
+                                struct bnx2x_phy *phy)
+{
+       struct bnx2x *bp = params->bp;
+       /* Each two bits represents a lane number:
+          No swap is 0123 => 0x1b no need to enable the swap */
+       u16 ser_lane, rx_lane_swap, tx_lane_swap;
+
+       ser_lane = ((params->lane_config &
+                        PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
+                       PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
+       rx_lane_swap = ((params->lane_config &
+                            PORT_HW_CFG_LANE_SWAP_CFG_RX_MASK) >>
+                           PORT_HW_CFG_LANE_SWAP_CFG_RX_SHIFT);
+       tx_lane_swap = ((params->lane_config &
+                            PORT_HW_CFG_LANE_SWAP_CFG_TX_MASK) >>
+                           PORT_HW_CFG_LANE_SWAP_CFG_TX_SHIFT);
 
        if (rx_lane_swap != 0x1b) {
-               CL45_WR_OVER_CL22(bp, params->port,
-                                     params->phy_addr,
+               CL45_WR_OVER_CL22(bp, phy,
                                    MDIO_REG_BANK_XGXS_BLOCK2,
                                    MDIO_XGXS_BLOCK2_RX_LN_SWAP,
                                    (rx_lane_swap |
                                    MDIO_XGXS_BLOCK2_RX_LN_SWAP_ENABLE |
                                    MDIO_XGXS_BLOCK2_RX_LN_SWAP_FORCE_ENABLE));
        } else {
-               CL45_WR_OVER_CL22(bp, params->port,
-                                     params->phy_addr,
+               CL45_WR_OVER_CL22(bp, phy,
                                      MDIO_REG_BANK_XGXS_BLOCK2,
                                      MDIO_XGXS_BLOCK2_RX_LN_SWAP, 0);
        }
 
        if (tx_lane_swap != 0x1b) {
-               CL45_WR_OVER_CL22(bp, params->port,
-                                     params->phy_addr,
+               CL45_WR_OVER_CL22(bp, phy,
                                      MDIO_REG_BANK_XGXS_BLOCK2,
                                      MDIO_XGXS_BLOCK2_TX_LN_SWAP,
                                      (tx_lane_swap |
                                       MDIO_XGXS_BLOCK2_TX_LN_SWAP_ENABLE));
        } else {
-               CL45_WR_OVER_CL22(bp, params->port,
-                                     params->phy_addr,
+               CL45_WR_OVER_CL22(bp, phy,
                                      MDIO_REG_BANK_XGXS_BLOCK2,
                                      MDIO_XGXS_BLOCK2_TX_LN_SWAP, 0);
        }
 }
 
-static void bnx2x_set_parallel_detection(struct link_params *params,
-                                      u8                phy_flags)
+static void bnx2x_set_parallel_detection(struct bnx2x_phy *phy,
+                                        struct link_params *params)
 {
        struct bnx2x *bp = params->bp;
        u16 control2;
-
-       CL45_RD_OVER_CL22(bp, params->port,
-                             params->phy_addr,
+       CL45_RD_OVER_CL22(bp, phy,
                              MDIO_REG_BANK_SERDES_DIGITAL,
                              MDIO_SERDES_DIGITAL_A_1000X_CONTROL2,
                              &control2);
-       if (params->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
+       if (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
                control2 |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_PRL_DT_EN;
        else
                control2 &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_PRL_DT_EN;
-       DP(NETIF_MSG_LINK, "params->speed_cap_mask = 0x%x, control2 = 0x%x\n",
-               params->speed_cap_mask, control2);
-       CL45_WR_OVER_CL22(bp, params->port,
-                             params->phy_addr,
+       DP(NETIF_MSG_LINK, "phy->speed_cap_mask = 0x%x, control2 = 0x%x\n",
+               phy->speed_cap_mask, control2);
+       CL45_WR_OVER_CL22(bp, phy,
                              MDIO_REG_BANK_SERDES_DIGITAL,
                              MDIO_SERDES_DIGITAL_A_1000X_CONTROL2,
                              control2);
 
-       if ((phy_flags & PHY_XGXS_FLAG) &&
-            (params->speed_cap_mask &
+       if ((phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) &&
+            (phy->speed_cap_mask &
                    PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) {
                DP(NETIF_MSG_LINK, "XGXS\n");
 
-               CL45_WR_OVER_CL22(bp, params->port,
-                                     params->phy_addr,
+               CL45_WR_OVER_CL22(bp, phy,
                                MDIO_REG_BANK_10G_PARALLEL_DETECT,
                                MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK,
                                MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK_CNT);
 
-               CL45_RD_OVER_CL22(bp, params->port,
-                                     params->phy_addr,
+               CL45_RD_OVER_CL22(bp, phy,
                                MDIO_REG_BANK_10G_PARALLEL_DETECT,
                                MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL,
                                &control2);
@@ -1142,15 +1172,13 @@ static void bnx2x_set_parallel_detection(struct link_params *params,
                control2 |=
                    MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL_PARDET10G_EN;
 
-               CL45_WR_OVER_CL22(bp, params->port,
-                                     params->phy_addr,
+               CL45_WR_OVER_CL22(bp, phy,
                                MDIO_REG_BANK_10G_PARALLEL_DETECT,
                                MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL,
                                control2);
 
                /* Disable parallel detection of HiG */
-               CL45_WR_OVER_CL22(bp, params->port,
-                                     params->phy_addr,
+               CL45_WR_OVER_CL22(bp, phy,
                                MDIO_REG_BANK_XGXS_BLOCK2,
                                MDIO_XGXS_BLOCK2_UNICORE_MODE_10G,
                                MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_CX4_XGXS |
@@ -1158,7 +1186,8 @@ static void bnx2x_set_parallel_detection(struct link_params *params,
        }
 }
 
-static void bnx2x_set_autoneg(struct link_params *params,
+static void bnx2x_set_autoneg(struct bnx2x_phy *phy,
+                             struct link_params *params,
                            struct link_vars *vars,
                            u8 enable_cl73)
 {
@@ -1166,9 +1195,7 @@ static void bnx2x_set_autoneg(struct link_params *params,
        u16 reg_val;
 
        /* CL37 Autoneg */
-
-       CL45_RD_OVER_CL22(bp, params->port,
-                             params->phy_addr,
+       CL45_RD_OVER_CL22(bp, phy,
                              MDIO_REG_BANK_COMBO_IEEE0,
                              MDIO_COMBO_IEEE0_MII_CONTROL, &reg_val);
 
@@ -1179,15 +1206,13 @@ static void bnx2x_set_autoneg(struct link_params *params,
                reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
                             MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN);
 
-       CL45_WR_OVER_CL22(bp, params->port,
-                             params->phy_addr,
+       CL45_WR_OVER_CL22(bp, phy,
                              MDIO_REG_BANK_COMBO_IEEE0,
                              MDIO_COMBO_IEEE0_MII_CONTROL, reg_val);
 
        /* Enable/Disable Autodetection */
 
-       CL45_RD_OVER_CL22(bp, params->port,
-                             params->phy_addr,
+       CL45_RD_OVER_CL22(bp, phy,
                              MDIO_REG_BANK_SERDES_DIGITAL,
                              MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, &reg_val);
        reg_val &= ~(MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_SIGNAL_DETECT_EN |
@@ -1198,14 +1223,12 @@ static void bnx2x_set_autoneg(struct link_params *params,
        else
                reg_val &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET;
 
-       CL45_WR_OVER_CL22(bp, params->port,
-                             params->phy_addr,
+       CL45_WR_OVER_CL22(bp, phy,
                              MDIO_REG_BANK_SERDES_DIGITAL,
                              MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, reg_val);
 
        /* Enable TetonII and BAM autoneg */
-       CL45_RD_OVER_CL22(bp, params->port,
-                             params->phy_addr,
+       CL45_RD_OVER_CL22(bp, phy,
                              MDIO_REG_BANK_BAM_NEXT_PAGE,
                              MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL,
                          &reg_val);
@@ -1218,23 +1241,20 @@ static void bnx2x_set_autoneg(struct link_params *params,
                reg_val &= ~(MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE |
                             MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN);
        }
-       CL45_WR_OVER_CL22(bp, params->port,
-                             params->phy_addr,
+       CL45_WR_OVER_CL22(bp, phy,
                              MDIO_REG_BANK_BAM_NEXT_PAGE,
                              MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL,
                              reg_val);
 
        if (enable_cl73) {
                /* Enable Cl73 FSM status bits */
-               CL45_WR_OVER_CL22(bp, params->port,
-                                     params->phy_addr,
+               CL45_WR_OVER_CL22(bp, phy,
                                      MDIO_REG_BANK_CL73_USERB0,
                                    MDIO_CL73_USERB0_CL73_UCTRL,
                                      0xe);
 
                /* Enable BAM Station Manager*/
-               CL45_WR_OVER_CL22(bp, params->port,
-                       params->phy_addr,
+               CL45_WR_OVER_CL22(bp, phy,
                        MDIO_REG_BANK_CL73_USERB0,
                        MDIO_CL73_USERB0_CL73_BAM_CTRL1,
                        MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_EN |
@@ -1242,20 +1262,18 @@ static void bnx2x_set_autoneg(struct link_params *params,
                        MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_NP_AFTER_BP_EN);
 
                /* Advertise CL73 link speeds */
-                       CL45_RD_OVER_CL22(bp, params->port,
-                                             params->phy_addr,
+               CL45_RD_OVER_CL22(bp, phy,
                                              MDIO_REG_BANK_CL73_IEEEB1,
                                              MDIO_CL73_IEEEB1_AN_ADV2,
                                              &reg_val);
-               if (params->speed_cap_mask &
+               if (phy->speed_cap_mask &
                    PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
                        reg_val |= MDIO_CL73_IEEEB1_AN_ADV2_ADVR_10G_KX4;
-               if (params->speed_cap_mask &
+               if (phy->speed_cap_mask &
                    PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
                        reg_val |= MDIO_CL73_IEEEB1_AN_ADV2_ADVR_1000M_KX;
 
-                       CL45_WR_OVER_CL22(bp, params->port,
-                                             params->phy_addr,
+               CL45_WR_OVER_CL22(bp, phy,
                                              MDIO_REG_BANK_CL73_IEEEB1,
                                              MDIO_CL73_IEEEB1_AN_ADV2,
                                      reg_val);
@@ -1266,38 +1284,35 @@ static void bnx2x_set_autoneg(struct link_params *params,
        } else /* CL73 Autoneg Disabled */
                reg_val = 0;
 
-       CL45_WR_OVER_CL22(bp, params->port,
-                             params->phy_addr,
+       CL45_WR_OVER_CL22(bp, phy,
                              MDIO_REG_BANK_CL73_IEEEB0,
                              MDIO_CL73_IEEEB0_CL73_AN_CONTROL, reg_val);
 }
 
 /* program SerDes, forced speed */
-static void bnx2x_program_serdes(struct link_params *params,
+static void bnx2x_program_serdes(struct bnx2x_phy *phy,
+                                struct link_params *params,
                               struct link_vars *vars)
 {
        struct bnx2x *bp = params->bp;
        u16 reg_val;
 
        /* program duplex, disable autoneg and sgmii*/
-       CL45_RD_OVER_CL22(bp, params->port,
-                             params->phy_addr,
+       CL45_RD_OVER_CL22(bp, phy,
                              MDIO_REG_BANK_COMBO_IEEE0,
                              MDIO_COMBO_IEEE0_MII_CONTROL, &reg_val);
        reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX |
                     MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
                     MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_MASK);
-       if (params->req_duplex == DUPLEX_FULL)
+       if (phy->req_duplex == DUPLEX_FULL)
                reg_val |= MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX;
-       CL45_WR_OVER_CL22(bp, params->port,
-                             params->phy_addr,
+       CL45_WR_OVER_CL22(bp, phy,
                              MDIO_REG_BANK_COMBO_IEEE0,
                              MDIO_COMBO_IEEE0_MII_CONTROL, reg_val);
 
        /* program speed
           - needed only if the speed is greater than 1G (2.5G or 10G) */
-       CL45_RD_OVER_CL22(bp, params->port,
-                                     params->phy_addr,
+       CL45_RD_OVER_CL22(bp, phy,
                                      MDIO_REG_BANK_SERDES_DIGITAL,
                                      MDIO_SERDES_DIGITAL_MISC1, &reg_val);
        /* clearing the speed value before setting the right speed */
@@ -1320,14 +1335,14 @@ static void bnx2x_program_serdes(struct link_params *params,
                                MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_13G;
        }
 
-       CL45_WR_OVER_CL22(bp, params->port,
-                                     params->phy_addr,
+       CL45_WR_OVER_CL22(bp, phy,
                                      MDIO_REG_BANK_SERDES_DIGITAL,
                                      MDIO_SERDES_DIGITAL_MISC1, reg_val);
 
 }
 
-static void bnx2x_set_brcm_cl37_advertisment(struct link_params *params)
+static void bnx2x_set_brcm_cl37_advertisment(struct bnx2x_phy *phy,
+                                            struct link_params *params)
 {
        struct bnx2x *bp = params->bp;
        u16 val = 0;
@@ -1335,29 +1350,28 @@ static void bnx2x_set_brcm_cl37_advertisment(struct link_params *params)
        /* configure the 48 bits for BAM AN */
 
        /* set extended capabilities */
-       if (params->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G)
+       if (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G)
                val |= MDIO_OVER_1G_UP1_2_5G;
-       if (params->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
+       if (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
                val |= MDIO_OVER_1G_UP1_10G;
-       CL45_WR_OVER_CL22(bp, params->port,
-                             params->phy_addr,
+       CL45_WR_OVER_CL22(bp, phy,
                              MDIO_REG_BANK_OVER_1G,
                              MDIO_OVER_1G_UP1, val);
 
-       CL45_WR_OVER_CL22(bp, params->port,
-                             params->phy_addr,
+       CL45_WR_OVER_CL22(bp, phy,
                              MDIO_REG_BANK_OVER_1G,
                              MDIO_OVER_1G_UP3, 0x400);
 }
 
-static void bnx2x_calc_ieee_aneg_adv(struct link_params *params, u16 *ieee_fc)
+static void bnx2x_calc_ieee_aneg_adv(struct bnx2x_phy *phy,
+                                    struct link_params *params, u16 *ieee_fc)
 {
        struct bnx2x *bp = params->bp;
        *ieee_fc = MDIO_COMBO_IEEE0_AUTO_NEG_ADV_FULL_DUPLEX;
        /* resolve pause mode and advertisement
         * Please refer to Table 28B-3 of the 802.3ab-1999 spec */
 
-       switch (params->req_flow_ctrl) {
+       switch (phy->req_flow_ctrl) {
        case BNX2X_FLOW_CTRL_AUTO:
                if (params->req_fc_auto_adv == BNX2X_FLOW_CTRL_BOTH) {
                        *ieee_fc |=
@@ -1385,30 +1399,30 @@ static void bnx2x_calc_ieee_aneg_adv(struct link_params *params, u16 *ieee_fc)
        DP(NETIF_MSG_LINK, "ieee_fc = 0x%x\n", *ieee_fc);
 }
 
-static void bnx2x_set_ieee_aneg_advertisment(struct link_params *params,
+static void bnx2x_set_ieee_aneg_advertisment(struct bnx2x_phy *phy,
+                                            struct link_params *params,
                                           u16 ieee_fc)
 {
        struct bnx2x *bp = params->bp;
        u16 val;
        /* for AN, we are always publishing full duplex */
 
-       CL45_WR_OVER_CL22(bp, params->port,
-                             params->phy_addr,
+       CL45_WR_OVER_CL22(bp, phy,
                              MDIO_REG_BANK_COMBO_IEEE0,
                              MDIO_COMBO_IEEE0_AUTO_NEG_ADV, ieee_fc);
-       CL45_RD_OVER_CL22(bp, params->port,
-                             params->phy_addr,
+       CL45_RD_OVER_CL22(bp, phy,
                              MDIO_REG_BANK_CL73_IEEEB1,
                              MDIO_CL73_IEEEB1_AN_ADV1, &val);
        val &= ~MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_BOTH;
        val |= ((ieee_fc<<3) & MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_MASK);
-       CL45_WR_OVER_CL22(bp, params->port,
-                             params->phy_addr,
+       CL45_WR_OVER_CL22(bp, phy,
                              MDIO_REG_BANK_CL73_IEEEB1,
                              MDIO_CL73_IEEEB1_AN_ADV1, val);
 }
 
-static void bnx2x_restart_autoneg(struct link_params *params, u8 enable_cl73)
+static void bnx2x_restart_autoneg(struct bnx2x_phy *phy,
+                                 struct link_params *params,
+                                 u8 enable_cl73)
 {
        struct bnx2x *bp = params->bp;
        u16 mii_control;
@@ -1417,14 +1431,12 @@ static void bnx2x_restart_autoneg(struct link_params *params, u8 enable_cl73)
        /* Enable and restart BAM/CL37 aneg */
 
        if (enable_cl73) {
-               CL45_RD_OVER_CL22(bp, params->port,
-                                     params->phy_addr,
+               CL45_RD_OVER_CL22(bp, phy,
                                      MDIO_REG_BANK_CL73_IEEEB0,
                                      MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
                                      &mii_control);
 
-               CL45_WR_OVER_CL22(bp, params->port,
-                               params->phy_addr,
+               CL45_WR_OVER_CL22(bp, phy,
                                MDIO_REG_BANK_CL73_IEEEB0,
                                MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
                                (mii_control |
@@ -1432,16 +1444,14 @@ static void bnx2x_restart_autoneg(struct link_params *params, u8 enable_cl73)
                                MDIO_CL73_IEEEB0_CL73_AN_CONTROL_RESTART_AN));
        } else {
 
-               CL45_RD_OVER_CL22(bp, params->port,
-                                     params->phy_addr,
+               CL45_RD_OVER_CL22(bp, phy,
                                      MDIO_REG_BANK_COMBO_IEEE0,
                                      MDIO_COMBO_IEEE0_MII_CONTROL,
                                      &mii_control);
                DP(NETIF_MSG_LINK,
                         "bnx2x_restart_autoneg mii_control before = 0x%x\n",
                         mii_control);
-               CL45_WR_OVER_CL22(bp, params->port,
-                                     params->phy_addr,
+               CL45_WR_OVER_CL22(bp, phy,
                                      MDIO_REG_BANK_COMBO_IEEE0,
                                      MDIO_COMBO_IEEE0_MII_CONTROL,
                                      (mii_control |
@@ -1450,7 +1460,8 @@ static void bnx2x_restart_autoneg(struct link_params *params, u8 enable_cl73)
        }
 }
 
-static void bnx2x_initialize_sgmii_process(struct link_params *params,
+static void bnx2x_initialize_sgmii_process(struct bnx2x_phy *phy,
+                                          struct link_params *params,
                                         struct link_vars *vars)
 {
        struct bnx2x *bp = params->bp;
@@ -1458,8 +1469,7 @@ static void bnx2x_initialize_sgmii_process(struct link_params *params,
 
        /* in SGMII mode, the unicore is always slave */
 
-       CL45_RD_OVER_CL22(bp, params->port,
-                             params->phy_addr,
+       CL45_RD_OVER_CL22(bp, phy,
                              MDIO_REG_BANK_SERDES_DIGITAL,
                              MDIO_SERDES_DIGITAL_A_1000X_CONTROL1,
                      &control1);
@@ -1468,8 +1478,7 @@ static void bnx2x_initialize_sgmii_process(struct link_params *params,
        control1 &= ~(MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_FIBER_MODE |
                      MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET |
                      MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_MSTR_MODE);
-       CL45_WR_OVER_CL22(bp, params->port,
-                             params->phy_addr,
+       CL45_WR_OVER_CL22(bp, phy,
                              MDIO_REG_BANK_SERDES_DIGITAL,
                              MDIO_SERDES_DIGITAL_A_1000X_CONTROL1,
                              control1);
@@ -1479,8 +1488,7 @@ static void bnx2x_initialize_sgmii_process(struct link_params *params,
                /* set speed, disable autoneg */
                u16 mii_control;
 
-               CL45_RD_OVER_CL22(bp, params->port,
-                                     params->phy_addr,
+               CL45_RD_OVER_CL22(bp, phy,
                                      MDIO_REG_BANK_COMBO_IEEE0,
                                      MDIO_COMBO_IEEE0_MII_CONTROL,
                                      &mii_control);
@@ -1508,18 +1516,17 @@ static void bnx2x_initialize_sgmii_process(struct link_params *params,
                }
 
                /* setting the full duplex */
-               if (params->req_duplex == DUPLEX_FULL)
+               if (phy->req_duplex == DUPLEX_FULL)
                        mii_control |=
                                MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX;
-               CL45_WR_OVER_CL22(bp, params->port,
-                                     params->phy_addr,
+               CL45_WR_OVER_CL22(bp, phy,
                                      MDIO_REG_BANK_COMBO_IEEE0,
                                      MDIO_COMBO_IEEE0_MII_CONTROL,
                                      mii_control);
 
        } else { /* AN mode */
                /* enable and restart AN */
-               bnx2x_restart_autoneg(params, 0);
+               bnx2x_restart_autoneg(phy, params, 0);
        }
 }
 
@@ -1549,91 +1556,24 @@ static void bnx2x_pause_resolve(struct link_vars *vars, u32 pause_result)
        default:
                break;
        }
+       if (pause_result & (1<<0))
+               vars->link_status |= LINK_STATUS_LINK_PARTNER_SYMMETRIC_PAUSE;
+       if (pause_result & (1<<1))
+               vars->link_status |= LINK_STATUS_LINK_PARTNER_ASYMMETRIC_PAUSE;
 }
 
-static u8 bnx2x_ext_phy_resolve_fc(struct link_params *params,
-                                 struct link_vars *vars)
-{
-       struct bnx2x *bp = params->bp;
-       u8 ext_phy_addr;
-       u16 ld_pause;           /* local */
-       u16 lp_pause;           /* link partner */
-       u16 an_complete;        /* AN complete */
-       u16 pause_result;
-       u8 ret = 0;
-       u32 ext_phy_type;
-       u8 port = params->port;
-       ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
-       ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
-       /* read twice */
-
-       bnx2x_cl45_read(bp, port,
-                     ext_phy_type,
-                     ext_phy_addr,
-                     MDIO_AN_DEVAD,
-                     MDIO_AN_REG_STATUS, &an_complete);
-       bnx2x_cl45_read(bp, port,
-                     ext_phy_type,
-                     ext_phy_addr,
-                     MDIO_AN_DEVAD,
-                     MDIO_AN_REG_STATUS, &an_complete);
-
-       if (an_complete & MDIO_AN_REG_STATUS_AN_COMPLETE) {
-               ret = 1;
-               bnx2x_cl45_read(bp, port,
-                             ext_phy_type,
-                             ext_phy_addr,
-                             MDIO_AN_DEVAD,
-                             MDIO_AN_REG_ADV_PAUSE, &ld_pause);
-               bnx2x_cl45_read(bp, port,
-                             ext_phy_type,
-                             ext_phy_addr,
-                             MDIO_AN_DEVAD,
-                             MDIO_AN_REG_LP_AUTO_NEG, &lp_pause);
-               pause_result = (ld_pause &
-                               MDIO_AN_REG_ADV_PAUSE_MASK) >> 8;
-               pause_result |= (lp_pause &
-                                MDIO_AN_REG_ADV_PAUSE_MASK) >> 10;
-               DP(NETIF_MSG_LINK, "Ext PHY pause result 0x%x\n",
-                  pause_result);
-               bnx2x_pause_resolve(vars, pause_result);
-               if (vars->flow_ctrl == BNX2X_FLOW_CTRL_NONE &&
-                    ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
-                       bnx2x_cl45_read(bp, port,
-                                     ext_phy_type,
-                                     ext_phy_addr,
-                                     MDIO_AN_DEVAD,
-                                     MDIO_AN_REG_CL37_FC_LD, &ld_pause);
-
-                       bnx2x_cl45_read(bp, port,
-                                     ext_phy_type,
-                                     ext_phy_addr,
-                                     MDIO_AN_DEVAD,
-                                     MDIO_AN_REG_CL37_FC_LP, &lp_pause);
-                       pause_result = (ld_pause &
-                               MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) >> 5;
-                       pause_result |= (lp_pause &
-                               MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) >> 7;
-
-                       bnx2x_pause_resolve(vars, pause_result);
-                       DP(NETIF_MSG_LINK, "Ext PHY CL37 pause result 0x%x\n",
-                                pause_result);
-               }
-       }
-       return ret;
-}
-
-static u8 bnx2x_direct_parallel_detect_used(struct link_params *params)
+static u8 bnx2x_direct_parallel_detect_used(struct bnx2x_phy *phy,
+                                           struct link_params *params)
 {
        struct bnx2x *bp = params->bp;
        u16 pd_10g, status2_1000x;
-       CL45_RD_OVER_CL22(bp, params->port,
-                             params->phy_addr,
+       if (phy->req_line_speed != SPEED_AUTO_NEG)
+               return 0;
+       CL45_RD_OVER_CL22(bp, phy,
                              MDIO_REG_BANK_SERDES_DIGITAL,
                              MDIO_SERDES_DIGITAL_A_1000X_STATUS2,
                              &status2_1000x);
-       CL45_RD_OVER_CL22(bp, params->port,
-                             params->phy_addr,
+       CL45_RD_OVER_CL22(bp, phy,
                              MDIO_REG_BANK_SERDES_DIGITAL,
                              MDIO_SERDES_DIGITAL_A_1000X_STATUS2,
                              &status2_1000x);
@@ -1643,8 +1583,7 @@ static u8 bnx2x_direct_parallel_detect_used(struct link_params *params)
                return 1;
        }
 
-       CL45_RD_OVER_CL22(bp, params->port,
-                             params->phy_addr,
+       CL45_RD_OVER_CL22(bp, phy,
                              MDIO_REG_BANK_10G_PARALLEL_DETECT,
                              MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_STATUS,
                              &pd_10g);
@@ -1657,9 +1596,10 @@ static u8 bnx2x_direct_parallel_detect_used(struct link_params *params)
        return 0;
 }
 
-static void bnx2x_flow_ctrl_resolve(struct link_params *params,
-                                 struct link_vars *vars,
-                                 u32 gp_status)
+static void bnx2x_flow_ctrl_resolve(struct bnx2x_phy *phy,
+                                   struct link_params *params,
+                                   struct link_vars *vars,
+                                   u32 gp_status)
 {
        struct bnx2x *bp = params->bp;
        u16 ld_pause;   /* local driver */
@@ -1669,12 +1609,13 @@ static void bnx2x_flow_ctrl_resolve(struct link_params *params,
        vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
 
        /* resolve from gp_status in case of AN complete and not sgmii */
-       if ((params->req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO) &&
-           (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) &&
-           (!(vars->phy_flags & PHY_SGMII_FLAG)) &&
-           (XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
-            PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT)) {
-               if (bnx2x_direct_parallel_detect_used(params)) {
+       if (phy->req_flow_ctrl != BNX2X_FLOW_CTRL_AUTO)
+               vars->flow_ctrl = phy->req_flow_ctrl;
+       else if (phy->req_line_speed != SPEED_AUTO_NEG)
+               vars->flow_ctrl = params->req_fc_auto_adv;
+       else if ((gp_status & MDIO_AN_CL73_OR_37_COMPLETE) &&
+                (!(vars->phy_flags & PHY_SGMII_FLAG))) {
+               if (bnx2x_direct_parallel_detect_used(phy, params)) {
                        vars->flow_ctrl = params->req_fc_auto_adv;
                        return;
                }
@@ -1684,13 +1625,11 @@ static void bnx2x_flow_ctrl_resolve(struct link_params *params,
                    (MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE |
                     MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_MR_LP_NP_AN_ABLE)) {
 
-                       CL45_RD_OVER_CL22(bp, params->port,
-                                             params->phy_addr,
+                       CL45_RD_OVER_CL22(bp, phy,
                                              MDIO_REG_BANK_CL73_IEEEB1,
                                              MDIO_CL73_IEEEB1_AN_ADV1,
                                              &ld_pause);
-                       CL45_RD_OVER_CL22(bp, params->port,
-                                            params->phy_addr,
+                       CL45_RD_OVER_CL22(bp, phy,
                                             MDIO_REG_BANK_CL73_IEEEB1,
                                             MDIO_CL73_IEEEB1_AN_LP_ADV1,
                                             &lp_pause);
@@ -1703,14 +1642,11 @@ static void bnx2x_flow_ctrl_resolve(struct link_params *params,
                        DP(NETIF_MSG_LINK, "pause_result CL73 0x%x\n",
                                 pause_result);
                } else {
-
-                       CL45_RD_OVER_CL22(bp, params->port,
-                                             params->phy_addr,
+                       CL45_RD_OVER_CL22(bp, phy,
                                              MDIO_REG_BANK_COMBO_IEEE0,
                                              MDIO_COMBO_IEEE0_AUTO_NEG_ADV,
                                              &ld_pause);
-                       CL45_RD_OVER_CL22(bp, params->port,
-                              params->phy_addr,
+                       CL45_RD_OVER_CL22(bp, phy,
                               MDIO_REG_BANK_COMBO_IEEE0,
                               MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1,
                               &lp_pause);
@@ -1722,26 +1658,18 @@ static void bnx2x_flow_ctrl_resolve(struct link_params *params,
                                 pause_result);
                }
                bnx2x_pause_resolve(vars, pause_result);
-       } else if ((params->req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO) &&
-                  (bnx2x_ext_phy_resolve_fc(params, vars))) {
-               return;
-       } else {
-               if (params->req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO)
-                       vars->flow_ctrl = params->req_fc_auto_adv;
-               else
-                       vars->flow_ctrl = params->req_flow_ctrl;
        }
        DP(NETIF_MSG_LINK, "flow_ctrl 0x%x\n", vars->flow_ctrl);
 }
 
-static void bnx2x_check_fallback_to_cl37(struct link_params *params)
+static void bnx2x_check_fallback_to_cl37(struct bnx2x_phy *phy,
+                                        struct link_params *params)
 {
        struct bnx2x *bp = params->bp;
        u16 rx_status, ustat_val, cl37_fsm_recieved;
        DP(NETIF_MSG_LINK, "bnx2x_check_fallback_to_cl37\n");
        /* Step 1: Make sure signal is detected */
-       CL45_RD_OVER_CL22(bp, params->port,
-                             params->phy_addr,
+       CL45_RD_OVER_CL22(bp, phy,
                              MDIO_REG_BANK_RX0,
                              MDIO_RX0_RX_STATUS,
                              &rx_status);
@@ -1749,16 +1677,14 @@ static void bnx2x_check_fallback_to_cl37(struct link_params *params)
            (MDIO_RX0_RX_STATUS_SIGDET)) {
                DP(NETIF_MSG_LINK, "Signal is not detected. Restoring CL73."
                             "rx_status(0x80b0) = 0x%x\n", rx_status);
-               CL45_WR_OVER_CL22(bp, params->port,
-                                     params->phy_addr,
+               CL45_WR_OVER_CL22(bp, phy,
                                      MDIO_REG_BANK_CL73_IEEEB0,
                                      MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
                                      MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN);
                return;
        }
        /* Step 2: Check CL73 state machine */
-       CL45_RD_OVER_CL22(bp, params->port,
-                             params->phy_addr,
+       CL45_RD_OVER_CL22(bp, phy,
                              MDIO_REG_BANK_CL73_USERB0,
                              MDIO_CL73_USERB0_CL73_USTAT1,
                              &ustat_val);
@@ -1773,8 +1699,7 @@ static void bnx2x_check_fallback_to_cl37(struct link_params *params)
        }
        /* Step 3: Check CL37 Message Pages received to indicate LP
        supports only CL37 */
-       CL45_RD_OVER_CL22(bp, params->port,
-                             params->phy_addr,
+       CL45_RD_OVER_CL22(bp, phy,
                              MDIO_REG_BANK_REMOTE_PHY,
                              MDIO_REMOTE_PHY_MISC_RX_STATUS,
                              &cl37_fsm_recieved);
@@ -1792,25 +1717,45 @@ static void bnx2x_check_fallback_to_cl37(struct link_params *params)
        connected to a device which does not support cl73, but does support
        cl37 BAM. In this case we disable cl73 and restart cl37 auto-neg */
        /* Disable CL73 */
-       CL45_WR_OVER_CL22(bp, params->port,
-                             params->phy_addr,
+       CL45_WR_OVER_CL22(bp, phy,
                              MDIO_REG_BANK_CL73_IEEEB0,
                              MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
                              0);
        /* Restart CL37 autoneg */
-       bnx2x_restart_autoneg(params, 0);
+       bnx2x_restart_autoneg(phy, params, 0);
        DP(NETIF_MSG_LINK, "Disabling CL73, and restarting CL37 autoneg\n");
 }
-static u8 bnx2x_link_settings_status(struct link_params *params,
-                                  struct link_vars *vars,
-                                  u32 gp_status,
-                                  u8 ext_phy_link_up)
+
+static void bnx2x_xgxs_an_resolve(struct bnx2x_phy *phy,
+                                 struct link_params *params,
+                                 struct link_vars *vars,
+                                 u32 gp_status)
+{
+       if (gp_status & MDIO_AN_CL73_OR_37_COMPLETE)
+               vars->link_status |=
+                       LINK_STATUS_AUTO_NEGOTIATE_COMPLETE;
+
+       if (bnx2x_direct_parallel_detect_used(phy, params))
+               vars->link_status |=
+                       LINK_STATUS_PARALLEL_DETECTION_USED;
+}
+
+static u8 bnx2x_link_settings_status(struct bnx2x_phy *phy,
+                                    struct link_params *params,
+                                    struct link_vars *vars)
 {
        struct bnx2x *bp = params->bp;
-       u16 new_line_speed;
+       u16 new_line_speed , gp_status;
        u8 rc = 0;
-       vars->link_status = 0;
 
+       /* Read gp_status */
+       CL45_RD_OVER_CL22(bp, phy,
+                               MDIO_REG_BANK_GP_STATUS,
+                               MDIO_GP_STATUS_TOP_AN_STATUS1,
+                               &gp_status);
+
+       if (phy->req_line_speed == SPEED_AUTO_NEG)
+               vars->link_status |= LINK_STATUS_AUTO_NEGOTIATE_ENABLED;
        if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) {
                DP(NETIF_MSG_LINK, "phy link up gp_status=0x%x\n",
                         gp_status);
@@ -1823,7 +1768,12 @@ static u8 bnx2x_link_settings_status(struct link_params *params,
                else
                        vars->duplex = DUPLEX_HALF;
 
-               bnx2x_flow_ctrl_resolve(params, vars, gp_status);
+               if (SINGLE_MEDIA_DIRECT(params)) {
+                       bnx2x_flow_ctrl_resolve(phy, params, vars, gp_status);
+                       if (phy->req_line_speed == SPEED_AUTO_NEG)
+                               bnx2x_xgxs_an_resolve(phy, params, vars,
+                                                     gp_status);
+               }
 
                switch (gp_status & GP_STATUS_SPEED_MASK) {
                case GP_STATUS_10M:
@@ -1905,56 +1855,7 @@ static u8 bnx2x_link_settings_status(struct link_params *params,
                        return -EINVAL;
                }
 
-               /* Upon link speed change set the NIG into drain mode.
-               Comes to deals with possible FIFO glitch due to clk change
-               when speed is decreased without link down indicator */
-               if (new_line_speed != vars->line_speed) {
-                       if (XGXS_EXT_PHY_TYPE(params->ext_phy_config) !=
-                            PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT &&
-                           ext_phy_link_up) {
-                               DP(NETIF_MSG_LINK, "Internal link speed %d is"
-                                           " different than the external"
-                                           " link speed %d\n", new_line_speed,
-                                         vars->line_speed);
-                               vars->phy_link_up = 0;
-                               return 0;
-                       }
-                       REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE
-                                   + params->port*4, 0);
-                       msleep(1);
-               }
                vars->line_speed = new_line_speed;
-               vars->link_status |= LINK_STATUS_SERDES_LINK;
-
-               if ((params->req_line_speed == SPEED_AUTO_NEG) &&
-                   ((XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
-                    PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) ||
-                   (XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
-                    PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) ||
-                   (XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
-                    PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706) ||
-                   (XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
-                    PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726))) {
-                       vars->autoneg = AUTO_NEG_ENABLED;
-
-                       if (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) {
-                               vars->autoneg |= AUTO_NEG_COMPLETE;
-                               vars->link_status |=
-                                       LINK_STATUS_AUTO_NEGOTIATE_COMPLETE;
-                       }
-
-                       vars->autoneg |= AUTO_NEG_PARALLEL_DETECTION_USED;
-                       vars->link_status |=
-                               LINK_STATUS_PARALLEL_DETECTION_USED;
-
-               }
-               if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
-                       vars->link_status |=
-                               LINK_STATUS_TX_FLOW_CONTROL_ENABLED;
-
-               if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
-                       vars->link_status |=
-                               LINK_STATUS_RX_FLOW_CONTROL_ENABLED;
 
        } else { /* link_down */
                DP(NETIF_MSG_LINK, "phy link down\n");
@@ -1963,38 +1864,32 @@ static u8 bnx2x_link_settings_status(struct link_params *params,
 
                vars->duplex = DUPLEX_FULL;
                vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
-               vars->autoneg = AUTO_NEG_DISABLED;
                vars->mac_type = MAC_TYPE_NONE;
 
-               if ((params->req_line_speed == SPEED_AUTO_NEG) &&
-                   ((XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
-                    PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT))) {
+               if ((phy->req_line_speed == SPEED_AUTO_NEG) &&
+                   SINGLE_MEDIA_DIRECT(params)) {
                        /* Check signal is detected */
-                       bnx2x_check_fallback_to_cl37(params);
+                       bnx2x_check_fallback_to_cl37(phy, params);
                }
        }
 
        DP(NETIF_MSG_LINK, "gp_status 0x%x  phy_link_up %x line_speed %x\n",
                 gp_status, vars->phy_link_up, vars->line_speed);
-       DP(NETIF_MSG_LINK, "duplex %x  flow_ctrl 0x%x"
-                " autoneg 0x%x\n",
-                vars->duplex,
-                vars->flow_ctrl, vars->autoneg);
-       DP(NETIF_MSG_LINK, "link_status 0x%x\n", vars->link_status);
-
+       DP(NETIF_MSG_LINK, "duplex %x  flow_ctrl 0x%x link_status 0x%x\n",
+                  vars->duplex, vars->flow_ctrl, vars->link_status);
        return rc;
 }
 
 static void bnx2x_set_gmii_tx_driver(struct link_params *params)
 {
        struct bnx2x *bp = params->bp;
+       struct bnx2x_phy *phy = &params->phy[INT_PHY];
        u16 lp_up2;
        u16 tx_driver;
        u16 bank;
 
        /* read precomp */
-       CL45_RD_OVER_CL22(bp, params->port,
-                             params->phy_addr,
+       CL45_RD_OVER_CL22(bp, phy,
                              MDIO_REG_BANK_OVER_1G,
                              MDIO_OVER_1G_LP_UP2, &lp_up2);
 
@@ -2008,8 +1903,7 @@ static void bnx2x_set_gmii_tx_driver(struct link_params *params)
 
        for (bank = MDIO_REG_BANK_TX0; bank <= MDIO_REG_BANK_TX3;
              bank += (MDIO_REG_BANK_TX1 - MDIO_REG_BANK_TX0)) {
-               CL45_RD_OVER_CL22(bp, params->port,
-                                     params->phy_addr,
+               CL45_RD_OVER_CL22(bp, phy,
                                      bank,
                                      MDIO_TX0_TX_DRIVER, &tx_driver);
 
@@ -2018,8 +1912,7 @@ static void bnx2x_set_gmii_tx_driver(struct link_params *params)
                    (tx_driver & MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK)) {
                        tx_driver &= ~MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK;
                        tx_driver |= lp_up2;
-                       CL45_WR_OVER_CL22(bp, params->port,
-                                             params->phy_addr,
+                       CL45_WR_OVER_CL22(bp, phy,
                                              bank,
                                              MDIO_TX0_TX_DRIVER, tx_driver);
                }
@@ -2027,7 +1920,7 @@ static void bnx2x_set_gmii_tx_driver(struct link_params *params)
 }
 
 static u8 bnx2x_emac_program(struct link_params *params,
-                          u32 line_speed, u32 duplex)
+                            struct link_vars *vars)
 {
        struct bnx2x *bp = params->bp;
        u8 port = params->port;
@@ -2039,7 +1932,7 @@ static u8 bnx2x_emac_program(struct link_params *params,
                     (EMAC_MODE_25G_MODE |
                     EMAC_MODE_PORT_MII_10M |
                     EMAC_MODE_HALF_DUPLEX));
-       switch (line_speed) {
+       switch (vars->line_speed) {
        case SPEED_10:
                mode |= EMAC_MODE_PORT_MII_10M;
                break;
@@ -2058,401 +1951,1393 @@ static u8 bnx2x_emac_program(struct link_params *params,
 
        default:
                /* 10G not valid for EMAC */
-               DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n", line_speed);
+               DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
+                          vars->line_speed);
                return -EINVAL;
        }
 
-       if (duplex == DUPLEX_HALF)
+       if (vars->duplex == DUPLEX_HALF)
                mode |= EMAC_MODE_HALF_DUPLEX;
        bnx2x_bits_en(bp,
                    GRCBASE_EMAC0 + port*0x400 + EMAC_REG_EMAC_MODE,
                    mode);
 
-       bnx2x_set_led(params, LED_MODE_OPER, line_speed);
+       bnx2x_set_led(params, vars, LED_MODE_OPER, vars->line_speed);
        return 0;
 }
 
-/*****************************************************************************/
-/*                          External Phy section                            */
-/*****************************************************************************/
-void bnx2x_ext_phy_hw_reset(struct bnx2x *bp, u8 port)
+static void bnx2x_set_preemphasis(struct bnx2x_phy *phy,
+                                 struct link_params *params)
 {
-       bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
-                      MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
-       msleep(1);
-       bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
-                     MISC_REGISTERS_GPIO_OUTPUT_HIGH, port);
+
+       u16 bank, i = 0;
+       struct bnx2x *bp = params->bp;
+
+       for (bank = MDIO_REG_BANK_RX0, i = 0; bank <= MDIO_REG_BANK_RX3;
+             bank += (MDIO_REG_BANK_RX1-MDIO_REG_BANK_RX0), i++) {
+                       CL45_WR_OVER_CL22(bp, phy,
+                                         bank,
+                                         MDIO_RX0_RX_EQ_BOOST,
+                                         phy->rx_preemphasis[i]);
+       }
+
+       for (bank = MDIO_REG_BANK_TX0, i = 0; bank <= MDIO_REG_BANK_TX3;
+                     bank += (MDIO_REG_BANK_TX1 - MDIO_REG_BANK_TX0), i++) {
+                       CL45_WR_OVER_CL22(bp, phy,
+                                         bank,
+                                         MDIO_TX0_TX_DRIVER,
+                                         phy->tx_preemphasis[i]);
+       }
 }
 
-static void bnx2x_ext_phy_reset(struct link_params *params,
-                             struct link_vars   *vars)
+static void bnx2x_init_internal_phy(struct bnx2x_phy *phy,
+                                   struct link_params *params,
+                                   struct link_vars *vars)
 {
        struct bnx2x *bp = params->bp;
-       u32 ext_phy_type;
-       u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
-
-       DP(NETIF_MSG_LINK, "Port %x: bnx2x_ext_phy_reset\n", params->port);
-       ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
-       /* The PHY reset is controled by GPIO 1
-        * Give it 1ms of reset pulse
-        */
-       if (vars->phy_flags & PHY_XGXS_FLAG) {
+       u8 enable_cl73 = (SINGLE_MEDIA_DIRECT(params) ||
+                         (params->loopback_mode == LOOPBACK_XGXS));
+       if (!(vars->phy_flags & PHY_SGMII_FLAG)) {
+               if (SINGLE_MEDIA_DIRECT(params) &&
+                   (params->feature_config_flags &
+                    FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED))
+                       bnx2x_set_preemphasis(phy, params);
 
-               switch (ext_phy_type) {
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
-                       DP(NETIF_MSG_LINK, "XGXS Direct\n");
-                       break;
+               /* forced speed requested? */
+               if (vars->line_speed != SPEED_AUTO_NEG ||
+                   (SINGLE_MEDIA_DIRECT(params) &&
+                         params->loopback_mode == LOOPBACK_EXT)) {
+                       DP(NETIF_MSG_LINK, "not SGMII, no AN\n");
 
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
-                       DP(NETIF_MSG_LINK, "XGXS 8705/8706\n");
+                       /* disable autoneg */
+                       bnx2x_set_autoneg(phy, params, vars, 0);
 
-                       /* Restore normal power mode*/
-                       bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
-                                     MISC_REGISTERS_GPIO_OUTPUT_HIGH,
-                                         params->port);
+                       /* program speed and duplex */
+                       bnx2x_program_serdes(phy, params, vars);
 
-                       /* HW reset */
-                       bnx2x_ext_phy_hw_reset(bp, params->port);
+               } else { /* AN_mode */
+                       DP(NETIF_MSG_LINK, "not SGMII, AN\n");
 
-                       bnx2x_cl45_write(bp, params->port,
-                                      ext_phy_type,
-                                      ext_phy_addr,
-                                      MDIO_PMA_DEVAD,
-                                      MDIO_PMA_REG_CTRL, 0xa040);
-                       break;
+                       /* AN enabled */
+                       bnx2x_set_brcm_cl37_advertisment(phy, params);
 
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
-                       break;
+                       /* program duplex & pause advertisement (for aneg) */
+                       bnx2x_set_ieee_aneg_advertisment(phy, params,
+                                                      vars->ieee_fc);
 
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
+                       /* enable autoneg */
+                       bnx2x_set_autoneg(phy, params, vars, enable_cl73);
 
-                       /* Restore normal power mode*/
-                       bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
-                                         MISC_REGISTERS_GPIO_OUTPUT_HIGH,
-                                         params->port);
+                       /* enable and restart AN */
+                       bnx2x_restart_autoneg(phy, params, enable_cl73);
+               }
 
-                       bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
-                                         MISC_REGISTERS_GPIO_OUTPUT_HIGH,
-                                         params->port);
+       } else { /* SGMII mode */
+               DP(NETIF_MSG_LINK, "SGMII\n");
 
-                       bnx2x_cl45_write(bp, params->port,
-                                      ext_phy_type,
-                                      ext_phy_addr,
-                                      MDIO_PMA_DEVAD,
-                                      MDIO_PMA_REG_CTRL,
-                                      1<<15);
-                       break;
+               bnx2x_initialize_sgmii_process(phy, params, vars);
+       }
+}
 
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
-                       DP(NETIF_MSG_LINK, "XGXS 8072\n");
+static u8 bnx2x_init_serdes(struct bnx2x_phy *phy,
+                           struct link_params *params,
+                           struct link_vars *vars)
+{
+       u8 rc;
+       vars->phy_flags |= PHY_SGMII_FLAG;
+       bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc);
+       bnx2x_set_aer_mmd(params, phy);
+       rc = bnx2x_reset_unicore(params, phy, 1);
+       /* reset the SerDes and wait for reset bit return low */
+       if (rc != 0)
+               return rc;
+       bnx2x_set_aer_mmd(params, phy);
 
-                       /* Unset Low Power Mode and SW reset */
-                       /* Restore normal power mode*/
-                       bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
-                                     MISC_REGISTERS_GPIO_OUTPUT_HIGH,
-                                         params->port);
+       return rc;
+}
 
-                       bnx2x_cl45_write(bp, params->port,
-                                      ext_phy_type,
-                                      ext_phy_addr,
-                                      MDIO_PMA_DEVAD,
-                                      MDIO_PMA_REG_CTRL,
-                                      1<<15);
-                       break;
+static u8 bnx2x_init_xgxs(struct bnx2x_phy *phy,
+                         struct link_params *params,
+                         struct link_vars *vars)
+{
+       u8 rc;
+       vars->phy_flags = PHY_XGXS_FLAG;
+       if ((phy->req_line_speed &&
+            ((phy->req_line_speed == SPEED_100) ||
+             (phy->req_line_speed == SPEED_10))) ||
+           (!phy->req_line_speed &&
+            (phy->speed_cap_mask >=
+             PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL) &&
+            (phy->speed_cap_mask <
+             PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
+            ))
+               vars->phy_flags |= PHY_SGMII_FLAG;
+       else
+               vars->phy_flags &= ~PHY_SGMII_FLAG;
 
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
-                       DP(NETIF_MSG_LINK, "XGXS 8073\n");
+       bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc);
+       bnx2x_set_aer_mmd(params, phy);
+       bnx2x_set_master_ln(params, phy);
 
-                       /* Restore normal power mode*/
-                       bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
-                                     MISC_REGISTERS_GPIO_OUTPUT_HIGH,
-                                         params->port);
+       rc = bnx2x_reset_unicore(params, phy, 0);
+       /* reset the SerDes and wait for reset bit return low */
+       if (rc != 0)
+               return rc;
 
-                       bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
-                                     MISC_REGISTERS_GPIO_OUTPUT_HIGH,
-                                         params->port);
-                       break;
+       bnx2x_set_aer_mmd(params, phy);
 
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
-                       DP(NETIF_MSG_LINK, "XGXS SFX7101\n");
+       /* setting the masterLn_def again after the reset */
+       bnx2x_set_master_ln(params, phy);
+       bnx2x_set_swap_lanes(params, phy);
 
-                       /* Restore normal power mode*/
-                       bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
-                                     MISC_REGISTERS_GPIO_OUTPUT_HIGH,
-                                         params->port);
+       return rc;
+}
 
-                       /* HW reset */
-                       bnx2x_ext_phy_hw_reset(bp, params->port);
+static u16 bnx2x_wait_reset_complete(struct bnx2x *bp,
+                                    struct bnx2x_phy *phy)
+{
+       u16 cnt, ctrl;
+       /* Wait for soft reset to get cleared upto 1 sec */
+       for (cnt = 0; cnt < 1000; cnt++) {
+               bnx2x_cl45_read(bp, phy,
+                               MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, &ctrl);
+               if (!(ctrl & (1<<15)))
                        break;
+               msleep(1);
+       }
+       DP(NETIF_MSG_LINK, "control reg 0x%x (after %d ms)\n", ctrl, cnt);
+       return cnt;
+}
 
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
-                       /* Restore normal power mode*/
-                       bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
-                                     MISC_REGISTERS_GPIO_OUTPUT_HIGH,
-                                         params->port);
-
-                       /* HW reset */
-                       bnx2x_ext_phy_hw_reset(bp, params->port);
+static void bnx2x_link_int_enable(struct link_params *params)
+{
+       u8 port = params->port;
+       u32 mask;
+       struct bnx2x *bp = params->bp;
 
-                       bnx2x_cl45_write(bp, params->port,
-                                      ext_phy_type,
-                                      ext_phy_addr,
-                                      MDIO_PMA_DEVAD,
-                                      MDIO_PMA_REG_CTRL,
-                                      1<<15);
-                       break;
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823:
-                       break;
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
-                       DP(NETIF_MSG_LINK, "XGXS PHY Failure detected\n");
-                       break;
+       /* setting the status to report on link up
+          for either XGXS or SerDes */
 
-               default:
-                       DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n",
-                          params->ext_phy_config);
-                       break;
+       if (params->switch_cfg == SWITCH_CFG_10G) {
+               mask = (NIG_MASK_XGXS0_LINK10G |
+                       NIG_MASK_XGXS0_LINK_STATUS);
+               DP(NETIF_MSG_LINK, "enabled XGXS interrupt\n");
+               if (!(SINGLE_MEDIA_DIRECT(params)) &&
+                       params->phy[INT_PHY].type !=
+                               PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) {
+                       mask |= NIG_MASK_MI_INT;
+                       DP(NETIF_MSG_LINK, "enabled external phy int\n");
                }
 
        } else { /* SerDes */
-               ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
-               switch (ext_phy_type) {
-               case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT:
-                       DP(NETIF_MSG_LINK, "SerDes Direct\n");
-                       break;
-
-               case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482:
-                       DP(NETIF_MSG_LINK, "SerDes 5482\n");
-                       bnx2x_ext_phy_hw_reset(bp, params->port);
-                       break;
-
-               default:
-                       DP(NETIF_MSG_LINK, "BAD SerDes ext_phy_config 0x%x\n",
-                                params->ext_phy_config);
-                       break;
+               mask = NIG_MASK_SERDES0_LINK_STATUS;
+               DP(NETIF_MSG_LINK, "enabled SerDes interrupt\n");
+               if (!(SINGLE_MEDIA_DIRECT(params)) &&
+                       params->phy[INT_PHY].type !=
+                               PORT_HW_CFG_SERDES_EXT_PHY_TYPE_NOT_CONN) {
+                       mask |= NIG_MASK_MI_INT;
+                       DP(NETIF_MSG_LINK, "enabled external phy int\n");
                }
        }
-}
-
-static void bnx2x_save_spirom_version(struct bnx2x *bp, u8 port,
-                                   u32 shmem_base, u32 spirom_ver)
-{
-       DP(NETIF_MSG_LINK, "FW version 0x%x:0x%x for port %d\n",
-                (u16)(spirom_ver>>16), (u16)spirom_ver, port);
-       REG_WR(bp, shmem_base +
-                  offsetof(struct shmem_region,
-                           port_mb[port].ext_phy_fw_version),
-                       spirom_ver);
-}
-
-static void bnx2x_save_bcm_spirom_ver(struct bnx2x *bp, u8 port,
-                                   u32 ext_phy_type, u8 ext_phy_addr,
-                                   u32 shmem_base)
-{
-       u16 fw_ver1, fw_ver2;
+       bnx2x_bits_en(bp,
+                     NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
+                     mask);
 
-       bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr, MDIO_PMA_DEVAD,
-                     MDIO_PMA_REG_ROM_VER1, &fw_ver1);
-       bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr, MDIO_PMA_DEVAD,
-                     MDIO_PMA_REG_ROM_VER2, &fw_ver2);
-       bnx2x_save_spirom_version(bp, port, shmem_base,
-                               (u32)(fw_ver1<<16 | fw_ver2));
+       DP(NETIF_MSG_LINK, "port %x, is_xgxs %x, int_status 0x%x\n", port,
+                (params->switch_cfg == SWITCH_CFG_10G),
+                REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4));
+       DP(NETIF_MSG_LINK, " int_mask 0x%x, MI_INT %x, SERDES_LINK %x\n",
+                REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4),
+                REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT + port*0x18),
+                REG_RD(bp, NIG_REG_SERDES0_STATUS_LINK_STATUS+port*0x3c));
+       DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n",
+          REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
+          REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68));
 }
 
-
-static void bnx2x_save_8481_spirom_version(struct bnx2x *bp, u8 port,
-                                        u8 ext_phy_addr, u32 shmem_base)
+static void bnx2x_rearm_latch_signal(struct bnx2x *bp, u8 port,
+                                    u8 exp_mi_int)
 {
-       u16 val, fw_ver1, fw_ver2, cnt;
-       /* For the 32 bits registers in 8481, access via MDIO2ARM interface.*/
-       /* (1) set register 0xc200_0014(SPI_BRIDGE_CTRL_2) to 0x03000000 */
-       bnx2x_cl45_write(bp, port,
-                      PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
-                      ext_phy_addr, MDIO_PMA_DEVAD,
-                      0xA819, 0x0014);
-       bnx2x_cl45_write(bp, port,
-                      PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
-                      ext_phy_addr,
-                      MDIO_PMA_DEVAD,
-                      0xA81A,
-                      0xc200);
-       bnx2x_cl45_write(bp, port,
-                      PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
-                      ext_phy_addr,
-                      MDIO_PMA_DEVAD,
-                      0xA81B,
-                      0x0000);
-       bnx2x_cl45_write(bp, port,
-                      PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
-                      ext_phy_addr,
-                      MDIO_PMA_DEVAD,
-                      0xA81C,
-                      0x0300);
-       bnx2x_cl45_write(bp, port,
-                      PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
-                      ext_phy_addr,
-                      MDIO_PMA_DEVAD,
-                      0xA817,
-                      0x0009);
+       u32 latch_status = 0;
 
-       for (cnt = 0; cnt < 100; cnt++) {
-               bnx2x_cl45_read(bp, port,
-                             PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
-                             ext_phy_addr,
-                             MDIO_PMA_DEVAD,
-                             0xA818,
-                             &val);
-               if (val & 1)
-                       break;
-               udelay(5);
-       }
-       if (cnt == 100) {
-               DP(NETIF_MSG_LINK, "Unable to read 8481 phy fw version(1)\n");
-               bnx2x_save_spirom_version(bp, port,
-                                       shmem_base, 0);
-               return;
-       }
+       /**
+        * Disable the MI INT ( external phy int ) by writing 1 to the
+        * status register. Link down indication is high-active-signal,
+        * so in this case we need to write the status to clear the XOR
+        */
+       /* Read Latched signals */
+       latch_status = REG_RD(bp,
+                                   NIG_REG_LATCH_STATUS_0 + port*8);
+       DP(NETIF_MSG_LINK, "latch_status = 0x%x\n", latch_status);
+       /* Handle only those with latched-signal=up.*/
+       if (exp_mi_int)
+               bnx2x_bits_en(bp,
+                             NIG_REG_STATUS_INTERRUPT_PORT0
+                             + port*4,
+                             NIG_STATUS_EMAC0_MI_INT);
+       else
+               bnx2x_bits_dis(bp,
+                              NIG_REG_STATUS_INTERRUPT_PORT0
+                              + port*4,
+                              NIG_STATUS_EMAC0_MI_INT);
 
+       if (latch_status & 1) {
 
-       /* 2) read register 0xc200_0000 (SPI_FW_STATUS) */
-       bnx2x_cl45_write(bp, port,
-                      PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
-                      ext_phy_addr, MDIO_PMA_DEVAD,
-                      0xA819, 0x0000);
-       bnx2x_cl45_write(bp, port,
-                      PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
-                      ext_phy_addr, MDIO_PMA_DEVAD,
-                      0xA81A, 0xc200);
-       bnx2x_cl45_write(bp, port,
-                      PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
-                      ext_phy_addr, MDIO_PMA_DEVAD,
-                      0xA817, 0x000A);
-       for (cnt = 0; cnt < 100; cnt++) {
-               bnx2x_cl45_read(bp, port,
-                             PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
-                             ext_phy_addr,
-                             MDIO_PMA_DEVAD,
-                             0xA818,
-                             &val);
-               if (val & 1)
-                       break;
-               udelay(5);
-       }
-       if (cnt == 100) {
-               DP(NETIF_MSG_LINK, "Unable to read 8481 phy fw version(2)\n");
-               bnx2x_save_spirom_version(bp, port,
-                                       shmem_base, 0);
-               return;
+               /* For all latched-signal=up : Re-Arm Latch signals */
+               REG_WR(bp, NIG_REG_LATCH_STATUS_0 + port*8,
+                            (latch_status & 0xfffe) | (latch_status & 1));
        }
-
-       /* lower 16 bits of the register SPI_FW_STATUS */
-       bnx2x_cl45_read(bp, port,
-                     PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
-                     ext_phy_addr,
-                     MDIO_PMA_DEVAD,
-                     0xA81B,
-                     &fw_ver1);
-       /* upper 16 bits of register SPI_FW_STATUS */
-       bnx2x_cl45_read(bp, port,
-                     PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
-                     ext_phy_addr,
-                     MDIO_PMA_DEVAD,
-                     0xA81C,
-                     &fw_ver2);
-
-       bnx2x_save_spirom_version(bp, port,
-                               shmem_base, (fw_ver2<<16) | fw_ver1);
+       /* For all latched-signal=up,Write original_signal to status */
 }
 
-static void bnx2x_bcm8072_external_rom_boot(struct link_params *params)
+static void bnx2x_link_int_ack(struct link_params *params,
+                            struct link_vars *vars, u8 is_10g)
 {
        struct bnx2x *bp = params->bp;
        u8 port = params->port;
-       u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
-       u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
 
-       /* Need to wait 200ms after reset */
-       msleep(200);
-       /* Boot port from external ROM
-        * Set ser_boot_ctl bit in the MISC_CTRL1 register
-        */
-       bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
-                           MDIO_PMA_DEVAD,
-                           MDIO_PMA_REG_MISC_CTRL1, 0x0001);
+       /* first reset all status
+        * we assume only one line will be change at a time */
+       bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
+                    (NIG_STATUS_XGXS0_LINK10G |
+                     NIG_STATUS_XGXS0_LINK_STATUS |
+                     NIG_STATUS_SERDES0_LINK_STATUS));
+       if (vars->phy_link_up) {
+               if (is_10g) {
+                       /* Disable the 10G link interrupt
+                        * by writing 1 to the status register
+                        */
+                       DP(NETIF_MSG_LINK, "10G XGXS phy link up\n");
+                       bnx2x_bits_en(bp,
+                                     NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
+                                     NIG_STATUS_XGXS0_LINK10G);
 
-       /* Reset internal microprocessor */
-       bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
-                         MDIO_PMA_DEVAD,
-                         MDIO_PMA_REG_GEN_CTRL,
-                         MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
-       /* set micro reset = 0 */
-       bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
-                           MDIO_PMA_DEVAD,
-                           MDIO_PMA_REG_GEN_CTRL,
-                           MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
-       /* Reset internal microprocessor */
-       bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
-                         MDIO_PMA_DEVAD,
-                         MDIO_PMA_REG_GEN_CTRL,
-                         MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
-       /* wait for 100ms for code download via SPI port */
-       msleep(100);
+               } else if (params->switch_cfg == SWITCH_CFG_10G) {
+                       /* Disable the link interrupt
+                        * by writing 1 to the relevant lane
+                        * in the status register
+                        */
+                       u32 ser_lane = ((params->lane_config &
+                                   PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
+                                   PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
 
-       /* Clear ser_boot_ctl bit */
-       bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
-                           MDIO_PMA_DEVAD,
-                           MDIO_PMA_REG_MISC_CTRL1, 0x0000);
-       /* Wait 100ms */
-       msleep(100);
+                       DP(NETIF_MSG_LINK, "%d speed XGXS phy link up\n",
+                                vars->line_speed);
+                       bnx2x_bits_en(bp,
+                                     NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
+                                     ((1 << ser_lane) <<
+                                      NIG_STATUS_XGXS0_LINK_STATUS_SIZE));
+
+               } else { /* SerDes */
+                       DP(NETIF_MSG_LINK, "SerDes phy link up\n");
+                       /* Disable the link interrupt
+                        * by writing 1 to the status register
+                        */
+                       bnx2x_bits_en(bp,
+                                     NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
+                                     NIG_STATUS_SERDES0_LINK_STATUS);
+               }
 
-       bnx2x_save_bcm_spirom_ver(bp, port,
-                               ext_phy_type,
-                               ext_phy_addr,
-                               params->shmem_base);
+       }
 }
 
-static u8 bnx2x_8073_is_snr_needed(struct link_params *params)
+static u8 bnx2x_format_ver(u32 num, u8 *str, u16 *len)
 {
-       /* This is only required for 8073A1, version 102 only */
-
-       struct bnx2x *bp = params->bp;
-       u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
-       u16 val;
-
-       /* Read 8073 HW revision*/
-       bnx2x_cl45_read(bp, params->port,
-                     PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
-                     ext_phy_addr,
-                     MDIO_PMA_DEVAD,
-                     MDIO_PMA_REG_8073_CHIP_REV, &val);
+       u8 *str_ptr = str;
+       u32 mask = 0xf0000000;
+       u8 shift = 8*4;
+       u8 digit;
+       u8 remove_leading_zeros = 1;
+       if (*len < 10) {
+               /* Need more than 10chars for this format */
+               *str_ptr = '\0';
+               (*len)--;
+               return -EINVAL;
+       }
+       while (shift > 0) {
 
-       if (val != 1) {
-               /* No need to workaround in 8073 A1 */
-               return 0;
+               shift -= 4;
+               digit = ((num & mask) >> shift);
+               if (digit == 0 && remove_leading_zeros) {
+                       mask = mask >> 4;
+                       continue;
+               } else if (digit < 0xa)
+                       *str_ptr = digit + '0';
+               else
+                       *str_ptr = digit - 0xa + 'a';
+               remove_leading_zeros = 0;
+               str_ptr++;
+               (*len)--;
+               mask = mask >> 4;
+               if (shift == 4*4) {
+                       *str_ptr = '.';
+                       str_ptr++;
+                       (*len)--;
+                       remove_leading_zeros = 1;
+               }
        }
+       return 0;
+}
 
-       bnx2x_cl45_read(bp, params->port,
-                     PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
-                     ext_phy_addr,
-                     MDIO_PMA_DEVAD,
-                     MDIO_PMA_REG_ROM_VER2, &val);
 
-       /* SNR should be applied only for version 0x102 */
-       if (val != 0x102)
-               return 0;
+static u8 bnx2x_null_format_ver(u32 spirom_ver, u8 *str, u16 *len)
+{
+       str[0] = '\0';
+       (*len)--;
+       return 0;
+}
+
+u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded,
+                             u8 *version, u16 len)
+{
+       struct bnx2x *bp;
+       u32 spirom_ver = 0;
+       u8 status = 0;
+       u8 *ver_p = version;
+       u16 remain_len = len;
+       if (version == NULL || params == NULL)
+               return -EINVAL;
+       bp = params->bp;
+
+       /* Extract first external phy*/
+       version[0] = '\0';
+       spirom_ver = REG_RD(bp, params->phy[EXT_PHY1].ver_addr);
+
+       if (params->phy[EXT_PHY1].format_fw_ver) {
+               status |= params->phy[EXT_PHY1].format_fw_ver(spirom_ver,
+                                                             ver_p,
+                                                             &remain_len);
+               ver_p += (len - remain_len);
+       }
+       if ((params->num_phys == MAX_PHYS) &&
+           (params->phy[EXT_PHY2].ver_addr != 0)) {
+               spirom_ver = REG_RD(bp,
+                                         params->phy[EXT_PHY2].ver_addr);
+               if (params->phy[EXT_PHY2].format_fw_ver) {
+                       *ver_p = '/';
+                       ver_p++;
+                       remain_len--;
+                       status |= params->phy[EXT_PHY2].format_fw_ver(
+                               spirom_ver,
+                               ver_p,
+                               &remain_len);
+                       ver_p = version + (len - remain_len);
+               }
+       }
+       *ver_p = '\0';
+       return status;
+}
+
+static void bnx2x_set_xgxs_loopback(struct bnx2x_phy *phy,
+                                   struct link_params *params)
+{
+       u8 port = params->port;
+       struct bnx2x *bp = params->bp;
+
+       if (phy->req_line_speed != SPEED_1000) {
+               u32 md_devad;
+
+               DP(NETIF_MSG_LINK, "XGXS 10G loopback enable\n");
+
+               /* change the uni_phy_addr in the nig */
+               md_devad = REG_RD(bp, (NIG_REG_XGXS0_CTRL_MD_DEVAD +
+                                         port*0x18));
+
+               REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18, 0x5);
+
+               bnx2x_cl45_write(bp, phy,
+                              5,
+                              (MDIO_REG_BANK_AER_BLOCK +
+                               (MDIO_AER_BLOCK_AER_REG & 0xf)),
+                              0x2800);
+
+               bnx2x_cl45_write(bp, phy,
+                              5,
+                              (MDIO_REG_BANK_CL73_IEEEB0 +
+                               (MDIO_CL73_IEEEB0_CL73_AN_CONTROL & 0xf)),
+                              0x6041);
+               msleep(200);
+               /* set aer mmd back */
+               bnx2x_set_aer_mmd(params, phy);
+
+               /* and md_devad */
+               REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18,
+                           md_devad);
+
+       } else {
+               u16 mii_ctrl;
+               DP(NETIF_MSG_LINK, "XGXS 1G loopback enable\n");
+               bnx2x_cl45_read(bp, phy, 5,
+                               (MDIO_REG_BANK_COMBO_IEEE0 +
+                               (MDIO_COMBO_IEEE0_MII_CONTROL & 0xf)),
+                               &mii_ctrl);
+               bnx2x_cl45_write(bp, phy, 5,
+                                (MDIO_REG_BANK_COMBO_IEEE0 +
+                                (MDIO_COMBO_IEEE0_MII_CONTROL & 0xf)),
+                                mii_ctrl |
+                                MDIO_COMBO_IEEO_MII_CONTROL_LOOPBACK);
+       }
+}
+
+/*
+ *------------------------------------------------------------------------
+ * bnx2x_override_led_value -
+ *
+ * Override the led value of the requested led
+ *
+ *------------------------------------------------------------------------
+ */
+u8 bnx2x_override_led_value(struct bnx2x *bp, u8 port,
+                         u32 led_idx, u32 value)
+{
+       u32 reg_val;
+
+       /* If port 0 then use EMAC0, else use EMAC1*/
+       u32 emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
+
+       DP(NETIF_MSG_LINK,
+                "bnx2x_override_led_value() port %x led_idx %d value %d\n",
+                port, led_idx, value);
+
+       switch (led_idx) {
+       case 0: /* 10MB led */
+               /* Read the current value of the LED register in
+               the EMAC block */
+               reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
+               /* Set the OVERRIDE bit to 1 */
+               reg_val |= EMAC_LED_OVERRIDE;
+               /* If value is 1, set the 10M_OVERRIDE bit,
+               otherwise reset it.*/
+               reg_val = (value == 1) ? (reg_val | EMAC_LED_10MB_OVERRIDE) :
+                       (reg_val & ~EMAC_LED_10MB_OVERRIDE);
+               REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
+               break;
+       case 1: /*100MB led    */
+               /*Read the current value of the LED register in
+               the EMAC block */
+               reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
+               /*  Set the OVERRIDE bit to 1 */
+               reg_val |= EMAC_LED_OVERRIDE;
+               /*  If value is 1, set the 100M_OVERRIDE bit,
+               otherwise reset it.*/
+               reg_val = (value == 1) ? (reg_val | EMAC_LED_100MB_OVERRIDE) :
+                       (reg_val & ~EMAC_LED_100MB_OVERRIDE);
+               REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
+               break;
+       case 2: /* 1000MB led */
+               /* Read the current value of the LED register in the
+               EMAC block */
+               reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
+               /* Set the OVERRIDE bit to 1 */
+               reg_val |= EMAC_LED_OVERRIDE;
+               /* If value is 1, set the 1000M_OVERRIDE bit, otherwise
+               reset it. */
+               reg_val = (value == 1) ? (reg_val | EMAC_LED_1000MB_OVERRIDE) :
+                       (reg_val & ~EMAC_LED_1000MB_OVERRIDE);
+               REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
+               break;
+       case 3: /* 2500MB led */
+               /*  Read the current value of the LED register in the
+               EMAC block*/
+               reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
+               /* Set the OVERRIDE bit to 1 */
+               reg_val |= EMAC_LED_OVERRIDE;
+               /*  If value is 1, set the 2500M_OVERRIDE bit, otherwise
+               reset it.*/
+               reg_val = (value == 1) ? (reg_val | EMAC_LED_2500MB_OVERRIDE) :
+                       (reg_val & ~EMAC_LED_2500MB_OVERRIDE);
+               REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
+               break;
+       case 4: /*10G led */
+               if (port == 0) {
+                       REG_WR(bp, NIG_REG_LED_10G_P0,
+                                   value);
+               } else {
+                       REG_WR(bp, NIG_REG_LED_10G_P1,
+                                   value);
+               }
+               break;
+       case 5: /* TRAFFIC led */
+               /* Find if the traffic control is via BMAC or EMAC */
+               if (port == 0)
+                       reg_val = REG_RD(bp, NIG_REG_NIG_EMAC0_EN);
+               else
+                       reg_val = REG_RD(bp, NIG_REG_NIG_EMAC1_EN);
+
+               /*  Override the traffic led in the EMAC:*/
+               if (reg_val == 1) {
+                       /* Read the current value of the LED register in
+                       the EMAC block */
+                       reg_val = REG_RD(bp, emac_base +
+                                            EMAC_REG_EMAC_LED);
+                       /* Set the TRAFFIC_OVERRIDE bit to 1 */
+                       reg_val |= EMAC_LED_OVERRIDE;
+                       /* If value is 1, set the TRAFFIC bit, otherwise
+                       reset it.*/
+                       reg_val = (value == 1) ? (reg_val | EMAC_LED_TRAFFIC) :
+                               (reg_val & ~EMAC_LED_TRAFFIC);
+                       REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
+               } else { /* Override the traffic led in the BMAC: */
+                       REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0
+                                  + port*4, 1);
+                       REG_WR(bp, NIG_REG_LED_CONTROL_TRAFFIC_P0 + port*4,
+                                   value);
+               }
+               break;
+       default:
+               DP(NETIF_MSG_LINK,
+                        "bnx2x_override_led_value() unknown led index %d "
+                        "(should be 0-5)\n", led_idx);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+
+u8 bnx2x_set_led(struct link_params *params,
+                struct link_vars *vars, u8 mode, u32 speed)
+{
+       u8 port = params->port;
+       u16 hw_led_mode = params->hw_led_mode;
+       u8 rc = 0, phy_idx;
+       u32 tmp;
+       u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
+       struct bnx2x *bp = params->bp;
+       DP(NETIF_MSG_LINK, "bnx2x_set_led: port %x, mode %d\n", port, mode);
+       DP(NETIF_MSG_LINK, "speed 0x%x, hw_led_mode 0x%x\n",
+                speed, hw_led_mode);
+       /* In case */
+       for (phy_idx = EXT_PHY1; phy_idx < MAX_PHYS; phy_idx++) {
+               if (params->phy[phy_idx].set_link_led) {
+                       params->phy[phy_idx].set_link_led(
+                               &params->phy[phy_idx], params, mode);
+               }
+       }
+
+       switch (mode) {
+       case LED_MODE_FRONT_PANEL_OFF:
+       case LED_MODE_OFF:
+               REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 0);
+               REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4,
+                          SHARED_HW_CFG_LED_MAC1);
+
+               tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
+               EMAC_WR(bp, EMAC_REG_EMAC_LED, (tmp | EMAC_LED_OVERRIDE));
+               break;
+
+       case LED_MODE_OPER:
+               /**
+                * For all other phys, OPER mode is same as ON, so in case
+                * link is down, do nothing
+                **/
+               if (!vars->link_up)
+                       break;
+       case LED_MODE_ON:
+               if (SINGLE_MEDIA_DIRECT(params)) {
+                       /**
+                       * This is a work-around for HW issue found when link
+                       * is up in CL73
+                       */
+                       REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, 0);
+                       REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 1);
+               } else {
+                       REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4,
+                                  hw_led_mode);
+               }
+
+               REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0 +
+                          port*4, 0);
+               /* Set blinking rate to ~15.9Hz */
+               REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_P0 + port*4,
+                          LED_BLINK_RATE_VAL);
+               REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_ENA_P0 +
+                          port*4, 1);
+               tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
+               EMAC_WR(bp, EMAC_REG_EMAC_LED,
+                           (tmp & (~EMAC_LED_OVERRIDE)));
+
+               if (CHIP_IS_E1(bp) &&
+                   ((speed == SPEED_2500) ||
+                    (speed == SPEED_1000) ||
+                    (speed == SPEED_100) ||
+                    (speed == SPEED_10))) {
+                       /* On Everest 1 Ax chip versions for speeds less than
+                       10G LED scheme is different */
+                       REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0
+                                  + port*4, 1);
+                       REG_WR(bp, NIG_REG_LED_CONTROL_TRAFFIC_P0 +
+                                  port*4, 0);
+                       REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_TRAFFIC_P0 +
+                                  port*4, 1);
+               }
+               break;
+
+       default:
+               rc = -EINVAL;
+               DP(NETIF_MSG_LINK, "bnx2x_set_led: Invalid led mode %d\n",
+                        mode);
+               break;
+       }
+       return rc;
+
+}
+
+/**
+ * This function comes to reflect the actual link state read DIRECTLY from the
+ * HW
+ */
+u8 bnx2x_test_link(struct link_params *params, struct link_vars *vars,
+                  u8 is_serdes)
+{
+       struct bnx2x *bp = params->bp;
+       u16 gp_status = 0, phy_index = 0;
+       u8 ext_phy_link_up = 0, serdes_phy_type;
+       struct link_vars temp_vars;
+
+       CL45_RD_OVER_CL22(bp, &params->phy[INT_PHY],
+                             MDIO_REG_BANK_GP_STATUS,
+                             MDIO_GP_STATUS_TOP_AN_STATUS1,
+                             &gp_status);
+       /* link is up only if both local phy and external phy are up */
+       if (!(gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS))
+               return -ESRCH;
+
+       switch (params->num_phys) {
+       case 1:
+               /* No external PHY */
+               return 0;
+       case 2:
+               ext_phy_link_up = params->phy[EXT_PHY1].read_status(
+                       &params->phy[EXT_PHY1],
+                       params, &temp_vars);
+               break;
+       case 3: /* Dual Media */
+               for (phy_index = EXT_PHY1; phy_index < params->num_phys;
+                     phy_index++) {
+                       serdes_phy_type = ((params->phy[phy_index].media_type ==
+                                           ETH_PHY_SFP_FIBER) ||
+                                          (params->phy[phy_index].media_type ==
+                                           ETH_PHY_XFP_FIBER));
+
+                       if (is_serdes != serdes_phy_type)
+                               continue;
+                       if (params->phy[phy_index].read_status) {
+                               ext_phy_link_up |=
+                                       params->phy[phy_index].read_status(
+                                               &params->phy[phy_index],
+                                               params, &temp_vars);
+                       }
+               }
+               break;
+       }
+       if (ext_phy_link_up)
+               return 0;
+       return -ESRCH;
+}
+
+static u8 bnx2x_link_initialize(struct link_params *params,
+                               struct link_vars *vars)
+{
+       u8 rc = 0;
+       u8 phy_index, non_ext_phy;
+       struct bnx2x *bp = params->bp;
+       /**
+       * In case of external phy existence, the line speed would be the
+       * line speed linked up by the external phy. In case it is direct
+       * only, then the line_speed during initialization will be
+       * equal to the req_line_speed
+       */
+       vars->line_speed = params->phy[INT_PHY].req_line_speed;
+
+       /**
+        * Initialize the internal phy in case this is a direct board
+        * (no external phys), or this board has external phy which requires
+        * to first.
+        */
+
+       if (params->phy[INT_PHY].config_init)
+               params->phy[INT_PHY].config_init(
+                       &params->phy[INT_PHY],
+                       params, vars);
+
+       /* init ext phy and enable link state int */
+       non_ext_phy = (SINGLE_MEDIA_DIRECT(params) ||
+                      (params->loopback_mode == LOOPBACK_XGXS));
+
+       if (non_ext_phy ||
+           (params->phy[EXT_PHY1].flags & FLAGS_INIT_XGXS_FIRST) ||
+           (params->loopback_mode == LOOPBACK_EXT_PHY)) {
+               struct bnx2x_phy *phy = &params->phy[INT_PHY];
+               if (vars->line_speed == SPEED_AUTO_NEG)
+                       bnx2x_set_parallel_detection(phy, params);
+               bnx2x_init_internal_phy(phy, params, vars);
+       }
+
+       /* Init external phy*/
+       if (!non_ext_phy)
+               for (phy_index = EXT_PHY1; phy_index < params->num_phys;
+                     phy_index++) {
+                       /**
+                        * No need to initialize second phy in case of first
+                        * phy only selection. In case of second phy, we do
+                        * need to initialize the first phy, since they are
+                        * connected.
+                        **/
+                       if (phy_index == EXT_PHY2 &&
+                           (bnx2x_phy_selection(params) ==
+                            PORT_HW_CFG_PHY_SELECTION_FIRST_PHY)) {
+                               DP(NETIF_MSG_LINK, "Not initializing"
+                                                  "second phy\n");
+                               continue;
+                       }
+                       params->phy[phy_index].config_init(
+                               &params->phy[phy_index],
+                               params, vars);
+               }
+
+       /* Reset the interrupt indication after phy was initialized */
+       bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 +
+                      params->port*4,
+                      (NIG_STATUS_XGXS0_LINK10G |
+                       NIG_STATUS_XGXS0_LINK_STATUS |
+                       NIG_STATUS_SERDES0_LINK_STATUS |
+                       NIG_MASK_MI_INT));
+       return rc;
+}
+
+static void bnx2x_int_link_reset(struct bnx2x_phy *phy,
+                                struct link_params *params)
+{
+       /* reset the SerDes/XGXS */
+       REG_WR(params->bp, GRCBASE_MISC +
+                    MISC_REGISTERS_RESET_REG_3_CLEAR,
+                    (0x1ff << (params->port*16)));
+}
+
+static void bnx2x_common_ext_link_reset(struct bnx2x_phy *phy,
+                                       struct link_params *params)
+{
+       struct bnx2x *bp = params->bp;
+       u8 gpio_port;
+       /* HW reset */
+       gpio_port = params->port;
+       bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
+                           MISC_REGISTERS_GPIO_OUTPUT_LOW,
+                           gpio_port);
+       bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
+                           MISC_REGISTERS_GPIO_OUTPUT_LOW,
+                           gpio_port);
+       DP(NETIF_MSG_LINK, "reset external PHY\n");
+}
+
+static u8 bnx2x_update_link_down(struct link_params *params,
+                              struct link_vars *vars)
+{
+       struct bnx2x *bp = params->bp;
+       u8 port = params->port;
+
+       DP(NETIF_MSG_LINK, "Port %x: Link is down\n", port);
+       bnx2x_set_led(params, vars, LED_MODE_OFF, 0);
+
+       /* indicate no mac active */
+       vars->mac_type = MAC_TYPE_NONE;
+
+       /* update shared memory */
+       vars->link_status = 0;
+       vars->line_speed = 0;
+       bnx2x_update_mng(params, vars->link_status);
+
+       /* activate nig drain */
+       REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
+
+       /* disable emac */
+       REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
+
+       msleep(10);
+
+       /* reset BigMac */
+       bnx2x_bmac_rx_disable(bp, params->port);
+       REG_WR(bp, GRCBASE_MISC +
+                  MISC_REGISTERS_RESET_REG_2_CLEAR,
+                  (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
+       return 0;
+}
+
+static u8 bnx2x_update_link_up(struct link_params *params,
+                            struct link_vars *vars,
+                            u8 link_10g)
+{
+       struct bnx2x *bp = params->bp;
+       u8 port = params->port;
+       u8 rc = 0;
+
+       vars->link_status |= LINK_STATUS_LINK_UP;
+
+       if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
+               vars->link_status |=
+                       LINK_STATUS_TX_FLOW_CONTROL_ENABLED;
+
+       if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
+               vars->link_status |=
+                       LINK_STATUS_RX_FLOW_CONTROL_ENABLED;
+
+       if (link_10g) {
+               bnx2x_bmac_enable(params, vars, 0);
+               bnx2x_set_led(params, vars,
+                             LED_MODE_OPER, SPEED_10000);
+       } else {
+               rc = bnx2x_emac_program(params, vars);
+
+               bnx2x_emac_enable(params, vars, 0);
+
+               /* AN complete? */
+               if ((vars->link_status & LINK_STATUS_AUTO_NEGOTIATE_COMPLETE)
+                   && (!(vars->phy_flags & PHY_SGMII_FLAG)) &&
+                   SINGLE_MEDIA_DIRECT(params))
+                       bnx2x_set_gmii_tx_driver(params);
+       }
+
+       /* PBF - link up */
+       rc |= bnx2x_pbf_update(params, vars->flow_ctrl,
+                             vars->line_speed);
+
+       /* disable drain */
+       REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 0);
+
+       /* update shared memory */
+       bnx2x_update_mng(params, vars->link_status);
+       msleep(20);
+       return rc;
+}
+/**
+ * The bnx2x_link_update function should be called upon link
+ * interrupt.
+ * Link is considered up as follows:
+ * - DIRECT_SINGLE_MEDIA - Only XGXS link (internal link) needs
+ *   to be up
+ * - SINGLE_MEDIA - The link between the 577xx and the external
+ *   phy (XGXS) need to up as well as the external link of the
+ *   phy (PHY_EXT1)
+ * - DUAL_MEDIA - The link between the 577xx and the first
+ *   external phy needs to be up, and at least one of the 2
+ *   external phy link must be up.
+ */
+u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars)
+{
+       struct bnx2x *bp = params->bp;
+       struct link_vars phy_vars[MAX_PHYS];
+       u8 port = params->port;
+       u8 link_10g, phy_index;
+       u8 ext_phy_link_up = 0, cur_link_up, rc = 0;
+       u8 is_mi_int = 0;
+       u16 ext_phy_line_speed = 0, prev_line_speed = vars->line_speed;
+       u8 active_external_phy = INT_PHY;
+       vars->link_status = 0;
+       for (phy_index = INT_PHY; phy_index < params->num_phys;
+             phy_index++) {
+               phy_vars[phy_index].flow_ctrl = 0;
+               phy_vars[phy_index].link_status = 0;
+               phy_vars[phy_index].line_speed = 0;
+               phy_vars[phy_index].duplex = DUPLEX_FULL;
+               phy_vars[phy_index].phy_link_up = 0;
+               phy_vars[phy_index].link_up = 0;
+       }
+
+       DP(NETIF_MSG_LINK, "port %x, XGXS?%x, int_status 0x%x\n",
+                port, (vars->phy_flags & PHY_XGXS_FLAG),
+                REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4));
+
+       is_mi_int = (u8)(REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT +
+                                   port*0x18) > 0);
+       DP(NETIF_MSG_LINK, "int_mask 0x%x MI_INT %x, SERDES_LINK %x\n",
+                REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4),
+                is_mi_int,
+                REG_RD(bp,
+                           NIG_REG_SERDES0_STATUS_LINK_STATUS + port*0x3c));
+
+       DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n",
+         REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
+         REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68));
+
+       /* disable emac */
+       REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
+
+       /**
+       * Step 1:
+       * Check external link change only for external phys, and apply
+       * priority selection between them in case the link on both phys
+       * is up. Note that the instead of the common vars, a temporary
+       * vars argument is used since each phy may have different link/
+       * speed/duplex result
+       */
+       for (phy_index = EXT_PHY1; phy_index < params->num_phys;
+             phy_index++) {
+               struct bnx2x_phy *phy = &params->phy[phy_index];
+               if (!phy->read_status)
+                       continue;
+               /* Read link status and params of this ext phy */
+               cur_link_up = phy->read_status(phy, params,
+                                              &phy_vars[phy_index]);
+               if (cur_link_up) {
+                       DP(NETIF_MSG_LINK, "phy in index %d link is up\n",
+                                  phy_index);
+               } else {
+                       DP(NETIF_MSG_LINK, "phy in index %d link is down\n",
+                                  phy_index);
+                       continue;
+               }
+
+               if (!ext_phy_link_up) {
+                       ext_phy_link_up = 1;
+                       active_external_phy = phy_index;
+               } else {
+                       switch (bnx2x_phy_selection(params)) {
+                       case PORT_HW_CFG_PHY_SELECTION_HARDWARE_DEFAULT:
+                       case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY:
+                       /**
+                        * In this option, the first PHY makes sure to pass the
+                        * traffic through itself only.
+                        * Its not clear how to reset the link on the second phy
+                        **/
+                               active_external_phy = EXT_PHY1;
+                               break;
+                       case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY:
+                       /**
+                        * In this option, the first PHY makes sure to pass the
+                        * traffic through the second PHY.
+                        **/
+                               active_external_phy = EXT_PHY2;
+                               break;
+                       default:
+                       /**
+                        * Link indication on both PHYs with the following cases
+                        * is invalid:
+                        * - FIRST_PHY means that second phy wasn't initialized,
+                        * hence its link is expected to be down
+                        * - SECOND_PHY means that first phy should not be able
+                        * to link up by itself (using configuration)
+                        * - DEFAULT should be overriden during initialiazation
+                        **/
+                               DP(NETIF_MSG_LINK, "Invalid link indication"
+                                          "mpc=0x%x. DISABLING LINK !!!\n",
+                                          params->multi_phy_config);
+                               ext_phy_link_up = 0;
+                               break;
+                       }
+               }
+       }
+       prev_line_speed = vars->line_speed;
+       /**
+       * Step 2:
+       * Read the status of the internal phy. In case of
+       * DIRECT_SINGLE_MEDIA board, this link is the external link,
+       * otherwise this is the link between the 577xx and the first
+       * external phy
+       */
+       if (params->phy[INT_PHY].read_status)
+               params->phy[INT_PHY].read_status(
+                       &params->phy[INT_PHY],
+                       params, vars);
+       /**
+        * The INT_PHY flow control reside in the vars. This include the
+        * case where the speed or flow control are not set to AUTO.
+        * Otherwise, the active external phy flow control result is set
+        * to the vars. The ext_phy_line_speed is needed to check if the
+        * speed is different between the internal phy and external phy.
+        * This case may be result of intermediate link speed change.
+        */
+       if (active_external_phy > INT_PHY) {
+               vars->flow_ctrl = phy_vars[active_external_phy].flow_ctrl;
+               /**
+                * Link speed is taken from the XGXS. AN and FC result from
+                * the external phy.
+                */
+               vars->link_status |= phy_vars[active_external_phy].link_status;
+
+               /**
+                * if active_external_phy is first PHY and link is up - disable
+                * disable TX on second external PHY
+                */
+               if (active_external_phy == EXT_PHY1) {
+                       if (params->phy[EXT_PHY2].phy_specific_func) {
+                               DP(NETIF_MSG_LINK, "Disabling TX on"
+                                                  " EXT_PHY2\n");
+                               params->phy[EXT_PHY2].phy_specific_func(
+                                       &params->phy[EXT_PHY2],
+                                       params, DISABLE_TX);
+                       }
+               }
+
+               ext_phy_line_speed = phy_vars[active_external_phy].line_speed;
+               vars->duplex = phy_vars[active_external_phy].duplex;
+               if (params->phy[active_external_phy].supported &
+                   SUPPORTED_FIBRE)
+                       vars->link_status |= LINK_STATUS_SERDES_LINK;
+               DP(NETIF_MSG_LINK, "Active external phy selected: %x\n",
+                          active_external_phy);
+       }
+
+       for (phy_index = EXT_PHY1; phy_index < params->num_phys;
+             phy_index++) {
+               if (params->phy[phy_index].flags &
+                   FLAGS_REARM_LATCH_SIGNAL) {
+                       bnx2x_rearm_latch_signal(bp, port,
+                                                phy_index ==
+                                                active_external_phy);
+                       break;
+               }
+       }
+       DP(NETIF_MSG_LINK, "vars->flow_ctrl = 0x%x, vars->link_status = 0x%x,"
+                  " ext_phy_line_speed = %d\n", vars->flow_ctrl,
+                  vars->link_status, ext_phy_line_speed);
+       /**
+        * Upon link speed change set the NIG into drain mode. Comes to
+        * deals with possible FIFO glitch due to clk change when speed
+        * is decreased without link down indicator
+        */
+
+       if (vars->phy_link_up) {
+               if (!(SINGLE_MEDIA_DIRECT(params)) && ext_phy_link_up &&
+                   (ext_phy_line_speed != vars->line_speed)) {
+                       DP(NETIF_MSG_LINK, "Internal link speed %d is"
+                                  " different than the external"
+                                  " link speed %d\n", vars->line_speed,
+                                  ext_phy_line_speed);
+                       vars->phy_link_up = 0;
+               } else if (prev_line_speed != vars->line_speed) {
+                       REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE
+                                    + params->port*4, 0);
+                       msleep(1);
+               }
+       }
+
+       /* anything 10 and over uses the bmac */
+       link_10g = ((vars->line_speed == SPEED_10000) ||
+                   (vars->line_speed == SPEED_12000) ||
+                   (vars->line_speed == SPEED_12500) ||
+                   (vars->line_speed == SPEED_13000) ||
+                   (vars->line_speed == SPEED_15000) ||
+                   (vars->line_speed == SPEED_16000));
+
+       bnx2x_link_int_ack(params, vars, link_10g);
+
+       /**
+       * In case external phy link is up, and internal link is down
+       * (not initialized yet probably after link initialization, it
+       * needs to be initialized.
+       * Note that after link down-up as result of cable plug, the xgxs
+       * link would probably become up again without the need
+       * initialize it
+       */
+       if (!(SINGLE_MEDIA_DIRECT(params))) {
+               DP(NETIF_MSG_LINK, "ext_phy_link_up = %d, int_link_up = %d,"
+                          " init_preceding = %d\n", ext_phy_link_up,
+                          vars->phy_link_up,
+                          params->phy[EXT_PHY1].flags &
+                          FLAGS_INIT_XGXS_FIRST);
+               if (!(params->phy[EXT_PHY1].flags &
+                     FLAGS_INIT_XGXS_FIRST)
+                   && ext_phy_link_up && !vars->phy_link_up) {
+                       vars->line_speed = ext_phy_line_speed;
+                       if (vars->line_speed < SPEED_1000)
+                               vars->phy_flags |= PHY_SGMII_FLAG;
+                       else
+                               vars->phy_flags &= ~PHY_SGMII_FLAG;
+                       bnx2x_init_internal_phy(&params->phy[INT_PHY],
+                                               params,
+                                               vars);
+               }
+       }
+       /**
+        *  Link is up only if both local phy and external phy (in case of
+        *  non-direct board) are up
+        */
+       vars->link_up = (vars->phy_link_up &&
+                        (ext_phy_link_up ||
+                         SINGLE_MEDIA_DIRECT(params)));
+
+       if (vars->link_up)
+               rc = bnx2x_update_link_up(params, vars, link_10g);
+       else
+               rc = bnx2x_update_link_down(params, vars);
+
+       return rc;
+}
+
+
+/*****************************************************************************/
+/*                         External Phy section                             */
+/*****************************************************************************/
+void bnx2x_ext_phy_hw_reset(struct bnx2x *bp, u8 port)
+{
+       bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
+                           MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
+       msleep(1);
+       bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
+                           MISC_REGISTERS_GPIO_OUTPUT_HIGH, port);
+}
+
+static void bnx2x_save_spirom_version(struct bnx2x *bp, u8 port,
+                                     u32 spirom_ver, u32 ver_addr)
+{
+       DP(NETIF_MSG_LINK, "FW version 0x%x:0x%x for port %d\n",
+                (u16)(spirom_ver>>16), (u16)spirom_ver, port);
+
+       if (ver_addr)
+               REG_WR(bp, ver_addr, spirom_ver);
+}
+
+static void bnx2x_save_bcm_spirom_ver(struct bnx2x *bp,
+                                     struct bnx2x_phy *phy,
+                                     u8 port)
+{
+       u16 fw_ver1, fw_ver2;
+
+       bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD,
+                     MDIO_PMA_REG_ROM_VER1, &fw_ver1);
+       bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD,
+                     MDIO_PMA_REG_ROM_VER2, &fw_ver2);
+       bnx2x_save_spirom_version(bp, port, (u32)(fw_ver1<<16 | fw_ver2),
+                                 phy->ver_addr);
+}
+
+static void bnx2x_ext_phy_set_pause(struct link_params *params,
+                                   struct bnx2x_phy *phy,
+                                   struct link_vars *vars)
+{
+       u16 val;
+       struct bnx2x *bp = params->bp;
+       /* read modify write pause advertizing */
+       bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV_PAUSE, &val);
+
+       val &= ~MDIO_AN_REG_ADV_PAUSE_BOTH;
+
+       /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */
+       bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc);
+       if ((vars->ieee_fc &
+           MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) ==
+           MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) {
+               val |=  MDIO_AN_REG_ADV_PAUSE_ASYMMETRIC;
+       }
+       if ((vars->ieee_fc &
+           MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) ==
+           MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) {
+               val |= MDIO_AN_REG_ADV_PAUSE_PAUSE;
+       }
+       DP(NETIF_MSG_LINK, "Ext phy AN advertize 0x%x\n", val);
+       bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV_PAUSE, val);
+}
+
+static u8 bnx2x_ext_phy_resolve_fc(struct bnx2x_phy *phy,
+                                  struct link_params *params,
+                                  struct link_vars *vars)
+{
+       struct bnx2x *bp = params->bp;
+       u16 ld_pause;           /* local */
+       u16 lp_pause;           /* link partner */
+       u16 pause_result;
+       u8 ret = 0;
+       /* read twice */
+
+       vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
+
+       if (phy->req_flow_ctrl != BNX2X_FLOW_CTRL_AUTO)
+               vars->flow_ctrl = phy->req_flow_ctrl;
+       else if (phy->req_line_speed != SPEED_AUTO_NEG)
+               vars->flow_ctrl = params->req_fc_auto_adv;
+       else if (vars->link_status & LINK_STATUS_AUTO_NEGOTIATE_COMPLETE) {
+               ret = 1;
+               bnx2x_cl45_read(bp, phy,
+                             MDIO_AN_DEVAD,
+                             MDIO_AN_REG_ADV_PAUSE, &ld_pause);
+               bnx2x_cl45_read(bp, phy,
+                             MDIO_AN_DEVAD,
+                             MDIO_AN_REG_LP_AUTO_NEG, &lp_pause);
+               pause_result = (ld_pause &
+                               MDIO_AN_REG_ADV_PAUSE_MASK) >> 8;
+               pause_result |= (lp_pause &
+                                MDIO_AN_REG_ADV_PAUSE_MASK) >> 10;
+               DP(NETIF_MSG_LINK, "Ext PHY pause result 0x%x\n",
+                  pause_result);
+               bnx2x_pause_resolve(vars, pause_result);
+       }
+       return ret;
+}
+
+static void bnx2x_ext_phy_10G_an_resolve(struct bnx2x *bp,
+                                      struct bnx2x_phy *phy,
+                                      struct link_vars *vars)
+{
+       u16 val;
+       bnx2x_cl45_read(bp, phy,
+                       MDIO_AN_DEVAD,
+                       MDIO_AN_REG_STATUS, &val);
+       bnx2x_cl45_read(bp, phy,
+                       MDIO_AN_DEVAD,
+                       MDIO_AN_REG_STATUS, &val);
+       if (val & (1<<5))
+               vars->link_status |= LINK_STATUS_AUTO_NEGOTIATE_COMPLETE;
+       if ((val & (1<<0)) == 0)
+               vars->link_status |= LINK_STATUS_PARALLEL_DETECTION_USED;
+}
+
+/******************************************************************/
+/*             common BCM8073/BCM8727 PHY SECTION                */
+/******************************************************************/
+static void bnx2x_8073_resolve_fc(struct bnx2x_phy *phy,
+                                 struct link_params *params,
+                                 struct link_vars *vars)
+{
+       struct bnx2x *bp = params->bp;
+       if (phy->req_line_speed == SPEED_10 ||
+           phy->req_line_speed == SPEED_100) {
+               vars->flow_ctrl = phy->req_flow_ctrl;
+               return;
+       }
+
+       if (bnx2x_ext_phy_resolve_fc(phy, params, vars) &&
+           (vars->flow_ctrl == BNX2X_FLOW_CTRL_NONE)) {
+               u16 pause_result;
+               u16 ld_pause;           /* local */
+               u16 lp_pause;           /* link partner */
+               bnx2x_cl45_read(bp, phy,
+                               MDIO_AN_DEVAD,
+                               MDIO_AN_REG_CL37_FC_LD, &ld_pause);
+
+               bnx2x_cl45_read(bp, phy,
+                               MDIO_AN_DEVAD,
+                               MDIO_AN_REG_CL37_FC_LP, &lp_pause);
+               pause_result = (ld_pause &
+                               MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) >> 5;
+               pause_result |= (lp_pause &
+                                MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) >> 7;
+
+               bnx2x_pause_resolve(vars, pause_result);
+               DP(NETIF_MSG_LINK, "Ext PHY CL37 pause result 0x%x\n",
+                          pause_result);
+       }
+}
+
+static void bnx2x_8073_8727_external_rom_boot(struct bnx2x *bp,
+                                             struct bnx2x_phy *phy,
+                                             u8 port)
+{
+       /* Boot port from external ROM  */
+       /* EDC grst */
+       bnx2x_cl45_write(bp, phy,
+                      MDIO_PMA_DEVAD,
+                      MDIO_PMA_REG_GEN_CTRL,
+                      0x0001);
+
+       /* ucode reboot and rst */
+       bnx2x_cl45_write(bp, phy,
+                      MDIO_PMA_DEVAD,
+                      MDIO_PMA_REG_GEN_CTRL,
+                      0x008c);
+
+       bnx2x_cl45_write(bp, phy,
+                      MDIO_PMA_DEVAD,
+                      MDIO_PMA_REG_MISC_CTRL1, 0x0001);
+
+       /* Reset internal microprocessor */
+       bnx2x_cl45_write(bp, phy,
+                      MDIO_PMA_DEVAD,
+                      MDIO_PMA_REG_GEN_CTRL,
+                      MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
+
+       /* Release srst bit */
+       bnx2x_cl45_write(bp, phy,
+                      MDIO_PMA_DEVAD,
+                      MDIO_PMA_REG_GEN_CTRL,
+                      MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
+
+       /* wait for 120ms for code download via SPI port */
+       msleep(120);
+
+       /* Clear ser_boot_ctl bit */
+       bnx2x_cl45_write(bp, phy,
+                      MDIO_PMA_DEVAD,
+                      MDIO_PMA_REG_MISC_CTRL1, 0x0000);
+       bnx2x_save_bcm_spirom_ver(bp, phy, port);
+}
+
+static void bnx2x_8073_set_xaui_low_power_mode(struct bnx2x *bp,
+                                              struct bnx2x_phy *phy)
+{
+       u16 val;
+       bnx2x_cl45_read(bp, phy,
+                       MDIO_PMA_DEVAD, MDIO_PMA_REG_8073_CHIP_REV, &val);
+
+       if (val == 0) {
+               /* Mustn't set low power mode in 8073 A0 */
+               return;
+       }
+
+       /* Disable PLL sequencer (use read-modify-write to clear bit 13) */
+       bnx2x_cl45_read(bp, phy,
+                       MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, &val);
+       val &= ~(1<<13);
+       bnx2x_cl45_write(bp, phy,
+                      MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, val);
+
+       /* PLL controls */
+       bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x805E, 0x1077);
+       bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x805D, 0x0000);
+       bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x805C, 0x030B);
+       bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x805B, 0x1240);
+       bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x805A, 0x2490);
+
+       /* Tx Controls */
+       bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x80A7, 0x0C74);
+       bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x80A6, 0x9041);
+       bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x80A5, 0x4640);
+
+       /* Rx Controls */
+       bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x80FE, 0x01C4);
+       bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x80FD, 0x9249);
+       bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x80FC, 0x2015);
+
+       /* Enable PLL sequencer  (use read-modify-write to set bit 13) */
+       bnx2x_cl45_read(bp, phy, MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, &val);
+       val |= (1<<13);
+       bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, val);
+}
+
+/******************************************************************/
+/*                     BCM8073 PHY SECTION                       */
+/******************************************************************/
+static u8 bnx2x_8073_is_snr_needed(struct bnx2x *bp, struct bnx2x_phy *phy)
+{
+       /* This is only required for 8073A1, version 102 only */
+       u16 val;
+
+       /* Read 8073 HW revision*/
+       bnx2x_cl45_read(bp, phy,
+                     MDIO_PMA_DEVAD,
+                     MDIO_PMA_REG_8073_CHIP_REV, &val);
+
+       if (val != 1) {
+               /* No need to workaround in 8073 A1 */
+               return 0;
+       }
+
+       bnx2x_cl45_read(bp, phy,
+                     MDIO_PMA_DEVAD,
+                     MDIO_PMA_REG_ROM_VER2, &val);
+
+       /* SNR should be applied only for version 0x102 */
+       if (val != 0x102)
+               return 0;
 
        return 1;
 }
 
-static u8 bnx2x_bcm8073_xaui_wa(struct link_params *params)
+static u8 bnx2x_8073_xaui_wa(struct bnx2x *bp, struct bnx2x_phy *phy)
 {
-       struct bnx2x *bp = params->bp;
-       u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
        u16 val, cnt, cnt1 ;
 
-       bnx2x_cl45_read(bp, params->port,
-                     PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
-                     ext_phy_addr,
+       bnx2x_cl45_read(bp, phy,
                      MDIO_PMA_DEVAD,
                      MDIO_PMA_REG_8073_CHIP_REV, &val);
 
@@ -2466,9 +3351,7 @@ static u8 bnx2x_bcm8073_xaui_wa(struct link_params *params)
        poll Dev1, Reg $C820: */
 
        for (cnt = 0; cnt < 1000; cnt++) {
-               bnx2x_cl45_read(bp, params->port,
-                             PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
-                             ext_phy_addr,
+               bnx2x_cl45_read(bp, phy,
                              MDIO_PMA_DEVAD,
                              MDIO_PMA_REG_8073_SPEED_LINK_STATUS,
                              &val);
@@ -2485,9 +3368,7 @@ static u8 bnx2x_bcm8073_xaui_wa(struct link_params *params)
                          XAUI workaround has completed),
                          then continue on with system initialization.*/
                        for (cnt1 = 0; cnt1 < 1000; cnt1++) {
-                               bnx2x_cl45_read(bp, params->port,
-                                       PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
-                                       ext_phy_addr,
+                               bnx2x_cl45_read(bp, phy,
                                        MDIO_PMA_DEVAD,
                                        MDIO_PMA_REG_8073_XAUI_WA, &val);
                                if (val & (1<<15)) {
@@ -2505,143 +3386,385 @@ static u8 bnx2x_bcm8073_xaui_wa(struct link_params *params)
        return -EINVAL;
 }
 
-static void bnx2x_bcm8073_bcm8727_external_rom_boot(struct bnx2x *bp, u8 port,
-                                                 u8 ext_phy_addr,
-                                                 u32 ext_phy_type,
-                                                 u32 shmem_base)
+static void bnx2x_807x_force_10G(struct bnx2x *bp, struct bnx2x_phy *phy)
 {
-       /* Boot port from external ROM  */
-       /* EDC grst */
-       bnx2x_cl45_write(bp, port,
-                      ext_phy_type,
-                      ext_phy_addr,
-                      MDIO_PMA_DEVAD,
-                      MDIO_PMA_REG_GEN_CTRL,
-                      0x0001);
+       /* Force KR or KX */
+       bnx2x_cl45_write(bp, phy,
+                        MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x2040);
+       bnx2x_cl45_write(bp, phy,
+                        MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, 0x000b);
+       bnx2x_cl45_write(bp, phy,
+                        MDIO_PMA_DEVAD, MDIO_PMA_REG_BCM_CTRL, 0x0000);
+       bnx2x_cl45_write(bp, phy,
+                        MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x0000);
+}
 
-       /* ucode reboot and rst */
-       bnx2x_cl45_write(bp, port,
-                      ext_phy_type,
-                      ext_phy_addr,
-                      MDIO_PMA_DEVAD,
-                      MDIO_PMA_REG_GEN_CTRL,
-                      0x008c);
+static void bnx2x_8073_set_pause_cl37(struct link_params *params,
+                                     struct bnx2x_phy *phy,
+                                     struct link_vars *vars)
+{
+       u16 cl37_val;
+       struct bnx2x *bp = params->bp;
+       bnx2x_cl45_read(bp, phy,
+                       MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD, &cl37_val);
 
-       bnx2x_cl45_write(bp, port,
-                      ext_phy_type,
-                      ext_phy_addr,
-                      MDIO_PMA_DEVAD,
-                      MDIO_PMA_REG_MISC_CTRL1, 0x0001);
+       cl37_val &= ~MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
+       /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */
+       bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc);
+       if ((vars->ieee_fc &
+           MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC) ==
+           MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC) {
+               cl37_val |=  MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC;
+       }
+       if ((vars->ieee_fc &
+           MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) ==
+           MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) {
+               cl37_val |=  MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
+       }
+       if ((vars->ieee_fc &
+           MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) ==
+           MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) {
+               cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
+       }
+       DP(NETIF_MSG_LINK,
+                "Ext phy AN advertize cl37 0x%x\n", cl37_val);
 
-       /* Reset internal microprocessor */
-       bnx2x_cl45_write(bp, port,
-                      ext_phy_type,
-                      ext_phy_addr,
-                      MDIO_PMA_DEVAD,
-                      MDIO_PMA_REG_GEN_CTRL,
-                      MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
+       bnx2x_cl45_write(bp, phy,
+                        MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD, cl37_val);
+       msleep(500);
+}
 
-       /* Release srst bit */
-       bnx2x_cl45_write(bp, port,
-                      ext_phy_type,
-                      ext_phy_addr,
-                      MDIO_PMA_DEVAD,
-                      MDIO_PMA_REG_GEN_CTRL,
-                      MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
+static u8 bnx2x_8073_config_init(struct bnx2x_phy *phy,
+                                struct link_params *params,
+                                struct link_vars *vars)
+{
+       struct bnx2x *bp = params->bp;
+       u16 val = 0, tmp1;
+       u8 gpio_port;
+       DP(NETIF_MSG_LINK, "Init 8073\n");
 
-       /* wait for 100ms for code download via SPI port */
-       msleep(100);
+       gpio_port = params->port;
+       /* Restore normal power mode*/
+       bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
+                           MISC_REGISTERS_GPIO_OUTPUT_HIGH, gpio_port);
 
-       /* Clear ser_boot_ctl bit */
-       bnx2x_cl45_write(bp, port,
-                      ext_phy_type,
-                      ext_phy_addr,
-                      MDIO_PMA_DEVAD,
-                      MDIO_PMA_REG_MISC_CTRL1, 0x0000);
+       bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
+                           MISC_REGISTERS_GPIO_OUTPUT_HIGH, gpio_port);
 
-       bnx2x_save_bcm_spirom_ver(bp, port,
-                               ext_phy_type,
-                               ext_phy_addr,
-                               shmem_base);
-}
+       /* enable LASI */
+       bnx2x_cl45_write(bp, phy,
+                        MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL, (1<<2));
+       bnx2x_cl45_write(bp, phy,
+                        MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL,  0x0004);
 
-static void bnx2x_bcm8073_external_rom_boot(struct bnx2x *bp, u8 port,
-                                         u8 ext_phy_addr,
-                                         u32 shmem_base)
-{
-       bnx2x_bcm8073_bcm8727_external_rom_boot(bp, port, ext_phy_addr,
-                                        PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
-                                        shmem_base);
-}
+       bnx2x_8073_set_pause_cl37(params, phy, vars);
 
-static void bnx2x_bcm8727_external_rom_boot(struct bnx2x *bp, u8 port,
-                                         u8 ext_phy_addr,
-                                         u32 shmem_base)
-{
-       bnx2x_bcm8073_bcm8727_external_rom_boot(bp, port, ext_phy_addr,
-                                        PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
-                                        shmem_base);
+       bnx2x_8073_set_xaui_low_power_mode(bp, phy);
 
-}
+       bnx2x_cl45_read(bp, phy,
+                       MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &tmp1);
 
-static void bnx2x_bcm8726_external_rom_boot(struct link_params *params)
-{
-       struct bnx2x *bp = params->bp;
-       u8 port = params->port;
-       u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
-       u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
+       bnx2x_cl45_read(bp, phy,
+                       MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM, &tmp1);
 
-       /* Need to wait 100ms after reset */
-       msleep(100);
+       DP(NETIF_MSG_LINK, "Before rom RX_ALARM(port1): 0x%x\n", tmp1);
 
-       /* Micro controller re-boot */
-       bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
-                      MDIO_PMA_DEVAD,
-                      MDIO_PMA_REG_GEN_CTRL,
-                      0x018B);
+       /* Enable CL37 BAM */
+       bnx2x_cl45_read(bp, phy,
+                       MDIO_AN_DEVAD,
+                       MDIO_AN_REG_8073_BAM, &val);
+       bnx2x_cl45_write(bp, phy,
+                        MDIO_AN_DEVAD,
+                        MDIO_AN_REG_8073_BAM, val | 1);
 
-       /* Set soft reset */
-       bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
-                      MDIO_PMA_DEVAD,
-                      MDIO_PMA_REG_GEN_CTRL,
-                      MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
+       if (params->loopback_mode == LOOPBACK_EXT) {
+               bnx2x_807x_force_10G(bp, phy);
+               DP(NETIF_MSG_LINK, "Forced speed 10G on 807X\n");
+               return 0;
+       } else {
+               bnx2x_cl45_write(bp, phy,
+                                MDIO_PMA_DEVAD, MDIO_PMA_REG_BCM_CTRL, 0x0002);
+       }
+       if (phy->req_line_speed != SPEED_AUTO_NEG) {
+               if (phy->req_line_speed == SPEED_10000) {
+                       val = (1<<7);
+               } else if (phy->req_line_speed ==  SPEED_2500) {
+                       val = (1<<5);
+                       /* Note that 2.5G works only
+                       when used with 1G advertisment */
+               } else
+                       val = (1<<5);
+       } else {
+               val = 0;
+               if (phy->speed_cap_mask &
+                       PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
+                       val |= (1<<7);
+
+               /* Note that 2.5G works only when
+               used with 1G advertisment */
+               if (phy->speed_cap_mask &
+                       (PORT_HW_CFG_SPEED_CAPABILITY_D0_1G |
+                        PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G))
+                       val |= (1<<5);
+               DP(NETIF_MSG_LINK, "807x autoneg val = 0x%x\n", val);
+       }
 
-       bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
-                      MDIO_PMA_DEVAD,
-                      MDIO_PMA_REG_MISC_CTRL1, 0x0001);
+       bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV, val);
+       bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_8073_2_5G, &tmp1);
+
+       if (((phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G) &&
+            (phy->req_line_speed == SPEED_AUTO_NEG)) ||
+           (phy->req_line_speed == SPEED_2500)) {
+               u16 phy_ver;
+               /* Allow 2.5G for A1 and above */
+               bnx2x_cl45_read(bp, phy,
+                               MDIO_PMA_DEVAD, MDIO_PMA_REG_8073_CHIP_REV,
+                               &phy_ver);
+               DP(NETIF_MSG_LINK, "Add 2.5G\n");
+               if (phy_ver > 0)
+                       tmp1 |= 1;
+               else
+                       tmp1 &= 0xfffe;
+       } else {
+               DP(NETIF_MSG_LINK, "Disable 2.5G\n");
+               tmp1 &= 0xfffe;
+       }
 
-       bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
-                      MDIO_PMA_DEVAD,
-                      MDIO_PMA_REG_GEN_CTRL,
-                      MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
+       bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_8073_2_5G, tmp1);
+       /* Add support for CL37 (passive mode) II */
 
-       /* wait for 150ms for microcode load */
-       msleep(150);
+       bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD, &tmp1);
+       bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD,
+                        (tmp1 | ((phy->req_duplex == DUPLEX_FULL) ?
+                                 0x20 : 0x40)));
 
-       /* Disable serial boot control, tristates pins SS_N, SCK, MOSI, MISO */
-       bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
-                      MDIO_PMA_DEVAD,
-                      MDIO_PMA_REG_MISC_CTRL1, 0x0000);
+       /* Add support for CL37 (passive mode) III */
+       bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1000);
 
-       msleep(200);
-       bnx2x_save_bcm_spirom_ver(bp, port,
-                               ext_phy_type,
-                               ext_phy_addr,
-                               params->shmem_base);
+       /* The SNR will improve about 2db by changing
+       BW and FEE main tap. Rest commands are executed
+       after link is up*/
+       if (bnx2x_8073_is_snr_needed(bp, phy))
+               bnx2x_cl45_write(bp, phy,
+                                MDIO_PMA_DEVAD, MDIO_PMA_REG_EDC_FFE_MAIN,
+                                0xFB0C);
+
+       /* Enable FEC (Forware Error Correction) Request in the AN */
+       bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV2, &tmp1);
+       tmp1 |= (1<<15);
+       bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV2, tmp1);
+
+       bnx2x_ext_phy_set_pause(params, phy, vars);
+
+       /* Restart autoneg */
+       msleep(500);
+       bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x1200);
+       DP(NETIF_MSG_LINK, "807x Autoneg Restart: Advertise 1G=%x, 10G=%x\n",
+                  ((val & (1<<5)) > 0), ((val & (1<<7)) > 0));
+       return 0;
+}
+
+static u8 bnx2x_8073_read_status(struct bnx2x_phy *phy,
+                                struct link_params *params,
+                                struct link_vars *vars)
+{
+       struct bnx2x *bp = params->bp;
+       u8 link_up = 0;
+       u16 val1, val2;
+       u16 link_status = 0;
+       u16 an1000_status = 0;
+
+       bnx2x_cl45_read(bp, phy,
+                       MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val1);
+
+       DP(NETIF_MSG_LINK, "8703 LASI status 0x%x\n", val1);
+
+       /* clear the interrupt LASI status register */
+       bnx2x_cl45_read(bp, phy,
+                       MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &val2);
+       bnx2x_cl45_read(bp, phy,
+                       MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &val1);
+       DP(NETIF_MSG_LINK, "807x PCS status 0x%x->0x%x\n", val2, val1);
+       /* Clear MSG-OUT */
+       bnx2x_cl45_read(bp, phy,
+                       MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &val1);
+
+       /* Check the LASI */
+       bnx2x_cl45_read(bp, phy,
+                       MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM, &val2);
+
+       DP(NETIF_MSG_LINK, "KR 0x9003 0x%x\n", val2);
+
+       /* Check the link status */
+       bnx2x_cl45_read(bp, phy,
+                       MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &val2);
+       DP(NETIF_MSG_LINK, "KR PCS status 0x%x\n", val2);
+
+       bnx2x_cl45_read(bp, phy,
+                       MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val2);
+       bnx2x_cl45_read(bp, phy,
+                       MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val1);
+       link_up = ((val1 & 4) == 4);
+       DP(NETIF_MSG_LINK, "PMA_REG_STATUS=0x%x\n", val1);
+
+       if (link_up &&
+            ((phy->req_line_speed != SPEED_10000))) {
+               if (bnx2x_8073_xaui_wa(bp, phy) != 0)
+                       return 0;
+       }
+       bnx2x_cl45_read(bp, phy,
+                       MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &an1000_status);
+       bnx2x_cl45_read(bp, phy,
+                       MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &an1000_status);
+
+       /* Check the link status on 1.1.2 */
+       bnx2x_cl45_read(bp, phy,
+                       MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val2);
+       bnx2x_cl45_read(bp, phy,
+                       MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val1);
+       DP(NETIF_MSG_LINK, "KR PMA status 0x%x->0x%x,"
+                  "an_link_status=0x%x\n", val2, val1, an1000_status);
+
+       link_up = (((val1 & 4) == 4) || (an1000_status & (1<<1)));
+       if (link_up && bnx2x_8073_is_snr_needed(bp, phy)) {
+               /* The SNR will improve about 2dbby
+               changing the BW and FEE main tap.*/
+               /* The 1st write to change FFE main
+               tap is set before restart AN */
+               /* Change PLL Bandwidth in EDC
+               register */
+               bnx2x_cl45_write(bp, phy,
+                                MDIO_PMA_DEVAD, MDIO_PMA_REG_PLL_BANDWIDTH,
+                                0x26BC);
+
+               /* Change CDR Bandwidth in EDC register */
+               bnx2x_cl45_write(bp, phy,
+                                MDIO_PMA_DEVAD, MDIO_PMA_REG_CDR_BANDWIDTH,
+                                0x0333);
+       }
+       bnx2x_cl45_read(bp, phy,
+                       MDIO_PMA_DEVAD, MDIO_PMA_REG_8073_SPEED_LINK_STATUS,
+                       &link_status);
+
+       /* Bits 0..2 --> speed detected, bits 13..15--> link is down */
+       if ((link_status & (1<<2)) && (!(link_status & (1<<15)))) {
+               link_up = 1;
+               vars->line_speed = SPEED_10000;
+               DP(NETIF_MSG_LINK, "port %x: External link up in 10G\n",
+                          params->port);
+       } else if ((link_status & (1<<1)) && (!(link_status & (1<<14)))) {
+               link_up = 1;
+               vars->line_speed = SPEED_2500;
+               DP(NETIF_MSG_LINK, "port %x: External link up in 2.5G\n",
+                          params->port);
+       } else if ((link_status & (1<<0)) && (!(link_status & (1<<13)))) {
+               link_up = 1;
+               vars->line_speed = SPEED_1000;
+               DP(NETIF_MSG_LINK, "port %x: External link up in 1G\n",
+                          params->port);
+       } else {
+               link_up = 0;
+               DP(NETIF_MSG_LINK, "port %x: External link is down\n",
+                          params->port);
+       }
+
+       if (link_up) {
+               bnx2x_ext_phy_10G_an_resolve(bp, phy, vars);
+               bnx2x_8073_resolve_fc(phy, params, vars);
+       }
+       return link_up;
+}
+
+static void bnx2x_8073_link_reset(struct bnx2x_phy *phy,
+                                 struct link_params *params)
+{
+       struct bnx2x *bp = params->bp;
+       u8 gpio_port;
+       gpio_port = params->port;
+       DP(NETIF_MSG_LINK, "Setting 8073 port %d into low power mode\n",
+          gpio_port);
+       bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
+                           MISC_REGISTERS_GPIO_OUTPUT_LOW,
+                           gpio_port);
+}
+
+/******************************************************************/
+/*                     BCM8705 PHY SECTION                       */
+/******************************************************************/
+static u8 bnx2x_8705_config_init(struct bnx2x_phy *phy,
+                                struct link_params *params,
+                                struct link_vars *vars)
+{
+       struct bnx2x *bp = params->bp;
+       DP(NETIF_MSG_LINK, "init 8705\n");
+       /* Restore normal power mode*/
+       bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
+                           MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
+       /* HW reset */
+       bnx2x_ext_phy_hw_reset(bp, params->port);
+       bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0xa040);
+       bnx2x_wait_reset_complete(bp, phy);
+
+       bnx2x_cl45_write(bp, phy,
+                        MDIO_PMA_DEVAD, MDIO_PMA_REG_MISC_CTRL, 0x8288);
+       bnx2x_cl45_write(bp, phy,
+                        MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, 0x7fbf);
+       bnx2x_cl45_write(bp, phy,
+                        MDIO_PMA_DEVAD, MDIO_PMA_REG_CMU_PLL_BYPASS, 0x0100);
+       bnx2x_cl45_write(bp, phy,
+                        MDIO_WIS_DEVAD, MDIO_WIS_REG_LASI_CNTL, 0x1);
+       /* BCM8705 doesn't have microcode, hence the 0 */
+       bnx2x_save_spirom_version(bp, params->port, params->shmem_base, 0);
+       return 0;
+}
+
+static u8 bnx2x_8705_read_status(struct bnx2x_phy *phy,
+                                struct link_params *params,
+                                struct link_vars *vars)
+{
+       u8 link_up = 0;
+       u16 val1, rx_sd;
+       struct bnx2x *bp = params->bp;
+       DP(NETIF_MSG_LINK, "read status 8705\n");
+       bnx2x_cl45_read(bp, phy,
+                     MDIO_WIS_DEVAD, MDIO_WIS_REG_LASI_STATUS, &val1);
+       DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1);
+
+       bnx2x_cl45_read(bp, phy,
+                     MDIO_WIS_DEVAD, MDIO_WIS_REG_LASI_STATUS, &val1);
+       DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1);
+
+       bnx2x_cl45_read(bp, phy,
+                     MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_SD, &rx_sd);
+
+       bnx2x_cl45_read(bp, phy,
+                     MDIO_PMA_DEVAD, 0xc809, &val1);
+       bnx2x_cl45_read(bp, phy,
+                     MDIO_PMA_DEVAD, 0xc809, &val1);
+
+       DP(NETIF_MSG_LINK, "8705 1.c809 val=0x%x\n", val1);
+       link_up = ((rx_sd & 0x1) && (val1 & (1<<9)) && ((val1 & (1<<8)) == 0));
+       if (link_up) {
+               vars->line_speed = SPEED_10000;
+               bnx2x_ext_phy_resolve_fc(phy, params, vars);
+       }
+       return link_up;
 }
 
-static void bnx2x_sfp_set_transmitter(struct bnx2x *bp, u8 port,
-                                   u32 ext_phy_type, u8 ext_phy_addr,
-                                   u8 tx_en)
+/******************************************************************/
+/*                     SFP+ module Section                       */
+/******************************************************************/
+static void bnx2x_sfp_set_transmitter(struct bnx2x *bp,
+                                     struct bnx2x_phy *phy,
+                                     u8 port,
+                                     u8 tx_en)
 {
        u16 val;
 
        DP(NETIF_MSG_LINK, "Setting transmitter tx_en=%x for port %x\n",
                 tx_en, port);
        /* Disable/Enable transmitter ( TX laser of the SFP+ module.)*/
-       bnx2x_cl45_read(bp, port,
-                     ext_phy_type,
-                     ext_phy_addr,
+       bnx2x_cl45_read(bp, phy,
                      MDIO_PMA_DEVAD,
                      MDIO_PMA_REG_PHY_IDENTIFIER,
                      &val);
@@ -2651,58 +3774,42 @@ static void bnx2x_sfp_set_transmitter(struct bnx2x *bp, u8 port,
        else
                val |= (1<<15);
 
-       bnx2x_cl45_write(bp, port,
-                      ext_phy_type,
-                      ext_phy_addr,
+       bnx2x_cl45_write(bp, phy,
                       MDIO_PMA_DEVAD,
                       MDIO_PMA_REG_PHY_IDENTIFIER,
                       val);
 }
 
-static u8 bnx2x_8726_read_sfp_module_eeprom(struct link_params *params,
+static u8 bnx2x_8726_read_sfp_module_eeprom(struct bnx2x_phy *phy,
+                                           struct link_params *params,
                                          u16 addr, u8 byte_cnt, u8 *o_buf)
 {
        struct bnx2x *bp = params->bp;
        u16 val = 0;
        u16 i;
-       u8 port = params->port;
-       u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
-       u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
-
        if (byte_cnt > 16) {
                DP(NETIF_MSG_LINK, "Reading from eeprom is"
                            " is limited to 0xf\n");
                return -EINVAL;
        }
        /* Set the read command byte count */
-       bnx2x_cl45_write(bp, port,
-                      ext_phy_type,
-                      ext_phy_addr,
-                      MDIO_PMA_DEVAD,
-                      MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT,
+       bnx2x_cl45_write(bp, phy,
+                        MDIO_PMA_DEVAD, MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT,
                       (byte_cnt | 0xa000));
 
        /* Set the read command address */
-       bnx2x_cl45_write(bp, port,
-                      ext_phy_type,
-                      ext_phy_addr,
-                      MDIO_PMA_DEVAD,
-                      MDIO_PMA_REG_SFP_TWO_WIRE_MEM_ADDR,
+       bnx2x_cl45_write(bp, phy,
+                        MDIO_PMA_DEVAD, MDIO_PMA_REG_SFP_TWO_WIRE_MEM_ADDR,
                       addr);
 
        /* Activate read command */
-       bnx2x_cl45_write(bp, port,
-                      ext_phy_type,
-                      ext_phy_addr,
-                      MDIO_PMA_DEVAD,
-                      MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
+       bnx2x_cl45_write(bp, phy,
+                        MDIO_PMA_DEVAD, MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
                       0x2c0f);
 
        /* Wait up to 500us for command complete status */
        for (i = 0; i < 100; i++) {
-               bnx2x_cl45_read(bp, port,
-                             ext_phy_type,
-                             ext_phy_addr,
+               bnx2x_cl45_read(bp, phy,
                              MDIO_PMA_DEVAD,
                              MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
                if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
@@ -2721,18 +3828,14 @@ static u8 bnx2x_8726_read_sfp_module_eeprom(struct link_params *params,
 
        /* Read the buffer */
        for (i = 0; i < byte_cnt; i++) {
-               bnx2x_cl45_read(bp, port,
-                             ext_phy_type,
-                             ext_phy_addr,
+               bnx2x_cl45_read(bp, phy,
                              MDIO_PMA_DEVAD,
                              MDIO_PMA_REG_8726_TWO_WIRE_DATA_BUF + i, &val);
                o_buf[i] = (u8)(val & MDIO_PMA_REG_8726_TWO_WIRE_DATA_MASK);
        }
 
        for (i = 0; i < 100; i++) {
-               bnx2x_cl45_read(bp, port,
-                             ext_phy_type,
-                             ext_phy_addr,
+               bnx2x_cl45_read(bp, phy,
                              MDIO_PMA_DEVAD,
                              MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
                if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
@@ -2743,14 +3846,12 @@ static u8 bnx2x_8726_read_sfp_module_eeprom(struct link_params *params,
        return -EINVAL;
 }
 
-static u8 bnx2x_8727_read_sfp_module_eeprom(struct link_params *params,
+static u8 bnx2x_8727_read_sfp_module_eeprom(struct bnx2x_phy *phy,
+                                           struct link_params *params,
                                          u16 addr, u8 byte_cnt, u8 *o_buf)
 {
        struct bnx2x *bp = params->bp;
        u16 val, i;
-       u8 port = params->port;
-       u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
-       u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
 
        if (byte_cnt > 16) {
                DP(NETIF_MSG_LINK, "Reading from eeprom is"
@@ -2759,40 +3860,30 @@ static u8 bnx2x_8727_read_sfp_module_eeprom(struct link_params *params,
        }
 
        /* Need to read from 1.8000 to clear it */
-       bnx2x_cl45_read(bp, port,
-                     PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
-                     ext_phy_addr,
+       bnx2x_cl45_read(bp, phy,
                      MDIO_PMA_DEVAD,
                      MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
                      &val);
 
        /* Set the read command byte count */
-       bnx2x_cl45_write(bp, port,
-                      ext_phy_type,
-                      ext_phy_addr,
+       bnx2x_cl45_write(bp, phy,
                       MDIO_PMA_DEVAD,
                       MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT,
                       ((byte_cnt < 2) ? 2 : byte_cnt));
 
        /* Set the read command address */
-       bnx2x_cl45_write(bp, port,
-                      ext_phy_type,
-                      ext_phy_addr,
+       bnx2x_cl45_write(bp, phy,
                       MDIO_PMA_DEVAD,
                       MDIO_PMA_REG_SFP_TWO_WIRE_MEM_ADDR,
                       addr);
        /* Set the destination address */
-       bnx2x_cl45_write(bp, port,
-                      ext_phy_type,
-                      ext_phy_addr,
+       bnx2x_cl45_write(bp, phy,
                       MDIO_PMA_DEVAD,
                       0x8004,
                       MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF);
 
        /* Activate read command */
-       bnx2x_cl45_write(bp, port,
-                      ext_phy_type,
-                      ext_phy_addr,
+       bnx2x_cl45_write(bp, phy,
                       MDIO_PMA_DEVAD,
                       MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
                       0x8002);
@@ -2802,9 +3893,7 @@ static u8 bnx2x_8727_read_sfp_module_eeprom(struct link_params *params,
 
        /* Wait up to 500us for command complete status */
        for (i = 0; i < 100; i++) {
-               bnx2x_cl45_read(bp, port,
-                             ext_phy_type,
-                             ext_phy_addr,
+               bnx2x_cl45_read(bp, phy,
                              MDIO_PMA_DEVAD,
                              MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
                if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
@@ -2823,18 +3912,14 @@ static u8 bnx2x_8727_read_sfp_module_eeprom(struct link_params *params,
 
        /* Read the buffer */
        for (i = 0; i < byte_cnt; i++) {
-               bnx2x_cl45_read(bp, port,
-                             ext_phy_type,
-                             ext_phy_addr,
+               bnx2x_cl45_read(bp, phy,
                              MDIO_PMA_DEVAD,
                              MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF + i, &val);
                o_buf[i] = (u8)(val & MDIO_PMA_REG_8727_TWO_WIRE_DATA_MASK);
        }
 
        for (i = 0; i < 100; i++) {
-               bnx2x_cl45_read(bp, port,
-                             ext_phy_type,
-                             ext_phy_addr,
+               bnx2x_cl45_read(bp, phy,
                              MDIO_PMA_DEVAD,
                              MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
                if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
@@ -2846,21 +3931,21 @@ static u8 bnx2x_8727_read_sfp_module_eeprom(struct link_params *params,
        return -EINVAL;
 }
 
-u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr,
+u8 bnx2x_read_sfp_module_eeprom(struct bnx2x_phy *phy,
+                               struct link_params *params, u16 addr,
                                     u8 byte_cnt, u8 *o_buf)
 {
-       u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
-
-       if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726)
-               return bnx2x_8726_read_sfp_module_eeprom(params, addr,
+       if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726)
+               return bnx2x_8726_read_sfp_module_eeprom(phy, params, addr,
                                                       byte_cnt, o_buf);
-       else if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727)
-               return bnx2x_8727_read_sfp_module_eeprom(params, addr,
+       else if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727)
+               return bnx2x_8727_read_sfp_module_eeprom(phy, params, addr,
                                                       byte_cnt, o_buf);
        return -EINVAL;
 }
 
-static u8 bnx2x_get_edc_mode(struct link_params *params,
+static u8 bnx2x_get_edc_mode(struct bnx2x_phy *phy,
+                            struct link_params *params,
                                  u16 *edc_mode)
 {
        struct bnx2x *bp = params->bp;
@@ -2868,10 +3953,11 @@ static u8 bnx2x_get_edc_mode(struct link_params *params,
        *edc_mode = EDC_MODE_LIMITING;
 
        /* First check for copper cable */
-       if (bnx2x_read_sfp_module_eeprom(params,
-                                      SFP_EEPROM_CON_TYPE_ADDR,
-                                      1,
-                                      &val) != 0) {
+       if (bnx2x_read_sfp_module_eeprom(phy,
+                                        params,
+                                        SFP_EEPROM_CON_TYPE_ADDR,
+                                        1,
+                                        &val) != 0) {
                DP(NETIF_MSG_LINK, "Failed to read from SFP+ module EEPROM\n");
                return -EINVAL;
        }
@@ -2883,7 +3969,8 @@ static u8 bnx2x_get_edc_mode(struct link_params *params,
 
                /* Check if its active cable( includes SFP+ module)
                of passive cable*/
-               if (bnx2x_read_sfp_module_eeprom(params,
+               if (bnx2x_read_sfp_module_eeprom(phy,
+                                              params,
                                               SFP_EEPROM_FC_TX_TECH_ADDR,
                                               1,
                                               &copper_module_type) !=
@@ -2923,10 +4010,11 @@ static u8 bnx2x_get_edc_mode(struct link_params *params,
 
        if (check_limiting_mode) {
                u8 options[SFP_EEPROM_OPTIONS_SIZE];
-               if (bnx2x_read_sfp_module_eeprom(params,
-                                              SFP_EEPROM_OPTIONS_ADDR,
-                                              SFP_EEPROM_OPTIONS_SIZE,
-                                              options) != 0) {
+               if (bnx2x_read_sfp_module_eeprom(phy,
+                                                params,
+                                                SFP_EEPROM_OPTIONS_ADDR,
+                                                SFP_EEPROM_OPTIONS_SIZE,
+                                                options) != 0) {
                        DP(NETIF_MSG_LINK, "Failed to read Option"
                                " field from module EEPROM\n");
                        return -EINVAL;
@@ -2939,17 +4027,17 @@ static u8 bnx2x_get_edc_mode(struct link_params *params,
        DP(NETIF_MSG_LINK, "EDC mode is set to 0x%x\n", *edc_mode);
        return 0;
 }
-
 /* This function read the relevant field from the module ( SFP+ ),
        and verify it is compliant with this board */
-static u8 bnx2x_verify_sfp_module(struct link_params *params)
+static u8 bnx2x_verify_sfp_module(struct bnx2x_phy *phy,
+                                 struct link_params *params)
 {
        struct bnx2x *bp = params->bp;
-       u32 val;
-       u32 fw_resp;
+       u32 val, cmd;
+       u32 fw_resp, fw_cmd_param;
        char vendor_name[SFP_EEPROM_VENDOR_NAME_SIZE+1];
        char vendor_pn[SFP_EEPROM_PART_NO_SIZE+1];
-
+       phy->flags &= ~FLAGS_SFP_NOT_APPROVED;
        val = REG_RD(bp, params->shmem_base +
                         offsetof(struct shmem_region, dev_info.
                                  port_feature_config[params->port].config));
@@ -2959,52 +4047,122 @@ static u8 bnx2x_verify_sfp_module(struct link_params *params)
                return 0;
        }
 
-       /* Ask the FW to validate the module */
-       if (!(params->feature_config_flags &
-             FEATURE_CONFIG_BC_SUPPORTS_OPT_MDL_VRFY)) {
+       if (params->feature_config_flags &
+           FEATURE_CONFIG_BC_SUPPORTS_DUAL_PHY_OPT_MDL_VRFY) {
+               /* Use specific phy request */
+               cmd = DRV_MSG_CODE_VRFY_SPECIFIC_PHY_OPT_MDL;
+       } else if (params->feature_config_flags &
+                  FEATURE_CONFIG_BC_SUPPORTS_OPT_MDL_VRFY) {
+               /* Use first phy request only in case of non-dual media*/
+               if (DUAL_MEDIA(params)) {
+                       DP(NETIF_MSG_LINK, "FW does not support OPT MDL "
+                          "verification\n");
+                       return -EINVAL;
+               }
+               cmd = DRV_MSG_CODE_VRFY_FIRST_PHY_OPT_MDL;
+       } else {
+               /* No support in OPT MDL detection */
                DP(NETIF_MSG_LINK, "FW does not support OPT MDL "
-                           "verification\n");
+                         "verification\n");
                return -EINVAL;
        }
-
-       fw_resp = bnx2x_fw_command(bp, DRV_MSG_CODE_VRFY_OPT_MDL);
+       fw_cmd_param = FW_PARAM_SET(phy->addr, phy->type, phy->mdio_ctrl);
+       fw_resp = bnx2x_fw_command(bp, cmd, fw_cmd_param);
        if (fw_resp == FW_MSG_CODE_VRFY_OPT_MDL_SUCCESS) {
                DP(NETIF_MSG_LINK, "Approved module\n");
                return 0;
        }
 
        /* format the warning message */
-       if (bnx2x_read_sfp_module_eeprom(params,
+       if (bnx2x_read_sfp_module_eeprom(phy,
+                                        params,
                                       SFP_EEPROM_VENDOR_NAME_ADDR,
                                       SFP_EEPROM_VENDOR_NAME_SIZE,
                                       (u8 *)vendor_name))
                vendor_name[0] = '\0';
        else
                vendor_name[SFP_EEPROM_VENDOR_NAME_SIZE] = '\0';
-       if (bnx2x_read_sfp_module_eeprom(params,
+       if (bnx2x_read_sfp_module_eeprom(phy,
+                                        params,
                                       SFP_EEPROM_PART_NO_ADDR,
                                       SFP_EEPROM_PART_NO_SIZE,
                                       (u8 *)vendor_pn))
                vendor_pn[0] = '\0';
        else
-               vendor_pn[SFP_EEPROM_PART_NO_SIZE] = '\0';
+               vendor_pn[SFP_EEPROM_PART_NO_SIZE] = '\0';
+
+       netdev_info(bp->dev, "Warning: Unqualified SFP+ module detected,"
+                            " Port %d from %s part number %s\n",
+                   params->port, vendor_name, vendor_pn);
+       phy->flags |= FLAGS_SFP_NOT_APPROVED;
+       return -EINVAL;
+}
+
+static u8 bnx2x_wait_for_sfp_module_initialized(struct bnx2x_phy *phy,
+                                               struct link_params *params)
+
+{
+       u8 val;
+       struct bnx2x *bp = params->bp;
+       u16 timeout;
+       /* Initialization time after hot-plug may take up to 300ms for some
+       phys type ( e.g. JDSU ) */
+       for (timeout = 0; timeout < 60; timeout++) {
+               if (bnx2x_read_sfp_module_eeprom(phy, params, 1, 1, &val)
+                   == 0) {
+                       DP(NETIF_MSG_LINK, "SFP+ module initialization "
+                                    "took %d ms\n", timeout * 5);
+                       return 0;
+               }
+               msleep(5);
+       }
+       return -EINVAL;
+}
+
+static void bnx2x_8727_power_module(struct bnx2x *bp,
+                                   struct bnx2x_phy *phy,
+                                   u8 is_power_up) {
+       /* Make sure GPIOs are not using for LED mode */
+       u16 val;
+       /*
+        * In the GPIO register, bit 4 is use to detemine if the GPIOs are
+        * operating as INPUT or as OUTPUT. Bit 1 is for input, and 0 for
+        * output
+        * Bits 0-1 determine the gpios value for OUTPUT in case bit 4 val is 0
+        * Bits 8-9 determine the gpios value for INPUT in case bit 4 val is 1
+        * where the 1st bit is the over-current(only input), and 2nd bit is
+        * for power( only output )
+       */
+
+       /*
+        * In case of NOC feature is disabled and power is up, set GPIO control
+        *  as input to enable listening of over-current indication
+        */
+       if (phy->flags & FLAGS_NOC)
+               return;
+       if (!(phy->flags &
+             FLAGS_NOC) && is_power_up)
+               val = (1<<4);
+       else
+               /*
+                * Set GPIO control to OUTPUT, and set the power bit
+                * to according to the is_power_up
+                */
+               val = ((!(is_power_up)) << 1);
 
-       netdev_info(bp->dev, "Warning: Unqualified SFP+ module detected, Port %d from %s part number %s\n",
-                   params->port, vendor_name, vendor_pn);
-       return -EINVAL;
+       bnx2x_cl45_write(bp, phy,
+                        MDIO_PMA_DEVAD,
+                        MDIO_PMA_REG_8727_GPIO_CTRL,
+                        val);
 }
 
-static u8 bnx2x_bcm8726_set_limiting_mode(struct link_params *params,
-                                       u16 edc_mode)
+static u8 bnx2x_8726_set_limiting_mode(struct bnx2x *bp,
+                                      struct bnx2x_phy *phy,
+                                      u16 edc_mode)
 {
-       struct bnx2x *bp = params->bp;
-       u8 port = params->port;
-       u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
        u16 cur_limiting_mode;
 
-       bnx2x_cl45_read(bp, port,
-                     PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
-                     ext_phy_addr,
+       bnx2x_cl45_read(bp, phy,
                      MDIO_PMA_DEVAD,
                      MDIO_PMA_REG_ROM_VER2,
                      &cur_limiting_mode);
@@ -3014,12 +4172,10 @@ static u8 bnx2x_bcm8726_set_limiting_mode(struct link_params *params,
        if (edc_mode == EDC_MODE_LIMITING) {
                DP(NETIF_MSG_LINK,
                         "Setting LIMITING MODE\n");
-               bnx2x_cl45_write(bp, port,
-                              PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
-                              ext_phy_addr,
-                              MDIO_PMA_DEVAD,
-                              MDIO_PMA_REG_ROM_VER2,
-                              EDC_MODE_LIMITING);
+               bnx2x_cl45_write(bp, phy,
+                                MDIO_PMA_DEVAD,
+                                MDIO_PMA_REG_ROM_VER2,
+                                EDC_MODE_LIMITING);
        } else { /* LRM mode ( default )*/
 
                DP(NETIF_MSG_LINK, "Setting LRM MODE\n");
@@ -3030,27 +4186,19 @@ static u8 bnx2x_bcm8726_set_limiting_mode(struct link_params *params,
                if (cur_limiting_mode != EDC_MODE_LIMITING)
                        return 0;
 
-               bnx2x_cl45_write(bp, port,
-                              PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
-                              ext_phy_addr,
+               bnx2x_cl45_write(bp, phy,
                               MDIO_PMA_DEVAD,
                               MDIO_PMA_REG_LRM_MODE,
                               0);
-               bnx2x_cl45_write(bp, port,
-                              PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
-                              ext_phy_addr,
+               bnx2x_cl45_write(bp, phy,
                               MDIO_PMA_DEVAD,
                               MDIO_PMA_REG_ROM_VER2,
                               0x128);
-               bnx2x_cl45_write(bp, port,
-                              PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
-                              ext_phy_addr,
+               bnx2x_cl45_write(bp, phy,
                               MDIO_PMA_DEVAD,
                               MDIO_PMA_REG_MISC_CTRL0,
                               0x4008);
-               bnx2x_cl45_write(bp, port,
-                              PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
-                              ext_phy_addr,
+               bnx2x_cl45_write(bp, phy,
                               MDIO_PMA_DEVAD,
                               MDIO_PMA_REG_LRM_MODE,
                               0xaaaa);
@@ -3058,46 +4206,33 @@ static u8 bnx2x_bcm8726_set_limiting_mode(struct link_params *params,
        return 0;
 }
 
-static u8 bnx2x_bcm8727_set_limiting_mode(struct link_params *params,
+static u8 bnx2x_8727_set_limiting_mode(struct bnx2x *bp,
+                                      struct bnx2x_phy *phy,
                                        u16 edc_mode)
 {
-       struct bnx2x *bp = params->bp;
-       u8 port = params->port;
        u16 phy_identifier;
        u16 rom_ver2_val;
-       u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
-
-       bnx2x_cl45_read(bp, port,
-                      PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
-                      ext_phy_addr,
+       bnx2x_cl45_read(bp, phy,
                       MDIO_PMA_DEVAD,
                       MDIO_PMA_REG_PHY_IDENTIFIER,
                       &phy_identifier);
 
-       bnx2x_cl45_write(bp, port,
-                      PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
-                      ext_phy_addr,
+       bnx2x_cl45_write(bp, phy,
                       MDIO_PMA_DEVAD,
                       MDIO_PMA_REG_PHY_IDENTIFIER,
                       (phy_identifier & ~(1<<9)));
 
-       bnx2x_cl45_read(bp, port,
-                     PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
-                     ext_phy_addr,
+       bnx2x_cl45_read(bp, phy,
                      MDIO_PMA_DEVAD,
                      MDIO_PMA_REG_ROM_VER2,
                      &rom_ver2_val);
        /* Keep the MSB 8-bits, and set the LSB 8-bits with the edc_mode */
-       bnx2x_cl45_write(bp, port,
-                      PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
-                      ext_phy_addr,
+       bnx2x_cl45_write(bp, phy,
                       MDIO_PMA_DEVAD,
                       MDIO_PMA_REG_ROM_VER2,
                       (rom_ver2_val & 0xff00) | (edc_mode & 0x00ff));
 
-       bnx2x_cl45_write(bp, port,
-                      PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
-                      ext_phy_addr,
+       bnx2x_cl45_write(bp, phy,
                       MDIO_PMA_DEVAD,
                       MDIO_PMA_REG_PHY_IDENTIFIER,
                       (phy_identifier | (1<<9)));
@@ -3105,72 +4240,34 @@ static u8 bnx2x_bcm8727_set_limiting_mode(struct link_params *params,
        return 0;
 }
 
-
-static u8 bnx2x_wait_for_sfp_module_initialized(struct link_params *params)
+static void bnx2x_8727_specific_func(struct bnx2x_phy *phy,
+                                    struct link_params *params,
+                                    u32 action)
 {
-       u8 val;
        struct bnx2x *bp = params->bp;
-       u16 timeout;
-       /* Initialization time after hot-plug may take up to 300ms for some
-       phys type ( e.g. JDSU ) */
-       for (timeout = 0; timeout < 60; timeout++) {
-               if (bnx2x_read_sfp_module_eeprom(params, 1, 1, &val)
-                   == 0) {
-                       DP(NETIF_MSG_LINK, "SFP+ module initialization "
-                                    "took %d ms\n", timeout * 5);
-                       return 0;
-               }
-               msleep(5);
-       }
-       return -EINVAL;
-}
-
-static void bnx2x_8727_power_module(struct bnx2x *bp,
-                                 struct link_params *params,
-                                 u8 ext_phy_addr, u8 is_power_up) {
-       /* Make sure GPIOs are not using for LED mode */
-       u16 val;
-       u8 port = params->port;
-       /*
-        * In the GPIO register, bit 4 is use to detemine if the GPIOs are
-        * operating as INPUT or as OUTPUT. Bit 1 is for input, and 0 for
-        * output
-        * Bits 0-1 determine the gpios value for OUTPUT in case bit 4 val is 0
-        * Bits 8-9 determine the gpios value for INPUT in case bit 4 val is 1
-        * where the 1st bit is the over-current(only input), and 2nd bit is
-        * for power( only output )
-       */
 
-       /*
-        * In case of NOC feature is disabled and power is up, set GPIO control
-        *  as input to enable listening of over-current indication
-        */
-
-       if (!(params->feature_config_flags &
-             FEATURE_CONFIG_BCM8727_NOC) && is_power_up)
-               val = (1<<4);
-       else
-               /*
-                * Set GPIO control to OUTPUT, and set the power bit
-                * to according to the is_power_up
-                */
-               val = ((!(is_power_up)) << 1);
-
-       bnx2x_cl45_write(bp, port,
-                      PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
-                      ext_phy_addr,
-                      MDIO_PMA_DEVAD,
-                      MDIO_PMA_REG_8727_GPIO_CTRL,
-                      val);
+       switch (action) {
+       case DISABLE_TX:
+               bnx2x_sfp_set_transmitter(bp, phy, params->port, 0);
+               break;
+       case ENABLE_TX:
+               if (!(phy->flags & FLAGS_SFP_NOT_APPROVED))
+                       bnx2x_sfp_set_transmitter(bp, phy, params->port, 1);
+               break;
+       default:
+               DP(NETIF_MSG_LINK, "Function 0x%x not supported by 8727\n",
+                  action);
+               return;
+       }
 }
 
-static u8 bnx2x_sfp_module_detection(struct link_params *params)
+static u8 bnx2x_sfp_module_detection(struct bnx2x_phy *phy,
+                                    struct link_params *params)
 {
        struct bnx2x *bp = params->bp;
        u16 edc_mode;
        u8 rc = 0;
-       u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
-       u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
+
        u32 val = REG_RD(bp, params->shmem_base +
                             offsetof(struct shmem_region, dev_info.
                                     port_feature_config[params->port].config));
@@ -3178,10 +4275,10 @@ static u8 bnx2x_sfp_module_detection(struct link_params *params)
        DP(NETIF_MSG_LINK, "SFP+ module plugged in/out detected on port %d\n",
                 params->port);
 
-       if (bnx2x_get_edc_mode(params, &edc_mode) != 0) {
+       if (bnx2x_get_edc_mode(phy, params, &edc_mode) != 0) {
                DP(NETIF_MSG_LINK, "Failed to get valid module type\n");
                return -EINVAL;
-       } else if (bnx2x_verify_sfp_module(params) !=
+       } else if (bnx2x_verify_sfp_module(phy, params) !=
                   0) {
                /* check SFP+ module compatibility */
                DP(NETIF_MSG_LINK, "Module verification failed!!\n");
@@ -3190,13 +4287,12 @@ static u8 bnx2x_sfp_module_detection(struct link_params *params)
                bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
                                  MISC_REGISTERS_GPIO_HIGH,
                                  params->port);
-               if ((ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727) &&
+               if ((phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727) &&
                    ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
                     PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_POWER_DOWN)) {
                        /* Shutdown SFP+ module */
                        DP(NETIF_MSG_LINK, "Shutdown SFP+ module!!\n");
-                       bnx2x_8727_power_module(bp, params,
-                                             ext_phy_addr, 0);
+                       bnx2x_8727_power_module(bp, phy, 0);
                        return rc;
                }
        } else {
@@ -3208,15 +4304,15 @@ static u8 bnx2x_sfp_module_detection(struct link_params *params)
        }
 
        /* power up the SFP module */
-       if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727)
-               bnx2x_8727_power_module(bp, params, ext_phy_addr, 1);
+       if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727)
+               bnx2x_8727_power_module(bp, phy, 1);
 
        /* Check and set limiting mode / LRM mode on 8726.
        On 8727 it is done automatically */
-       if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726)
-               bnx2x_bcm8726_set_limiting_mode(params, edc_mode);
+       if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726)
+               bnx2x_8726_set_limiting_mode(bp, phy, edc_mode);
        else
-               bnx2x_bcm8727_set_limiting_mode(params, edc_mode);
+               bnx2x_8727_set_limiting_mode(bp, phy, edc_mode);
        /*
         * Enable transmit for this module if the module is approved, or
         * if unapproved modules should also enable the Tx laser
@@ -3224,11 +4320,9 @@ static u8 bnx2x_sfp_module_detection(struct link_params *params)
        if (rc == 0 ||
            (val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) !=
            PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
-               bnx2x_sfp_set_transmitter(bp, params->port,
-                                       ext_phy_type, ext_phy_addr, 1);
+               bnx2x_sfp_set_transmitter(bp, phy, params->port, 1);
        else
-               bnx2x_sfp_set_transmitter(bp, params->port,
-                                       ext_phy_type, ext_phy_addr, 0);
+               bnx2x_sfp_set_transmitter(bp, phy, params->port, 0);
 
        return rc;
 }
@@ -3236,6 +4330,7 @@ static u8 bnx2x_sfp_module_detection(struct link_params *params)
 void bnx2x_handle_module_detect_int(struct link_params *params)
 {
        struct bnx2x *bp = params->bp;
+       struct bnx2x_phy *phy = &params->phy[EXT_PHY1];
        u32 gpio_val;
        u8 port = params->port;
 
@@ -3245,1349 +4340,587 @@ void bnx2x_handle_module_detect_int(struct link_params *params)
                          params->port);
 
        /* Get current gpio val refelecting module plugged in / out*/
-       gpio_val = bnx2x_get_gpio(bp,  MISC_REGISTERS_GPIO_3, port);
+       gpio_val = bnx2x_get_gpio(bp, MISC_REGISTERS_GPIO_3, port);
 
        /* Call the handling function in case module is detected */
        if (gpio_val == 0) {
 
                bnx2x_set_gpio_int(bp, MISC_REGISTERS_GPIO_3,
-                                     MISC_REGISTERS_GPIO_INT_OUTPUT_CLR,
-                                     port);
+                                  MISC_REGISTERS_GPIO_INT_OUTPUT_CLR,
+                                  port);
 
-               if (bnx2x_wait_for_sfp_module_initialized(params) ==
-                   0)
-                       bnx2x_sfp_module_detection(params);
+               if (bnx2x_wait_for_sfp_module_initialized(phy, params) == 0)
+                       bnx2x_sfp_module_detection(phy, params);
                else
-                       DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n");
-       } else {
-               u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
-
-               u32 ext_phy_type =
-                       XGXS_EXT_PHY_TYPE(params->ext_phy_config);
-               u32 val = REG_RD(bp, params->shmem_base +
-                                    offsetof(struct shmem_region, dev_info.
-                                             port_feature_config[params->port].
-                                             config));
-
-               bnx2x_set_gpio_int(bp, MISC_REGISTERS_GPIO_3,
-                                     MISC_REGISTERS_GPIO_INT_OUTPUT_SET,
-                                     port);
-               /* Module was plugged out. */
-               /* Disable transmit for this module */
-               if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
-                   PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
-                       bnx2x_sfp_set_transmitter(bp, params->port,
-                                               ext_phy_type, ext_phy_addr, 0);
-       }
-}
-
-static void bnx2x_bcm807x_force_10G(struct link_params *params)
-{
-       struct bnx2x *bp = params->bp;
-       u8 port = params->port;
-       u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
-       u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
-
-       /* Force KR or KX */
-       bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
-                      MDIO_PMA_DEVAD,
-                      MDIO_PMA_REG_CTRL,
-                      0x2040);
-       bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
-                      MDIO_PMA_DEVAD,
-                      MDIO_PMA_REG_10G_CTRL2,
-                      0x000b);
-       bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
-                      MDIO_PMA_DEVAD,
-                      MDIO_PMA_REG_BCM_CTRL,
-                      0x0000);
-       bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
-                      MDIO_AN_DEVAD,
-                      MDIO_AN_REG_CTRL,
-                      0x0000);
-}
-
-static void bnx2x_bcm8073_set_xaui_low_power_mode(struct link_params *params)
-{
-       struct bnx2x *bp = params->bp;
-       u8 port = params->port;
-       u16 val;
-       u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
-       u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
-
-       bnx2x_cl45_read(bp, params->port,
-                     PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
-                     ext_phy_addr,
-                     MDIO_PMA_DEVAD,
-                     MDIO_PMA_REG_8073_CHIP_REV, &val);
-
-       if (val == 0) {
-               /* Mustn't set low power mode in 8073 A0 */
-               return;
-       }
-
-       /* Disable PLL sequencer (use read-modify-write to clear bit 13) */
-       bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr,
-                      MDIO_XS_DEVAD,
-                      MDIO_XS_PLL_SEQUENCER, &val);
-       val &= ~(1<<13);
-       bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
-                      MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, val);
-
-       /* PLL controls */
-       bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
-                      MDIO_XS_DEVAD, 0x805E, 0x1077);
-       bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
-                      MDIO_XS_DEVAD, 0x805D, 0x0000);
-       bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
-                      MDIO_XS_DEVAD, 0x805C, 0x030B);
-       bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
-                      MDIO_XS_DEVAD, 0x805B, 0x1240);
-       bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
-                      MDIO_XS_DEVAD, 0x805A, 0x2490);
-
-       /* Tx Controls */
-       bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
-                      MDIO_XS_DEVAD, 0x80A7, 0x0C74);
-       bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
-                      MDIO_XS_DEVAD, 0x80A6, 0x9041);
-       bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
-                      MDIO_XS_DEVAD, 0x80A5, 0x4640);
-
-       /* Rx Controls */
-       bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
-                      MDIO_XS_DEVAD, 0x80FE, 0x01C4);
-       bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
-                      MDIO_XS_DEVAD, 0x80FD, 0x9249);
-       bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
-                      MDIO_XS_DEVAD, 0x80FC, 0x2015);
-
-       /* Enable PLL sequencer  (use read-modify-write to set bit 13) */
-       bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr,
-                      MDIO_XS_DEVAD,
-                      MDIO_XS_PLL_SEQUENCER, &val);
-       val |= (1<<13);
-       bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
-                      MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, val);
-}
-
-static void bnx2x_8073_set_pause_cl37(struct link_params *params,
-                                 struct link_vars *vars)
-{
-       struct bnx2x *bp = params->bp;
-       u16 cl37_val;
-       u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
-       u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
-
-       bnx2x_cl45_read(bp, params->port,
-                     ext_phy_type,
-                     ext_phy_addr,
-                     MDIO_AN_DEVAD,
-                     MDIO_AN_REG_CL37_FC_LD, &cl37_val);
-
-       cl37_val &= ~MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
-       /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */
-
-       if ((vars->ieee_fc &
-           MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC) ==
-           MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC) {
-               cl37_val |=  MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC;
-       }
-       if ((vars->ieee_fc &
-           MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) ==
-           MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) {
-               cl37_val |=  MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
-       }
-       if ((vars->ieee_fc &
-           MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) ==
-           MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) {
-               cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
-       }
-       DP(NETIF_MSG_LINK,
-                "Ext phy AN advertize cl37 0x%x\n", cl37_val);
-
-       bnx2x_cl45_write(bp, params->port,
-                      ext_phy_type,
-                      ext_phy_addr,
-                      MDIO_AN_DEVAD,
-                      MDIO_AN_REG_CL37_FC_LD, cl37_val);
-       msleep(500);
-}
-
-static void bnx2x_ext_phy_set_pause(struct link_params *params,
-                                 struct link_vars *vars)
-{
-       struct bnx2x *bp = params->bp;
-       u16 val;
-       u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
-       u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
-
-       /* read modify write pause advertizing */
-       bnx2x_cl45_read(bp, params->port,
-                     ext_phy_type,
-                     ext_phy_addr,
-                     MDIO_AN_DEVAD,
-                     MDIO_AN_REG_ADV_PAUSE, &val);
-
-       val &= ~MDIO_AN_REG_ADV_PAUSE_BOTH;
-
-       /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */
-
-       if ((vars->ieee_fc &
-           MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) ==
-           MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) {
-               val |=  MDIO_AN_REG_ADV_PAUSE_ASYMMETRIC;
-       }
-       if ((vars->ieee_fc &
-           MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) ==
-           MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) {
-               val |=
-                MDIO_AN_REG_ADV_PAUSE_PAUSE;
-       }
-       DP(NETIF_MSG_LINK,
-                "Ext phy AN advertize 0x%x\n", val);
-       bnx2x_cl45_write(bp, params->port,
-                      ext_phy_type,
-                      ext_phy_addr,
-                      MDIO_AN_DEVAD,
-                      MDIO_AN_REG_ADV_PAUSE, val);
-}
-static void bnx2x_set_preemphasis(struct link_params *params)
-{
-       u16 bank, i = 0;
-       struct bnx2x *bp = params->bp;
-
-       for (bank = MDIO_REG_BANK_RX0, i = 0; bank <= MDIO_REG_BANK_RX3;
-             bank += (MDIO_REG_BANK_RX1-MDIO_REG_BANK_RX0), i++) {
-                       CL45_WR_OVER_CL22(bp, params->port,
-                                             params->phy_addr,
-                                             bank,
-                                             MDIO_RX0_RX_EQ_BOOST,
-                                             params->xgxs_config_rx[i]);
-       }
-
-       for (bank = MDIO_REG_BANK_TX0, i = 0; bank <= MDIO_REG_BANK_TX3;
-                     bank += (MDIO_REG_BANK_TX1 - MDIO_REG_BANK_TX0), i++) {
-                       CL45_WR_OVER_CL22(bp, params->port,
-                                             params->phy_addr,
-                                             bank,
-                                             MDIO_TX0_TX_DRIVER,
-                                             params->xgxs_config_tx[i]);
-       }
-}
-
-
-static void bnx2x_8481_set_led4(struct link_params *params,
-                             u32 ext_phy_type, u8 ext_phy_addr)
-{
-       struct bnx2x *bp = params->bp;
-
-       /* PHYC_CTL_LED_CTL */
-       bnx2x_cl45_write(bp, params->port,
-                      ext_phy_type,
-                      ext_phy_addr,
-                      MDIO_PMA_DEVAD,
-                      MDIO_PMA_REG_8481_LINK_SIGNAL, 0xa482);
-
-       /* Unmask LED4 for 10G link */
-       bnx2x_cl45_write(bp, params->port,
-                      ext_phy_type,
-                      ext_phy_addr,
-                      MDIO_PMA_DEVAD,
-                      MDIO_PMA_REG_8481_SIGNAL_MASK, (1<<6));
-       /* 'Interrupt Mask' */
-       bnx2x_cl45_write(bp, params->port,
-                      ext_phy_type,
-                      ext_phy_addr,
-                      MDIO_AN_DEVAD,
-                      0xFFFB, 0xFFFD);
-}
-static void bnx2x_8481_set_legacy_led_mode(struct link_params *params,
-                                        u32 ext_phy_type, u8 ext_phy_addr)
-{
-       struct bnx2x *bp = params->bp;
-
-       /* LED1 (10G Link): Disable LED1 when 10/100/1000 link */
-       /* LED2 (1G/100/10 Link): Enable LED2 when 10/100/1000 link) */
-       bnx2x_cl45_write(bp, params->port,
-                      ext_phy_type,
-                      ext_phy_addr,
-                      MDIO_AN_DEVAD,
-                      MDIO_AN_REG_8481_LEGACY_SHADOW,
-                      (1<<15) | (0xd << 10) | (0xc<<4) | 0xe);
-}
-
-static void bnx2x_8481_set_10G_led_mode(struct link_params *params,
-                                     u32 ext_phy_type, u8 ext_phy_addr)
-{
-       struct bnx2x *bp = params->bp;
-       u16 val1;
-
-       /* LED1 (10G Link) */
-       /* Enable continuse based on source 7(10G-link) */
-       bnx2x_cl45_read(bp, params->port,
-                      ext_phy_type,
-                      ext_phy_addr,
-                      MDIO_PMA_DEVAD,
-                      MDIO_PMA_REG_8481_LINK_SIGNAL,
-                      &val1);
-       /* Set bit 2 to 0, and bits [1:0] to 10 */
-       val1 &= ~((1<<0) | (1<<2) | (1<<7)); /* Clear bits 0,2,7*/
-       val1 |= ((1<<1) | (1<<6)); /* Set bit 1, 6 */
-
-       bnx2x_cl45_write(bp, params->port,
-                      ext_phy_type,
-                      ext_phy_addr,
-                      MDIO_PMA_DEVAD,
-                      MDIO_PMA_REG_8481_LINK_SIGNAL,
-                      val1);
-
-       /* Unmask LED1 for 10G link */
-       bnx2x_cl45_read(bp, params->port,
-                     ext_phy_type,
-                     ext_phy_addr,
-                     MDIO_PMA_DEVAD,
-                     MDIO_PMA_REG_8481_LED1_MASK,
-                     &val1);
-       /* Set bit 2 to 0, and bits [1:0] to 10 */
-       val1 |= (1<<7);
-       bnx2x_cl45_write(bp, params->port,
-                      ext_phy_type,
-                      ext_phy_addr,
-                      MDIO_PMA_DEVAD,
-                      MDIO_PMA_REG_8481_LED1_MASK,
-                      val1);
-
-       /* LED2 (1G/100/10G Link) */
-       /* Mask LED2 for 10G link */
-       bnx2x_cl45_write(bp, params->port,
-                      ext_phy_type,
-                      ext_phy_addr,
-                      MDIO_PMA_DEVAD,
-                      MDIO_PMA_REG_8481_LED2_MASK,
-                      0);
-
-       /* Unmask LED3 for 10G link */
-       bnx2x_cl45_write(bp, params->port,
-                      ext_phy_type,
-                      ext_phy_addr,
-                      MDIO_PMA_DEVAD,
-                     MDIO_PMA_REG_8481_LED3_MASK,
-                      0x6);
-       bnx2x_cl45_write(bp, params->port,
-                      ext_phy_type,
-                      ext_phy_addr,
-                      MDIO_PMA_DEVAD,
-                      MDIO_PMA_REG_8481_LED3_BLINK,
-                      0);
-}
-
-
-static void bnx2x_init_internal_phy(struct link_params *params,
-                                 struct link_vars *vars,
-                                 u8 enable_cl73)
-{
-       struct bnx2x *bp = params->bp;
-
-       if (!(vars->phy_flags & PHY_SGMII_FLAG)) {
-               if ((XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
-                    PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) &&
-                   (params->feature_config_flags &
-                    FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED))
-                       bnx2x_set_preemphasis(params);
-
-               /* forced speed requested? */
-               if (vars->line_speed != SPEED_AUTO_NEG ||
-                   ((XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
-                    PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) &&
-                         params->loopback_mode == LOOPBACK_EXT)) {
-                       DP(NETIF_MSG_LINK, "not SGMII, no AN\n");
-
-                       /* disable autoneg */
-                       bnx2x_set_autoneg(params, vars, 0);
-
-                       /* program speed and duplex */
-                       bnx2x_program_serdes(params, vars);
-
-               } else { /* AN_mode */
-                       DP(NETIF_MSG_LINK, "not SGMII, AN\n");
-
-                       /* AN enabled */
-                       bnx2x_set_brcm_cl37_advertisment(params);
-
-                       /* program duplex & pause advertisement (for aneg) */
-                       bnx2x_set_ieee_aneg_advertisment(params,
-                                                      vars->ieee_fc);
-
-                       /* enable autoneg */
-                       bnx2x_set_autoneg(params, vars, enable_cl73);
-
-                       /* enable and restart AN */
-                       bnx2x_restart_autoneg(params, enable_cl73);
-               }
-
-       } else { /* SGMII mode */
-               DP(NETIF_MSG_LINK, "SGMII\n");
+                       DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n");
+       } else {
+               u32 val = REG_RD(bp, params->shmem_base +
+                                    offsetof(struct shmem_region, dev_info.
+                                             port_feature_config[params->port].
+                                             config));
 
-               bnx2x_initialize_sgmii_process(params, vars);
+               bnx2x_set_gpio_int(bp, MISC_REGISTERS_GPIO_3,
+                                  MISC_REGISTERS_GPIO_INT_OUTPUT_SET,
+                                  port);
+               /* Module was plugged out. */
+               /* Disable transmit for this module */
+               if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
+                   PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
+                       bnx2x_sfp_set_transmitter(bp, phy, params->port, 0);
        }
 }
 
-static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars)
+/******************************************************************/
+/*             common BCM8706/BCM8726 PHY SECTION                */
+/******************************************************************/
+static u8 bnx2x_8706_8726_read_status(struct bnx2x_phy *phy,
+                                     struct link_params *params,
+                                     struct link_vars *vars)
 {
+       u8 link_up = 0;
+       u16 val1, val2, rx_sd, pcs_status;
        struct bnx2x *bp = params->bp;
-       u32 ext_phy_type;
-       u8 ext_phy_addr;
-       u16 cnt;
-       u16 ctrl = 0;
-       u16 val = 0;
-       u8 rc = 0;
+       DP(NETIF_MSG_LINK, "XGXS 8706/8726\n");
+       /* Clear RX Alarm*/
+       bnx2x_cl45_read(bp, phy,
+                       MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM, &val2);
+       /* clear LASI indication*/
+       bnx2x_cl45_read(bp, phy,
+                       MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val1);
+       bnx2x_cl45_read(bp, phy,
+                       MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val2);
+       DP(NETIF_MSG_LINK, "8706/8726 LASI status 0x%x--> 0x%x\n", val1, val2);
+
+       bnx2x_cl45_read(bp, phy,
+                       MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_SD, &rx_sd);
+       bnx2x_cl45_read(bp, phy,
+                       MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &pcs_status);
+       bnx2x_cl45_read(bp, phy,
+                       MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &val2);
+       bnx2x_cl45_read(bp, phy,
+                       MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &val2);
+
+       DP(NETIF_MSG_LINK, "8706/8726 rx_sd 0x%x pcs_status 0x%x 1Gbps"
+                       " link_status 0x%x\n", rx_sd, pcs_status, val2);
+       /* link is up if both bit 0 of pmd_rx_sd and
+        * bit 0 of pcs_status are set, or if the autoneg bit
+        * 1 is set
+        */
+       link_up = ((rx_sd & pcs_status & 0x1) || (val2 & (1<<1)));
+       if (link_up) {
+               if (val2 & (1<<1))
+                       vars->line_speed = SPEED_1000;
+               else
+                       vars->line_speed = SPEED_10000;
+               bnx2x_ext_phy_resolve_fc(phy, params, vars);
+       }
+       return link_up;
+}
 
-       if (vars->phy_flags & PHY_XGXS_FLAG) {
-               ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
+/******************************************************************/
+/*                     BCM8706 PHY SECTION                       */
+/******************************************************************/
+static u8 bnx2x_8706_config_init(struct bnx2x_phy *phy,
+                                struct link_params *params,
+                                struct link_vars *vars)
+{
+       u16 cnt, val;
+       struct bnx2x *bp = params->bp;
+       bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
+                           MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
+       /* HW reset */
+       bnx2x_ext_phy_hw_reset(bp, params->port);
+       bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0xa040);
+       bnx2x_wait_reset_complete(bp, phy);
 
-               ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
-               /* Make sure that the soft reset is off (expect for the 8072:
-                * due to the lock, it will be done inside the specific
-                * handling)
-                */
-               if ((ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) &&
-                   (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) &&
-                  (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN) &&
-                   (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072) &&
-                   (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073)) {
-                       /* Wait for soft reset to get cleared upto 1 sec */
-                       for (cnt = 0; cnt < 1000; cnt++) {
-                               bnx2x_cl45_read(bp, params->port,
-                                             ext_phy_type,
-                                             ext_phy_addr,
-                                             MDIO_PMA_DEVAD,
-                                             MDIO_PMA_REG_CTRL, &ctrl);
-                               if (!(ctrl & (1<<15)))
-                                       break;
-                               msleep(1);
-                       }
-                       DP(NETIF_MSG_LINK, "control reg 0x%x (after %d ms)\n",
-                                ctrl, cnt);
+       /* Wait until fw is loaded */
+       for (cnt = 0; cnt < 100; cnt++) {
+               bnx2x_cl45_read(bp, phy,
+                               MDIO_PMA_DEVAD, MDIO_PMA_REG_ROM_VER1, &val);
+               if (val)
+                       break;
+               msleep(10);
+       }
+       DP(NETIF_MSG_LINK, "XGXS 8706 is initialized after %d ms\n", cnt);
+       if ((params->feature_config_flags &
+            FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
+               u8 i;
+               u16 reg;
+               for (i = 0; i < 4; i++) {
+                       reg = MDIO_XS_8706_REG_BANK_RX0 +
+                               i*(MDIO_XS_8706_REG_BANK_RX1 -
+                                  MDIO_XS_8706_REG_BANK_RX0);
+                       bnx2x_cl45_read(bp, phy, MDIO_XS_DEVAD, reg, &val);
+                       /* Clear first 3 bits of the control */
+                       val &= ~0x7;
+                       /* Set control bits according to configuration */
+                       val |= (phy->rx_preemphasis[i] & 0x7);
+                       DP(NETIF_MSG_LINK, "Setting RX Equalizer to BCM8706"
+                                  " reg 0x%x <-- val 0x%x\n", reg, val);
+                       bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, reg, val);
                }
+       }
+       /* Force speed */
+       if (phy->req_line_speed == SPEED_10000) {
+               DP(NETIF_MSG_LINK, "XGXS 8706 force 10Gbps\n");
+
+               bnx2x_cl45_write(bp, phy,
+                                MDIO_PMA_DEVAD,
+                                MDIO_PMA_REG_DIGITAL_CTRL, 0x400);
+               bnx2x_cl45_write(bp, phy,
+                                MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 1);
+       } else {
+               /* Force 1Gbps using autoneg with 1G advertisment */
+
+               /* Allow CL37 through CL73 */
+               DP(NETIF_MSG_LINK, "XGXS 8706 AutoNeg\n");
+               bnx2x_cl45_write(bp, phy,
+                                MDIO_AN_DEVAD, MDIO_AN_REG_CL37_CL73, 0x040c);
+
+               /* Enable Full-Duplex advertisment on CL37 */
+               bnx2x_cl45_write(bp, phy,
+                                MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LP, 0x0020);
+               /* Enable CL37 AN */
+               bnx2x_cl45_write(bp, phy,
+                                MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1000);
+               /* 1G support */
+               bnx2x_cl45_write(bp, phy,
+                                MDIO_AN_DEVAD, MDIO_AN_REG_ADV, (1<<5));
+
+               /* Enable clause 73 AN */
+               bnx2x_cl45_write(bp, phy,
+                                MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x1200);
+               bnx2x_cl45_write(bp, phy,
+                                MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
+                                0x0400);
+               bnx2x_cl45_write(bp, phy,
+                                MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL,
+                                0x0004);
+       }
+       bnx2x_save_bcm_spirom_ver(bp, phy, params->port);
+       return 0;
+}
 
-               switch (ext_phy_type) {
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
-                       break;
+static u8 bnx2x_8706_read_status(struct bnx2x_phy *phy,
+                                struct link_params *params,
+                                struct link_vars *vars)
+{
+       return bnx2x_8706_8726_read_status(phy, params, vars);
+}
 
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
-                       DP(NETIF_MSG_LINK, "XGXS 8705\n");
-
-                       bnx2x_cl45_write(bp, params->port,
-                                      ext_phy_type,
-                                      ext_phy_addr,
-                                      MDIO_PMA_DEVAD,
-                                      MDIO_PMA_REG_MISC_CTRL,
-                                      0x8288);
-                       bnx2x_cl45_write(bp, params->port,
-                                      ext_phy_type,
-                                      ext_phy_addr,
-                                      MDIO_PMA_DEVAD,
-                                      MDIO_PMA_REG_PHY_IDENTIFIER,
-                                      0x7fbf);
-                       bnx2x_cl45_write(bp, params->port,
-                                      ext_phy_type,
-                                      ext_phy_addr,
-                                      MDIO_PMA_DEVAD,
-                                      MDIO_PMA_REG_CMU_PLL_BYPASS,
-                                      0x0100);
-                       bnx2x_cl45_write(bp, params->port,
-                                      ext_phy_type,
-                                      ext_phy_addr,
-                                      MDIO_WIS_DEVAD,
-                                      MDIO_WIS_REG_LASI_CNTL, 0x1);
-
-                       /* BCM8705 doesn't have microcode, hence the 0 */
-                       bnx2x_save_spirom_version(bp, params->port,
-                                               params->shmem_base, 0);
-                       break;
+/******************************************************************/
+/*                     BCM8726 PHY SECTION                       */
+/******************************************************************/
+static void bnx2x_8726_config_loopback(struct bnx2x_phy *phy,
+                                      struct link_params *params)
+{
+       struct bnx2x *bp = params->bp;
+       DP(NETIF_MSG_LINK, "PMA/PMD ext_phy_loopback: 8726\n");
+       bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x0001);
+}
 
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
-                       /* Wait until fw is loaded */
-                       for (cnt = 0; cnt < 100; cnt++) {
-                               bnx2x_cl45_read(bp, params->port, ext_phy_type,
-                                             ext_phy_addr, MDIO_PMA_DEVAD,
-                                             MDIO_PMA_REG_ROM_VER1, &val);
-                               if (val)
-                                       break;
-                               msleep(10);
-                       }
-                       DP(NETIF_MSG_LINK, "XGXS 8706 is initialized "
-                               "after %d ms\n", cnt);
-                       if ((params->feature_config_flags &
-                            FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
-                               u8 i;
-                               u16 reg;
-                               for (i = 0; i < 4; i++) {
-                                       reg = MDIO_XS_8706_REG_BANK_RX0 +
-                                               i*(MDIO_XS_8706_REG_BANK_RX1 -
-                                                  MDIO_XS_8706_REG_BANK_RX0);
-                                       bnx2x_cl45_read(bp, params->port,
-                                                     ext_phy_type,
-                                                     ext_phy_addr,
-                                                     MDIO_XS_DEVAD,
-                                                     reg, &val);
-                                       /* Clear first 3 bits of the control */
-                                       val &= ~0x7;
-                                       /* Set control bits according to
-                                       configuation */
-                                       val |= (params->xgxs_config_rx[i] &
-                                               0x7);
-                                       DP(NETIF_MSG_LINK, "Setting RX"
-                                                "Equalizer to BCM8706 reg 0x%x"
-                                                " <-- val 0x%x\n", reg, val);
-                                       bnx2x_cl45_write(bp, params->port,
-                                                      ext_phy_type,
-                                                      ext_phy_addr,
-                                                      MDIO_XS_DEVAD,
-                                                      reg, val);
-                               }
-                       }
-                       /* Force speed */
-                       if (params->req_line_speed == SPEED_10000) {
-                               DP(NETIF_MSG_LINK, "XGXS 8706 force 10Gbps\n");
-
-                               bnx2x_cl45_write(bp, params->port,
-                                              ext_phy_type,
-                                              ext_phy_addr,
-                                              MDIO_PMA_DEVAD,
-                                              MDIO_PMA_REG_DIGITAL_CTRL,
-                                              0x400);
-                               bnx2x_cl45_write(bp, params->port, ext_phy_type,
-                                              ext_phy_addr, MDIO_PMA_DEVAD,
-                                              MDIO_PMA_REG_LASI_CTRL, 1);
-                       } else {
-                               /* Force 1Gbps using autoneg with 1G
-                               advertisment */
-
-                               /* Allow CL37 through CL73 */
-                               DP(NETIF_MSG_LINK, "XGXS 8706 AutoNeg\n");
-                               bnx2x_cl45_write(bp, params->port,
-                                              ext_phy_type,
-                                              ext_phy_addr,
-                                              MDIO_AN_DEVAD,
-                                              MDIO_AN_REG_CL37_CL73,
-                                              0x040c);
-
-                               /* Enable Full-Duplex advertisment on CL37 */
-                               bnx2x_cl45_write(bp, params->port,
-                                              ext_phy_type,
-                                              ext_phy_addr,
-                                              MDIO_AN_DEVAD,
-                                              MDIO_AN_REG_CL37_FC_LP,
-                                              0x0020);
-                               /* Enable CL37 AN */
-                               bnx2x_cl45_write(bp, params->port,
-                                              ext_phy_type,
-                                              ext_phy_addr,
-                                              MDIO_AN_DEVAD,
-                                              MDIO_AN_REG_CL37_AN,
-                                              0x1000);
-                               /* 1G support */
-                               bnx2x_cl45_write(bp, params->port,
-                                              ext_phy_type,
-                                              ext_phy_addr,
-                                              MDIO_AN_DEVAD,
-                                              MDIO_AN_REG_ADV, (1<<5));
-
-                               /* Enable clause 73 AN */
-                               bnx2x_cl45_write(bp, params->port,
-                                              ext_phy_type,
-                                              ext_phy_addr,
-                                              MDIO_AN_DEVAD,
-                                              MDIO_AN_REG_CTRL,
-                                              0x1200);
-                               bnx2x_cl45_write(bp, params->port,
-                                              ext_phy_type,
-                                              ext_phy_addr,
-                                              MDIO_PMA_DEVAD,
-                                              MDIO_PMA_REG_RX_ALARM_CTRL,
-                                              0x0400);
-                               bnx2x_cl45_write(bp, params->port,
-                                              ext_phy_type,
-                                              ext_phy_addr,
-                                              MDIO_PMA_DEVAD,
-                                              MDIO_PMA_REG_LASI_CTRL, 0x0004);
+static void bnx2x_8726_external_rom_boot(struct bnx2x_phy *phy,
+                                        struct link_params *params)
+{
+       struct bnx2x *bp = params->bp;
+       /* Need to wait 100ms after reset */
+       msleep(100);
 
-                       }
-                       bnx2x_save_bcm_spirom_ver(bp, params->port,
-                                               ext_phy_type,
-                                               ext_phy_addr,
-                                               params->shmem_base);
-                       break;
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
-                       DP(NETIF_MSG_LINK, "Initializing BCM8726\n");
-                       bnx2x_bcm8726_external_rom_boot(params);
-
-                       /* Need to call module detected on initialization since
-                       the module detection triggered by actual module
-                       insertion might occur before driver is loaded, and when
-                       driver is loaded, it reset all registers, including the
-                       transmitter */
-                       bnx2x_sfp_module_detection(params);
-
-                       /* Set Flow control */
-                       bnx2x_ext_phy_set_pause(params, vars);
-                       if (params->req_line_speed == SPEED_1000) {
-                               DP(NETIF_MSG_LINK, "Setting 1G force\n");
-                               bnx2x_cl45_write(bp, params->port, ext_phy_type,
-                                              ext_phy_addr, MDIO_PMA_DEVAD,
-                                              MDIO_PMA_REG_CTRL, 0x40);
-                               bnx2x_cl45_write(bp, params->port, ext_phy_type,
-                                              ext_phy_addr, MDIO_PMA_DEVAD,
-                                              MDIO_PMA_REG_10G_CTRL2, 0xD);
-                               bnx2x_cl45_write(bp, params->port, ext_phy_type,
-                                              ext_phy_addr, MDIO_PMA_DEVAD,
-                                              MDIO_PMA_REG_LASI_CTRL, 0x5);
-                               bnx2x_cl45_write(bp, params->port, ext_phy_type,
-                                              ext_phy_addr, MDIO_PMA_DEVAD,
-                                              MDIO_PMA_REG_RX_ALARM_CTRL,
-                                              0x400);
-                       } else if ((params->req_line_speed ==
-                                   SPEED_AUTO_NEG) &&
-                                  ((params->speed_cap_mask &
-                                    PORT_HW_CFG_SPEED_CAPABILITY_D0_1G))) {
-                               DP(NETIF_MSG_LINK, "Setting 1G clause37\n");
-                               bnx2x_cl45_write(bp, params->port, ext_phy_type,
-                                              ext_phy_addr, MDIO_AN_DEVAD,
-                                              MDIO_AN_REG_ADV, 0x20);
-                               bnx2x_cl45_write(bp, params->port, ext_phy_type,
-                                              ext_phy_addr, MDIO_AN_DEVAD,
-                                              MDIO_AN_REG_CL37_CL73, 0x040c);
-                               bnx2x_cl45_write(bp, params->port, ext_phy_type,
-                                              ext_phy_addr, MDIO_AN_DEVAD,
-                                              MDIO_AN_REG_CL37_FC_LD, 0x0020);
-                               bnx2x_cl45_write(bp, params->port, ext_phy_type,
-                                              ext_phy_addr, MDIO_AN_DEVAD,
-                                              MDIO_AN_REG_CL37_AN, 0x1000);
-                               bnx2x_cl45_write(bp, params->port, ext_phy_type,
-                                              ext_phy_addr, MDIO_AN_DEVAD,
-                                              MDIO_AN_REG_CTRL, 0x1200);
-
-                               /* Enable RX-ALARM control to receive
-                               interrupt for 1G speed change */
-                               bnx2x_cl45_write(bp, params->port, ext_phy_type,
-                                              ext_phy_addr, MDIO_PMA_DEVAD,
-                                              MDIO_PMA_REG_LASI_CTRL, 0x4);
-                               bnx2x_cl45_write(bp, params->port, ext_phy_type,
-                                              ext_phy_addr, MDIO_PMA_DEVAD,
-                                              MDIO_PMA_REG_RX_ALARM_CTRL,
-                                              0x400);
-
-                       } else { /* Default 10G. Set only LASI control */
-                               bnx2x_cl45_write(bp, params->port, ext_phy_type,
-                                              ext_phy_addr, MDIO_PMA_DEVAD,
-                                              MDIO_PMA_REG_LASI_CTRL, 1);
-                       }
+       /* Micro controller re-boot */
+       bnx2x_cl45_write(bp, phy,
+                        MDIO_PMA_DEVAD, MDIO_PMA_REG_GEN_CTRL, 0x018B);
 
-                       /* Set TX PreEmphasis if needed */
-                       if ((params->feature_config_flags &
-                            FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
-                               DP(NETIF_MSG_LINK, "Setting TX_CTRL1 0x%x,"
-                                        "TX_CTRL2 0x%x\n",
-                                        params->xgxs_config_tx[0],
-                                        params->xgxs_config_tx[1]);
-                               bnx2x_cl45_write(bp, params->port,
-                                              ext_phy_type,
-                                              ext_phy_addr,
-                                              MDIO_PMA_DEVAD,
-                                              MDIO_PMA_REG_8726_TX_CTRL1,
-                                              params->xgxs_config_tx[0]);
-
-                               bnx2x_cl45_write(bp, params->port,
-                                              ext_phy_type,
-                                              ext_phy_addr,
-                                              MDIO_PMA_DEVAD,
-                                              MDIO_PMA_REG_8726_TX_CTRL2,
-                                              params->xgxs_config_tx[1]);
-                       }
-                       break;
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
-               {
-                       u16 tmp1;
-                       u16 rx_alarm_ctrl_val;
-                       u16 lasi_ctrl_val;
-                       if (ext_phy_type ==
-                           PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072) {
-                               rx_alarm_ctrl_val = 0x400;
-                               lasi_ctrl_val = 0x0004;
-                       } else {
-                               rx_alarm_ctrl_val = (1<<2);
-                               lasi_ctrl_val = 0x0004;
-                       }
+       /* Set soft reset */
+       bnx2x_cl45_write(bp, phy,
+                      MDIO_PMA_DEVAD,
+                      MDIO_PMA_REG_GEN_CTRL,
+                      MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
 
-                       /* enable LASI */
-                       bnx2x_cl45_write(bp, params->port,
-                                  ext_phy_type,
-                                  ext_phy_addr,
-                                  MDIO_PMA_DEVAD,
-                                  MDIO_PMA_REG_RX_ALARM_CTRL,
-                                  rx_alarm_ctrl_val);
-
-                       bnx2x_cl45_write(bp, params->port,
-                                      ext_phy_type,
-                                      ext_phy_addr,
-                                      MDIO_PMA_DEVAD,
-                                      MDIO_PMA_REG_LASI_CTRL,
-                                      lasi_ctrl_val);
-
-                       bnx2x_8073_set_pause_cl37(params, vars);
-
-                       if (ext_phy_type ==
-                           PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072)
-                               bnx2x_bcm8072_external_rom_boot(params);
-                       else
-                               /* In case of 8073 with long xaui lines,
-                               don't set the 8073 xaui low power*/
-                               bnx2x_bcm8073_set_xaui_low_power_mode(params);
-
-                       bnx2x_cl45_read(bp, params->port,
-                                     ext_phy_type,
-                                     ext_phy_addr,
-                                     MDIO_PMA_DEVAD,
-                                     MDIO_PMA_REG_M8051_MSGOUT_REG,
-                                     &tmp1);
-
-                       bnx2x_cl45_read(bp, params->port,
-                                     ext_phy_type,
-                                     ext_phy_addr,
-                                     MDIO_PMA_DEVAD,
-                                     MDIO_PMA_REG_RX_ALARM, &tmp1);
-
-                       DP(NETIF_MSG_LINK, "Before rom RX_ALARM(port1):"
-                                            "0x%x\n", tmp1);
-
-                       /* If this is forced speed, set to KR or KX
-                        * (all other are not supported)
-                        */
-                       if (params->loopback_mode == LOOPBACK_EXT) {
-                               bnx2x_bcm807x_force_10G(params);
-                               DP(NETIF_MSG_LINK,
-                                       "Forced speed 10G on 807X\n");
-                               break;
-                       } else {
-                               bnx2x_cl45_write(bp, params->port,
-                                              ext_phy_type, ext_phy_addr,
-                                              MDIO_PMA_DEVAD,
-                                              MDIO_PMA_REG_BCM_CTRL,
-                                              0x0002);
-                       }
-                       if (params->req_line_speed != SPEED_AUTO_NEG) {
-                               if (params->req_line_speed == SPEED_10000) {
-                                       val = (1<<7);
-                               } else if (params->req_line_speed ==
-                                          SPEED_2500) {
-                                       val = (1<<5);
-                                       /* Note that 2.5G works only
-                                       when used with 1G advertisment */
-                               } else
-                                       val = (1<<5);
-                       } else {
-
-                               val = 0;
-                               if (params->speed_cap_mask &
-                                       PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
-                                       val |= (1<<7);
-
-                               /* Note that 2.5G works only when
-                               used with 1G advertisment */
-                               if (params->speed_cap_mask &
-                                       (PORT_HW_CFG_SPEED_CAPABILITY_D0_1G |
-                                        PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G))
-                                       val |= (1<<5);
-                               DP(NETIF_MSG_LINK,
-                                        "807x autoneg val = 0x%x\n", val);
-                       }
+       bnx2x_cl45_write(bp, phy,
+                      MDIO_PMA_DEVAD,
+                      MDIO_PMA_REG_MISC_CTRL1, 0x0001);
 
-                       bnx2x_cl45_write(bp, params->port,
-                                      ext_phy_type,
-                                      ext_phy_addr,
-                                      MDIO_AN_DEVAD,
-                                      MDIO_AN_REG_ADV, val);
-                       if (ext_phy_type ==
-                           PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
-                               bnx2x_cl45_read(bp, params->port,
-                                             ext_phy_type,
-                                             ext_phy_addr,
-                                             MDIO_AN_DEVAD,
-                                             MDIO_AN_REG_8073_2_5G, &tmp1);
-
-                               if (((params->speed_cap_mask &
-                                     PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G) &&
-                                    (params->req_line_speed ==
-                                     SPEED_AUTO_NEG)) ||
-                                   (params->req_line_speed ==
-                                    SPEED_2500)) {
-                                       u16 phy_ver;
-                                       /* Allow 2.5G for A1 and above */
-                                       bnx2x_cl45_read(bp, params->port,
-                                        PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
-                                        ext_phy_addr,
-                                        MDIO_PMA_DEVAD,
-                                        MDIO_PMA_REG_8073_CHIP_REV, &phy_ver);
-                                       DP(NETIF_MSG_LINK, "Add 2.5G\n");
-                                       if (phy_ver > 0)
-                                               tmp1 |= 1;
-                                       else
-                                               tmp1 &= 0xfffe;
-                               } else {
-                                       DP(NETIF_MSG_LINK, "Disable 2.5G\n");
-                                       tmp1 &= 0xfffe;
-                               }
-
-                               bnx2x_cl45_write(bp, params->port,
-                                              ext_phy_type,
-                                              ext_phy_addr,
-                                              MDIO_AN_DEVAD,
-                                              MDIO_AN_REG_8073_2_5G, tmp1);
-                       }
+       bnx2x_cl45_write(bp, phy,
+                      MDIO_PMA_DEVAD,
+                      MDIO_PMA_REG_GEN_CTRL,
+                      MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
 
-                       /* Add support for CL37 (passive mode) II */
-
-                       bnx2x_cl45_read(bp, params->port,
-                                      ext_phy_type,
-                                      ext_phy_addr,
-                                      MDIO_AN_DEVAD,
-                                      MDIO_AN_REG_CL37_FC_LD,
-                                      &tmp1);
-
-                       bnx2x_cl45_write(bp, params->port,
-                                      ext_phy_type,
-                                      ext_phy_addr,
-                                      MDIO_AN_DEVAD,
-                                      MDIO_AN_REG_CL37_FC_LD, (tmp1 |
-                                      ((params->req_duplex == DUPLEX_FULL) ?
-                                      0x20 : 0x40)));
-
-                       /* Add support for CL37 (passive mode) III */
-                       bnx2x_cl45_write(bp, params->port,
-                                      ext_phy_type,
-                                      ext_phy_addr,
-                                      MDIO_AN_DEVAD,
-                                      MDIO_AN_REG_CL37_AN, 0x1000);
-
-                       if (ext_phy_type ==
-                           PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
-                               /* The SNR will improve about 2db by changing
-                               BW and FEE main tap. Rest commands are executed
-                               after link is up*/
-                               /*Change FFE main cursor to 5 in EDC register*/
-                               if (bnx2x_8073_is_snr_needed(params))
-                                       bnx2x_cl45_write(bp, params->port,
-                                                   ext_phy_type,
-                                                   ext_phy_addr,
-                                                   MDIO_PMA_DEVAD,
-                                                   MDIO_PMA_REG_EDC_FFE_MAIN,
-                                                   0xFB0C);
-
-                               /* Enable FEC (Forware Error Correction)
-                               Request in the AN */
-                               bnx2x_cl45_read(bp, params->port,
-                                             ext_phy_type,
-                                             ext_phy_addr,
-                                             MDIO_AN_DEVAD,
-                                             MDIO_AN_REG_ADV2, &tmp1);
-
-                               tmp1 |= (1<<15);
-
-                               bnx2x_cl45_write(bp, params->port,
-                                              ext_phy_type,
-                                              ext_phy_addr,
-                                              MDIO_AN_DEVAD,
-                                              MDIO_AN_REG_ADV2, tmp1);
+       /* wait for 150ms for microcode load */
+       msleep(150);
 
-                       }
+       /* Disable serial boot control, tristates pins SS_N, SCK, MOSI, MISO */
+       bnx2x_cl45_write(bp, phy,
+                      MDIO_PMA_DEVAD,
+                      MDIO_PMA_REG_MISC_CTRL1, 0x0000);
 
-                       bnx2x_ext_phy_set_pause(params, vars);
-
-                       /* Restart autoneg */
-                       msleep(500);
-                       bnx2x_cl45_write(bp, params->port,
-                                      ext_phy_type,
-                                      ext_phy_addr,
-                                      MDIO_AN_DEVAD,
-                                      MDIO_AN_REG_CTRL, 0x1200);
-                       DP(NETIF_MSG_LINK, "807x Autoneg Restart: "
-                          "Advertise 1G=%x, 10G=%x\n",
-                          ((val & (1<<5)) > 0),
-                          ((val & (1<<7)) > 0));
-                       break;
+       msleep(200);
+       bnx2x_save_bcm_spirom_ver(bp, phy, params->port);
+}
+
+static u8 bnx2x_8726_read_status(struct bnx2x_phy *phy,
+                                struct link_params *params,
+                                struct link_vars *vars)
+{
+       struct bnx2x *bp = params->bp;
+       u16 val1;
+       u8 link_up = bnx2x_8706_8726_read_status(phy, params, vars);
+       if (link_up) {
+               bnx2x_cl45_read(bp, phy,
+                               MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER,
+                               &val1);
+               if (val1 & (1<<15)) {
+                       DP(NETIF_MSG_LINK, "Tx is disabled\n");
+                       link_up = 0;
+                       vars->line_speed = 0;
                }
+       }
+       return link_up;
+}
 
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
-               {
-                       u16 tmp1;
-                       u16 rx_alarm_ctrl_val;
-                       u16 lasi_ctrl_val;
-
-                       /* Enable PMD link, MOD_ABS_FLT, and 1G link alarm */
-
-                       u16 mod_abs;
-                       rx_alarm_ctrl_val = (1<<2) | (1<<5) ;
-                       lasi_ctrl_val = 0x0004;
-
-                       DP(NETIF_MSG_LINK, "Initializing BCM8727\n");
-                       /* enable LASI */
-                       bnx2x_cl45_write(bp, params->port,
-                                      ext_phy_type,
-                                      ext_phy_addr,
-                                      MDIO_PMA_DEVAD,
-                                      MDIO_PMA_REG_RX_ALARM_CTRL,
-                                      rx_alarm_ctrl_val);
-
-                       bnx2x_cl45_write(bp, params->port,
-                                      ext_phy_type,
-                                      ext_phy_addr,
-                                      MDIO_PMA_DEVAD,
-                                      MDIO_PMA_REG_LASI_CTRL,
-                                      lasi_ctrl_val);
-
-                       /* Initially configure  MOD_ABS to interrupt when
-                       module is presence( bit 8) */
-                       bnx2x_cl45_read(bp, params->port,
-                                     ext_phy_type,
-                                     ext_phy_addr,
-                                     MDIO_PMA_DEVAD,
-                                     MDIO_PMA_REG_PHY_IDENTIFIER, &mod_abs);
-                       /* Set EDC off by setting OPTXLOS signal input to low
-                       (bit 9).
-                       When the EDC is off it locks onto a reference clock and
-                       avoids becoming 'lost'.*/
-                       mod_abs &= ~((1<<8) | (1<<9));
-                       bnx2x_cl45_write(bp, params->port,
-                                      ext_phy_type,
-                                      ext_phy_addr,
-                                      MDIO_PMA_DEVAD,
-                                      MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
-
-                       /* Make MOD_ABS give interrupt on change */
-                       bnx2x_cl45_read(bp, params->port,
-                                     ext_phy_type,
-                                     ext_phy_addr,
-                                     MDIO_PMA_DEVAD,
-                                     MDIO_PMA_REG_8727_PCS_OPT_CTRL,
-                                     &val);
-                       val |= (1<<12);
-                       bnx2x_cl45_write(bp, params->port,
-                                      ext_phy_type,
-                                      ext_phy_addr,
-                                      MDIO_PMA_DEVAD,
-                                      MDIO_PMA_REG_8727_PCS_OPT_CTRL,
-                                      val);
-
-                       /* Set 8727 GPIOs to input to allow reading from the
-                       8727 GPIO0 status which reflect SFP+ module
-                       over-current */
-
-                       bnx2x_cl45_read(bp, params->port,
-                                      PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
-                                      ext_phy_addr,
-                                      MDIO_PMA_DEVAD,
-                                      MDIO_PMA_REG_8727_PCS_OPT_CTRL,
-                                      &val);
-                       val &= 0xff8f; /* Reset bits 4-6 */
-                       bnx2x_cl45_write(bp, params->port,
-                                      PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
-                                      ext_phy_addr,
-                                      MDIO_PMA_DEVAD,
-                                      MDIO_PMA_REG_8727_PCS_OPT_CTRL,
-                                      val);
-
-                       bnx2x_8727_power_module(bp, params, ext_phy_addr, 1);
-                       bnx2x_bcm8073_set_xaui_low_power_mode(params);
-
-                       bnx2x_cl45_read(bp, params->port,
-                                     ext_phy_type,
-                                     ext_phy_addr,
-                                     MDIO_PMA_DEVAD,
-                                     MDIO_PMA_REG_M8051_MSGOUT_REG,
-                                     &tmp1);
-
-                       bnx2x_cl45_read(bp, params->port,
-                                     ext_phy_type,
-                                     ext_phy_addr,
-                                     MDIO_PMA_DEVAD,
-                                     MDIO_PMA_REG_RX_ALARM, &tmp1);
-
-                       /* Set option 1G speed */
-                       if (params->req_line_speed == SPEED_1000) {
-
-                               DP(NETIF_MSG_LINK, "Setting 1G force\n");
-                               bnx2x_cl45_write(bp, params->port,
-                                              ext_phy_type,
-                                              ext_phy_addr,
-                                              MDIO_PMA_DEVAD,
-                                              MDIO_PMA_REG_CTRL, 0x40);
-                               bnx2x_cl45_write(bp, params->port,
-                                              ext_phy_type,
-                                              ext_phy_addr,
-                                              MDIO_PMA_DEVAD,
-                                              MDIO_PMA_REG_10G_CTRL2, 0xD);
-                               bnx2x_cl45_read(bp, params->port,
-                                     ext_phy_type,
-                                     ext_phy_addr,
-                                     MDIO_PMA_DEVAD,
-                                     MDIO_PMA_REG_10G_CTRL2, &tmp1);
-                               DP(NETIF_MSG_LINK, "1.7 = 0x%x\n", tmp1);
-
-                       } else if ((params->req_line_speed ==
-                                   SPEED_AUTO_NEG) &&
-                                  ((params->speed_cap_mask &
-                                    PORT_HW_CFG_SPEED_CAPABILITY_D0_1G))) {
-
-                               DP(NETIF_MSG_LINK, "Setting 1G clause37\n");
-                               bnx2x_cl45_write(bp, params->port, ext_phy_type,
-                                              ext_phy_addr, MDIO_AN_DEVAD,
-                                              MDIO_PMA_REG_8727_MISC_CTRL, 0);
-                               bnx2x_cl45_write(bp, params->port, ext_phy_type,
-                                              ext_phy_addr, MDIO_AN_DEVAD,
-                                              MDIO_AN_REG_CL37_AN, 0x1300);
-                       } else {
-                               /* Since the 8727 has only single reset pin,
-                               need to set the 10G registers although it is
-                               default */
-                               bnx2x_cl45_write(bp, params->port, ext_phy_type,
-                                              ext_phy_addr, MDIO_AN_DEVAD,
-                                              MDIO_AN_REG_CTRL, 0x0020);
-                               bnx2x_cl45_write(bp, params->port, ext_phy_type,
-                                              ext_phy_addr, MDIO_AN_DEVAD,
-                                              0x7, 0x0100);
-                               bnx2x_cl45_write(bp, params->port, ext_phy_type,
-                                              ext_phy_addr, MDIO_PMA_DEVAD,
-                                              MDIO_PMA_REG_CTRL, 0x2040);
-                               bnx2x_cl45_write(bp, params->port, ext_phy_type,
-                                              ext_phy_addr, MDIO_PMA_DEVAD,
-                                              MDIO_PMA_REG_10G_CTRL2, 0x0008);
-                       }
 
-                       /* Set 2-wire transfer rate of SFP+ module EEPROM
-                        * to 100Khz since some DACs(direct attached cables) do
-                        * not work at 400Khz.
-                        */
-                       bnx2x_cl45_write(bp, params->port,
-                                      ext_phy_type,
-                                      ext_phy_addr,
-                                      MDIO_PMA_DEVAD,
-                                      MDIO_PMA_REG_8727_TWO_WIRE_SLAVE_ADDR,
-                                      0xa001);
-
-                       /* Set TX PreEmphasis if needed */
-                       if ((params->feature_config_flags &
-                            FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
-                               DP(NETIF_MSG_LINK, "Setting TX_CTRL1 0x%x,"
-                                        "TX_CTRL2 0x%x\n",
-                                        params->xgxs_config_tx[0],
-                                        params->xgxs_config_tx[1]);
-                               bnx2x_cl45_write(bp, params->port,
-                                              ext_phy_type,
-                                              ext_phy_addr,
-                                              MDIO_PMA_DEVAD,
-                                              MDIO_PMA_REG_8727_TX_CTRL1,
-                                              params->xgxs_config_tx[0]);
-
-                               bnx2x_cl45_write(bp, params->port,
-                                              ext_phy_type,
-                                              ext_phy_addr,
-                                              MDIO_PMA_DEVAD,
-                                              MDIO_PMA_REG_8727_TX_CTRL2,
-                                              params->xgxs_config_tx[1]);
-                       }
+static u8 bnx2x_8726_config_init(struct bnx2x_phy *phy,
+                                struct link_params *params,
+                                struct link_vars *vars)
+{
+       struct bnx2x *bp = params->bp;
+       u32 val;
+       u32 swap_val, swap_override, aeu_gpio_mask, offset;
+       DP(NETIF_MSG_LINK, "Initializing BCM8726\n");
+       /* Restore normal power mode*/
+       bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
+                           MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
 
-                       break;
-               }
+       bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
+                           MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
+
+       bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1<<15);
+       bnx2x_wait_reset_complete(bp, phy);
+
+       bnx2x_8726_external_rom_boot(phy, params);
+
+       /* Need to call module detected on initialization since
+       the module detection triggered by actual module
+       insertion might occur before driver is loaded, and when
+       driver is loaded, it reset all registers, including the
+       transmitter */
+       bnx2x_sfp_module_detection(phy, params);
+
+       if (phy->req_line_speed == SPEED_1000) {
+               DP(NETIF_MSG_LINK, "Setting 1G force\n");
+               bnx2x_cl45_write(bp, phy,
+                                MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x40);
+               bnx2x_cl45_write(bp, phy,
+                                MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, 0xD);
+               bnx2x_cl45_write(bp, phy,
+                                MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0x5);
+               bnx2x_cl45_write(bp, phy,
+                                MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
+                                0x400);
+       } else if ((phy->req_line_speed == SPEED_AUTO_NEG) &&
+                  (phy->speed_cap_mask &
+                     PORT_HW_CFG_SPEED_CAPABILITY_D0_1G) &&
+                  ((phy->speed_cap_mask &
+                     PORT_HW_CFG_SPEED_CAPABILITY_D0_10G) !=
+                   PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) {
+               DP(NETIF_MSG_LINK, "Setting 1G clause37\n");
+               /* Set Flow control */
+               bnx2x_ext_phy_set_pause(params, phy, vars);
+               bnx2x_cl45_write(bp, phy,
+                                MDIO_AN_DEVAD, MDIO_AN_REG_ADV, 0x20);
+               bnx2x_cl45_write(bp, phy,
+                                MDIO_AN_DEVAD, MDIO_AN_REG_CL37_CL73, 0x040c);
+               bnx2x_cl45_write(bp, phy,
+                                MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD, 0x0020);
+               bnx2x_cl45_write(bp, phy,
+                                MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1000);
+               bnx2x_cl45_write(bp, phy,
+                               MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x1200);
+               /* Enable RX-ALARM control to receive
+               interrupt for 1G speed change */
+               bnx2x_cl45_write(bp, phy,
+                                MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0x4);
+               bnx2x_cl45_write(bp, phy,
+                                MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
+                                0x400);
+
+       } else { /* Default 10G. Set only LASI control */
+               bnx2x_cl45_write(bp, phy,
+                                MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 1);
+       }
 
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
-               {
-                       u16 fw_ver1, fw_ver2;
-                       DP(NETIF_MSG_LINK,
-                               "Setting the SFX7101 LASI indication\n");
+       /* Set TX PreEmphasis if needed */
+       if ((params->feature_config_flags &
+            FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
+               DP(NETIF_MSG_LINK, "Setting TX_CTRL1 0x%x,"
+                        "TX_CTRL2 0x%x\n",
+                        phy->tx_preemphasis[0],
+                        phy->tx_preemphasis[1]);
+               bnx2x_cl45_write(bp, phy,
+                                MDIO_PMA_DEVAD,
+                                MDIO_PMA_REG_8726_TX_CTRL1,
+                                phy->tx_preemphasis[0]);
+
+               bnx2x_cl45_write(bp, phy,
+                                MDIO_PMA_DEVAD,
+                                MDIO_PMA_REG_8726_TX_CTRL2,
+                                phy->tx_preemphasis[1]);
+       }
 
-                       bnx2x_cl45_write(bp, params->port,
-                                      ext_phy_type,
-                                      ext_phy_addr,
-                                      MDIO_PMA_DEVAD,
-                                      MDIO_PMA_REG_LASI_CTRL, 0x1);
-                       DP(NETIF_MSG_LINK,
-                         "Setting the SFX7101 LED to blink on traffic\n");
-                       bnx2x_cl45_write(bp, params->port,
-                                      ext_phy_type,
-                                      ext_phy_addr,
-                                      MDIO_PMA_DEVAD,
-                                      MDIO_PMA_REG_7107_LED_CNTL, (1<<3));
-
-                       bnx2x_ext_phy_set_pause(params, vars);
-                       /* Restart autoneg */
-                       bnx2x_cl45_read(bp, params->port,
-                                     ext_phy_type,
-                                     ext_phy_addr,
-                                     MDIO_AN_DEVAD,
-                                     MDIO_AN_REG_CTRL, &val);
-                       val |= 0x200;
-                       bnx2x_cl45_write(bp, params->port,
-                                      ext_phy_type,
-                                      ext_phy_addr,
-                                      MDIO_AN_DEVAD,
-                                      MDIO_AN_REG_CTRL, val);
-
-                       /* Save spirom version */
-                       bnx2x_cl45_read(bp, params->port, ext_phy_type,
-                                     ext_phy_addr, MDIO_PMA_DEVAD,
-                                     MDIO_PMA_REG_7101_VER1, &fw_ver1);
-
-                       bnx2x_cl45_read(bp, params->port, ext_phy_type,
-                                     ext_phy_addr, MDIO_PMA_DEVAD,
-                                     MDIO_PMA_REG_7101_VER2, &fw_ver2);
-
-                       bnx2x_save_spirom_version(params->bp, params->port,
-                                               params->shmem_base,
-                                               (u32)(fw_ver1<<16 | fw_ver2));
-                       break;
-               }
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823:
-                       /* This phy uses the NIG latch mechanism since link
-                               indication arrives through its LED4 and not via
-                               its LASI signal, so we get steady signal
-                               instead of clear on read */
-                       bnx2x_bits_en(bp, NIG_REG_LATCH_BC_0 + params->port*4,
-                                   1 << NIG_LATCH_BC_ENABLE_MI_INT);
-
-                       bnx2x_cl45_write(bp, params->port,
-                                      PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
-                                      ext_phy_addr,
-                                      MDIO_PMA_DEVAD,
-                                      MDIO_PMA_REG_CTRL, 0x0000);
-
-                       bnx2x_8481_set_led4(params, ext_phy_type, ext_phy_addr);
-                       if (params->req_line_speed == SPEED_AUTO_NEG) {
-
-                               u16 autoneg_val, an_1000_val, an_10_100_val;
-                               /* set 1000 speed advertisement */
-                               bnx2x_cl45_read(bp, params->port,
-                                             ext_phy_type,
-                                             ext_phy_addr,
-                                             MDIO_AN_DEVAD,
-                                             MDIO_AN_REG_8481_1000T_CTRL,
-                                             &an_1000_val);
-
-                               if (params->speed_cap_mask &
-                                   PORT_HW_CFG_SPEED_CAPABILITY_D0_1G) {
-                                       an_1000_val |= (1<<8);
-                                       if (params->req_duplex == DUPLEX_FULL)
-                                               an_1000_val |= (1<<9);
-                                       DP(NETIF_MSG_LINK, "Advertising 1G\n");
-                               } else
-                                       an_1000_val &= ~((1<<8) | (1<<9));
-
-                               bnx2x_cl45_write(bp, params->port,
-                                              ext_phy_type,
-                                              ext_phy_addr,
-                                              MDIO_AN_DEVAD,
-                                              MDIO_AN_REG_8481_1000T_CTRL,
-                                              an_1000_val);
-
-                               /* set 100 speed advertisement */
-                               bnx2x_cl45_read(bp, params->port,
-                                             ext_phy_type,
-                                             ext_phy_addr,
-                                             MDIO_AN_DEVAD,
-                                             MDIO_AN_REG_8481_LEGACY_AN_ADV,
-                                             &an_10_100_val);
-
-                               if (params->speed_cap_mask &
-                                (PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_FULL |
-                                 PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_HALF)) {
-                                       an_10_100_val |= (1<<7);
-                                       if (params->req_duplex == DUPLEX_FULL)
-                                               an_10_100_val |= (1<<8);
-                                       DP(NETIF_MSG_LINK,
-                                               "Advertising 100M\n");
-                               } else
-                                       an_10_100_val &= ~((1<<7) | (1<<8));
-
-                               /* set 10 speed advertisement */
-                               if (params->speed_cap_mask &
-                                 (PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL |
-                                  PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_HALF)) {
-                                       an_10_100_val |= (1<<5);
-                                       if (params->req_duplex == DUPLEX_FULL)
-                                               an_10_100_val |= (1<<6);
-                                       DP(NETIF_MSG_LINK, "Advertising 10M\n");
-                                    }
-                               else
-                                       an_10_100_val &= ~((1<<5) | (1<<6));
-
-                               bnx2x_cl45_write(bp, params->port,
-                                              ext_phy_type,
-                                              ext_phy_addr,
-                                              MDIO_AN_DEVAD,
-                                              MDIO_AN_REG_8481_LEGACY_AN_ADV,
-                                              an_10_100_val);
-
-                               bnx2x_cl45_read(bp, params->port,
-                                             ext_phy_type,
-                                             ext_phy_addr,
-                                             MDIO_AN_DEVAD,
-                                             MDIO_AN_REG_8481_LEGACY_MII_CTRL,
-                                             &autoneg_val);
-
-                               /* Disable forced speed */
-                               autoneg_val &= ~(1<<6|1<<13);
-
-                               /* Enable autoneg and restart autoneg
-                               for legacy speeds */
-                               autoneg_val |= (1<<9|1<<12);
-
-                               if (params->req_duplex == DUPLEX_FULL)
-                                       autoneg_val |= (1<<8);
-                               else
-                                       autoneg_val &= ~(1<<8);
-
-                               bnx2x_cl45_write(bp, params->port,
-                                              ext_phy_type,
-                                              ext_phy_addr,
-                                              MDIO_AN_DEVAD,
-                                              MDIO_AN_REG_8481_LEGACY_MII_CTRL,
-                                              autoneg_val);
-
-                               if (params->speed_cap_mask &
-                                   PORT_HW_CFG_SPEED_CAPABILITY_D0_10G) {
-                                       DP(NETIF_MSG_LINK, "Advertising 10G\n");
-                                       /* Restart autoneg for 10G*/
-
-                       bnx2x_cl45_write(bp, params->port,
-                                      ext_phy_type,
-                                      ext_phy_addr,
-                                      MDIO_AN_DEVAD,
-                                      MDIO_AN_REG_CTRL, 0x3200);
-                               }
-                       } else {
-                               /* Force speed */
-                               u16 autoneg_ctrl, pma_ctrl;
-                               bnx2x_cl45_read(bp, params->port,
-                                             ext_phy_type,
-                                             ext_phy_addr,
-                                             MDIO_AN_DEVAD,
-                                             MDIO_AN_REG_8481_LEGACY_MII_CTRL,
-                                             &autoneg_ctrl);
-
-                               /* Disable autoneg */
-                               autoneg_ctrl &= ~(1<<12);
-
-                               /* Set 1000 force */
-                               switch (params->req_line_speed) {
-                               case SPEED_10000:
-                                       DP(NETIF_MSG_LINK,
-                                               "Unable to set 10G force !\n");
-                                       break;
-                               case SPEED_1000:
-                                       bnx2x_cl45_read(bp, params->port,
-                                                     ext_phy_type,
-                                                     ext_phy_addr,
-                                                     MDIO_PMA_DEVAD,
-                                                     MDIO_PMA_REG_CTRL,
-                                                     &pma_ctrl);
-                                       autoneg_ctrl &= ~(1<<13);
-                                       autoneg_ctrl |= (1<<6);
-                                       pma_ctrl &= ~(1<<13);
-                                       pma_ctrl |= (1<<6);
-                                       DP(NETIF_MSG_LINK,
-                                               "Setting 1000M force\n");
-                                       bnx2x_cl45_write(bp, params->port,
-                                                      ext_phy_type,
-                                                      ext_phy_addr,
-                                                      MDIO_PMA_DEVAD,
-                                                      MDIO_PMA_REG_CTRL,
-                                                      pma_ctrl);
-                                       break;
-                               case SPEED_100:
-                                       autoneg_ctrl |= (1<<13);
-                                       autoneg_ctrl &= ~(1<<6);
-                                       DP(NETIF_MSG_LINK,
-                                               "Setting 100M force\n");
-                                       break;
-                               case SPEED_10:
-                                       autoneg_ctrl &= ~(1<<13);
-                                       autoneg_ctrl &= ~(1<<6);
-                                       DP(NETIF_MSG_LINK,
-                                               "Setting 10M force\n");
-                                       break;
-                               }
+       /* Set GPIO3 to trigger SFP+ module insertion/removal */
+       bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3,
+                           MISC_REGISTERS_GPIO_INPUT_HI_Z, params->port);
 
-                               /* Duplex mode */
-                               if (params->req_duplex == DUPLEX_FULL) {
-                                       autoneg_ctrl |= (1<<8);
-                                       DP(NETIF_MSG_LINK,
-                                               "Setting full duplex\n");
-                               } else
-                                       autoneg_ctrl &= ~(1<<8);
-
-                               /* Update autoneg ctrl and pma ctrl */
-                               bnx2x_cl45_write(bp, params->port,
-                                              ext_phy_type,
-                                              ext_phy_addr,
-                                              MDIO_AN_DEVAD,
-                                              MDIO_AN_REG_8481_LEGACY_MII_CTRL,
-                                              autoneg_ctrl);
-                       }
+       /* The GPIO should be swapped if the swap register is set and active */
+       swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
+       swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
 
-                       /* Save spirom version */
-                       bnx2x_save_8481_spirom_version(bp, params->port,
-                                                    ext_phy_addr,
-                                                    params->shmem_base);
-                       break;
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
-                       DP(NETIF_MSG_LINK,
-                                "XGXS PHY Failure detected 0x%x\n",
-                                params->ext_phy_config);
-                       rc = -EINVAL;
-                       break;
-               default:
-                       DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n",
-                                 params->ext_phy_config);
-                       rc = -EINVAL;
-                       break;
-               }
+       /* Select function upon port-swap configuration */
+       if (params->port == 0) {
+               offset = MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0;
+               aeu_gpio_mask = (swap_val && swap_override) ?
+                       AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_1 :
+                       AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_0;
+       } else {
+               offset = MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0;
+               aeu_gpio_mask = (swap_val && swap_override) ?
+                       AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_0 :
+                       AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_1;
+       }
+       val = REG_RD(bp, offset);
+       /* add GPIO3 to group */
+       val |= aeu_gpio_mask;
+       REG_WR(bp, offset, val);
+       return 0;
 
-       } else { /* SerDes */
+}
 
-               ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
-               switch (ext_phy_type) {
-               case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT:
-                       DP(NETIF_MSG_LINK, "SerDes Direct\n");
-                       break;
+static void bnx2x_8726_link_reset(struct bnx2x_phy *phy,
+                                 struct link_params *params)
+{
+       struct bnx2x *bp = params->bp;
+       DP(NETIF_MSG_LINK, "bnx2x_8726_link_reset port %d\n", params->port);
+       /* Set serial boot control for external load */
+       bnx2x_cl45_write(bp, phy,
+                        MDIO_PMA_DEVAD,
+                        MDIO_PMA_REG_GEN_CTRL, 0x0001);
+}
 
-               case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482:
-                       DP(NETIF_MSG_LINK, "SerDes 5482\n");
-                       break;
+/******************************************************************/
+/*                     BCM8727 PHY SECTION                       */
+/******************************************************************/
 
-               default:
-                       DP(NETIF_MSG_LINK, "BAD SerDes ext_phy_config 0x%x\n",
-                          params->ext_phy_config);
-                       break;
+static void bnx2x_8727_set_link_led(struct bnx2x_phy *phy,
+                                   struct link_params *params, u8 mode)
+{
+       struct bnx2x *bp = params->bp;
+       u16 led_mode_bitmask = 0;
+       u16 gpio_pins_bitmask = 0;
+       u16 val;
+       /* Only NOC flavor requires to set the LED specifically */
+       if (!(phy->flags & FLAGS_NOC))
+               return;
+       switch (mode) {
+       case LED_MODE_FRONT_PANEL_OFF:
+       case LED_MODE_OFF:
+               led_mode_bitmask = 0;
+               gpio_pins_bitmask = 0x03;
+               break;
+       case LED_MODE_ON:
+               led_mode_bitmask = 0;
+               gpio_pins_bitmask = 0x02;
+               break;
+       case LED_MODE_OPER:
+               led_mode_bitmask = 0x60;
+               gpio_pins_bitmask = 0x11;
+               break;
+       }
+       bnx2x_cl45_read(bp, phy,
+                       MDIO_PMA_DEVAD,
+                       MDIO_PMA_REG_8727_PCS_OPT_CTRL,
+                       &val);
+       val &= 0xff8f;
+       val |= led_mode_bitmask;
+       bnx2x_cl45_write(bp, phy,
+                        MDIO_PMA_DEVAD,
+                        MDIO_PMA_REG_8727_PCS_OPT_CTRL,
+                        val);
+       bnx2x_cl45_read(bp, phy,
+                       MDIO_PMA_DEVAD,
+                       MDIO_PMA_REG_8727_GPIO_CTRL,
+                       &val);
+       val &= 0xffe0;
+       val |= gpio_pins_bitmask;
+       bnx2x_cl45_write(bp, phy,
+                        MDIO_PMA_DEVAD,
+                        MDIO_PMA_REG_8727_GPIO_CTRL,
+                        val);
+}
+static void bnx2x_8727_hw_reset(struct bnx2x_phy *phy,
+                               struct link_params *params) {
+       u32 swap_val, swap_override;
+       u8 port;
+       /**
+        * The PHY reset is controlled by GPIO 1. Fake the port number
+        * to cancel the swap done in set_gpio()
+        */
+       struct bnx2x *bp = params->bp;
+       swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
+       swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
+       port = (swap_val && swap_override) ^ 1;
+       bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
+                           MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
+}
+
+static u8 bnx2x_8727_config_init(struct bnx2x_phy *phy,
+                                struct link_params *params,
+                                struct link_vars *vars)
+{
+       u16 tmp1, val, mod_abs;
+       u16 rx_alarm_ctrl_val;
+       u16 lasi_ctrl_val;
+       struct bnx2x *bp = params->bp;
+       /* Enable PMD link, MOD_ABS_FLT, and 1G link alarm */
+
+       bnx2x_wait_reset_complete(bp, phy);
+       rx_alarm_ctrl_val = (1<<2) | (1<<5) ;
+       lasi_ctrl_val = 0x0004;
+
+       DP(NETIF_MSG_LINK, "Initializing BCM8727\n");
+       /* enable LASI */
+       bnx2x_cl45_write(bp, phy,
+                        MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
+                        rx_alarm_ctrl_val);
+
+       bnx2x_cl45_write(bp, phy,
+                        MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, lasi_ctrl_val);
+
+       /* Initially configure  MOD_ABS to interrupt when
+       module is presence( bit 8) */
+       bnx2x_cl45_read(bp, phy,
+                       MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, &mod_abs);
+       /* Set EDC off by setting OPTXLOS signal input to low
+       (bit 9).
+       When the EDC is off it locks onto a reference clock and
+       avoids becoming 'lost'.*/
+       mod_abs &= ~(1<<8);
+       if (!(phy->flags & FLAGS_NOC))
+               mod_abs &= ~(1<<9);
+       bnx2x_cl45_write(bp, phy,
+                        MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
+
+
+       /* Make MOD_ABS give interrupt on change */
+       bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_PCS_OPT_CTRL,
+                       &val);
+       val |= (1<<12);
+       if (phy->flags & FLAGS_NOC)
+               val |= (3<<5);
+
+       /**
+        * Set 8727 GPIOs to input to allow reading from the 8727 GPIO0
+        * status which reflect SFP+ module over-current
+        */
+       if (!(phy->flags & FLAGS_NOC))
+               val &= 0xff8f; /* Reset bits 4-6 */
+       bnx2x_cl45_write(bp, phy,
+                        MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_PCS_OPT_CTRL, val);
+
+       bnx2x_8727_power_module(bp, phy, 1);
+
+       bnx2x_cl45_read(bp, phy,
+                       MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &tmp1);
+
+       bnx2x_cl45_read(bp, phy,
+                       MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM, &tmp1);
+
+       /* Set option 1G speed */
+       if (phy->req_line_speed == SPEED_1000) {
+               DP(NETIF_MSG_LINK, "Setting 1G force\n");
+               bnx2x_cl45_write(bp, phy,
+                                MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x40);
+               bnx2x_cl45_write(bp, phy,
+                                MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, 0xD);
+               bnx2x_cl45_read(bp, phy,
+                               MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, &tmp1);
+               DP(NETIF_MSG_LINK, "1.7 = 0x%x\n", tmp1);
+               /**
+                * Power down the XAUI until link is up in case of dual-media
+                * and 1G
+                */
+               if (DUAL_MEDIA(params)) {
+                       bnx2x_cl45_read(bp, phy,
+                                       MDIO_PMA_DEVAD,
+                                       MDIO_PMA_REG_8727_PCS_GP, &val);
+                       val |= (3<<10);
+                       bnx2x_cl45_write(bp, phy,
+                                        MDIO_PMA_DEVAD,
+                                        MDIO_PMA_REG_8727_PCS_GP, val);
                }
+       } else if ((phy->req_line_speed == SPEED_AUTO_NEG) &&
+                  ((phy->speed_cap_mask &
+                    PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) &&
+                  ((phy->speed_cap_mask &
+                     PORT_HW_CFG_SPEED_CAPABILITY_D0_10G) !=
+                  PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) {
+
+               DP(NETIF_MSG_LINK, "Setting 1G clause37\n");
+               bnx2x_cl45_write(bp, phy,
+                                MDIO_AN_DEVAD, MDIO_AN_REG_8727_MISC_CTRL, 0);
+               bnx2x_cl45_write(bp, phy,
+                                MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1300);
+       } else {
+               /**
+                * Since the 8727 has only single reset pin, need to set the 10G
+                * registers although it is default
+                */
+               bnx2x_cl45_write(bp, phy,
+                                MDIO_AN_DEVAD, MDIO_AN_REG_8727_MISC_CTRL,
+                                0x0020);
+               bnx2x_cl45_write(bp, phy,
+                                MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x0100);
+               bnx2x_cl45_write(bp, phy,
+                                MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x2040);
+               bnx2x_cl45_write(bp, phy,
+                                MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2,
+                                0x0008);
        }
-       return rc;
+
+       /* Set 2-wire transfer rate of SFP+ module EEPROM
+        * to 100Khz since some DACs(direct attached cables) do
+        * not work at 400Khz.
+        */
+       bnx2x_cl45_write(bp, phy,
+                        MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_TWO_WIRE_SLAVE_ADDR,
+                        0xa001);
+
+       /* Set TX PreEmphasis if needed */
+       if ((params->feature_config_flags &
+            FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
+               DP(NETIF_MSG_LINK, "Setting TX_CTRL1 0x%x, TX_CTRL2 0x%x\n",
+                          phy->tx_preemphasis[0],
+                          phy->tx_preemphasis[1]);
+               bnx2x_cl45_write(bp, phy,
+                                MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_TX_CTRL1,
+                                phy->tx_preemphasis[0]);
+
+               bnx2x_cl45_write(bp, phy,
+                                MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_TX_CTRL2,
+                                phy->tx_preemphasis[1]);
+       }
+
+       return 0;
 }
 
-static void bnx2x_8727_handle_mod_abs(struct link_params *params)
+static void bnx2x_8727_handle_mod_abs(struct bnx2x_phy *phy,
+                                     struct link_params *params)
 {
        struct bnx2x *bp = params->bp;
        u16 mod_abs, rx_alarm_status;
-       u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
        u32 val = REG_RD(bp, params->shmem_base +
                             offsetof(struct shmem_region, dev_info.
                                      port_feature_config[params->port].
                                      config));
-       bnx2x_cl45_read(bp, params->port,
-                     PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
-                     ext_phy_addr,
+       bnx2x_cl45_read(bp, phy,
                      MDIO_PMA_DEVAD,
                      MDIO_PMA_REG_PHY_IDENTIFIER, &mod_abs);
        if (mod_abs & (1<<8)) {
@@ -4602,18 +4935,16 @@ static void bnx2x_8727_handle_mod_abs(struct link_params *params)
                        (bit 9).
                        When the EDC is off it locks onto a reference clock and
                        avoids becoming 'lost'.*/
-               mod_abs &= ~((1<<8)|(1<<9));
-               bnx2x_cl45_write(bp, params->port,
-                              PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
-                              ext_phy_addr,
+               mod_abs &= ~(1<<8);
+               if (!(phy->flags & FLAGS_NOC))
+                       mod_abs &= ~(1<<9);
+               bnx2x_cl45_write(bp, phy,
                               MDIO_PMA_DEVAD,
                               MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
 
                /* Clear RX alarm since it stays up as long as
                the mod_abs wasn't changed */
-               bnx2x_cl45_read(bp, params->port,
-                             PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
-                             ext_phy_addr,
+               bnx2x_cl45_read(bp, phy,
                              MDIO_PMA_DEVAD,
                              MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
 
@@ -4630,33 +4961,28 @@ static void bnx2x_8727_handle_mod_abs(struct link_params *params)
                   2. Restore the default polarity of the OPRXLOS signal and
                this signal will then correctly indicate the presence or
                absence of the Rx signal. (bit 9) */
-               mod_abs |= ((1<<8)|(1<<9));
-               bnx2x_cl45_write(bp, params->port,
-                      PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
-                      ext_phy_addr,
-                      MDIO_PMA_DEVAD,
-                      MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
+               mod_abs |= (1<<8);
+               if (!(phy->flags & FLAGS_NOC))
+                       mod_abs |= (1<<9);
+               bnx2x_cl45_write(bp, phy,
+                                MDIO_PMA_DEVAD,
+                                MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
 
                /* Clear RX alarm since it stays up as long as
                the mod_abs wasn't changed. This is need to be done
                before calling the module detection, otherwise it will clear
                the link update alarm */
-               bnx2x_cl45_read(bp, params->port,
-                             PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
-                             ext_phy_addr,
-                             MDIO_PMA_DEVAD,
-                             MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
+               bnx2x_cl45_read(bp, phy,
+                               MDIO_PMA_DEVAD,
+                               MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
 
 
                if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
                    PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
-                       bnx2x_sfp_set_transmitter(bp, params->port,
-                                       PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
-                                       ext_phy_addr, 0);
+                       bnx2x_sfp_set_transmitter(bp, phy, params->port, 0);
 
-               if (bnx2x_wait_for_sfp_module_initialized(params)
-                   == 0)
-                       bnx2x_sfp_module_detection(params);
+               if (bnx2x_wait_for_sfp_module_initialized(phy, params) == 0)
+                       bnx2x_sfp_module_detection(phy, params);
                else
                        DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n");
        }
@@ -4667,1298 +4993,1711 @@ static void bnx2x_8727_handle_mod_abs(struct link_params *params)
        module plugged in/out */
 }
 
+static u8 bnx2x_8727_read_status(struct bnx2x_phy *phy,
+                                struct link_params *params,
+                                struct link_vars *vars)
 
-static u8 bnx2x_ext_phy_is_link_up(struct link_params *params,
-                                struct link_vars *vars,
-                                u8 is_mi_int)
 {
        struct bnx2x *bp = params->bp;
-       u32 ext_phy_type;
-       u8 ext_phy_addr;
-       u16 val1 = 0, val2;
-       u16 rx_sd, pcs_status;
-       u8 ext_phy_link_up = 0;
-       u8 port = params->port;
-
-       if (vars->phy_flags & PHY_XGXS_FLAG) {
-               ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
-               ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
-               switch (ext_phy_type) {
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
-                       DP(NETIF_MSG_LINK, "XGXS Direct\n");
-                       ext_phy_link_up = 1;
-                       break;
+       u8 link_up = 0;
+       u16 link_status = 0;
+       u16 rx_alarm_status, lasi_ctrl, val1;
+
+       /* If PHY is not initialized, do not check link status */
+       bnx2x_cl45_read(bp, phy,
+                       MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL,
+                       &lasi_ctrl);
+       if (!lasi_ctrl)
+               return 0;
 
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
-                       DP(NETIF_MSG_LINK, "XGXS 8705\n");
-                       bnx2x_cl45_read(bp, params->port, ext_phy_type,
-                                     ext_phy_addr,
-                                     MDIO_WIS_DEVAD,
-                                     MDIO_WIS_REG_LASI_STATUS, &val1);
-                       DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1);
-
-                       bnx2x_cl45_read(bp, params->port, ext_phy_type,
-                                     ext_phy_addr,
-                                     MDIO_WIS_DEVAD,
-                                     MDIO_WIS_REG_LASI_STATUS, &val1);
-                       DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1);
-
-                       bnx2x_cl45_read(bp, params->port, ext_phy_type,
-                                     ext_phy_addr,
-                                     MDIO_PMA_DEVAD,
-                                     MDIO_PMA_REG_RX_SD, &rx_sd);
-
-                       bnx2x_cl45_read(bp, params->port, ext_phy_type,
-                                     ext_phy_addr,
-                                     1,
-                                     0xc809, &val1);
-                       bnx2x_cl45_read(bp, params->port, ext_phy_type,
-                                     ext_phy_addr,
-                                     1,
-                                     0xc809, &val1);
-
-                       DP(NETIF_MSG_LINK, "8705 1.c809 val=0x%x\n", val1);
-                       ext_phy_link_up = ((rx_sd & 0x1) && (val1 & (1<<9)) &&
-                                          ((val1 & (1<<8)) == 0));
-                       if (ext_phy_link_up)
-                               vars->line_speed = SPEED_10000;
-                       break;
+       /* Check the LASI */
+       bnx2x_cl45_read(bp, phy,
+                       MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM,
+                       &rx_alarm_status);
+       vars->line_speed = 0;
+       DP(NETIF_MSG_LINK, "8727 RX_ALARM_STATUS  0x%x\n", rx_alarm_status);
 
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
-                       DP(NETIF_MSG_LINK, "XGXS 8706/8726\n");
-                       /* Clear RX Alarm*/
-                       bnx2x_cl45_read(bp, params->port, ext_phy_type,
-                                     ext_phy_addr,
-                                     MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM,
-                                     &val2);
-                       /* clear LASI indication*/
-                       bnx2x_cl45_read(bp, params->port, ext_phy_type,
-                                     ext_phy_addr,
-                                     MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS,
-                                     &val1);
-                       bnx2x_cl45_read(bp, params->port, ext_phy_type,
-                                     ext_phy_addr,
-                                     MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS,
-                                     &val2);
-                       DP(NETIF_MSG_LINK, "8706/8726 LASI status 0x%x-->"
-                                    "0x%x\n", val1, val2);
-
-                       bnx2x_cl45_read(bp, params->port, ext_phy_type,
-                                     ext_phy_addr,
-                                     MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_SD,
-                                     &rx_sd);
-                       bnx2x_cl45_read(bp, params->port, ext_phy_type,
-                                     ext_phy_addr,
-                                     MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS,
-                                     &pcs_status);
-                       bnx2x_cl45_read(bp, params->port, ext_phy_type,
-                                     ext_phy_addr,
-                                     MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS,
-                                     &val2);
-                       bnx2x_cl45_read(bp, params->port, ext_phy_type,
-                                     ext_phy_addr,
-                                     MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS,
-                                     &val2);
-
-                       DP(NETIF_MSG_LINK, "8706/8726 rx_sd 0x%x"
-                          "  pcs_status 0x%x 1Gbps link_status 0x%x\n",
-                          rx_sd, pcs_status, val2);
-                       /* link is up if both bit 0 of pmd_rx_sd and
-                        * bit 0 of pcs_status are set, or if the autoneg bit
-                          1 is set
-                        */
-                       ext_phy_link_up = ((rx_sd & pcs_status & 0x1) ||
-                                          (val2 & (1<<1)));
-                       if (ext_phy_link_up) {
-                               if (ext_phy_type ==
-                                    PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) {
-                                       /* If transmitter is disabled,
-                                       ignore false link up indication */
-                                       bnx2x_cl45_read(bp, params->port,
-                                                  ext_phy_type,
-                                                  ext_phy_addr,
-                                                  MDIO_PMA_DEVAD,
-                                                  MDIO_PMA_REG_PHY_IDENTIFIER,
-                                                  &val1);
-                                       if (val1 & (1<<15)) {
-                                               DP(NETIF_MSG_LINK, "Tx is "
-                                                           "disabled\n");
-                                               ext_phy_link_up = 0;
-                                               break;
-                                       }
-                               }
-                               if (val2 & (1<<1))
-                                       vars->line_speed = SPEED_1000;
-                               else
-                                       vars->line_speed = SPEED_10000;
-                       }
-                       break;
+       bnx2x_cl45_read(bp, phy,
+                       MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val1);
 
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
-               {
-                       u16 link_status = 0;
-                       u16 rx_alarm_status;
-                       /* Check the LASI */
-                       bnx2x_cl45_read(bp, params->port,
-                                     ext_phy_type,
-                                     ext_phy_addr,
-                                     MDIO_PMA_DEVAD,
-                                     MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
-
-                       DP(NETIF_MSG_LINK, "8727 RX_ALARM_STATUS 0x%x\n",
-                                rx_alarm_status);
-
-                       bnx2x_cl45_read(bp, params->port,
-                                     ext_phy_type,
-                                     ext_phy_addr,
-                                     MDIO_PMA_DEVAD,
-                                     MDIO_PMA_REG_LASI_STATUS, &val1);
+       DP(NETIF_MSG_LINK, "8727 LASI status 0x%x\n", val1);
 
-                       DP(NETIF_MSG_LINK,
-                                "8727 LASI status 0x%x\n",
-                                val1);
+       /* Clear MSG-OUT */
+       bnx2x_cl45_read(bp, phy,
+                       MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &val1);
 
-                       /* Clear MSG-OUT */
-                       bnx2x_cl45_read(bp, params->port,
-                                     ext_phy_type,
-                                     ext_phy_addr,
-                                     MDIO_PMA_DEVAD,
-                                     MDIO_PMA_REG_M8051_MSGOUT_REG,
-                                     &val1);
+       /**
+        * If a module is present and there is need to check
+        * for over current
+        */
+       if (!(phy->flags & FLAGS_NOC) && !(rx_alarm_status & (1<<5))) {
+               /* Check over-current using 8727 GPIO0 input*/
+               bnx2x_cl45_read(bp, phy,
+                               MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_GPIO_CTRL,
+                               &val1);
+
+               if ((val1 & (1<<8)) == 0) {
+                       DP(NETIF_MSG_LINK, "8727 Power fault has been detected"
+                                      " on port %d\n", params->port);
+                       netdev_err(bp->dev, "Error:  Power fault on Port %d has"
+                                           " been detected and the power to "
+                                           "that SFP+ module has been removed"
+                                           " to prevent failure of the card."
+                                           " Please remove the SFP+ module and"
+                                           " restart the system to clear this"
+                                           " error.\n",
+                                  params->port);
 
                        /*
-                        * If a module is present and there is need to check
-                        * for over current
+                        * Disable all RX_ALARMs except for
+                        * mod_abs
                         */
-                       if (!(params->feature_config_flags &
-                             FEATURE_CONFIG_BCM8727_NOC) &&
-                           !(rx_alarm_status & (1<<5))) {
-                               /* Check over-current using 8727 GPIO0 input*/
-                               bnx2x_cl45_read(bp, params->port,
-                                             ext_phy_type,
-                                             ext_phy_addr,
-                                             MDIO_PMA_DEVAD,
-                                             MDIO_PMA_REG_8727_GPIO_CTRL,
-                                             &val1);
-
-                               if ((val1 & (1<<8)) == 0) {
-                                       DP(NETIF_MSG_LINK, "8727 Power fault"
-                                                    " has been detected on "
-                                                    "port %d\n",
-                                                params->port);
-                                       netdev_err(bp->dev, "Error:  Power fault on Port %d has been detected and the power to that SFP+ module has been removed to prevent failure of the card. Please remove the SFP+ module and restart the system to clear this error.\n",
-                                                  params->port);
-                                       /*
-                                        * Disable all RX_ALARMs except for
-                                        * mod_abs
-                                        */
-                                       bnx2x_cl45_write(bp, params->port,
-                                                    ext_phy_type,
-                                                    ext_phy_addr,
-                                                    MDIO_PMA_DEVAD,
-                                                    MDIO_PMA_REG_RX_ALARM_CTRL,
-                                                    (1<<5));
-
-                                       bnx2x_cl45_read(bp, params->port,
-                                                   ext_phy_type,
-                                                   ext_phy_addr,
-                                                   MDIO_PMA_DEVAD,
-                                                   MDIO_PMA_REG_PHY_IDENTIFIER,
-                                                   &val1);
-                                       /* Wait for module_absent_event */
-                                       val1 |= (1<<8);
-                                       bnx2x_cl45_write(bp, params->port,
-                                                   ext_phy_type,
-                                                   ext_phy_addr,
-                                                   MDIO_PMA_DEVAD,
-                                                   MDIO_PMA_REG_PHY_IDENTIFIER,
-                                                   val1);
-                                       /* Clear RX alarm */
-                                       bnx2x_cl45_read(bp, params->port,
-                                                     ext_phy_type,
-                                                     ext_phy_addr,
-                                                     MDIO_PMA_DEVAD,
-                                                     MDIO_PMA_REG_RX_ALARM,
-                                                     &rx_alarm_status);
-                                       break;
-                               }
-                       } /* Over current check */
-
-                       /* When module absent bit is set, check module */
-                       if (rx_alarm_status & (1<<5)) {
-                               bnx2x_8727_handle_mod_abs(params);
-                               /* Enable all mod_abs and link detection bits */
-                               bnx2x_cl45_write(bp, params->port,
-                                              ext_phy_type,
-                                              ext_phy_addr,
-                                              MDIO_PMA_DEVAD,
-                                              MDIO_PMA_REG_RX_ALARM_CTRL,
-                                              ((1<<5) | (1<<2)));
-                       }
-
-                       /* If transmitter is disabled,
-                       ignore false link up indication */
-                       bnx2x_cl45_read(bp, params->port,
-                                     ext_phy_type,
-                                     ext_phy_addr,
-                                     MDIO_PMA_DEVAD,
-                                     MDIO_PMA_REG_PHY_IDENTIFIER,
-                                     &val1);
-                       if (val1 & (1<<15)) {
-                               DP(NETIF_MSG_LINK, "Tx is disabled\n");
-                               ext_phy_link_up = 0;
-                               break;
-                       }
+                       bnx2x_cl45_write(bp, phy,
+                                        MDIO_PMA_DEVAD,
+                                        MDIO_PMA_REG_RX_ALARM_CTRL, (1<<5));
 
-                       bnx2x_cl45_read(bp, params->port,
-                                     ext_phy_type,
-                                     ext_phy_addr,
-                                     MDIO_PMA_DEVAD,
-                                     MDIO_PMA_REG_8073_SPEED_LINK_STATUS,
-                                     &link_status);
-
-                       /* Bits 0..2 --> speed detected,
-                          bits 13..15--> link is down */
-                       if ((link_status & (1<<2)) &&
-                           (!(link_status & (1<<15)))) {
-                               ext_phy_link_up = 1;
-                               vars->line_speed = SPEED_10000;
-                       } else if ((link_status & (1<<0)) &&
-                                  (!(link_status & (1<<13)))) {
-                               ext_phy_link_up = 1;
-                               vars->line_speed = SPEED_1000;
-                               DP(NETIF_MSG_LINK,
-                                        "port %x: External link"
-                                        " up in 1G\n", params->port);
-                       } else {
-                               ext_phy_link_up = 0;
-                               DP(NETIF_MSG_LINK,
-                                        "port %x: External link"
-                                        " is down\n", params->port);
-                       }
-                       break;
+                       bnx2x_cl45_read(bp, phy,
+                                       MDIO_PMA_DEVAD,
+                                       MDIO_PMA_REG_PHY_IDENTIFIER, &val1);
+                       /* Wait for module_absent_event */
+                       val1 |= (1<<8);
+                       bnx2x_cl45_write(bp, phy,
+                                        MDIO_PMA_DEVAD,
+                                        MDIO_PMA_REG_PHY_IDENTIFIER, val1);
+                       /* Clear RX alarm */
+                       bnx2x_cl45_read(bp, phy,
+                               MDIO_PMA_DEVAD,
+                               MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
+                       return 0;
                }
+       } /* Over current check */
+
+       /* When module absent bit is set, check module */
+       if (rx_alarm_status & (1<<5)) {
+               bnx2x_8727_handle_mod_abs(phy, params);
+               /* Enable all mod_abs and link detection bits */
+               bnx2x_cl45_write(bp, phy,
+                                MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
+                                ((1<<5) | (1<<2)));
+       }
+       DP(NETIF_MSG_LINK, "Enabling 8727 TX laser if SFP is approved\n");
+       bnx2x_8727_specific_func(phy, params, ENABLE_TX);
+       /* If transmitter is disabled, ignore false link up indication */
+       bnx2x_cl45_read(bp, phy,
+                       MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, &val1);
+       if (val1 & (1<<15)) {
+               DP(NETIF_MSG_LINK, "Tx is disabled\n");
+               return 0;
+       }
 
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
-               {
-                       u16 link_status = 0;
-                       u16 an1000_status = 0;
-
-                       if (ext_phy_type ==
-                            PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072) {
-                               bnx2x_cl45_read(bp, params->port,
-                                     ext_phy_type,
-                                     ext_phy_addr,
-                                     MDIO_PCS_DEVAD,
-                                     MDIO_PCS_REG_LASI_STATUS, &val1);
-                       bnx2x_cl45_read(bp, params->port,
-                                     ext_phy_type,
-                                     ext_phy_addr,
-                                     MDIO_PCS_DEVAD,
-                                     MDIO_PCS_REG_LASI_STATUS, &val2);
-                       DP(NETIF_MSG_LINK,
-                                "870x LASI status 0x%x->0x%x\n",
-                                 val1, val2);
-                       } else {
-                               /* In 8073, port1 is directed through emac0 and
-                                * port0 is directed through emac1
-                                */
-                               bnx2x_cl45_read(bp, params->port,
-                                             ext_phy_type,
-                                             ext_phy_addr,
-                                             MDIO_PMA_DEVAD,
-                                             MDIO_PMA_REG_LASI_STATUS, &val1);
-
-                               DP(NETIF_MSG_LINK,
-                                        "8703 LASI status 0x%x\n",
-                                         val1);
-                       }
+       bnx2x_cl45_read(bp, phy,
+                       MDIO_PMA_DEVAD,
+                       MDIO_PMA_REG_8073_SPEED_LINK_STATUS, &link_status);
 
-                       /* clear the interrupt LASI status register */
-                       bnx2x_cl45_read(bp, params->port,
-                                     ext_phy_type,
-                                     ext_phy_addr,
-                                     MDIO_PCS_DEVAD,
-                                     MDIO_PCS_REG_STATUS, &val2);
-                       bnx2x_cl45_read(bp, params->port,
-                                     ext_phy_type,
-                                     ext_phy_addr,
-                                     MDIO_PCS_DEVAD,
-                                     MDIO_PCS_REG_STATUS, &val1);
-                       DP(NETIF_MSG_LINK, "807x PCS status 0x%x->0x%x\n",
-                          val2, val1);
-                       /* Clear MSG-OUT */
-                       bnx2x_cl45_read(bp, params->port,
-                                     ext_phy_type,
-                                     ext_phy_addr,
-                                     MDIO_PMA_DEVAD,
-                                     MDIO_PMA_REG_M8051_MSGOUT_REG,
-                                     &val1);
-
-                       /* Check the LASI */
-                       bnx2x_cl45_read(bp, params->port,
-                                     ext_phy_type,
-                                     ext_phy_addr,
-                                     MDIO_PMA_DEVAD,
-                                     MDIO_PMA_REG_RX_ALARM, &val2);
-
-                       DP(NETIF_MSG_LINK, "KR 0x9003 0x%x\n", val2);
-
-                       /* Check the link status */
-                       bnx2x_cl45_read(bp, params->port,
-                                     ext_phy_type,
-                                     ext_phy_addr,
-                                     MDIO_PCS_DEVAD,
-                                     MDIO_PCS_REG_STATUS, &val2);
-                       DP(NETIF_MSG_LINK, "KR PCS status 0x%x\n", val2);
-
-                       bnx2x_cl45_read(bp, params->port,
-                                     ext_phy_type,
-                                     ext_phy_addr,
-                                     MDIO_PMA_DEVAD,
-                                     MDIO_PMA_REG_STATUS, &val2);
-                       bnx2x_cl45_read(bp, params->port,
-                                     ext_phy_type,
-                                     ext_phy_addr,
-                                     MDIO_PMA_DEVAD,
-                                     MDIO_PMA_REG_STATUS, &val1);
-                       ext_phy_link_up = ((val1 & 4) == 4);
-                       DP(NETIF_MSG_LINK, "PMA_REG_STATUS=0x%x\n", val1);
-                       if (ext_phy_type ==
-                           PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
-
-                               if (ext_phy_link_up &&
-                                   ((params->req_line_speed !=
-                                       SPEED_10000))) {
-                                       if (bnx2x_bcm8073_xaui_wa(params)
-                                            != 0) {
-                                               ext_phy_link_up = 0;
-                                               break;
-                                       }
-                               }
-                               bnx2x_cl45_read(bp, params->port,
-                                             ext_phy_type,
-                                             ext_phy_addr,
-                                             MDIO_AN_DEVAD,
-                                             MDIO_AN_REG_LINK_STATUS,
-                                             &an1000_status);
-                               bnx2x_cl45_read(bp, params->port,
-                                             ext_phy_type,
-                                             ext_phy_addr,
-                                             MDIO_AN_DEVAD,
-                                             MDIO_AN_REG_LINK_STATUS,
-                                             &an1000_status);
-
-                               /* Check the link status on 1.1.2 */
-                               bnx2x_cl45_read(bp, params->port,
-                                             ext_phy_type,
-                                             ext_phy_addr,
-                                             MDIO_PMA_DEVAD,
-                                             MDIO_PMA_REG_STATUS, &val2);
-                               bnx2x_cl45_read(bp, params->port,
-                                             ext_phy_type,
-                                             ext_phy_addr,
-                                             MDIO_PMA_DEVAD,
-                                             MDIO_PMA_REG_STATUS, &val1);
-                               DP(NETIF_MSG_LINK, "KR PMA status 0x%x->0x%x,"
-                                            "an_link_status=0x%x\n",
-                                         val2, val1, an1000_status);
-
-                               ext_phy_link_up = (((val1 & 4) == 4) ||
-                                               (an1000_status & (1<<1)));
-                               if (ext_phy_link_up &&
-                                   bnx2x_8073_is_snr_needed(params)) {
-                                       /* The SNR will improve about 2dbby
-                                       changing the BW and FEE main tap.*/
-
-                                       /* The 1st write to change FFE main
-                                       tap is set before restart AN */
-                                       /* Change PLL Bandwidth in EDC
-                                       register */
-                                       bnx2x_cl45_write(bp, port, ext_phy_type,
-                                                   ext_phy_addr,
-                                                   MDIO_PMA_DEVAD,
-                                                   MDIO_PMA_REG_PLL_BANDWIDTH,
-                                                   0x26BC);
-
-                                       /* Change CDR Bandwidth in EDC
-                                       register */
-                                       bnx2x_cl45_write(bp, port, ext_phy_type,
-                                                   ext_phy_addr,
-                                                   MDIO_PMA_DEVAD,
-                                                   MDIO_PMA_REG_CDR_BANDWIDTH,
-                                                   0x0333);
-                               }
-                               bnx2x_cl45_read(bp, params->port,
-                                          ext_phy_type,
-                                          ext_phy_addr,
-                                          MDIO_PMA_DEVAD,
-                                          MDIO_PMA_REG_8073_SPEED_LINK_STATUS,
-                                          &link_status);
-
-                               /* Bits 0..2 --> speed detected,
-                                  bits 13..15--> link is down */
-                               if ((link_status & (1<<2)) &&
-                                   (!(link_status & (1<<15)))) {
-                                       ext_phy_link_up = 1;
-                                       vars->line_speed = SPEED_10000;
-                                       DP(NETIF_MSG_LINK,
-                                                "port %x: External link"
-                                                " up in 10G\n", params->port);
-                               } else if ((link_status & (1<<1)) &&
-                                          (!(link_status & (1<<14)))) {
-                                       ext_phy_link_up = 1;
-                                       vars->line_speed = SPEED_2500;
-                                       DP(NETIF_MSG_LINK,
-                                                "port %x: External link"
-                                                " up in 2.5G\n", params->port);
-                               } else if ((link_status & (1<<0)) &&
-                                          (!(link_status & (1<<13)))) {
-                                       ext_phy_link_up = 1;
-                                       vars->line_speed = SPEED_1000;
-                                       DP(NETIF_MSG_LINK,
-                                                "port %x: External link"
-                                                " up in 1G\n", params->port);
-                               } else {
-                                       ext_phy_link_up = 0;
-                                       DP(NETIF_MSG_LINK,
-                                                "port %x: External link"
-                                                " is down\n", params->port);
-                               }
-                       } else {
-                               /* See if 1G link is up for the 8072 */
-                               bnx2x_cl45_read(bp, params->port,
-                                             ext_phy_type,
-                                             ext_phy_addr,
-                                             MDIO_AN_DEVAD,
-                                             MDIO_AN_REG_LINK_STATUS,
-                                             &an1000_status);
-                               bnx2x_cl45_read(bp, params->port,
-                                             ext_phy_type,
-                                             ext_phy_addr,
-                                             MDIO_AN_DEVAD,
-                                             MDIO_AN_REG_LINK_STATUS,
-                                             &an1000_status);
-                               if (an1000_status & (1<<1)) {
-                                       ext_phy_link_up = 1;
-                                       vars->line_speed = SPEED_1000;
-                                       DP(NETIF_MSG_LINK,
-                                                "port %x: External link"
-                                                " up in 1G\n", params->port);
-                               } else if (ext_phy_link_up) {
-                                       ext_phy_link_up = 1;
-                                       vars->line_speed = SPEED_10000;
-                                       DP(NETIF_MSG_LINK,
-                                                "port %x: External link"
-                                                " up in 10G\n", params->port);
-                               }
-                       }
+       /* Bits 0..2 --> speed detected,
+          bits 13..15--> link is down */
+       if ((link_status & (1<<2)) && (!(link_status & (1<<15)))) {
+               link_up = 1;
+               vars->line_speed = SPEED_10000;
+       } else if ((link_status & (1<<0)) && (!(link_status & (1<<13)))) {
+               link_up = 1;
+               vars->line_speed = SPEED_1000;
+               DP(NETIF_MSG_LINK, "port %x: External link up in 1G\n",
+                          params->port);
+       } else {
+               link_up = 0;
+               DP(NETIF_MSG_LINK, "port %x: External link is down\n",
+                          params->port);
+       }
+       if (link_up)
+               bnx2x_ext_phy_resolve_fc(phy, params, vars);
+
+       if ((DUAL_MEDIA(params)) &&
+           (phy->req_line_speed == SPEED_1000)) {
+               bnx2x_cl45_read(bp, phy,
+                               MDIO_PMA_DEVAD,
+                               MDIO_PMA_REG_8727_PCS_GP, &val1);
+               /**
+                * In case of dual-media board and 1G, power up the XAUI side,
+                * otherwise power it down. For 10G it is done automatically
+                */
+               if (link_up)
+                       val1 &= ~(3<<10);
+               else
+                       val1 |= (3<<10);
+               bnx2x_cl45_write(bp, phy,
+                                MDIO_PMA_DEVAD,
+                                MDIO_PMA_REG_8727_PCS_GP, val1);
+       }
+       return link_up;
+}
 
+static void bnx2x_8727_link_reset(struct bnx2x_phy *phy,
+                                 struct link_params *params)
+{
+       struct bnx2x *bp = params->bp;
+       /* Disable Transmitter */
+       bnx2x_sfp_set_transmitter(bp, phy, params->port, 0);
+       /* Clear LASI */
+       bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0);
 
+}
+
+/******************************************************************/
+/*             BCM8481/BCM84823/BCM84833 PHY SECTION             */
+/******************************************************************/
+static void bnx2x_save_848xx_spirom_version(struct bnx2x_phy *phy,
+                                          struct link_params *params)
+{
+       u16 val, fw_ver1, fw_ver2, cnt;
+       struct bnx2x *bp = params->bp;
+
+       /* For the 32 bits registers in 848xx, access via MDIO2ARM interface.*/
+       /* (1) set register 0xc200_0014(SPI_BRIDGE_CTRL_2) to 0x03000000 */
+       bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA819, 0x0014);
+       bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81A, 0xc200);
+       bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81B, 0x0000);
+       bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81C, 0x0300);
+       bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA817, 0x0009);
+
+       for (cnt = 0; cnt < 100; cnt++) {
+               bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA818, &val);
+               if (val & 1)
                        break;
-               }
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
-                       bnx2x_cl45_read(bp, params->port, ext_phy_type,
-                                     ext_phy_addr,
-                                     MDIO_PMA_DEVAD,
-                                     MDIO_PMA_REG_LASI_STATUS, &val2);
-                       bnx2x_cl45_read(bp, params->port, ext_phy_type,
-                                     ext_phy_addr,
-                                     MDIO_PMA_DEVAD,
-                                     MDIO_PMA_REG_LASI_STATUS, &val1);
-                       DP(NETIF_MSG_LINK,
-                                "10G-base-T LASI status 0x%x->0x%x\n",
-                                 val2, val1);
-                       bnx2x_cl45_read(bp, params->port, ext_phy_type,
-                                     ext_phy_addr,
-                                     MDIO_PMA_DEVAD,
-                                     MDIO_PMA_REG_STATUS, &val2);
-                       bnx2x_cl45_read(bp, params->port, ext_phy_type,
-                                     ext_phy_addr,
-                                     MDIO_PMA_DEVAD,
-                                     MDIO_PMA_REG_STATUS, &val1);
-                       DP(NETIF_MSG_LINK,
-                                "10G-base-T PMA status 0x%x->0x%x\n",
-                                val2, val1);
-                       ext_phy_link_up = ((val1 & 4) == 4);
-                       /* if link is up
-                        * print the AN outcome of the SFX7101 PHY
-                        */
-                       if (ext_phy_link_up) {
-                               bnx2x_cl45_read(bp, params->port,
-                                             ext_phy_type,
-                                             ext_phy_addr,
-                                             MDIO_AN_DEVAD,
-                                             MDIO_AN_REG_MASTER_STATUS,
-                                             &val2);
-                               vars->line_speed = SPEED_10000;
-                               DP(NETIF_MSG_LINK,
-                                        "SFX7101 AN status 0x%x->Master=%x\n",
-                                         val2,
-                                        (val2 & (1<<14)));
-                       }
-                       break;
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823:
-                       /* Check 10G-BaseT link status */
-                       /* Check PMD signal ok */
-                       bnx2x_cl45_read(bp, params->port, ext_phy_type,
-                                                     ext_phy_addr,
-                                                     MDIO_AN_DEVAD,
-                                                     0xFFFA,
-                                                     &val1);
-                       bnx2x_cl45_read(bp, params->port, ext_phy_type,
-                                     ext_phy_addr,
-                                     MDIO_PMA_DEVAD,
-                                     MDIO_PMA_REG_8481_PMD_SIGNAL,
-                                     &val2);
-                       DP(NETIF_MSG_LINK, "PMD_SIGNAL 1.a811 = 0x%x\n", val2);
-
-                       /* Check link 10G */
-                       if (val2 & (1<<11)) {
-                               vars->line_speed = SPEED_10000;
-                               ext_phy_link_up = 1;
-                               bnx2x_8481_set_10G_led_mode(params,
-                                                         ext_phy_type,
-                                                         ext_phy_addr);
-                       } else { /* Check Legacy speed link */
-                               u16 legacy_status, legacy_speed;
-
-                               /* Enable expansion register 0x42
-                               (Operation mode status) */
-                               bnx2x_cl45_write(bp, params->port,
-                                        ext_phy_type,
-                                        ext_phy_addr,
-                                        MDIO_AN_DEVAD,
-                                        MDIO_AN_REG_8481_EXPANSION_REG_ACCESS,
-                                        0xf42);
-
-                               /* Get legacy speed operation status */
-                               bnx2x_cl45_read(bp, params->port,
-                                         ext_phy_type,
-                                         ext_phy_addr,
-                                         MDIO_AN_DEVAD,
-                                         MDIO_AN_REG_8481_EXPANSION_REG_RD_RW,
-                                         &legacy_status);
-
-                               DP(NETIF_MSG_LINK, "Legacy speed status"
-                                            " = 0x%x\n", legacy_status);
-                               ext_phy_link_up = ((legacy_status & (1<<11))
-                                                  == (1<<11));
-                               if (ext_phy_link_up) {
-                                       legacy_speed = (legacy_status & (3<<9));
-                                       if (legacy_speed == (0<<9))
-                                               vars->line_speed = SPEED_10;
-                                       else if (legacy_speed == (1<<9))
-                                               vars->line_speed =
-                                                       SPEED_100;
-                                       else if (legacy_speed == (2<<9))
-                                               vars->line_speed =
-                                                       SPEED_1000;
-                                       else /* Should not happen */
-                                               vars->line_speed = 0;
-
-                                       if (legacy_status & (1<<8))
-                                               vars->duplex = DUPLEX_FULL;
-                                       else
-                                               vars->duplex = DUPLEX_HALF;
-
-                                       DP(NETIF_MSG_LINK, "Link is up "
-                                                    "in %dMbps, is_duplex_full"
-                                                    "= %d\n",
-                                               vars->line_speed,
-                                               (vars->duplex == DUPLEX_FULL));
-                                       bnx2x_8481_set_legacy_led_mode(params,
-                                                                ext_phy_type,
-                                                                ext_phy_addr);
-                               }
-                       }
-                       break;
-               default:
-                       DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n",
-                          params->ext_phy_config);
-                       ext_phy_link_up = 0;
+               udelay(5);
+       }
+       if (cnt == 100) {
+               DP(NETIF_MSG_LINK, "Unable to read 848xx phy fw version(1)\n");
+               bnx2x_save_spirom_version(bp, params->port, 0,
+                                         phy->ver_addr);
+               return;
+       }
+
+
+       /* 2) read register 0xc200_0000 (SPI_FW_STATUS) */
+       bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA819, 0x0000);
+       bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81A, 0xc200);
+       bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA817, 0x000A);
+       for (cnt = 0; cnt < 100; cnt++) {
+               bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA818, &val);
+               if (val & 1)
                        break;
-               }
-               /* Set SGMII mode for external phy */
-               if (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) {
-                       if (vars->line_speed < SPEED_1000)
-                               vars->phy_flags |= PHY_SGMII_FLAG;
-                       else
-                               vars->phy_flags &= ~PHY_SGMII_FLAG;
-               }
+               udelay(5);
+       }
+       if (cnt == 100) {
+               DP(NETIF_MSG_LINK, "Unable to read 848xx phy fw version(2)\n");
+               bnx2x_save_spirom_version(bp, params->port, 0,
+                                         phy->ver_addr);
+               return;
+       }
 
-       } else { /* SerDes */
-               ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
-               switch (ext_phy_type) {
-               case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT:
-                       DP(NETIF_MSG_LINK, "SerDes Direct\n");
-                       ext_phy_link_up = 1;
-                       break;
+       /* lower 16 bits of the register SPI_FW_STATUS */
+       bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA81B, &fw_ver1);
+       /* upper 16 bits of register SPI_FW_STATUS */
+       bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA81C, &fw_ver2);
 
-               case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482:
-                       DP(NETIF_MSG_LINK, "SerDes 5482\n");
-                       ext_phy_link_up = 1;
-                       break;
+       bnx2x_save_spirom_version(bp, params->port, (fw_ver2<<16) | fw_ver1,
+                                 phy->ver_addr);
+}
 
-               default:
-                       DP(NETIF_MSG_LINK,
-                                "BAD SerDes ext_phy_config 0x%x\n",
-                                params->ext_phy_config);
-                       ext_phy_link_up = 0;
-                       break;
-               }
-       }
+static void bnx2x_848xx_set_led(struct bnx2x *bp,
+                               struct bnx2x_phy *phy)
+{
+       u16 val;
+
+       /* PHYC_CTL_LED_CTL */
+       bnx2x_cl45_read(bp, phy,
+                       MDIO_PMA_DEVAD,
+                       MDIO_PMA_REG_8481_LINK_SIGNAL, &val);
+       val &= 0xFE00;
+       val |= 0x0092;
+
+       bnx2x_cl45_write(bp, phy,
+                        MDIO_PMA_DEVAD,
+                        MDIO_PMA_REG_8481_LINK_SIGNAL, val);
+
+       bnx2x_cl45_write(bp, phy,
+                        MDIO_PMA_DEVAD,
+                        MDIO_PMA_REG_8481_LED1_MASK,
+                        0x80);
+
+       bnx2x_cl45_write(bp, phy,
+                        MDIO_PMA_DEVAD,
+                        MDIO_PMA_REG_8481_LED2_MASK,
+                        0x18);
+
+       bnx2x_cl45_write(bp, phy,
+                        MDIO_PMA_DEVAD,
+                        MDIO_PMA_REG_8481_LED3_MASK,
+                        0x0040);
 
-       return ext_phy_link_up;
+       /* 'Interrupt Mask' */
+       bnx2x_cl45_write(bp, phy,
+                        MDIO_AN_DEVAD,
+                        0xFFFB, 0xFFFD);
 }
 
-static void bnx2x_link_int_enable(struct link_params *params)
+static u8 bnx2x_848xx_cmn_config_init(struct bnx2x_phy *phy,
+                                     struct link_params *params,
+                                     struct link_vars *vars)
 {
-       u8 port = params->port;
-       u32 ext_phy_type;
-       u32 mask;
        struct bnx2x *bp = params->bp;
+       u16 autoneg_val, an_1000_val, an_10_100_val;
+       bnx2x_wait_reset_complete(bp, phy);
+       bnx2x_bits_en(bp, NIG_REG_LATCH_BC_0 + params->port*4,
+                     1 << NIG_LATCH_BC_ENABLE_MI_INT);
+
+       bnx2x_cl45_write(bp, phy,
+                        MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x0000);
+
+       bnx2x_848xx_set_led(bp, phy);
+
+       /* set 1000 speed advertisement */
+       bnx2x_cl45_read(bp, phy,
+                       MDIO_AN_DEVAD, MDIO_AN_REG_8481_1000T_CTRL,
+                       &an_1000_val);
+
+       bnx2x_ext_phy_set_pause(params, phy, vars);
+       bnx2x_cl45_read(bp, phy,
+                       MDIO_AN_DEVAD,
+                       MDIO_AN_REG_8481_LEGACY_AN_ADV,
+                       &an_10_100_val);
+       bnx2x_cl45_read(bp, phy,
+                       MDIO_AN_DEVAD, MDIO_AN_REG_8481_LEGACY_MII_CTRL,
+                       &autoneg_val);
+       /* Disable forced speed */
+       autoneg_val &= ~((1<<6) | (1<<8) | (1<<9) | (1<<12) | (1<<13));
+       an_10_100_val &= ~((1<<5) | (1<<6) | (1<<7) | (1<<8));
+
+       if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
+            (phy->speed_cap_mask &
+            PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) ||
+           (phy->req_line_speed == SPEED_1000)) {
+               an_1000_val |= (1<<8);
+               autoneg_val |= (1<<9 | 1<<12);
+               if (phy->req_duplex == DUPLEX_FULL)
+                       an_1000_val |= (1<<9);
+               DP(NETIF_MSG_LINK, "Advertising 1G\n");
+       } else
+               an_1000_val &= ~((1<<8) | (1<<9));
+
+       bnx2x_cl45_write(bp, phy,
+                        MDIO_AN_DEVAD, MDIO_AN_REG_8481_1000T_CTRL,
+                        an_1000_val);
+
+       /* set 10 speed advertisement */
+       if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
+            (phy->speed_cap_mask &
+            (PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_FULL |
+             PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_HALF)))) {
+               an_10_100_val |= (1<<7);
+               /* Enable autoneg and restart autoneg for legacy speeds */
+               autoneg_val |= (1<<9 | 1<<12);
+
+               if (phy->req_duplex == DUPLEX_FULL)
+                       an_10_100_val |= (1<<8);
+               DP(NETIF_MSG_LINK, "Advertising 100M\n");
+       }
+       /* set 10 speed advertisement */
+       if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
+           (phy->speed_cap_mask &
+         (PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL |
+          PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_HALF)))) {
+               an_10_100_val |= (1<<5);
+               autoneg_val |= (1<<9 | 1<<12);
+               if (phy->req_duplex == DUPLEX_FULL)
+                       an_10_100_val |= (1<<6);
+               DP(NETIF_MSG_LINK, "Advertising 10M\n");
+       }
 
-       /* setting the status to report on link up
-          for either XGXS or SerDes */
-
-       if (params->switch_cfg == SWITCH_CFG_10G) {
-               mask = (NIG_MASK_XGXS0_LINK10G |
-                       NIG_MASK_XGXS0_LINK_STATUS);
-               DP(NETIF_MSG_LINK, "enabled XGXS interrupt\n");
-               ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
-               if ((ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) &&
-                   (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) &&
-                   (ext_phy_type !=
-                               PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN)) {
-                       mask |= NIG_MASK_MI_INT;
-                       DP(NETIF_MSG_LINK, "enabled external phy int\n");
-               }
+       /* Only 10/100 are allowed to work in FORCE mode */
+       if (phy->req_line_speed == SPEED_100) {
+               autoneg_val |= (1<<13);
+               /* Enabled AUTO-MDIX when autoneg is disabled */
+               bnx2x_cl45_write(bp, phy,
+                                MDIO_AN_DEVAD, MDIO_AN_REG_8481_AUX_CTRL,
+                                (1<<15 | 1<<9 | 7<<0));
+               DP(NETIF_MSG_LINK, "Setting 100M force\n");
+       }
+       if (phy->req_line_speed == SPEED_10) {
+               /* Enabled AUTO-MDIX when autoneg is disabled */
+               bnx2x_cl45_write(bp, phy,
+                                MDIO_AN_DEVAD, MDIO_AN_REG_8481_AUX_CTRL,
+                                (1<<15 | 1<<9 | 7<<0));
+               DP(NETIF_MSG_LINK, "Setting 10M force\n");
+       }
 
-       } else { /* SerDes */
-               mask = NIG_MASK_SERDES0_LINK_STATUS;
-               DP(NETIF_MSG_LINK, "enabled SerDes interrupt\n");
-               ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
-               if ((ext_phy_type !=
-                               PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT) &&
-                   (ext_phy_type !=
-                               PORT_HW_CFG_SERDES_EXT_PHY_TYPE_NOT_CONN)) {
-                       mask |= NIG_MASK_MI_INT;
-                       DP(NETIF_MSG_LINK, "enabled external phy int\n");
-               }
+       bnx2x_cl45_write(bp, phy,
+                        MDIO_AN_DEVAD, MDIO_AN_REG_8481_LEGACY_AN_ADV,
+                        an_10_100_val);
+
+       if (phy->req_duplex == DUPLEX_FULL)
+               autoneg_val |= (1<<8);
+
+       bnx2x_cl45_write(bp, phy,
+                        MDIO_AN_DEVAD,
+                        MDIO_AN_REG_8481_LEGACY_MII_CTRL, autoneg_val);
+
+       if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
+           (phy->speed_cap_mask &
+            PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) ||
+               (phy->req_line_speed == SPEED_10000)) {
+               DP(NETIF_MSG_LINK, "Advertising 10G\n");
+               /* Restart autoneg for 10G*/
+
+               bnx2x_cl45_write(bp, phy,
+                                MDIO_AN_DEVAD, MDIO_AN_REG_CTRL,
+                                0x3200);
+       } else if (phy->req_line_speed != SPEED_10 &&
+                  phy->req_line_speed != SPEED_100) {
+               bnx2x_cl45_write(bp, phy,
+                                MDIO_AN_DEVAD,
+                                MDIO_AN_REG_8481_10GBASE_T_AN_CTRL,
+                                1);
        }
-       bnx2x_bits_en(bp,
-                     NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
-                     mask);
+       /* Save spirom version */
+       bnx2x_save_848xx_spirom_version(phy, params);
 
-       DP(NETIF_MSG_LINK, "port %x, is_xgxs %x, int_status 0x%x\n", port,
-                (params->switch_cfg == SWITCH_CFG_10G),
-                REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4));
-       DP(NETIF_MSG_LINK, " int_mask 0x%x, MI_INT %x, SERDES_LINK %x\n",
-                REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4),
-                REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT + port*0x18),
-                REG_RD(bp, NIG_REG_SERDES0_STATUS_LINK_STATUS+port*0x3c));
-       DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n",
-          REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
-          REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68));
+       return 0;
 }
 
-static void bnx2x_8481_rearm_latch_signal(struct bnx2x *bp, u8 port,
-                                       u8 is_mi_int)
+static u8 bnx2x_8481_config_init(struct bnx2x_phy *phy,
+                                struct link_params *params,
+                                struct link_vars *vars)
 {
-       u32 latch_status = 0, is_mi_int_status;
-       /* Disable the MI INT ( external phy int )
-        * by writing 1 to the status register. Link down indication
-        * is high-active-signal, so in this case we need to write the
-        * status to clear the XOR
-        */
-       /* Read Latched signals */
-       latch_status = REG_RD(bp,
-                                 NIG_REG_LATCH_STATUS_0 + port*8);
-       is_mi_int_status = REG_RD(bp,
-                                 NIG_REG_STATUS_INTERRUPT_PORT0 + port*4);
-       DP(NETIF_MSG_LINK, "original_signal = 0x%x, nig_status = 0x%x,"
-                    "latch_status = 0x%x\n",
-                is_mi_int, is_mi_int_status, latch_status);
-       /* Handle only those with latched-signal=up.*/
-       if (latch_status & 1) {
-               /* For all latched-signal=up,Write original_signal to status */
-               if (is_mi_int)
-                       bnx2x_bits_en(bp,
-                                   NIG_REG_STATUS_INTERRUPT_PORT0
-                                   + port*4,
-                                   NIG_STATUS_EMAC0_MI_INT);
-               else
-                       bnx2x_bits_dis(bp,
-                                    NIG_REG_STATUS_INTERRUPT_PORT0
-                                    + port*4,
-                                    NIG_STATUS_EMAC0_MI_INT);
-               /* For all latched-signal=up : Re-Arm Latch signals */
-               REG_WR(bp, NIG_REG_LATCH_STATUS_0 + port*8,
-                          (latch_status & 0xfffe) | (latch_status & 1));
-       }
+       struct bnx2x *bp = params->bp;
+       /* Restore normal power mode*/
+       bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
+                           MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
+
+       /* HW reset */
+       bnx2x_ext_phy_hw_reset(bp, params->port);
+
+       bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1<<15);
+       return bnx2x_848xx_cmn_config_init(phy, params, vars);
 }
-/*
- * link management
- */
-static void bnx2x_link_int_ack(struct link_params *params,
-                            struct link_vars *vars, u8 is_10g,
-                            u8 is_mi_int)
+
+static u8 bnx2x_848x3_config_init(struct bnx2x_phy *phy,
+                                 struct link_params *params,
+                                 struct link_vars *vars)
 {
        struct bnx2x *bp = params->bp;
-       u8 port = params->port;
+       u8 port = params->port, initialize = 1;
+       u16 val;
+       u16 temp;
+       u32 actual_phy_selection;
+       u8 rc = 0;
 
-       /* first reset all status
-        * we assume only one line will be change at a time */
-       bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
-                    (NIG_STATUS_XGXS0_LINK10G |
-                     NIG_STATUS_XGXS0_LINK_STATUS |
-                     NIG_STATUS_SERDES0_LINK_STATUS));
-       if ((XGXS_EXT_PHY_TYPE(params->ext_phy_config)
-               == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481) ||
-       (XGXS_EXT_PHY_TYPE(params->ext_phy_config)
-               == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823)) {
-               bnx2x_8481_rearm_latch_signal(bp, port, is_mi_int);
+       /* This is just for MDIO_CTL_REG_84823_MEDIA register. */
+
+       msleep(1);
+       bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3,
+                      MISC_REGISTERS_GPIO_OUTPUT_HIGH,
+                      port);
+       msleep(200); /* 100 is not enough */
+
+       /* BCM84823 requires that XGXS links up first @ 10G for normal
+       behavior */
+       temp = vars->line_speed;
+       vars->line_speed = SPEED_10000;
+       bnx2x_set_autoneg(&params->phy[INT_PHY], params, vars, 0);
+       bnx2x_program_serdes(&params->phy[INT_PHY], params, vars);
+       vars->line_speed = temp;
+
+       /* Set dual-media configuration according to configuration */
+
+       bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD,
+                       MDIO_CTL_REG_84823_MEDIA, &val);
+       val &= ~(MDIO_CTL_REG_84823_MEDIA_MAC_MASK |
+                MDIO_CTL_REG_84823_MEDIA_LINE_MASK |
+                MDIO_CTL_REG_84823_MEDIA_COPPER_CORE_DOWN |
+                MDIO_CTL_REG_84823_MEDIA_PRIORITY_MASK |
+                MDIO_CTL_REG_84823_MEDIA_FIBER_1G);
+       val |= MDIO_CTL_REG_84823_CTRL_MAC_XFI |
+               MDIO_CTL_REG_84823_MEDIA_LINE_XAUI_L;
+
+       actual_phy_selection = bnx2x_phy_selection(params);
+
+       switch (actual_phy_selection) {
+       case PORT_HW_CFG_PHY_SELECTION_HARDWARE_DEFAULT:
+               /* Do nothing. Essentialy this is like the priority copper */
+               break;
+       case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY:
+               val |= MDIO_CTL_REG_84823_MEDIA_PRIORITY_COPPER;
+               break;
+       case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY:
+               val |= MDIO_CTL_REG_84823_MEDIA_PRIORITY_FIBER;
+               break;
+       case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY:
+               /* Do nothing here. The first PHY won't be initialized at all */
+               break;
+       case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY:
+               val |= MDIO_CTL_REG_84823_MEDIA_COPPER_CORE_DOWN;
+               initialize = 0;
+               break;
        }
-       if (vars->phy_link_up) {
-               if (is_10g) {
-                       /* Disable the 10G link interrupt
-                        * by writing 1 to the status register
-                        */
-                       DP(NETIF_MSG_LINK, "10G XGXS phy link up\n");
-                       bnx2x_bits_en(bp,
-                                     NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
-                                     NIG_STATUS_XGXS0_LINK10G);
+       if (params->phy[EXT_PHY2].req_line_speed == SPEED_1000)
+               val |= MDIO_CTL_REG_84823_MEDIA_FIBER_1G;
 
-               } else if (params->switch_cfg == SWITCH_CFG_10G) {
-                       /* Disable the link interrupt
-                        * by writing 1 to the relevant lane
-                        * in the status register
-                        */
-                       u32 ser_lane = ((params->lane_config &
-                                   PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
-                                   PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
+       bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD,
+                        MDIO_CTL_REG_84823_MEDIA, val);
+       DP(NETIF_MSG_LINK, "Multi_phy config = 0x%x, Media control = 0x%x\n",
+                  params->multi_phy_config, val);
 
-                       DP(NETIF_MSG_LINK, "%d speed XGXS phy link up\n",
-                                vars->line_speed);
-                       bnx2x_bits_en(bp,
-                                     NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
-                                     ((1 << ser_lane) <<
-                                      NIG_STATUS_XGXS0_LINK_STATUS_SIZE));
+       if (initialize)
+               rc = bnx2x_848xx_cmn_config_init(phy, params, vars);
+       else
+               bnx2x_save_848xx_spirom_version(phy, params);
+       return rc;
+}
 
-               } else { /* SerDes */
-                       DP(NETIF_MSG_LINK, "SerDes phy link up\n");
-                       /* Disable the link interrupt
-                        * by writing 1 to the status register
-                        */
-                       bnx2x_bits_en(bp,
-                                     NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
-                                     NIG_STATUS_SERDES0_LINK_STATUS);
-               }
+static u8 bnx2x_848xx_read_status(struct bnx2x_phy *phy,
+                                      struct link_params *params,
+                                      struct link_vars *vars)
+{
+       struct bnx2x *bp = params->bp;
+       u16 val, val1, val2;
+       u8 link_up = 0;
+
+       /* Check 10G-BaseT link status */
+       /* Check PMD signal ok */
+       bnx2x_cl45_read(bp, phy,
+                       MDIO_AN_DEVAD, 0xFFFA, &val1);
+       bnx2x_cl45_read(bp, phy,
+                       MDIO_PMA_DEVAD, MDIO_PMA_REG_8481_PMD_SIGNAL,
+                       &val2);
+       DP(NETIF_MSG_LINK, "BCM848xx: PMD_SIGNAL 1.a811 = 0x%x\n", val2);
+
+       /* Check link 10G */
+       if (val2 & (1<<11)) {
+               vars->line_speed = SPEED_10000;
+               link_up = 1;
+               bnx2x_ext_phy_10G_an_resolve(bp, phy, vars);
+       } else { /* Check Legacy speed link */
+               u16 legacy_status, legacy_speed;
+
+               /* Enable expansion register 0x42 (Operation mode status) */
+               bnx2x_cl45_write(bp, phy,
+                                MDIO_AN_DEVAD,
+                                MDIO_AN_REG_8481_EXPANSION_REG_ACCESS, 0xf42);
+
+               /* Get legacy speed operation status */
+               bnx2x_cl45_read(bp, phy,
+                               MDIO_AN_DEVAD,
+                               MDIO_AN_REG_8481_EXPANSION_REG_RD_RW,
+                               &legacy_status);
+
+               DP(NETIF_MSG_LINK, "Legacy speed status"
+                            " = 0x%x\n", legacy_status);
+               link_up = ((legacy_status & (1<<11)) == (1<<11));
+               if (link_up) {
+                       legacy_speed = (legacy_status & (3<<9));
+                       if (legacy_speed == (0<<9))
+                               vars->line_speed = SPEED_10;
+                       else if (legacy_speed == (1<<9))
+                               vars->line_speed = SPEED_100;
+                       else if (legacy_speed == (2<<9))
+                               vars->line_speed = SPEED_1000;
+                       else /* Should not happen */
+                               vars->line_speed = 0;
 
-       } else { /* link_down */
+                       if (legacy_status & (1<<8))
+                               vars->duplex = DUPLEX_FULL;
+                       else
+                               vars->duplex = DUPLEX_HALF;
+
+                       DP(NETIF_MSG_LINK, "Link is up in %dMbps,"
+                                  " is_duplex_full= %d\n", vars->line_speed,
+                                  (vars->duplex == DUPLEX_FULL));
+                       /* Check legacy speed AN resolution */
+                       bnx2x_cl45_read(bp, phy,
+                                       MDIO_AN_DEVAD,
+                                       MDIO_AN_REG_8481_LEGACY_MII_STATUS,
+                                       &val);
+                       if (val & (1<<5))
+                               vars->link_status |=
+                                       LINK_STATUS_AUTO_NEGOTIATE_COMPLETE;
+                       bnx2x_cl45_read(bp, phy,
+                                       MDIO_AN_DEVAD,
+                                       MDIO_AN_REG_8481_LEGACY_AN_EXPANSION,
+                                       &val);
+                       if ((val & (1<<0)) == 0)
+                               vars->link_status |=
+                                       LINK_STATUS_PARALLEL_DETECTION_USED;
+               }
        }
+       if (link_up) {
+               DP(NETIF_MSG_LINK, "BCM84823: link speed is %d\n",
+                          vars->line_speed);
+               bnx2x_ext_phy_resolve_fc(phy, params, vars);
+       }
+
+       return link_up;
 }
 
-static u8 bnx2x_format_ver(u32 num, u8 *str, u16 len)
+static u8 bnx2x_848xx_format_ver(u32 raw_ver, u8 *str, u16 *len)
 {
-       u8 *str_ptr = str;
-       u32 mask = 0xf0000000;
-       u8 shift = 8*4;
-       u8 digit;
-       if (len < 10) {
-               /* Need more than 10chars for this format */
-               *str_ptr = '\0';
-               return -EINVAL;
-       }
-       while (shift > 0) {
+       u8 status = 0;
+       u32 spirom_ver;
+       spirom_ver = ((raw_ver & 0xF80) >> 7) << 16 | (raw_ver & 0x7F);
+       status = bnx2x_format_ver(spirom_ver, str, len);
+       return status;
+}
 
-               shift -= 4;
-               digit = ((num & mask) >> shift);
-               if (digit < 0xa)
-                       *str_ptr = digit + '0';
-               else
-                       *str_ptr = digit - 0xa + 'a';
-               str_ptr++;
-               mask = mask >> 4;
-               if (shift == 4*4) {
-                       *str_ptr = ':';
-                       str_ptr++;
-               }
-       }
-       *str_ptr = '\0';
-       return 0;
+static void bnx2x_8481_hw_reset(struct bnx2x_phy *phy,
+                               struct link_params *params)
+{
+       bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_1,
+                           MISC_REGISTERS_GPIO_OUTPUT_LOW, 0);
+       bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_1,
+                           MISC_REGISTERS_GPIO_OUTPUT_LOW, 1);
 }
 
-u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded,
-                             u8 *version, u16 len)
+static void bnx2x_8481_link_reset(struct bnx2x_phy *phy,
+                                       struct link_params *params)
 {
-       struct bnx2x *bp;
-       u32 ext_phy_type = 0;
-       u32 spirom_ver = 0;
-       u8 status;
+       bnx2x_cl45_write(params->bp, phy,
+                        MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x0000);
+       bnx2x_cl45_write(params->bp, phy,
+                        MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1);
+}
 
-       if (version == NULL || params == NULL)
-               return -EINVAL;
-       bp = params->bp;
+static void bnx2x_848x3_link_reset(struct bnx2x_phy *phy,
+                                  struct link_params *params)
+{
+       struct bnx2x *bp = params->bp;
+       u8 port = params->port;
+       bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3,
+                           MISC_REGISTERS_GPIO_OUTPUT_LOW,
+                           port);
+}
 
-       spirom_ver = REG_RD(bp, params->shmem_base +
-                  offsetof(struct shmem_region,
-                           port_mb[params->port].ext_phy_fw_version));
+static void bnx2x_848xx_set_link_led(struct bnx2x_phy *phy,
+                                    struct link_params *params, u8 mode)
+{
+       struct bnx2x *bp = params->bp;
+       u16 val;
 
-       status = 0;
-       /* reset the returned value to zero */
-       ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
-       switch (ext_phy_type) {
-       case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
+       switch (mode) {
+       case LED_MODE_OFF:
 
-               if (len < 5)
-                       return -EINVAL;
+               DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE OFF\n", params->port);
 
-               version[0] = (spirom_ver & 0xFF);
-               version[1] = (spirom_ver & 0xFF00) >> 8;
-               version[2] = (spirom_ver & 0xFF0000) >> 16;
-               version[3] = (spirom_ver & 0xFF000000) >> 24;
-               version[4] = '\0';
+               if ((params->hw_led_mode << SHARED_HW_CFG_LED_MODE_SHIFT) ==
+                   SHARED_HW_CFG_LED_EXTPHY1) {
 
-               break;
-       case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
-       case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
-       case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
-       case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
-       case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
-               status = bnx2x_format_ver(spirom_ver, version, len);
-               break;
-       case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
-       case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823:
-               spirom_ver = ((spirom_ver & 0xF80) >> 7) << 16 |
-                       (spirom_ver & 0x7F);
-               status = bnx2x_format_ver(spirom_ver, version, len);
-               break;
-       case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
-       case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
-               version[0] = '\0';
-               break;
+                       /* Set LED masks */
+                       bnx2x_cl45_write(bp, phy,
+                                       MDIO_PMA_DEVAD,
+                                       MDIO_PMA_REG_8481_LED1_MASK,
+                                       0x0);
 
-       case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
-               DP(NETIF_MSG_LINK, "bnx2x_get_ext_phy_fw_version:"
-                                   " type is FAILURE!\n");
-               status = -EINVAL;
+                       bnx2x_cl45_write(bp, phy,
+                                       MDIO_PMA_DEVAD,
+                                       MDIO_PMA_REG_8481_LED2_MASK,
+                                       0x0);
+
+                       bnx2x_cl45_write(bp, phy,
+                                       MDIO_PMA_DEVAD,
+                                       MDIO_PMA_REG_8481_LED3_MASK,
+                                       0x0);
+
+                       bnx2x_cl45_write(bp, phy,
+                                       MDIO_PMA_DEVAD,
+                                       MDIO_PMA_REG_8481_LED5_MASK,
+                                       0x0);
+
+               } else {
+                       bnx2x_cl45_write(bp, phy,
+                                        MDIO_PMA_DEVAD,
+                                        MDIO_PMA_REG_8481_LED1_MASK,
+                                        0x0);
+               }
                break;
+       case LED_MODE_FRONT_PANEL_OFF:
 
-       default:
+               DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE FRONT PANEL OFF\n",
+                  params->port);
+
+               if ((params->hw_led_mode << SHARED_HW_CFG_LED_MODE_SHIFT) ==
+                   SHARED_HW_CFG_LED_EXTPHY1) {
+
+                       /* Set LED masks */
+                       bnx2x_cl45_write(bp, phy,
+                                       MDIO_PMA_DEVAD,
+                                       MDIO_PMA_REG_8481_LED1_MASK,
+                                       0x0);
+
+                       bnx2x_cl45_write(bp, phy,
+                                       MDIO_PMA_DEVAD,
+                                       MDIO_PMA_REG_8481_LED2_MASK,
+                                       0x0);
+
+                       bnx2x_cl45_write(bp, phy,
+                                       MDIO_PMA_DEVAD,
+                                       MDIO_PMA_REG_8481_LED3_MASK,
+                                       0x0);
+
+                       bnx2x_cl45_write(bp, phy,
+                                       MDIO_PMA_DEVAD,
+                                       MDIO_PMA_REG_8481_LED5_MASK,
+                                       0x20);
+
+               } else {
+                       bnx2x_cl45_write(bp, phy,
+                                        MDIO_PMA_DEVAD,
+                                        MDIO_PMA_REG_8481_LED1_MASK,
+                                        0x0);
+               }
                break;
-       }
-       return status;
-}
+       case LED_MODE_ON:
 
-static void bnx2x_set_xgxs_loopback(struct link_params *params,
-                                 struct link_vars *vars,
-                                 u8 is_10g)
-{
-       u8 port = params->port;
-       struct bnx2x *bp = params->bp;
+               DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE ON\n", params->port);
 
-       if (is_10g) {
-               u32 md_devad;
+               if ((params->hw_led_mode << SHARED_HW_CFG_LED_MODE_SHIFT) ==
+                   SHARED_HW_CFG_LED_EXTPHY1) {
+                       /* Set control reg */
+                       bnx2x_cl45_read(bp, phy,
+                                       MDIO_PMA_DEVAD,
+                                       MDIO_PMA_REG_8481_LINK_SIGNAL,
+                                       &val);
+                       val &= 0x8000;
+                       val |= 0x2492;
 
-               DP(NETIF_MSG_LINK, "XGXS 10G loopback enable\n");
+                       bnx2x_cl45_write(bp, phy,
+                                       MDIO_PMA_DEVAD,
+                                       MDIO_PMA_REG_8481_LINK_SIGNAL,
+                                       val);
 
-               /* change the uni_phy_addr in the nig */
-               md_devad = REG_RD(bp, (NIG_REG_XGXS0_CTRL_MD_DEVAD +
-                                         port*0x18));
+                       /* Set LED masks */
+                       bnx2x_cl45_write(bp, phy,
+                                       MDIO_PMA_DEVAD,
+                                       MDIO_PMA_REG_8481_LED1_MASK,
+                                       0x0);
 
-               REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18, 0x5);
+                       bnx2x_cl45_write(bp, phy,
+                                       MDIO_PMA_DEVAD,
+                                       MDIO_PMA_REG_8481_LED2_MASK,
+                                       0x20);
 
-               bnx2x_cl45_write(bp, port, 0,
-                              params->phy_addr,
-                              5,
-                              (MDIO_REG_BANK_AER_BLOCK +
-                               (MDIO_AER_BLOCK_AER_REG & 0xf)),
-                              0x2800);
+                       bnx2x_cl45_write(bp, phy,
+                                       MDIO_PMA_DEVAD,
+                                       MDIO_PMA_REG_8481_LED3_MASK,
+                                       0x20);
+
+                       bnx2x_cl45_write(bp, phy,
+                                       MDIO_PMA_DEVAD,
+                                       MDIO_PMA_REG_8481_LED5_MASK,
+                                       0x0);
+               } else {
+                       bnx2x_cl45_write(bp, phy,
+                                       MDIO_PMA_DEVAD,
+                                       MDIO_PMA_REG_8481_LED1_MASK,
+                                       0x20);
+               }
+               break;
+
+       case LED_MODE_OPER:
+
+               DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE OPER\n", params->port);
 
-               bnx2x_cl45_write(bp, port, 0,
-                              params->phy_addr,
-                              5,
-                              (MDIO_REG_BANK_CL73_IEEEB0 +
-                               (MDIO_CL73_IEEEB0_CL73_AN_CONTROL & 0xf)),
-                              0x6041);
-               msleep(200);
-               /* set aer mmd back */
-               bnx2x_set_aer_mmd(params, vars);
+               if ((params->hw_led_mode << SHARED_HW_CFG_LED_MODE_SHIFT) ==
+                   SHARED_HW_CFG_LED_EXTPHY1) {
 
-               /* and md_devad */
-               REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18,
-                           md_devad);
+                       /* Set control reg */
+                       bnx2x_cl45_read(bp, phy,
+                                       MDIO_PMA_DEVAD,
+                                       MDIO_PMA_REG_8481_LINK_SIGNAL,
+                                       &val);
+
+                       if (!((val &
+                             MDIO_PMA_REG_8481_LINK_SIGNAL_LED4_ENABLE_MASK)
+                          >> MDIO_PMA_REG_8481_LINK_SIGNAL_LED4_ENABLE_SHIFT)){
+                               DP(NETIF_MSG_LINK, "Seting LINK_SIGNAL\n");
+                               bnx2x_cl45_write(bp, phy,
+                                                MDIO_PMA_DEVAD,
+                                                MDIO_PMA_REG_8481_LINK_SIGNAL,
+                                                0xa492);
+                       }
 
-       } else {
-               u16 mii_control;
+                       /* Set LED masks */
+                       bnx2x_cl45_write(bp, phy,
+                                       MDIO_PMA_DEVAD,
+                                       MDIO_PMA_REG_8481_LED1_MASK,
+                                       0x10);
 
-               DP(NETIF_MSG_LINK, "XGXS 1G loopback enable\n");
+                       bnx2x_cl45_write(bp, phy,
+                                       MDIO_PMA_DEVAD,
+                                       MDIO_PMA_REG_8481_LED2_MASK,
+                                       0x80);
 
-               CL45_RD_OVER_CL22(bp, port,
-                                     params->phy_addr,
-                                     MDIO_REG_BANK_COMBO_IEEE0,
-                                     MDIO_COMBO_IEEE0_MII_CONTROL,
-                                     &mii_control);
+                       bnx2x_cl45_write(bp, phy,
+                                       MDIO_PMA_DEVAD,
+                                       MDIO_PMA_REG_8481_LED3_MASK,
+                                       0x98);
 
-               CL45_WR_OVER_CL22(bp, port,
-                                     params->phy_addr,
-                                     MDIO_REG_BANK_COMBO_IEEE0,
-                                     MDIO_COMBO_IEEE0_MII_CONTROL,
-                                     (mii_control |
-                                      MDIO_COMBO_IEEO_MII_CONTROL_LOOPBACK));
+                       bnx2x_cl45_write(bp, phy,
+                                       MDIO_PMA_DEVAD,
+                                       MDIO_PMA_REG_8481_LED5_MASK,
+                                       0x40);
+
+               } else {
+                       bnx2x_cl45_write(bp, phy,
+                                        MDIO_PMA_DEVAD,
+                                        MDIO_PMA_REG_8481_LED1_MASK,
+                                        0x80);
+               }
+               break;
        }
 }
+/******************************************************************/
+/*                     SFX7101 PHY SECTION                       */
+/******************************************************************/
+static void bnx2x_7101_config_loopback(struct bnx2x_phy *phy,
+                                      struct link_params *params)
+{
+       struct bnx2x *bp = params->bp;
+       /* SFX7101_XGXS_TEST1 */
+       bnx2x_cl45_write(bp, phy,
+                        MDIO_XS_DEVAD, MDIO_XS_SFX7101_XGXS_TEST1, 0x100);
+}
 
-
-static void bnx2x_ext_phy_loopback(struct link_params *params)
+static u8 bnx2x_7101_config_init(struct bnx2x_phy *phy,
+                                struct link_params *params,
+                                struct link_vars *vars)
 {
+       u16 fw_ver1, fw_ver2, val;
        struct bnx2x *bp = params->bp;
-       u8 ext_phy_addr;
-       u32 ext_phy_type;
+       DP(NETIF_MSG_LINK, "Setting the SFX7101 LASI indication\n");
 
-       if (params->switch_cfg == SWITCH_CFG_10G) {
-               ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
-               ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config);
-               /* CL37 Autoneg Enabled */
-               switch (ext_phy_type) {
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN:
-                       DP(NETIF_MSG_LINK,
-                               "ext_phy_loopback: We should not get here\n");
-                       break;
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
-                       DP(NETIF_MSG_LINK, "ext_phy_loopback: 8705\n");
-                       break;
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
-                       DP(NETIF_MSG_LINK, "ext_phy_loopback: 8706\n");
-                       break;
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
-                       DP(NETIF_MSG_LINK, "PMA/PMD ext_phy_loopback: 8726\n");
-                       bnx2x_cl45_write(bp, params->port, ext_phy_type,
-                                      ext_phy_addr,
-                                      MDIO_PMA_DEVAD,
-                                      MDIO_PMA_REG_CTRL,
-                                      0x0001);
-                       break;
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
-                       /* SFX7101_XGXS_TEST1 */
-                       bnx2x_cl45_write(bp, params->port, ext_phy_type,
-                                      ext_phy_addr,
-                                      MDIO_XS_DEVAD,
-                                      MDIO_XS_SFX7101_XGXS_TEST1,
-                                      0x100);
-                       DP(NETIF_MSG_LINK,
-                               "ext_phy_loopback: set ext phy loopback\n");
-                       break;
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
+       /* Restore normal power mode*/
+       bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
+                           MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
+       /* HW reset */
+       bnx2x_ext_phy_hw_reset(bp, params->port);
+       bnx2x_wait_reset_complete(bp, phy);
+
+       bnx2x_cl45_write(bp, phy,
+                        MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 0x1);
+       DP(NETIF_MSG_LINK, "Setting the SFX7101 LED to blink on traffic\n");
+       bnx2x_cl45_write(bp, phy,
+                        MDIO_PMA_DEVAD, MDIO_PMA_REG_7107_LED_CNTL, (1<<3));
+
+       bnx2x_ext_phy_set_pause(params, phy, vars);
+       /* Restart autoneg */
+       bnx2x_cl45_read(bp, phy,
+                       MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, &val);
+       val |= 0x200;
+       bnx2x_cl45_write(bp, phy,
+                        MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, val);
+
+       /* Save spirom version */
+       bnx2x_cl45_read(bp, phy,
+                       MDIO_PMA_DEVAD, MDIO_PMA_REG_7101_VER1, &fw_ver1);
+
+       bnx2x_cl45_read(bp, phy,
+                       MDIO_PMA_DEVAD, MDIO_PMA_REG_7101_VER2, &fw_ver2);
+       bnx2x_save_spirom_version(bp, params->port,
+                                 (u32)(fw_ver1<<16 | fw_ver2), phy->ver_addr);
+       return 0;
+}
 
-                       break;
-               } /* switch external PHY type */
-       } else {
-               /* serdes */
-               ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
-               ext_phy_addr = (params->ext_phy_config  &
-               PORT_HW_CFG_SERDES_EXT_PHY_ADDR_MASK)
-               >> PORT_HW_CFG_SERDES_EXT_PHY_ADDR_SHIFT;
+static u8 bnx2x_7101_read_status(struct bnx2x_phy *phy,
+                                struct link_params *params,
+                                struct link_vars *vars)
+{
+       struct bnx2x *bp = params->bp;
+       u8 link_up;
+       u16 val1, val2;
+       bnx2x_cl45_read(bp, phy,
+                       MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val2);
+       bnx2x_cl45_read(bp, phy,
+                       MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val1);
+       DP(NETIF_MSG_LINK, "10G-base-T LASI status 0x%x->0x%x\n",
+                  val2, val1);
+       bnx2x_cl45_read(bp, phy,
+                       MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val2);
+       bnx2x_cl45_read(bp, phy,
+                       MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val1);
+       DP(NETIF_MSG_LINK, "10G-base-T PMA status 0x%x->0x%x\n",
+                  val2, val1);
+       link_up = ((val1 & 4) == 4);
+       /* if link is up
+        * print the AN outcome of the SFX7101 PHY
+        */
+       if (link_up) {
+               bnx2x_cl45_read(bp, phy,
+                               MDIO_AN_DEVAD, MDIO_AN_REG_MASTER_STATUS,
+                               &val2);
+               vars->line_speed = SPEED_10000;
+               DP(NETIF_MSG_LINK, "SFX7101 AN status 0x%x->Master=%x\n",
+                          val2, (val2 & (1<<14)));
+               bnx2x_ext_phy_10G_an_resolve(bp, phy, vars);
+               bnx2x_ext_phy_resolve_fc(phy, params, vars);
        }
+       return link_up;
 }
 
 
-/*
- *------------------------------------------------------------------------
- * bnx2x_override_led_value -
- *
- * Override the led value of the requsted led
- *
- *------------------------------------------------------------------------
- */
-u8 bnx2x_override_led_value(struct bnx2x *bp, u8 port,
-                         u32 led_idx, u32 value)
+static u8 bnx2x_7101_format_ver(u32 spirom_ver, u8 *str, u16 *len)
 {
-       u32 reg_val;
+       if (*len < 5)
+               return -EINVAL;
+       str[0] = (spirom_ver & 0xFF);
+       str[1] = (spirom_ver & 0xFF00) >> 8;
+       str[2] = (spirom_ver & 0xFF0000) >> 16;
+       str[3] = (spirom_ver & 0xFF000000) >> 24;
+       str[4] = '\0';
+       *len -= 5;
+       return 0;
+}
 
-       /* If port 0 then use EMAC0, else use EMAC1*/
-       u32 emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
+void bnx2x_sfx7101_sp_sw_reset(struct bnx2x *bp, struct bnx2x_phy *phy)
+{
+       u16 val, cnt;
 
-       DP(NETIF_MSG_LINK,
-                "bnx2x_override_led_value() port %x led_idx %d value %d\n",
-                port, led_idx, value);
+       bnx2x_cl45_read(bp, phy,
+                     MDIO_PMA_DEVAD,
+                     MDIO_PMA_REG_7101_RESET, &val);
 
-       switch (led_idx) {
-       case 0: /* 10MB led */
-               /* Read the current value of the LED register in
-               the EMAC block */
-               reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
-               /* Set the OVERRIDE bit to 1 */
-               reg_val |= EMAC_LED_OVERRIDE;
-               /* If value is 1, set the 10M_OVERRIDE bit,
-               otherwise reset it.*/
-               reg_val = (value == 1) ? (reg_val | EMAC_LED_10MB_OVERRIDE) :
-                       (reg_val & ~EMAC_LED_10MB_OVERRIDE);
-               REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
-               break;
-       case 1: /*100MB led    */
-               /*Read the current value of the LED register in
-               the EMAC block */
-               reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
-               /*  Set the OVERRIDE bit to 1 */
-               reg_val |= EMAC_LED_OVERRIDE;
-               /*  If value is 1, set the 100M_OVERRIDE bit,
-               otherwise reset it.*/
-               reg_val = (value == 1) ? (reg_val | EMAC_LED_100MB_OVERRIDE) :
-                       (reg_val & ~EMAC_LED_100MB_OVERRIDE);
-               REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
+       for (cnt = 0; cnt < 10; cnt++) {
+               msleep(50);
+               /* Writes a self-clearing reset */
+               bnx2x_cl45_write(bp, phy,
+                              MDIO_PMA_DEVAD,
+                              MDIO_PMA_REG_7101_RESET,
+                              (val | (1<<15)));
+               /* Wait for clear */
+               bnx2x_cl45_read(bp, phy,
+                             MDIO_PMA_DEVAD,
+                             MDIO_PMA_REG_7101_RESET, &val);
+
+               if ((val & (1<<15)) == 0)
+                       break;
+       }
+}
+
+static void bnx2x_7101_hw_reset(struct bnx2x_phy *phy,
+                               struct link_params *params) {
+       /* Low power mode is controlled by GPIO 2 */
+       bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_2,
+                           MISC_REGISTERS_GPIO_OUTPUT_LOW, params->port);
+       /* The PHY reset is controlled by GPIO 1 */
+       bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_1,
+                           MISC_REGISTERS_GPIO_OUTPUT_LOW, params->port);
+}
+
+static void bnx2x_7101_set_link_led(struct bnx2x_phy *phy,
+                                   struct link_params *params, u8 mode)
+{
+       u16 val = 0;
+       struct bnx2x *bp = params->bp;
+       switch (mode) {
+       case LED_MODE_FRONT_PANEL_OFF:
+       case LED_MODE_OFF:
+               val = 2;
                break;
-       case 2: /* 1000MB led */
-               /* Read the current value of the LED register in the
-               EMAC block */
-               reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
-               /* Set the OVERRIDE bit to 1 */
-               reg_val |= EMAC_LED_OVERRIDE;
-               /* If value is 1, set the 1000M_OVERRIDE bit, otherwise
-               reset it. */
-               reg_val = (value == 1) ? (reg_val | EMAC_LED_1000MB_OVERRIDE) :
-                       (reg_val & ~EMAC_LED_1000MB_OVERRIDE);
-               REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
+       case LED_MODE_ON:
+               val = 1;
                break;
-       case 3: /* 2500MB led */
-               /*  Read the current value of the LED register in the
-               EMAC block*/
-               reg_val = REG_RD(bp, emac_base + EMAC_REG_EMAC_LED);
-               /* Set the OVERRIDE bit to 1 */
-               reg_val |= EMAC_LED_OVERRIDE;
-               /*  If value is 1, set the 2500M_OVERRIDE bit, otherwise
-               reset it.*/
-               reg_val = (value == 1) ? (reg_val | EMAC_LED_2500MB_OVERRIDE) :
-                       (reg_val & ~EMAC_LED_2500MB_OVERRIDE);
-               REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
+       case LED_MODE_OPER:
+               val = 0;
                break;
-       case 4: /*10G led */
-               if (port == 0) {
-                       REG_WR(bp, NIG_REG_LED_10G_P0,
-                                   value);
+       }
+       bnx2x_cl45_write(bp, phy,
+                        MDIO_PMA_DEVAD,
+                        MDIO_PMA_REG_7107_LINK_LED_CNTL,
+                        val);
+}
+
+/******************************************************************/
+/*                     STATIC PHY DECLARATION                    */
+/******************************************************************/
+
+static struct bnx2x_phy phy_null = {
+       .type           = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN,
+       .addr           = 0,
+       .flags          = FLAGS_INIT_XGXS_FIRST,
+       .def_md_devad   = 0,
+       .reserved       = 0,
+       .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
+       .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
+       .mdio_ctrl      = 0,
+       .supported      = 0,
+       .media_type     = ETH_PHY_NOT_PRESENT,
+       .ver_addr       = 0,
+       .req_flow_ctrl  = 0,
+       .req_line_speed = 0,
+       .speed_cap_mask = 0,
+       .req_duplex     = 0,
+       .rsrv           = 0,
+       .config_init    = (config_init_t)NULL,
+       .read_status    = (read_status_t)NULL,
+       .link_reset     = (link_reset_t)NULL,
+       .config_loopback = (config_loopback_t)NULL,
+       .format_fw_ver  = (format_fw_ver_t)NULL,
+       .hw_reset       = (hw_reset_t)NULL,
+       .set_link_led   = (set_link_led_t)NULL,
+       .phy_specific_func = (phy_specific_func_t)NULL
+};
+
+static struct bnx2x_phy phy_serdes = {
+       .type           = PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT,
+       .addr           = 0xff,
+       .flags          = 0,
+       .def_md_devad   = 0,
+       .reserved       = 0,
+       .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
+       .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
+       .mdio_ctrl      = 0,
+       .supported      = (SUPPORTED_10baseT_Half |
+                          SUPPORTED_10baseT_Full |
+                          SUPPORTED_100baseT_Half |
+                          SUPPORTED_100baseT_Full |
+                          SUPPORTED_1000baseT_Full |
+                          SUPPORTED_2500baseX_Full |
+                          SUPPORTED_TP |
+                          SUPPORTED_Autoneg |
+                          SUPPORTED_Pause |
+                          SUPPORTED_Asym_Pause),
+       .media_type     = ETH_PHY_UNSPECIFIED,
+       .ver_addr       = 0,
+       .req_flow_ctrl  = 0,
+       .req_line_speed = 0,
+       .speed_cap_mask = 0,
+       .req_duplex     = 0,
+       .rsrv           = 0,
+       .config_init    = (config_init_t)bnx2x_init_serdes,
+       .read_status    = (read_status_t)bnx2x_link_settings_status,
+       .link_reset     = (link_reset_t)bnx2x_int_link_reset,
+       .config_loopback = (config_loopback_t)NULL,
+       .format_fw_ver  = (format_fw_ver_t)NULL,
+       .hw_reset       = (hw_reset_t)NULL,
+       .set_link_led   = (set_link_led_t)NULL,
+       .phy_specific_func = (phy_specific_func_t)NULL
+};
+
+static struct bnx2x_phy phy_xgxs = {
+       .type           = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT,
+       .addr           = 0xff,
+       .flags          = 0,
+       .def_md_devad   = 0,
+       .reserved       = 0,
+       .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
+       .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
+       .mdio_ctrl      = 0,
+       .supported      = (SUPPORTED_10baseT_Half |
+                          SUPPORTED_10baseT_Full |
+                          SUPPORTED_100baseT_Half |
+                          SUPPORTED_100baseT_Full |
+                          SUPPORTED_1000baseT_Full |
+                          SUPPORTED_2500baseX_Full |
+                          SUPPORTED_10000baseT_Full |
+                          SUPPORTED_FIBRE |
+                          SUPPORTED_Autoneg |
+                          SUPPORTED_Pause |
+                          SUPPORTED_Asym_Pause),
+       .media_type     = ETH_PHY_UNSPECIFIED,
+       .ver_addr       = 0,
+       .req_flow_ctrl  = 0,
+       .req_line_speed = 0,
+       .speed_cap_mask = 0,
+       .req_duplex     = 0,
+       .rsrv           = 0,
+       .config_init    = (config_init_t)bnx2x_init_xgxs,
+       .read_status    = (read_status_t)bnx2x_link_settings_status,
+       .link_reset     = (link_reset_t)bnx2x_int_link_reset,
+       .config_loopback = (config_loopback_t)bnx2x_set_xgxs_loopback,
+       .format_fw_ver  = (format_fw_ver_t)NULL,
+       .hw_reset       = (hw_reset_t)NULL,
+       .set_link_led   = (set_link_led_t)NULL,
+       .phy_specific_func = (phy_specific_func_t)NULL
+};
+
+static struct bnx2x_phy phy_7101 = {
+       .type           = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
+       .addr           = 0xff,
+       .flags          = FLAGS_FAN_FAILURE_DET_REQ,
+       .def_md_devad   = 0,
+       .reserved       = 0,
+       .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
+       .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
+       .mdio_ctrl      = 0,
+       .supported      = (SUPPORTED_10000baseT_Full |
+                          SUPPORTED_TP |
+                          SUPPORTED_Autoneg |
+                          SUPPORTED_Pause |
+                          SUPPORTED_Asym_Pause),
+       .media_type     = ETH_PHY_BASE_T,
+       .ver_addr       = 0,
+       .req_flow_ctrl  = 0,
+       .req_line_speed = 0,
+       .speed_cap_mask = 0,
+       .req_duplex     = 0,
+       .rsrv           = 0,
+       .config_init    = (config_init_t)bnx2x_7101_config_init,
+       .read_status    = (read_status_t)bnx2x_7101_read_status,
+       .link_reset     = (link_reset_t)bnx2x_common_ext_link_reset,
+       .config_loopback = (config_loopback_t)bnx2x_7101_config_loopback,
+       .format_fw_ver  = (format_fw_ver_t)bnx2x_7101_format_ver,
+       .hw_reset       = (hw_reset_t)bnx2x_7101_hw_reset,
+       .set_link_led   = (set_link_led_t)bnx2x_7101_set_link_led,
+       .phy_specific_func = (phy_specific_func_t)NULL
+};
+static struct bnx2x_phy phy_8073 = {
+       .type           = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
+       .addr           = 0xff,
+       .flags          = FLAGS_HW_LOCK_REQUIRED,
+       .def_md_devad   = 0,
+       .reserved       = 0,
+       .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
+       .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
+       .mdio_ctrl      = 0,
+       .supported      = (SUPPORTED_10000baseT_Full |
+                          SUPPORTED_2500baseX_Full |
+                          SUPPORTED_1000baseT_Full |
+                          SUPPORTED_FIBRE |
+                          SUPPORTED_Autoneg |
+                          SUPPORTED_Pause |
+                          SUPPORTED_Asym_Pause),
+       .media_type     = ETH_PHY_UNSPECIFIED,
+       .ver_addr       = 0,
+       .req_flow_ctrl  = 0,
+       .req_line_speed = 0,
+       .speed_cap_mask = 0,
+       .req_duplex     = 0,
+       .rsrv           = 0,
+       .config_init    = (config_init_t)bnx2x_8073_config_init,
+       .read_status    = (read_status_t)bnx2x_8073_read_status,
+       .link_reset     = (link_reset_t)bnx2x_8073_link_reset,
+       .config_loopback = (config_loopback_t)NULL,
+       .format_fw_ver  = (format_fw_ver_t)bnx2x_format_ver,
+       .hw_reset       = (hw_reset_t)NULL,
+       .set_link_led   = (set_link_led_t)NULL,
+       .phy_specific_func = (phy_specific_func_t)NULL
+};
+static struct bnx2x_phy phy_8705 = {
+       .type           = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705,
+       .addr           = 0xff,
+       .flags          = FLAGS_INIT_XGXS_FIRST,
+       .def_md_devad   = 0,
+       .reserved       = 0,
+       .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
+       .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
+       .mdio_ctrl      = 0,
+       .supported      = (SUPPORTED_10000baseT_Full |
+                          SUPPORTED_FIBRE |
+                          SUPPORTED_Pause |
+                          SUPPORTED_Asym_Pause),
+       .media_type     = ETH_PHY_XFP_FIBER,
+       .ver_addr       = 0,
+       .req_flow_ctrl  = 0,
+       .req_line_speed = 0,
+       .speed_cap_mask = 0,
+       .req_duplex     = 0,
+       .rsrv           = 0,
+       .config_init    = (config_init_t)bnx2x_8705_config_init,
+       .read_status    = (read_status_t)bnx2x_8705_read_status,
+       .link_reset     = (link_reset_t)bnx2x_common_ext_link_reset,
+       .config_loopback = (config_loopback_t)NULL,
+       .format_fw_ver  = (format_fw_ver_t)bnx2x_null_format_ver,
+       .hw_reset       = (hw_reset_t)NULL,
+       .set_link_led   = (set_link_led_t)NULL,
+       .phy_specific_func = (phy_specific_func_t)NULL
+};
+static struct bnx2x_phy phy_8706 = {
+       .type           = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706,
+       .addr           = 0xff,
+       .flags          = FLAGS_INIT_XGXS_FIRST,
+       .def_md_devad   = 0,
+       .reserved       = 0,
+       .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
+       .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
+       .mdio_ctrl      = 0,
+       .supported      = (SUPPORTED_10000baseT_Full |
+                          SUPPORTED_1000baseT_Full |
+                          SUPPORTED_FIBRE |
+                          SUPPORTED_Pause |
+                          SUPPORTED_Asym_Pause),
+       .media_type     = ETH_PHY_SFP_FIBER,
+       .ver_addr       = 0,
+       .req_flow_ctrl  = 0,
+       .req_line_speed = 0,
+       .speed_cap_mask = 0,
+       .req_duplex     = 0,
+       .rsrv           = 0,
+       .config_init    = (config_init_t)bnx2x_8706_config_init,
+       .read_status    = (read_status_t)bnx2x_8706_read_status,
+       .link_reset     = (link_reset_t)bnx2x_common_ext_link_reset,
+       .config_loopback = (config_loopback_t)NULL,
+       .format_fw_ver  = (format_fw_ver_t)bnx2x_format_ver,
+       .hw_reset       = (hw_reset_t)NULL,
+       .set_link_led   = (set_link_led_t)NULL,
+       .phy_specific_func = (phy_specific_func_t)NULL
+};
+
+static struct bnx2x_phy phy_8726 = {
+       .type           = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
+       .addr           = 0xff,
+       .flags          = (FLAGS_HW_LOCK_REQUIRED |
+                          FLAGS_INIT_XGXS_FIRST),
+       .def_md_devad   = 0,
+       .reserved       = 0,
+       .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
+       .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
+       .mdio_ctrl      = 0,
+       .supported      = (SUPPORTED_10000baseT_Full |
+                          SUPPORTED_1000baseT_Full |
+                          SUPPORTED_Autoneg |
+                          SUPPORTED_FIBRE |
+                          SUPPORTED_Pause |
+                          SUPPORTED_Asym_Pause),
+       .media_type     = ETH_PHY_SFP_FIBER,
+       .ver_addr       = 0,
+       .req_flow_ctrl  = 0,
+       .req_line_speed = 0,
+       .speed_cap_mask = 0,
+       .req_duplex     = 0,
+       .rsrv           = 0,
+       .config_init    = (config_init_t)bnx2x_8726_config_init,
+       .read_status    = (read_status_t)bnx2x_8726_read_status,
+       .link_reset     = (link_reset_t)bnx2x_8726_link_reset,
+       .config_loopback = (config_loopback_t)bnx2x_8726_config_loopback,
+       .format_fw_ver  = (format_fw_ver_t)bnx2x_format_ver,
+       .hw_reset       = (hw_reset_t)NULL,
+       .set_link_led   = (set_link_led_t)NULL,
+       .phy_specific_func = (phy_specific_func_t)NULL
+};
+
+static struct bnx2x_phy phy_8727 = {
+       .type           = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+       .addr           = 0xff,
+       .flags          = FLAGS_FAN_FAILURE_DET_REQ,
+       .def_md_devad   = 0,
+       .reserved       = 0,
+       .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
+       .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
+       .mdio_ctrl      = 0,
+       .supported      = (SUPPORTED_10000baseT_Full |
+                          SUPPORTED_1000baseT_Full |
+                          SUPPORTED_FIBRE |
+                          SUPPORTED_Pause |
+                          SUPPORTED_Asym_Pause),
+       .media_type     = ETH_PHY_SFP_FIBER,
+       .ver_addr       = 0,
+       .req_flow_ctrl  = 0,
+       .req_line_speed = 0,
+       .speed_cap_mask = 0,
+       .req_duplex     = 0,
+       .rsrv           = 0,
+       .config_init    = (config_init_t)bnx2x_8727_config_init,
+       .read_status    = (read_status_t)bnx2x_8727_read_status,
+       .link_reset     = (link_reset_t)bnx2x_8727_link_reset,
+       .config_loopback = (config_loopback_t)NULL,
+       .format_fw_ver  = (format_fw_ver_t)bnx2x_format_ver,
+       .hw_reset       = (hw_reset_t)bnx2x_8727_hw_reset,
+       .set_link_led   = (set_link_led_t)bnx2x_8727_set_link_led,
+       .phy_specific_func = (phy_specific_func_t)bnx2x_8727_specific_func
+};
+static struct bnx2x_phy phy_8481 = {
+       .type           = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
+       .addr           = 0xff,
+       .flags          = FLAGS_FAN_FAILURE_DET_REQ |
+                         FLAGS_REARM_LATCH_SIGNAL,
+       .def_md_devad   = 0,
+       .reserved       = 0,
+       .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
+       .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
+       .mdio_ctrl      = 0,
+       .supported      = (SUPPORTED_10baseT_Half |
+                          SUPPORTED_10baseT_Full |
+                          SUPPORTED_100baseT_Half |
+                          SUPPORTED_100baseT_Full |
+                          SUPPORTED_1000baseT_Full |
+                          SUPPORTED_10000baseT_Full |
+                          SUPPORTED_TP |
+                          SUPPORTED_Autoneg |
+                          SUPPORTED_Pause |
+                          SUPPORTED_Asym_Pause),
+       .media_type     = ETH_PHY_BASE_T,
+       .ver_addr       = 0,
+       .req_flow_ctrl  = 0,
+       .req_line_speed = 0,
+       .speed_cap_mask = 0,
+       .req_duplex     = 0,
+       .rsrv           = 0,
+       .config_init    = (config_init_t)bnx2x_8481_config_init,
+       .read_status    = (read_status_t)bnx2x_848xx_read_status,
+       .link_reset     = (link_reset_t)bnx2x_8481_link_reset,
+       .config_loopback = (config_loopback_t)NULL,
+       .format_fw_ver  = (format_fw_ver_t)bnx2x_848xx_format_ver,
+       .hw_reset       = (hw_reset_t)bnx2x_8481_hw_reset,
+       .set_link_led   = (set_link_led_t)bnx2x_848xx_set_link_led,
+       .phy_specific_func = (phy_specific_func_t)NULL
+};
+
+static struct bnx2x_phy phy_84823 = {
+       .type           = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823,
+       .addr           = 0xff,
+       .flags          = FLAGS_FAN_FAILURE_DET_REQ |
+                         FLAGS_REARM_LATCH_SIGNAL,
+       .def_md_devad   = 0,
+       .reserved       = 0,
+       .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
+       .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
+       .mdio_ctrl      = 0,
+       .supported      = (SUPPORTED_10baseT_Half |
+                          SUPPORTED_10baseT_Full |
+                          SUPPORTED_100baseT_Half |
+                          SUPPORTED_100baseT_Full |
+                          SUPPORTED_1000baseT_Full |
+                          SUPPORTED_10000baseT_Full |
+                          SUPPORTED_TP |
+                          SUPPORTED_Autoneg |
+                          SUPPORTED_Pause |
+                          SUPPORTED_Asym_Pause),
+       .media_type     = ETH_PHY_BASE_T,
+       .ver_addr       = 0,
+       .req_flow_ctrl  = 0,
+       .req_line_speed = 0,
+       .speed_cap_mask = 0,
+       .req_duplex     = 0,
+       .rsrv           = 0,
+       .config_init    = (config_init_t)bnx2x_848x3_config_init,
+       .read_status    = (read_status_t)bnx2x_848xx_read_status,
+       .link_reset     = (link_reset_t)bnx2x_848x3_link_reset,
+       .config_loopback = (config_loopback_t)NULL,
+       .format_fw_ver  = (format_fw_ver_t)bnx2x_848xx_format_ver,
+       .hw_reset       = (hw_reset_t)NULL,
+       .set_link_led   = (set_link_led_t)bnx2x_848xx_set_link_led,
+       .phy_specific_func = (phy_specific_func_t)NULL
+};
+
+/*****************************************************************/
+/*                                                               */
+/* Populate the phy according. Main function: bnx2x_populate_phy   */
+/*                                                               */
+/*****************************************************************/
+
+static void bnx2x_populate_preemphasis(struct bnx2x *bp, u32 shmem_base,
+                                    struct bnx2x_phy *phy, u8 port,
+                                    u8 phy_index)
+{
+       /* Get the 4 lanes xgxs config rx and tx */
+       u32 rx = 0, tx = 0, i;
+       for (i = 0; i < 2; i++) {
+               /**
+                * INT_PHY and EXT_PHY1 share the same value location in the
+                * shmem. When num_phys is greater than 1, than this value
+                * applies only to EXT_PHY1
+                */
+               if (phy_index == INT_PHY || phy_index == EXT_PHY1) {
+                       rx = REG_RD(bp, shmem_base +
+                                   offsetof(struct shmem_region,
+                          dev_info.port_hw_config[port].xgxs_config_rx[i<<1]));
+
+                       tx = REG_RD(bp, shmem_base +
+                                   offsetof(struct shmem_region,
+                          dev_info.port_hw_config[port].xgxs_config_tx[i<<1]));
                } else {
-                       REG_WR(bp, NIG_REG_LED_10G_P1,
-                                   value);
-               }
-               break;
-       case 5: /* TRAFFIC led */
-               /* Find if the traffic control is via BMAC or EMAC */
-               if (port == 0)
-                       reg_val = REG_RD(bp, NIG_REG_NIG_EMAC0_EN);
-               else
-                       reg_val = REG_RD(bp, NIG_REG_NIG_EMAC1_EN);
+                       rx = REG_RD(bp, shmem_base +
+                                   offsetof(struct shmem_region,
+                         dev_info.port_hw_config[port].xgxs_config2_rx[i<<1]));
 
-               /*  Override the traffic led in the EMAC:*/
-               if (reg_val == 1) {
-                       /* Read the current value of the LED register in
-                       the EMAC block */
-                       reg_val = REG_RD(bp, emac_base +
-                                            EMAC_REG_EMAC_LED);
-                       /* Set the TRAFFIC_OVERRIDE bit to 1 */
-                       reg_val |= EMAC_LED_OVERRIDE;
-                       /* If value is 1, set the TRAFFIC bit, otherwise
-                       reset it.*/
-                       reg_val = (value == 1) ? (reg_val | EMAC_LED_TRAFFIC) :
-                               (reg_val & ~EMAC_LED_TRAFFIC);
-                       REG_WR(bp, emac_base + EMAC_REG_EMAC_LED, reg_val);
-               } else { /* Override the traffic led in the BMAC: */
-                       REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0
-                                  + port*4, 1);
-                       REG_WR(bp, NIG_REG_LED_CONTROL_TRAFFIC_P0 + port*4,
-                                   value);
+                       tx = REG_RD(bp, shmem_base +
+                                   offsetof(struct shmem_region,
+                         dev_info.port_hw_config[port].xgxs_config2_rx[i<<1]));
                }
+
+               phy->rx_preemphasis[i << 1] = ((rx>>16) & 0xffff);
+               phy->rx_preemphasis[(i << 1) + 1] = (rx & 0xffff);
+
+               phy->tx_preemphasis[i << 1] = ((tx>>16) & 0xffff);
+               phy->tx_preemphasis[(i << 1) + 1] = (tx & 0xffff);
+       }
+}
+
+static u32 bnx2x_get_ext_phy_config(struct bnx2x *bp, u32 shmem_base,
+                                   u8 phy_index, u8 port)
+{
+       u32 ext_phy_config = 0;
+       switch (phy_index) {
+       case EXT_PHY1:
+               ext_phy_config = REG_RD(bp, shmem_base +
+                                             offsetof(struct shmem_region,
+                       dev_info.port_hw_config[port].external_phy_config));
+               break;
+       case EXT_PHY2:
+               ext_phy_config = REG_RD(bp, shmem_base +
+                                             offsetof(struct shmem_region,
+                       dev_info.port_hw_config[port].external_phy_config2));
                break;
        default:
-               DP(NETIF_MSG_LINK,
-                        "bnx2x_override_led_value() unknown led index %d "
-                        "(should be 0-5)\n", led_idx);
+               DP(NETIF_MSG_LINK, "Invalid phy_index %d\n", phy_index);
                return -EINVAL;
        }
 
-       return 0;
+       return ext_phy_config;
 }
-
-
-u8 bnx2x_set_led(struct link_params *params, u8 mode, u32 speed)
+static u8 bnx2x_populate_int_phy(struct bnx2x *bp, u32 shmem_base, u8 port,
+                                struct bnx2x_phy *phy)
 {
-       u8 port = params->port;
-       u16 hw_led_mode = params->hw_led_mode;
-       u8 rc = 0;
-       u32 tmp;
-       u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
-       u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
-       struct bnx2x *bp = params->bp;
-       DP(NETIF_MSG_LINK, "bnx2x_set_led: port %x, mode %d\n", port, mode);
-       DP(NETIF_MSG_LINK, "speed 0x%x, hw_led_mode 0x%x\n",
-                speed, hw_led_mode);
-       switch (mode) {
-       case LED_MODE_OFF:
-               REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 0);
-               REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4,
-                          SHARED_HW_CFG_LED_MAC1);
-
-               tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
-               EMAC_WR(bp, EMAC_REG_EMAC_LED, (tmp | EMAC_LED_OVERRIDE));
+       u32 phy_addr;
+       u32 chip_id;
+       u32 switch_cfg = (REG_RD(bp, shmem_base +
+                                      offsetof(struct shmem_region,
+                       dev_info.port_feature_config[port].link_config)) &
+                         PORT_FEATURE_CONNECTED_SWITCH_MASK);
+       chip_id = REG_RD(bp, MISC_REG_CHIP_NUM) << 16;
+       switch (switch_cfg) {
+       case SWITCH_CFG_1G:
+               phy_addr = REG_RD(bp,
+                                       NIG_REG_SERDES0_CTRL_PHY_ADDR +
+                                       port * 0x10);
+               *phy = phy_serdes;
+               break;
+       case SWITCH_CFG_10G:
+               phy_addr = REG_RD(bp,
+                                       NIG_REG_XGXS0_CTRL_PHY_ADDR +
+                                       port * 0x18);
+               *phy = phy_xgxs;
                break;
+       default:
+               DP(NETIF_MSG_LINK, "Invalid switch_cfg\n");
+               return -EINVAL;
+       }
+       phy->addr = (u8)phy_addr;
+       phy->mdio_ctrl = bnx2x_get_emac_base(bp,
+                                           SHARED_HW_CFG_MDC_MDIO_ACCESS1_BOTH,
+                                           port);
+       phy->def_md_devad = DEFAULT_PHY_DEV_ADDR;
 
-       case LED_MODE_OPER:
-               if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) {
-                       REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, 0);
-                       REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 1);
-               } else {
-                       REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4,
-                                  hw_led_mode);
-               }
+       DP(NETIF_MSG_LINK, "Internal phy port=%d, addr=0x%x, mdio_ctl=0x%x\n",
+                  port, phy->addr, phy->mdio_ctrl);
 
-               REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0 +
-                          port*4, 0);
-               /* Set blinking rate to ~15.9Hz */
-               REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_P0 + port*4,
-                          LED_BLINK_RATE_VAL);
-               REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_ENA_P0 +
-                          port*4, 1);
-               tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
-               EMAC_WR(bp, EMAC_REG_EMAC_LED,
-                           (tmp & (~EMAC_LED_OVERRIDE)));
+       bnx2x_populate_preemphasis(bp, shmem_base, phy, port, INT_PHY);
+       return 0;
+}
 
-               if (CHIP_IS_E1(bp) &&
-                   ((speed == SPEED_2500) ||
-                    (speed == SPEED_1000) ||
-                    (speed == SPEED_100) ||
-                    (speed == SPEED_10))) {
-                       /* On Everest 1 Ax chip versions for speeds less than
-                       10G LED scheme is different */
-                       REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0
-                                  + port*4, 1);
-                       REG_WR(bp, NIG_REG_LED_CONTROL_TRAFFIC_P0 +
-                                  port*4, 0);
-                       REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_TRAFFIC_P0 +
-                                  port*4, 1);
-               }
+static u8 bnx2x_populate_ext_phy(struct bnx2x *bp,
+                                u8 phy_index,
+                                u32 shmem_base,
+                                u32 shmem2_base,
+                                u8 port,
+                                struct bnx2x_phy *phy)
+{
+       u32 ext_phy_config, phy_type, config2;
+       u32 mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_BOTH;
+       ext_phy_config = bnx2x_get_ext_phy_config(bp, shmem_base,
+                                                 phy_index, port);
+       phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config);
+       /* Select the phy type */
+       switch (phy_type) {
+       case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
+               mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_SWAPPED;
+               *phy = phy_8073;
+               break;
+       case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
+               *phy = phy_8705;
+               break;
+       case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
+               *phy = phy_8706;
+               break;
+       case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
+               mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC1;
+               *phy = phy_8726;
                break;
-
-       default:
-               rc = -EINVAL;
-               DP(NETIF_MSG_LINK, "bnx2x_set_led: Invalid led mode %d\n",
-                        mode);
+       case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC:
+               /* BCM8727_NOC => BCM8727 no over current */
+               mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC1;
+               *phy = phy_8727;
+               phy->flags |= FLAGS_NOC;
+               break;
+       case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
+               mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC1;
+               *phy = phy_8727;
                break;
+       case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
+               *phy = phy_8481;
+               break;
+       case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823:
+               *phy = phy_84823;
+               break;
+       case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
+               *phy = phy_7101;
+               break;
+       case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
+               *phy = phy_null;
+               return -EINVAL;
+       default:
+               *phy = phy_null;
+               return 0;
        }
-       return rc;
 
-}
+       phy->addr = XGXS_EXT_PHY_ADDR(ext_phy_config);
+       bnx2x_populate_preemphasis(bp, shmem_base, phy, port, phy_index);
 
-u8 bnx2x_test_link(struct link_params *params, struct link_vars *vars)
-{
-       struct bnx2x *bp = params->bp;
-       u16 gp_status = 0;
+       /**
+       * The shmem address of the phy version is located on different
+       * structures. In case this structure is too old, do not set
+       * the address
+       */
+       config2 = REG_RD(bp, shmem_base + offsetof(struct shmem_region,
+                                       dev_info.shared_hw_config.config2));
+       if (phy_index == EXT_PHY1) {
+               phy->ver_addr = shmem_base + offsetof(struct shmem_region,
+                               port_mb[port].ext_phy_fw_version);
+
+       /* Check specific mdc mdio settings */
+       if (config2 & SHARED_HW_CFG_MDC_MDIO_ACCESS1_MASK)
+               mdc_mdio_access = config2 &
+               SHARED_HW_CFG_MDC_MDIO_ACCESS1_MASK;
+       } else {
+               u32 size = REG_RD(bp, shmem2_base);
 
-       CL45_RD_OVER_CL22(bp, params->port,
-                             params->phy_addr,
-                             MDIO_REG_BANK_GP_STATUS,
-                             MDIO_GP_STATUS_TOP_AN_STATUS1,
-                             &gp_status);
-       /* link is up only if both local phy and external phy are up */
-       if ((gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) &&
-           bnx2x_ext_phy_is_link_up(params, vars, 1))
-               return 0;
+               if (size >
+                   offsetof(struct shmem2_region, ext_phy_fw_version2)) {
+                       phy->ver_addr = shmem2_base +
+                           offsetof(struct shmem2_region,
+                                    ext_phy_fw_version2[port]);
+               }
+               /* Check specific mdc mdio settings */
+               if (config2 & SHARED_HW_CFG_MDC_MDIO_ACCESS2_MASK)
+                       mdc_mdio_access = (config2 &
+                       SHARED_HW_CFG_MDC_MDIO_ACCESS2_MASK) >>
+                       (SHARED_HW_CFG_MDC_MDIO_ACCESS2_SHIFT -
+                        SHARED_HW_CFG_MDC_MDIO_ACCESS1_SHIFT);
+       }
+       phy->mdio_ctrl = bnx2x_get_emac_base(bp, mdc_mdio_access, port);
 
-       return -ESRCH;
+       /**
+        * In case mdc/mdio_access of the external phy is different than the
+        * mdc/mdio access of the XGXS, a HW lock must be taken in each access
+        * to prevent one port interfere with another port's CL45 operations.
+        */
+       if (mdc_mdio_access != SHARED_HW_CFG_MDC_MDIO_ACCESS1_BOTH)
+               phy->flags |= FLAGS_HW_LOCK_REQUIRED;
+       DP(NETIF_MSG_LINK, "phy_type 0x%x port %d found in index %d\n",
+                  phy_type, port, phy_index);
+       DP(NETIF_MSG_LINK, "             addr=0x%x, mdio_ctl=0x%x\n",
+                  phy->addr, phy->mdio_ctrl);
+       return 0;
 }
 
-static u8 bnx2x_link_initialize(struct link_params *params,
-                             struct link_vars *vars)
+static u8 bnx2x_populate_phy(struct bnx2x *bp, u8 phy_index, u32 shmem_base,
+                            u32 shmem2_base, u8 port, struct bnx2x_phy *phy)
 {
-       struct bnx2x *bp = params->bp;
-       u8 port = params->port;
-       u8 rc = 0;
-       u8 non_ext_phy;
-       u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
-
-       /* Activate the external PHY */
-       bnx2x_ext_phy_reset(params, vars);
+       u8 status = 0;
+       phy->type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN;
+       if (phy_index == INT_PHY)
+               return bnx2x_populate_int_phy(bp, shmem_base, port, phy);
+       status = bnx2x_populate_ext_phy(bp, phy_index, shmem_base, shmem2_base,
+                                       port, phy);
+       return status;
+}
 
-       bnx2x_set_aer_mmd(params, vars);
+static void bnx2x_phy_def_cfg(struct link_params *params,
+                             struct bnx2x_phy *phy,
+                             u8 phy_index)
+{
+       struct bnx2x *bp = params->bp;
+       u32 link_config;
+       /* Populate the default phy configuration for MF mode */
+       if (phy_index == EXT_PHY2) {
+               link_config = REG_RD(bp, params->shmem_base +
+                                        offsetof(struct shmem_region, dev_info.
+                       port_feature_config[params->port].link_config2));
+               phy->speed_cap_mask = REG_RD(bp, params->shmem_base +
+                                       offsetof(struct shmem_region, dev_info.
+                       port_hw_config[params->port].speed_capability_mask2));
+       } else {
+               link_config = REG_RD(bp, params->shmem_base +
+                               offsetof(struct shmem_region, dev_info.
+                               port_feature_config[params->port].link_config));
+               phy->speed_cap_mask = REG_RD(bp, params->shmem_base +
+                               offsetof(struct shmem_region, dev_info.
+                          port_hw_config[params->port].speed_capability_mask));
+       }
+       DP(NETIF_MSG_LINK, "Default config phy idx %x cfg 0x%x speed_cap_mask"
+                      " 0x%x\n", phy_index, link_config, phy->speed_cap_mask);
+
+       phy->req_duplex = DUPLEX_FULL;
+       switch (link_config  & PORT_FEATURE_LINK_SPEED_MASK) {
+       case PORT_FEATURE_LINK_SPEED_10M_HALF:
+               phy->req_duplex = DUPLEX_HALF;
+       case PORT_FEATURE_LINK_SPEED_10M_FULL:
+               phy->req_line_speed = SPEED_10;
+               break;
+       case PORT_FEATURE_LINK_SPEED_100M_HALF:
+               phy->req_duplex = DUPLEX_HALF;
+       case PORT_FEATURE_LINK_SPEED_100M_FULL:
+               phy->req_line_speed = SPEED_100;
+               break;
+       case PORT_FEATURE_LINK_SPEED_1G:
+               phy->req_line_speed = SPEED_1000;
+               break;
+       case PORT_FEATURE_LINK_SPEED_2_5G:
+               phy->req_line_speed = SPEED_2500;
+               break;
+       case PORT_FEATURE_LINK_SPEED_10G_CX4:
+               phy->req_line_speed = SPEED_10000;
+               break;
+       default:
+               phy->req_line_speed = SPEED_AUTO_NEG;
+               break;
+       }
 
-       if (vars->phy_flags & PHY_XGXS_FLAG)
-               bnx2x_set_master_ln(params);
+       switch (link_config  & PORT_FEATURE_FLOW_CONTROL_MASK) {
+       case PORT_FEATURE_FLOW_CONTROL_AUTO:
+               phy->req_flow_ctrl = BNX2X_FLOW_CTRL_AUTO;
+               break;
+       case PORT_FEATURE_FLOW_CONTROL_TX:
+               phy->req_flow_ctrl = BNX2X_FLOW_CTRL_TX;
+               break;
+       case PORT_FEATURE_FLOW_CONTROL_RX:
+               phy->req_flow_ctrl = BNX2X_FLOW_CTRL_RX;
+               break;
+       case PORT_FEATURE_FLOW_CONTROL_BOTH:
+               phy->req_flow_ctrl = BNX2X_FLOW_CTRL_BOTH;
+               break;
+       default:
+               phy->req_flow_ctrl = BNX2X_FLOW_CTRL_NONE;
+               break;
+       }
+}
 
-       rc = bnx2x_reset_unicore(params);
-       /* reset the SerDes and wait for reset bit return low */
-       if (rc != 0)
-               return rc;
+u32 bnx2x_phy_selection(struct link_params *params)
+{
+       u32 phy_config_swapped, prio_cfg;
+       u32 return_cfg = PORT_HW_CFG_PHY_SELECTION_HARDWARE_DEFAULT;
+
+       phy_config_swapped = params->multi_phy_config &
+               PORT_HW_CFG_PHY_SWAPPED_ENABLED;
+
+       prio_cfg = params->multi_phy_config &
+                       PORT_HW_CFG_PHY_SELECTION_MASK;
+
+       if (phy_config_swapped) {
+               switch (prio_cfg) {
+               case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY:
+                    return_cfg = PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY;
+                    break;
+               case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY:
+                    return_cfg = PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY;
+                    break;
+               case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY:
+                    return_cfg = PORT_HW_CFG_PHY_SELECTION_FIRST_PHY;
+                    break;
+               case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY:
+                    return_cfg = PORT_HW_CFG_PHY_SELECTION_SECOND_PHY;
+                    break;
+               }
+       } else
+               return_cfg = prio_cfg;
 
-       bnx2x_set_aer_mmd(params, vars);
+       return return_cfg;
+}
 
-       /* setting the masterLn_def again after the reset */
-       if (vars->phy_flags & PHY_XGXS_FLAG) {
-               bnx2x_set_master_ln(params);
-               bnx2x_set_swap_lanes(params);
-       }
 
-       if (vars->phy_flags & PHY_XGXS_FLAG) {
-               if ((params->req_line_speed &&
-                   ((params->req_line_speed == SPEED_100) ||
-                    (params->req_line_speed == SPEED_10))) ||
-                   (!params->req_line_speed &&
-                    (params->speed_cap_mask >=
-                      PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL) &&
-                    (params->speed_cap_mask <
-                      PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
-                    ))  {
-                       vars->phy_flags |= PHY_SGMII_FLAG;
-               } else {
-                       vars->phy_flags &= ~PHY_SGMII_FLAG;
+u8 bnx2x_phy_probe(struct link_params *params)
+{
+       u8 phy_index, actual_phy_idx, link_cfg_idx;
+       u32 phy_config_swapped;
+       struct bnx2x *bp = params->bp;
+       struct bnx2x_phy *phy;
+       params->num_phys = 0;
+       DP(NETIF_MSG_LINK, "Begin phy probe\n");
+       phy_config_swapped = params->multi_phy_config &
+               PORT_HW_CFG_PHY_SWAPPED_ENABLED;
+
+       for (phy_index = INT_PHY; phy_index < MAX_PHYS;
+             phy_index++) {
+               link_cfg_idx = LINK_CONFIG_IDX(phy_index);
+               actual_phy_idx = phy_index;
+               if (phy_config_swapped) {
+                       if (phy_index == EXT_PHY1)
+                               actual_phy_idx = EXT_PHY2;
+                       else if (phy_index == EXT_PHY2)
+                               actual_phy_idx = EXT_PHY1;
+               }
+               DP(NETIF_MSG_LINK, "phy_config_swapped %x, phy_index %x,"
+                              " actual_phy_idx %x\n", phy_config_swapped,
+                          phy_index, actual_phy_idx);
+               phy = &params->phy[actual_phy_idx];
+               if (bnx2x_populate_phy(bp, phy_index, params->shmem_base,
+                                      params->shmem2_base, params->port,
+                                      phy) != 0) {
+                       params->num_phys = 0;
+                       DP(NETIF_MSG_LINK, "phy probe failed in phy index %d\n",
+                                  phy_index);
+                       for (phy_index = INT_PHY;
+                             phy_index < MAX_PHYS;
+                             phy_index++)
+                               *phy = phy_null;
+                       return -EINVAL;
                }
+               if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN)
+                       break;
+
+               bnx2x_phy_def_cfg(params, phy, phy_index);
+               params->num_phys++;
        }
-       /* In case of external phy existance, the line speed would be the
-        line speed linked up by the external phy. In case it is direct only,
-         then the line_speed during initialization will be equal to the
-          req_line_speed*/
-       vars->line_speed = params->req_line_speed;
 
-       bnx2x_calc_ieee_aneg_adv(params, &vars->ieee_fc);
+       DP(NETIF_MSG_LINK, "End phy probe. #phys found %x\n", params->num_phys);
+       return 0;
+}
 
-       /* init ext phy and enable link state int */
-       non_ext_phy = ((ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) ||
-                      (params->loopback_mode == LOOPBACK_XGXS_10));
+u32 bnx2x_supported_attr(struct link_params *params, u8 phy_idx)
+{
+       if (phy_idx < params->num_phys)
+               return params->phy[phy_idx].supported;
+       return 0;
+}
 
-       if (non_ext_phy ||
-           (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) ||
-           (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706) ||
-           (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) ||
-           (params->loopback_mode == LOOPBACK_EXT_PHY)) {
-               if (params->req_line_speed == SPEED_AUTO_NEG)
-                       bnx2x_set_parallel_detection(params, vars->phy_flags);
-               bnx2x_init_internal_phy(params, vars, non_ext_phy);
-       }
+static void set_phy_vars(struct link_params *params)
+{
+       struct bnx2x *bp = params->bp;
+       u8 actual_phy_idx, phy_index, link_cfg_idx;
+       u8 phy_config_swapped = params->multi_phy_config &
+                       PORT_HW_CFG_PHY_SWAPPED_ENABLED;
+       for (phy_index = INT_PHY; phy_index < params->num_phys;
+             phy_index++) {
+               link_cfg_idx = LINK_CONFIG_IDX(phy_index);
+               actual_phy_idx = phy_index;
+               if (phy_config_swapped) {
+                       if (phy_index == EXT_PHY1)
+                               actual_phy_idx = EXT_PHY2;
+                       else if (phy_index == EXT_PHY2)
+                               actual_phy_idx = EXT_PHY1;
+               }
+               params->phy[actual_phy_idx].req_flow_ctrl  =
+                       params->req_flow_ctrl[link_cfg_idx];
 
-       if (!non_ext_phy)
-               rc |= bnx2x_ext_phy_init(params, vars);
+               params->phy[actual_phy_idx].req_line_speed =
+                       params->req_line_speed[link_cfg_idx];
 
-       bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
-                    (NIG_STATUS_XGXS0_LINK10G |
-                     NIG_STATUS_XGXS0_LINK_STATUS |
-                     NIG_STATUS_SERDES0_LINK_STATUS));
+               params->phy[actual_phy_idx].speed_cap_mask =
+                       params->speed_cap_mask[link_cfg_idx];
 
-       return rc;
+               params->phy[actual_phy_idx].req_duplex =
+                       params->req_duplex[link_cfg_idx];
 
+               DP(NETIF_MSG_LINK, "req_flow_ctrl %x, req_line_speed %x,"
+                          " speed_cap_mask %x\n",
+                          params->phy[actual_phy_idx].req_flow_ctrl,
+                          params->phy[actual_phy_idx].req_line_speed,
+                          params->phy[actual_phy_idx].speed_cap_mask);
+       }
 }
 
-
 u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
 {
        struct bnx2x *bp = params->bp;
-       u32 val;
-
        DP(NETIF_MSG_LINK, "Phy Initialization started\n");
-       DP(NETIF_MSG_LINK, "req_speed %d, req_flowctrl %d\n",
-                params->req_line_speed, params->req_flow_ctrl);
+       DP(NETIF_MSG_LINK, "(1) req_speed %d, req_flowctrl %d\n",
+                  params->req_line_speed[0], params->req_flow_ctrl[0]);
+       DP(NETIF_MSG_LINK, "(2) req_speed %d, req_flowctrl %d\n",
+                  params->req_line_speed[1], params->req_flow_ctrl[1]);
        vars->link_status = 0;
        vars->phy_link_up = 0;
        vars->link_up = 0;
@@ -5966,11 +6705,7 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
        vars->duplex = DUPLEX_FULL;
        vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
        vars->mac_type = MAC_TYPE_NONE;
-
-       if (params->switch_cfg ==  SWITCH_CFG_1G)
-               vars->phy_flags = PHY_SERDES_FLAG;
-       else
-               vars->phy_flags = PHY_XGXS_FLAG;
+       vars->phy_flags = 0;
 
        /* disable attentions */
        bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + params->port*4,
@@ -5981,6 +6716,13 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
 
        bnx2x_emac_init(params, vars);
 
+       if (params->num_phys == 0) {
+               DP(NETIF_MSG_LINK, "No phy found for initialization !!\n");
+               return -EINVAL;
+       }
+       set_phy_vars(params);
+
+       DP(NETIF_MSG_LINK, "Num of phys on board: %d\n", params->num_phys);
        if (CHIP_REV_IS_FPGA(bp)) {
 
                vars->link_up = 1;
@@ -6040,7 +6782,8 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
 
                vars->phy_flags = PHY_XGXS_FLAG;
 
-               bnx2x_phy_deassert(params, vars->phy_flags);
+               bnx2x_xgxs_deassert(params);
+
                /* set bmac loopback */
                bnx2x_bmac_enable(params, vars, 1);
 
@@ -6057,395 +6800,153 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
 
                vars->phy_flags = PHY_XGXS_FLAG;
 
-               bnx2x_phy_deassert(params, vars->phy_flags);
+               bnx2x_xgxs_deassert(params);
                /* set bmac loopback */
                bnx2x_emac_enable(params, vars, 1);
-               bnx2x_emac_program(params, vars->line_speed,
-                                             vars->duplex);
+               bnx2x_emac_program(params, vars);
                REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
                    params->port*4, 0);
 
-       } else if ((params->loopback_mode == LOOPBACK_XGXS_10) ||
+       } else if ((params->loopback_mode == LOOPBACK_XGXS) ||
                   (params->loopback_mode == LOOPBACK_EXT_PHY)) {
 
-               vars->link_up = 1;
-               vars->line_speed = SPEED_10000;
-               vars->duplex = DUPLEX_FULL;
-               vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
-
-               vars->phy_flags = PHY_XGXS_FLAG;
-
-               val = REG_RD(bp,
-                                NIG_REG_XGXS0_CTRL_PHY_ADDR+
-                                params->port*0x18);
-               params->phy_addr = (u8)val;
-
-               bnx2x_phy_deassert(params, vars->phy_flags);
-               bnx2x_link_initialize(params, vars);
-
-               vars->mac_type = MAC_TYPE_BMAC;
-
-               bnx2x_bmac_enable(params, vars, 0);
-
-               if (params->loopback_mode == LOOPBACK_XGXS_10) {
-                       /* set 10G XGXS loopback */
-                       bnx2x_set_xgxs_loopback(params, vars, 1);
-               } else {
-                       /* set external phy loopback */
-                       bnx2x_ext_phy_loopback(params);
-               }
-               REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
-                           params->port*4, 0);
-
-               bnx2x_set_led(params, LED_MODE_OPER, vars->line_speed);
-       } else
-       /* No loopback */
-       {
-               bnx2x_phy_deassert(params, vars->phy_flags);
-               switch (params->switch_cfg) {
-               case SWITCH_CFG_1G:
-                       vars->phy_flags |= PHY_SERDES_FLAG;
-                       if ((params->ext_phy_config &
-                            PORT_HW_CFG_SERDES_EXT_PHY_TYPE_MASK) ==
-                            PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482) {
-                               vars->phy_flags |= PHY_SGMII_FLAG;
-                       }
-
-                       val = REG_RD(bp,
-                                        NIG_REG_SERDES0_CTRL_PHY_ADDR+
-                                        params->port*0x10);
-
-                       params->phy_addr = (u8)val;
-
-                       break;
-               case SWITCH_CFG_10G:
-                       vars->phy_flags |= PHY_XGXS_FLAG;
-                       val = REG_RD(bp,
-                                NIG_REG_XGXS0_CTRL_PHY_ADDR+
-                                params->port*0x18);
-                       params->phy_addr = (u8)val;
-
-                       break;
-               default:
-                       DP(NETIF_MSG_LINK, "Invalid switch_cfg\n");
-                       return -EINVAL;
-               }
-               DP(NETIF_MSG_LINK, "Phy address = 0x%x\n", params->phy_addr);
-
-               bnx2x_link_initialize(params, vars);
-               msleep(30);
-               bnx2x_link_int_enable(params);
-       }
-       return 0;
-}
-
-static void bnx2x_8726_reset_phy(struct bnx2x *bp, u8 port, u8 ext_phy_addr)
-{
-       DP(NETIF_MSG_LINK, "bnx2x_8726_reset_phy port %d\n", port);
-
-       /* Set serial boot control for external load */
-       bnx2x_cl45_write(bp, port,
-                      PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726, ext_phy_addr,
-                      MDIO_PMA_DEVAD,
-                      MDIO_PMA_REG_GEN_CTRL, 0x0001);
-}
-
-u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
-                 u8 reset_ext_phy)
-{
-       struct bnx2x *bp = params->bp;
-       u32 ext_phy_config = params->ext_phy_config;
-       u8 port = params->port;
-       u32 ext_phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config);
-       u32 val = REG_RD(bp, params->shmem_base +
-                            offsetof(struct shmem_region, dev_info.
-                                     port_feature_config[params->port].
-                                     config));
-       DP(NETIF_MSG_LINK, "Resetting the link of port %d\n", port);
-       /* disable attentions */
-       vars->link_status = 0;
-       bnx2x_update_mng(params, vars->link_status);
-       bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
-                    (NIG_MASK_XGXS0_LINK_STATUS |
-                     NIG_MASK_XGXS0_LINK10G |
-                     NIG_MASK_SERDES0_LINK_STATUS |
-                     NIG_MASK_MI_INT));
-
-       /* activate nig drain */
-       REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
-
-       /* disable nig egress interface */
-       REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0);
-       REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0);
-
-       /* Stop BigMac rx */
-       bnx2x_bmac_rx_disable(bp, port);
-
-       /* disable emac */
-       REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
-
-       msleep(10);
-       /* The PHY reset is controled by GPIO 1
-        * Hold it as vars low
-        */
-        /* clear link led */
-       bnx2x_set_led(params, LED_MODE_OFF, 0);
-       if (reset_ext_phy) {
-               switch (ext_phy_type) {
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
-                       break;
-
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
-               {
-
-                       /* Disable Transmitter */
-                       u8 ext_phy_addr =
-                               XGXS_EXT_PHY_ADDR(params->ext_phy_config);
-                       if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
-                           PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
-                               bnx2x_sfp_set_transmitter(bp, port,
-                                       PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
-                                       ext_phy_addr, 0);
-                       break;
-               }
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
-                       DP(NETIF_MSG_LINK, "Setting 8073 port %d into "
-                                "low power mode\n",
-                                port);
-                       bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
-                                         MISC_REGISTERS_GPIO_OUTPUT_LOW,
-                                         port);
-                       break;
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
-               {
-                       u8 ext_phy_addr =
-                               XGXS_EXT_PHY_ADDR(params->ext_phy_config);
-                       /* Set soft reset */
-                       bnx2x_8726_reset_phy(bp, params->port, ext_phy_addr);
-                       break;
-               }
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823:
-               {
-                       u8 ext_phy_addr =
-                               XGXS_EXT_PHY_ADDR(params->ext_phy_config);
-                       bnx2x_cl45_write(bp, port,
-                                      PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
-                                      ext_phy_addr,
-                                      MDIO_AN_DEVAD,
-                                      MDIO_AN_REG_CTRL, 0x0000);
-                       bnx2x_cl45_write(bp, port,
-                                      PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
-                                      ext_phy_addr,
-                                      MDIO_PMA_DEVAD,
-                                      MDIO_PMA_REG_CTRL, 1);
-                       break;
-               }
-               default:
-                       /* HW reset */
-                       bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
-                                         MISC_REGISTERS_GPIO_OUTPUT_LOW,
-                                         port);
-                       bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
-                                         MISC_REGISTERS_GPIO_OUTPUT_LOW,
-                                         port);
-                       DP(NETIF_MSG_LINK, "reset external PHY\n");
-               }
-       }
-       /* reset the SerDes/XGXS */
-       REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR,
-              (0x1ff << (port*16)));
-
-       /* reset BigMac */
-       REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
-              (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
-
-       /* disable nig ingress interface */
-       REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0);
-       REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0);
-       REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0);
-       REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0);
-       vars->link_up = 0;
-       return 0;
-}
-
-static u8 bnx2x_update_link_down(struct link_params *params,
-                              struct link_vars *vars)
-{
-       struct bnx2x *bp = params->bp;
-       u8 port = params->port;
-
-       DP(NETIF_MSG_LINK, "Port %x: Link is down\n", port);
-       bnx2x_set_led(params, LED_MODE_OFF, 0);
-
-       /* indicate no mac active */
-       vars->mac_type = MAC_TYPE_NONE;
-
-       /* update shared memory */
-       vars->link_status = 0;
-       vars->line_speed = 0;
-       bnx2x_update_mng(params, vars->link_status);
-
-       /* activate nig drain */
-       REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
-
-       /* disable emac */
-       REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
-
-       msleep(10);
-
-       /* reset BigMac */
-       bnx2x_bmac_rx_disable(bp, params->port);
-       REG_WR(bp, GRCBASE_MISC +
-                  MISC_REGISTERS_RESET_REG_2_CLEAR,
-                  (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
-       return 0;
-}
-
-static u8 bnx2x_update_link_up(struct link_params *params,
-                            struct link_vars *vars,
-                            u8 link_10g, u32 gp_status)
-{
-       struct bnx2x *bp = params->bp;
-       u8 port = params->port;
-       u8 rc = 0;
+               vars->link_up = 1;
+               vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
+               vars->duplex = DUPLEX_FULL;
+               if (params->req_line_speed[0] == SPEED_1000) {
+                       vars->line_speed = SPEED_1000;
+                       vars->mac_type = MAC_TYPE_EMAC;
+               } else {
+                       vars->line_speed = SPEED_10000;
+                       vars->mac_type = MAC_TYPE_BMAC;
+               }
 
-       vars->link_status |= LINK_STATUS_LINK_UP;
-       if (link_10g) {
+               bnx2x_xgxs_deassert(params);
+               bnx2x_link_initialize(params, vars);
+
+               if (params->req_line_speed[0] == SPEED_1000) {
+                       bnx2x_emac_program(params, vars);
+                       bnx2x_emac_enable(params, vars, 0);
+               } else
                bnx2x_bmac_enable(params, vars, 0);
-               bnx2x_set_led(params, LED_MODE_OPER, SPEED_10000);
-       } else {
-               rc = bnx2x_emac_program(params, vars->line_speed,
-                                     vars->duplex);
 
-               bnx2x_emac_enable(params, vars, 0);
+               if (params->loopback_mode == LOOPBACK_XGXS) {
+                       /* set 10G XGXS loopback */
+                       params->phy[INT_PHY].config_loopback(
+                               &params->phy[INT_PHY],
+                               params);
 
-               /* AN complete? */
-               if (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) {
-                       if (!(vars->phy_flags &
-                             PHY_SGMII_FLAG))
-                               bnx2x_set_gmii_tx_driver(params);
+               } else {
+                       /* set external phy loopback */
+                       u8 phy_index;
+                       for (phy_index = EXT_PHY1;
+                             phy_index < params->num_phys; phy_index++) {
+                               if (params->phy[phy_index].config_loopback)
+                                       params->phy[phy_index].config_loopback(
+                                               &params->phy[phy_index],
+                                               params);
+                       }
                }
-       }
 
-       /* PBF - link up */
-       rc |= bnx2x_pbf_update(params, vars->flow_ctrl,
-                             vars->line_speed);
+               REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
+                           params->port*4, 0);
 
-       /* disable drain */
-       REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 0);
+               bnx2x_set_led(params, vars,
+                             LED_MODE_OPER, vars->line_speed);
+       } else
+       /* No loopback */
+       {
+               if (params->switch_cfg == SWITCH_CFG_10G)
+                       bnx2x_xgxs_deassert(params);
+               else
+                       bnx2x_serdes_deassert(bp, params->port);
 
-       /* update shared memory */
-       bnx2x_update_mng(params, vars->link_status);
-       msleep(20);
-       return rc;
+               bnx2x_link_initialize(params, vars);
+               msleep(30);
+               bnx2x_link_int_enable(params);
+       }
+       return 0;
 }
-/* This function should called upon link interrupt */
-/* In case vars->link_up, driver needs to
-       1. Update the pbf
-       2. Disable drain
-       3. Update the shared memory
-       4. Indicate link up
-       5. Set LEDs
-   Otherwise,
-       1. Update shared memory
-       2. Reset BigMac
-       3. Report link down
-       4. Unset LEDs
-*/
-u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars)
+u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
+                 u8 reset_ext_phy)
 {
        struct bnx2x *bp = params->bp;
-       u8 port = params->port;
-       u16 gp_status;
-       u8 link_10g;
-       u8 ext_phy_link_up, rc = 0;
-       u32 ext_phy_type;
-       u8 is_mi_int = 0;
+       u8 phy_index, port = params->port;
+       DP(NETIF_MSG_LINK, "Resetting the link of port %d\n", port);
+       /* disable attentions */
+       vars->link_status = 0;
+       bnx2x_update_mng(params, vars->link_status);
+       bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
+                    (NIG_MASK_XGXS0_LINK_STATUS |
+                     NIG_MASK_XGXS0_LINK10G |
+                     NIG_MASK_SERDES0_LINK_STATUS |
+                     NIG_MASK_MI_INT));
 
-       DP(NETIF_MSG_LINK, "port %x, XGXS?%x, int_status 0x%x\n",
-                port, (vars->phy_flags & PHY_XGXS_FLAG),
-                REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4));
+       /* activate nig drain */
+       REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
 
-       is_mi_int = (u8)(REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT +
-                                   port*0x18) > 0);
-       DP(NETIF_MSG_LINK, "int_mask 0x%x MI_INT %x, SERDES_LINK %x\n",
-                REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4),
-                is_mi_int,
-                REG_RD(bp,
-                           NIG_REG_SERDES0_STATUS_LINK_STATUS + port*0x3c));
+       /* disable nig egress interface */
+       REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0);
+       REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0);
 
-       DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n",
-         REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
-         REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68));
+       /* Stop BigMac rx */
+       bnx2x_bmac_rx_disable(bp, port);
 
        /* disable emac */
        REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
 
-       ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
-
-       /* Check external link change only for non-direct */
-       ext_phy_link_up = bnx2x_ext_phy_is_link_up(params, vars, is_mi_int);
-
-       /* Read gp_status */
-       CL45_RD_OVER_CL22(bp, port, params->phy_addr,
-                             MDIO_REG_BANK_GP_STATUS,
-                             MDIO_GP_STATUS_TOP_AN_STATUS1,
-                             &gp_status);
-
-       rc = bnx2x_link_settings_status(params, vars, gp_status,
-                                     ext_phy_link_up);
-       if (rc != 0)
-               return rc;
-
-       /* anything 10 and over uses the bmac */
-       link_10g = ((vars->line_speed == SPEED_10000) ||
-                   (vars->line_speed == SPEED_12000) ||
-                   (vars->line_speed == SPEED_12500) ||
-                   (vars->line_speed == SPEED_13000) ||
-                   (vars->line_speed == SPEED_15000) ||
-                   (vars->line_speed == SPEED_16000));
-
-       bnx2x_link_int_ack(params, vars, link_10g, is_mi_int);
-
-       /* In case external phy link is up, and internal link is down
-       ( not initialized yet probably after link initialization, it needs
-       to be initialized.
-       Note that after link down-up as result of cable plug,
-       the xgxs link would probably become up again without the need to
-       initialize it*/
-
-       if ((ext_phy_type != PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT) &&
-           (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) &&
-           (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706) &&
-           (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) &&
-           (ext_phy_link_up && !vars->phy_link_up))
-               bnx2x_init_internal_phy(params, vars, 0);
+       msleep(10);
+       /* The PHY reset is controled by GPIO 1
+        * Hold it as vars low
+        */
+        /* clear link led */
+       bnx2x_set_led(params, vars, LED_MODE_OFF, 0);
 
-       /* link is up only if both local phy and external phy are up */
-       vars->link_up = (ext_phy_link_up && vars->phy_link_up);
+       if (reset_ext_phy) {
+               for (phy_index = EXT_PHY1; phy_index < params->num_phys;
+                     phy_index++) {
+                       if (params->phy[phy_index].link_reset)
+                               params->phy[phy_index].link_reset(
+                                       &params->phy[phy_index],
+                                       params);
+               }
+       }
 
-       if (vars->link_up)
-               rc = bnx2x_update_link_up(params, vars, link_10g, gp_status);
-       else
-               rc = bnx2x_update_link_down(params, vars);
+       if (params->phy[INT_PHY].link_reset)
+               params->phy[INT_PHY].link_reset(
+                       &params->phy[INT_PHY], params);
+       /* reset BigMac */
+       REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
+              (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
 
-       return rc;
+       /* disable nig ingress interface */
+       REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0);
+       REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0);
+       REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0);
+       REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0);
+       vars->link_up = 0;
+       return 0;
 }
 
-static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp, u32 shmem_base)
+/****************************************************************************/
+/*                             Common function                             */
+/****************************************************************************/
+static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp, u32 shmem_base, u32 shmem2_base, u8 phy_index)
 {
-       u8 ext_phy_addr[PORT_MAX];
+       struct bnx2x_phy phy[PORT_MAX];
+       struct bnx2x_phy *phy_blk[PORT_MAX];
        u16 val;
        s8 port;
 
        /* PART1 - Reset both phys */
        for (port = PORT_MAX - 1; port >= PORT_0; port--) {
                /* Extract the ext phy address for the port */
-               u32 ext_phy_config = REG_RD(bp, shmem_base +
-                                       offsetof(struct shmem_region,
-                  dev_info.port_hw_config[port].external_phy_config));
-
+               if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base,
+                                      port, &phy[port]) !=
+                   0) {
+                       DP(NETIF_MSG_LINK, "populate_phy failed\n");
+                       return -EINVAL;
+               }
                /* disable attentions */
                bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
                             (NIG_MASK_XGXS0_LINK_STATUS |
@@ -6453,17 +6954,13 @@ static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp, u32 shmem_base)
                              NIG_MASK_SERDES0_LINK_STATUS |
                              NIG_MASK_MI_INT));
 
-               ext_phy_addr[port] = XGXS_EXT_PHY_ADDR(ext_phy_config);
-
                /* Need to take the phy out of low power mode in order
                        to write to access its registers */
                bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
                                  MISC_REGISTERS_GPIO_OUTPUT_HIGH, port);
 
                /* Reset the phy */
-               bnx2x_cl45_write(bp, port,
-                              PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
-                              ext_phy_addr[port],
+               bnx2x_cl45_write(bp, &phy[port],
                               MDIO_PMA_DEVAD,
                               MDIO_PMA_REG_CTRL,
                               1<<15);
@@ -6472,15 +6969,22 @@ static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp, u32 shmem_base)
        /* Add delay of 150ms after reset */
        msleep(150);
 
+       if (phy[PORT_0].addr & 0x1) {
+               phy_blk[PORT_0] = &(phy[PORT_1]);
+               phy_blk[PORT_1] = &(phy[PORT_0]);
+       } else {
+               phy_blk[PORT_0] = &(phy[PORT_0]);
+               phy_blk[PORT_1] = &(phy[PORT_1]);
+       }
+
        /* PART2 - Download firmware to both phys */
        for (port = PORT_MAX - 1; port >= PORT_0; port--) {
                u16 fw_ver1;
 
-               bnx2x_bcm8073_external_rom_boot(bp, port,
-                                             ext_phy_addr[port], shmem_base);
+               bnx2x_8073_8727_external_rom_boot(bp, phy_blk[port],
+                                                 port);
 
-               bnx2x_cl45_read(bp, port, PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
-                             ext_phy_addr[port],
+               bnx2x_cl45_read(bp, phy_blk[port],
                              MDIO_PMA_DEVAD,
                              MDIO_PMA_REG_ROM_VER1, &fw_ver1);
                if (fw_ver1 == 0 || fw_ver1 == 0x4321) {
@@ -6492,16 +6996,12 @@ static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp, u32 shmem_base)
                }
 
                /* Only set bit 10 = 1 (Tx power down) */
-               bnx2x_cl45_read(bp, port,
-                             PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
-                             ext_phy_addr[port],
+               bnx2x_cl45_read(bp, phy_blk[port],
                              MDIO_PMA_DEVAD,
                              MDIO_PMA_REG_TX_POWER_DOWN, &val);
 
                /* Phase1 of TX_POWER_DOWN reset */
-               bnx2x_cl45_write(bp, port,
-                              PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
-                              ext_phy_addr[port],
+               bnx2x_cl45_write(bp, phy_blk[port],
                               MDIO_PMA_DEVAD,
                               MDIO_PMA_REG_TX_POWER_DOWN,
                               (val | 1<<10));
@@ -6515,28 +7015,20 @@ static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp, u32 shmem_base)
        for (port = PORT_MAX - 1; port >= PORT_0; port--) {
                /* Phase2 of POWER_DOWN_RESET */
                /* Release bit 10 (Release Tx power down) */
-               bnx2x_cl45_read(bp, port,
-                             PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
-                             ext_phy_addr[port],
+               bnx2x_cl45_read(bp, phy_blk[port],
                              MDIO_PMA_DEVAD,
                              MDIO_PMA_REG_TX_POWER_DOWN, &val);
 
-               bnx2x_cl45_write(bp, port,
-                              PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
-                              ext_phy_addr[port],
+               bnx2x_cl45_write(bp, phy_blk[port],
                               MDIO_PMA_DEVAD,
                               MDIO_PMA_REG_TX_POWER_DOWN, (val & (~(1<<10))));
                msleep(15);
 
                /* Read modify write the SPI-ROM version select register */
-               bnx2x_cl45_read(bp, port,
-                             PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
-                             ext_phy_addr[port],
+               bnx2x_cl45_read(bp, phy_blk[port],
                              MDIO_PMA_DEVAD,
                              MDIO_PMA_REG_EDC_FFE_MAIN, &val);
-               bnx2x_cl45_write(bp, port,
-                             PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
-                             ext_phy_addr[port],
+               bnx2x_cl45_write(bp, phy_blk[port],
                              MDIO_PMA_DEVAD,
                              MDIO_PMA_REG_EDC_FFE_MAIN, (val | (1<<12)));
 
@@ -6545,33 +7037,74 @@ static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp, u32 shmem_base)
                                  MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
        }
        return 0;
-
 }
 
-static u8 bnx2x_8727_common_init_phy(struct bnx2x *bp, u32 shmem_base)
+static u8 bnx2x_8726_common_init_phy(struct bnx2x *bp, u32 shmem_base,
+                                    u32 shmem2_base, u8 phy_index)
+{
+       u32 val;
+       s8 port;
+       struct bnx2x_phy phy;
+       /* Use port1 because of the static port-swap */
+       /* Enable the module detection interrupt */
+       val = REG_RD(bp, MISC_REG_GPIO_EVENT_EN);
+       val |= ((1<<MISC_REGISTERS_GPIO_3)|
+               (1<<(MISC_REGISTERS_GPIO_3 + MISC_REGISTERS_GPIO_PORT_SHIFT)));
+       REG_WR(bp, MISC_REG_GPIO_EVENT_EN, val);
+
+       bnx2x_ext_phy_hw_reset(bp, 1);
+       msleep(5);
+       for (port = 0; port < PORT_MAX; port++) {
+               /* Extract the ext phy address for the port */
+               if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base,
+                                      port, &phy) !=
+                   0) {
+                       DP(NETIF_MSG_LINK, "populate phy failed\n");
+                       return -EINVAL;
+               }
+
+               /* Reset phy*/
+               bnx2x_cl45_write(bp, &phy,
+                                MDIO_PMA_DEVAD, MDIO_PMA_REG_GEN_CTRL, 0x0001);
+
+
+               /* Set fault module detected LED on */
+               bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
+                                 MISC_REGISTERS_GPIO_HIGH,
+                                 port);
+       }
+
+       return 0;
+}
+static u8 bnx2x_8727_common_init_phy(struct bnx2x *bp, u32 shmem_base,
+                                    u32 shmem2_base, u8 phy_index)
 {
-       u8 ext_phy_addr[PORT_MAX];
-       s8 port, first_port, i;
+       s8 port;
        u32 swap_val, swap_override;
+       struct bnx2x_phy phy[PORT_MAX];
+       struct bnx2x_phy *phy_blk[PORT_MAX];
        DP(NETIF_MSG_LINK, "Executing BCM8727 common init\n");
        swap_val = REG_RD(bp,  NIG_REG_PORT_SWAP);
        swap_override = REG_RD(bp,  NIG_REG_STRAP_OVERRIDE);
 
-       bnx2x_ext_phy_hw_reset(bp, 1 ^ (swap_val && swap_override));
-       msleep(5);
+       port = 1;
 
-       if (swap_val && swap_override)
-               first_port = PORT_0;
-       else
-               first_port = PORT_1;
+       bnx2x_ext_phy_hw_reset(bp, port ^ (swap_val && swap_override));
+
+       /* Calculate the port based on port swap */
+       port ^= (swap_val && swap_override);
+
+       msleep(5);
 
        /* PART1 - Reset both phys */
-       for (i = 0, port = first_port; i < PORT_MAX; i++, port = !port) {
+       for (port = PORT_MAX - 1; port >= PORT_0; port--) {
                /* Extract the ext phy address for the port */
-               u32 ext_phy_config = REG_RD(bp, shmem_base +
-                                       offsetof(struct shmem_region,
-                  dev_info.port_hw_config[port].external_phy_config));
-
+               if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base,
+                                      port, &phy[port]) !=
+                                      0) {
+                       DP(NETIF_MSG_LINK, "populate phy failed\n");
+                       return -EINVAL;
+               }
                /* disable attentions */
                bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
                             (NIG_MASK_XGXS0_LINK_STATUS |
@@ -6579,12 +7112,9 @@ static u8 bnx2x_8727_common_init_phy(struct bnx2x *bp, u32 shmem_base)
                              NIG_MASK_SERDES0_LINK_STATUS |
                              NIG_MASK_MI_INT));
 
-               ext_phy_addr[port] = XGXS_EXT_PHY_ADDR(ext_phy_config);
 
                /* Reset the phy */
-               bnx2x_cl45_write(bp, port,
-                              PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
-                              ext_phy_addr[port],
+               bnx2x_cl45_write(bp, &phy[port],
                               MDIO_PMA_DEVAD,
                               MDIO_PMA_REG_CTRL,
                               1<<15);
@@ -6592,16 +7122,20 @@ static u8 bnx2x_8727_common_init_phy(struct bnx2x *bp, u32 shmem_base)
 
        /* Add delay of 150ms after reset */
        msleep(150);
-
+       if (phy[PORT_0].addr & 0x1) {
+               phy_blk[PORT_0] = &(phy[PORT_1]);
+               phy_blk[PORT_1] = &(phy[PORT_0]);
+       } else {
+               phy_blk[PORT_0] = &(phy[PORT_0]);
+               phy_blk[PORT_1] = &(phy[PORT_1]);
+       }
        /* PART2 - Download firmware to both phys */
-       for (i = 0, port = first_port; i < PORT_MAX; i++, port = !port) {
+       for (port = PORT_MAX - 1; port >= PORT_0; port--) {
                u16 fw_ver1;
 
-               bnx2x_bcm8727_external_rom_boot(bp, port,
-                                             ext_phy_addr[port], shmem_base);
-
-               bnx2x_cl45_read(bp, port, PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
-                             ext_phy_addr[port],
+               bnx2x_8073_8727_external_rom_boot(bp, phy_blk[port],
+                                                 port);
+               bnx2x_cl45_read(bp, phy_blk[port],
                              MDIO_PMA_DEVAD,
                              MDIO_PMA_REG_ROM_VER1, &fw_ver1);
                if (fw_ver1 == 0 || fw_ver1 == 0x4321) {
@@ -6616,82 +7150,32 @@ static u8 bnx2x_8727_common_init_phy(struct bnx2x *bp, u32 shmem_base)
        return 0;
 }
 
-
-static u8 bnx2x_8726_common_init_phy(struct bnx2x *bp, u32 shmem_base)
-{
-       u8 ext_phy_addr;
-       u32 val;
-       s8 port;
-
-       /* Use port1 because of the static port-swap */
-       /* Enable the module detection interrupt */
-       val = REG_RD(bp, MISC_REG_GPIO_EVENT_EN);
-       val |= ((1<<MISC_REGISTERS_GPIO_3)|
-               (1<<(MISC_REGISTERS_GPIO_3 + MISC_REGISTERS_GPIO_PORT_SHIFT)));
-       REG_WR(bp, MISC_REG_GPIO_EVENT_EN, val);
-
-       bnx2x_ext_phy_hw_reset(bp, 1);
-       msleep(5);
-       for (port = 0; port < PORT_MAX; port++) {
-               /* Extract the ext phy address for the port */
-               u32 ext_phy_config = REG_RD(bp, shmem_base +
-                                       offsetof(struct shmem_region,
-                       dev_info.port_hw_config[port].external_phy_config));
-
-               ext_phy_addr = XGXS_EXT_PHY_ADDR(ext_phy_config);
-               DP(NETIF_MSG_LINK, "8726_common_init : ext_phy_addr = 0x%x\n",
-                        ext_phy_addr);
-
-               bnx2x_8726_reset_phy(bp, port, ext_phy_addr);
-
-               /* Set fault module detected LED on */
-               bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
-                                 MISC_REGISTERS_GPIO_HIGH,
-                                 port);
-       }
-
-       return 0;
-}
-
-
-static u8 bnx2x_84823_common_init_phy(struct bnx2x *bp, u32 shmem_base)
-{
-       /* HW reset */
-       bnx2x_ext_phy_hw_reset(bp, 1);
-       return 0;
-}
-u8 bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base)
+static u8 bnx2x_ext_phy_common_init(struct bnx2x *bp, u32 shmem_base,
+                                   u32 shmem2_base, u8 phy_index,
+                                   u32 ext_phy_type)
 {
        u8 rc = 0;
-       u32 ext_phy_type;
-
-       DP(NETIF_MSG_LINK, "Begin common phy init\n");
-
-       /* Read the ext_phy_type for arbitrary port(0) */
-       ext_phy_type = XGXS_EXT_PHY_TYPE(
-                       REG_RD(bp, shmem_base +
-                          offsetof(struct shmem_region,
-                            dev_info.port_hw_config[0].external_phy_config)));
 
        switch (ext_phy_type) {
        case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
-       {
-               rc = bnx2x_8073_common_init_phy(bp, shmem_base);
+               rc = bnx2x_8073_common_init_phy(bp, shmem_base,
+                                               shmem2_base, phy_index);
                break;
-       }
 
        case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
        case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC:
-               rc = bnx2x_8727_common_init_phy(bp, shmem_base);
+               rc = bnx2x_8727_common_init_phy(bp, shmem_base,
+                                               shmem2_base, phy_index);
                break;
 
        case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
                /* GPIO1 affects both ports, so there's need to pull
                it for single port alone */
-               rc = bnx2x_8726_common_init_phy(bp, shmem_base);
+               rc = bnx2x_8726_common_init_phy(bp, shmem_base,
+                                               shmem2_base, phy_index);
                break;
-       case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823:
-               rc = bnx2x_84823_common_init_phy(bp, shmem_base);
+       case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
+               rc = -EINVAL;
                break;
        default:
                DP(NETIF_MSG_LINK,
@@ -6703,33 +7187,80 @@ u8 bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base)
        return rc;
 }
 
-void bnx2x_sfx7101_sp_sw_reset(struct bnx2x *bp, u8 port, u8 phy_addr)
+u8 bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base,
+                        u32 shmem2_base)
 {
-       u16 val, cnt;
+       u8 rc = 0;
+       u8 phy_index;
+       u32 ext_phy_type, ext_phy_config;
+       DP(NETIF_MSG_LINK, "Begin common phy init\n");
 
-       bnx2x_cl45_read(bp, port,
-                     PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
-                     phy_addr,
-                     MDIO_PMA_DEVAD,
-                     MDIO_PMA_REG_7101_RESET, &val);
+       if (CHIP_REV_IS_EMUL(bp))
+               return 0;
 
-       for (cnt = 0; cnt < 10; cnt++) {
-               msleep(50);
-               /* Writes a self-clearing reset */
-               bnx2x_cl45_write(bp, port,
-                              PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
-                              phy_addr,
-                              MDIO_PMA_DEVAD,
-                              MDIO_PMA_REG_7101_RESET,
-                              (val | (1<<15)));
-               /* Wait for clear */
-               bnx2x_cl45_read(bp, port,
-                             PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
-                             phy_addr,
-                             MDIO_PMA_DEVAD,
-                             MDIO_PMA_REG_7101_RESET, &val);
+       /* Read the ext_phy_type for arbitrary port(0) */
+       for (phy_index = EXT_PHY1; phy_index < MAX_PHYS;
+             phy_index++) {
+               ext_phy_config = bnx2x_get_ext_phy_config(bp,
+                                                         shmem_base,
+                                                         phy_index, 0);
+               ext_phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config);
+               rc |= bnx2x_ext_phy_common_init(bp, shmem_base,
+                                               shmem2_base,
+                                               phy_index, ext_phy_type);
+       }
+       return rc;
+}
 
-               if ((val & (1<<15)) == 0)
-                       break;
+u8 bnx2x_hw_lock_required(struct bnx2x *bp, u32 shmem_base, u32 shmem2_base)
+{
+       u8 phy_index;
+       struct bnx2x_phy phy;
+       for (phy_index = INT_PHY; phy_index < MAX_PHYS;
+             phy_index++) {
+               if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base,
+                                      0, &phy) != 0) {
+                       DP(NETIF_MSG_LINK, "populate phy failed\n");
+                       return 0;
+               }
+
+               if (phy.flags & FLAGS_HW_LOCK_REQUIRED)
+                       return 1;
+       }
+       return 0;
+}
+
+u8 bnx2x_fan_failure_det_req(struct bnx2x *bp,
+                            u32 shmem_base,
+                            u32 shmem2_base,
+                            u8 port)
+{
+       u8 phy_index, fan_failure_det_req = 0;
+       struct bnx2x_phy phy;
+       for (phy_index = EXT_PHY1; phy_index < MAX_PHYS;
+             phy_index++) {
+               if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base,
+                                      port, &phy)
+                   != 0) {
+                       DP(NETIF_MSG_LINK, "populate phy failed\n");
+                       return 0;
+               }
+               fan_failure_det_req |= (phy.flags &
+                                       FLAGS_FAN_FAILURE_DET_REQ);
+       }
+       return fan_failure_det_req;
+}
+
+void bnx2x_hw_reset_phy(struct link_params *params)
+{
+       u8 phy_index;
+       for (phy_index = EXT_PHY1; phy_index < MAX_PHYS;
+             phy_index++) {
+               if (params->phy[phy_index].hw_reset) {
+                       params->phy[phy_index].hw_reset(
+                               &params->phy[phy_index],
+                               params);
+                       params->phy[phy_index] = phy_null;
+               }
        }
 }
index 40c2981de8edde699fbc0211da844ee046b12ed1..e98ea3d19471674140f9581a322a8095ddabe9b5 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright 2008-2009 Broadcom Corporation
+/* Copyright 2008-2010 Broadcom Corporation
  *
  * Unless you and Broadcom execute a separate written software license
  * agreement governing use of this software, this software is licensed to you
 #define SFP_EEPROM_PART_NO_ADDR                0x28
 #define SFP_EEPROM_PART_NO_SIZE                16
 #define PWR_FLT_ERR_MSG_LEN                    250
+
+#define XGXS_EXT_PHY_TYPE(ext_phy_config) \
+               ((ext_phy_config) & PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK)
+#define XGXS_EXT_PHY_ADDR(ext_phy_config) \
+               (((ext_phy_config) & PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> \
+                PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT)
+#define SERDES_EXT_PHY_TYPE(ext_phy_config) \
+               ((ext_phy_config) & PORT_HW_CFG_SERDES_EXT_PHY_TYPE_MASK)
+
+/* Single Media Direct board is the plain 577xx board with CX4/RJ45 jacks */
+#define SINGLE_MEDIA_DIRECT(params)    (params->num_phys == 1)
+/* Single Media board contains single external phy */
+#define SINGLE_MEDIA(params)           (params->num_phys == 2)
+/* Dual Media board contains two external phy with different media */
+#define DUAL_MEDIA(params)             (params->num_phys == 3)
+#define FW_PARAM_MDIO_CTRL_OFFSET 16
+#define FW_PARAM_SET(phy_addr, phy_type, mdio_access) \
+       (phy_addr | phy_type | mdio_access << FW_PARAM_MDIO_CTRL_OFFSET)
 /***********************************************************/
 /*                         Structs                         */
 /***********************************************************/
+#define INT_PHY                0
+#define EXT_PHY1       1
+#define EXT_PHY2       2
+#define MAX_PHYS       3
+
+/* Same configuration is shared between the XGXS and the first external phy */
+#define LINK_CONFIG_SIZE (MAX_PHYS - 1)
+#define LINK_CONFIG_IDX(_phy_idx) ((_phy_idx == INT_PHY) ? \
+                                        0 : (_phy_idx - 1))
+/***********************************************************/
+/*                      bnx2x_phy struct                     */
+/*  Defines the required arguments and function per phy    */
+/***********************************************************/
+struct link_vars;
+struct link_params;
+struct bnx2x_phy;
+
+typedef u8 (*config_init_t)(struct bnx2x_phy *phy, struct link_params *params,
+                           struct link_vars *vars);
+typedef u8 (*read_status_t)(struct bnx2x_phy *phy, struct link_params *params,
+                           struct link_vars *vars);
+typedef void (*link_reset_t)(struct bnx2x_phy *phy,
+                            struct link_params *params);
+typedef void (*config_loopback_t)(struct bnx2x_phy *phy,
+                                 struct link_params *params);
+typedef u8 (*format_fw_ver_t)(u32 raw, u8 *str, u16 *len);
+typedef void (*hw_reset_t)(struct bnx2x_phy *phy, struct link_params *params);
+typedef void (*set_link_led_t)(struct bnx2x_phy *phy,
+                              struct link_params *params, u8 mode);
+typedef void (*phy_specific_func_t)(struct bnx2x_phy *phy,
+                                   struct link_params *params, u32 action);
+
+struct bnx2x_phy {
+       u32 type;
+
+       /* Loaded during init */
+       u8 addr;
+
+       u8 flags;
+       /* Require HW lock */
+#define FLAGS_HW_LOCK_REQUIRED         (1<<0)
+       /* No Over-Current detection */
+#define FLAGS_NOC                      (1<<1)
+       /* Fan failure detection required */
+#define FLAGS_FAN_FAILURE_DET_REQ      (1<<2)
+       /* Initialize first the XGXS and only then the phy itself */
+#define FLAGS_INIT_XGXS_FIRST          (1<<3)
+#define FLAGS_REARM_LATCH_SIGNAL       (1<<6)
+#define FLAGS_SFP_NOT_APPROVED         (1<<7)
+
+       u8 def_md_devad;
+       u8 reserved;
+       /* preemphasis values for the rx side */
+       u16 rx_preemphasis[4];
+
+       /* preemphasis values for the tx side */
+       u16 tx_preemphasis[4];
+
+       /* EMAC address for access MDIO */
+       u32 mdio_ctrl;
+
+       u32 supported;
+
+       u32 media_type;
+#define        ETH_PHY_UNSPECIFIED 0x0
+#define        ETH_PHY_SFP_FIBER   0x1
+#define        ETH_PHY_XFP_FIBER   0x2
+#define        ETH_PHY_DA_TWINAX   0x3
+#define        ETH_PHY_BASE_T      0x4
+#define        ETH_PHY_NOT_PRESENT 0xff
+
+       /* The address in which version is located*/
+       u32 ver_addr;
+
+       u16 req_flow_ctrl;
+
+       u16 req_line_speed;
+
+       u32 speed_cap_mask;
+
+       u16 req_duplex;
+       u16 rsrv;
+       /* Called per phy/port init, and it configures LASI, speed, autoneg,
+        duplex, flow control negotiation, etc. */
+       config_init_t config_init;
+
+       /* Called due to interrupt. It determines the link, speed */
+       read_status_t read_status;
+
+       /* Called when driver is unloading. Should reset the phy */
+       link_reset_t link_reset;
+
+       /* Set the loopback configuration for the phy */
+       config_loopback_t config_loopback;
+
+       /* Format the given raw number into str up to len */
+       format_fw_ver_t format_fw_ver;
+
+       /* Reset the phy (both ports) */
+       hw_reset_t hw_reset;
+
+       /* Set link led mode (on/off/oper)*/
+       set_link_led_t set_link_led;
+
+       /* PHY Specific tasks */
+       phy_specific_func_t phy_specific_func;
+#define DISABLE_TX     1
+#define ENABLE_TX      2
+};
+
 /* Inputs parameters to the CLC */
 struct link_params {
 
@@ -59,56 +187,50 @@ struct link_params {
 #define LOOPBACK_NONE  0
 #define LOOPBACK_EMAC  1
 #define LOOPBACK_BMAC  2
-#define LOOPBACK_XGXS_10       3
+#define LOOPBACK_XGXS          3
 #define LOOPBACK_EXT_PHY       4
 #define LOOPBACK_EXT   5
 
-       u16 req_duplex;
-       u16 req_flow_ctrl;
-       u16 req_fc_auto_adv; /* Should be set to TX / BOTH when
-       req_flow_ctrl is set to AUTO */
-       u16 req_line_speed; /* Also determine AutoNeg */
-
        /* Device parameters */
        u8 mac_addr[6];
 
+       u16 req_duplex[LINK_CONFIG_SIZE];
+       u16 req_flow_ctrl[LINK_CONFIG_SIZE];
+
+       u16 req_line_speed[LINK_CONFIG_SIZE]; /* Also determine AutoNeg */
+
        /* shmem parameters */
        u32 shmem_base;
-       u32 speed_cap_mask;
+       u32 shmem2_base;
+       u32 speed_cap_mask[LINK_CONFIG_SIZE];
        u32 switch_cfg;
 #define SWITCH_CFG_1G          PORT_FEATURE_CON_SWITCH_1G_SWITCH
 #define SWITCH_CFG_10G         PORT_FEATURE_CON_SWITCH_10G_SWITCH
 #define SWITCH_CFG_AUTO_DETECT PORT_FEATURE_CON_SWITCH_AUTO_DETECT
 
-       u16 hw_led_mode; /* part of the hw_config read from the shmem */
-
-       /* phy_addr populated by the phy_init function */
-       u8 phy_addr;
-       /*u8 reserved1;*/
-
        u32 lane_config;
-       u32 ext_phy_config;
-#define XGXS_EXT_PHY_TYPE(ext_phy_config) \
-               ((ext_phy_config) & PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK)
-#define XGXS_EXT_PHY_ADDR(ext_phy_config) \
-               (((ext_phy_config) & PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> \
-                PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT)
-#define SERDES_EXT_PHY_TYPE(ext_phy_config) \
-               ((ext_phy_config) & PORT_HW_CFG_SERDES_EXT_PHY_TYPE_MASK)
 
        /* Phy register parameter */
        u32 chip_id;
 
-       u16 xgxs_config_rx[4]; /* preemphasis values for the rx side */
-       u16 xgxs_config_tx[4]; /* preemphasis values for the tx side */
-
        u32 feature_config_flags;
 #define FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED (1<<0)
 #define FEATURE_CONFIG_BC_SUPPORTS_OPT_MDL_VRFY        (1<<2)
-#define FEATURE_CONFIG_BCM8727_NOC                     (1<<3)
+#define FEATURE_CONFIG_BC_SUPPORTS_DUAL_PHY_OPT_MDL_VRFY       (1<<3)
+       /* Will be populated during common init */
+       struct bnx2x_phy phy[MAX_PHYS];
+
+       /* Will be populated during common init */
+       u8 num_phys;
+
+       u8 rsrv;
+       u16 hw_led_mode; /* part of the hw_config read from the shmem */
+       u32 multi_phy_config;
 
        /* Device pointer passed to all callback functions */
        struct bnx2x *bp;
+       u16 req_fc_auto_adv; /* Should be set to TX / BOTH when
+                               req_flow_ctrl is set to AUTO */
 };
 
 /* Output parameters */
@@ -129,12 +251,6 @@ struct link_vars {
        u16 flow_ctrl;
        u16 ieee_fc;
 
-       u32 autoneg;
-#define AUTO_NEG_DISABLED                      0x0
-#define AUTO_NEG_ENABLED                       0x1
-#define AUTO_NEG_COMPLETE                      0x2
-#define AUTO_NEG_PARALLEL_DETECTION_USED       0x3
-
        /* The same definitions as the shmem parameter */
        u32 link_status;
 };
@@ -142,8 +258,6 @@ struct link_vars {
 /***********************************************************/
 /*                         Functions                       */
 /***********************************************************/
-
-/* Initialize the phy */
 u8 bnx2x_phy_init(struct link_params *input, struct link_vars *output);
 
 /* Reset the link. Should be called when driver or interface goes down
@@ -155,17 +269,21 @@ u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
 /* bnx2x_link_update should be called upon link interrupt */
 u8 bnx2x_link_update(struct link_params *input, struct link_vars *output);
 
-/* use the following cl45 functions to read/write from external_phy
+/* use the following phy functions to read/write from external_phy
   In order to use it to read/write internal phy registers, use
   DEFAULT_PHY_DEV_ADDR as devad, and (_bank + (_addr & 0xf)) as
-  Use ext_phy_type of 0 in case of cl22 over cl45
   the register */
-u8 bnx2x_cl45_read(struct bnx2x *bp, u8 port, u32 ext_phy_type,
-                u8 phy_addr, u8 devad, u16 reg, u16 *ret_val);
+u8 bnx2x_phy_read(struct link_params *params, u8 phy_addr,
+                 u8 devad, u16 reg, u16 *ret_val);
+
+u8 bnx2x_phy_write(struct link_params *params, u8 phy_addr,
+                  u8 devad, u16 reg, u16 val);
 
-u8 bnx2x_cl45_write(struct bnx2x *bp, u8 port, u32 ext_phy_type,
-                 u8 phy_addr, u8 devad, u16 reg, u16 val);
+u8 bnx2x_cl45_read(struct bnx2x *bp, struct bnx2x_phy *phy,
+                  u8 devad, u16 reg, u16 *ret_val);
 
+u8 bnx2x_cl45_write(struct bnx2x *bp, struct bnx2x_phy *phy,
+                   u8 devad, u16 reg, u16 val);
 /* Reads the link_status from the shmem,
    and update the link vars accordingly */
 void bnx2x_link_status_update(struct link_params *input,
@@ -178,9 +296,12 @@ u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded,
    Basically, the CLC takes care of the led for the link, but in case one needs
    to set/unset the led unnaturally, set the "mode" to LED_MODE_OPER to
    blink the led, and LED_MODE_OFF to set the led off.*/
-u8 bnx2x_set_led(struct link_params *params, u8 mode, u32 speed);
-#define LED_MODE_OFF   0
-#define LED_MODE_OPER  2
+u8 bnx2x_set_led(struct link_params *params, struct link_vars *vars,
+                u8 mode, u32 speed);
+#define LED_MODE_OFF                   0
+#define LED_MODE_ON                    1
+#define LED_MODE_OPER                  2
+#define LED_MODE_FRONT_PANEL_OFF       3
 
 u8 bnx2x_override_led_value(struct bnx2x *bp, u8 port, u32 led_idx, u32 value);
 
@@ -190,17 +311,38 @@ void bnx2x_handle_module_detect_int(struct link_params *params);
 
 /* Get the actual link status. In case it returns 0, link is up,
        otherwise link is down*/
-u8 bnx2x_test_link(struct link_params *input, struct link_vars *vars);
+u8 bnx2x_test_link(struct link_params *input, struct link_vars *vars,
+                  u8 is_serdes);
 
 /* One-time initialization for external phy after power up */
-u8 bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base);
+u8 bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base, u32 shmem2_base);
 
 /* Reset the external PHY using GPIO */
 void bnx2x_ext_phy_hw_reset(struct bnx2x *bp, u8 port);
 
-void bnx2x_sfx7101_sp_sw_reset(struct bnx2x *bp, u8 port, u8 phy_addr);
+/* Reset the external of SFX7101 */
+void bnx2x_sfx7101_sp_sw_reset(struct bnx2x *bp, struct bnx2x_phy *phy);
 
-u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr,
+u8 bnx2x_read_sfp_module_eeprom(struct bnx2x_phy *phy,
+                               struct link_params *params, u16 addr,
                              u8 byte_cnt, u8 *o_buf);
 
+void bnx2x_hw_reset_phy(struct link_params *params);
+
+/* Checks if HW lock is required for this phy/board type */
+u8 bnx2x_hw_lock_required(struct bnx2x *bp, u32 shmem_base,
+                         u32 shmem2_base);
+
+/* Returns the aggregative supported attributes of the phys on board */
+u32 bnx2x_supported_attr(struct link_params *params, u8 phy_idx);
+
+/* Check swap bit and adjust PHY order */
+u32 bnx2x_phy_selection(struct link_params *params);
+
+/* Probe the phys on board, and populate them in "params" */
+u8 bnx2x_phy_probe(struct link_params *params);
+/* Checks if fan failure detection is required on one of the phys on board */
+u8 bnx2x_fan_failure_det_req(struct bnx2x *bp, u32 shmem_base,
+                            u32 shmem2_base, u8 port);
+
 #endif /* BNX2X_LINK_H */
index f8c3f08e4ce73fb4d5d37739fa7dd18cfc557da7..7ba3a6d96fd5e6f1c7ac4477869dac3d97cf8346 100644 (file)
@@ -781,7 +781,7 @@ static bool bnx2x_trylock_hw_lock(struct bnx2x *bp, u32 resource)
                DP(NETIF_MSG_HW,
                   "resource(0x%x) > HW_LOCK_MAX_RESOURCE_VALUE(0x%x)\n",
                   resource, HW_LOCK_MAX_RESOURCE_VALUE);
-               return -EINVAL;
+               return false;
        }
 
        if (func <= 5)
@@ -1227,26 +1227,66 @@ static int bnx2x_set_spio(struct bnx2x *bp, int spio_num, u32 mode)
        return 0;
 }
 
+int bnx2x_get_link_cfg_idx(struct bnx2x *bp)
+{
+       u32 sel_phy_idx = 0;
+       if (bp->link_vars.link_up) {
+               sel_phy_idx = EXT_PHY1;
+               /* In case link is SERDES, check if the EXT_PHY2 is the one */
+               if ((bp->link_vars.link_status & LINK_STATUS_SERDES_LINK) &&
+                   (bp->link_params.phy[EXT_PHY2].supported & SUPPORTED_FIBRE))
+                       sel_phy_idx = EXT_PHY2;
+       } else {
+
+               switch (bnx2x_phy_selection(&bp->link_params)) {
+               case PORT_HW_CFG_PHY_SELECTION_HARDWARE_DEFAULT:
+               case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY:
+               case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY:
+                      sel_phy_idx = EXT_PHY1;
+                      break;
+               case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY:
+               case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY:
+                      sel_phy_idx = EXT_PHY2;
+                      break;
+               }
+       }
+       /*
+       * The selected actived PHY is always after swapping (in case PHY
+       * swapping is enabled). So when swapping is enabled, we need to reverse
+       * the configuration
+       */
+
+       if (bp->link_params.multi_phy_config &
+           PORT_HW_CFG_PHY_SWAPPED_ENABLED) {
+               if (sel_phy_idx == EXT_PHY1)
+                       sel_phy_idx = EXT_PHY2;
+               else if (sel_phy_idx == EXT_PHY2)
+                       sel_phy_idx = EXT_PHY1;
+       }
+       return LINK_CONFIG_IDX(sel_phy_idx);
+}
+
 void bnx2x_calc_fc_adv(struct bnx2x *bp)
 {
+       u8 cfg_idx = bnx2x_get_link_cfg_idx(bp);
        switch (bp->link_vars.ieee_fc &
                MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK) {
        case MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_NONE:
-               bp->port.advertising &= ~(ADVERTISED_Asym_Pause |
+               bp->port.advertising[cfg_idx] &= ~(ADVERTISED_Asym_Pause |
                                          ADVERTISED_Pause);
                break;
 
        case MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH:
-               bp->port.advertising |= (ADVERTISED_Asym_Pause |
+               bp->port.advertising[cfg_idx] |= (ADVERTISED_Asym_Pause |
                                         ADVERTISED_Pause);
                break;
 
        case MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC:
-               bp->port.advertising |= ADVERTISED_Asym_Pause;
+               bp->port.advertising[cfg_idx] |= ADVERTISED_Asym_Pause;
                break;
 
        default:
-               bp->port.advertising &= ~(ADVERTISED_Asym_Pause |
+               bp->port.advertising[cfg_idx] &= ~(ADVERTISED_Asym_Pause |
                                          ADVERTISED_Pause);
                break;
        }
@@ -1257,7 +1297,8 @@ u8 bnx2x_initial_phy_init(struct bnx2x *bp, int load_mode)
 {
        if (!BP_NOMCP(bp)) {
                u8 rc;
-
+               int cfx_idx = bnx2x_get_link_cfg_idx(bp);
+               u16 req_line_speed = bp->link_params.req_line_speed[cfx_idx];
                /* Initialize link parameters structure variables */
                /* It is recommended to turn off RX FC for jumbo frames
                   for better performance */
@@ -1268,8 +1309,10 @@ u8 bnx2x_initial_phy_init(struct bnx2x *bp, int load_mode)
 
                bnx2x_acquire_phy_lock(bp);
 
-               if (load_mode == LOAD_DIAG)
-                       bp->link_params.loopback_mode = LOOPBACK_XGXS_10;
+               if (load_mode == LOAD_DIAG) {
+                       bp->link_params.loopback_mode = LOOPBACK_XGXS;
+                       bp->link_params.req_line_speed[cfx_idx] = SPEED_10000;
+               }
 
                rc = bnx2x_phy_init(&bp->link_params, &bp->link_vars);
 
@@ -1281,7 +1324,7 @@ u8 bnx2x_initial_phy_init(struct bnx2x *bp, int load_mode)
                        bnx2x_stats_handle(bp, STATS_EVENT_LINK_UP);
                        bnx2x_link_report(bp);
                }
-
+               bp->link_params.req_line_speed[cfx_idx] = req_line_speed;
                return rc;
        }
        BNX2X_ERR("Bootcode is missing - can not initialize link\n");
@@ -1292,6 +1335,7 @@ void bnx2x_link_set(struct bnx2x *bp)
 {
        if (!BP_NOMCP(bp)) {
                bnx2x_acquire_phy_lock(bp);
+               bnx2x_link_reset(&bp->link_params, &bp->link_vars, 1);
                bnx2x_phy_init(&bp->link_params, &bp->link_vars);
                bnx2x_release_phy_lock(bp);
 
@@ -1310,13 +1354,14 @@ static void bnx2x__link_reset(struct bnx2x *bp)
                BNX2X_ERR("Bootcode is missing - can not reset link\n");
 }
 
-u8 bnx2x_link_test(struct bnx2x *bp)
+u8 bnx2x_link_test(struct bnx2x *bp, u8 is_serdes)
 {
        u8 rc = 0;
 
        if (!BP_NOMCP(bp)) {
                bnx2x_acquire_phy_lock(bp);
-               rc = bnx2x_test_link(&bp->link_params, &bp->link_vars);
+               rc = bnx2x_test_link(&bp->link_params, &bp->link_vars,
+                                    is_serdes);
                bnx2x_release_phy_lock(bp);
        } else
                BNX2X_ERR("Bootcode is missing - can not test link\n");
@@ -1585,7 +1630,7 @@ static void bnx2x_pmf_update(struct bnx2x *bp)
  */
 
 /* send the MCP a request, block until there is a reply */
-u32 bnx2x_fw_command(struct bnx2x *bp, u32 command)
+u32 bnx2x_fw_command(struct bnx2x *bp, u32 command, u32 param)
 {
        int func = BP_FUNC(bp);
        u32 seq = ++bp->fw_seq;
@@ -1594,6 +1639,7 @@ u32 bnx2x_fw_command(struct bnx2x *bp, u32 command)
        u8 delay = CHIP_REV_IS_SLOW(bp) ? 100 : 10;
 
        mutex_lock(&bp->fw_mb_mutex);
+       SHMEM_WR(bp, func_mb[func].drv_mb_param, param);
        SHMEM_WR(bp, func_mb[func].drv_mb_header, (command | seq));
        DP(BNX2X_MSG_MCP, "wrote command (%x) to FW MB\n", (command | seq));
 
@@ -1715,9 +1761,9 @@ static void bnx2x_dcc_event(struct bnx2x *bp, u32 dcc_event)
 
        /* Report results to MCP */
        if (dcc_event)
-               bnx2x_fw_command(bp, DRV_MSG_CODE_DCC_FAILURE);
+               bnx2x_fw_command(bp, DRV_MSG_CODE_DCC_FAILURE, 0);
        else
-               bnx2x_fw_command(bp, DRV_MSG_CODE_DCC_OK);
+               bnx2x_fw_command(bp, DRV_MSG_CODE_DCC_OK, 0);
 }
 
 /* must be called under the spq lock */
@@ -1959,12 +2005,16 @@ static void bnx2x_attn_int_asserted(struct bnx2x *bp, u32 asserted)
 static inline void bnx2x_fan_failure(struct bnx2x *bp)
 {
        int port = BP_PORT(bp);
-
+       u32 ext_phy_config;
        /* mark the failure */
-       bp->link_params.ext_phy_config &= ~PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK;
-       bp->link_params.ext_phy_config |= PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE;
+       ext_phy_config =
+               SHMEM_RD(bp,
+                        dev_info.port_hw_config[port].external_phy_config);
+
+       ext_phy_config &= ~PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK;
+       ext_phy_config |= PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE;
        SHMEM_WR(bp, dev_info.port_hw_config[port].external_phy_config,
-                bp->link_params.ext_phy_config);
+                ext_phy_config);
 
        /* log the failure */
        netdev_err(bp->dev, "Fan Failure on Network Controller has caused"
@@ -1976,7 +2026,7 @@ static inline void bnx2x_attn_int_deasserted0(struct bnx2x *bp, u32 attn)
 {
        int port = BP_PORT(bp);
        int reg_offset;
-       u32 val, swap_val, swap_override;
+       u32 val;
 
        reg_offset = (port ? MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0 :
                             MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0);
@@ -1990,30 +2040,7 @@ static inline void bnx2x_attn_int_deasserted0(struct bnx2x *bp, u32 attn)
                BNX2X_ERR("SPIO5 hw attention\n");
 
                /* Fan failure attention */
-               switch (XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config)) {
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
-                       /* Low power mode is controlled by GPIO 2 */
-                       bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
-                                      MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
-                       /* The PHY reset is controlled by GPIO 1 */
-                       bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
-                                      MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
-                       break;
-
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
-                       /* The PHY reset is controlled by GPIO 1 */
-                       /* fake the port number to cancel the swap done in
-                          set_gpio() */
-                       swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
-                       swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
-                       port = (swap_val && swap_override) ^ 1;
-                       bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
-                                      MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
-                       break;
-
-               default:
-                       break;
-               }
+               bnx2x_hw_reset_phy(&bp->link_params);
                bnx2x_fan_failure(bp);
        }
 
@@ -3803,10 +3830,9 @@ static const struct {
 
 static void enable_blocks_parity(struct bnx2x *bp)
 {
-       int i, mask_arr_len =
-               sizeof(bnx2x_parity_mask)/(sizeof(bnx2x_parity_mask[0]));
+       int i;
 
-       for (i = 0; i < mask_arr_len; i++)
+       for (i = 0; i < ARRAY_SIZE(bnx2x_parity_mask); i++)
                REG_WR(bp, bnx2x_parity_mask[i].addr,
                        bnx2x_parity_mask[i].mask);
 }
@@ -3862,17 +3888,12 @@ static void bnx2x_setup_fan_failure_detection(struct bnx2x *bp)
         */
        else if (val == SHARED_HW_CFG_FAN_FAILURE_PHY_TYPE)
                for (port = PORT_0; port < PORT_MAX; port++) {
-                       u32 phy_type =
-                               SHMEM_RD(bp, dev_info.port_hw_config[port].
-                                        external_phy_config) &
-                               PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK;
                        is_required |=
-                               ((phy_type ==
-                                 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101) ||
-                                (phy_type ==
-                                 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727) ||
-                                (phy_type ==
-                                 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481));
+                               bnx2x_fan_failure_det_req(
+                                       bp,
+                                       bp->common.shmem_base,
+                                       bp->common.shmem2_base,
+                                       port);
                }
 
        DP(NETIF_MSG_HW, "fan detection setting: %d\n", is_required);
@@ -4139,17 +4160,9 @@ static int bnx2x_init_common(struct bnx2x *bp)
                return -EBUSY;
        }
 
-       switch (XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config)) {
-       case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
-       case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
-       case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
-       case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
-               bp->port.need_hw_lock = 1;
-               break;
-
-       default:
-               break;
-       }
+       bp->port.need_hw_lock = bnx2x_hw_lock_required(bp,
+                                                      bp->common.shmem_base,
+                                                      bp->common.shmem2_base);
 
        bnx2x_setup_fan_failure_detection(bp);
 
@@ -4162,7 +4175,8 @@ static int bnx2x_init_common(struct bnx2x *bp)
 
        if (!BP_NOMCP(bp)) {
                bnx2x_acquire_phy_lock(bp);
-               bnx2x_common_init_phy(bp, bp->common.shmem_base);
+               bnx2x_common_init_phy(bp, bp->common.shmem_base,
+                                     bp->common.shmem2_base);
                bnx2x_release_phy_lock(bp);
        } else
                BNX2X_ERR("Bootcode is missing - can not initialize link\n");
@@ -4297,60 +4311,17 @@ static int bnx2x_init_port(struct bnx2x *bp)
 
        bnx2x_init_block(bp, MCP_BLOCK, init_stage);
        bnx2x_init_block(bp, DMAE_BLOCK, init_stage);
-
-       switch (XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config)) {
-       case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
-               {
-               u32 swap_val, swap_override, aeu_gpio_mask, offset;
-
-               bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3,
-                              MISC_REGISTERS_GPIO_INPUT_HI_Z, port);
-
-               /* The GPIO should be swapped if the swap register is
-                  set and active */
-               swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
-               swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
-
-               /* Select function upon port-swap configuration */
-               if (port == 0) {
-                       offset = MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0;
-                       aeu_gpio_mask = (swap_val && swap_override) ?
-                               AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_1 :
-                               AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_0;
-               } else {
-                       offset = MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0;
-                       aeu_gpio_mask = (swap_val && swap_override) ?
-                               AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_0 :
-                               AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_1;
-               }
-               val = REG_RD(bp, offset);
-               /* add GPIO3 to group */
-               val |= aeu_gpio_mask;
-               REG_WR(bp, offset, val);
-               }
-               bp->port.need_hw_lock = 1;
-               break;
-
-       case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
-               bp->port.need_hw_lock = 1;
-       case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
-               /* add SPIO 5 to group 0 */
-               {
+       bp->port.need_hw_lock = bnx2x_hw_lock_required(bp,
+                                                      bp->common.shmem_base,
+                                                      bp->common.shmem2_base);
+       if (bnx2x_fan_failure_det_req(bp, bp->common.shmem_base,
+                                     bp->common.shmem2_base, port)) {
                u32 reg_addr = (port ? MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0 :
                                       MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0);
                val = REG_RD(bp, reg_addr);
                val |= AEU_INPUTS_ATTN_BITS_SPIO5;
                REG_WR(bp, reg_addr, val);
-               }
-               break;
-       case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
-       case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
-               bp->port.need_hw_lock = 1;
-               break;
-       default:
-               break;
        }
-
        bnx2x__link_reset(bp);
 
        return 0;
@@ -4480,7 +4451,7 @@ static int bnx2x_init_func(struct bnx2x *bp)
        /* Reset PCIE errors for debug */
        REG_WR(bp, 0x2114, 0xffffffff);
        REG_WR(bp, 0x2120, 0xffffffff);
-
+       bnx2x_phy_probe(&bp->link_params);
        return 0;
 }
 
@@ -5302,7 +5273,7 @@ void bnx2x_chip_cleanup(struct bnx2x *bp, int unload_mode)
 
 unload_error:
        if (!BP_NOMCP(bp))
-               reset_code = bnx2x_fw_command(bp, reset_code);
+               reset_code = bnx2x_fw_command(bp, reset_code, 0);
        else {
                DP(NETIF_MSG_IFDOWN, "NO MCP - load counts      %d, %d, %d\n",
                   load_count[0], load_count[1], load_count[2]);
@@ -5327,7 +5298,7 @@ unload_error:
 
        /* Report UNLOAD_DONE to MCP */
        if (!BP_NOMCP(bp))
-               bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_DONE);
+               bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_DONE, 0);
 
 }
 
@@ -5892,13 +5863,14 @@ static void __devinit bnx2x_undi_unload(struct bnx2x *bp)
                        bp->fw_seq =
                               (SHMEM_RD(bp, func_mb[bp->func].drv_mb_header) &
                                DRV_MSG_SEQ_NUMBER_MASK);
-                       reset_code = bnx2x_fw_command(bp, reset_code);
+                       reset_code = bnx2x_fw_command(bp, reset_code, 0);
 
                        /* if UNDI is loaded on the other port */
                        if (reset_code != FW_MSG_CODE_DRV_UNLOAD_COMMON) {
 
                                /* send "DONE" for previous unload */
-                               bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_DONE);
+                               bnx2x_fw_command(bp,
+                                                DRV_MSG_CODE_UNLOAD_DONE, 0);
 
                                /* unload UNDI on port 1 */
                                bp->func = 1;
@@ -5907,7 +5879,7 @@ static void __devinit bnx2x_undi_unload(struct bnx2x *bp)
                                        DRV_MSG_SEQ_NUMBER_MASK);
                                reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_DIS;
 
-                               bnx2x_fw_command(bp, reset_code);
+                               bnx2x_fw_command(bp, reset_code, 0);
                        }
 
                        /* now it's safe to release the lock */
@@ -5949,7 +5921,7 @@ static void __devinit bnx2x_undi_unload(struct bnx2x *bp)
                        REG_WR(bp, NIG_REG_STRAP_OVERRIDE, swap_en);
 
                        /* send unload done to the MCP */
-                       bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_DONE);
+                       bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_DONE, 0);
 
                        /* restore our func and fw_seq */
                        bp->func = func;
@@ -5997,6 +5969,7 @@ static void __devinit bnx2x_get_common_hwinfo(struct bnx2x *bp)
        bp->common.shmem_base = REG_RD(bp, MISC_REG_SHARED_MEM_ADDR);
        bp->common.shmem2_base = REG_RD(bp, MISC_REG_GENERIC_CR_0);
        bp->link_params.shmem_base = bp->common.shmem_base;
+       bp->link_params.shmem2_base = bp->common.shmem2_base;
        BNX2X_DEV_INFO("shmem offset 0x%x  shmem2 offset 0x%x\n",
                       bp->common.shmem_base, bp->common.shmem2_base);
 
@@ -6039,8 +6012,11 @@ static void __devinit bnx2x_get_common_hwinfo(struct bnx2x *bp)
                            "please upgrade BC\n", BNX2X_BC_VER, val);
        }
        bp->link_params.feature_config_flags |=
-               (val >= REQ_BC_VER_4_VRFY_OPT_MDL) ?
+                               (val >= REQ_BC_VER_4_VRFY_FIRST_PHY_OPT_MDL) ?
                FEATURE_CONFIG_BC_SUPPORTS_OPT_MDL_VRFY : 0;
+       bp->link_params.feature_config_flags |=
+               (val >= REQ_BC_VER_4_VRFY_SPECIFIC_PHY_OPT_MDL) ?
+               FEATURE_CONFIG_BC_SUPPORTS_DUAL_PHY_OPT_MDL_VRFY : 0;
 
        if (BP_E1HVN(bp) == 0) {
                pci_read_config_word(bp->pdev, bp->pm_cap + PCI_PM_PMC, &pmc);
@@ -6064,194 +6040,55 @@ static void __devinit bnx2x_get_common_hwinfo(struct bnx2x *bp)
 static void __devinit bnx2x_link_settings_supported(struct bnx2x *bp,
                                                    u32 switch_cfg)
 {
-       int port = BP_PORT(bp);
-       u32 ext_phy_type;
-
-       switch (switch_cfg) {
-       case SWITCH_CFG_1G:
-               BNX2X_DEV_INFO("switch_cfg 0x%x (1G)\n", switch_cfg);
-
-               ext_phy_type =
-                       SERDES_EXT_PHY_TYPE(bp->link_params.ext_phy_config);
-               switch (ext_phy_type) {
-               case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT:
-                       BNX2X_DEV_INFO("ext_phy_type 0x%x (Direct)\n",
-                                      ext_phy_type);
-
-                       bp->port.supported |= (SUPPORTED_10baseT_Half |
-                                              SUPPORTED_10baseT_Full |
-                                              SUPPORTED_100baseT_Half |
-                                              SUPPORTED_100baseT_Full |
-                                              SUPPORTED_1000baseT_Full |
-                                              SUPPORTED_2500baseX_Full |
-                                              SUPPORTED_TP |
-                                              SUPPORTED_FIBRE |
-                                              SUPPORTED_Autoneg |
-                                              SUPPORTED_Pause |
-                                              SUPPORTED_Asym_Pause);
-                       break;
+       int cfg_size = 0, idx, port = BP_PORT(bp);
 
-               case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482:
-                       BNX2X_DEV_INFO("ext_phy_type 0x%x (5482)\n",
-                                      ext_phy_type);
-
-                       bp->port.supported |= (SUPPORTED_10baseT_Half |
-                                              SUPPORTED_10baseT_Full |
-                                              SUPPORTED_100baseT_Half |
-                                              SUPPORTED_100baseT_Full |
-                                              SUPPORTED_1000baseT_Full |
-                                              SUPPORTED_TP |
-                                              SUPPORTED_FIBRE |
-                                              SUPPORTED_Autoneg |
-                                              SUPPORTED_Pause |
-                                              SUPPORTED_Asym_Pause);
-                       break;
+       /* Aggregation of supported attributes of all external phys */
+       bp->port.supported[0] = 0;
+       bp->port.supported[1] = 0;
+       switch (bp->link_params.num_phys) {
+       case 1:
+               bp->port.supported[0] = bp->link_params.phy[INT_PHY].supported;
+               cfg_size = 1;
+               break;
+       case 2:
+               bp->port.supported[0] = bp->link_params.phy[EXT_PHY1].supported;
+               cfg_size = 1;
+               break;
+       case 3:
+               if (bp->link_params.multi_phy_config &
+                   PORT_HW_CFG_PHY_SWAPPED_ENABLED) {
+                       bp->port.supported[1] =
+                               bp->link_params.phy[EXT_PHY1].supported;
+                       bp->port.supported[0] =
+                               bp->link_params.phy[EXT_PHY2].supported;
+               } else {
+                       bp->port.supported[0] =
+                               bp->link_params.phy[EXT_PHY1].supported;
+                       bp->port.supported[1] =
+                               bp->link_params.phy[EXT_PHY2].supported;
+               }
+               cfg_size = 2;
+               break;
+       }
 
-               default:
-                       BNX2X_ERR("NVRAM config error. "
-                                 "BAD SerDes ext_phy_config 0x%x\n",
-                                 bp->link_params.ext_phy_config);
+       if (!(bp->port.supported[0] || bp->port.supported[1])) {
+               BNX2X_ERR("NVRAM config error. BAD phy config."
+                         "PHY1 config 0x%x, PHY2 config 0x%x\n",
+                          SHMEM_RD(bp,
+                          dev_info.port_hw_config[port].external_phy_config),
+                          SHMEM_RD(bp,
+                          dev_info.port_hw_config[port].external_phy_config2));
                        return;
                }
 
+       switch (switch_cfg) {
+       case SWITCH_CFG_1G:
                bp->port.phy_addr = REG_RD(bp, NIG_REG_SERDES0_CTRL_PHY_ADDR +
                                           port*0x10);
                BNX2X_DEV_INFO("phy_addr 0x%x\n", bp->port.phy_addr);
                break;
 
        case SWITCH_CFG_10G:
-               BNX2X_DEV_INFO("switch_cfg 0x%x (10G)\n", switch_cfg);
-
-               ext_phy_type =
-                       XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config);
-               switch (ext_phy_type) {
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
-                       BNX2X_DEV_INFO("ext_phy_type 0x%x (Direct)\n",
-                                      ext_phy_type);
-
-                       bp->port.supported |= (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);
-                       break;
-
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
-                       BNX2X_DEV_INFO("ext_phy_type 0x%x (8072)\n",
-                                      ext_phy_type);
-
-                       bp->port.supported |= (SUPPORTED_10000baseT_Full |
-                                              SUPPORTED_1000baseT_Full |
-                                              SUPPORTED_FIBRE |
-                                              SUPPORTED_Autoneg |
-                                              SUPPORTED_Pause |
-                                              SUPPORTED_Asym_Pause);
-                       break;
-
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
-                       BNX2X_DEV_INFO("ext_phy_type 0x%x (8073)\n",
-                                      ext_phy_type);
-
-                       bp->port.supported |= (SUPPORTED_10000baseT_Full |
-                                              SUPPORTED_2500baseX_Full |
-                                              SUPPORTED_1000baseT_Full |
-                                              SUPPORTED_FIBRE |
-                                              SUPPORTED_Autoneg |
-                                              SUPPORTED_Pause |
-                                              SUPPORTED_Asym_Pause);
-                       break;
-
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
-                       BNX2X_DEV_INFO("ext_phy_type 0x%x (8705)\n",
-                                      ext_phy_type);
-
-                       bp->port.supported |= (SUPPORTED_10000baseT_Full |
-                                              SUPPORTED_FIBRE |
-                                              SUPPORTED_Pause |
-                                              SUPPORTED_Asym_Pause);
-                       break;
-
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
-                       BNX2X_DEV_INFO("ext_phy_type 0x%x (8706)\n",
-                                      ext_phy_type);
-
-                       bp->port.supported |= (SUPPORTED_10000baseT_Full |
-                                              SUPPORTED_1000baseT_Full |
-                                              SUPPORTED_FIBRE |
-                                              SUPPORTED_Pause |
-                                              SUPPORTED_Asym_Pause);
-                       break;
-
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
-                       BNX2X_DEV_INFO("ext_phy_type 0x%x (8726)\n",
-                                      ext_phy_type);
-
-                       bp->port.supported |= (SUPPORTED_10000baseT_Full |
-                                              SUPPORTED_1000baseT_Full |
-                                              SUPPORTED_Autoneg |
-                                              SUPPORTED_FIBRE |
-                                              SUPPORTED_Pause |
-                                              SUPPORTED_Asym_Pause);
-                       break;
-
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
-                       BNX2X_DEV_INFO("ext_phy_type 0x%x (8727)\n",
-                                      ext_phy_type);
-
-                       bp->port.supported |= (SUPPORTED_10000baseT_Full |
-                                              SUPPORTED_1000baseT_Full |
-                                              SUPPORTED_Autoneg |
-                                              SUPPORTED_FIBRE |
-                                              SUPPORTED_Pause |
-                                              SUPPORTED_Asym_Pause);
-                       break;
-
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
-                       BNX2X_DEV_INFO("ext_phy_type 0x%x (SFX7101)\n",
-                                      ext_phy_type);
-
-                       bp->port.supported |= (SUPPORTED_10000baseT_Full |
-                                              SUPPORTED_TP |
-                                              SUPPORTED_Autoneg |
-                                              SUPPORTED_Pause |
-                                              SUPPORTED_Asym_Pause);
-                       break;
-
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
-                       BNX2X_DEV_INFO("ext_phy_type 0x%x (BCM8481)\n",
-                                      ext_phy_type);
-
-                       bp->port.supported |= (SUPPORTED_10baseT_Half |
-                                              SUPPORTED_10baseT_Full |
-                                              SUPPORTED_100baseT_Half |
-                                              SUPPORTED_100baseT_Full |
-                                              SUPPORTED_1000baseT_Full |
-                                              SUPPORTED_10000baseT_Full |
-                                              SUPPORTED_TP |
-                                              SUPPORTED_Autoneg |
-                                              SUPPORTED_Pause |
-                                              SUPPORTED_Asym_Pause);
-                       break;
-
-               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
-                       BNX2X_ERR("XGXS PHY Failure detected 0x%x\n",
-                                 bp->link_params.ext_phy_config);
-                       break;
-
-               default:
-                       BNX2X_ERR("NVRAM config error. "
-                                 "BAD XGXS ext_phy_config 0x%x\n",
-                                 bp->link_params.ext_phy_config);
-                       return;
-               }
-
                bp->port.phy_addr = REG_RD(bp, NIG_REG_XGXS0_CTRL_PHY_ADDR +
                                           port*0x18);
                BNX2X_DEV_INFO("phy_addr 0x%x\n", bp->port.phy_addr);
@@ -6260,164 +6097,183 @@ static void __devinit bnx2x_link_settings_supported(struct bnx2x *bp,
 
        default:
                BNX2X_ERR("BAD switch_cfg link_config 0x%x\n",
-                         bp->port.link_config);
+                         bp->port.link_config[0]);
                return;
        }
-       bp->link_params.phy_addr = bp->port.phy_addr;
-
-       /* mask what we support according to speed_cap_mask */
-       if (!(bp->link_params.speed_cap_mask &
+       /* mask what we support according to speed_cap_mask per configuration */
+       for (idx = 0; idx < cfg_size; idx++) {
+               if (!(bp->link_params.speed_cap_mask[idx] &
                                PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_HALF))
-               bp->port.supported &= ~SUPPORTED_10baseT_Half;
+                       bp->port.supported[idx] &= ~SUPPORTED_10baseT_Half;
 
-       if (!(bp->link_params.speed_cap_mask &
+               if (!(bp->link_params.speed_cap_mask[idx] &
                                PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL))
-               bp->port.supported &= ~SUPPORTED_10baseT_Full;
+                       bp->port.supported[idx] &= ~SUPPORTED_10baseT_Full;
 
-       if (!(bp->link_params.speed_cap_mask &
+               if (!(bp->link_params.speed_cap_mask[idx] &
                                PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_HALF))
-               bp->port.supported &= ~SUPPORTED_100baseT_Half;
+                       bp->port.supported[idx] &= ~SUPPORTED_100baseT_Half;
 
-       if (!(bp->link_params.speed_cap_mask &
+               if (!(bp->link_params.speed_cap_mask[idx] &
                                PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_FULL))
-               bp->port.supported &= ~SUPPORTED_100baseT_Full;
+                       bp->port.supported[idx] &= ~SUPPORTED_100baseT_Full;
 
-       if (!(bp->link_params.speed_cap_mask &
+               if (!(bp->link_params.speed_cap_mask[idx] &
                                        PORT_HW_CFG_SPEED_CAPABILITY_D0_1G))
-               bp->port.supported &= ~(SUPPORTED_1000baseT_Half |
+                       bp->port.supported[idx] &= ~(SUPPORTED_1000baseT_Half |
                                        SUPPORTED_1000baseT_Full);
 
-       if (!(bp->link_params.speed_cap_mask &
+               if (!(bp->link_params.speed_cap_mask[idx] &
                                        PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G))
-               bp->port.supported &= ~SUPPORTED_2500baseX_Full;
+                       bp->port.supported[idx] &= ~SUPPORTED_2500baseX_Full;
 
-       if (!(bp->link_params.speed_cap_mask &
+               if (!(bp->link_params.speed_cap_mask[idx] &
                                        PORT_HW_CFG_SPEED_CAPABILITY_D0_10G))
-               bp->port.supported &= ~SUPPORTED_10000baseT_Full;
+                       bp->port.supported[idx] &= ~SUPPORTED_10000baseT_Full;
+
+       }
 
-       BNX2X_DEV_INFO("supported 0x%x\n", bp->port.supported);
+       BNX2X_DEV_INFO("supported 0x%x 0x%x\n", bp->port.supported[0],
+                      bp->port.supported[1]);
 }
 
 static void __devinit bnx2x_link_settings_requested(struct bnx2x *bp)
 {
-       bp->link_params.req_duplex = DUPLEX_FULL;
-
-       switch (bp->port.link_config & PORT_FEATURE_LINK_SPEED_MASK) {
+       u32 link_config, idx, cfg_size = 0;
+       bp->port.advertising[0] = 0;
+       bp->port.advertising[1] = 0;
+       switch (bp->link_params.num_phys) {
+       case 1:
+       case 2:
+               cfg_size = 1;
+               break;
+       case 3:
+               cfg_size = 2;
+               break;
+       }
+       for (idx = 0; idx < cfg_size; idx++) {
+               bp->link_params.req_duplex[idx] = DUPLEX_FULL;
+               link_config = bp->port.link_config[idx];
+               switch (link_config & PORT_FEATURE_LINK_SPEED_MASK) {
        case PORT_FEATURE_LINK_SPEED_AUTO:
-               if (bp->port.supported & SUPPORTED_Autoneg) {
-                       bp->link_params.req_line_speed = SPEED_AUTO_NEG;
-                       bp->port.advertising = bp->port.supported;
+                       if (bp->port.supported[idx] & SUPPORTED_Autoneg) {
+                               bp->link_params.req_line_speed[idx] =
+                                       SPEED_AUTO_NEG;
+                               bp->port.advertising[idx] |=
+                                       bp->port.supported[idx];
                } else {
-                       u32 ext_phy_type =
-                           XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config);
-
-                       if ((ext_phy_type ==
-                            PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) ||
-                           (ext_phy_type ==
-                            PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706)) {
-                               /* force 10G, no AN */
-                               bp->link_params.req_line_speed = SPEED_10000;
-                               bp->port.advertising =
-                                               (ADVERTISED_10000baseT_Full |
+                       /* force 10G, no AN */
+                               bp->link_params.req_line_speed[idx] =
+                                       SPEED_10000;
+                               bp->port.advertising[idx] |=
+                                       (ADVERTISED_10000baseT_Full |
                                                 ADVERTISED_FIBRE);
-                               break;
-                       }
-                       BNX2X_ERR("NVRAM config error. "
-                                 "Invalid link_config 0x%x"
-                                 "  Autoneg not supported\n",
-                                 bp->port.link_config);
-                       return;
+                               continue;
                }
                break;
 
        case PORT_FEATURE_LINK_SPEED_10M_FULL:
-               if (bp->port.supported & SUPPORTED_10baseT_Full) {
-                       bp->link_params.req_line_speed = SPEED_10;
-                       bp->port.advertising = (ADVERTISED_10baseT_Full |
+                       if (bp->port.supported[idx] & SUPPORTED_10baseT_Full) {
+                               bp->link_params.req_line_speed[idx] =
+                                       SPEED_10;
+                               bp->port.advertising[idx] |=
+                                       (ADVERTISED_10baseT_Full |
                                                ADVERTISED_TP);
                } else {
                        BNX2X_ERROR("NVRAM config error. "
                                    "Invalid link_config 0x%x"
                                    "  speed_cap_mask 0x%x\n",
-                                   bp->port.link_config,
-                                   bp->link_params.speed_cap_mask);
+                                   link_config,
+                                   bp->link_params.speed_cap_mask[idx]);
                        return;
                }
                break;
 
        case PORT_FEATURE_LINK_SPEED_10M_HALF:
-               if (bp->port.supported & SUPPORTED_10baseT_Half) {
-                       bp->link_params.req_line_speed = SPEED_10;
-                       bp->link_params.req_duplex = DUPLEX_HALF;
-                       bp->port.advertising = (ADVERTISED_10baseT_Half |
+                       if (bp->port.supported[idx] & SUPPORTED_10baseT_Half) {
+                               bp->link_params.req_line_speed[idx] =
+                                       SPEED_10;
+                               bp->link_params.req_duplex[idx] =
+                                       DUPLEX_HALF;
+                               bp->port.advertising[idx] |=
+                                       (ADVERTISED_10baseT_Half |
                                                ADVERTISED_TP);
                } else {
                        BNX2X_ERROR("NVRAM config error. "
                                    "Invalid link_config 0x%x"
                                    "  speed_cap_mask 0x%x\n",
-                                   bp->port.link_config,
-                                   bp->link_params.speed_cap_mask);
+                                   link_config,
+                                   bp->link_params.speed_cap_mask[idx]);
                        return;
                }
                break;
 
        case PORT_FEATURE_LINK_SPEED_100M_FULL:
-               if (bp->port.supported & SUPPORTED_100baseT_Full) {
-                       bp->link_params.req_line_speed = SPEED_100;
-                       bp->port.advertising = (ADVERTISED_100baseT_Full |
+                       if (bp->port.supported[idx] & SUPPORTED_100baseT_Full) {
+                               bp->link_params.req_line_speed[idx] =
+                                       SPEED_100;
+                               bp->port.advertising[idx] |=
+                                       (ADVERTISED_100baseT_Full |
                                                ADVERTISED_TP);
                } else {
                        BNX2X_ERROR("NVRAM config error. "
                                    "Invalid link_config 0x%x"
                                    "  speed_cap_mask 0x%x\n",
-                                   bp->port.link_config,
-                                   bp->link_params.speed_cap_mask);
+                                   link_config,
+                                   bp->link_params.speed_cap_mask[idx]);
                        return;
                }
                break;
 
        case PORT_FEATURE_LINK_SPEED_100M_HALF:
-               if (bp->port.supported & SUPPORTED_100baseT_Half) {
-                       bp->link_params.req_line_speed = SPEED_100;
-                       bp->link_params.req_duplex = DUPLEX_HALF;
-                       bp->port.advertising = (ADVERTISED_100baseT_Half |
+                       if (bp->port.supported[idx] & SUPPORTED_100baseT_Half) {
+                               bp->link_params.req_line_speed[idx] = SPEED_100;
+                               bp->link_params.req_duplex[idx] = DUPLEX_HALF;
+                               bp->port.advertising[idx] |=
+                                       (ADVERTISED_100baseT_Half |
                                                ADVERTISED_TP);
                } else {
                        BNX2X_ERROR("NVRAM config error. "
                                    "Invalid link_config 0x%x"
                                    "  speed_cap_mask 0x%x\n",
-                                   bp->port.link_config,
-                                   bp->link_params.speed_cap_mask);
+                                   link_config,
+                                   bp->link_params.speed_cap_mask[idx]);
                        return;
                }
                break;
 
        case PORT_FEATURE_LINK_SPEED_1G:
-               if (bp->port.supported & SUPPORTED_1000baseT_Full) {
-                       bp->link_params.req_line_speed = SPEED_1000;
-                       bp->port.advertising = (ADVERTISED_1000baseT_Full |
+                       if (bp->port.supported[idx] &
+                           SUPPORTED_1000baseT_Full) {
+                               bp->link_params.req_line_speed[idx] =
+                                       SPEED_1000;
+                               bp->port.advertising[idx] |=
+                                       (ADVERTISED_1000baseT_Full |
                                                ADVERTISED_TP);
                } else {
                        BNX2X_ERROR("NVRAM config error. "
                                    "Invalid link_config 0x%x"
                                    "  speed_cap_mask 0x%x\n",
-                                   bp->port.link_config,
-                                   bp->link_params.speed_cap_mask);
+                                   link_config,
+                                   bp->link_params.speed_cap_mask[idx]);
                        return;
                }
                break;
 
        case PORT_FEATURE_LINK_SPEED_2_5G:
-               if (bp->port.supported & SUPPORTED_2500baseX_Full) {
-                       bp->link_params.req_line_speed = SPEED_2500;
-                       bp->port.advertising = (ADVERTISED_2500baseX_Full |
+                       if (bp->port.supported[idx] &
+                           SUPPORTED_2500baseX_Full) {
+                               bp->link_params.req_line_speed[idx] =
+                                       SPEED_2500;
+                               bp->port.advertising[idx] |=
+                                       (ADVERTISED_2500baseX_Full |
                                                ADVERTISED_TP);
                } else {
                        BNX2X_ERROR("NVRAM config error. "
                                    "Invalid link_config 0x%x"
                                    "  speed_cap_mask 0x%x\n",
-                                   bp->port.link_config,
-                                   bp->link_params.speed_cap_mask);
+                                   link_config,
+                                    bp->link_params.speed_cap_mask[idx]);
                        return;
                }
                break;
@@ -6425,16 +6281,19 @@ static void __devinit bnx2x_link_settings_requested(struct bnx2x *bp)
        case PORT_FEATURE_LINK_SPEED_10G_CX4:
        case PORT_FEATURE_LINK_SPEED_10G_KX4:
        case PORT_FEATURE_LINK_SPEED_10G_KR:
-               if (bp->port.supported & SUPPORTED_10000baseT_Full) {
-                       bp->link_params.req_line_speed = SPEED_10000;
-                       bp->port.advertising = (ADVERTISED_10000baseT_Full |
+                       if (bp->port.supported[idx] &
+                           SUPPORTED_10000baseT_Full) {
+                               bp->link_params.req_line_speed[idx] =
+                                       SPEED_10000;
+                               bp->port.advertising[idx] |=
+                                       (ADVERTISED_10000baseT_Full |
                                                ADVERTISED_FIBRE);
                } else {
                        BNX2X_ERROR("NVRAM config error. "
                                    "Invalid link_config 0x%x"
                                    "  speed_cap_mask 0x%x\n",
-                                   bp->port.link_config,
-                                   bp->link_params.speed_cap_mask);
+                                   link_config,
+                                    bp->link_params.speed_cap_mask[idx]);
                        return;
                }
                break;
@@ -6442,23 +6301,28 @@ static void __devinit bnx2x_link_settings_requested(struct bnx2x *bp)
        default:
                BNX2X_ERROR("NVRAM config error. "
                            "BAD link speed link_config 0x%x\n",
-                           bp->port.link_config);
-               bp->link_params.req_line_speed = SPEED_AUTO_NEG;
-               bp->port.advertising = bp->port.supported;
+                                 link_config);
+                       bp->link_params.req_line_speed[idx] = SPEED_AUTO_NEG;
+                       bp->port.advertising[idx] = bp->port.supported[idx];
                break;
        }
 
-       bp->link_params.req_flow_ctrl = (bp->port.link_config &
+               bp->link_params.req_flow_ctrl[idx] = (link_config &
                                         PORT_FEATURE_FLOW_CONTROL_MASK);
-       if ((bp->link_params.req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO) &&
-           !(bp->port.supported & SUPPORTED_Autoneg))
-               bp->link_params.req_flow_ctrl = BNX2X_FLOW_CTRL_NONE;
+               if ((bp->link_params.req_flow_ctrl[idx] ==
+                    BNX2X_FLOW_CTRL_AUTO) &&
+                   !(bp->port.supported[idx] & SUPPORTED_Autoneg)) {
+                       bp->link_params.req_flow_ctrl[idx] =
+                               BNX2X_FLOW_CTRL_NONE;
+               }
 
-       BNX2X_DEV_INFO("req_line_speed %d  req_duplex %d  req_flow_ctrl 0x%x"
-                      "  advertising 0x%x\n",
-                      bp->link_params.req_line_speed,
-                      bp->link_params.req_duplex,
-                      bp->link_params.req_flow_ctrl, bp->port.advertising);
+               BNX2X_DEV_INFO("req_line_speed %d  req_duplex %d req_flow_ctrl"
+                              " 0x%x advertising 0x%x\n",
+                              bp->link_params.req_line_speed[idx],
+                              bp->link_params.req_duplex[idx],
+                              bp->link_params.req_flow_ctrl[idx],
+                              bp->port.advertising[idx]);
+       }
 }
 
 static void __devinit bnx2x_set_mac_buf(u8 *mac_buf, u32 mac_lo, u16 mac_hi)
@@ -6474,48 +6338,28 @@ static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp)
        int port = BP_PORT(bp);
        u32 val, val2;
        u32 config;
-       u16 i;
-       u32 ext_phy_type;
+       u32 ext_phy_type, ext_phy_config;;
 
        bp->link_params.bp = bp;
        bp->link_params.port = port;
 
        bp->link_params.lane_config =
                SHMEM_RD(bp, dev_info.port_hw_config[port].lane_config);
-       bp->link_params.ext_phy_config =
-               SHMEM_RD(bp,
-                        dev_info.port_hw_config[port].external_phy_config);
-       /* BCM8727_NOC => BCM8727 no over current */
-       if (XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config) ==
-           PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC) {
-               bp->link_params.ext_phy_config &=
-                       ~PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK;
-               bp->link_params.ext_phy_config |=
-                       PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727;
-               bp->link_params.feature_config_flags |=
-                       FEATURE_CONFIG_BCM8727_NOC;
-       }
 
-       bp->link_params.speed_cap_mask =
+       bp->link_params.speed_cap_mask[0] =
                SHMEM_RD(bp,
                         dev_info.port_hw_config[port].speed_capability_mask);
-
-       bp->port.link_config =
+       bp->link_params.speed_cap_mask[1] =
+               SHMEM_RD(bp,
+                        dev_info.port_hw_config[port].speed_capability_mask2);
+       bp->port.link_config[0] =
                SHMEM_RD(bp, dev_info.port_feature_config[port].link_config);
 
-       /* Get the 4 lanes xgxs config rx and tx */
-       for (i = 0; i < 2; i++) {
-               val = SHMEM_RD(bp,
-                          dev_info.port_hw_config[port].xgxs_config_rx[i<<1]);
-               bp->link_params.xgxs_config_rx[i << 1] = ((val>>16) & 0xffff);
-               bp->link_params.xgxs_config_rx[(i << 1) + 1] = (val & 0xffff);
-
-               val = SHMEM_RD(bp,
-                          dev_info.port_hw_config[port].xgxs_config_tx[i<<1]);
-               bp->link_params.xgxs_config_tx[i << 1] = ((val>>16) & 0xffff);
-               bp->link_params.xgxs_config_tx[(i << 1) + 1] = (val & 0xffff);
-       }
+       bp->port.link_config[1] =
+               SHMEM_RD(bp, dev_info.port_feature_config[port].link_config2);
 
+       bp->link_params.multi_phy_config =
+               SHMEM_RD(bp, dev_info.port_hw_config[port].multi_phy_config);
        /* If the device is capable of WoL, set the default state according
         * to the HW
         */
@@ -6523,14 +6367,15 @@ static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp)
        bp->wol = (!(bp->flags & NO_WOL_FLAG) &&
                   (config & PORT_FEATURE_WOL_ENABLED));
 
-       BNX2X_DEV_INFO("lane_config 0x%08x  ext_phy_config 0x%08x"
-                      "  speed_cap_mask 0x%08x  link_config 0x%08x\n",
+       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.ext_phy_config,
-                      bp->link_params.speed_cap_mask, bp->port.link_config);
+                      bp->link_params.speed_cap_mask[0],
+                      bp->port.link_config[0]);
 
-       bp->link_params.switch_cfg |= (bp->port.link_config &
+       bp->link_params.switch_cfg = (bp->port.link_config[0] &
                                       PORT_FEATURE_CONNECTED_SWITCH_MASK);
+       bnx2x_phy_probe(&bp->link_params);
        bnx2x_link_settings_supported(bp, bp->link_params.switch_cfg);
 
        bnx2x_link_settings_requested(bp);
@@ -6539,14 +6384,17 @@ static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp)
         * If connected directly, work with the internal PHY, otherwise, work
         * with the external PHY
         */
-       ext_phy_type = XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config);
+       ext_phy_config =
+               SHMEM_RD(bp,
+                        dev_info.port_hw_config[port].external_phy_config);
+       ext_phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config);
        if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT)
-               bp->mdio.prtad = bp->link_params.phy_addr;
+               bp->mdio.prtad = bp->port.phy_addr;
 
        else if ((ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) &&
                 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN))
                bp->mdio.prtad =
-                       XGXS_EXT_PHY_ADDR(bp->link_params.ext_phy_config);
+                       XGXS_EXT_PHY_ADDR(ext_phy_config);
 
        val2 = SHMEM_RD(bp, dev_info.port_hw_config[port].mac_upper);
        val = SHMEM_RD(bp, dev_info.port_hw_config[port].mac_lower);
@@ -6982,23 +6830,15 @@ static int bnx2x_mdio_read(struct net_device *netdev, int prtad,
        struct bnx2x *bp = netdev_priv(netdev);
        u16 value;
        int rc;
-       u32 phy_type = XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config);
 
        DP(NETIF_MSG_LINK, "mdio_read: prtad 0x%x, devad 0x%x, addr 0x%x\n",
           prtad, devad, addr);
 
-       if (prtad != bp->mdio.prtad) {
-               DP(NETIF_MSG_LINK, "prtad missmatch (cmd:0x%x != bp:0x%x)\n",
-                  prtad, bp->mdio.prtad);
-               return -EINVAL;
-       }
-
        /* The HW expects different devad if CL22 is used */
        devad = (devad == MDIO_DEVAD_NONE) ? DEFAULT_PHY_DEV_ADDR : devad;
 
        bnx2x_acquire_phy_lock(bp);
-       rc = bnx2x_cl45_read(bp, BP_PORT(bp), phy_type, prtad,
-                            devad, addr, &value);
+       rc = bnx2x_phy_read(&bp->link_params, prtad, devad, addr, &value);
        bnx2x_release_phy_lock(bp);
        DP(NETIF_MSG_LINK, "mdio_read_val 0x%x rc = 0x%x\n", value, rc);
 
@@ -7012,24 +6852,16 @@ static int bnx2x_mdio_write(struct net_device *netdev, int prtad, int devad,
                            u16 addr, u16 value)
 {
        struct bnx2x *bp = netdev_priv(netdev);
-       u32 ext_phy_type = XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config);
        int rc;
 
        DP(NETIF_MSG_LINK, "mdio_write: prtad 0x%x, devad 0x%x, addr 0x%x,"
                           " value 0x%x\n", prtad, devad, addr, value);
 
-       if (prtad != bp->mdio.prtad) {
-               DP(NETIF_MSG_LINK, "prtad missmatch (cmd:0x%x != bp:0x%x)\n",
-                  prtad, bp->mdio.prtad);
-               return -EINVAL;
-       }
-
        /* The HW expects different devad if CL22 is used */
        devad = (devad == MDIO_DEVAD_NONE) ? DEFAULT_PHY_DEV_ADDR : devad;
 
        bnx2x_acquire_phy_lock(bp);
-       rc = bnx2x_cl45_write(bp, BP_PORT(bp), ext_phy_type, prtad,
-                             devad, addr, value);
+       rc = bnx2x_phy_write(&bp->link_params, prtad, devad, addr, value);
        bnx2x_release_phy_lock(bp);
        return rc;
 }
@@ -7259,7 +7091,7 @@ static void __devinit bnx2x_get_pcie_width_speed(struct bnx2x *bp,
        *speed = (val & PCICFG_LINK_SPEED) >> PCICFG_LINK_SPEED_SHIFT;
 }
 
-static int __devinit bnx2x_check_firmware(struct bnx2x *bp)
+static int bnx2x_check_firmware(struct bnx2x *bp)
 {
        const struct firmware *firmware = bp->firmware;
        struct bnx2x_fw_file_hdr *fw_hdr;
@@ -7370,7 +7202,7 @@ do {                                                                      \
             (u8 *)bp->arr, len);                                       \
 } while (0)
 
-static int __devinit bnx2x_init_firmware(struct bnx2x *bp, struct device *dev)
+int bnx2x_init_firmware(struct bnx2x *bp)
 {
        const char *fw_file_name;
        struct bnx2x_fw_file_hdr *fw_hdr;
@@ -7381,21 +7213,21 @@ static int __devinit bnx2x_init_firmware(struct bnx2x *bp, struct device *dev)
        else if (CHIP_IS_E1H(bp))
                fw_file_name = FW_FILE_NAME_E1H;
        else {
-               dev_err(dev, "Unsupported chip revision\n");
+               BNX2X_ERR("Unsupported chip revision\n");
                return -EINVAL;
        }
 
-       dev_info(dev, "Loading %s\n", fw_file_name);
+       BNX2X_DEV_INFO("Loading %s\n", fw_file_name);
 
-       rc = request_firmware(&bp->firmware, fw_file_name, dev);
+       rc = request_firmware(&bp->firmware, fw_file_name, &bp->pdev->dev);
        if (rc) {
-               dev_err(dev, "Can't load firmware file %s\n", fw_file_name);
+               BNX2X_ERR("Can't load firmware file %s\n", fw_file_name);
                goto request_firmware_exit;
        }
 
        rc = bnx2x_check_firmware(bp);
        if (rc) {
-               dev_err(dev, "Corrupt firmware file %s\n", fw_file_name);
+               BNX2X_ERR("Corrupt firmware file %s\n", fw_file_name);
                goto request_firmware_exit;
        }
 
@@ -7473,13 +7305,6 @@ static int __devinit bnx2x_init_one(struct pci_dev *pdev,
        if (rc)
                goto init_one_exit;
 
-       /* Set init arrays */
-       rc = bnx2x_init_firmware(bp, &pdev->dev);
-       if (rc) {
-               dev_err(&pdev->dev, "Error loading firmware\n");
-               goto init_one_exit;
-       }
-
        rc = register_netdev(dev);
        if (rc) {
                dev_err(&pdev->dev, "Cannot register net device\n");
@@ -7530,11 +7355,6 @@ static void __devexit bnx2x_remove_one(struct pci_dev *pdev)
        /* Make sure RESET task is not scheduled before continuing */
        cancel_delayed_work_sync(&bp->reset_task);
 
-       kfree(bp->init_ops_offsets);
-       kfree(bp->init_ops);
-       kfree(bp->init_data);
-       release_firmware(bp->firmware);
-
        if (bp->regview)
                iounmap(bp->regview);
 
index a1f3bf0cd630d2de15be155830ca7f038de904f7..6be0d09ad3fddbd79185601a8cfc57265aea5a96 100644 (file)
 #define MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_PRL_DT_EN                 0x0001
 #define MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_AN_FST_TMR                0x0040
 #define MDIO_SERDES_DIGITAL_A_1000X_STATUS1                    0x14
+#define MDIO_SERDES_DIGITAL_A_1000X_STATUS1_SGMII                      0x0001
+#define MDIO_SERDES_DIGITAL_A_1000X_STATUS1_LINK                       0x0002
 #define MDIO_SERDES_DIGITAL_A_1000X_STATUS1_DUPLEX                     0x0004
 #define MDIO_SERDES_DIGITAL_A_1000X_STATUS1_SPEED_MASK                 0x0018
 #define MDIO_SERDES_DIGITAL_A_1000X_STATUS1_SPEED_SHIFT                3
@@ -5135,28 +5137,35 @@ Theotherbitsarereservedandshouldbezero*/
 #define MDIO_PMA_REG_8727_TWO_WIRE_SLAVE_ADDR  0x8005
 #define MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF    0x8007
 #define MDIO_PMA_REG_8727_TWO_WIRE_DATA_MASK 0xff
-#define MDIO_PMA_REG_8727_MISC_CTRL            0x8309
 #define MDIO_PMA_REG_8727_TX_CTRL1             0xca02
 #define MDIO_PMA_REG_8727_TX_CTRL2             0xca05
 #define MDIO_PMA_REG_8727_PCS_OPT_CTRL         0xc808
 #define MDIO_PMA_REG_8727_GPIO_CTRL            0xc80e
+#define MDIO_PMA_REG_8727_PCS_GP               0xc842
+
+#define MDIO_AN_REG_8727_MISC_CTRL             0x8309
 
 #define MDIO_PMA_REG_8073_CHIP_REV                     0xc801
 #define MDIO_PMA_REG_8073_SPEED_LINK_STATUS            0xc820
 #define MDIO_PMA_REG_8073_XAUI_WA                      0xc841
+#define MDIO_PMA_REG_8073_OPT_DIGITAL_CTRL             0xcd08
 
 #define MDIO_PMA_REG_7101_RESET        0xc000
 #define MDIO_PMA_REG_7107_LED_CNTL     0xc007
+#define MDIO_PMA_REG_7107_LINK_LED_CNTL 0xc009
 #define MDIO_PMA_REG_7101_VER1         0xc026
 #define MDIO_PMA_REG_7101_VER2         0xc027
 
-#define MDIO_PMA_REG_8481_PMD_SIGNAL   0xa811
-#define MDIO_PMA_REG_8481_LED1_MASK    0xa82c
-#define MDIO_PMA_REG_8481_LED2_MASK    0xa82f
-#define MDIO_PMA_REG_8481_LED3_MASK    0xa832
-#define MDIO_PMA_REG_8481_LED3_BLINK   0xa834
-#define MDIO_PMA_REG_8481_SIGNAL_MASK  0xa835
-#define MDIO_PMA_REG_8481_LINK_SIGNAL  0xa83b
+#define MDIO_PMA_REG_8481_PMD_SIGNAL                   0xa811
+#define MDIO_PMA_REG_8481_LED1_MASK                    0xa82c
+#define MDIO_PMA_REG_8481_LED2_MASK                    0xa82f
+#define MDIO_PMA_REG_8481_LED3_MASK                    0xa832
+#define MDIO_PMA_REG_8481_LED3_BLINK                   0xa834
+#define MDIO_PMA_REG_8481_LED5_MASK                    0xa838
+#define MDIO_PMA_REG_8481_SIGNAL_MASK                  0xa835
+#define MDIO_PMA_REG_8481_LINK_SIGNAL                  0xa83b
+#define MDIO_PMA_REG_8481_LINK_SIGNAL_LED4_ENABLE_MASK 0x800
+#define MDIO_PMA_REG_8481_LINK_SIGNAL_LED4_ENABLE_SHIFT 11
 
 
 #define MDIO_WIS_DEVAD                 0x2
@@ -5188,6 +5197,8 @@ Theotherbitsarereservedandshouldbezero*/
 #define MDIO_XS_8706_REG_BANK_RX3      0x80ec
 #define MDIO_XS_8706_REG_BANK_RXA      0x80fc
 
+#define MDIO_XS_REG_8073_RX_CTRL_PCIE  0x80FA
+
 #define MDIO_AN_DEVAD                  0x7
 /*ieee*/
 #define MDIO_AN_REG_CTRL               0x0000
@@ -5210,14 +5221,40 @@ Theotherbitsarereservedandshouldbezero*/
 #define MDIO_AN_REG_CL37_FC_LP         0xffe5
 
 #define MDIO_AN_REG_8073_2_5G          0x8329
+#define MDIO_AN_REG_8073_BAM           0x8350
 
+#define MDIO_AN_REG_8481_10GBASE_T_AN_CTRL     0x0020
 #define MDIO_AN_REG_8481_LEGACY_MII_CTRL       0xffe0
+#define MDIO_AN_REG_8481_LEGACY_MII_STATUS     0xffe1
 #define MDIO_AN_REG_8481_LEGACY_AN_ADV         0xffe4
+#define MDIO_AN_REG_8481_LEGACY_AN_EXPANSION   0xffe6
 #define MDIO_AN_REG_8481_1000T_CTRL            0xffe9
 #define MDIO_AN_REG_8481_EXPANSION_REG_RD_RW   0xfff5
 #define MDIO_AN_REG_8481_EXPANSION_REG_ACCESS  0xfff7
+#define MDIO_AN_REG_8481_AUX_CTRL              0xfff8
 #define MDIO_AN_REG_8481_LEGACY_SHADOW         0xfffc
 
+/* BCM84823 only */
+#define MDIO_CTL_DEVAD                 0x1e
+#define MDIO_CTL_REG_84823_MEDIA               0x401a
+#define MDIO_CTL_REG_84823_MEDIA_MAC_MASK              0x0018
+       /* These pins configure the BCM84823 interface to MAC after reset. */
+#define MDIO_CTL_REG_84823_CTRL_MAC_XFI                        0x0008
+#define MDIO_CTL_REG_84823_MEDIA_MAC_XAUI_M            0x0010
+       /* These pins configure the BCM84823 interface to Line after reset. */
+#define MDIO_CTL_REG_84823_MEDIA_LINE_MASK             0x0060
+#define MDIO_CTL_REG_84823_MEDIA_LINE_XAUI_L           0x0020
+#define MDIO_CTL_REG_84823_MEDIA_LINE_XFI              0x0040
+       /* When this pin is active high during reset, 10GBASE-T core is power
+        * down, When it is active low the 10GBASE-T is power up
+        */
+#define MDIO_CTL_REG_84823_MEDIA_COPPER_CORE_DOWN      0x0080
+#define MDIO_CTL_REG_84823_MEDIA_PRIORITY_MASK         0x0100
+#define MDIO_CTL_REG_84823_MEDIA_PRIORITY_COPPER       0x0000
+#define MDIO_CTL_REG_84823_MEDIA_PRIORITY_FIBER                0x0100
+#define MDIO_CTL_REG_84823_MEDIA_FIBER_1G                      0x1000
+
+
 #define IGU_FUNC_BASE                  0x0400
 
 #define IGU_ADDR_MSIX                  0x0000
index c74724461020aa9ba60265a43907eabca6a40454..efa1403ebf8297cec2369ae4cbf48abd90813175 100644 (file)
@@ -969,6 +969,7 @@ static void bnx2x_net_stats_update(struct bnx2x *bp)
 {
        struct bnx2x_eth_stats *estats = &bp->eth_stats;
        struct net_device_stats *nstats = &bp->dev->stats;
+       unsigned long tmp;
        int i;
 
        nstats->rx_packets =
@@ -985,10 +986,10 @@ static void bnx2x_net_stats_update(struct bnx2x *bp)
 
        nstats->tx_bytes = bnx2x_hilo(&estats->total_bytes_transmitted_hi);
 
-       nstats->rx_dropped = estats->mac_discard;
+       tmp = estats->mac_discard;
        for_each_queue(bp, i)
-               nstats->rx_dropped +=
-                       le32_to_cpu(bp->fp[i].old_tclient.checksum_discard);
+               tmp += le32_to_cpu(bp->fp[i].old_tclient.checksum_discard);
+       nstats->rx_dropped = tmp;
 
        nstats->tx_dropped = 0;
 
index b1bdc909090f7130ccf88cbb6e5257542623b9d2..312b9c8f4f3bdbcb5342b4aae732bde2a3307c70 100644 (file)
@@ -143,12 +143,12 @@ static u32 __devinit mpc512x_can_get_clock(struct platform_device *ofdev,
        np_clock = of_find_matching_node(NULL, mpc512x_clock_ids);
        if (!np_clock) {
                dev_err(&ofdev->dev, "couldn't find clock node\n");
-               return -ENODEV;
+               return 0;
        }
        clockctl = of_iomap(np_clock, 0);
        if (!clockctl) {
                dev_err(&ofdev->dev, "couldn't map clock registers\n");
-               return 0;
+               goto exit_put;
        }
 
        /* Determine the MSCAN device index from the physical address */
@@ -233,9 +233,9 @@ static u32 __devinit mpc512x_can_get_clock(struct platform_device *ofdev,
                clocksrc == 1 ? "ref_clk" : "sys_clk", clockdiv);
 
 exit_unmap:
-       of_node_put(np_clock);
        iounmap(clockctl);
-
+exit_put:
+       of_node_put(np_clock);
        return freq;
 }
 #else /* !CONFIG_PPC_MPC512x */
index 28c88eeec757361fb2fa3db11a63b57c97b892fb..32aaadc4734f32cb0deeb6b46678d3a9113ca140 100644 (file)
@@ -2149,7 +2149,7 @@ end_copy_pkt:
                skb->csum = csum_unfold(~csum);
                skb->ip_summed = CHECKSUM_COMPLETE;
        } else
-               skb->ip_summed = CHECKSUM_NONE;
+               skb_checksum_none_assert(skb);
        return len;
 }
 
index f01cfdb995deaef8a04d74b5d997a8fb1e74b6dd..1950b9a20ecd8976ea092aea28805092e53b50fa 100644 (file)
@@ -1388,7 +1388,7 @@ static void sge_rx(struct sge *sge, struct freelQ *fl, unsigned int len)
                ++st->rx_cso_good;
                skb->ip_summed = CHECKSUM_UNNECESSARY;
        } else
-               skb->ip_summed = CHECKSUM_NONE;
+               skb_checksum_none_assert(skb);
 
        if (unlikely(adapter->vlan_grp && p->vlan_valid)) {
                st->vlan_xtract++;
index 599d178df62ddd0e1289369802c04c18921a1583..63ebf76d2390858ec10f2bf77cfce1439a87ffc5 100644 (file)
@@ -314,14 +314,12 @@ static int mi1_mdio_write(struct net_device *dev, int phy_addr, int mmd_addr,
        return 0;
 }
 
-#if defined(CONFIG_CHELSIO_T1_1G)
 static const struct mdio_ops mi1_mdio_ops = {
        .init = mi1_mdio_init,
        .read = mi1_mdio_read,
        .write = mi1_mdio_write,
        .mode_support = MDIO_SUPPORTS_C22
 };
-#endif
 
 #endif
 
index 09610323a948cab243d083c1a8435853b8893184..2ab6a7c4ffc1cac6ea22ca8b88377cc469fd2217 100644 (file)
@@ -1022,7 +1022,7 @@ static int cnic_alloc_bnx2x_context(struct cnic_dev *dev)
        if (blks > cp->ethdev->ctx_tbl_len)
                return -ENOMEM;
 
-       cp->ctx_arr = kzalloc(blks * sizeof(struct cnic_ctx), GFP_KERNEL);
+       cp->ctx_arr = kcalloc(blks, sizeof(struct cnic_ctx), GFP_KERNEL);
        if (cp->ctx_arr == NULL)
                return -ENOMEM;
 
index e1f6156b3710e9888f779610ddb10a52fcfd5d9d..fec939f8f65f760cf31b7d4a1981a499124d1cba 100644 (file)
@@ -38,7 +38,7 @@
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
 #include <linux/clk.h>
-#include <asm/gpio.h>
+#include <linux/gpio.h>
 #include <asm/atomic.h>
 
 MODULE_AUTHOR("Eugene Konev <ejka@imfi.kspu.ru>");
@@ -108,7 +108,7 @@ MODULE_PARM_DESC(dumb_switch, "Assume switch is not connected to MDIO bus");
 #define CPMAC_RX_INT_CLEAR             0x019c
 #define CPMAC_MAC_INT_ENABLE           0x01a8
 #define CPMAC_MAC_INT_CLEAR            0x01ac
-#define CPMAC_MAC_ADDR_LO(channel)     (0x01b0 + (channel) * 4)
+#define CPMAC_MAC_ADDR_LO(channel)     (0x01b0 + (channel) * 4)
 #define CPMAC_MAC_ADDR_MID             0x01d0
 #define CPMAC_MAC_ADDR_HI              0x01d4
 #define CPMAC_MAC_HASH_LO              0x01d8
@@ -227,7 +227,7 @@ static void cpmac_dump_regs(struct net_device *dev)
        for (i = 0; i < CPMAC_REG_END; i += 4) {
                if (i % 16 == 0) {
                        if (i)
-                               printk("\n");
+                               pr_cont("\n");
                        printk(KERN_DEBUG "%s: reg[%p]:", dev->name,
                               priv->regs + i);
                }
@@ -262,7 +262,7 @@ static void cpmac_dump_skb(struct net_device *dev, struct sk_buff *skb)
        for (i = 0; i < skb->len; i++) {
                if (i % 16 == 0) {
                        if (i)
-                               printk("\n");
+                               pr_cont("\n");
                        printk(KERN_DEBUG "%s: data[%p]:", dev->name,
                               skb->data + i);
                }
@@ -391,7 +391,7 @@ static struct sk_buff *cpmac_rx_one(struct cpmac_priv *priv,
        if (likely(skb)) {
                skb_put(desc->skb, desc->datalen);
                desc->skb->protocol = eth_type_trans(desc->skb, priv->dev);
-               desc->skb->ip_summed = CHECKSUM_NONE;
+               skb_checksum_none_assert(desc->skb);
                priv->dev->stats.rx_packets++;
                priv->dev->stats.rx_bytes += desc->datalen;
                result = desc->skb;
@@ -506,7 +506,7 @@ static int cpmac_poll(struct napi_struct *napi, int budget)
                                        "restart rx from a descriptor that's "
                                        "not free: %p\n",
                                        priv->dev->name, restart);
-                               goto fatal_error;
+                       goto fatal_error;
                }
 
                cpmac_write(priv->regs, CPMAC_RX_PTR(0), restart->mapping);
@@ -873,7 +873,8 @@ static int cpmac_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
        return -EINVAL;
 }
 
-static void cpmac_get_ringparam(struct net_device *dev, struct ethtool_ringparam* ring)
+static void cpmac_get_ringparam(struct net_device *dev,
+                                               struct ethtool_ringparam *ring)
 {
        struct cpmac_priv *priv = netdev_priv(dev);
 
@@ -888,7 +889,8 @@ static void cpmac_get_ringparam(struct net_device *dev, struct ethtool_ringparam
        ring->tx_pending = 1;
 }
 
-static int cpmac_set_ringparam(struct net_device *dev, struct ethtool_ringparam* ring)
+static int cpmac_set_ringparam(struct net_device *dev,
+                                               struct ethtool_ringparam *ring)
 {
        struct cpmac_priv *priv = netdev_priv(dev);
 
@@ -1012,8 +1014,8 @@ static int cpmac_open(struct net_device *dev)
 
        priv->rx_head->prev->hw_next = (u32)0;
 
-       if ((res = request_irq(dev->irq, cpmac_irq, IRQF_SHARED,
-                              dev->name, dev))) {
+       res = request_irq(dev->irq, cpmac_irq, IRQF_SHARED, dev->name, dev);
+       if (res) {
                if (netif_msg_drv(priv))
                        printk(KERN_ERR "%s: failed to obtain irq\n",
                               dev->name);
@@ -1133,7 +1135,8 @@ static int __devinit cpmac_probe(struct platform_device *pdev)
        }
 
        if (phy_id == PHY_MAX_ADDR) {
-               dev_err(&pdev->dev, "no PHY present, falling back to switch on MDIO bus 0\n");
+               dev_err(&pdev->dev, "no PHY present, falling back "
+                                       "to switch on MDIO bus 0\n");
                strncpy(mdio_bus_id, "0", MII_BUS_ID_SIZE); /* fixed phys bus */
                phy_id = pdev->id;
        }
@@ -1169,9 +1172,10 @@ static int __devinit cpmac_probe(struct platform_device *pdev)
        priv->msg_enable = netif_msg_init(debug_level, 0xff);
        memcpy(dev->dev_addr, pdata->dev_addr, sizeof(pdata->dev_addr));
 
-       snprintf(priv->phy_name, MII_BUS_ID_SIZE, PHY_ID_FMT, mdio_bus_id, phy_id);
+       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,
+       priv->phy = phy_connect(dev, priv->phy_name, cpmac_adjust_link, 0,
                                                PHY_INTERFACE_MODE_MII);
 
        if (IS_ERR(priv->phy)) {
@@ -1182,7 +1186,8 @@ static int __devinit cpmac_probe(struct platform_device *pdev)
                goto fail;
        }
 
-       if ((rc = register_netdev(dev))) {
+       rc = register_netdev(dev);
+       if (rc) {
                printk(KERN_ERR "cpmac: error %i registering device %s\n", rc,
                       dev->name);
                goto fail;
@@ -1248,11 +1253,13 @@ int __devinit cpmac_init(void)
 
        cpmac_mii->reset(cpmac_mii);
 
-       for (i = 0; i < 300; i++)
-               if ((mask = cpmac_read(cpmac_mii->priv, CPMAC_MDIO_ALIVE)))
+       for (i = 0; i < 300; i++) {
+               mask = cpmac_read(cpmac_mii->priv, CPMAC_MDIO_ALIVE);
+               if (mask)
                        break;
                else
                        msleep(10);
+       }
 
        mask &= 0x7fffffff;
        if (mask & (mask - 1)) {
index ad19585d960be79c0ec350c312fce978afaf2a9b..1ecf53dafe06c818c9e7ccd9802c0c8fb3d65a16 100644 (file)
@@ -1286,7 +1286,7 @@ irq_err:
 /*
  * Release resources when all the ports and offloading have been stopped.
  */
-static void cxgb_down(struct adapter *adapter)
+static void cxgb_down(struct adapter *adapter, int on_wq)
 {
        t3_sge_stop(adapter);
        spin_lock_irq(&adapter->work_lock);     /* sync with PHY intr task */
@@ -1296,7 +1296,8 @@ static void cxgb_down(struct adapter *adapter)
        free_irq_resources(adapter);
        quiesce_rx(adapter);
        t3_sge_stop(adapter);
-       flush_workqueue(cxgb3_wq);      /* wait for external IRQ handler */
+       if (!on_wq)
+               flush_workqueue(cxgb3_wq);/* wait for external IRQ handler */
 }
 
 static void schedule_chk_task(struct adapter *adap)
@@ -1374,7 +1375,7 @@ static int offload_close(struct t3cdev *tdev)
        clear_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map);
 
        if (!adapter->open_device_map)
-               cxgb_down(adapter);
+               cxgb_down(adapter, 0);
 
        cxgb3_offload_deactivate(adapter);
        return 0;
@@ -1409,7 +1410,7 @@ static int cxgb_open(struct net_device *dev)
        return 0;
 }
 
-static int cxgb_close(struct net_device *dev)
+static int __cxgb_close(struct net_device *dev, int on_wq)
 {
        struct port_info *pi = netdev_priv(dev);
        struct adapter *adapter = pi->adapter;
@@ -1436,12 +1437,17 @@ static int cxgb_close(struct net_device *dev)
                cancel_delayed_work_sync(&adapter->adap_check_task);
 
        if (!adapter->open_device_map)
-               cxgb_down(adapter);
+               cxgb_down(adapter, on_wq);
 
        cxgb3_event_notify(&adapter->tdev, OFFLOAD_PORT_DOWN, pi->port_id);
        return 0;
 }
 
+static int cxgb_close(struct net_device *dev)
+{
+       return __cxgb_close(dev, 0);
+}
+
 static struct net_device_stats *cxgb_get_stats(struct net_device *dev)
 {
        struct port_info *pi = netdev_priv(dev);
@@ -2862,7 +2868,7 @@ void t3_os_link_fault_handler(struct adapter *adapter, int port_id)
        spin_unlock(&adapter->work_lock);
 }
 
-static int t3_adapter_error(struct adapter *adapter, int reset)
+static int t3_adapter_error(struct adapter *adapter, int reset, int on_wq)
 {
        int i, ret = 0;
 
@@ -2877,7 +2883,7 @@ static int t3_adapter_error(struct adapter *adapter, int reset)
                struct net_device *netdev = adapter->port[i];
 
                if (netif_running(netdev))
-                       cxgb_close(netdev);
+                       __cxgb_close(netdev, on_wq);
        }
 
        /* Stop SGE timers */
@@ -2948,7 +2954,7 @@ static void fatal_error_task(struct work_struct *work)
        int err = 0;
 
        rtnl_lock();
-       err = t3_adapter_error(adapter, 1);
+       err = t3_adapter_error(adapter, 1, 1);
        if (!err)
                err = t3_reenable_adapter(adapter);
        if (!err)
@@ -2998,7 +3004,7 @@ static pci_ers_result_t t3_io_error_detected(struct pci_dev *pdev,
        if (state == pci_channel_io_perm_failure)
                return PCI_ERS_RESULT_DISCONNECT;
 
-       ret = t3_adapter_error(adapter, 0);
+       ret = t3_adapter_error(adapter, 0, 0);
 
        /* Request a slot reset. */
        return PCI_ERS_RESULT_NEED_RESET;
index cb42353c9fdd49c3368c70fe6ced350463a1c761..6990f6c6522164a7e602903554f3c8e3ccde83fc 100644 (file)
 
 #define A_PL_RST 0x6f0
 
+#define S_FATALPERREN    4
+#define V_FATALPERREN(x) ((x) << S_FATALPERREN)
+#define F_FATALPERREN    V_FATALPERREN(1U)
+
 #define S_CRSTWRM    1
 #define V_CRSTWRM(x) ((x) << S_CRSTWRM)
 #define F_CRSTWRM    V_CRSTWRM(1U)
index 8ff96c6f6de53304789a16de04a98ac86d1f7d15..c5a142bea5e92a759885a2a70115b4a3031fd871 100644 (file)
@@ -2022,7 +2022,7 @@ static void rx_eth(struct adapter *adap, struct sge_rspq *rq,
                qs->port_stats[SGE_PSTAT_RX_CSUM_GOOD]++;
                skb->ip_summed = CHECKSUM_UNNECESSARY;
        } else
-               skb->ip_summed = CHECKSUM_NONE;
+               skb_checksum_none_assert(skb);
        skb_record_rx_queue(skb, qs - &adap->sge.qs[0]);
 
        if (unlikely(p->vlan_valid)) {
index 427c451be1a78d64b6ed7ca4e710ce4fddee2192..d307c9de59fbda00e425138355574a44ffc6bbdf 100644 (file)
@@ -1408,6 +1408,7 @@ static int t3_handle_intr_status(struct adapter *adapter, unsigned int reg,
                        fatal++;
                        CH_ALERT(adapter, "%s (0x%x)\n",
                                 acts->msg, status & acts->mask);
+                       status &= ~acts->mask;
                } else if (acts->msg)
                        CH_WARN(adapter, "%s (0x%x)\n",
                                acts->msg, status & acts->mask);
@@ -1843,11 +1844,10 @@ static int mac_intr_handler(struct adapter *adap, unsigned int idx)
                t3_os_link_fault_handler(adap, idx);
        }
 
-       t3_write_reg(adap, A_XGM_INT_CAUSE + mac->offset, cause);
-
        if (cause & XGM_INTR_FATAL)
                t3_fatal_err(adap);
 
+       t3_write_reg(adap, A_XGM_INT_CAUSE + mac->offset, cause);
        return cause != 0;
 }
 
@@ -3569,6 +3569,7 @@ int t3_init_hw(struct adapter *adapter, u32 fw_params)
        t3_write_reg(adapter, A_PM1_TX_MODE, 0);
        chan_init_hw(adapter, adapter->params.chan_map);
        t3_sge_init(adapter, &adapter->params.sge);
+       t3_set_reg_field(adapter, A_PL_RST, 0, F_FATALPERREN);
 
        t3_write_reg(adapter, A_T3DBG_GPIO_ACT_LOW, calc_gpio_intr(adapter));
 
index 6e562c0dad7dee0a309b87a0e7cec03a91cf69ec..3ece9f5069fa6a4ac79ef32c2e768bbbfdce3978 100644 (file)
@@ -463,6 +463,8 @@ struct sge {
        u8 counter_val[SGE_NCOUNTERS];
        unsigned int starve_thres;
        u8 idma_state[2];
+       unsigned int egr_start;
+       unsigned int ingr_start;
        void *egr_map[MAX_EGRQ];    /* qid->queue egress queue map */
        struct sge_rspq *ingr_map[MAX_INGQ]; /* qid->queue ingress queue map */
        DECLARE_BITMAP(starving_fl, MAX_EGRQ);
index c327527fbbc854d6cf4f63d0457221cf434869e6..75b9401fd484c9f45ec2a3305b4d2d5a6d58f5ba 100644 (file)
@@ -175,16 +175,26 @@ enum {
 
 static DEFINE_PCI_DEVICE_TABLE(cxgb4_pci_tbl) = {
        CH_DEVICE(0xa000, 0),  /* PE10K */
-       CH_DEVICE(0x4001, 0),
-       CH_DEVICE(0x4002, 0),
-       CH_DEVICE(0x4003, 0),
-       CH_DEVICE(0x4004, 0),
-       CH_DEVICE(0x4005, 0),
-       CH_DEVICE(0x4006, 0),
-       CH_DEVICE(0x4007, 0),
-       CH_DEVICE(0x4008, 0),
-       CH_DEVICE(0x4009, 0),
-       CH_DEVICE(0x400a, 0),
+       CH_DEVICE(0x4001, -1),
+       CH_DEVICE(0x4002, -1),
+       CH_DEVICE(0x4003, -1),
+       CH_DEVICE(0x4004, -1),
+       CH_DEVICE(0x4005, -1),
+       CH_DEVICE(0x4006, -1),
+       CH_DEVICE(0x4007, -1),
+       CH_DEVICE(0x4008, -1),
+       CH_DEVICE(0x4009, -1),
+       CH_DEVICE(0x400a, -1),
+       CH_DEVICE(0x4401, 4),
+       CH_DEVICE(0x4402, 4),
+       CH_DEVICE(0x4403, 4),
+       CH_DEVICE(0x4404, 4),
+       CH_DEVICE(0x4405, 4),
+       CH_DEVICE(0x4406, 4),
+       CH_DEVICE(0x4407, 4),
+       CH_DEVICE(0x4408, 4),
+       CH_DEVICE(0x4409, 4),
+       CH_DEVICE(0x440a, 4),
        { 0, }
 };
 
@@ -423,10 +433,11 @@ static int fwevtq_handler(struct sge_rspq *q, const __be64 *rsp,
        if (likely(opcode == CPL_SGE_EGR_UPDATE)) {
                const struct cpl_sge_egr_update *p = (void *)rsp;
                unsigned int qid = EGR_QID(ntohl(p->opcode_qid));
-               struct sge_txq *txq = q->adap->sge.egr_map[qid];
+               struct sge_txq *txq;
 
+               txq = q->adap->sge.egr_map[qid - q->adap->sge.egr_start];
                txq->restarts++;
-               if ((u8 *)txq < (u8 *)q->adap->sge.ethrxq) {
+               if ((u8 *)txq < (u8 *)q->adap->sge.ofldtxq) {
                        struct sge_eth_txq *eq;
 
                        eq = container_of(txq, struct sge_eth_txq, q);
@@ -657,6 +668,15 @@ static int setup_rss(struct adapter *adap)
        return 0;
 }
 
+/*
+ * Return the channel of the ingress queue with the given qid.
+ */
+static unsigned int rxq_to_chan(const struct sge *p, unsigned int qid)
+{
+       qid -= p->ingr_start;
+       return netdev2pinfo(p->ingr_map[qid]->netdev)->tx_chan;
+}
+
 /*
  * Wait until all NAPI handlers are descheduled.
  */
@@ -1671,27 +1691,41 @@ static int get_coalesce(struct net_device *dev, struct ethtool_coalesce *c)
        return 0;
 }
 
-/*
- * Translate a physical EEPROM address to virtual.  The first 1K is accessed
- * through virtual addresses starting at 31K, the rest is accessed through
- * virtual addresses starting at 0.  This mapping is correct only for PF0.
+/**
+ *     eeprom_ptov - translate a physical EEPROM address to virtual
+ *     @phys_addr: the physical EEPROM address
+ *     @fn: the PCI function number
+ *     @sz: size of function-specific area
+ *
+ *     Translate a physical EEPROM address to virtual.  The first 1K is
+ *     accessed through virtual addresses starting at 31K, the rest is
+ *     accessed through virtual addresses starting at 0.
+ *
+ *     The mapping is as follows:
+ *     [0..1K) -> [31K..32K)
+ *     [1K..1K+A) -> [31K-A..31K)
+ *     [1K+A..ES) -> [0..ES-A-1K)
+ *
+ *     where A = @fn * @sz, and ES = EEPROM size.
  */
-static int eeprom_ptov(unsigned int phys_addr)
+static int eeprom_ptov(unsigned int phys_addr, unsigned int fn, unsigned int sz)
 {
+       fn *= sz;
        if (phys_addr < 1024)
                return phys_addr + (31 << 10);
+       if (phys_addr < 1024 + fn)
+               return 31744 - fn + phys_addr - 1024;
        if (phys_addr < EEPROMSIZE)
-               return phys_addr - 1024;
+               return phys_addr - 1024 - fn;
        return -EINVAL;
 }
 
 /*
  * The next two routines implement eeprom read/write from physical addresses.
- * The physical->virtual translation is correct only for PF0.
  */
 static int eeprom_rd_phys(struct adapter *adap, unsigned int phys_addr, u32 *v)
 {
-       int vaddr = eeprom_ptov(phys_addr);
+       int vaddr = eeprom_ptov(phys_addr, adap->fn, EEPROMPFSIZE);
 
        if (vaddr >= 0)
                vaddr = pci_read_vpd(adap->pdev, vaddr, sizeof(u32), v);
@@ -1700,7 +1734,7 @@ static int eeprom_rd_phys(struct adapter *adap, unsigned int phys_addr, u32 *v)
 
 static int eeprom_wr_phys(struct adapter *adap, unsigned int phys_addr, u32 v)
 {
-       int vaddr = eeprom_ptov(phys_addr);
+       int vaddr = eeprom_ptov(phys_addr, adap->fn, EEPROMPFSIZE);
 
        if (vaddr >= 0)
                vaddr = pci_write_vpd(adap->pdev, vaddr, sizeof(u32), &v);
@@ -1743,6 +1777,14 @@ static int set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
        aligned_offset = eeprom->offset & ~3;
        aligned_len = (eeprom->len + (eeprom->offset & 3) + 3) & ~3;
 
+       if (adapter->fn > 0) {
+               u32 start = 1024 + adapter->fn * EEPROMPFSIZE;
+
+               if (aligned_offset < start ||
+                   aligned_offset + aligned_len > start + EEPROMPFSIZE)
+                       return -EPERM;
+       }
+
        if (aligned_offset != eeprom->offset || aligned_len != eeprom->len) {
                /*
                 * RMW possibly needed for first or last words.
@@ -2304,7 +2346,7 @@ int cxgb4_create_server(const struct net_device *dev, unsigned int stid,
        req->peer_port = htons(0);
        req->local_ip = sip;
        req->peer_ip = htonl(0);
-       chan = netdev2pinfo(adap->sge.ingr_map[queue]->netdev)->tx_chan;
+       chan = rxq_to_chan(&adap->sge, queue);
        req->opt0 = cpu_to_be64(TX_CHAN(chan));
        req->opt1 = cpu_to_be64(CONN_POLICY_ASK |
                                SYN_RSS_ENABLE | SYN_RSS_QUEUE(queue));
@@ -2346,7 +2388,7 @@ int cxgb4_create_server6(const struct net_device *dev, unsigned int stid,
        req->local_ip_lo = *(__be64 *)(sip->s6_addr + 8);
        req->peer_ip_hi = cpu_to_be64(0);
        req->peer_ip_lo = cpu_to_be64(0);
-       chan = netdev2pinfo(adap->sge.ingr_map[queue]->netdev)->tx_chan;
+       chan = rxq_to_chan(&adap->sge, queue);
        req->opt0 = cpu_to_be64(TX_CHAN(chan));
        req->opt1 = cpu_to_be64(CONN_POLICY_ASK |
                                SYN_RSS_ENABLE | SYN_RSS_QUEUE(queue));
@@ -3061,12 +3103,16 @@ static int adap_init0(struct adapter *adap)
        params[2] = FW_PARAM_PFVF(L2T_END);
        params[3] = FW_PARAM_PFVF(FILTER_START);
        params[4] = FW_PARAM_PFVF(FILTER_END);
-       ret = t4_query_params(adap, adap->fn, adap->fn, 0, 5, params, val);
+       params[5] = FW_PARAM_PFVF(IQFLINT_START);
+       params[6] = FW_PARAM_PFVF(EQ_START);
+       ret = t4_query_params(adap, adap->fn, adap->fn, 0, 7, params, val);
        if (ret < 0)
                goto bye;
        port_vec = val[0];
        adap->tids.ftid_base = val[3];
        adap->tids.nftids = val[4] - val[3] + 1;
+       adap->sge.ingr_start = val[5];
+       adap->sge.egr_start = val[6];
 
        if (c.ofldcaps) {
                /* query offload-related parameters */
index bf38cfc575655650b46038f9722170c801f75070..9967f3debce7e1010bd6ff58df5d6ad2060543d3 100644 (file)
@@ -557,7 +557,8 @@ out:        cred = q->avail - cred;
 
        if (unlikely(fl_starving(q))) {
                smp_wmb();
-               set_bit(q->cntxt_id, adap->sge.starving_fl);
+               set_bit(q->cntxt_id - adap->sge.egr_start,
+                       adap->sge.starving_fl);
        }
 
        return cred;
@@ -974,7 +975,7 @@ out_free:   dev_kfree_skb(skb);
        }
 
        cpl->ctrl0 = htonl(TXPKT_OPCODE(CPL_TX_PKT_XT) |
-                          TXPKT_INTF(pi->tx_chan) | TXPKT_PF(0));
+                          TXPKT_INTF(pi->tx_chan) | TXPKT_PF(adap->fn));
        cpl->pack = htons(0);
        cpl->len = htons(skb->len);
        cpl->ctrl1 = cpu_to_be64(cntrl);
@@ -1213,7 +1214,8 @@ static void txq_stop_maperr(struct sge_ofld_txq *q)
 {
        q->mapping_err++;
        q->q.stops++;
-       set_bit(q->q.cntxt_id, q->adap->sge.txq_maperr);
+       set_bit(q->q.cntxt_id - q->adap->sge.egr_start,
+               q->adap->sge.txq_maperr);
 }
 
 /**
@@ -1603,7 +1605,7 @@ int t4_ethrx_handler(struct sge_rspq *q, const __be64 *rsp,
                        rxq->stats.rx_cso++;
                }
        } else
-               skb->ip_summed = CHECKSUM_NONE;
+               skb_checksum_none_assert(skb);
 
        if (unlikely(pkt->vlan_ex)) {
                struct vlan_group *grp = pi->vlan_grp;
@@ -1835,6 +1837,7 @@ static unsigned int process_intrq(struct adapter *adap)
                if (RSPD_TYPE(rc->type_gen) == RSP_TYPE_INTR) {
                        unsigned int qid = ntohl(rc->pldbuflen_qid);
 
+                       qid -= adap->sge.ingr_start;
                        napi_schedule(&adap->sge.ingr_map[qid]->napi);
                }
 
@@ -2050,14 +2053,14 @@ int t4_sge_alloc_rxq(struct adapter *adap, struct sge_rspq *iq, bool fwevtq,
        /* set offset to -1 to distinguish ingress queues without FL */
        iq->offset = fl ? 0 : -1;
 
-       adap->sge.ingr_map[iq->cntxt_id] = iq;
+       adap->sge.ingr_map[iq->cntxt_id - adap->sge.ingr_start] = iq;
 
        if (fl) {
                fl->cntxt_id = ntohs(c.fl0id);
                fl->avail = fl->pend_cred = 0;
                fl->pidx = fl->cidx = 0;
                fl->alloc_failed = fl->large_alloc_failed = fl->starving = 0;
-               adap->sge.egr_map[fl->cntxt_id] = fl;
+               adap->sge.egr_map[fl->cntxt_id - adap->sge.egr_start] = fl;
                refill_fl(adap, fl, fl_cap(fl), GFP_KERNEL);
        }
        return 0;
@@ -2087,7 +2090,7 @@ static void init_txq(struct adapter *adap, struct sge_txq *q, unsigned int id)
        q->stops = q->restarts = 0;
        q->stat = (void *)&q->desc[q->size];
        q->cntxt_id = id;
-       adap->sge.egr_map[id] = q;
+       adap->sge.egr_map[id - adap->sge.egr_start] = q;
 }
 
 int t4_sge_alloc_eth_txq(struct adapter *adap, struct sge_eth_txq *txq,
@@ -2259,7 +2262,7 @@ static void free_rspq_fl(struct adapter *adap, struct sge_rspq *rq,
 {
        unsigned int fl_id = fl ? fl->cntxt_id : 0xffff;
 
-       adap->sge.ingr_map[rq->cntxt_id] = NULL;
+       adap->sge.ingr_map[rq->cntxt_id - adap->sge.ingr_start] = NULL;
        t4_iq_free(adap, adap->fn, adap->fn, 0, FW_IQ_TYPE_FL_INT_CAP,
                   rq->cntxt_id, fl_id, 0xffff);
        dma_free_coherent(adap->pdev_dev, (rq->size + 1) * rq->iqe_len,
index 10a055565776cfceb4730df1168b44662d4d9761..c26b455f37de54c1075a93e6d100282ef8c6e134 100644 (file)
@@ -42,6 +42,7 @@ enum {
        MAX_MTU        = 9600,  /* max MAC MTU, excluding header + FCS */
        EEPROMSIZE     = 17408, /* Serial EEPROM physical size */
        EEPROMVSIZE    = 32768, /* Serial EEPROM virtual address space size */
+       EEPROMPFSIZE   = 1024,  /* EEPROM writable area size for PFn, n>0 */
        RSS_NENTRIES   = 2048,  /* # of entries in RSS mapping table */
        TCB_SIZE       = 128,   /* TCB size */
        NMTUS          = 16,    /* size of MTU table */
index 0969f2fbc1b0f0a977b1e470a1f4d60e19be215c..940584a8a640b077374e5caf1319341773f08fd3 100644 (file)
@@ -487,6 +487,11 @@ enum fw_params_param_pfvf {
        FW_PARAMS_PARAM_PFVF_CPMASK     = 0x25,
        FW_PARAMS_PARAM_PFVF_OCQ_START  = 0x26,
        FW_PARAMS_PARAM_PFVF_OCQ_END    = 0x27,
+       FW_PARAMS_PARAM_PFVF_CONM_MAP   = 0x28,
+       FW_PARAMS_PARAM_PFVF_IQFLINT_START = 0x29,
+       FW_PARAMS_PARAM_PFVF_IQFLINT_END = 0x2A,
+       FW_PARAMS_PARAM_PFVF_EQ_START   = 0x2B,
+       FW_PARAMS_PARAM_PFVF_EQ_END     = 0x2C,
 };
 
 /*
index eb5a1c9cb2d3b588a309ea9cefc326ef1ee71b81..f10864ddafbef62492fc95608e0d0f7b8737c561 100644 (file)
@@ -1520,7 +1520,6 @@ int t4vf_ethrx_handler(struct sge_rspq *rspq, const __be64 *rsp,
        __skb_pull(skb, PKTSHIFT);
        skb->protocol = eth_type_trans(skb, rspq->netdev);
        skb_record_rx_queue(skb, rspq->idx);
-       skb->dev->last_rx = jiffies;                  /* XXX removed 2.6.29 */
        pi = netdev_priv(skb->dev);
        rxq->stats.pkts++;
 
@@ -1535,7 +1534,7 @@ int t4vf_ethrx_handler(struct sge_rspq *rspq, const __be64 *rsp,
                }
                rxq->stats.rx_cso++;
        } else
-               skb->ip_summed = CHECKSUM_NONE;
+               skb_checksum_none_assert(skb);
 
        if (unlikely(pkt->vlan_ex)) {
                struct vlan_group *grp = pi->vlan_grp;
index d7de376d7178ad2b9470797d5cab92846277e363..219eb5ad5c128bda75e0a9c3bcaabd9ef6df8e31 100644 (file)
@@ -1255,7 +1255,7 @@ static int __devinit dec_lance_probe(struct device *bdev, const int type)
         */
        init_timer(&lp->multicast_timer);
        lp->multicast_timer.data = (unsigned long) dev;
-       lp->multicast_timer.function = &lance_set_multicast_retry;
+       lp->multicast_timer.function = lance_set_multicast_retry;
 
        ret = register_netdev(dev);
        if (ret) {
index a2f238d20caab0cfa80f196890ea6b96f47df363..e1a8216ff6926608759e9da69313c1d1958f4759 100644 (file)
@@ -465,7 +465,7 @@ rio_open (struct net_device *dev)
        init_timer (&np->timer);
        np->timer.expires = jiffies + 1*HZ;
        np->timer.data = (unsigned long) dev;
-       np->timer.function = &rio_timer;
+       np->timer.function = rio_timer;
        add_timer (&np->timer);
 
        /* Start Tx/Rx */
index 4fd6b2b4554b18e0072048bd2f018b5497072b89..9f6aeefa06bf9dd8060da75e57d5b796450abd32 100644 (file)
@@ -1056,7 +1056,7 @@ dm9000_rx(struct net_device *dev)
                                if ((((rxbyte & 0x1c) << 3) & rxbyte) == 0)
                                        skb->ip_summed = CHECKSUM_UNNECESSARY;
                                else
-                                       skb->ip_summed = CHECKSUM_NONE;
+                                       skb_checksum_none_assert(skb);
                        }
                        netif_rx(skb);
                        dev->stats.rx_packets++;
index 5cc39ed289c62234d2f56cd9ad4c1eb841c26b8e..8d9269d12a67f3b7eb69f3fbf65b0483fb14cbee 100644 (file)
@@ -789,6 +789,70 @@ static const struct net_device_ops e1000_netdev_ops = {
 #endif
 };
 
+/**
+ * e1000_init_hw_struct - initialize members of hw struct
+ * @adapter: board private struct
+ * @hw: structure used by e1000_hw.c
+ *
+ * Factors out initialization of the e1000_hw struct to its own function
+ * that can be called very early at init (just after struct allocation).
+ * Fields are initialized based on PCI device information and
+ * OS network device settings (MTU size).
+ * Returns negative error codes if MAC type setup fails.
+ */
+static int e1000_init_hw_struct(struct e1000_adapter *adapter,
+                               struct e1000_hw *hw)
+{
+       struct pci_dev *pdev = adapter->pdev;
+
+       /* PCI config space info */
+       hw->vendor_id = pdev->vendor;
+       hw->device_id = pdev->device;
+       hw->subsystem_vendor_id = pdev->subsystem_vendor;
+       hw->subsystem_id = pdev->subsystem_device;
+       hw->revision_id = pdev->revision;
+
+       pci_read_config_word(pdev, PCI_COMMAND, &hw->pci_cmd_word);
+
+       hw->max_frame_size = adapter->netdev->mtu +
+                            ENET_HEADER_SIZE + ETHERNET_FCS_SIZE;
+       hw->min_frame_size = MINIMUM_ETHERNET_FRAME_SIZE;
+
+       /* identify the MAC */
+       if (e1000_set_mac_type(hw)) {
+               e_err(probe, "Unknown MAC Type\n");
+               return -EIO;
+       }
+
+       switch (hw->mac_type) {
+       default:
+               break;
+       case e1000_82541:
+       case e1000_82547:
+       case e1000_82541_rev_2:
+       case e1000_82547_rev_2:
+               hw->phy_init_script = 1;
+               break;
+       }
+
+       e1000_set_media_type(hw);
+       e1000_get_bus_info(hw);
+
+       hw->wait_autoneg_complete = false;
+       hw->tbi_compatibility_en = true;
+       hw->adaptive_ifs = true;
+
+       /* Copper options */
+
+       if (hw->media_type == e1000_media_type_copper) {
+               hw->mdix = AUTO_ALL_MODES;
+               hw->disable_polarity_correction = false;
+               hw->master_slave = E1000_MASTER_SLAVE;
+       }
+
+       return 0;
+}
+
 /**
  * e1000_probe - Device Initialization Routine
  * @pdev: PCI device information struct
@@ -826,22 +890,6 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
        if (err)
                return err;
 
-       if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(64)) &&
-           !dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64))) {
-               pci_using_dac = 1;
-       } else {
-               err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
-               if (err) {
-                       err = dma_set_coherent_mask(&pdev->dev,
-                                                   DMA_BIT_MASK(32));
-                       if (err) {
-                               pr_err("No usable DMA config, aborting\n");
-                               goto err_dma;
-                       }
-               }
-               pci_using_dac = 0;
-       }
-
        err = pci_request_selected_regions(pdev, bars, e1000_driver_name);
        if (err)
                goto err_pci_reg;
@@ -885,6 +933,32 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
                }
        }
 
+       /* make ready for any if (hw->...) below */
+       err = e1000_init_hw_struct(adapter, hw);
+       if (err)
+               goto err_sw_init;
+
+       /*
+        * there is a workaround being applied below that limits
+        * 64-bit DMA addresses to 64-bit hardware.  There are some
+        * 32-bit adapters that Tx hang when given 64-bit DMA addresses
+        */
+       pci_using_dac = 0;
+       if ((hw->bus_type == e1000_bus_type_pcix) &&
+           !dma_set_mask(&pdev->dev, DMA_BIT_MASK(64))) {
+               /*
+                * according to DMA-API-HOWTO, coherent calls will always
+                * succeed if the set call did
+                */
+               dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64));
+               pci_using_dac = 1;
+       } else if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) {
+               dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
+       } else {
+               pr_err("No usable DMA config, aborting\n");
+               goto err_dma;
+       }
+
        netdev->netdev_ops = &e1000_netdev_ops;
        e1000_set_ethtool_ops(netdev);
        netdev->watchdog_timeo = 5 * HZ;
@@ -959,18 +1033,16 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
        if (!is_valid_ether_addr(netdev->perm_addr))
                e_err(probe, "Invalid MAC Address\n");
 
-       e1000_get_bus_info(hw);
-
        init_timer(&adapter->tx_fifo_stall_timer);
-       adapter->tx_fifo_stall_timer.function = &e1000_82547_tx_fifo_stall;
+       adapter->tx_fifo_stall_timer.function = e1000_82547_tx_fifo_stall;
        adapter->tx_fifo_stall_timer.data = (unsigned long)adapter;
 
        init_timer(&adapter->watchdog_timer);
-       adapter->watchdog_timer.function = &e1000_watchdog;
+       adapter->watchdog_timer.function = e1000_watchdog;
        adapter->watchdog_timer.data = (unsigned long) adapter;
 
        init_timer(&adapter->phy_info_timer);
-       adapter->phy_info_timer.function = &e1000_update_phy_info;
+       adapter->phy_info_timer.function = e1000_update_phy_info;
        adapter->phy_info_timer.data = (unsigned long)adapter;
 
        INIT_WORK(&adapter->reset_task, e1000_reset_task);
@@ -1072,6 +1144,7 @@ err_eeprom:
                iounmap(hw->flash_address);
        kfree(adapter->tx_ring);
        kfree(adapter->rx_ring);
+err_dma:
 err_sw_init:
        iounmap(hw->hw_addr);
 err_ioremap:
@@ -1079,7 +1152,6 @@ err_ioremap:
 err_alloc_etherdev:
        pci_release_selected_regions(pdev, bars);
 err_pci_reg:
-err_dma:
        pci_disable_device(pdev);
        return err;
 }
@@ -1131,62 +1203,12 @@ static void __devexit e1000_remove(struct pci_dev *pdev)
  * @adapter: board private structure to initialize
  *
  * e1000_sw_init initializes the Adapter private data structure.
- * Fields are initialized based on PCI device information and
- * OS network device settings (MTU size).
+ * e1000_init_hw_struct MUST be called before this function
  **/
 
 static int __devinit e1000_sw_init(struct e1000_adapter *adapter)
 {
-       struct e1000_hw *hw = &adapter->hw;
-       struct net_device *netdev = adapter->netdev;
-       struct pci_dev *pdev = adapter->pdev;
-
-       /* PCI config space info */
-
-       hw->vendor_id = pdev->vendor;
-       hw->device_id = pdev->device;
-       hw->subsystem_vendor_id = pdev->subsystem_vendor;
-       hw->subsystem_id = pdev->subsystem_device;
-       hw->revision_id = pdev->revision;
-
-       pci_read_config_word(pdev, PCI_COMMAND, &hw->pci_cmd_word);
-
        adapter->rx_buffer_len = MAXIMUM_ETHERNET_VLAN_SIZE;
-       hw->max_frame_size = netdev->mtu +
-                            ENET_HEADER_SIZE + ETHERNET_FCS_SIZE;
-       hw->min_frame_size = MINIMUM_ETHERNET_FRAME_SIZE;
-
-       /* identify the MAC */
-
-       if (e1000_set_mac_type(hw)) {
-               e_err(probe, "Unknown MAC Type\n");
-               return -EIO;
-       }
-
-       switch (hw->mac_type) {
-       default:
-               break;
-       case e1000_82541:
-       case e1000_82547:
-       case e1000_82541_rev_2:
-       case e1000_82547_rev_2:
-               hw->phy_init_script = 1;
-               break;
-       }
-
-       e1000_set_media_type(hw);
-
-       hw->wait_autoneg_complete = false;
-       hw->tbi_compatibility_en = true;
-       hw->adaptive_ifs = true;
-
-       /* Copper options */
-
-       if (hw->media_type == e1000_media_type_copper) {
-               hw->mdix = AUTO_ALL_MODES;
-               hw->disable_polarity_correction = false;
-               hw->master_slave = E1000_MASTER_SLAVE;
-       }
 
        adapter->num_tx_queues = 1;
        adapter->num_rx_queues = 1;
@@ -3552,7 +3574,8 @@ static void e1000_rx_checksum(struct e1000_adapter *adapter, u32 status_err,
        struct e1000_hw *hw = &adapter->hw;
        u16 status = (u16)status_err;
        u8 errors = (u8)(status_err >> 24);
-       skb->ip_summed = CHECKSUM_NONE;
+
+       skb_checksum_none_assert(skb);
 
        /* 82543 or newer only */
        if (unlikely(hw->mac_type < e1000_82543)) return;
index 2b8ef44bd2b1629c5d203206479a3b8bab510fab..c9b66f4727e4535eb2de110133d86f0229eb36b0 100644 (file)
@@ -475,7 +475,8 @@ static void e1000_rx_checksum(struct e1000_adapter *adapter, u32 status_err,
 {
        u16 status = (u16)status_err;
        u8 errors = (u8)(status_err >> 24);
-       skb->ip_summed = CHECKSUM_NONE;
+
+       skb_checksum_none_assert(skb);
 
        /* Ignore Checksum bit is set */
        if (status & E1000_RXD_STAT_IXSM)
@@ -5745,11 +5746,11 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
        }
 
        init_timer(&adapter->watchdog_timer);
-       adapter->watchdog_timer.function = &e1000_watchdog;
+       adapter->watchdog_timer.function = e1000_watchdog;
        adapter->watchdog_timer.data = (unsigned long) adapter;
 
        init_timer(&adapter->phy_info_timer);
-       adapter->phy_info_timer.function = &e1000_update_phy_info;
+       adapter->phy_info_timer.function = e1000_update_phy_info;
        adapter->phy_info_timer.data = (unsigned long) adapter;
 
        INIT_WORK(&adapter->reset_task, e1000_reset_task);
index 8d97f168f018734bcaeb1af1372b77ba9fca2eef..7c826319ee5a153111a59a1c517992dadcd5a84e 100644 (file)
@@ -1457,11 +1457,11 @@ hardware_send_packet(struct net_device *dev, void *buf, short length)
        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)
+       /* 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 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) {
index a333b42111b8c2ba20b92eca94bf5648704c4f9a..043d99013056447e1ab72f2b491c46271a1ddaf2 100644 (file)
@@ -180,7 +180,7 @@ static void ehea_update_firmware_handles(void)
                         num_portres * EHEA_NUM_PORTRES_FW_HANDLES;
 
        if (num_fw_handles) {
-               arr = kzalloc(num_fw_handles * sizeof(*arr), GFP_KERNEL);
+               arr = kcalloc(num_fw_handles, sizeof(*arr), GFP_KERNEL);
                if (!arr)
                        goto out;  /* Keep the existing array */
        } else
@@ -265,7 +265,7 @@ static void ehea_update_bcmc_registrations(void)
                }
 
        if (num_registrations) {
-               arr = kzalloc(num_registrations * sizeof(*arr), GFP_ATOMIC);
+               arr = kcalloc(num_registrations, sizeof(*arr), GFP_ATOMIC);
                if (!arr)
                        goto out;  /* Keep the existing array */
        } else
@@ -3721,7 +3721,7 @@ int __init ehea_module_init(void)
        if (ret)
                ehea_info("failed registering memory remove notifier");
 
-       ret = crash_shutdown_register(&ehea_crash_handler);
+       ret = crash_shutdown_register(ehea_crash_handler);
        if (ret)
                ehea_info("failed registering crash handler");
 
@@ -3746,7 +3746,7 @@ out3:
 out2:
        unregister_memory_notifier(&ehea_mem_nb);
        unregister_reboot_notifier(&ehea_reboot_nb);
-       crash_shutdown_unregister(&ehea_crash_handler);
+       crash_shutdown_unregister(ehea_crash_handler);
 out:
        return ret;
 }
@@ -3759,7 +3759,7 @@ static void __exit ehea_module_exit(void)
        driver_remove_file(&ehea_driver.driver, &driver_attr_capabilities);
        ibmebus_unregister_driver(&ehea_driver);
        unregister_reboot_notifier(&ehea_reboot_nb);
-       ret = crash_shutdown_unregister(&ehea_crash_handler);
+       ret = crash_shutdown_unregister(ehea_crash_handler);
        if (ret)
                ehea_info("failed unregistering crash handler");
        unregister_memory_notifier(&ehea_mem_nb);
index f239aa8c6f4ce6d6e86341ab09ca461fdd76f89e..75869ed7226f81d3c7957656823f30c86049af32 100644 (file)
@@ -32,7 +32,7 @@
 
 #define DRV_NAME               "enic"
 #define DRV_DESCRIPTION                "Cisco VIC Ethernet NIC Driver"
-#define DRV_VERSION            "1.4.1.1"
+#define DRV_VERSION            "1.4.1.2"
 #define DRV_COPYRIGHT          "Copyright 2008-2010 Cisco Systems, Inc"
 
 #define ENIC_BARS_MAX          6
index 9aab85366d21e782e0f60d5c2e917f3ee2759780..711077a2e3451191ad98c9563cec376e06db15e0 100644 (file)
@@ -911,7 +911,9 @@ static int enic_set_mac_address_dynamic(struct net_device *netdev, void *p)
 
 static int enic_set_mac_address(struct net_device *netdev, void *p)
 {
-       return -EOPNOTSUPP;
+       struct sockaddr *saddr = p;
+
+       return enic_set_mac_addr(netdev, (char *)saddr->sa_data);
 }
 
 static int enic_dev_packet_filter(struct enic *enic, int directed,
@@ -2152,17 +2154,6 @@ void enic_dev_deinit(struct enic *enic)
        enic_clear_intr_mode(enic);
 }
 
-static int enic_dev_stats_clear(struct enic *enic)
-{
-       int err;
-
-       spin_lock(&enic->devcmd_lock);
-       err = vnic_dev_stats_clear(enic->vdev);
-       spin_unlock(&enic->devcmd_lock);
-
-       return err;
-}
-
 int enic_dev_init(struct enic *enic)
 {
        struct device *dev = enic_get_dev(enic);
@@ -2205,10 +2196,6 @@ int enic_dev_init(struct enic *enic)
 
        enic_init_vnic_resources(enic);
 
-       /* Clear LIF stats
-        */
-       enic_dev_stats_clear(enic);
-
        err = enic_set_rq_alloc_buf(enic);
        if (err) {
                dev_err(dev, "Failed to set RQ buffer allocator, aborting\n");
index 6a5b578a69e169501f27eca1ec31262b3fc0d3d2..08d5d42da2605856859110f33dc02fe8b03d3331 100644 (file)
@@ -74,6 +74,7 @@ static int vnic_dev_discover_res(struct vnic_dev *vdev,
        struct vnic_dev_bar *bar, unsigned int num_bars)
 {
        struct vnic_resource_header __iomem *rh;
+       struct mgmt_barmap_hdr __iomem *mrh;
        struct vnic_resource __iomem *r;
        u8 type;
 
@@ -85,22 +86,32 @@ static int vnic_dev_discover_res(struct vnic_dev *vdev,
                return -EINVAL;
        }
 
-       rh = bar->vaddr;
+       rh  = bar->vaddr;
+       mrh = bar->vaddr;
        if (!rh) {
                pr_err("vNIC BAR0 res hdr not mem-mapped\n");
                return -EINVAL;
        }
 
-       if (ioread32(&rh->magic) != VNIC_RES_MAGIC ||
-           ioread32(&rh->version) != VNIC_RES_VERSION) {
-               pr_err("vNIC BAR0 res magic/version error "
-                       "exp (%lx/%lx) curr (%x/%x)\n",
+       /* Check for mgmt vnic in addition to normal vnic */
+       if ((ioread32(&rh->magic) != VNIC_RES_MAGIC) ||
+               (ioread32(&rh->version) != VNIC_RES_VERSION)) {
+               if ((ioread32(&mrh->magic) != MGMTVNIC_MAGIC) ||
+                       (ioread32(&mrh->version) != MGMTVNIC_VERSION)) {
+                       pr_err("vNIC BAR0 res magic/version error "
+                       "exp (%lx/%lx) or (%lx/%lx), curr (%x/%x)\n",
                        VNIC_RES_MAGIC, VNIC_RES_VERSION,
+                       MGMTVNIC_MAGIC, MGMTVNIC_VERSION,
                        ioread32(&rh->magic), ioread32(&rh->version));
-               return -EINVAL;
+                       return -EINVAL;
+               }
        }
 
-       r = (struct vnic_resource __iomem *)(rh + 1);
+       if (ioread32(&mrh->magic) == MGMTVNIC_MAGIC)
+               r = (struct vnic_resource __iomem *)(mrh + 1);
+       else
+               r = (struct vnic_resource __iomem *)(rh + 1);
+
 
        while ((type = ioread8(&r->type)) != RES_TYPE_EOL) {
 
index 20661755df6bf4c96f9209efe4767a53c9217cdd..9abb3d51dea18bbdb33d361dc443a41b30721752 100644 (file)
@@ -238,6 +238,18 @@ enum vnic_devcmd_cmd {
         * out: (u32)a0=status of proxied cmd
         *      a1-a15=out args of proxied cmd */
        CMD_PROXY_BY_BDF =      _CMDC(_CMD_DIR_RW, _CMD_VTYPE_ALL, 42),
+
+       /*
+        * As for BY_BDF except a0 is index of hvnlink subordinate vnic
+        * or SR-IOV virtual vnic */
+       CMD_PROXY_BY_INDEX =    _CMDC(_CMD_DIR_RW, _CMD_VTYPE_ALL, 43),
+
+       /*
+        * in:  (u64)a0=paddr of buffer to put latest VIC VIF-CONFIG-INFO TLV in
+        *      (u32)a1=length of buffer in a0
+        * out: (u64)a0=paddr of buffer with latest VIC VIF-CONFIG-INFO TLV
+        *      (u32)a1=actual length of latest VIC VIF-CONFIG-INFO TLV */
+       CMD_CONFIG_INFO_GET     = _CMDC(_CMD_DIR_RW, _CMD_VTYPE_ALL, 44),
 };
 
 /* flags for CMD_OPEN */
index 3b3291248956a4d01848b635bf294f2622c175e7..e8740e3704e495eedbdb4726bc0f48bff72b06ff 100644 (file)
@@ -30,7 +30,7 @@ struct vnic_enet_config {
        u32 wq_desc_count;
        u32 rq_desc_count;
        u16 mtu;
-       u16 intr_timer;
+       u16 intr_timer_deprecated;
        u8 intr_timer_type;
        u8 intr_mode;
        char devname[16];
index 810287beff149f2969e0bda67b28754d600555e9..e0a73f1ca6f43e3b66558edb933cb9a9105aa5bb 100644 (file)
 
 #define VNIC_RES_MAGIC         0x766E6963L     /* 'vnic' */
 #define VNIC_RES_VERSION       0x00000000L
+#define MGMTVNIC_MAGIC         0x544d474dL     /* 'MGMT' */
+#define MGMTVNIC_VERSION       0x00000000L
+
+/* The MAC address assigned to the CFG vNIC is fixed. */
+#define MGMTVNIC_MAC           { 0x02, 0x00, 0x54, 0x4d, 0x47, 0x4d }
 
 /* vNIC resource types */
 enum vnic_res_type {
@@ -52,6 +57,14 @@ struct vnic_resource_header {
        u32 version;
 };
 
+struct mgmt_barmap_hdr {
+       u32 magic;                      /* magic number */
+       u32 version;                    /* header format version */
+       u16 lif;                        /* loopback lif for mgmt frames */
+       u16 pci_slot;                   /* installed pci slot */
+       char serial[16];                /* card serial number */
+};
+
 struct vnic_resource {
        u8 type;
        u8 bar;
index dbb2aca258b9087ed1734dd2b7da61e478702303..b236d7cbc137ba0831c8bb6aa5e046038a236d76 100644 (file)
@@ -77,8 +77,10 @@ void vnic_rq_free(struct vnic_rq *rq)
        vnic_dev_free_desc_ring(vdev, &rq->ring);
 
        for (i = 0; i < VNIC_RQ_BUF_BLKS_MAX; i++) {
-               kfree(rq->bufs[i]);
-               rq->bufs[i] = NULL;
+               if (rq->bufs[i]) {
+                       kfree(rq->bufs[i]);
+                       rq->bufs[i] = NULL;
+               }
        }
 
        rq->ctrl = NULL;
index 197c9d24af824552a62622ec3aebfc39ec9b02cf..4725b79de0ef1686484e71dda80e9ae2aad48bc1 100644 (file)
@@ -54,8 +54,8 @@ int vic_provinfo_add_tlv(struct vic_provinfo *vp, u16 type, u16 length,
        if (!vp || !value)
                return -EINVAL;
 
-       if (ntohl(vp->length) + sizeof(*tlv) + length >
-               VIC_PROVINFO_MAX_TLV_DATA)
+       if (ntohl(vp->length) + offsetof(struct vic_provinfo_tlv, value) +
+               length > VIC_PROVINFO_MAX_TLV_DATA)
                return -ENOMEM;
 
        tlv = (struct vic_provinfo_tlv *)((u8 *)vp->tlv +
@@ -66,7 +66,8 @@ int vic_provinfo_add_tlv(struct vic_provinfo *vp, u16 type, u16 length,
        memcpy(tlv->value, value, length);
 
        vp->num_tlvs = htonl(ntohl(vp->num_tlvs) + 1);
-       vp->length = htonl(ntohl(vp->length) + sizeof(*tlv) + length);
+       vp->length = htonl(ntohl(vp->length) +
+               offsetof(struct vic_provinfo_tlv, value) + length);
 
        return 0;
 }
index 122e33bcc57826a1ef08abf0337a3b97da014570..4b2a6c6a569be11752846674727e7fdfaf02133f 100644 (file)
@@ -77,8 +77,10 @@ void vnic_wq_free(struct vnic_wq *wq)
        vnic_dev_free_desc_ring(vdev, &wq->ring);
 
        for (i = 0; i < VNIC_WQ_BUF_BLKS_MAX; i++) {
-               kfree(wq->bufs[i]);
-               wq->bufs[i] = NULL;
+               if (wq->bufs[i]) {
+                       kfree(wq->bufs[i]);
+                       wq->bufs[i] = NULL;
+               }
        }
 
        wq->ctrl = NULL;
index 57c8ac0ef3f1232d41e4f00399eb27b18170dcf6..32543a300b810aeddecc69db0c25d9cf8e44e0ff 100644 (file)
@@ -758,7 +758,7 @@ static int epic_open(struct net_device *dev)
        init_timer(&ep->timer);
        ep->timer.expires = jiffies + 3*HZ;
        ep->timer.data = (unsigned long)dev;
-       ep->timer.function = &epic_timer;                               /* timer handler */
+       ep->timer.function = epic_timer;                                /* timer handler */
        add_timer(&ep->timer);
 
        return 0;
index 6d653c459c1f7e817661225619ddb837ddb0622e..c5a2fe099a8d772d6ef158bfac61bbe903f54aaa 100644 (file)
@@ -806,11 +806,6 @@ static void ethoc_tx_timeout(struct net_device *dev)
                ethoc_interrupt(dev->irq, dev);
 }
 
-static struct net_device_stats *ethoc_stats(struct net_device *dev)
-{
-       return &dev->stats;
-}
-
 static netdev_tx_t ethoc_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct ethoc *priv = netdev_priv(dev);
@@ -863,7 +858,6 @@ static const struct net_device_ops ethoc_netdev_ops = {
        .ndo_set_multicast_list = ethoc_set_multicast_list,
        .ndo_change_mtu = ethoc_change_mtu,
        .ndo_tx_timeout = ethoc_tx_timeout,
-       .ndo_get_stats = ethoc_stats,
        .ndo_start_xmit = ethoc_start_xmit,
 };
 
index d7e8f6b8f4cf38c54107b5a616d87af7c0b5db3d..dd54abe2f7103d1a4eef72928b4f0494f212a013 100644 (file)
@@ -915,14 +915,14 @@ static int netdev_open(struct net_device *dev)
        init_timer(&np->timer);
        np->timer.expires = RUN_AT(3 * HZ);
        np->timer.data = (unsigned long) dev;
-       np->timer.function = &netdev_timer;
+       np->timer.function = netdev_timer;
 
        /* timer handler */
        add_timer(&np->timer);
 
        init_timer(&np->reset_timer);
        np->reset_timer.data = (unsigned long) dev;
-       np->reset_timer.function = &reset_timer;
+       np->reset_timer.function = reset_timer;
        np->reset_timer_armed = 0;
 
        return 0;
index e3e10b4add9ce3e2f1f55adf54707190a6622ea9..e9f5d030bc267923acb405d394f1ba67be1101ae 100644 (file)
@@ -771,11 +771,6 @@ static void mpc52xx_fec_reset(struct net_device *dev)
 
 
 /* ethtool interface */
-static void mpc52xx_fec_get_drvinfo(struct net_device *dev,
-               struct ethtool_drvinfo *info)
-{
-       strcpy(info->driver, DRIVER_NAME);
-}
 
 static int mpc52xx_fec_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
@@ -810,7 +805,6 @@ static void mpc52xx_fec_set_msglevel(struct net_device *dev, u32 level)
 }
 
 static const struct ethtool_ops mpc52xx_fec_ethtool_ops = {
-       .get_drvinfo = mpc52xx_fec_get_drvinfo,
        .get_settings = mpc52xx_fec_get_settings,
        .set_settings = mpc52xx_fec_set_settings,
        .get_link = ethtool_op_get_link,
index 4da05b1b445c033a3606bdd0d1cf05ca0675660b..6a44fe4115892c28b17b9687d8ecc587d3d2b7db 100644 (file)
@@ -5440,13 +5440,13 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
 
        init_timer(&np->oom_kick);
        np->oom_kick.data = (unsigned long) dev;
-       np->oom_kick.function = &nv_do_rx_refill;       /* timer handler */
+       np->oom_kick.function = nv_do_rx_refill;        /* timer handler */
        init_timer(&np->nic_poll);
        np->nic_poll.data = (unsigned long) dev;
-       np->nic_poll.function = &nv_do_nic_poll;        /* timer handler */
+       np->nic_poll.function = nv_do_nic_poll; /* timer handler */
        init_timer(&np->stats_poll);
        np->stats_poll.data = (unsigned long) dev;
-       np->stats_poll.function = &nv_do_stats_poll;    /* timer handler */
+       np->stats_poll.function = nv_do_stats_poll;     /* timer handler */
 
        err = pci_enable_device(pci_dev);
        if (err)
index d6e3111959abc49d82849fc22dd2ad6a3ec62b1b..d684f187de57714f4b38a2e7e8bf58771234d0a5 100644 (file)
@@ -1036,7 +1036,7 @@ static int __devinit fs_enet_probe(struct platform_device *ofdev,
        ndev = alloc_etherdev(privsize);
        if (!ndev) {
                ret = -ENOMEM;
-               goto out_free_fpi;
+               goto out_put;
        }
 
        SET_NETDEV_DEV(ndev, &ofdev->dev);
@@ -1099,6 +1099,7 @@ out_cleanup_data:
 out_free_dev:
        free_netdev(ndev);
        dev_set_drvdata(&ofdev->dev, NULL);
+out_put:
        of_node_put(fpi->phy_node);
 out_free_fpi:
        kfree(fpi);
index 4f7c3f3ca234634203c246d4e6494930de5f7247..f30adbf86bb2978b731e0b9c8ac60aef3e98e2ec 100644 (file)
@@ -1859,7 +1859,7 @@ static int register_grp_irqs(struct gfar_priv_grp *grp)
                                printk(KERN_ERR "%s: Can't get IRQ %d\n",
                                        dev->name, grp->interruptError);
 
-                               goto err_irq_fail;
+                       goto err_irq_fail;
                }
 
                if ((err = request_irq(grp->interruptTransmit, gfar_transmit,
@@ -2048,7 +2048,6 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
        u32 bufaddr;
        unsigned long flags;
        unsigned int nr_frags, nr_txbds, length;
-       union skb_shared_tx *shtx;
 
        /*
         * TOE=1 frames larger than 2500 bytes may see excess delays
@@ -2069,10 +2068,10 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
        txq = netdev_get_tx_queue(dev, rq);
        base = tx_queue->tx_bd_base;
        regs = tx_queue->grp->regs;
-       shtx = skb_tx(skb);
 
        /* check if time stamp should be generated */
-       if (unlikely(shtx->hardware && priv->hwts_tx_en))
+       if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP &&
+                    priv->hwts_tx_en))
                do_tstamp = 1;
 
        /* make space for additional header when fcb is needed */
@@ -2174,7 +2173,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        /* Setup tx hardware time stamping if requested */
        if (unlikely(do_tstamp)) {
-               shtx->in_progress = 1;
+               skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
                if (fcb == NULL)
                        fcb = gfar_add_fcb(skb);
                fcb->ptp = 1;
@@ -2446,7 +2445,6 @@ static int gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue)
        int howmany = 0;
        u32 lstatus;
        size_t buflen;
-       union skb_shared_tx *shtx;
 
        rx_queue = priv->rx_queue[tx_queue->qindex];
        bdp = tx_queue->dirty_tx;
@@ -2461,8 +2459,7 @@ static int gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue)
                 * When time stamping, one additional TxBD must be freed.
                 * Also, we need to dma_unmap_single() the TxPAL.
                 */
-               shtx = skb_tx(skb);
-               if (unlikely(shtx->in_progress))
+               if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS))
                        nr_txbds = frags + 2;
                else
                        nr_txbds = frags + 1;
@@ -2476,7 +2473,7 @@ static int gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue)
                                (lstatus & BD_LENGTH_MASK))
                        break;
 
-               if (unlikely(shtx->in_progress)) {
+               if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS)) {
                        next = next_txbd(bdp, base, tx_ring_size);
                        buflen = next->length + GMAC_FCB_LEN;
                } else
@@ -2485,7 +2482,7 @@ static int gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue)
                dma_unmap_single(&priv->ofdev->dev, bdp->bufPtr,
                                buflen, DMA_TO_DEVICE);
 
-               if (unlikely(shtx->in_progress)) {
+               if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS)) {
                        struct skb_shared_hwtstamps shhwtstamps;
                        u64 *ns = (u64*) (((u32)skb->data + 0x10) & ~0x7);
                        memset(&shhwtstamps, 0, sizeof(shhwtstamps));
@@ -2657,7 +2654,7 @@ static inline void gfar_rx_checksum(struct sk_buff *skb, struct rxfcb *fcb)
        if ((fcb->flags & RXFCB_CSUM_MASK) == (RXFCB_CIP | RXFCB_CTU))
                skb->ip_summed = CHECKSUM_UNNECESSARY;
        else
-               skb->ip_summed = CHECKSUM_NONE;
+               skb_checksum_none_assert(skb);
 }
 
 
index f15c64f1cd3886a77ec09354c7caf3408eba14b4..27d6960ce09ea7a8d7f12ef970f9de5c769ebd37 100644 (file)
@@ -893,7 +893,7 @@ static int greth_rx_gbit(struct net_device *dev, int limit)
                                if (greth->flags & GRETH_FLAG_RX_CSUM && hw_checksummed(status))
                                        skb->ip_summed = CHECKSUM_UNNECESSARY;
                                else
-                                       skb->ip_summed = CHECKSUM_NONE;
+                                       skb_checksum_none_assert(skb);
 
                                skb->protocol = eth_type_trans(skb, dev);
                                dev->stats.rx_packets++;
@@ -1547,10 +1547,10 @@ static int __devinit greth_of_probe(struct platform_device *ofdev, const struct
        dev->netdev_ops = &greth_netdev_ops;
        dev->ethtool_ops = &greth_ethtool_ops;
 
-       if (register_netdev(dev)) {
+       err = register_netdev(dev);
+       if (err) {
                if (netif_msg_probe(greth))
                        dev_err(greth->dev, "netdevice registration failed.\n");
-               err = -ENOMEM;
                goto error5;
        }
 
index 49aac7027fbb8841f62f11b18492119e02bb0bb1..9a6485892b3d48dfbcf783a27b670be83704e803 100644 (file)
@@ -1004,7 +1004,7 @@ static int hamachi_open(struct net_device *dev)
        init_timer(&hmp->timer);
        hmp->timer.expires = RUN_AT((24*HZ)/10);                        /* 2.4 sec. */
        hmp->timer.data = (unsigned long)dev;
-       hmp->timer.function = &hamachi_timer;                           /* timer handler */
+       hmp->timer.function = hamachi_timer;                            /* timer handler */
        add_timer(&hmp->timer);
 
        return 0;
index 9f64c8637208c4b8395743ef8385dc57b9e7605a..33655814448e3a5485cce6d923961c615c986781 100644 (file)
@@ -1069,7 +1069,8 @@ static void scc_tx_done(struct scc_channel *scc)
                case KISS_DUPLEX_LINK:
                        scc->stat.tx_state = TXS_IDLE2;
                        if (scc->kiss.idletime != TIMER_OFF)
-                       scc_start_tx_timer(scc, t_idle, scc->kiss.idletime*100);
+                               scc_start_tx_timer(scc, t_idle,
+                                                  scc->kiss.idletime*100);
                        break;
                case KISS_DUPLEX_OPTIMA:
                        scc_notify(scc, HWEV_ALL_SENT);
index 86ececd3c6582d17f7d0ffe0d3a19eeb5d85cfb0..d15d2f2ba78ec84cc9e6e73d0898f4d0b20e745c 100644 (file)
@@ -204,10 +204,10 @@ static int __init hp_probe1(struct net_device *dev, int ioaddr)
        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;
+       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);
index 07d8e5b634f36caeec8e8df868e3ab586807c774..c5ef62ceb8403ac777a36886156bec25a94006dd 100644 (file)
@@ -155,10 +155,10 @@ static int __devinit hydra_init(struct zorro_dev *z)
 
     ei_status.rx_start_page = start_page + TX_PAGES;
 
-    ei_status.reset_8390 = &hydra_reset_8390;
-    ei_status.block_input = &hydra_block_input;
-    ei_status.block_output = &hydra_block_output;
-    ei_status.get_8390_hdr = &hydra_get_8390_hdr;
+    ei_status.reset_8390 = hydra_reset_8390;
+    ei_status.block_input = hydra_block_input;
+    ei_status.block_output = hydra_block_output;
+    ei_status.get_8390_hdr = hydra_get_8390_hdr;
     ei_status.reg_offset = hydra_offsets;
 
     dev->netdev_ops = &hydra_netdev_ops;
@@ -173,9 +173,8 @@ static int __devinit hydra_init(struct zorro_dev *z)
 
     zorro_set_drvdata(z, dev);
 
-    printk(KERN_INFO "%s: Hydra at 0x%08llx, address "
-          "%pM (hydra.c " HYDRA_VERSION ")\n",
-          dev->name, (unsigned long long)z->resource.start, dev->dev_addr);
+    pr_info("%s: Hydra at %pR, address %pM (hydra.c " HYDRA_VERSION ")\n",
+           dev->name, &z->resource, dev->dev_addr);
 
     return 0;
 }
index 294ccfb427cf13475603a7194a03df6b8cbdc619..0037a696cd0a78e880e2e5968ded58a87b70bf17 100644 (file)
@@ -602,7 +602,7 @@ static void irqrx_handler(struct net_device *dev)
                                /* set up skb fields */
 
                                skb->protocol = eth_type_trans(skb, dev);
-                               skb->ip_summed = CHECKSUM_NONE;
+                               skb_checksum_none_assert(skb);
 
                                /* bookkeeping */
                                dev->stats.rx_packets++;
index 4734c939ad03574a63e6dd0bc9ccf6d8cf29c06a..b3e157ed6776ebe0dd7e60ac45eba561018ba117 100644 (file)
-/**************************************************************************/
-/*                                                                        */
-/* IBM eServer i/pSeries Virtual Ethernet Device Driver                   */
-/* Copyright (C) 2003 IBM Corp.                                           */
-/*  Originally written by Dave Larson (larson1@us.ibm.com)                */
-/*  Maintained by Santiago Leon (santil@us.ibm.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 of the License, 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  */
-/*                                                                   USA  */
-/*                                                                        */
-/* This module contains the implementation of a virtual ethernet device   */
-/* for use with IBM i/pSeries LPAR Linux.  It utilizes the logical LAN    */
-/* option of the RS/6000 Platform Architechture to interface with virtual */
-/* ethernet NICs that are presented to the partition by the hypervisor.   */
-/*                                                                        */
-/**************************************************************************/
 /*
-  TODO:
-  - add support for sysfs
-  - possibly remove procfs support
-*/
+ * IBM Power Virtual Ethernet Device Driver
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * Copyright (C) IBM Corporation, 2003, 2010
+ *
+ * Authors: Dave Larson <larson1@us.ibm.com>
+ *         Santiago Leon <santil@linux.vnet.ibm.com>
+ *         Brian King <brking@linux.vnet.ibm.com>
+ *         Robert Jennings <rcj@linux.vnet.ibm.com>
+ *         Anton Blanchard <anton@au.ibm.com>
+ */
 
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
 #include <linux/errno.h>
-#include <linux/ioport.h>
 #include <linux/dma-mapping.h>
 #include <linux/kernel.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/init.h>
-#include <linux/delay.h>
 #include <linux/mm.h>
 #include <linux/pm.h>
 #include <linux/ethtool.h>
-#include <linux/proc_fs.h>
 #include <linux/in.h>
 #include <linux/ip.h>
+#include <linux/ipv6.h>
 #include <linux/slab.h>
-#include <net/net_namespace.h>
 #include <asm/hvcall.h>
 #include <asm/atomic.h>
 #include <asm/vio.h>
 #include <asm/iommu.h>
-#include <asm/uaccess.h>
 #include <asm/firmware.h>
-#include <linux/seq_file.h>
 
 #include "ibmveth.h"
 
-#undef DEBUG
-
-#define ibmveth_printk(fmt, args...) \
-  printk(KERN_DEBUG "%s: " fmt, __FILE__, ## args)
-
-#define ibmveth_error_printk(fmt, args...) \
-  printk(KERN_ERR "(%s:%3.3d ua:%x) ERROR: " fmt, __FILE__, __LINE__ , adapter->vdev->unit_address, ## args)
-
-#ifdef DEBUG
-#define ibmveth_debug_printk_no_adapter(fmt, args...) \
-  printk(KERN_DEBUG "(%s:%3.3d): " fmt, __FILE__, __LINE__ , ## args)
-#define ibmveth_debug_printk(fmt, args...) \
-  printk(KERN_DEBUG "(%s:%3.3d ua:%x): " fmt, __FILE__, __LINE__ , adapter->vdev->unit_address, ## args)
-#define ibmveth_assert(expr) \
-  if(!(expr)) {                                   \
-    printk(KERN_DEBUG "assertion failed (%s:%3.3d ua:%x): %s\n", __FILE__, __LINE__, adapter->vdev->unit_address, #expr); \
-    BUG(); \
-  }
-#else
-#define ibmveth_debug_printk_no_adapter(fmt, args...)
-#define ibmveth_debug_printk(fmt, args...)
-#define ibmveth_assert(expr)
-#endif
-
-static int ibmveth_open(struct net_device *dev);
-static int ibmveth_close(struct net_device *dev);
-static int ibmveth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
-static int ibmveth_poll(struct napi_struct *napi, int budget);
-static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static void ibmveth_set_multicast_list(struct net_device *dev);
-static int ibmveth_change_mtu(struct net_device *dev, int new_mtu);
-static void ibmveth_proc_register_driver(void);
-static void ibmveth_proc_unregister_driver(void);
-static void ibmveth_proc_register_adapter(struct ibmveth_adapter *adapter);
-static void ibmveth_proc_unregister_adapter(struct ibmveth_adapter *adapter);
 static irqreturn_t ibmveth_interrupt(int irq, void *dev_instance);
 static void ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter);
 static unsigned long ibmveth_get_desired_dma(struct vio_dev *vdev);
-static struct kobj_type ktype_veth_pool;
 
+static struct kobj_type ktype_veth_pool;
 
-#ifdef CONFIG_PROC_FS
-#define IBMVETH_PROC_DIR "ibmveth"
-static struct proc_dir_entry *ibmveth_proc_dir;
-#endif
 
 static const char ibmveth_driver_name[] = "ibmveth";
-static const char ibmveth_driver_string[] = "IBM i/pSeries Virtual Ethernet Driver";
-#define ibmveth_driver_version "1.03"
+static const char ibmveth_driver_string[] = "IBM Power Virtual Ethernet Driver";
+#define ibmveth_driver_version "1.04"
 
-MODULE_AUTHOR("Santiago Leon <santil@us.ibm.com>");
-MODULE_DESCRIPTION("IBM i/pSeries Virtual Ethernet Driver");
+MODULE_AUTHOR("Santiago Leon <santil@linux.vnet.ibm.com>");
+MODULE_DESCRIPTION("IBM Power Virtual Ethernet Driver");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(ibmveth_driver_version);
 
+static unsigned int tx_copybreak __read_mostly = 128;
+module_param(tx_copybreak, uint, 0644);
+MODULE_PARM_DESC(tx_copybreak,
+       "Maximum size of packet that is copied to a new buffer on transmit");
+
+static unsigned int rx_copybreak __read_mostly = 128;
+module_param(rx_copybreak, uint, 0644);
+MODULE_PARM_DESC(rx_copybreak,
+       "Maximum size of packet that is copied to a new buffer on receive");
+
+static unsigned int rx_flush __read_mostly = 0;
+module_param(rx_flush, uint, 0644);
+MODULE_PARM_DESC(rx_flush, "Flush receive buffers before use");
+
 struct ibmveth_stat {
        char name[ETH_GSTRING_LEN];
        int offset;
@@ -128,12 +90,16 @@ struct ibmveth_stat {
 struct ibmveth_stat ibmveth_stats[] = {
        { "replenish_task_cycles", IBMVETH_STAT_OFF(replenish_task_cycles) },
        { "replenish_no_mem", IBMVETH_STAT_OFF(replenish_no_mem) },
-       { "replenish_add_buff_failure", IBMVETH_STAT_OFF(replenish_add_buff_failure) },
-       { "replenish_add_buff_success", IBMVETH_STAT_OFF(replenish_add_buff_success) },
+       { "replenish_add_buff_failure",
+                       IBMVETH_STAT_OFF(replenish_add_buff_failure) },
+       { "replenish_add_buff_success",
+                       IBMVETH_STAT_OFF(replenish_add_buff_success) },
        { "rx_invalid_buffer", IBMVETH_STAT_OFF(rx_invalid_buffer) },
        { "rx_no_buffer", IBMVETH_STAT_OFF(rx_no_buffer) },
        { "tx_map_failed", IBMVETH_STAT_OFF(tx_map_failed) },
        { "tx_send_failed", IBMVETH_STAT_OFF(tx_send_failed) },
+       { "fw_enabled_ipv4_csum", IBMVETH_STAT_OFF(fw_ipv4_csum_support) },
+       { "fw_enabled_ipv6_csum", IBMVETH_STAT_OFF(fw_ipv6_csum_support) },
 };
 
 /* simple methods of getting data from the current rxq entry */
@@ -144,41 +110,44 @@ static inline u32 ibmveth_rxq_flags(struct ibmveth_adapter *adapter)
 
 static inline int ibmveth_rxq_toggle(struct ibmveth_adapter *adapter)
 {
-       return (ibmveth_rxq_flags(adapter) & IBMVETH_RXQ_TOGGLE) >> IBMVETH_RXQ_TOGGLE_SHIFT;
+       return (ibmveth_rxq_flags(adapter) & IBMVETH_RXQ_TOGGLE) >>
+                       IBMVETH_RXQ_TOGGLE_SHIFT;
 }
 
 static inline int ibmveth_rxq_pending_buffer(struct ibmveth_adapter *adapter)
 {
-       return (ibmveth_rxq_toggle(adapter) == adapter->rx_queue.toggle);
+       return ibmveth_rxq_toggle(adapter) == adapter->rx_queue.toggle;
 }
 
 static inline int ibmveth_rxq_buffer_valid(struct ibmveth_adapter *adapter)
 {
-       return (ibmveth_rxq_flags(adapter) & IBMVETH_RXQ_VALID);
+       return ibmveth_rxq_flags(adapter) & IBMVETH_RXQ_VALID;
 }
 
 static inline int ibmveth_rxq_frame_offset(struct ibmveth_adapter *adapter)
 {
-       return (ibmveth_rxq_flags(adapter) & IBMVETH_RXQ_OFF_MASK);
+       return ibmveth_rxq_flags(adapter) & IBMVETH_RXQ_OFF_MASK;
 }
 
 static inline int ibmveth_rxq_frame_length(struct ibmveth_adapter *adapter)
 {
-       return (adapter->rx_queue.queue_addr[adapter->rx_queue.index].length);
+       return adapter->rx_queue.queue_addr[adapter->rx_queue.index].length;
 }
 
 static inline int ibmveth_rxq_csum_good(struct ibmveth_adapter *adapter)
 {
-       return (ibmveth_rxq_flags(adapter) & IBMVETH_RXQ_CSUM_GOOD);
+       return ibmveth_rxq_flags(adapter) & IBMVETH_RXQ_CSUM_GOOD;
 }
 
 /* setup the initial settings for a buffer pool */
-static void ibmveth_init_buffer_pool(struct ibmveth_buff_pool *pool, u32 pool_index, u32 pool_size, u32 buff_size, u32 pool_active)
+static void ibmveth_init_buffer_pool(struct ibmveth_buff_pool *pool,
+                                    u32 pool_index, u32 pool_size,
+                                    u32 buff_size, u32 pool_active)
 {
        pool->size = pool_size;
        pool->index = pool_index;
        pool->buff_size = buff_size;
-       pool->threshold = pool_size / 2;
+       pool->threshold = pool_size * 7 / 8;
        pool->active = pool_active;
 }
 
@@ -189,12 +158,11 @@ static int ibmveth_alloc_buffer_pool(struct ibmveth_buff_pool *pool)
 
        pool->free_map = kmalloc(sizeof(u16) * pool->size, GFP_KERNEL);
 
-       if(!pool->free_map) {
+       if (!pool->free_map)
                return -1;
-       }
 
        pool->dma_addr = kmalloc(sizeof(dma_addr_t) * pool->size, GFP_KERNEL);
-       if(!pool->dma_addr) {
+       if (!pool->dma_addr) {
                kfree(pool->free_map);
                pool->free_map = NULL;
                return -1;
@@ -202,7 +170,7 @@ static int ibmveth_alloc_buffer_pool(struct ibmveth_buff_pool *pool)
 
        pool->skbuff = kcalloc(pool->size, sizeof(void *), GFP_KERNEL);
 
-       if(!pool->skbuff) {
+       if (!pool->skbuff) {
                kfree(pool->dma_addr);
                pool->dma_addr = NULL;
 
@@ -213,9 +181,8 @@ static int ibmveth_alloc_buffer_pool(struct ibmveth_buff_pool *pool)
 
        memset(pool->dma_addr, 0, sizeof(dma_addr_t) * pool->size);
 
-       for(i = 0; i < pool->size; ++i) {
+       for (i = 0; i < pool->size; ++i)
                pool->free_map[i] = i;
-       }
 
        atomic_set(&pool->available, 0);
        pool->producer_index = 0;
@@ -224,10 +191,19 @@ static int ibmveth_alloc_buffer_pool(struct ibmveth_buff_pool *pool)
        return 0;
 }
 
+static inline void ibmveth_flush_buffer(void *addr, unsigned long length)
+{
+       unsigned long offset;
+
+       for (offset = 0; offset < length; offset += SMP_CACHE_BYTES)
+               asm("dcbfl %0,%1" :: "b" (addr), "r" (offset));
+}
+
 /* replenish the buffers for a pool.  note that we don't need to
  * skb_reserve these since they are used for incoming...
  */
-static void ibmveth_replenish_buffer_pool(struct ibmveth_adapter *adapter, struct ibmveth_buff_pool *pool)
+static void ibmveth_replenish_buffer_pool(struct ibmveth_adapter *adapter,
+                                         struct ibmveth_buff_pool *pool)
 {
        u32 i;
        u32 count = pool->size - atomic_read(&pool->available);
@@ -240,23 +216,26 @@ static void ibmveth_replenish_buffer_pool(struct ibmveth_adapter *adapter, struc
 
        mb();
 
-       for(i = 0; i < count; ++i) {
+       for (i = 0; i < count; ++i) {
                union ibmveth_buf_desc desc;
 
-               skb = alloc_skb(pool->buff_size, GFP_ATOMIC);
+               skb = netdev_alloc_skb(adapter->netdev, pool->buff_size);
 
-               if(!skb) {
-                       ibmveth_debug_printk("replenish: unable to allocate skb\n");
+               if (!skb) {
+                       netdev_dbg(adapter->netdev,
+                                  "replenish: unable to allocate skb\n");
                        adapter->replenish_no_mem++;
                        break;
                }
 
                free_index = pool->consumer_index;
-               pool->consumer_index = (pool->consumer_index + 1) % pool->size;
+               pool->consumer_index++;
+               if (pool->consumer_index >= pool->size)
+                       pool->consumer_index = 0;
                index = pool->free_map[free_index];
 
-               ibmveth_assert(index != IBM_VETH_INVALID_MAP);
-               ibmveth_assert(pool->skbuff[index] == NULL);
+               BUG_ON(index == IBM_VETH_INVALID_MAP);
+               BUG_ON(pool->skbuff[index] != NULL);
 
                dma_addr = dma_map_single(&adapter->vdev->dev, skb->data,
                                pool->buff_size, DMA_FROM_DEVICE);
@@ -269,16 +248,23 @@ static void ibmveth_replenish_buffer_pool(struct ibmveth_adapter *adapter, struc
                pool->skbuff[index] = skb;
 
                correlator = ((u64)pool->index << 32) | index;
-               *(u64*)skb->data = correlator;
+               *(u64 *)skb->data = correlator;
 
                desc.fields.flags_len = IBMVETH_BUF_VALID | pool->buff_size;
                desc.fields.address = dma_addr;
 
-               lpar_rc = h_add_logical_lan_buffer(adapter->vdev->unit_address, desc.desc);
+               if (rx_flush) {
+                       unsigned int len = min(pool->buff_size,
+                                               adapter->netdev->mtu +
+                                               IBMVETH_BUFF_OH);
+                       ibmveth_flush_buffer(skb->data, len);
+               }
+               lpar_rc = h_add_logical_lan_buffer(adapter->vdev->unit_address,
+                                                  desc.desc);
 
-               if (lpar_rc != H_SUCCESS)
+               if (lpar_rc != H_SUCCESS) {
                        goto failure;
-               else {
+               else {
                        buffers_added++;
                        adapter->replenish_add_buff_success++;
                }
@@ -313,26 +299,31 @@ static void ibmveth_replenish_task(struct ibmveth_adapter *adapter)
 
        adapter->replenish_task_cycles++;
 
-       for (i = (IbmVethNumBufferPools - 1); i >= 0; i--)
-               if(adapter->rx_buff_pool[i].active)
-                       ibmveth_replenish_buffer_pool(adapter,
-                                                    &adapter->rx_buff_pool[i]);
+       for (i = (IBMVETH_NUM_BUFF_POOLS - 1); i >= 0; i--) {
+               struct ibmveth_buff_pool *pool = &adapter->rx_buff_pool[i];
 
-       adapter->rx_no_buffer = *(u64*)(((char*)adapter->buffer_list_addr) + 4096 - 8);
+               if (pool->active &&
+                   (atomic_read(&pool->available) < pool->threshold))
+                       ibmveth_replenish_buffer_pool(adapter, pool);
+       }
+
+       adapter->rx_no_buffer = *(u64 *)(((char*)adapter->buffer_list_addr) +
+                                               4096 - 8);
 }
 
 /* empty and free ana buffer pool - also used to do cleanup in error paths */
-static void ibmveth_free_buffer_pool(struct ibmveth_adapter *adapter, struct ibmveth_buff_pool *pool)
+static void ibmveth_free_buffer_pool(struct ibmveth_adapter *adapter,
+                                    struct ibmveth_buff_pool *pool)
 {
        int i;
 
        kfree(pool->free_map);
        pool->free_map = NULL;
 
-       if(pool->skbuff && pool->dma_addr) {
-               for(i = 0; i < pool->size; ++i) {
+       if (pool->skbuff && pool->dma_addr) {
+               for (i = 0; i < pool->size; ++i) {
                        struct sk_buff *skb = pool->skbuff[i];
-                       if(skb) {
+                       if (skb) {
                                dma_unmap_single(&adapter->vdev->dev,
                                                 pool->dma_addr[i],
                                                 pool->buff_size,
@@ -343,31 +334,32 @@ static void ibmveth_free_buffer_pool(struct ibmveth_adapter *adapter, struct ibm
                }
        }
 
-       if(pool->dma_addr) {
+       if (pool->dma_addr) {
                kfree(pool->dma_addr);
                pool->dma_addr = NULL;
        }
 
-       if(pool->skbuff) {
+       if (pool->skbuff) {
                kfree(pool->skbuff);
                pool->skbuff = NULL;
        }
 }
 
 /* remove a buffer from a pool */
-static void ibmveth_remove_buffer_from_pool(struct ibmveth_adapter *adapter, u64 correlator)
+static void ibmveth_remove_buffer_from_pool(struct ibmveth_adapter *adapter,
+                                           u64 correlator)
 {
        unsigned int pool  = correlator >> 32;
        unsigned int index = correlator & 0xffffffffUL;
        unsigned int free_index;
        struct sk_buff *skb;
 
-       ibmveth_assert(pool < IbmVethNumBufferPools);
-       ibmveth_assert(index < adapter->rx_buff_pool[pool].size);
+       BUG_ON(pool >= IBMVETH_NUM_BUFF_POOLS);
+       BUG_ON(index >= adapter->rx_buff_pool[pool].size);
 
        skb = adapter->rx_buff_pool[pool].skbuff[index];
 
-       ibmveth_assert(skb != NULL);
+       BUG_ON(skb == NULL);
 
        adapter->rx_buff_pool[pool].skbuff[index] = NULL;
 
@@ -377,9 +369,10 @@ static void ibmveth_remove_buffer_from_pool(struct ibmveth_adapter *adapter, u64
                         DMA_FROM_DEVICE);
 
        free_index = adapter->rx_buff_pool[pool].producer_index;
-       adapter->rx_buff_pool[pool].producer_index
-               = (adapter->rx_buff_pool[pool].producer_index + 1)
-               % adapter->rx_buff_pool[pool].size;
+       adapter->rx_buff_pool[pool].producer_index++;
+       if (adapter->rx_buff_pool[pool].producer_index >=
+           adapter->rx_buff_pool[pool].size)
+               adapter->rx_buff_pool[pool].producer_index = 0;
        adapter->rx_buff_pool[pool].free_map[free_index] = index;
 
        mb();
@@ -394,8 +387,8 @@ static inline struct sk_buff *ibmveth_rxq_get_buffer(struct ibmveth_adapter *ada
        unsigned int pool = correlator >> 32;
        unsigned int index = correlator & 0xffffffffUL;
 
-       ibmveth_assert(pool < IbmVethNumBufferPools);
-       ibmveth_assert(index < adapter->rx_buff_pool[pool].size);
+       BUG_ON(pool >= IBMVETH_NUM_BUFF_POOLS);
+       BUG_ON(index >= adapter->rx_buff_pool[pool].size);
 
        return adapter->rx_buff_pool[pool].skbuff[index];
 }
@@ -410,10 +403,10 @@ static void ibmveth_rxq_recycle_buffer(struct ibmveth_adapter *adapter)
        union ibmveth_buf_desc desc;
        unsigned long lpar_rc;
 
-       ibmveth_assert(pool < IbmVethNumBufferPools);
-       ibmveth_assert(index < adapter->rx_buff_pool[pool].size);
+       BUG_ON(pool >= IBMVETH_NUM_BUFF_POOLS);
+       BUG_ON(index >= adapter->rx_buff_pool[pool].size);
 
-       if(!adapter->rx_buff_pool[pool].active) {
+       if (!adapter->rx_buff_pool[pool].active) {
                ibmveth_rxq_harvest_buffer(adapter);
                ibmveth_free_buffer_pool(adapter, &adapter->rx_buff_pool[pool]);
                return;
@@ -425,12 +418,13 @@ static void ibmveth_rxq_recycle_buffer(struct ibmveth_adapter *adapter)
 
        lpar_rc = h_add_logical_lan_buffer(adapter->vdev->unit_address, desc.desc);
 
-       if(lpar_rc != H_SUCCESS) {
-               ibmveth_debug_printk("h_add_logical_lan_buffer failed during recycle rc=%ld", lpar_rc);
+       if (lpar_rc != H_SUCCESS) {
+               netdev_dbg(adapter->netdev, "h_add_logical_lan_buffer failed "
+                          "during recycle rc=%ld", lpar_rc);
                ibmveth_remove_buffer_from_pool(adapter, adapter->rx_queue.queue_addr[adapter->rx_queue.index].correlator);
        }
 
-       if(++adapter->rx_queue.index == adapter->rx_queue.num_slots) {
+       if (++adapter->rx_queue.index == adapter->rx_queue.num_slots) {
                adapter->rx_queue.index = 0;
                adapter->rx_queue.toggle = !adapter->rx_queue.toggle;
        }
@@ -440,7 +434,7 @@ static void ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter)
 {
        ibmveth_remove_buffer_from_pool(adapter, adapter->rx_queue.queue_addr[adapter->rx_queue.index].correlator);
 
-       if(++adapter->rx_queue.index == adapter->rx_queue.num_slots) {
+       if (++adapter->rx_queue.index == adapter->rx_queue.num_slots) {
                adapter->rx_queue.index = 0;
                adapter->rx_queue.toggle = !adapter->rx_queue.toggle;
        }
@@ -451,7 +445,7 @@ static void ibmveth_cleanup(struct ibmveth_adapter *adapter)
        int i;
        struct device *dev = &adapter->vdev->dev;
 
-       if(adapter->buffer_list_addr != NULL) {
+       if (adapter->buffer_list_addr != NULL) {
                if (!dma_mapping_error(dev, adapter->buffer_list_dma)) {
                        dma_unmap_single(dev, adapter->buffer_list_dma, 4096,
                                        DMA_BIDIRECTIONAL);
@@ -461,7 +455,7 @@ static void ibmveth_cleanup(struct ibmveth_adapter *adapter)
                adapter->buffer_list_addr = NULL;
        }
 
-       if(adapter->filter_list_addr != NULL) {
+       if (adapter->filter_list_addr != NULL) {
                if (!dma_mapping_error(dev, adapter->filter_list_dma)) {
                        dma_unmap_single(dev, adapter->filter_list_dma, 4096,
                                        DMA_BIDIRECTIONAL);
@@ -471,7 +465,7 @@ static void ibmveth_cleanup(struct ibmveth_adapter *adapter)
                adapter->filter_list_addr = NULL;
        }
 
-       if(adapter->rx_queue.queue_addr != NULL) {
+       if (adapter->rx_queue.queue_addr != NULL) {
                if (!dma_mapping_error(dev, adapter->rx_queue.queue_dma)) {
                        dma_unmap_single(dev,
                                        adapter->rx_queue.queue_dma,
@@ -483,7 +477,7 @@ static void ibmveth_cleanup(struct ibmveth_adapter *adapter)
                adapter->rx_queue.queue_addr = NULL;
        }
 
-       for(i = 0; i<IbmVethNumBufferPools; i++)
+       for (i = 0; i < IBMVETH_NUM_BUFF_POOLS; i++)
                if (adapter->rx_buff_pool[i].active)
                        ibmveth_free_buffer_pool(adapter,
                                                 &adapter->rx_buff_pool[i]);
@@ -506,9 +500,11 @@ static int ibmveth_register_logical_lan(struct ibmveth_adapter *adapter,
 {
        int rc, try_again = 1;
 
-       /* After a kexec the adapter will still be open, so our attempt to
-       * open it will fail. So if we get a failure we free the adapter and
-       * try again, but only once. */
+       /*
+        * After a kexec the adapter will still be open, so our attempt to
+        * open it will fail. So if we get a failure we free the adapter and
+        * try again, but only once.
+        */
 retry:
        rc = h_register_logical_lan(adapter->vdev->unit_address,
                                    adapter->buffer_list_dma, rxq_desc.desc,
@@ -537,28 +533,31 @@ static int ibmveth_open(struct net_device *netdev)
        int i;
        struct device *dev;
 
-       ibmveth_debug_printk("open starting\n");
+       netdev_dbg(netdev, "open starting\n");
 
        napi_enable(&adapter->napi);
 
-       for(i = 0; i<IbmVethNumBufferPools; i++)
+       for(i = 0; i < IBMVETH_NUM_BUFF_POOLS; i++)
                rxq_entries += adapter->rx_buff_pool[i].size;
 
        adapter->buffer_list_addr = (void*) get_zeroed_page(GFP_KERNEL);
        adapter->filter_list_addr = (void*) get_zeroed_page(GFP_KERNEL);
 
-       if(!adapter->buffer_list_addr || !adapter->filter_list_addr) {
-               ibmveth_error_printk("unable to allocate filter or buffer list pages\n");
+       if (!adapter->buffer_list_addr || !adapter->filter_list_addr) {
+               netdev_err(netdev, "unable to allocate filter or buffer list "
+                          "pages\n");
                ibmveth_cleanup(adapter);
                napi_disable(&adapter->napi);
                return -ENOMEM;
        }
 
-       adapter->rx_queue.queue_len = sizeof(struct ibmveth_rx_q_entry) * rxq_entries;
-       adapter->rx_queue.queue_addr = kmalloc(adapter->rx_queue.queue_len, GFP_KERNEL);
+       adapter->rx_queue.queue_len = sizeof(struct ibmveth_rx_q_entry) *
+                                               rxq_entries;
+       adapter->rx_queue.queue_addr = kmalloc(adapter->rx_queue.queue_len,
+                                               GFP_KERNEL);
 
-       if(!adapter->rx_queue.queue_addr) {
-               ibmveth_error_printk("unable to allocate rx queue pages\n");
+       if (!adapter->rx_queue.queue_addr) {
+               netdev_err(netdev, "unable to allocate rx queue pages\n");
                ibmveth_cleanup(adapter);
                napi_disable(&adapter->napi);
                return -ENOMEM;
@@ -577,7 +576,8 @@ static int ibmveth_open(struct net_device *netdev)
        if ((dma_mapping_error(dev, adapter->buffer_list_dma)) ||
            (dma_mapping_error(dev, adapter->filter_list_dma)) ||
            (dma_mapping_error(dev, adapter->rx_queue.queue_dma))) {
-               ibmveth_error_printk("unable to map filter or buffer list pages\n");
+               netdev_err(netdev, "unable to map filter or buffer list "
+                          "pages\n");
                ibmveth_cleanup(adapter);
                napi_disable(&adapter->napi);
                return -ENOMEM;
@@ -590,20 +590,23 @@ static int ibmveth_open(struct net_device *netdev)
        memcpy(&mac_address, netdev->dev_addr, netdev->addr_len);
        mac_address = mac_address >> 16;
 
-       rxq_desc.fields.flags_len = IBMVETH_BUF_VALID | adapter->rx_queue.queue_len;
+       rxq_desc.fields.flags_len = IBMVETH_BUF_VALID |
+                                       adapter->rx_queue.queue_len;
        rxq_desc.fields.address = adapter->rx_queue.queue_dma;
 
-       ibmveth_debug_printk("buffer list @ 0x%p\n", adapter->buffer_list_addr);
-       ibmveth_debug_printk("filter list @ 0x%p\n", adapter->filter_list_addr);
-       ibmveth_debug_printk("receive q   @ 0x%p\n", adapter->rx_queue.queue_addr);
+       netdev_dbg(netdev, "buffer list @ 0x%p\n", adapter->buffer_list_addr);
+       netdev_dbg(netdev, "filter list @ 0x%p\n", adapter->filter_list_addr);
+       netdev_dbg(netdev, "receive q   @ 0x%p\n", adapter->rx_queue.queue_addr);
 
        h_vio_signal(adapter->vdev->unit_address, VIO_IRQ_DISABLE);
 
        lpar_rc = ibmveth_register_logical_lan(adapter, rxq_desc, mac_address);
 
-       if(lpar_rc != H_SUCCESS) {
-               ibmveth_error_printk("h_register_logical_lan failed with %ld\n", lpar_rc);
-               ibmveth_error_printk("buffer TCE:0x%llx filter TCE:0x%llx rxq desc:0x%llx MAC:0x%llx\n",
+       if (lpar_rc != H_SUCCESS) {
+               netdev_err(netdev, "h_register_logical_lan failed with %ld\n",
+                          lpar_rc);
+               netdev_err(netdev, "buffer TCE:0x%llx filter TCE:0x%llx rxq "
+                          "desc:0x%llx MAC:0x%llx\n",
                                     adapter->buffer_list_dma,
                                     adapter->filter_list_dma,
                                     rxq_desc.desc,
@@ -613,11 +616,11 @@ static int ibmveth_open(struct net_device *netdev)
                return -ENONET;
        }
 
-       for(i = 0; i<IbmVethNumBufferPools; i++) {
-               if(!adapter->rx_buff_pool[i].active)
+       for (i = 0; i < IBMVETH_NUM_BUFF_POOLS; i++) {
+               if (!adapter->rx_buff_pool[i].active)
                        continue;
                if (ibmveth_alloc_buffer_pool(&adapter->rx_buff_pool[i])) {
-                       ibmveth_error_printk("unable to alloc pool\n");
+                       netdev_err(netdev, "unable to alloc pool\n");
                        adapter->rx_buff_pool[i].active = 0;
                        ibmveth_cleanup(adapter);
                        napi_disable(&adapter->napi);
@@ -625,9 +628,12 @@ static int ibmveth_open(struct net_device *netdev)
                }
        }
 
-       ibmveth_debug_printk("registering irq 0x%x\n", netdev->irq);
-       if((rc = request_irq(netdev->irq, ibmveth_interrupt, 0, netdev->name, netdev)) != 0) {
-               ibmveth_error_printk("unable to request irq 0x%x, rc %d\n", netdev->irq, rc);
+       netdev_dbg(netdev, "registering irq 0x%x\n", netdev->irq);
+       rc = request_irq(netdev->irq, ibmveth_interrupt, 0, netdev->name,
+                        netdev);
+       if (rc != 0) {
+               netdev_err(netdev, "unable to request irq 0x%x, rc %d\n",
+                          netdev->irq, rc);
                do {
                        rc = h_free_logical_lan(adapter->vdev->unit_address);
                } while (H_IS_LONG_BUSY(rc) || (rc == H_BUSY));
@@ -640,7 +646,7 @@ static int ibmveth_open(struct net_device *netdev)
        adapter->bounce_buffer =
            kmalloc(netdev->mtu + IBMVETH_BUFF_OH, GFP_KERNEL);
        if (!adapter->bounce_buffer) {
-               ibmveth_error_printk("unable to allocate bounce buffer\n");
+               netdev_err(netdev, "unable to allocate bounce buffer\n");
                ibmveth_cleanup(adapter);
                napi_disable(&adapter->napi);
                return -ENOMEM;
@@ -649,18 +655,18 @@ static int ibmveth_open(struct net_device *netdev)
            dma_map_single(&adapter->vdev->dev, adapter->bounce_buffer,
                           netdev->mtu + IBMVETH_BUFF_OH, DMA_BIDIRECTIONAL);
        if (dma_mapping_error(dev, adapter->bounce_buffer_dma)) {
-               ibmveth_error_printk("unable to map bounce buffer\n");
+               netdev_err(netdev, "unable to map bounce buffer\n");
                ibmveth_cleanup(adapter);
                napi_disable(&adapter->napi);
                return -ENOMEM;
        }
 
-       ibmveth_debug_printk("initial replenish cycle\n");
+       netdev_dbg(netdev, "initial replenish cycle\n");
        ibmveth_interrupt(netdev->irq, netdev);
 
        netif_start_queue(netdev);
 
-       ibmveth_debug_printk("open complete\n");
+       netdev_dbg(netdev, "open complete\n");
 
        return 0;
 }
@@ -670,7 +676,7 @@ static int ibmveth_close(struct net_device *netdev)
        struct ibmveth_adapter *adapter = netdev_priv(netdev);
        long lpar_rc;
 
-       ibmveth_debug_printk("close starting\n");
+       netdev_dbg(netdev, "close starting\n");
 
        napi_disable(&adapter->napi);
 
@@ -683,26 +689,29 @@ static int ibmveth_close(struct net_device *netdev)
                lpar_rc = h_free_logical_lan(adapter->vdev->unit_address);
        } while (H_IS_LONG_BUSY(lpar_rc) || (lpar_rc == H_BUSY));
 
-       if(lpar_rc != H_SUCCESS)
-       {
-               ibmveth_error_printk("h_free_logical_lan failed with %lx, continuing with close\n",
-                                    lpar_rc);
+       if (lpar_rc != H_SUCCESS) {
+               netdev_err(netdev, "h_free_logical_lan failed with %lx, "
+                          "continuing with close\n", lpar_rc);
        }
 
        free_irq(netdev->irq, netdev);
 
-       adapter->rx_no_buffer = *(u64*)(((char*)adapter->buffer_list_addr) + 4096 - 8);
+       adapter->rx_no_buffer = *(u64 *)(((char *)adapter->buffer_list_addr) +
+                                               4096 - 8);
 
        ibmveth_cleanup(adapter);
 
-       ibmveth_debug_printk("close complete\n");
+       netdev_dbg(netdev, "close complete\n");
 
        return 0;
 }
 
-static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) {
-       cmd->supported = (SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | SUPPORTED_FIBRE);
-       cmd->advertising = (ADVERTISED_1000baseT_Full | ADVERTISED_Autoneg | ADVERTISED_FIBRE);
+static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+       cmd->supported = (SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg |
+                               SUPPORTED_FIBRE);
+       cmd->advertising = (ADVERTISED_1000baseT_Full | ADVERTISED_Autoneg |
+                               ADVERTISED_FIBRE);
        cmd->speed = SPEED_1000;
        cmd->duplex = DUPLEX_FULL;
        cmd->port = PORT_FIBRE;
@@ -714,12 +723,16 @@ static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
        return 0;
 }
 
-static void netdev_get_drvinfo (struct net_device *dev, struct ethtool_drvinfo *info) {
+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);
+       strncpy(info->version, ibmveth_driver_version,
+               sizeof(info->version) - 1);
 }
 
-static u32 netdev_get_link(struct net_device *dev) {
+static u32 netdev_get_link(struct net_device *dev)
+{
        return 1;
 }
 
@@ -727,18 +740,20 @@ static void ibmveth_set_rx_csum_flags(struct net_device *dev, u32 data)
 {
        struct ibmveth_adapter *adapter = netdev_priv(dev);
 
-       if (data)
+       if (data) {
                adapter->rx_csum = 1;
-       else {
+       else {
                /*
-                * Since the ibmveth firmware interface does not have the concept of
-                * separate tx/rx checksum offload enable, if rx checksum is disabled
-                * we also have to disable tx checksum offload. Once we disable rx
-                * checksum offload, we are no longer allowed to send tx buffers that
-                * are not properly checksummed.
+                * Since the ibmveth firmware interface does not have the
+                * concept of separate tx/rx checksum offload enable, if rx
+                * checksum is disabled we also have to disable tx checksum
+                * offload. Once we disable rx checksum offload, we are no
+                * longer allowed to send tx buffers that are not properly
+                * checksummed.
                 */
                adapter->rx_csum = 0;
                dev->features &= ~NETIF_F_IP_CSUM;
+               dev->features &= ~NETIF_F_IPV6_CSUM;
        }
 }
 
@@ -747,10 +762,15 @@ static void ibmveth_set_tx_csum_flags(struct net_device *dev, u32 data)
        struct ibmveth_adapter *adapter = netdev_priv(dev);
 
        if (data) {
-               dev->features |= NETIF_F_IP_CSUM;
+               if (adapter->fw_ipv4_csum_support)
+                       dev->features |= NETIF_F_IP_CSUM;
+               if (adapter->fw_ipv6_csum_support)
+                       dev->features |= NETIF_F_IPV6_CSUM;
                adapter->rx_csum = 1;
-       } else
+       } else {
                dev->features &= ~NETIF_F_IP_CSUM;
+               dev->features &= ~NETIF_F_IPV6_CSUM;
+       }
 }
 
 static int ibmveth_set_csum_offload(struct net_device *dev, u32 data,
@@ -758,7 +778,8 @@ static int ibmveth_set_csum_offload(struct net_device *dev, u32 data,
 {
        struct ibmveth_adapter *adapter = netdev_priv(dev);
        unsigned long set_attr, clr_attr, ret_attr;
-       long ret;
+       unsigned long set_attr6, clr_attr6;
+       long ret, ret6;
        int rc1 = 0, rc2 = 0;
        int restart = 0;
 
@@ -772,10 +793,13 @@ static int ibmveth_set_csum_offload(struct net_device *dev, u32 data,
        set_attr = 0;
        clr_attr = 0;
 
-       if (data)
+       if (data) {
                set_attr = IBMVETH_ILLAN_IPV4_TCP_CSUM;
-       else
+               set_attr6 = IBMVETH_ILLAN_IPV6_TCP_CSUM;
+       } else {
                clr_attr = IBMVETH_ILLAN_IPV4_TCP_CSUM;
+               clr_attr6 = IBMVETH_ILLAN_IPV6_TCP_CSUM;
+       }
 
        ret = h_illan_attributes(adapter->vdev->unit_address, 0, 0, &ret_attr);
 
@@ -786,18 +810,39 @@ static int ibmveth_set_csum_offload(struct net_device *dev, u32 data,
                                         set_attr, &ret_attr);
 
                if (ret != H_SUCCESS) {
-                       rc1 = -EIO;
-                       ibmveth_error_printk("unable to change checksum offload settings."
-                                            " %d rc=%ld\n", data, ret);
+                       netdev_err(dev, "unable to change IPv4 checksum "
+                                       "offload settings. %d rc=%ld\n",
+                                       data, ret);
 
                        ret = h_illan_attributes(adapter->vdev->unit_address,
                                                 set_attr, clr_attr, &ret_attr);
+               } else {
+                       adapter->fw_ipv4_csum_support = data;
+               }
+
+               ret6 = h_illan_attributes(adapter->vdev->unit_address,
+                                        clr_attr6, set_attr6, &ret_attr);
+
+               if (ret6 != H_SUCCESS) {
+                       netdev_err(dev, "unable to change IPv6 checksum "
+                                       "offload settings. %d rc=%ld\n",
+                                       data, ret);
+
+                       ret = h_illan_attributes(adapter->vdev->unit_address,
+                                                set_attr6, clr_attr6,
+                                                &ret_attr);
                } else
+                       adapter->fw_ipv6_csum_support = data;
+
+               if (ret == H_SUCCESS || ret6 == H_SUCCESS)
                        done(dev, data);
+               else
+                       rc1 = -EIO;
        } else {
                rc1 = -EIO;
-               ibmveth_error_printk("unable to change checksum offload settings."
-                                    " %d rc=%ld ret_attr=%lx\n", data, ret, ret_attr);
+               netdev_err(dev, "unable to change checksum offload settings."
+                                    " %d rc=%ld ret_attr=%lx\n", data, ret,
+                                    ret_attr);
        }
 
        if (restart)
@@ -821,13 +866,14 @@ static int ibmveth_set_tx_csum(struct net_device *dev, u32 data)
        struct ibmveth_adapter *adapter = netdev_priv(dev);
        int rc = 0;
 
-       if (data && (dev->features & NETIF_F_IP_CSUM))
+       if (data && (dev->features & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM)))
                return 0;
-       if (!data && !(dev->features & NETIF_F_IP_CSUM))
+       if (!data && !(dev->features & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM)))
                return 0;
 
        if (data && !adapter->rx_csum)
-               rc = ibmveth_set_csum_offload(dev, data, ibmveth_set_tx_csum_flags);
+               rc = ibmveth_set_csum_offload(dev, data,
+                                             ibmveth_set_tx_csum_flags);
        else
                ibmveth_set_tx_csum_flags(dev, data);
 
@@ -881,6 +927,7 @@ static const struct ethtool_ops netdev_ethtool_ops = {
        .get_strings            = ibmveth_get_strings,
        .get_sset_count         = ibmveth_get_sset_count,
        .get_ethtool_stats      = ibmveth_get_ethtool_stats,
+       .set_sg                 = ethtool_op_set_sg,
 };
 
 static int ibmveth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
@@ -890,129 +937,216 @@ static int ibmveth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 
 #define page_offset(v) ((unsigned long)(v) & ((1 << 12) - 1))
 
-static netdev_tx_t ibmveth_start_xmit(struct sk_buff *skb,
-                                     struct net_device *netdev)
+static int ibmveth_send(struct ibmveth_adapter *adapter,
+                       union ibmveth_buf_desc *descs)
 {
-       struct ibmveth_adapter *adapter = netdev_priv(netdev);
-       union ibmveth_buf_desc desc;
-       unsigned long lpar_rc;
        unsigned long correlator;
-       unsigned long flags;
        unsigned int retry_count;
-       unsigned int tx_dropped = 0;
-       unsigned int tx_bytes = 0;
-       unsigned int tx_packets = 0;
-       unsigned int tx_send_failed = 0;
-       unsigned int tx_map_failed = 0;
-       int used_bounce = 0;
-       unsigned long data_dma_addr;
+       unsigned long ret;
+
+       /*
+        * The retry count sets a maximum for the number of broadcast and
+        * multicast destinations within the system.
+        */
+       retry_count = 1024;
+       correlator = 0;
+       do {
+               ret = h_send_logical_lan(adapter->vdev->unit_address,
+                                            descs[0].desc, descs[1].desc,
+                                            descs[2].desc, descs[3].desc,
+                                            descs[4].desc, descs[5].desc,
+                                            correlator, &correlator);
+       } while ((ret == H_BUSY) && (retry_count--));
+
+       if (ret != H_SUCCESS && ret != H_DROPPED) {
+               netdev_err(adapter->netdev, "tx: h_send_logical_lan failed "
+                          "with rc=%ld\n", ret);
+               return 1;
+       }
+
+       return 0;
+}
 
-       desc.fields.flags_len = IBMVETH_BUF_VALID | skb->len;
+static netdev_tx_t ibmveth_start_xmit(struct sk_buff *skb,
+                                     struct net_device *netdev)
+{
+       struct ibmveth_adapter *adapter = netdev_priv(netdev);
+       unsigned int desc_flags;
+       union ibmveth_buf_desc descs[6];
+       int last, i;
+       int force_bounce = 0;
+
+       /*
+        * veth handles a maximum of 6 segments including the header, so
+        * we have to linearize the skb if there are more than this.
+        */
+       if (skb_shinfo(skb)->nr_frags > 5 && __skb_linearize(skb)) {
+               netdev->stats.tx_dropped++;
+               goto out;
+       }
 
+       /* veth can't checksum offload UDP */
        if (skb->ip_summed == CHECKSUM_PARTIAL &&
-           ip_hdr(skb)->protocol != IPPROTO_TCP && skb_checksum_help(skb)) {
-               ibmveth_error_printk("tx: failed to checksum packet\n");
-               tx_dropped++;
+           ((skb->protocol == htons(ETH_P_IP) &&
+             ip_hdr(skb)->protocol != IPPROTO_TCP) ||
+            (skb->protocol == htons(ETH_P_IPV6) &&
+             ipv6_hdr(skb)->nexthdr != IPPROTO_TCP)) &&
+           skb_checksum_help(skb)) {
+
+               netdev_err(netdev, "tx: failed to checksum packet\n");
+               netdev->stats.tx_dropped++;
                goto out;
        }
 
+       desc_flags = IBMVETH_BUF_VALID;
+
        if (skb->ip_summed == CHECKSUM_PARTIAL) {
-               unsigned char *buf = skb_transport_header(skb) + skb->csum_offset;
+               unsigned char *buf = skb_transport_header(skb) +
+                                               skb->csum_offset;
 
-               desc.fields.flags_len |= (IBMVETH_BUF_NO_CSUM | IBMVETH_BUF_CSUM_GOOD);
+               desc_flags |= (IBMVETH_BUF_NO_CSUM | IBMVETH_BUF_CSUM_GOOD);
 
                /* Need to zero out the checksum */
                buf[0] = 0;
                buf[1] = 0;
        }
 
-       data_dma_addr = dma_map_single(&adapter->vdev->dev, skb->data,
-                                      skb->len, DMA_TO_DEVICE);
-       if (dma_mapping_error(&adapter->vdev->dev, data_dma_addr)) {
-               if (!firmware_has_feature(FW_FEATURE_CMO))
-                       ibmveth_error_printk("tx: unable to map xmit buffer\n");
+retry_bounce:
+       memset(descs, 0, sizeof(descs));
+
+       /*
+        * If a linear packet is below the rx threshold then
+        * copy it into the static bounce buffer. This avoids the
+        * cost of a TCE insert and remove.
+        */
+       if (force_bounce || (!skb_is_nonlinear(skb) &&
+                               (skb->len < tx_copybreak))) {
                skb_copy_from_linear_data(skb, adapter->bounce_buffer,
                                          skb->len);
-               desc.fields.address = adapter->bounce_buffer_dma;
-               tx_map_failed++;
-               used_bounce = 1;
-               wmb();
-       } else
-               desc.fields.address = data_dma_addr;
-
-       /* send the frame. Arbitrarily set retrycount to 1024 */
-       correlator = 0;
-       retry_count = 1024;
-       do {
-               lpar_rc = h_send_logical_lan(adapter->vdev->unit_address,
-                                            desc.desc, 0, 0, 0, 0, 0,
-                                            correlator, &correlator);
-       } while ((lpar_rc == H_BUSY) && (retry_count--));
-
-       if(lpar_rc != H_SUCCESS && lpar_rc != H_DROPPED) {
-               ibmveth_error_printk("tx: h_send_logical_lan failed with rc=%ld\n", lpar_rc);
-               ibmveth_error_printk("tx: valid=%d, len=%d, address=0x%08x\n",
-                                    (desc.fields.flags_len & IBMVETH_BUF_VALID) ? 1 : 0,
-                                    skb->len, desc.fields.address);
-               tx_send_failed++;
-               tx_dropped++;
-       } else {
-               tx_packets++;
-               tx_bytes += skb->len;
-               netdev->trans_start = jiffies; /* NETIF_F_LLTX driver :( */
+
+               descs[0].fields.flags_len = desc_flags | skb->len;
+               descs[0].fields.address = adapter->bounce_buffer_dma;
+
+               if (ibmveth_send(adapter, descs)) {
+                       adapter->tx_send_failed++;
+                       netdev->stats.tx_dropped++;
+               } else {
+                       netdev->stats.tx_packets++;
+                       netdev->stats.tx_bytes += skb->len;
+               }
+
+               goto out;
+       }
+
+       /* Map the header */
+       descs[0].fields.address = dma_map_single(&adapter->vdev->dev, skb->data,
+                                                skb_headlen(skb),
+                                                DMA_TO_DEVICE);
+       if (dma_mapping_error(&adapter->vdev->dev, descs[0].fields.address))
+               goto map_failed;
+
+       descs[0].fields.flags_len = desc_flags | skb_headlen(skb);
+
+       /* Map the frags */
+       for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+               unsigned long dma_addr;
+               skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+
+               dma_addr = dma_map_page(&adapter->vdev->dev, frag->page,
+                                       frag->page_offset, frag->size,
+                                       DMA_TO_DEVICE);
+
+               if (dma_mapping_error(&adapter->vdev->dev, dma_addr))
+                       goto map_failed_frags;
+
+               descs[i+1].fields.flags_len = desc_flags | frag->size;
+               descs[i+1].fields.address = dma_addr;
        }
 
-       if (!used_bounce)
-               dma_unmap_single(&adapter->vdev->dev, data_dma_addr,
-                                skb->len, DMA_TO_DEVICE);
+       if (ibmveth_send(adapter, descs)) {
+               adapter->tx_send_failed++;
+               netdev->stats.tx_dropped++;
+       } else {
+               netdev->stats.tx_packets++;
+               netdev->stats.tx_bytes += skb->len;
+       }
 
-out:   spin_lock_irqsave(&adapter->stats_lock, flags);
-       netdev->stats.tx_dropped += tx_dropped;
-       netdev->stats.tx_bytes += tx_bytes;
-       netdev->stats.tx_packets += tx_packets;
-       adapter->tx_send_failed += tx_send_failed;
-       adapter->tx_map_failed += tx_map_failed;
-       spin_unlock_irqrestore(&adapter->stats_lock, flags);
+       for (i = 0; i < skb_shinfo(skb)->nr_frags + 1; i++)
+               dma_unmap_page(&adapter->vdev->dev, descs[i].fields.address,
+                              descs[i].fields.flags_len & IBMVETH_BUF_LEN_MASK,
+                              DMA_TO_DEVICE);
 
+out:
        dev_kfree_skb(skb);
        return NETDEV_TX_OK;
+
+map_failed_frags:
+       last = i+1;
+       for (i = 0; i < last; i++)
+               dma_unmap_page(&adapter->vdev->dev, descs[i].fields.address,
+                              descs[i].fields.flags_len & IBMVETH_BUF_LEN_MASK,
+                              DMA_TO_DEVICE);
+
+map_failed:
+       if (!firmware_has_feature(FW_FEATURE_CMO))
+               netdev_err(netdev, "tx: unable to map xmit buffer\n");
+       adapter->tx_map_failed++;
+       skb_linearize(skb);
+       force_bounce = 1;
+       goto retry_bounce;
 }
 
 static int ibmveth_poll(struct napi_struct *napi, int budget)
 {
-       struct ibmveth_adapter *adapter = container_of(napi, struct ibmveth_adapter, napi);
+       struct ibmveth_adapter *adapter =
+                       container_of(napi, struct ibmveth_adapter, napi);
        struct net_device *netdev = adapter->netdev;
        int frames_processed = 0;
        unsigned long lpar_rc;
 
- restart_poll:
+restart_poll:
        do {
-               struct sk_buff *skb;
-
                if (!ibmveth_rxq_pending_buffer(adapter))
                        break;
 
-               rmb();
+               smp_rmb();
                if (!ibmveth_rxq_buffer_valid(adapter)) {
                        wmb(); /* suggested by larson1 */
                        adapter->rx_invalid_buffer++;
-                       ibmveth_debug_printk("recycling invalid buffer\n");
+                       netdev_dbg(netdev, "recycling invalid buffer\n");
                        ibmveth_rxq_recycle_buffer(adapter);
                } else {
+                       struct sk_buff *skb, *new_skb;
                        int length = ibmveth_rxq_frame_length(adapter);
                        int offset = ibmveth_rxq_frame_offset(adapter);
                        int csum_good = ibmveth_rxq_csum_good(adapter);
 
                        skb = ibmveth_rxq_get_buffer(adapter);
-                       if (csum_good)
-                               skb->ip_summed = CHECKSUM_UNNECESSARY;
 
-                       ibmveth_rxq_harvest_buffer(adapter);
+                       new_skb = NULL;
+                       if (length < rx_copybreak)
+                               new_skb = netdev_alloc_skb(netdev, length);
+
+                       if (new_skb) {
+                               skb_copy_to_linear_data(new_skb,
+                                                       skb->data + offset,
+                                                       length);
+                               if (rx_flush)
+                                       ibmveth_flush_buffer(skb->data,
+                                               length + offset);
+                               skb = new_skb;
+                               ibmveth_rxq_recycle_buffer(adapter);
+                       } else {
+                               ibmveth_rxq_harvest_buffer(adapter);
+                               skb_reserve(skb, offset);
+                       }
 
-                       skb_reserve(skb, offset);
                        skb_put(skb, length);
                        skb->protocol = eth_type_trans(skb, netdev);
 
+                       if (csum_good)
+                               skb->ip_summed = CHECKSUM_UNNECESSARY;
+
                        netif_receive_skb(skb); /* send it up */
 
                        netdev->stats.rx_packets++;
@@ -1030,7 +1164,7 @@ static int ibmveth_poll(struct napi_struct *napi, int budget)
                lpar_rc = h_vio_signal(adapter->vdev->unit_address,
                                       VIO_IRQ_ENABLE);
 
-               ibmveth_assert(lpar_rc == H_SUCCESS);
+               BUG_ON(lpar_rc != H_SUCCESS);
 
                napi_complete(napi);
 
@@ -1054,7 +1188,7 @@ static irqreturn_t ibmveth_interrupt(int irq, void *dev_instance)
        if (napi_schedule_prep(&adapter->napi)) {
                lpar_rc = h_vio_signal(adapter->vdev->unit_address,
                                       VIO_IRQ_DISABLE);
-               ibmveth_assert(lpar_rc == H_SUCCESS);
+               BUG_ON(lpar_rc != H_SUCCESS);
                __napi_schedule(&adapter->napi);
        }
        return IRQ_HANDLED;
@@ -1071,8 +1205,9 @@ static void ibmveth_set_multicast_list(struct net_device *netdev)
                                           IbmVethMcastEnableRecv |
                                           IbmVethMcastDisableFiltering,
                                           0);
-               if(lpar_rc != H_SUCCESS) {
-                       ibmveth_error_printk("h_multicast_ctrl rc=%ld when entering promisc mode\n", lpar_rc);
+               if (lpar_rc != H_SUCCESS) {
+                       netdev_err(netdev, "h_multicast_ctrl rc=%ld when "
+                                  "entering promisc mode\n", lpar_rc);
                }
        } else {
                struct netdev_hw_addr *ha;
@@ -1082,19 +1217,23 @@ static void ibmveth_set_multicast_list(struct net_device *netdev)
                                           IbmVethMcastDisableFiltering |
                                           IbmVethMcastClearFilterTable,
                                           0);
-               if(lpar_rc != H_SUCCESS) {
-                       ibmveth_error_printk("h_multicast_ctrl rc=%ld when attempting to clear filter table\n", lpar_rc);
+               if (lpar_rc != H_SUCCESS) {
+                       netdev_err(netdev, "h_multicast_ctrl rc=%ld when "
+                                  "attempting to clear filter table\n",
+                                  lpar_rc);
                }
                /* add the addresses to the filter table */
                netdev_for_each_mc_addr(ha, netdev) {
-                       // add the multicast address to the filter table
+                       /* add the multicast address to the filter table */
                        unsigned long mcast_addr = 0;
                        memcpy(((char *)&mcast_addr)+2, ha->addr, 6);
                        lpar_rc = h_multicast_ctrl(adapter->vdev->unit_address,
                                                   IbmVethMcastAddFilter,
                                                   mcast_addr);
-                       if(lpar_rc != H_SUCCESS) {
-                               ibmveth_error_printk("h_multicast_ctrl rc=%ld when adding an entry to the filter table\n", lpar_rc);
+                       if (lpar_rc != H_SUCCESS) {
+                               netdev_err(netdev, "h_multicast_ctrl rc=%ld "
+                                          "when adding an entry to the filter "
+                                          "table\n", lpar_rc);
                        }
                }
 
@@ -1102,8 +1241,9 @@ static void ibmveth_set_multicast_list(struct net_device *netdev)
                lpar_rc = h_multicast_ctrl(adapter->vdev->unit_address,
                                           IbmVethMcastEnableFiltering,
                                           0);
-               if(lpar_rc != H_SUCCESS) {
-                       ibmveth_error_printk("h_multicast_ctrl rc=%ld when enabling filtering\n", lpar_rc);
+               if (lpar_rc != H_SUCCESS) {
+                       netdev_err(netdev, "h_multicast_ctrl rc=%ld when "
+                                  "enabling filtering\n", lpar_rc);
                }
        }
 }
@@ -1116,14 +1256,14 @@ static int ibmveth_change_mtu(struct net_device *dev, int new_mtu)
        int i, rc;
        int need_restart = 0;
 
-       if (new_mtu < IBMVETH_MAX_MTU)
+       if (new_mtu < IBMVETH_MIN_MTU)
                return -EINVAL;
 
-       for (i = 0; i < IbmVethNumBufferPools; i++)
+       for (i = 0; i < IBMVETH_NUM_BUFF_POOLS; i++)
                if (new_mtu_oh < adapter->rx_buff_pool[i].buff_size)
                        break;
 
-       if (i == IbmVethNumBufferPools)
+       if (i == IBMVETH_NUM_BUFF_POOLS)
                return -EINVAL;
 
        /* Deactivate all the buffer pools so that the next loop can activate
@@ -1136,7 +1276,7 @@ static int ibmveth_change_mtu(struct net_device *dev, int new_mtu)
        }
 
        /* Look for an active buffer pool that can hold the new MTU */
-       for(i = 0; i<IbmVethNumBufferPools; i++) {
+       for (i = 0; i < IBMVETH_NUM_BUFF_POOLS; i++) {
                adapter->rx_buff_pool[i].active = 1;
 
                if (new_mtu_oh < adapter->rx_buff_pool[i].buff_size) {
@@ -1190,7 +1330,7 @@ static unsigned long ibmveth_get_desired_dma(struct vio_dev *vdev)
        ret = IBMVETH_BUFF_LIST_SIZE + IBMVETH_FILT_LIST_SIZE;
        ret += IOMMU_PAGE_ALIGN(netdev->mtu);
 
-       for (i = 0; i < IbmVethNumBufferPools; i++) {
+       for (i = 0; i < IBMVETH_NUM_BUFF_POOLS; i++) {
                /* add the size of the active receive buffers */
                if (adapter->rx_buff_pool[i].active)
                        ret +=
@@ -1219,41 +1359,36 @@ static const struct net_device_ops ibmveth_netdev_ops = {
 #endif
 };
 
-static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id)
+static int __devinit ibmveth_probe(struct vio_dev *dev,
+                                  const struct vio_device_id *id)
 {
        int rc, i;
-       long ret;
        struct net_device *netdev;
        struct ibmveth_adapter *adapter;
-       unsigned long set_attr, ret_attr;
-
        unsigned char *mac_addr_p;
        unsigned int *mcastFilterSize_p;
 
+       dev_dbg(&dev->dev, "entering ibmveth_probe for UA 0x%x\n",
+               dev->unit_address);
 
-       ibmveth_debug_printk_no_adapter("entering ibmveth_probe for UA 0x%x\n",
-                                       dev->unit_address);
-
-       mac_addr_p = (unsigned char *) vio_get_attribute(dev,
-                                               VETH_MAC_ADDR, NULL);
-       if(!mac_addr_p) {
-               printk(KERN_ERR "(%s:%3.3d) ERROR: Can't find VETH_MAC_ADDR "
-                               "attribute\n", __FILE__, __LINE__);
-               return 0;
+       mac_addr_p = (unsigned char *)vio_get_attribute(dev, VETH_MAC_ADDR,
+                                                       NULL);
+       if (!mac_addr_p) {
+               dev_err(&dev->dev, "Can't find VETH_MAC_ADDR attribute\n");
+               return -EINVAL;
        }
 
-       mcastFilterSize_p = (unsigned int *) vio_get_attribute(dev,
+       mcastFilterSize_p = (unsigned int *)vio_get_attribute(dev,
                                                VETH_MCAST_FILTER_SIZE, NULL);
-       if(!mcastFilterSize_p) {
-               printk(KERN_ERR "(%s:%3.3d) ERROR: Can't find "
-                               "VETH_MCAST_FILTER_SIZE attribute\n",
-                               __FILE__, __LINE__);
-               return 0;
+       if (!mcastFilterSize_p) {
+               dev_err(&dev->dev, "Can't find VETH_MCAST_FILTER_SIZE "
+                       "attribute\n");
+               return -EINVAL;
        }
 
        netdev = alloc_etherdev(sizeof(struct ibmveth_adapter));
 
-       if(!netdev)
+       if (!netdev)
                return -ENOMEM;
 
        adapter = netdev_priv(netdev);
@@ -1261,19 +1396,19 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_
 
        adapter->vdev = dev;
        adapter->netdev = netdev;
-       adapter->mcastFilterSize= *mcastFilterSize_p;
+       adapter->mcastFilterSize = *mcastFilterSize_p;
        adapter->pool_config = 0;
 
        netif_napi_add(netdev, &adapter->napi, ibmveth_poll, 16);
 
-       /*      Some older boxes running PHYP non-natively have an OF that
-               returns a 8-byte local-mac-address field (and the first
-               2 bytes have to be ignored) while newer boxes' OF return
-               a 6-byte field. Note that IEEE 1275 specifies that
-               local-mac-address must be a 6-byte field.
-               The RPA doc specifies that the first byte must be 10b, so
-               we'll just look for it to solve this 8 vs. 6 byte field issue */
-
+       /*
+        * Some older boxes running PHYP non-natively have an OF that returns
+        * a 8-byte local-mac-address field (and the first 2 bytes have to be
+        * ignored) while newer boxes' OF return a 6-byte field. Note that
+        * IEEE 1275 specifies that local-mac-address must be a 6-byte field.
+        * The RPA doc specifies that the first byte must be 10b, so we'll
+        * just look for it to solve this 8 vs. 6 byte field issue
+        */
        if ((*mac_addr_p & 0x3) != 0x02)
                mac_addr_p += 2;
 
@@ -1284,12 +1419,11 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_
        netdev->netdev_ops = &ibmveth_netdev_ops;
        netdev->ethtool_ops = &netdev_ethtool_ops;
        SET_NETDEV_DEV(netdev, &dev->dev);
-       netdev->features |= NETIF_F_LLTX;
-       spin_lock_init(&adapter->stats_lock);
+       netdev->features |= NETIF_F_SG;
 
        memcpy(netdev->dev_addr, &adapter->mac_addr, netdev->addr_len);
 
-       for(i = 0; i<IbmVethNumBufferPools; i++) {
+       for (i = 0; i < IBMVETH_NUM_BUFF_POOLS; i++) {
                struct kobject *kobj = &adapter->rx_buff_pool[i].kobj;
                int error;
 
@@ -1302,41 +1436,25 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_
                        kobject_uevent(kobj, KOBJ_ADD);
        }
 
-       ibmveth_debug_printk("adapter @ 0x%p\n", adapter);
+       netdev_dbg(netdev, "adapter @ 0x%p\n", adapter);
 
        adapter->buffer_list_dma = DMA_ERROR_CODE;
        adapter->filter_list_dma = DMA_ERROR_CODE;
        adapter->rx_queue.queue_dma = DMA_ERROR_CODE;
 
-       ibmveth_debug_printk("registering netdev...\n");
-
-       ret = h_illan_attributes(dev->unit_address, 0, 0, &ret_attr);
-
-       if (ret == H_SUCCESS && !(ret_attr & IBMVETH_ILLAN_ACTIVE_TRUNK) &&
-           !(ret_attr & IBMVETH_ILLAN_TRUNK_PRI_MASK) &&
-           (ret_attr & IBMVETH_ILLAN_PADDED_PKT_CSUM)) {
-               set_attr = IBMVETH_ILLAN_IPV4_TCP_CSUM;
-
-               ret = h_illan_attributes(dev->unit_address, 0, set_attr, &ret_attr);
+       netdev_dbg(netdev, "registering netdev...\n");
 
-               if (ret == H_SUCCESS) {
-                       adapter->rx_csum = 1;
-                       netdev->features |= NETIF_F_IP_CSUM;
-               } else
-                       ret = h_illan_attributes(dev->unit_address, set_attr, 0, &ret_attr);
-       }
+       ibmveth_set_csum_offload(netdev, 1, ibmveth_set_tx_csum_flags);
 
        rc = register_netdev(netdev);
 
-       if(rc) {
-               ibmveth_debug_printk("failed to register netdev rc=%d\n", rc);
+       if (rc) {
+               netdev_dbg(netdev, "failed to register netdev rc=%d\n", rc);
                free_netdev(netdev);
                return rc;
        }
 
-       ibmveth_debug_printk("registered\n");
-
-       ibmveth_proc_register_adapter(adapter);
+       netdev_dbg(netdev, "registered\n");
 
        return 0;
 }
@@ -1347,114 +1465,23 @@ static int __devexit ibmveth_remove(struct vio_dev *dev)
        struct ibmveth_adapter *adapter = netdev_priv(netdev);
        int i;
 
-       for(i = 0; i<IbmVethNumBufferPools; i++)
+       for (i = 0; i < IBMVETH_NUM_BUFF_POOLS; i++)
                kobject_put(&adapter->rx_buff_pool[i].kobj);
 
        unregister_netdev(netdev);
 
-       ibmveth_proc_unregister_adapter(adapter);
-
        free_netdev(netdev);
        dev_set_drvdata(&dev->dev, NULL);
 
        return 0;
 }
 
-#ifdef CONFIG_PROC_FS
-static void ibmveth_proc_register_driver(void)
-{
-       ibmveth_proc_dir = proc_mkdir(IBMVETH_PROC_DIR, init_net.proc_net);
-       if (ibmveth_proc_dir) {
-       }
-}
-
-static void ibmveth_proc_unregister_driver(void)
-{
-       remove_proc_entry(IBMVETH_PROC_DIR, init_net.proc_net);
-}
-
-static int ibmveth_show(struct seq_file *seq, void *v)
-{
-       struct ibmveth_adapter *adapter = seq->private;
-       char *current_mac = (char *) adapter->netdev->dev_addr;
-       char *firmware_mac = (char *) &adapter->mac_addr;
-
-       seq_printf(seq, "%s %s\n\n", ibmveth_driver_string, ibmveth_driver_version);
-
-       seq_printf(seq, "Unit Address:    0x%x\n", adapter->vdev->unit_address);
-       seq_printf(seq, "Current MAC:     %pM\n", current_mac);
-       seq_printf(seq, "Firmware MAC:    %pM\n", firmware_mac);
-
-       seq_printf(seq, "\nAdapter Statistics:\n");
-       seq_printf(seq, "  TX:  vio_map_single failres:      %lld\n", adapter->tx_map_failed);
-       seq_printf(seq, "       send failures:               %lld\n", adapter->tx_send_failed);
-       seq_printf(seq, "  RX:  replenish task cycles:       %lld\n", adapter->replenish_task_cycles);
-       seq_printf(seq, "       alloc_skb_failures:          %lld\n", adapter->replenish_no_mem);
-       seq_printf(seq, "       add buffer failures:         %lld\n", adapter->replenish_add_buff_failure);
-       seq_printf(seq, "       invalid buffers:             %lld\n", adapter->rx_invalid_buffer);
-       seq_printf(seq, "       no buffers:                  %lld\n", adapter->rx_no_buffer);
-
-       return 0;
-}
-
-static int ibmveth_proc_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, ibmveth_show, PDE(inode)->data);
-}
-
-static const struct file_operations ibmveth_proc_fops = {
-       .owner   = THIS_MODULE,
-       .open    = ibmveth_proc_open,
-       .read    = seq_read,
-       .llseek  = seq_lseek,
-       .release = single_release,
-};
-
-static void ibmveth_proc_register_adapter(struct ibmveth_adapter *adapter)
-{
-       struct proc_dir_entry *entry;
-       if (ibmveth_proc_dir) {
-               char u_addr[10];
-               sprintf(u_addr, "%x", adapter->vdev->unit_address);
-               entry = proc_create_data(u_addr, S_IFREG, ibmveth_proc_dir,
-                                        &ibmveth_proc_fops, adapter);
-               if (!entry)
-                       ibmveth_error_printk("Cannot create adapter proc entry");
-       }
-}
-
-static void ibmveth_proc_unregister_adapter(struct ibmveth_adapter *adapter)
-{
-       if (ibmveth_proc_dir) {
-               char u_addr[10];
-               sprintf(u_addr, "%x", adapter->vdev->unit_address);
-               remove_proc_entry(u_addr, ibmveth_proc_dir);
-       }
-}
-
-#else /* CONFIG_PROC_FS */
-static void ibmveth_proc_register_adapter(struct ibmveth_adapter *adapter)
-{
-}
-
-static void ibmveth_proc_unregister_adapter(struct ibmveth_adapter *adapter)
-{
-}
-static void ibmveth_proc_register_driver(void)
-{
-}
-
-static void ibmveth_proc_unregister_driver(void)
-{
-}
-#endif /* CONFIG_PROC_FS */
-
 static struct attribute veth_active_attr;
 static struct attribute veth_num_attr;
 static struct attribute veth_size_attr;
 
-static ssize_t veth_pool_show(struct kobject * kobj,
-                              struct attribute * attr, char * buf)
+static ssize_t veth_pool_show(struct kobject *kobj,
+                             struct attribute *attr, char *buf)
 {
        struct ibmveth_buff_pool *pool = container_of(kobj,
                                                      struct ibmveth_buff_pool,
@@ -1469,8 +1496,8 @@ static ssize_t veth_pool_show(struct kobject * kobj,
        return 0;
 }
 
-static ssize_t veth_pool_store(struct kobject * kobj, struct attribute * attr,
-const char * buf, size_t count)
+static ssize_t veth_pool_store(struct kobject *kobj, struct attribute *attr,
+                              const char *buf, size_t count)
 {
        struct ibmveth_buff_pool *pool = container_of(kobj,
                                                      struct ibmveth_buff_pool,
@@ -1484,8 +1511,9 @@ const char * buf, size_t count)
        if (attr == &veth_active_attr) {
                if (value && !pool->active) {
                        if (netif_running(netdev)) {
-                               if(ibmveth_alloc_buffer_pool(pool)) {
-                                       ibmveth_error_printk("unable to alloc pool\n");
+                               if (ibmveth_alloc_buffer_pool(pool)) {
+                                       netdev_err(netdev,
+                                                  "unable to alloc pool\n");
                                        return -ENOMEM;
                                }
                                pool->active = 1;
@@ -1494,14 +1522,15 @@ const char * buf, size_t count)
                                adapter->pool_config = 0;
                                if ((rc = ibmveth_open(netdev)))
                                        return rc;
-                       } else
+                       } else {
                                pool->active = 1;
+                       }
                } else if (!value && pool->active) {
                        int mtu = netdev->mtu + IBMVETH_BUFF_OH;
                        int i;
                        /* Make sure there is a buffer pool with buffers that
                           can hold a packet of the size of the MTU */
-                       for (i = 0; i < IbmVethNumBufferPools; i++) {
+                       for (i = 0; i < IBMVETH_NUM_BUFF_POOLS; i++) {
                                if (pool == &adapter->rx_buff_pool[i])
                                        continue;
                                if (!adapter->rx_buff_pool[i].active)
@@ -1510,8 +1539,8 @@ const char * buf, size_t count)
                                        break;
                        }
 
-                       if (i == IbmVethNumBufferPools) {
-                               ibmveth_error_printk("no active pool >= MTU\n");
+                       if (i == IBMVETH_NUM_BUFF_POOLS) {
+                               netdev_err(netdev, "no active pool >= MTU\n");
                                return -EPERM;
                        }
 
@@ -1526,9 +1555,9 @@ const char * buf, size_t count)
                        pool->active = 0;
                }
        } else if (attr == &veth_num_attr) {
-               if (value <= 0 || value > IBMVETH_MAX_POOL_COUNT)
+               if (value <= 0 || value > IBMVETH_MAX_POOL_COUNT) {
                        return -EINVAL;
-               else {
+               else {
                        if (netif_running(netdev)) {
                                adapter->pool_config = 1;
                                ibmveth_close(netdev);
@@ -1536,13 +1565,14 @@ const char * buf, size_t count)
                                pool->size = value;
                                if ((rc = ibmveth_open(netdev)))
                                        return rc;
-                       } else
+                       } else {
                                pool->size = value;
+                       }
                }
        } else if (attr == &veth_size_attr) {
-               if (value <= IBMVETH_BUFF_OH || value > IBMVETH_MAX_BUF_SIZE)
+               if (value <= IBMVETH_BUFF_OH || value > IBMVETH_MAX_BUF_SIZE) {
                        return -EINVAL;
-               else {
+               else {
                        if (netif_running(netdev)) {
                                adapter->pool_config = 1;
                                ibmveth_close(netdev);
@@ -1550,8 +1580,9 @@ const char * buf, size_t count)
                                pool->buff_size = value;
                                if ((rc = ibmveth_open(netdev)))
                                        return rc;
-                       } else
+                       } else {
                                pool->buff_size = value;
+                       }
                }
        }
 
@@ -1561,16 +1592,16 @@ const char * buf, size_t count)
 }
 
 
-#define ATTR(_name, _mode)      \
-        struct attribute veth_##_name##_attr = {               \
-        .name = __stringify(_name), .mode = _mode, \
-        };
+#define ATTR(_name, _mode)                             \
+       struct attribute veth_##_name##_attr = {        \
+       .name = __stringify(_name), .mode = _mode,      \
+       };
 
 static ATTR(active, 0644);
 static ATTR(num, 0644);
 static ATTR(size, 0644);
 
-static struct attribute * veth_pool_attrs[] = {
+static struct attribute *veth_pool_attrs[] = {
        &veth_active_attr,
        &veth_num_attr,
        &veth_size_attr,
@@ -1595,7 +1626,7 @@ static int ibmveth_resume(struct device *dev)
        return 0;
 }
 
-static struct vio_device_id ibmveth_device_table[] __devinitdata= {
+static struct vio_device_id ibmveth_device_table[] __devinitdata = {
        { "network", "IBM,l-lan"},
        { "", "" }
 };
@@ -1619,9 +1650,8 @@ static struct vio_driver ibmveth_driver = {
 
 static int __init ibmveth_module_init(void)
 {
-       ibmveth_printk("%s: %s %s\n", ibmveth_driver_name, ibmveth_driver_string, ibmveth_driver_version);
-
-       ibmveth_proc_register_driver();
+       printk(KERN_DEBUG "%s: %s %s\n", ibmveth_driver_name,
+              ibmveth_driver_string, ibmveth_driver_version);
 
        return vio_register_driver(&ibmveth_driver);
 }
@@ -1629,7 +1659,6 @@ static int __init ibmveth_module_init(void)
 static void __exit ibmveth_module_exit(void)
 {
        vio_unregister_driver(&ibmveth_driver);
-       ibmveth_proc_unregister_driver();
 }
 
 module_init(ibmveth_module_init);
index ec76ace66c6b64520f2a3e4ac9d2f88ad29f88e5..43a794fab9ff9e2b0e9998ceaa887d1973562059 100644 (file)
@@ -1,26 +1,28 @@
-/**************************************************************************/
-/*                                                                        */
-/* IBM eServer i/[Series Virtual Ethernet Device Driver                   */
-/* Copyright (C) 2003 IBM Corp.                                           */
-/*  Dave Larson (larson1@us.ibm.com)                                      */
-/*  Santiago Leon (santil@us.ibm.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 of the License, 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  */
-/*                                                                   USA  */
-/*                                                                        */
-/**************************************************************************/
+/*
+ * IBM Power Virtual Ethernet Device Driver
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * Copyright (C) IBM Corporation, 2003, 2010
+ *
+ * Authors: Dave Larson <larson1@us.ibm.com>
+ *         Santiago Leon <santil@linux.vnet.ibm.com>
+ *         Brian King <brking@linux.vnet.ibm.com>
+ *         Robert Jennings <rcj@linux.vnet.ibm.com>
+ *         Anton Blanchard <anton@au.ibm.com>
+ */
 
 #ifndef _IBMVETH_H
 #define _IBMVETH_H
@@ -92,17 +94,17 @@ static inline long h_illan_attributes(unsigned long unit_address,
 #define h_change_logical_lan_mac(ua, mac) \
   plpar_hcall_norets(H_CHANGE_LOGICAL_LAN_MAC, ua, mac)
 
-#define IbmVethNumBufferPools 5
+#define IBMVETH_NUM_BUFF_POOLS 5
 #define IBMVETH_IO_ENTITLEMENT_DEFAULT 4243456 /* MTU of 1500 needs 4.2Mb */
 #define IBMVETH_BUFF_OH 22 /* Overhead: 14 ethernet header + 8 opaque handle */
-#define IBMVETH_MAX_MTU 68
+#define IBMVETH_MIN_MTU 68
 #define IBMVETH_MAX_POOL_COUNT 4096
 #define IBMVETH_BUFF_LIST_SIZE 4096
 #define IBMVETH_FILT_LIST_SIZE 4096
 #define IBMVETH_MAX_BUF_SIZE (1024 * 128)
 
 static int pool_size[] = { 512, 1024 * 2, 1024 * 16, 1024 * 32, 1024 * 64 };
-static int pool_count[] = { 256, 768, 256, 256, 256 };
+static int pool_count[] = { 256, 512, 256, 256, 256 };
 static int pool_active[] = { 1, 1, 0, 0, 0};
 
 #define IBM_VETH_INVALID_MAP ((u16)0xffff)
@@ -142,13 +144,15 @@ struct ibmveth_adapter {
     void * filter_list_addr;
     dma_addr_t buffer_list_dma;
     dma_addr_t filter_list_dma;
-    struct ibmveth_buff_pool rx_buff_pool[IbmVethNumBufferPools];
+    struct ibmveth_buff_pool rx_buff_pool[IBMVETH_NUM_BUFF_POOLS];
     struct ibmveth_rx_q rx_queue;
     int pool_config;
     int rx_csum;
     void *bounce_buffer;
     dma_addr_t bounce_buffer_dma;
 
+    u64 fw_ipv6_csum_support;
+    u64 fw_ipv4_csum_support;
     /* adapter specific stats */
     u64 replenish_task_cycles;
     u64 replenish_no_mem;
@@ -158,7 +162,6 @@ struct ibmveth_adapter {
     u64 rx_no_buffer;
     u64 tx_map_failed;
     u64 tx_send_failed;
-    spinlock_t stats_lock;
 };
 
 struct ibmveth_buf_desc_fields {
index 6e63d9a7fc75808baac188b1719f3d0223ad3303..44e0ff1494e08f37395d18a4827ea31db06935aa 100644 (file)
@@ -143,7 +143,7 @@ struct igb_buffer {
                        u16 next_to_watch;
                        unsigned int bytecount;
                        u16 gso_segs;
-                       union skb_shared_tx shtx;
+                       u8 tx_flags;
                        u8 mapped_as_page;
                };
                /* RX */
index 9b4e5895f5f9d978992b204c3cbbbd8190b2340f..c4d861b557ca43c367d16db99113cd8135d0ad9a 100644 (file)
@@ -1888,9 +1888,9 @@ static int __devinit igb_probe(struct pci_dev *pdev,
                goto err_eeprom;
        }
 
-       setup_timer(&adapter->watchdog_timer, &igb_watchdog,
+       setup_timer(&adapter->watchdog_timer, igb_watchdog,
                    (unsigned long) adapter);
-       setup_timer(&adapter->phy_info_timer, &igb_update_phy_info,
+       setup_timer(&adapter->phy_info_timer, igb_update_phy_info,
                    (unsigned long) adapter);
 
        INIT_WORK(&adapter->reset_task, igb_reset_task);
@@ -3954,7 +3954,7 @@ static inline int igb_tx_map_adv(struct igb_ring *tx_ring, struct sk_buff *skb,
        }
 
        tx_ring->buffer_info[i].skb = skb;
-       tx_ring->buffer_info[i].shtx = skb_shinfo(skb)->tx_flags;
+       tx_ring->buffer_info[i].tx_flags = skb_shinfo(skb)->tx_flags;
        /* multiply data chunks by size of headers */
        tx_ring->buffer_info[i].bytecount = ((gso_segs - 1) * hlen) + skb->len;
        tx_ring->buffer_info[i].gso_segs = gso_segs;
@@ -4088,7 +4088,6 @@ netdev_tx_t igb_xmit_frame_ring_adv(struct sk_buff *skb,
        u32 tx_flags = 0;
        u16 first;
        u8 hdr_len = 0;
-       union skb_shared_tx *shtx = skb_tx(skb);
 
        /* need: 1 descriptor per page,
         *       + 2 desc gap to keep tail from touching head,
@@ -4100,8 +4099,8 @@ netdev_tx_t igb_xmit_frame_ring_adv(struct sk_buff *skb,
                return NETDEV_TX_BUSY;
        }
 
-       if (unlikely(shtx->hardware)) {
-               shtx->in_progress = 1;
+       if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) {
+               skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
                tx_flags |= IGB_TX_FLAGS_TSTAMP;
        }
 
@@ -5319,7 +5318,7 @@ static void igb_tx_hwtstamp(struct igb_q_vector *q_vector, struct igb_buffer *bu
        u64 regval;
 
        /* if skb does not support hw timestamp or TX stamp not valid exit */
-       if (likely(!buffer_info->shtx.hardware) ||
+       if (likely(!(buffer_info->tx_flags & SKBTX_HW_TSTAMP)) ||
            !(rd32(E1000_TSYNCTXCTL) & E1000_TSYNCTXCTL_VALID))
                return;
 
@@ -5456,7 +5455,7 @@ static void igb_receive_skb(struct igb_q_vector *q_vector,
 static inline void igb_rx_checksum_adv(struct igb_ring *ring,
                                       u32 status_err, struct sk_buff *skb)
 {
-       skb->ip_summed = CHECKSUM_NONE;
+       skb_checksum_none_assert(skb);
 
        /* Ignore Checksum bit is set or checksum is disabled through ethtool */
        if (!(ring->flags & IGB_RING_FLAG_RX_CSUM) ||
@@ -5500,7 +5499,7 @@ static void igb_rx_hwtstamp(struct igb_q_vector *q_vector, u32 staterr,
         * values must belong to this one here and therefore we don't need to
         * compare any of the additional attributes stored for it.
         *
-        * If nothing went wrong, then it should have a skb_shared_tx that we
+        * If nothing went wrong, then it should have a shared tx_flags that we
         * can turn into a skb_shared_hwtstamps.
         */
        if (staterr & E1000_RXDADV_STAT_TSIP) {
index c539f7c9c3e08a2957826387fb1ce259954e9015..c7fab80d24906ef061acf85e600473bcc2c36472 100644 (file)
@@ -103,7 +103,7 @@ static void igbvf_receive_skb(struct igbvf_adapter *adapter,
 static inline void igbvf_rx_checksum_adv(struct igbvf_adapter *adapter,
                                          u32 status_err, struct sk_buff *skb)
 {
-       skb->ip_summed = CHECKSUM_NONE;
+       skb_checksum_none_assert(skb);
 
        /* Ignore Checksum bit is set or checksum is disabled through ethtool */
        if ((status_err & E1000_RXD_STAT_IXSM) ||
index 0b3f6df5cff78686d4324626fbc9c1966879e63c..c8ee8d28767b6832167e65c98a00ca859e26d87f 100644 (file)
@@ -827,7 +827,7 @@ static void ioc3_mii_start(struct ioc3_private *ip)
 {
        ip->ioc3_timer.expires = jiffies + (12 * HZ)/10;  /* 1.2 sec. */
        ip->ioc3_timer.data = (unsigned long) ip;
-       ip->ioc3_timer.function = &ioc3_timer;
+       ip->ioc3_timer.function = ioc3_timer;
        add_timer(&ip->ioc3_timer);
 }
 
index 72e3d2da9e9fd3174bea52c1d9feaf57e0423316..dc019809234352418978474531efa675a4e879a2 100644 (file)
@@ -1213,7 +1213,7 @@ static void ipg_nic_rx_with_start_and_end(struct net_device *dev,
 
        skb_put(skb, framelen);
        skb->protocol = eth_type_trans(skb, dev);
-       skb->ip_summed = CHECKSUM_NONE;
+       skb_checksum_none_assert(skb);
        netif_rx(skb);
        sp->rx_buff[entry] = NULL;
 }
@@ -1278,7 +1278,7 @@ static void ipg_nic_rx_with_end(struct net_device *dev,
                                jumbo->skb->protocol =
                                    eth_type_trans(jumbo->skb, dev);
 
-                               jumbo->skb->ip_summed = CHECKSUM_NONE;
+                               skb_checksum_none_assert(jumbo->skb);
                                netif_rx(jumbo->skb);
                        }
                }
@@ -1476,7 +1476,7 @@ static int ipg_nic_rx(struct net_device *dev)
                         * IP/TCP/UDP frame was received. Let the
                         * upper layer decide.
                         */
-                       skb->ip_summed = CHECKSUM_NONE;
+                       skb_checksum_none_assert(skb);
 
                        /* Hand off frame for higher layer processing.
                         * The function netif_rx() releases the sk_buff
index 5b1036ac38d7ba1a14a54394ad19f9f29b0397f4..74b20f179cea029be0f2767fac5e3b04cee987a6 100644 (file)
@@ -734,7 +734,7 @@ static int mcs_net_open(struct net_device *netdev)
        }
 
        if (!mcs_setup_urbs(mcs))
-       goto error3;
+               goto error3;
 
        ret = mcs_receive_start(mcs);
        if (ret)
index b0a6cd815be198e11334880d9ce8a728ee28d4e4..67c0ad42d818a37a282312d72ab396f9b0a1e106 100644 (file)
@@ -1182,12 +1182,13 @@ F01_E */
 
                skb = dev_alloc_skb(len + 1 - 4);
                /*
-                * if frame size,data ptr,or skb ptr are wrong ,the get next
+                * if frame size, data ptr, or skb ptr are wrong, then get next
                 * entry.
                 */
                if ((skb == NULL) || (skb->data == NULL) ||
                    (self->rx_buff.data == NULL) || (len < 6)) {
                        self->netdev->stats.rx_dropped++;
+                       kfree_skb(skb);
                        return TRUE;
                }
                skb_reserve(skb, 1);
index ba1de5973fb2083fe669027d551ea98d427bf350..8df645e78f2e9618bd22b83225efbfde4f43008a 100644 (file)
@@ -1524,7 +1524,7 @@ static void veth_receive(struct veth_lpar_connection *cnx,
 
                skb_put(skb, length);
                skb->protocol = eth_type_trans(skb, dev);
-               skb->ip_summed = CHECKSUM_NONE;
+               skb_checksum_none_assert(skb);
                netif_rx(skb);  /* send it up */
                dev->stats.rx_packets++;
                dev->stats.rx_bytes += length;
index 45fc89b9ba643d0e8f28edc8664cba4d89ae964a..c2f6e71e1181e66a810049e8bf886e541474fd27 100644 (file)
@@ -470,7 +470,7 @@ ixgb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        adapter->part_num = ixgb_get_ee_pba_number(&adapter->hw);
 
        init_timer(&adapter->watchdog_timer);
-       adapter->watchdog_timer.function = &ixgb_watchdog;
+       adapter->watchdog_timer.function = ixgb_watchdog;
        adapter->watchdog_timer.data = (unsigned long)adapter;
 
        INIT_WORK(&adapter->tx_timeout_task, ixgb_tx_timeout_task);
@@ -1905,7 +1905,7 @@ ixgb_rx_checksum(struct ixgb_adapter *adapter,
         */
        if ((rx_desc->status & IXGB_RX_DESC_STATUS_IXSM) ||
           (!(rx_desc->status & IXGB_RX_DESC_STATUS_TCPCS))) {
-               skb->ip_summed = CHECKSUM_NONE;
+               skb_checksum_none_assert(skb);
                return;
        }
 
@@ -1913,7 +1913,7 @@ ixgb_rx_checksum(struct ixgb_adapter *adapter,
        /* now look at the TCP checksum error bit */
        if (rx_desc->errors & IXGB_RX_DESC_ERRORS_TCPE) {
                /* let the stack verify checksum errors */
-               skb->ip_summed = CHECKSUM_NONE;
+               skb_checksum_none_assert(skb);
                adapter->hw_csum_rx_error++;
        } else {
                /* TCP checksum is good */
index 9e15eb93860eb4686ad79ca5058de708ff2bda72..5cebc3755b644e3a96e2581f48b848fa09393e78 100644 (file)
 #define IXGBE_MAX_FCPAUSE               0xFFFF
 
 /* Supported Rx Buffer Sizes */
-#define IXGBE_RXBUFFER_64    64     /* Used for packet split */
-#define IXGBE_RXBUFFER_128   128    /* Used for packet split */
-#define IXGBE_RXBUFFER_256   256    /* Used for packet split */
+#define IXGBE_RXBUFFER_512   512    /* Used for packet split */
 #define IXGBE_RXBUFFER_2048  2048
 #define IXGBE_RXBUFFER_4096  4096
 #define IXGBE_RXBUFFER_8192  8192
 #define IXGBE_MAX_RXBUFFER   16384  /* largest size for a single descriptor */
 
-#define IXGBE_RX_HDR_SIZE IXGBE_RXBUFFER_256
+/*
+ * NOTE: netdev_alloc_skb reserves up to 64 bytes, NET_IP_ALIGN mans we
+ * reserve 2 more, and skb_shared_info adds an additional 384 bytes more,
+ * this adds up to 512 bytes of extra data meaning the smallest allocation
+ * we could have is 1K.
+ * i.e. RXBUFFER_512 --> size-1024 slab
+ */
+#define IXGBE_RX_HDR_SIZE IXGBE_RXBUFFER_512
 
 #define MAXIMUM_ETHERNET_VLAN_SIZE (ETH_FRAME_LEN + ETH_FCS_LEN + VLAN_HLEN)
 
@@ -251,11 +256,11 @@ struct ixgbe_q_vector {
        (R)->next_to_clean - (R)->next_to_use - 1)
 
 #define IXGBE_RX_DESC_ADV(R, i)            \
-       (&(((union ixgbe_adv_rx_desc *)((R).desc))[i]))
+       (&(((union ixgbe_adv_rx_desc *)((R)->desc))[i]))
 #define IXGBE_TX_DESC_ADV(R, i)            \
-       (&(((union ixgbe_adv_tx_desc *)((R).desc))[i]))
+       (&(((union ixgbe_adv_tx_desc *)((R)->desc))[i]))
 #define IXGBE_TX_CTXTDESC_ADV(R, i)        \
-       (&(((struct ixgbe_adv_tx_context_desc *)((R).desc))[i]))
+       (&(((struct ixgbe_adv_tx_context_desc *)((R)->desc))[i]))
 
 #define IXGBE_MAX_JUMBO_FRAME_SIZE        16128
 #ifdef IXGBE_FCOE
@@ -448,9 +453,20 @@ extern int ixgbe_setup_rx_resources(struct ixgbe_adapter *, struct ixgbe_ring *)
 extern int ixgbe_setup_tx_resources(struct ixgbe_adapter *, struct ixgbe_ring *);
 extern void ixgbe_free_rx_resources(struct ixgbe_adapter *, struct ixgbe_ring *);
 extern void ixgbe_free_tx_resources(struct ixgbe_adapter *, struct ixgbe_ring *);
+extern void ixgbe_configure_rx_ring(struct ixgbe_adapter *,struct ixgbe_ring *);
+extern void ixgbe_configure_tx_ring(struct ixgbe_adapter *,struct ixgbe_ring *);
 extern void ixgbe_update_stats(struct ixgbe_adapter *adapter);
 extern int ixgbe_init_interrupt_scheme(struct ixgbe_adapter *adapter);
 extern void ixgbe_clear_interrupt_scheme(struct ixgbe_adapter *adapter);
+extern netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *,
+                                        struct net_device *,
+                                        struct ixgbe_adapter *,
+                                        struct ixgbe_ring *);
+extern void ixgbe_unmap_and_free_tx_resource(struct ixgbe_adapter *,
+                                             struct ixgbe_tx_buffer *);
+extern void ixgbe_alloc_rx_buffers(struct ixgbe_adapter *adapter,
+                                   struct ixgbe_ring *rx_ring,
+                                   int cleaned_count);
 extern void ixgbe_write_eitr(struct ixgbe_q_vector *);
 extern int ethtool_ioctl(struct ifreq *ifr);
 extern s32 ixgbe_reinit_fdir_tables_82599(struct ixgbe_hw *hw);
index dcebc82c6f4de3a4ae0134f802cbf5c7f8e8d302..25ef8b1973733df8907ce59b34a06bbae1edec7b 100644 (file)
@@ -820,16 +820,19 @@ static void ixgbe_get_drvinfo(struct net_device *netdev,
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
        char firmware_version[32];
 
-       strncpy(drvinfo->driver, ixgbe_driver_name, 32);
-       strncpy(drvinfo->version, ixgbe_driver_version, 32);
-
-       sprintf(firmware_version, "%d.%d-%d",
-               (adapter->eeprom_version & 0xF000) >> 12,
-               (adapter->eeprom_version & 0x0FF0) >> 4,
-               adapter->eeprom_version & 0x000F);
-
-       strncpy(drvinfo->fw_version, firmware_version, 32);
-       strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
+       strncpy(drvinfo->driver, ixgbe_driver_name, sizeof(drvinfo->driver));
+       strncpy(drvinfo->version, ixgbe_driver_version,
+               sizeof(drvinfo->version));
+
+       snprintf(firmware_version, sizeof(firmware_version), "%d.%d-%d",
+                (adapter->eeprom_version & 0xF000) >> 12,
+                (adapter->eeprom_version & 0x0FF0) >> 4,
+                adapter->eeprom_version & 0x000F);
+
+       strncpy(drvinfo->fw_version, firmware_version,
+               sizeof(drvinfo->fw_version));
+       strncpy(drvinfo->bus_info, pci_name(adapter->pdev),
+               sizeof(drvinfo->bus_info));
        drvinfo->n_stats = IXGBE_STATS_LEN;
        drvinfo->testinfo_len = IXGBE_TEST_LEN;
        drvinfo->regdump_len = ixgbe_get_regs_len(netdev);
@@ -1435,9 +1438,7 @@ static void ixgbe_free_desc_rings(struct ixgbe_adapter *adapter)
        struct ixgbe_ring *tx_ring = &adapter->test_tx_ring;
        struct ixgbe_ring *rx_ring = &adapter->test_rx_ring;
        struct ixgbe_hw *hw = &adapter->hw;
-       struct pci_dev *pdev = adapter->pdev;
        u32 reg_ctl;
-       int i;
 
        /* shut down the DMA engines now so they can be reinitialized later */
 
@@ -1445,14 +1446,15 @@ static void ixgbe_free_desc_rings(struct ixgbe_adapter *adapter)
        reg_ctl = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
        reg_ctl &= ~IXGBE_RXCTRL_RXEN;
        IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, reg_ctl);
-       reg_ctl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(0));
+       reg_ctl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(rx_ring->reg_idx));
        reg_ctl &= ~IXGBE_RXDCTL_ENABLE;
-       IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(0), reg_ctl);
+       IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(rx_ring->reg_idx), reg_ctl);
 
        /* now Tx */
-       reg_ctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(0));
+       reg_ctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(tx_ring->reg_idx));
        reg_ctl &= ~IXGBE_TXDCTL_ENABLE;
-       IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(0), reg_ctl);
+       IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(tx_ring->reg_idx), reg_ctl);
+
        if (hw->mac.type == ixgbe_mac_82599EB) {
                reg_ctl = IXGBE_READ_REG(hw, IXGBE_DMATXCTL);
                reg_ctl &= ~IXGBE_DMATXCTL_TE;
@@ -1461,221 +1463,57 @@ static void ixgbe_free_desc_rings(struct ixgbe_adapter *adapter)
 
        ixgbe_reset(adapter);
 
-       if (tx_ring->desc && tx_ring->tx_buffer_info) {
-               for (i = 0; i < tx_ring->count; i++) {
-                       struct ixgbe_tx_buffer *buf =
-                                       &(tx_ring->tx_buffer_info[i]);
-                       if (buf->dma)
-                               dma_unmap_single(&pdev->dev, buf->dma,
-                                                buf->length, DMA_TO_DEVICE);
-                       if (buf->skb)
-                               dev_kfree_skb(buf->skb);
-               }
-       }
-
-       if (rx_ring->desc && rx_ring->rx_buffer_info) {
-               for (i = 0; i < rx_ring->count; i++) {
-                       struct ixgbe_rx_buffer *buf =
-                                       &(rx_ring->rx_buffer_info[i]);
-                       if (buf->dma)
-                               dma_unmap_single(&pdev->dev, buf->dma,
-                                                IXGBE_RXBUFFER_2048,
-                                                DMA_FROM_DEVICE);
-                       if (buf->skb)
-                               dev_kfree_skb(buf->skb);
-               }
-       }
-
-       if (tx_ring->desc) {
-               dma_free_coherent(&pdev->dev, tx_ring->size, tx_ring->desc,
-                                 tx_ring->dma);
-               tx_ring->desc = NULL;
-       }
-       if (rx_ring->desc) {
-               dma_free_coherent(&pdev->dev, rx_ring->size, rx_ring->desc,
-                                 rx_ring->dma);
-               rx_ring->desc = NULL;
-       }
-
-       kfree(tx_ring->tx_buffer_info);
-       tx_ring->tx_buffer_info = NULL;
-       kfree(rx_ring->rx_buffer_info);
-       rx_ring->rx_buffer_info = NULL;
+       ixgbe_free_tx_resources(adapter, &adapter->test_tx_ring);
+       ixgbe_free_rx_resources(adapter, &adapter->test_rx_ring);
 }
 
 static int ixgbe_setup_desc_rings(struct ixgbe_adapter *adapter)
 {
        struct ixgbe_ring *tx_ring = &adapter->test_tx_ring;
        struct ixgbe_ring *rx_ring = &adapter->test_rx_ring;
-       struct pci_dev *pdev = adapter->pdev;
        u32 rctl, reg_data;
-       int i, ret_val;
+       int ret_val;
+       int err;
 
        /* Setup Tx descriptor ring and Tx buffers */
+       tx_ring->count = IXGBE_DEFAULT_TXD;
+       tx_ring->queue_index = 0;
+       tx_ring->reg_idx = adapter->tx_ring[0]->reg_idx;
+       tx_ring->numa_node = adapter->node;
 
-       if (!tx_ring->count)
-               tx_ring->count = IXGBE_DEFAULT_TXD;
-
-       tx_ring->tx_buffer_info = kcalloc(tx_ring->count,
-                                         sizeof(struct ixgbe_tx_buffer),
-                                         GFP_KERNEL);
-       if (!(tx_ring->tx_buffer_info)) {
-               ret_val = 1;
-               goto err_nomem;
-       }
-
-       tx_ring->size = tx_ring->count * sizeof(union ixgbe_adv_tx_desc);
-       tx_ring->size = ALIGN(tx_ring->size, 4096);
-       tx_ring->desc = dma_alloc_coherent(&pdev->dev, tx_ring->size,
-                                          &tx_ring->dma, GFP_KERNEL);
-       if (!(tx_ring->desc)) {
-               ret_val = 2;
-               goto err_nomem;
-       }
-       tx_ring->next_to_use = tx_ring->next_to_clean = 0;
-
-       IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDBAL(0),
-                       ((u64) tx_ring->dma & 0x00000000FFFFFFFF));
-       IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDBAH(0),
-                       ((u64) tx_ring->dma >> 32));
-       IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDLEN(0),
-                       tx_ring->count * sizeof(union ixgbe_adv_tx_desc));
-       IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDH(0), 0);
-       IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDT(0), 0);
-
-       reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_HLREG0);
-       reg_data |= IXGBE_HLREG0_TXPADEN;
-       IXGBE_WRITE_REG(&adapter->hw, IXGBE_HLREG0, reg_data);
+       err = ixgbe_setup_tx_resources(adapter, tx_ring);
+       if (err)
+               return 1;
 
        if (adapter->hw.mac.type == ixgbe_mac_82599EB) {
                reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_DMATXCTL);
                reg_data |= IXGBE_DMATXCTL_TE;
                IXGBE_WRITE_REG(&adapter->hw, IXGBE_DMATXCTL, reg_data);
        }
-       reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_TXDCTL(0));
-       reg_data |= IXGBE_TXDCTL_ENABLE;
-       IXGBE_WRITE_REG(&adapter->hw, IXGBE_TXDCTL(0), reg_data);
-
-       for (i = 0; i < tx_ring->count; i++) {
-               union ixgbe_adv_tx_desc *desc = IXGBE_TX_DESC_ADV(*tx_ring, i);
-               struct sk_buff *skb;
-               unsigned int size = 1024;
-
-               skb = alloc_skb(size, GFP_KERNEL);
-               if (!skb) {
-                       ret_val = 3;
-                       goto err_nomem;
-               }
-               skb_put(skb, size);
-               tx_ring->tx_buffer_info[i].skb = skb;
-               tx_ring->tx_buffer_info[i].length = skb->len;
-               tx_ring->tx_buffer_info[i].dma =
-                       dma_map_single(&pdev->dev, skb->data, skb->len,
-                                      DMA_TO_DEVICE);
-               desc->read.buffer_addr =
-                                   cpu_to_le64(tx_ring->tx_buffer_info[i].dma);
-               desc->read.cmd_type_len = cpu_to_le32(skb->len);
-               desc->read.cmd_type_len |= cpu_to_le32(IXGBE_TXD_CMD_EOP |
-                                                      IXGBE_TXD_CMD_IFCS |
-                                                      IXGBE_TXD_CMD_RS);
-               desc->read.olinfo_status = 0;
-               if (adapter->hw.mac.type == ixgbe_mac_82599EB)
-                       desc->read.olinfo_status |=
-                                       (skb->len << IXGBE_ADVTXD_PAYLEN_SHIFT);
 
-       }
+       ixgbe_configure_tx_ring(adapter, tx_ring);
 
        /* Setup Rx Descriptor ring and Rx buffers */
-
-       if (!rx_ring->count)
-               rx_ring->count = IXGBE_DEFAULT_RXD;
-
-       rx_ring->rx_buffer_info = kcalloc(rx_ring->count,
-                                         sizeof(struct ixgbe_rx_buffer),
-                                         GFP_KERNEL);
-       if (!(rx_ring->rx_buffer_info)) {
+       rx_ring->count = IXGBE_DEFAULT_RXD;
+       rx_ring->queue_index = 0;
+       rx_ring->reg_idx = adapter->rx_ring[0]->reg_idx;
+       rx_ring->rx_buf_len = IXGBE_RXBUFFER_2048;
+       rx_ring->numa_node = adapter->node;
+
+       err = ixgbe_setup_rx_resources(adapter, rx_ring);
+       if (err) {
                ret_val = 4;
                goto err_nomem;
        }
 
-       rx_ring->size = rx_ring->count * sizeof(union ixgbe_adv_rx_desc);
-       rx_ring->size = ALIGN(rx_ring->size, 4096);
-       rx_ring->desc = dma_alloc_coherent(&pdev->dev, rx_ring->size,
-                                          &rx_ring->dma, GFP_KERNEL);
-       if (!(rx_ring->desc)) {
-               ret_val = 5;
-               goto err_nomem;
-       }
-       rx_ring->next_to_use = rx_ring->next_to_clean = 0;
-
        rctl = IXGBE_READ_REG(&adapter->hw, IXGBE_RXCTRL);
        IXGBE_WRITE_REG(&adapter->hw, IXGBE_RXCTRL, rctl & ~IXGBE_RXCTRL_RXEN);
-       IXGBE_WRITE_REG(&adapter->hw, IXGBE_RDBAL(0),
-                       ((u64)rx_ring->dma & 0xFFFFFFFF));
-       IXGBE_WRITE_REG(&adapter->hw, IXGBE_RDBAH(0),
-                       ((u64) rx_ring->dma >> 32));
-       IXGBE_WRITE_REG(&adapter->hw, IXGBE_RDLEN(0), rx_ring->size);
-       IXGBE_WRITE_REG(&adapter->hw, IXGBE_RDH(0), 0);
-       IXGBE_WRITE_REG(&adapter->hw, IXGBE_RDT(0), 0);
-
-       reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_FCTRL);
-       reg_data |= IXGBE_FCTRL_BAM | IXGBE_FCTRL_SBP | IXGBE_FCTRL_MPE;
-       IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, reg_data);
-
-       reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_HLREG0);
-       reg_data &= ~IXGBE_HLREG0_LPBK;
-       IXGBE_WRITE_REG(&adapter->hw, IXGBE_HLREG0, reg_data);
 
-       reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_RDRXCTL);
-#define IXGBE_RDRXCTL_RDMTS_MASK    0x00000003 /* Receive Descriptor Minimum
-                                                  Threshold Size mask */
-       reg_data &= ~IXGBE_RDRXCTL_RDMTS_MASK;
-       IXGBE_WRITE_REG(&adapter->hw, IXGBE_RDRXCTL, reg_data);
-
-       reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_MCSTCTRL);
-#define IXGBE_MCSTCTRL_MO_MASK      0x00000003 /* Multicast Offset mask */
-       reg_data &= ~IXGBE_MCSTCTRL_MO_MASK;
-       reg_data |= adapter->hw.mac.mc_filter_type;
-       IXGBE_WRITE_REG(&adapter->hw, IXGBE_MCSTCTRL, reg_data);
-
-       reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_RXDCTL(0));
-       reg_data |= IXGBE_RXDCTL_ENABLE;
-       IXGBE_WRITE_REG(&adapter->hw, IXGBE_RXDCTL(0), reg_data);
-       if (adapter->hw.mac.type == ixgbe_mac_82599EB) {
-               int j = adapter->rx_ring[0]->reg_idx;
-               u32 k;
-               for (k = 0; k < 10; k++) {
-                       if (IXGBE_READ_REG(&adapter->hw,
-                                          IXGBE_RXDCTL(j)) & IXGBE_RXDCTL_ENABLE)
-                               break;
-                       else
-                               msleep(1);
-               }
-       }
+       ixgbe_configure_rx_ring(adapter, rx_ring);
 
        rctl |= IXGBE_RXCTRL_RXEN | IXGBE_RXCTRL_DMBYPS;
        IXGBE_WRITE_REG(&adapter->hw, IXGBE_RXCTRL, rctl);
 
-       for (i = 0; i < rx_ring->count; i++) {
-               union ixgbe_adv_rx_desc *rx_desc =
-                                                IXGBE_RX_DESC_ADV(*rx_ring, i);
-               struct sk_buff *skb;
-
-               skb = alloc_skb(IXGBE_RXBUFFER_2048 + NET_IP_ALIGN, GFP_KERNEL);
-               if (!skb) {
-                       ret_val = 6;
-                       goto err_nomem;
-               }
-               skb_reserve(skb, NET_IP_ALIGN);
-               rx_ring->rx_buffer_info[i].skb = skb;
-               rx_ring->rx_buffer_info[i].dma =
-                       dma_map_single(&pdev->dev, skb->data,
-                                      IXGBE_RXBUFFER_2048, DMA_FROM_DEVICE);
-               rx_desc->read.pkt_addr =
-                               cpu_to_le64(rx_ring->rx_buffer_info[i].dma);
-               memset(skb->data, 0x00, skb->len);
-       }
-
        return 0;
 
 err_nomem:
@@ -1689,16 +1527,21 @@ static int ixgbe_setup_loopback_test(struct ixgbe_adapter *adapter)
        u32 reg_data;
 
        /* right now we only support MAC loopback in the driver */
-
-       /* Setup MAC loopback */
        reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_HLREG0);
+       /* Setup MAC loopback */
        reg_data |= IXGBE_HLREG0_LPBK;
        IXGBE_WRITE_REG(&adapter->hw, IXGBE_HLREG0, reg_data);
 
+       reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_FCTRL);
+       reg_data |= IXGBE_FCTRL_BAM | IXGBE_FCTRL_SBP | IXGBE_FCTRL_MPE;
+       IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, reg_data);
+
        reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_AUTOC);
        reg_data &= ~IXGBE_AUTOC_LMS_MASK;
        reg_data |= IXGBE_AUTOC_LMS_10G_LINK_NO_AN | IXGBE_AUTOC_FLU;
        IXGBE_WRITE_REG(&adapter->hw, IXGBE_AUTOC, reg_data);
+       IXGBE_WRITE_FLUSH(&adapter->hw);
+       msleep(10);
 
        /* Disable Atlas Tx lanes; re-enabled in reset path */
        if (hw->mac.type == ixgbe_mac_82598EB) {
@@ -1756,15 +1599,81 @@ static int ixgbe_check_lbtest_frame(struct sk_buff *skb,
        return 13;
 }
 
+static u16 ixgbe_clean_test_rings(struct ixgbe_adapter *adapter,
+                                  struct ixgbe_ring *rx_ring,
+                                  struct ixgbe_ring *tx_ring,
+                                  unsigned int size)
+{
+       union ixgbe_adv_rx_desc *rx_desc;
+       struct ixgbe_rx_buffer *rx_buffer_info;
+       struct ixgbe_tx_buffer *tx_buffer_info;
+       const int bufsz = rx_ring->rx_buf_len;
+       u32 staterr;
+       u16 rx_ntc, tx_ntc, count = 0;
+
+       /* initialize next to clean and descriptor values */
+       rx_ntc = rx_ring->next_to_clean;
+       tx_ntc = tx_ring->next_to_clean;
+       rx_desc = IXGBE_RX_DESC_ADV(rx_ring, rx_ntc);
+       staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
+
+       while (staterr & IXGBE_RXD_STAT_DD) {
+               /* check Rx buffer */
+               rx_buffer_info = &rx_ring->rx_buffer_info[rx_ntc];
+
+               /* unmap Rx buffer, will be remapped by alloc_rx_buffers */
+               dma_unmap_single(&adapter->pdev->dev,
+                                rx_buffer_info->dma,
+                                bufsz,
+                                DMA_FROM_DEVICE);
+               rx_buffer_info->dma = 0;
+
+               /* verify contents of skb */
+               if (!ixgbe_check_lbtest_frame(rx_buffer_info->skb, size))
+                       count++;
+
+               /* unmap buffer on Tx side */
+               tx_buffer_info = &tx_ring->tx_buffer_info[tx_ntc];
+               ixgbe_unmap_and_free_tx_resource(adapter, tx_buffer_info);
+
+               /* increment Rx/Tx next to clean counters */
+               rx_ntc++;
+               if (rx_ntc == rx_ring->count)
+                       rx_ntc = 0;
+               tx_ntc++;
+               if (tx_ntc == tx_ring->count)
+                       tx_ntc = 0;
+
+               /* fetch next descriptor */
+               rx_desc = IXGBE_RX_DESC_ADV(rx_ring, rx_ntc);
+               staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
+       }
+
+       /* re-map buffers to ring, store next to clean values */
+       ixgbe_alloc_rx_buffers(adapter, rx_ring, count);
+       rx_ring->next_to_clean = rx_ntc;
+       tx_ring->next_to_clean = tx_ntc;
+
+       return count;
+}
+
 static int ixgbe_run_loopback_test(struct ixgbe_adapter *adapter)
 {
        struct ixgbe_ring *tx_ring = &adapter->test_tx_ring;
        struct ixgbe_ring *rx_ring = &adapter->test_rx_ring;
-       struct pci_dev *pdev = adapter->pdev;
-       int i, j, k, l, lc, good_cnt, ret_val = 0;
-       unsigned long time;
+       int i, j, lc, good_cnt, ret_val = 0;
+       unsigned int size = 1024;
+       netdev_tx_t tx_ret_val;
+       struct sk_buff *skb;
 
-       IXGBE_WRITE_REG(&adapter->hw, IXGBE_RDT(0), rx_ring->count - 1);
+       /* allocate test skb */
+       skb = alloc_skb(size, GFP_KERNEL);
+       if (!skb)
+               return 11;
+
+       /* place data into test skb */
+       ixgbe_create_lbtest_frame(skb, size);
+       skb_put(skb, size);
 
        /*
         * Calculate the loop count based on the largest descriptor ring
@@ -1777,54 +1686,40 @@ static int ixgbe_run_loopback_test(struct ixgbe_adapter *adapter)
        else
                lc = ((rx_ring->count / 64) * 2) + 1;
 
-       k = l = 0;
        for (j = 0; j <= lc; j++) {
-               for (i = 0; i < 64; i++) {
-                       ixgbe_create_lbtest_frame(
-                                       tx_ring->tx_buffer_info[k].skb,
-                                       1024);
-                       dma_sync_single_for_device(&pdev->dev,
-                               tx_ring->tx_buffer_info[k].dma,
-                               tx_ring->tx_buffer_info[k].length,
-                               DMA_TO_DEVICE);
-                       if (unlikely(++k == tx_ring->count))
-                               k = 0;
-               }
-               IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDT(0), k);
-               msleep(200);
-               /* set the start time for the receive */
-               time = jiffies;
+               /* reset count of good packets */
                good_cnt = 0;
-               do {
-                       /* receive the sent packets */
-                       dma_sync_single_for_cpu(&pdev->dev,
-                                       rx_ring->rx_buffer_info[l].dma,
-                                       IXGBE_RXBUFFER_2048,
-                                       DMA_FROM_DEVICE);
-                       ret_val = ixgbe_check_lbtest_frame(
-                                       rx_ring->rx_buffer_info[l].skb, 1024);
-                       if (!ret_val)
+
+               /* place 64 packets on the transmit queue*/
+               for (i = 0; i < 64; i++) {
+                       skb_get(skb);
+                       tx_ret_val = ixgbe_xmit_frame_ring(skb,
+                                                          adapter->netdev,
+                                                          adapter,
+                                                          tx_ring);
+                       if (tx_ret_val == NETDEV_TX_OK)
                                good_cnt++;
-                       if (++l == rx_ring->count)
-                               l = 0;
-                       /*
-                        * time + 20 msecs (200 msecs on 2.4) is more than
-                        * enough time to complete the receives, if it's
-                        * exceeded, break and error off
-                        */
-               } while (good_cnt < 64 && jiffies < (time + 20));
+               }
+
                if (good_cnt != 64) {
-                       /* ret_val is the same as mis-compare */
-                       ret_val = 13;
+                       ret_val = 12;
                        break;
                }
-               if (jiffies >= (time + 20)) {
-                       /* Error code for time out error */
-                       ret_val = 14;
+
+               /* allow 200 milliseconds for packets to go from Tx to Rx */
+               msleep(200);
+
+               good_cnt = ixgbe_clean_test_rings(adapter, rx_ring,
+                                                 tx_ring, size);
+               if (good_cnt != 64) {
+                       ret_val = 13;
                        break;
                }
        }
 
+       /* free the original skb */
+       kfree_skb(skb);
+
        return ret_val;
 }
 
index 072327c5e41ab287e4ad9598145f6d3f60283f12..2f1de8b90f9eb42a1b82d9a16409893cc1592902 100644 (file)
@@ -304,12 +304,13 @@ int ixgbe_fcoe_ddp(struct ixgbe_adapter *adapter,
        if (!ixgbe_rx_is_fcoe(rx_desc))
                goto ddp_out;
 
-       skb->ip_summed = CHECKSUM_UNNECESSARY;
        sterr = le32_to_cpu(rx_desc->wb.upper.status_error);
        fcerr = (sterr & IXGBE_RXDADV_ERR_FCERR);
        fceofe = (sterr & IXGBE_RXDADV_ERR_FCEOFE);
        if (fcerr == IXGBE_FCERR_BADCRC)
-               skb->ip_summed = CHECKSUM_NONE;
+               skb_checksum_none_assert(skb);
+       else
+               skb->ip_summed = CHECKSUM_UNNECESSARY;
 
        if (eth_hdr(skb)->h_proto == htons(ETH_P_8021Q))
                fh = (struct fc_frame_header *)(skb->data +
@@ -471,7 +472,7 @@ int ixgbe_fso(struct ixgbe_adapter *adapter,
 
        /* write context desc */
        i = tx_ring->next_to_use;
-       context_desc = IXGBE_TX_CTXTDESC_ADV(*tx_ring, i);
+       context_desc = IXGBE_TX_CTXTDESC_ADV(tx_ring, i);
        context_desc->vlan_macip_lens   = cpu_to_le32(vlan_macip_lens);
        context_desc->seqnum_seed       = cpu_to_le32(fcoe_sof_eof);
        context_desc->type_tucmd_mlhl   = cpu_to_le32(type_tucmd);
index e32af434cc9dd4903f41f2d53d438ff950e9fb82..d03eef96c0ba22831b9610edce8fbe28c636555b 100644 (file)
@@ -50,7 +50,7 @@
 
 char ixgbe_driver_name[] = "ixgbe";
 static const char ixgbe_driver_string[] =
-                              "Intel(R) 10 Gigabit PCI Express Network Driver";
+                             "Intel(R) 10 Gigabit PCI Express Network Driver";
 
 #define DRV_VERSION "2.0.84-k2"
 const char ixgbe_driver_version[] = DRV_VERSION;
@@ -120,7 +120,7 @@ MODULE_DEVICE_TABLE(pci, ixgbe_pci_tbl);
 
 #ifdef CONFIG_IXGBE_DCA
 static int ixgbe_notify_dca(struct notifier_block *, unsigned long event,
-                            void *p);
+                           void *p);
 static struct notifier_block dca_notifier = {
        .notifier_call = ixgbe_notify_dca,
        .next          = NULL,
@@ -131,8 +131,8 @@ static struct notifier_block dca_notifier = {
 #ifdef CONFIG_PCI_IOV
 static unsigned int max_vfs;
 module_param(max_vfs, uint, 0);
-MODULE_PARM_DESC(max_vfs, "Maximum number of virtual functions to allocate "
-                 "per physical function");
+MODULE_PARM_DESC(max_vfs,
+                "Maximum number of virtual functions to allocate per physical function");
 #endif /* CONFIG_PCI_IOV */
 
 MODULE_AUTHOR("Intel Corporation, <linux.nics@intel.com>");
@@ -169,8 +169,8 @@ static inline void ixgbe_disable_sriov(struct ixgbe_adapter *adapter)
 
        /* take a breather then clean up driver data */
        msleep(100);
-       if (adapter->vfinfo)
-               kfree(adapter->vfinfo);
+
+       kfree(adapter->vfinfo);
        adapter->vfinfo = NULL;
 
        adapter->num_vfs = 0;
@@ -282,17 +282,17 @@ static void ixgbe_regdump(struct ixgbe_hw *hw, struct ixgbe_reg_info *reginfo)
                        regs[i] = IXGBE_READ_REG(hw, IXGBE_TXDCTL(i));
                break;
        default:
-               printk(KERN_INFO "%-15s %08x\n", reginfo->name,
+               pr_info("%-15s %08x\n", reginfo->name,
                        IXGBE_READ_REG(hw, reginfo->ofs));
                return;
        }
 
        for (i = 0; i < 8; i++) {
                snprintf(rname, 16, "%s[%d-%d]", reginfo->name, i*8, i*8+7);
-               printk(KERN_ERR "%-15s ", rname);
+               pr_err("%-15s", rname);
                for (j = 0; j < 8; j++)
-                       printk(KERN_CONT "%08x ", regs[i*8+j]);
-               printk(KERN_CONT "\n");
+                       pr_cont(" %08x", regs[i*8+j]);
+               pr_cont("\n");
        }
 
 }
@@ -322,18 +322,18 @@ static void ixgbe_dump(struct ixgbe_adapter *adapter)
        /* Print netdevice Info */
        if (netdev) {
                dev_info(&adapter->pdev->dev, "Net device Info\n");
-               printk(KERN_INFO "Device Name     state            "
+               pr_info("Device Name     state            "
                        "trans_start      last_rx\n");
-               printk(KERN_INFO "%-15s %016lX %016lX %016lX\n",
-               netdev->name,
-               netdev->state,
-               netdev->trans_start,
-               netdev->last_rx);
+               pr_info("%-15s %016lX %016lX %016lX\n",
+                       netdev->name,
+                       netdev->state,
+                       netdev->trans_start,
+                       netdev->last_rx);
        }
 
        /* Print Registers */
        dev_info(&adapter->pdev->dev, "Register Dump\n");
-       printk(KERN_INFO " Register Name   Value\n");
+       pr_info(" Register Name   Value\n");
        for (reginfo = (struct ixgbe_reg_info *)ixgbe_reg_info_tbl;
             reginfo->name; reginfo++) {
                ixgbe_regdump(hw, reginfo);
@@ -344,13 +344,12 @@ static void ixgbe_dump(struct ixgbe_adapter *adapter)
                goto exit;
 
        dev_info(&adapter->pdev->dev, "TX Rings Summary\n");
-       printk(KERN_INFO "Queue [NTU] [NTC] [bi(ntc)->dma  ] "
-               "leng ntw timestamp\n");
+       pr_info("Queue [NTU] [NTC] [bi(ntc)->dma  ] leng ntw timestamp\n");
        for (n = 0; n < adapter->num_tx_queues; n++) {
                tx_ring = adapter->tx_ring[n];
                tx_buffer_info =
                        &tx_ring->tx_buffer_info[tx_ring->next_to_clean];
-               printk(KERN_INFO " %5d %5X %5X %016llX %04X %3X %016llX\n",
+               pr_info(" %5d %5X %5X %016llX %04X %3X %016llX\n",
                           n, tx_ring->next_to_use, tx_ring->next_to_clean,
                           (u64)tx_buffer_info->dma,
                           tx_buffer_info->length,
@@ -377,18 +376,18 @@ static void ixgbe_dump(struct ixgbe_adapter *adapter)
 
        for (n = 0; n < adapter->num_tx_queues; n++) {
                tx_ring = adapter->tx_ring[n];
-               printk(KERN_INFO "------------------------------------\n");
-               printk(KERN_INFO "TX QUEUE INDEX = %d\n", tx_ring->queue_index);
-               printk(KERN_INFO "------------------------------------\n");
-               printk(KERN_INFO "T [desc]     [address 63:0  ] "
+               pr_info("------------------------------------\n");
+               pr_info("TX QUEUE INDEX = %d\n", tx_ring->queue_index);
+               pr_info("------------------------------------\n");
+               pr_info("T [desc]     [address 63:0  ] "
                        "[PlPOIdStDDt Ln] [bi->dma       ] "
                        "leng  ntw timestamp        bi->skb\n");
 
                for (i = 0; tx_ring->desc && (i < tx_ring->count); i++) {
-                       tx_desc = IXGBE_TX_DESC_ADV(*tx_ring, i);
+                       tx_desc = IXGBE_TX_DESC_ADV(tx_ring, i);
                        tx_buffer_info = &tx_ring->tx_buffer_info[i];
                        u0 = (struct my_u0 *)tx_desc;
-                       printk(KERN_INFO "T [0x%03X]    %016llX %016llX %016llX"
+                       pr_info("T [0x%03X]    %016llX %016llX %016llX"
                                " %04X  %3X %016llX %p", i,
                                le64_to_cpu(u0->a),
                                le64_to_cpu(u0->b),
@@ -399,13 +398,13 @@ static void ixgbe_dump(struct ixgbe_adapter *adapter)
                                tx_buffer_info->skb);
                        if (i == tx_ring->next_to_use &&
                                i == tx_ring->next_to_clean)
-                               printk(KERN_CONT " NTC/U\n");
+                               pr_cont(" NTC/U\n");
                        else if (i == tx_ring->next_to_use)
-                               printk(KERN_CONT " NTU\n");
+                               pr_cont(" NTU\n");
                        else if (i == tx_ring->next_to_clean)
-                               printk(KERN_CONT " NTC\n");
+                               pr_cont(" NTC\n");
                        else
-                               printk(KERN_CONT "\n");
+                               pr_cont("\n");
 
                        if (netif_msg_pktdata(adapter) &&
                                tx_buffer_info->dma != 0)
@@ -419,11 +418,11 @@ static void ixgbe_dump(struct ixgbe_adapter *adapter)
        /* Print RX Rings Summary */
 rx_ring_summary:
        dev_info(&adapter->pdev->dev, "RX Rings Summary\n");
-       printk(KERN_INFO "Queue [NTU] [NTC]\n");
+       pr_info("Queue [NTU] [NTC]\n");
        for (n = 0; n < adapter->num_rx_queues; n++) {
                rx_ring = adapter->rx_ring[n];
-               printk(KERN_INFO "%5d %5X %5X\n", n,
-                          rx_ring->next_to_use, rx_ring->next_to_clean);
+               pr_info("%5d %5X %5X\n",
+                       n, rx_ring->next_to_use, rx_ring->next_to_clean);
        }
 
        /* Print RX Rings */
@@ -454,30 +453,30 @@ rx_ring_summary:
         */
        for (n = 0; n < adapter->num_rx_queues; n++) {
                rx_ring = adapter->rx_ring[n];
-               printk(KERN_INFO "------------------------------------\n");
-               printk(KERN_INFO "RX QUEUE INDEX = %d\n", rx_ring->queue_index);
-               printk(KERN_INFO "------------------------------------\n");
-               printk(KERN_INFO "R  [desc]      [ PktBuf     A0] "
+               pr_info("------------------------------------\n");
+               pr_info("RX QUEUE INDEX = %d\n", rx_ring->queue_index);
+               pr_info("------------------------------------\n");
+               pr_info("R  [desc]      [ PktBuf     A0] "
                        "[  HeadBuf   DD] [bi->dma       ] [bi->skb] "
                        "<-- Adv Rx Read format\n");
-               printk(KERN_INFO "RWB[desc]      [PcsmIpSHl PtRs] "
+               pr_info("RWB[desc]      [PcsmIpSHl PtRs] "
                        "[vl er S cks ln] ---------------- [bi->skb] "
                        "<-- Adv Rx Write-Back format\n");
 
                for (i = 0; i < rx_ring->count; i++) {
                        rx_buffer_info = &rx_ring->rx_buffer_info[i];
-                       rx_desc = IXGBE_RX_DESC_ADV(*rx_ring, i);
+                       rx_desc = IXGBE_RX_DESC_ADV(rx_ring, i);
                        u0 = (struct my_u0 *)rx_desc;
                        staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
                        if (staterr & IXGBE_RXD_STAT_DD) {
                                /* Descriptor Done */
-                               printk(KERN_INFO "RWB[0x%03X]     %016llX "
+                               pr_info("RWB[0x%03X]     %016llX "
                                        "%016llX ---------------- %p", i,
                                        le64_to_cpu(u0->a),
                                        le64_to_cpu(u0->b),
                                        rx_buffer_info->skb);
                        } else {
-                               printk(KERN_INFO "R  [0x%03X]     %016llX "
+                               pr_info("R  [0x%03X]     %016llX "
                                        "%016llX %016llX %p", i,
                                        le64_to_cpu(u0->a),
                                        le64_to_cpu(u0->b),
@@ -503,11 +502,11 @@ rx_ring_summary:
                        }
 
                        if (i == rx_ring->next_to_use)
-                               printk(KERN_CONT " NTU\n");
+                               pr_cont(" NTU\n");
                        else if (i == rx_ring->next_to_clean)
-                               printk(KERN_CONT " NTC\n");
+                               pr_cont(" NTC\n");
                        else
-                               printk(KERN_CONT "\n");
+                               pr_cont("\n");
 
                }
        }
@@ -523,7 +522,7 @@ static void ixgbe_release_hw_control(struct ixgbe_adapter *adapter)
        /* Let firmware take over control of h/w */
        ctrl_ext = IXGBE_READ_REG(&adapter->hw, IXGBE_CTRL_EXT);
        IXGBE_WRITE_REG(&adapter->hw, IXGBE_CTRL_EXT,
-                       ctrl_ext & ~IXGBE_CTRL_EXT_DRV_LOAD);
+                       ctrl_ext & ~IXGBE_CTRL_EXT_DRV_LOAD);
 }
 
 static void ixgbe_get_hw_control(struct ixgbe_adapter *adapter)
@@ -533,7 +532,7 @@ static void ixgbe_get_hw_control(struct ixgbe_adapter *adapter)
        /* Let firmware know the driver has taken over */
        ctrl_ext = IXGBE_READ_REG(&adapter->hw, IXGBE_CTRL_EXT);
        IXGBE_WRITE_REG(&adapter->hw, IXGBE_CTRL_EXT,
-                       ctrl_ext | IXGBE_CTRL_EXT_DRV_LOAD);
+                       ctrl_ext | IXGBE_CTRL_EXT_DRV_LOAD);
 }
 
 /*
@@ -545,7 +544,7 @@ static void ixgbe_get_hw_control(struct ixgbe_adapter *adapter)
  *
  */
 static void ixgbe_set_ivar(struct ixgbe_adapter *adapter, s8 direction,
-                          u8 queue, u8 msix_vector)
+                          u8 queue, u8 msix_vector)
 {
        u32 ivar, index;
        struct ixgbe_hw *hw = &adapter->hw;
@@ -586,7 +585,7 @@ static void ixgbe_set_ivar(struct ixgbe_adapter *adapter, s8 direction,
 }
 
 static inline void ixgbe_irq_rearm_queues(struct ixgbe_adapter *adapter,
-                                          u64 qmask)
+                                         u64 qmask)
 {
        u32 mask;
 
@@ -601,9 +600,9 @@ static inline void ixgbe_irq_rearm_queues(struct ixgbe_adapter *adapter,
        }
 }
 
-static void ixgbe_unmap_and_free_tx_resource(struct ixgbe_adapter *adapter,
-                                             struct ixgbe_tx_buffer
-                                             *tx_buffer_info)
+void ixgbe_unmap_and_free_tx_resource(struct ixgbe_adapter *adapter,
+                                     struct ixgbe_tx_buffer
+                                     *tx_buffer_info)
 {
        if (tx_buffer_info->dma) {
                if (tx_buffer_info->mapped_as_page)
@@ -637,7 +636,7 @@ static void ixgbe_unmap_and_free_tx_resource(struct ixgbe_adapter *adapter,
  * Returns : true if in xon state (currently not paused)
  */
 static inline bool ixgbe_tx_xon_state(struct ixgbe_adapter *adapter,
-                                      struct ixgbe_ring *tx_ring)
+                                     struct ixgbe_ring *tx_ring)
 {
        u32 txoff = IXGBE_TFCS_TXOFF;
 
@@ -682,8 +681,8 @@ static inline bool ixgbe_tx_xon_state(struct ixgbe_adapter *adapter,
 }
 
 static inline bool ixgbe_check_tx_hang(struct ixgbe_adapter *adapter,
-                                       struct ixgbe_ring *tx_ring,
-                                       unsigned int eop)
+                                      struct ixgbe_ring *tx_ring,
+                                      unsigned int eop)
 {
        struct ixgbe_hw *hw = &adapter->hw;
 
@@ -695,7 +694,7 @@ static inline bool ixgbe_check_tx_hang(struct ixgbe_adapter *adapter,
            ixgbe_tx_xon_state(adapter, tx_ring)) {
                /* detected Tx unit hang */
                union ixgbe_adv_tx_desc *tx_desc;
-               tx_desc = IXGBE_TX_DESC_ADV(*tx_ring, eop);
+               tx_desc = IXGBE_TX_DESC_ADV(tx_ring, eop);
                e_err(drv, "Detected Tx Unit Hang\n"
                      "  Tx Queue             <%d>\n"
                      "  TDH, TDT             <%x>, <%x>\n"
@@ -732,7 +731,7 @@ static void ixgbe_tx_timeout(struct net_device *netdev);
  * @tx_ring: tx ring to clean
  **/
 static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
-                               struct ixgbe_ring *tx_ring)
+                              struct ixgbe_ring *tx_ring)
 {
        struct ixgbe_adapter *adapter = q_vector->adapter;
        struct net_device *netdev = adapter->netdev;
@@ -743,7 +742,7 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
 
        i = tx_ring->next_to_clean;
        eop = tx_ring->tx_buffer_info[i].next_to_watch;
-       eop_desc = IXGBE_TX_DESC_ADV(*tx_ring, eop);
+       eop_desc = IXGBE_TX_DESC_ADV(tx_ring, eop);
 
        while ((eop_desc->wb.status & cpu_to_le32(IXGBE_TXD_STAT_DD)) &&
               (count < tx_ring->work_limit)) {
@@ -751,7 +750,7 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
                rmb(); /* read buffer_info after eop_desc */
                for ( ; !cleaned; count++) {
                        struct sk_buff *skb;
-                       tx_desc = IXGBE_TX_DESC_ADV(*tx_ring, i);
+                       tx_desc = IXGBE_TX_DESC_ADV(tx_ring, i);
                        tx_buffer_info = &tx_ring->tx_buffer_info[i];
                        cleaned = (i == eop);
                        skb = tx_buffer_info->skb;
@@ -781,7 +780,7 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
                        }
 
                        ixgbe_unmap_and_free_tx_resource(adapter,
-                                                        tx_buffer_info);
+                                                        tx_buffer_info);
 
                        tx_desc->wb.status = 0;
 
@@ -791,14 +790,14 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
                }
 
                eop = tx_ring->tx_buffer_info[i].next_to_watch;
-               eop_desc = IXGBE_TX_DESC_ADV(*tx_ring, eop);
+               eop_desc = IXGBE_TX_DESC_ADV(tx_ring, eop);
        }
 
        tx_ring->next_to_clean = i;
 
 #define TX_WAKE_THRESHOLD (DESC_NEEDED * 2)
        if (unlikely(count && netif_carrier_ok(netdev) &&
-                    (IXGBE_DESC_UNUSED(tx_ring) >= TX_WAKE_THRESHOLD))) {
+                    (IXGBE_DESC_UNUSED(tx_ring) >= TX_WAKE_THRESHOLD))) {
                /* Make sure that anybody stopping the queue after this
                 * sees the new next_to_clean.
                 */
@@ -832,7 +831,7 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
 
 #ifdef CONFIG_IXGBE_DCA
 static void ixgbe_update_rx_dca(struct ixgbe_adapter *adapter,
-                                struct ixgbe_ring *rx_ring)
+                               struct ixgbe_ring *rx_ring)
 {
        u32 rxctrl;
        int cpu = get_cpu();
@@ -846,13 +845,13 @@ static void ixgbe_update_rx_dca(struct ixgbe_adapter *adapter,
                } else if (adapter->hw.mac.type == ixgbe_mac_82599EB) {
                        rxctrl &= ~IXGBE_DCA_RXCTRL_CPUID_MASK_82599;
                        rxctrl |= (dca3_get_tag(&adapter->pdev->dev, cpu) <<
-                                  IXGBE_DCA_RXCTRL_CPUID_SHIFT_82599);
+                                  IXGBE_DCA_RXCTRL_CPUID_SHIFT_82599);
                }
                rxctrl |= IXGBE_DCA_RXCTRL_DESC_DCA_EN;
                rxctrl |= IXGBE_DCA_RXCTRL_HEAD_DCA_EN;
                rxctrl &= ~(IXGBE_DCA_RXCTRL_DESC_RRO_EN);
                rxctrl &= ~(IXGBE_DCA_RXCTRL_DESC_WRO_EN |
-                           IXGBE_DCA_RXCTRL_DESC_HSRO_EN);
+                           IXGBE_DCA_RXCTRL_DESC_HSRO_EN);
                IXGBE_WRITE_REG(&adapter->hw, IXGBE_DCA_RXCTRL(q), rxctrl);
                rx_ring->cpu = cpu;
        }
@@ -860,7 +859,7 @@ static void ixgbe_update_rx_dca(struct ixgbe_adapter *adapter,
 }
 
 static void ixgbe_update_tx_dca(struct ixgbe_adapter *adapter,
-                                struct ixgbe_ring *tx_ring)
+                               struct ixgbe_ring *tx_ring)
 {
        u32 txctrl;
        int cpu = get_cpu();
@@ -878,7 +877,7 @@ static void ixgbe_update_tx_dca(struct ixgbe_adapter *adapter,
                        txctrl = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL_82599(q));
                        txctrl &= ~IXGBE_DCA_TXCTRL_CPUID_MASK_82599;
                        txctrl |= (dca3_get_tag(&adapter->pdev->dev, cpu) <<
-                                 IXGBE_DCA_TXCTRL_CPUID_SHIFT_82599);
+                                 IXGBE_DCA_TXCTRL_CPUID_SHIFT_82599);
                        txctrl |= IXGBE_DCA_TXCTRL_DESC_DCA_EN;
                        IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL_82599(q), txctrl);
                }
@@ -946,16 +945,15 @@ static int __ixgbe_notify_dca(struct device *dev, void *data)
  * @rx_desc: rx descriptor
  **/
 static void ixgbe_receive_skb(struct ixgbe_q_vector *q_vector,
-                              struct sk_buff *skb, u8 status,
-                              struct ixgbe_ring *ring,
-                              union ixgbe_adv_rx_desc *rx_desc)
+                             struct sk_buff *skb, u8 status,
+                             struct ixgbe_ring *ring,
+                             union ixgbe_adv_rx_desc *rx_desc)
 {
        struct ixgbe_adapter *adapter = q_vector->adapter;
        struct napi_struct *napi = &q_vector->napi;
        bool is_vlan = (status & IXGBE_RXD_STAT_VP);
        u16 tag = le16_to_cpu(rx_desc->wb.upper.vlan);
 
-       skb_record_rx_queue(skb, ring->queue_index);
        if (!(adapter->flags & IXGBE_FLAG_IN_NETPOLL)) {
                if (adapter->vlgrp && is_vlan && (tag & VLAN_VID_MASK))
                        vlan_gro_receive(napi, adapter->vlgrp, tag, skb);
@@ -981,7 +979,7 @@ static inline void ixgbe_rx_checksum(struct ixgbe_adapter *adapter,
 {
        u32 status_err = le32_to_cpu(rx_desc->wb.upper.status_error);
 
-       skb->ip_summed = CHECKSUM_NONE;
+       skb_checksum_none_assert(skb);
 
        /* Rx csum disabled */
        if (!(adapter->flags & IXGBE_FLAG_RX_CSUM_ENABLED))
@@ -1017,7 +1015,7 @@ static inline void ixgbe_rx_checksum(struct ixgbe_adapter *adapter,
 }
 
 static inline void ixgbe_release_rx_desc(struct ixgbe_hw *hw,
-                                         struct ixgbe_ring *rx_ring, u32 val)
+                                        struct ixgbe_ring *rx_ring, u32 val)
 {
        /*
         * Force memory writes to complete before letting h/w
@@ -1033,25 +1031,27 @@ static inline void ixgbe_release_rx_desc(struct ixgbe_hw *hw,
  * ixgbe_alloc_rx_buffers - Replace used receive buffers; packet split
  * @adapter: address of board private structure
  **/
-static void ixgbe_alloc_rx_buffers(struct ixgbe_adapter *adapter,
-                                   struct ixgbe_ring *rx_ring,
-                                   int cleaned_count)
+void ixgbe_alloc_rx_buffers(struct ixgbe_adapter *adapter,
+                           struct ixgbe_ring *rx_ring,
+                           int cleaned_count)
 {
+       struct net_device *netdev = adapter->netdev;
        struct pci_dev *pdev = adapter->pdev;
        union ixgbe_adv_rx_desc *rx_desc;
        struct ixgbe_rx_buffer *bi;
        unsigned int i;
+       unsigned int bufsz = rx_ring->rx_buf_len;
 
        i = rx_ring->next_to_use;
        bi = &rx_ring->rx_buffer_info[i];
 
        while (cleaned_count--) {
-               rx_desc = IXGBE_RX_DESC_ADV(*rx_ring, i);
+               rx_desc = IXGBE_RX_DESC_ADV(rx_ring, i);
 
                if (!bi->page_dma &&
                    (rx_ring->flags & IXGBE_RING_RX_PS_ENABLED)) {
                        if (!bi->page) {
-                               bi->page = alloc_page(GFP_ATOMIC);
+                               bi->page = netdev_alloc_page(netdev);
                                if (!bi->page) {
                                        adapter->alloc_rx_page_failed++;
                                        goto no_buffers;
@@ -1063,29 +1063,28 @@ static void ixgbe_alloc_rx_buffers(struct ixgbe_adapter *adapter,
                        }
 
                        bi->page_dma = dma_map_page(&pdev->dev, bi->page,
-                                                   bi->page_offset,
-                                                   (PAGE_SIZE / 2),
+                                                   bi->page_offset,
+                                                   (PAGE_SIZE / 2),
                                                    DMA_FROM_DEVICE);
                }
 
                if (!bi->skb) {
-                       struct sk_buff *skb;
-                       /* netdev_alloc_skb reserves 32 bytes up front!! */
-                       uint bufsz = rx_ring->rx_buf_len + SMP_CACHE_BYTES;
-                       skb = netdev_alloc_skb(adapter->netdev, bufsz);
+                       struct sk_buff *skb = netdev_alloc_skb_ip_align(netdev,
+                                                                       bufsz);
+                       bi->skb = skb;
 
                        if (!skb) {
                                adapter->alloc_rx_buff_failed++;
                                goto no_buffers;
                        }
+                       /* initialize queue mapping */
+                       skb_record_rx_queue(skb, rx_ring->queue_index);
+               }
 
-                       /* advance the data pointer to the next cache line */
-                       skb_reserve(skb, (PTR_ALIGN(skb->data, SMP_CACHE_BYTES)
-                                         - skb->data));
-
-                       bi->skb = skb;
-                       bi->dma = dma_map_single(&pdev->dev, skb->data,
-                                                rx_ring->rx_buf_len,
+               if (!bi->dma) {
+                       bi->dma = dma_map_single(&pdev->dev,
+                                                bi->skb->data,
+                                                rx_ring->rx_buf_len,
                                                 DMA_FROM_DEVICE);
                }
                /* Refresh the desc even if buffer_addrs didn't change because
@@ -1095,6 +1094,7 @@ static void ixgbe_alloc_rx_buffers(struct ixgbe_adapter *adapter,
                        rx_desc->read.hdr_addr = cpu_to_le64(bi->dma);
                } else {
                        rx_desc->read.pkt_addr = cpu_to_le64(bi->dma);
+                       rx_desc->read.hdr_addr = 0;
                }
 
                i++;
@@ -1126,8 +1126,8 @@ static inline u16 ixgbe_get_pkt_info(union ixgbe_adv_rx_desc *rx_desc)
 static inline u32 ixgbe_get_rsc_count(union ixgbe_adv_rx_desc *rx_desc)
 {
        return (le32_to_cpu(rx_desc->wb.lower.lo_dword.data) &
-               IXGBE_RXDADV_RSCCNT_MASK) >>
-               IXGBE_RXDADV_RSCCNT_SHIFT;
+               IXGBE_RXDADV_RSCCNT_MASK) >>
+               IXGBE_RXDADV_RSCCNT_SHIFT;
 }
 
 /**
@@ -1140,7 +1140,7 @@ static inline u32 ixgbe_get_rsc_count(union ixgbe_adv_rx_desc *rx_desc)
  * turns it into the frag list owner.
  **/
 static inline struct sk_buff *ixgbe_transform_rsc_queue(struct sk_buff *skb,
-                                                        u64 *count)
+                                                       u64 *count)
 {
        unsigned int frag_list_size = 0;
 
@@ -1168,8 +1168,8 @@ struct ixgbe_rsc_cb {
 #define IXGBE_RSC_CB(skb) ((struct ixgbe_rsc_cb *)(skb)->cb)
 
 static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
-                               struct ixgbe_ring *rx_ring,
-                               int *work_done, int work_to_do)
+                              struct ixgbe_ring *rx_ring,
+                              int *work_done, int work_to_do)
 {
        struct ixgbe_adapter *adapter = q_vector->adapter;
        struct net_device *netdev = adapter->netdev;
@@ -1188,7 +1188,7 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
 #endif /* IXGBE_FCOE */
 
        i = rx_ring->next_to_clean;
-       rx_desc = IXGBE_RX_DESC_ADV(*rx_ring, i);
+       rx_desc = IXGBE_RX_DESC_ADV(rx_ring, i);
        staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
        rx_buffer_info = &rx_ring->rx_buffer_info[i];
 
@@ -1231,9 +1231,9 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
                                IXGBE_RSC_CB(skb)->dma = rx_buffer_info->dma;
                        } else {
                                dma_unmap_single(&pdev->dev,
-                                                rx_buffer_info->dma,
-                                                rx_ring->rx_buf_len,
-                                                DMA_FROM_DEVICE);
+                                                rx_buffer_info->dma,
+                                                rx_ring->rx_buf_len,
+                                                DMA_FROM_DEVICE);
                        }
                        rx_buffer_info->dma = 0;
                        skb_put(skb, len);
@@ -1244,9 +1244,9 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
                                       PAGE_SIZE / 2, DMA_FROM_DEVICE);
                        rx_buffer_info->page_dma = 0;
                        skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags,
-                                          rx_buffer_info->page,
-                                          rx_buffer_info->page_offset,
-                                          upper_len);
+                                          rx_buffer_info->page,
+                                          rx_buffer_info->page_offset,
+                                          upper_len);
 
                        if ((rx_ring->rx_buf_len > (PAGE_SIZE / 2)) ||
                            (page_count(rx_buffer_info->page) != 1))
@@ -1263,7 +1263,7 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
                if (i == rx_ring->count)
                        i = 0;
 
-               next_rxd = IXGBE_RX_DESC_ADV(*rx_ring, i);
+               next_rxd = IXGBE_RX_DESC_ADV(rx_ring, i);
                prefetch(next_rxd);
                cleaned_count++;
 
@@ -1280,18 +1280,20 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
 
                if (staterr & IXGBE_RXD_STAT_EOP) {
                        if (skb->prev)
-                               skb = ixgbe_transform_rsc_queue(skb, &(rx_ring->rsc_count));
+                               skb = ixgbe_transform_rsc_queue(skb,
+                                                               &(rx_ring->rsc_count));
                        if (adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED) {
                                if (IXGBE_RSC_CB(skb)->delay_unmap) {
                                        dma_unmap_single(&pdev->dev,
                                                         IXGBE_RSC_CB(skb)->dma,
-                                                        rx_ring->rx_buf_len,
+                                                        rx_ring->rx_buf_len,
                                                         DMA_FROM_DEVICE);
                                        IXGBE_RSC_CB(skb)->dma = 0;
                                        IXGBE_RSC_CB(skb)->delay_unmap = false;
                                }
                                if (rx_ring->flags & IXGBE_RING_RX_PS_ENABLED)
-                                       rx_ring->rsc_count += skb_shinfo(skb)->nr_frags;
+                                       rx_ring->rsc_count +=
+                                               skb_shinfo(skb)->nr_frags;
                                else
                                        rx_ring->rsc_count++;
                                rx_ring->rsc_flush++;
@@ -1403,24 +1405,24 @@ static void ixgbe_configure_msix(struct ixgbe_adapter *adapter)
                q_vector = adapter->q_vector[v_idx];
                /* XXX for_each_set_bit(...) */
                r_idx = find_first_bit(q_vector->rxr_idx,
-                                      adapter->num_rx_queues);
+                                      adapter->num_rx_queues);
 
                for (i = 0; i < q_vector->rxr_count; i++) {
                        j = adapter->rx_ring[r_idx]->reg_idx;
                        ixgbe_set_ivar(adapter, 0, j, v_idx);
                        r_idx = find_next_bit(q_vector->rxr_idx,
-                                             adapter->num_rx_queues,
-                                             r_idx + 1);
+                                             adapter->num_rx_queues,
+                                             r_idx + 1);
                }
                r_idx = find_first_bit(q_vector->txr_idx,
-                                      adapter->num_tx_queues);
+                                      adapter->num_tx_queues);
 
                for (i = 0; i < q_vector->txr_count; i++) {
                        j = adapter->tx_ring[r_idx]->reg_idx;
                        ixgbe_set_ivar(adapter, 1, j, v_idx);
                        r_idx = find_next_bit(q_vector->txr_idx,
-                                             adapter->num_tx_queues,
-                                             r_idx + 1);
+                                             adapter->num_tx_queues,
+                                             r_idx + 1);
                }
 
                if (q_vector->txr_count && !q_vector->rxr_count)
@@ -1435,7 +1437,7 @@ static void ixgbe_configure_msix(struct ixgbe_adapter *adapter)
 
        if (adapter->hw.mac.type == ixgbe_mac_82598EB)
                ixgbe_set_ivar(adapter, -1, IXGBE_IVAR_OTHER_CAUSES_INDEX,
-                              v_idx);
+                              v_idx);
        else if (adapter->hw.mac.type == ixgbe_mac_82599EB)
                ixgbe_set_ivar(adapter, -1, 1, v_idx);
        IXGBE_WRITE_REG(&adapter->hw, IXGBE_EITR(v_idx), 1950);
@@ -1477,8 +1479,8 @@ enum latency_range {
  *      parameter (see ixgbe_param.c)
  **/
 static u8 ixgbe_update_itr(struct ixgbe_adapter *adapter,
-                           u32 eitr, u8 itr_setting,
-                           int packets, int bytes)
+                          u32 eitr, u8 itr_setting,
+                          int packets, int bytes)
 {
        unsigned int retval = itr_setting;
        u32 timepassed_us;
@@ -1567,30 +1569,30 @@ static void ixgbe_set_itr_msix(struct ixgbe_q_vector *q_vector)
        for (i = 0; i < q_vector->txr_count; i++) {
                tx_ring = adapter->tx_ring[r_idx];
                ret_itr = ixgbe_update_itr(adapter, q_vector->eitr,
-                                          q_vector->tx_itr,
-                                          tx_ring->total_packets,
-                                          tx_ring->total_bytes);
+                                          q_vector->tx_itr,
+                                          tx_ring->total_packets,
+                                          tx_ring->total_bytes);
                /* if the result for this queue would decrease interrupt
                 * rate for this vector then use that result */
                q_vector->tx_itr = ((q_vector->tx_itr > ret_itr) ?
-                                   q_vector->tx_itr - 1 : ret_itr);
+                                   q_vector->tx_itr - 1 : ret_itr);
                r_idx = find_next_bit(q_vector->txr_idx, adapter->num_tx_queues,
-                                     r_idx + 1);
+                                     r_idx + 1);
        }
 
        r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues);
        for (i = 0; i < q_vector->rxr_count; i++) {
                rx_ring = adapter->rx_ring[r_idx];
                ret_itr = ixgbe_update_itr(adapter, q_vector->eitr,
-                                          q_vector->rx_itr,
-                                          rx_ring->total_packets,
-                                          rx_ring->total_bytes);
+                                          q_vector->rx_itr,
+                                          rx_ring->total_packets,
+                                          rx_ring->total_bytes);
                /* if the result for this queue would decrease interrupt
                 * rate for this vector then use that result */
                q_vector->rx_itr = ((q_vector->rx_itr > ret_itr) ?
-                                   q_vector->rx_itr - 1 : ret_itr);
+                                   q_vector->rx_itr - 1 : ret_itr);
                r_idx = find_next_bit(q_vector->rxr_idx, adapter->num_rx_queues,
-                                     r_idx + 1);
+                                     r_idx + 1);
        }
 
        current_itr = max(q_vector->rx_itr, q_vector->tx_itr);
@@ -1627,39 +1629,40 @@ static void ixgbe_set_itr_msix(struct ixgbe_q_vector *q_vector)
 static void ixgbe_check_overtemp_task(struct work_struct *work)
 {
        struct ixgbe_adapter *adapter = container_of(work,
-                                                    struct ixgbe_adapter,
-                                                    check_overtemp_task);
+                                                    struct ixgbe_adapter,
+                                                    check_overtemp_task);
        struct ixgbe_hw *hw = &adapter->hw;
        u32 eicr = adapter->interrupt_event;
 
-       if (adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE) {
-               switch (hw->device_id) {
-               case IXGBE_DEV_ID_82599_T3_LOM: {
-                       u32 autoneg;
-                       bool link_up = false;
+       if (!(adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE))
+               return;
+
+       switch (hw->device_id) {
+       case IXGBE_DEV_ID_82599_T3_LOM: {
+               u32 autoneg;
+               bool link_up = false;
 
-                       if (hw->mac.ops.check_link)
-                               hw->mac.ops.check_link(hw, &autoneg, &link_up, false);
+               if (hw->mac.ops.check_link)
+                       hw->mac.ops.check_link(hw, &autoneg, &link_up, false);
 
-                       if (((eicr & IXGBE_EICR_GPI_SDP0) && (!link_up)) ||
-                           (eicr & IXGBE_EICR_LSC))
-                               /* Check if this is due to overtemp */
-                               if (hw->phy.ops.check_overtemp(hw) == IXGBE_ERR_OVERTEMP)
-                                       break;
-                       }
+               if (((eicr & IXGBE_EICR_GPI_SDP0) && (!link_up)) ||
+                   (eicr & IXGBE_EICR_LSC))
+                       /* Check if this is due to overtemp */
+                       if (hw->phy.ops.check_overtemp(hw) == IXGBE_ERR_OVERTEMP)
+                               break;
+               return;
+       }
+       default:
+               if (!(eicr & IXGBE_EICR_GPI_SDP0))
                        return;
-               default:
-                       if (!(eicr & IXGBE_EICR_GPI_SDP0))
-                               return;
-                       break;
-               }
-               e_crit(drv, "Network adapter has been stopped because it has "
-                      "over heated. Restart the computer. If the problem "
-                      "persists, power off the system and replace the "
-                      "adapter\n");
-               /* write to clear the interrupt */
-               IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP0);
+               break;
        }
+       e_crit(drv,
+              "Network adapter has been stopped because it has over heated. "
+              "Restart the computer. If the problem persists, "
+              "power off the system and replace the adapter\n");
+       /* write to clear the interrupt */
+       IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP0);
 }
 
 static void ixgbe_check_fan_failure(struct ixgbe_adapter *adapter, u32 eicr)
@@ -1746,9 +1749,9 @@ static irqreturn_t ixgbe_msix_lsc(int irq, void *data)
                        netif_tx_stop_all_queues(netdev);
                        for (i = 0; i < adapter->num_tx_queues; i++) {
                                struct ixgbe_ring *tx_ring =
-                                                           adapter->tx_ring[i];
+                                                           adapter->tx_ring[i];
                                if (test_and_clear_bit(__IXGBE_FDIR_INIT_DONE,
-                                                      &tx_ring->reinit_state))
+                                                      &tx_ring->reinit_state))
                                        schedule_work(&adapter->fdir_reinit_task);
                        }
                }
@@ -1777,7 +1780,7 @@ static inline void ixgbe_irq_enable_queues(struct ixgbe_adapter *adapter,
 }
 
 static inline void ixgbe_irq_disable_queues(struct ixgbe_adapter *adapter,
-                                            u64 qmask)
+                                           u64 qmask)
 {
        u32 mask;
 
@@ -1809,7 +1812,7 @@ static irqreturn_t ixgbe_msix_clean_tx(int irq, void *data)
                tx_ring->total_bytes = 0;
                tx_ring->total_packets = 0;
                r_idx = find_next_bit(q_vector->txr_idx, adapter->num_tx_queues,
-                                     r_idx + 1);
+                                     r_idx + 1);
        }
 
        /* EIAM disabled interrupts (on this vector) for us */
@@ -1837,7 +1840,7 @@ static irqreturn_t ixgbe_msix_clean_rx(int irq, void *data)
                rx_ring->total_bytes = 0;
                rx_ring->total_packets = 0;
                r_idx = find_next_bit(q_vector->rxr_idx, adapter->num_rx_queues,
-                                     r_idx + 1);
+                                     r_idx + 1);
        }
 
        if (!q_vector->rxr_count)
@@ -1867,7 +1870,7 @@ static irqreturn_t ixgbe_msix_clean_many(int irq, void *data)
                ring->total_bytes = 0;
                ring->total_packets = 0;
                r_idx = find_next_bit(q_vector->txr_idx, adapter->num_tx_queues,
-                                     r_idx + 1);
+                                     r_idx + 1);
        }
 
        r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues);
@@ -1876,7 +1879,7 @@ static irqreturn_t ixgbe_msix_clean_many(int irq, void *data)
                ring->total_bytes = 0;
                ring->total_packets = 0;
                r_idx = find_next_bit(q_vector->rxr_idx, adapter->num_rx_queues,
-                                     r_idx + 1);
+                                     r_idx + 1);
        }
 
        /* EIAM disabled interrupts (on this vector) for us */
@@ -1896,7 +1899,7 @@ static irqreturn_t ixgbe_msix_clean_many(int irq, void *data)
 static int ixgbe_clean_rxonly(struct napi_struct *napi, int budget)
 {
        struct ixgbe_q_vector *q_vector =
-                              container_of(napi, struct ixgbe_q_vector, napi);
+                              container_of(napi, struct ixgbe_q_vector, napi);
        struct ixgbe_adapter *adapter = q_vector->adapter;
        struct ixgbe_ring *rx_ring = NULL;
        int work_done = 0;
@@ -1918,7 +1921,7 @@ static int ixgbe_clean_rxonly(struct napi_struct *napi, int budget)
                        ixgbe_set_itr_msix(q_vector);
                if (!test_bit(__IXGBE_DOWN, &adapter->state))
                        ixgbe_irq_enable_queues(adapter,
-                                               ((u64)1 << q_vector->v_idx));
+                                               ((u64)1 << q_vector->v_idx));
        }
 
        return work_done;
@@ -1935,7 +1938,7 @@ static int ixgbe_clean_rxonly(struct napi_struct *napi, int budget)
 static int ixgbe_clean_rxtx_many(struct napi_struct *napi, int budget)
 {
        struct ixgbe_q_vector *q_vector =
-                              container_of(napi, struct ixgbe_q_vector, napi);
+                              container_of(napi, struct ixgbe_q_vector, napi);
        struct ixgbe_adapter *adapter = q_vector->adapter;
        struct ixgbe_ring *ring = NULL;
        int work_done = 0, i;
@@ -1951,7 +1954,7 @@ static int ixgbe_clean_rxtx_many(struct napi_struct *napi, int budget)
 #endif
                tx_clean_complete &= ixgbe_clean_tx_irq(q_vector, ring);
                r_idx = find_next_bit(q_vector->txr_idx, adapter->num_tx_queues,
-                                     r_idx + 1);
+                                     r_idx + 1);
        }
 
        /* attempt to distribute budget to each queue fairly, but don't allow
@@ -1967,7 +1970,7 @@ static int ixgbe_clean_rxtx_many(struct napi_struct *napi, int budget)
 #endif
                ixgbe_clean_rx_irq(q_vector, ring, &work_done, budget);
                r_idx = find_next_bit(q_vector->rxr_idx, adapter->num_rx_queues,
-                                     r_idx + 1);
+                                     r_idx + 1);
        }
 
        r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues);
@@ -1979,7 +1982,7 @@ static int ixgbe_clean_rxtx_many(struct napi_struct *napi, int budget)
                        ixgbe_set_itr_msix(q_vector);
                if (!test_bit(__IXGBE_DOWN, &adapter->state))
                        ixgbe_irq_enable_queues(adapter,
-                                               ((u64)1 << q_vector->v_idx));
+                                               ((u64)1 << q_vector->v_idx));
                return 0;
        }
 
@@ -1997,7 +2000,7 @@ static int ixgbe_clean_rxtx_many(struct napi_struct *napi, int budget)
 static int ixgbe_clean_txonly(struct napi_struct *napi, int budget)
 {
        struct ixgbe_q_vector *q_vector =
-                              container_of(napi, struct ixgbe_q_vector, napi);
+                              container_of(napi, struct ixgbe_q_vector, napi);
        struct ixgbe_adapter *adapter = q_vector->adapter;
        struct ixgbe_ring *tx_ring = NULL;
        int work_done = 0;
@@ -2019,14 +2022,15 @@ static int ixgbe_clean_txonly(struct napi_struct *napi, int budget)
                if (adapter->tx_itr_setting & 1)
                        ixgbe_set_itr_msix(q_vector);
                if (!test_bit(__IXGBE_DOWN, &adapter->state))
-                       ixgbe_irq_enable_queues(adapter, ((u64)1 << q_vector->v_idx));
+                       ixgbe_irq_enable_queues(adapter,
+                                               ((u64)1 << q_vector->v_idx));
        }
 
        return work_done;
 }
 
 static inline void map_vector_to_rxq(struct ixgbe_adapter *a, int v_idx,
-                                     int r_idx)
+                                    int r_idx)
 {
        struct ixgbe_q_vector *q_vector = a->q_vector[v_idx];
 
@@ -2035,7 +2039,7 @@ static inline void map_vector_to_rxq(struct ixgbe_adapter *a, int v_idx,
 }
 
 static inline void map_vector_to_txq(struct ixgbe_adapter *a, int v_idx,
-                                     int t_idx)
+                                    int t_idx)
 {
        struct ixgbe_q_vector *q_vector = a->q_vector[v_idx];
 
@@ -2055,7 +2059,7 @@ static inline void map_vector_to_txq(struct ixgbe_adapter *a, int v_idx,
  * mapping configurations in here.
  **/
 static int ixgbe_map_rings_to_vectors(struct ixgbe_adapter *adapter,
-                                      int vectors)
+                                     int vectors)
 {
        int v_start = 0;
        int rxr_idx = 0, txr_idx = 0;
@@ -2122,7 +2126,7 @@ static int ixgbe_request_msix_irqs(struct ixgbe_adapter *adapter)
        struct net_device *netdev = adapter->netdev;
        irqreturn_t (*handler)(int, void *);
        int i, vector, q_vectors, err;
-       int ri=0, ti=0;
+       int ri = 0, ti = 0;
 
        /* Decrement for Other and TCP Timer vectors */
        q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS;
@@ -2133,26 +2137,24 @@ static int ixgbe_request_msix_irqs(struct ixgbe_adapter *adapter)
                goto out;
 
 #define SET_HANDLER(_v) ((!(_v)->rxr_count) ? &ixgbe_msix_clean_tx : \
-                         (!(_v)->txr_count) ? &ixgbe_msix_clean_rx : \
-                         &ixgbe_msix_clean_many)
+                        (!(_v)->txr_count) ? &ixgbe_msix_clean_rx : \
+                        &ixgbe_msix_clean_many)
        for (vector = 0; vector < q_vectors; vector++) {
                handler = SET_HANDLER(adapter->q_vector[vector]);
 
-               if(handler == &ixgbe_msix_clean_rx) {
+               if (handler == &ixgbe_msix_clean_rx) {
                        sprintf(adapter->name[vector], "%s-%s-%d",
                                netdev->name, "rx", ri++);
-               }
-               else if(handler == &ixgbe_msix_clean_tx) {
+               } else if (handler == &ixgbe_msix_clean_tx) {
                        sprintf(adapter->name[vector], "%s-%s-%d",
                                netdev->name, "tx", ti++);
-               }
-               else
+               } else
                        sprintf(adapter->name[vector], "%s-%s-%d",
                                netdev->name, "TxRx", vector);
 
                err = request_irq(adapter->msix_entries[vector].vector,
-                                 handler, 0, adapter->name[vector],
-                                 adapter->q_vector[vector]);
+                                 handler, 0, adapter->name[vector],
+                                 adapter->q_vector[vector]);
                if (err) {
                        e_err(probe, "request_irq failed for MSIX interrupt "
                              "Error: %d\n", err);
@@ -2162,7 +2164,7 @@ static int ixgbe_request_msix_irqs(struct ixgbe_adapter *adapter)
 
        sprintf(adapter->name[vector], "%s:lsc", netdev->name);
        err = request_irq(adapter->msix_entries[vector].vector,
-                         ixgbe_msix_lsc, 0, adapter->name[vector], netdev);
+                         ixgbe_msix_lsc, 0, adapter->name[vector], netdev);
        if (err) {
                e_err(probe, "request_irq for msix_lsc failed: %d\n", err);
                goto free_queue_irqs;
@@ -2173,7 +2175,7 @@ static int ixgbe_request_msix_irqs(struct ixgbe_adapter *adapter)
 free_queue_irqs:
        for (i = vector - 1; i >= 0; i--)
                free_irq(adapter->msix_entries[--vector].vector,
-                        adapter->q_vector[i]);
+                        adapter->q_vector[i]);
        adapter->flags &= ~IXGBE_FLAG_MSIX_ENABLED;
        pci_disable_msix(adapter->pdev);
        kfree(adapter->msix_entries);
@@ -2191,13 +2193,13 @@ static void ixgbe_set_itr(struct ixgbe_adapter *adapter)
        struct ixgbe_ring *tx_ring = adapter->tx_ring[0];
 
        q_vector->tx_itr = ixgbe_update_itr(adapter, new_itr,
-                                           q_vector->tx_itr,
-                                           tx_ring->total_packets,
-                                           tx_ring->total_bytes);
+                                           q_vector->tx_itr,
+                                           tx_ring->total_packets,
+                                           tx_ring->total_bytes);
        q_vector->rx_itr = ixgbe_update_itr(adapter, new_itr,
-                                           q_vector->rx_itr,
-                                           rx_ring->total_packets,
-                                           rx_ring->total_bytes);
+                                           q_vector->rx_itr,
+                                           rx_ring->total_packets,
+                                           rx_ring->total_bytes);
 
        current_itr = max(q_vector->rx_itr, q_vector->tx_itr);
 
@@ -2343,10 +2345,10 @@ static int ixgbe_request_irq(struct ixgbe_adapter *adapter)
                err = ixgbe_request_msix_irqs(adapter);
        } else if (adapter->flags & IXGBE_FLAG_MSI_ENABLED) {
                err = request_irq(adapter->pdev->irq, ixgbe_intr, 0,
-                                 netdev->name, netdev);
+                                 netdev->name, netdev);
        } else {
                err = request_irq(adapter->pdev->irq, ixgbe_intr, IRQF_SHARED,
-                                 netdev->name, netdev);
+                                 netdev->name, netdev);
        }
 
        if (err)
@@ -2370,7 +2372,7 @@ static void ixgbe_free_irq(struct ixgbe_adapter *adapter)
                i--;
                for (; i >= 0; i--) {
                        free_irq(adapter->msix_entries[i].vector,
-                                adapter->q_vector[i]);
+                                adapter->q_vector[i]);
                }
 
                ixgbe_reset_q_vectors(adapter);
@@ -2413,7 +2415,7 @@ static void ixgbe_configure_msi_and_legacy(struct ixgbe_adapter *adapter)
        struct ixgbe_hw *hw = &adapter->hw;
 
        IXGBE_WRITE_REG(hw, IXGBE_EITR(0),
-                       EITR_INTS_PER_SEC_TO_REG(adapter->rx_eitr_param));
+                       EITR_INTS_PER_SEC_TO_REG(adapter->rx_eitr_param));
 
        ixgbe_set_ivar(adapter, 0, 0, 0);
        ixgbe_set_ivar(adapter, 1, 0, 0);
@@ -2425,95 +2427,140 @@ static void ixgbe_configure_msi_and_legacy(struct ixgbe_adapter *adapter)
 }
 
 /**
- * ixgbe_configure_tx - Configure 8259x Transmit Unit after Reset
+ * ixgbe_configure_tx_ring - Configure 8259x Tx ring after Reset
  * @adapter: board private structure
+ * @ring: structure containing ring specific data
  *
- * Configure the Tx unit of the MAC after a reset.
+ * Configure the Tx descriptor ring after a reset.
  **/
-static void ixgbe_configure_tx(struct ixgbe_adapter *adapter)
+void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
+                            struct ixgbe_ring *ring)
 {
-       u64 tdba;
        struct ixgbe_hw *hw = &adapter->hw;
-       u32 i, j, tdlen, txctrl;
+       u64 tdba = ring->dma;
+       int wait_loop = 10;
+       u32 txdctl;
+       u16 reg_idx = ring->reg_idx;
 
-       /* Setup the HW Tx Head and Tail descriptor pointers */
-       for (i = 0; i < adapter->num_tx_queues; i++) {
-               struct ixgbe_ring *ring = adapter->tx_ring[i];
-               j = ring->reg_idx;
-               tdba = ring->dma;
-               tdlen = ring->count * sizeof(union ixgbe_adv_tx_desc);
-               IXGBE_WRITE_REG(hw, IXGBE_TDBAL(j),
-                               (tdba & DMA_BIT_MASK(32)));
-               IXGBE_WRITE_REG(hw, IXGBE_TDBAH(j), (tdba >> 32));
-               IXGBE_WRITE_REG(hw, IXGBE_TDLEN(j), tdlen);
-               IXGBE_WRITE_REG(hw, IXGBE_TDH(j), 0);
-               IXGBE_WRITE_REG(hw, IXGBE_TDT(j), 0);
-               adapter->tx_ring[i]->head = IXGBE_TDH(j);
-               adapter->tx_ring[i]->tail = IXGBE_TDT(j);
-               /*
-                * Disable Tx Head Writeback RO bit, since this hoses
-                * bookkeeping if things aren't delivered in order.
-                */
-               switch (hw->mac.type) {
-               case ixgbe_mac_82598EB:
-                       txctrl = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL(j));
-                       break;
-               case ixgbe_mac_82599EB:
-               default:
-                       txctrl = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL_82599(j));
-                       break;
-               }
-               txctrl &= ~IXGBE_DCA_TXCTRL_TX_WB_RO_EN;
-               switch (hw->mac.type) {
-               case ixgbe_mac_82598EB:
-                       IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL(j), txctrl);
-                       break;
-               case ixgbe_mac_82599EB:
-               default:
-                       IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL_82599(j), txctrl);
-                       break;
-               }
+       /* disable queue to avoid issues while updating state */
+       txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(reg_idx));
+       IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx),
+                       txdctl & ~IXGBE_TXDCTL_ENABLE);
+       IXGBE_WRITE_FLUSH(hw);
+
+       IXGBE_WRITE_REG(hw, IXGBE_TDBAL(reg_idx),
+                       (tdba & DMA_BIT_MASK(32)));
+       IXGBE_WRITE_REG(hw, IXGBE_TDBAH(reg_idx), (tdba >> 32));
+       IXGBE_WRITE_REG(hw, IXGBE_TDLEN(reg_idx),
+                       ring->count * sizeof(union ixgbe_adv_tx_desc));
+       IXGBE_WRITE_REG(hw, IXGBE_TDH(reg_idx), 0);
+       IXGBE_WRITE_REG(hw, IXGBE_TDT(reg_idx), 0);
+       ring->head = IXGBE_TDH(reg_idx);
+       ring->tail = IXGBE_TDT(reg_idx);
+
+       /* configure fetching thresholds */
+       if (adapter->rx_itr_setting == 0) {
+               /* cannot set wthresh when itr==0 */
+               txdctl &= ~0x007F0000;
+       } else {
+               /* enable WTHRESH=8 descriptors, to encourage burst writeback */
+               txdctl |= (8 << 16);
+       }
+       if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) {
+               /* PThresh workaround for Tx hang with DFP enabled. */
+               txdctl |= 32;
        }
 
-       if (hw->mac.type == ixgbe_mac_82599EB) {
-               u32 rttdcs;
-               u32 mask;
+       /* reinitialize flowdirector state */
+       set_bit(__IXGBE_FDIR_INIT_DONE, &ring->reinit_state);
 
-               /* disable the arbiter while setting MTQC */
-               rttdcs = IXGBE_READ_REG(hw, IXGBE_RTTDCS);
-               rttdcs |= IXGBE_RTTDCS_ARBDIS;
-               IXGBE_WRITE_REG(hw, IXGBE_RTTDCS, rttdcs);
+       /* enable queue */
+       txdctl |= IXGBE_TXDCTL_ENABLE;
+       IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), txdctl);
 
-               /* set transmit pool layout */
-               mask = (IXGBE_FLAG_SRIOV_ENABLED | IXGBE_FLAG_DCB_ENABLED);
-               switch (adapter->flags & mask) {
+       /* TXDCTL.EN will return 0 on 82598 if link is down, so skip it */
+       if (hw->mac.type == ixgbe_mac_82598EB &&
+           !(IXGBE_READ_REG(hw, IXGBE_LINKS) & IXGBE_LINKS_UP))
+               return;
 
-               case (IXGBE_FLAG_SRIOV_ENABLED):
-                       IXGBE_WRITE_REG(hw, IXGBE_MTQC,
-                                       (IXGBE_MTQC_VT_ENA | IXGBE_MTQC_64VF));
-                       break;
+       /* poll to verify queue is enabled */
+       do {
+               msleep(1);
+               txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(reg_idx));
+       } while (--wait_loop && !(txdctl & IXGBE_TXDCTL_ENABLE));
+       if (!wait_loop)
+               e_err(drv, "Could not enable Tx Queue %d\n", reg_idx);
+}
 
-               case (IXGBE_FLAG_DCB_ENABLED):
-                       /* We enable 8 traffic classes, DCB only */
-                       IXGBE_WRITE_REG(hw, IXGBE_MTQC,
-                                     (IXGBE_MTQC_RT_ENA | IXGBE_MTQC_8TC_8TQ));
-                       break;
+static void ixgbe_setup_mtqc(struct ixgbe_adapter *adapter)
+{
+       struct ixgbe_hw *hw = &adapter->hw;
+       u32 rttdcs;
+       u32 mask;
 
-               default:
-                       IXGBE_WRITE_REG(hw, IXGBE_MTQC, IXGBE_MTQC_64Q_1PB);
-                       break;
-               }
+       if (hw->mac.type == ixgbe_mac_82598EB)
+               return;
+
+       /* disable the arbiter while setting MTQC */
+       rttdcs = IXGBE_READ_REG(hw, IXGBE_RTTDCS);
+       rttdcs |= IXGBE_RTTDCS_ARBDIS;
+       IXGBE_WRITE_REG(hw, IXGBE_RTTDCS, rttdcs);
+
+       /* set transmit pool layout */
+       mask = (IXGBE_FLAG_SRIOV_ENABLED | IXGBE_FLAG_DCB_ENABLED);
+       switch (adapter->flags & mask) {
+
+       case (IXGBE_FLAG_SRIOV_ENABLED):
+               IXGBE_WRITE_REG(hw, IXGBE_MTQC,
+                               (IXGBE_MTQC_VT_ENA | IXGBE_MTQC_64VF));
+               break;
+
+       case (IXGBE_FLAG_DCB_ENABLED):
+               /* We enable 8 traffic classes, DCB only */
+               IXGBE_WRITE_REG(hw, IXGBE_MTQC,
+                             (IXGBE_MTQC_RT_ENA | IXGBE_MTQC_8TC_8TQ));
+               break;
+
+       default:
+               IXGBE_WRITE_REG(hw, IXGBE_MTQC, IXGBE_MTQC_64Q_1PB);
+               break;
+       }
+
+       /* re-enable the arbiter */
+       rttdcs &= ~IXGBE_RTTDCS_ARBDIS;
+       IXGBE_WRITE_REG(hw, IXGBE_RTTDCS, rttdcs);
+}
+
+/**
+ * ixgbe_configure_tx - Configure 8259x Transmit Unit after Reset
+ * @adapter: board private structure
+ *
+ * Configure the Tx unit of the MAC after a reset.
+ **/
+static void ixgbe_configure_tx(struct ixgbe_adapter *adapter)
+{
+       struct ixgbe_hw *hw = &adapter->hw;
+       u32 dmatxctl;
+       u32 i;
+
+       ixgbe_setup_mtqc(adapter);
 
-               /* re-eable the arbiter */
-               rttdcs &= ~IXGBE_RTTDCS_ARBDIS;
-               IXGBE_WRITE_REG(hw, IXGBE_RTTDCS, rttdcs);
+       if (hw->mac.type != ixgbe_mac_82598EB) {
+               /* DMATXCTL.EN must be before Tx queues are enabled */
+               dmatxctl = IXGBE_READ_REG(hw, IXGBE_DMATXCTL);
+               dmatxctl |= IXGBE_DMATXCTL_TE;
+               IXGBE_WRITE_REG(hw, IXGBE_DMATXCTL, dmatxctl);
        }
+
+       /* Setup the HW Tx Head and Tail descriptor pointers */
+       for (i = 0; i < adapter->num_tx_queues; i++)
+               ixgbe_configure_tx_ring(adapter, adapter->tx_ring[i]);
 }
 
 #define IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT 2
 
 static void ixgbe_configure_srrctl(struct ixgbe_adapter *adapter,
-                                   struct ixgbe_ring *rx_ring)
+                                  struct ixgbe_ring *rx_ring)
 {
        u32 srrctl;
        int index;
@@ -2529,6 +2576,8 @@ static void ixgbe_configure_srrctl(struct ixgbe_adapter *adapter,
 
        srrctl &= ~IXGBE_SRRCTL_BSIZEHDR_MASK;
        srrctl &= ~IXGBE_SRRCTL_BSIZEPKT_MASK;
+       if (adapter->num_vfs)
+               srrctl |= IXGBE_SRRCTL_DROP_EN;
 
        srrctl |= (IXGBE_RX_HDR_SIZE << IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT) &
                  IXGBE_SRRCTL_BSIZEHDR_MASK;
@@ -2549,20 +2598,46 @@ static void ixgbe_configure_srrctl(struct ixgbe_adapter *adapter,
        IXGBE_WRITE_REG(&adapter->hw, IXGBE_SRRCTL(index), srrctl);
 }
 
-static u32 ixgbe_setup_mrqc(struct ixgbe_adapter *adapter)
+static void ixgbe_setup_mrqc(struct ixgbe_adapter *adapter)
 {
-       u32 mrqc = 0;
+       struct ixgbe_hw *hw = &adapter->hw;
+       static const u32 seed[10] = { 0xE291D73D, 0x1805EC6C, 0x2A94B30D,
+                         0xA54F2BEC, 0xEA49AF7C, 0xE214AD3D, 0xB855AABE,
+                         0x6A3E67EA, 0x14364D17, 0x3BED200D};
+       u32 mrqc = 0, reta = 0;
+       u32 rxcsum;
+       int i, j;
        int mask;
 
-       if (!(adapter->hw.mac.type == ixgbe_mac_82599EB))
-               return mrqc;
+       /* Fill out hash function seeds */
+       for (i = 0; i < 10; i++)
+               IXGBE_WRITE_REG(hw, IXGBE_RSSRK(i), seed[i]);
+
+       /* Fill out redirection table */
+       for (i = 0, j = 0; i < 128; i++, j++) {
+               if (j == adapter->ring_feature[RING_F_RSS].indices)
+                       j = 0;
+               /* reta = 4-byte sliding window of
+                * 0x00..(indices-1)(indices-1)00..etc. */
+               reta = (reta << 8) | (j * 0x11);
+               if ((i & 3) == 3)
+                       IXGBE_WRITE_REG(hw, IXGBE_RETA(i >> 2), reta);
+       }
+
+       /* Disable indicating checksum in descriptor, enables RSS hash */
+       rxcsum = IXGBE_READ_REG(hw, IXGBE_RXCSUM);
+       rxcsum |= IXGBE_RXCSUM_PCSD;
+       IXGBE_WRITE_REG(hw, IXGBE_RXCSUM, rxcsum);
 
-       mask = adapter->flags & (IXGBE_FLAG_RSS_ENABLED
+       if (adapter->hw.mac.type == ixgbe_mac_82598EB)
+               mask = adapter->flags & IXGBE_FLAG_RSS_ENABLED;
+       else
+               mask = adapter->flags & (IXGBE_FLAG_RSS_ENABLED
 #ifdef CONFIG_IXGBE_DCB
-                                | IXGBE_FLAG_DCB_ENABLED
+                                        | IXGBE_FLAG_DCB_ENABLED
 #endif
-                                | IXGBE_FLAG_SRIOV_ENABLED
-                               );
+                                        | IXGBE_FLAG_SRIOV_ENABLED
+                                       );
 
        switch (mask) {
        case (IXGBE_FLAG_RSS_ENABLED):
@@ -2580,7 +2655,13 @@ static u32 ixgbe_setup_mrqc(struct ixgbe_adapter *adapter)
                break;
        }
 
-       return mrqc;
+       /* Perform hash on these packet types */
+       mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4
+             | IXGBE_MRQC_RSS_FIELD_IPV4_TCP
+             | IXGBE_MRQC_RSS_FIELD_IPV6
+             | IXGBE_MRQC_RSS_FIELD_IPV6_TCP;
+
+       IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc);
 }
 
 /**
@@ -2588,25 +2669,26 @@ static u32 ixgbe_setup_mrqc(struct ixgbe_adapter *adapter)
  * @adapter:    address of board private structure
  * @index:      index of ring to set
  **/
-static void ixgbe_configure_rscctl(struct ixgbe_adapter *adapter, int index)
+static void ixgbe_configure_rscctl(struct ixgbe_adapter *adapter,
+                                  struct ixgbe_ring *ring)
 {
-       struct ixgbe_ring *rx_ring;
        struct ixgbe_hw *hw = &adapter->hw;
-       int j;
        u32 rscctrl;
        int rx_buf_len;
+       u16 reg_idx = ring->reg_idx;
 
-       rx_ring = adapter->rx_ring[index];
-       j = rx_ring->reg_idx;
-       rx_buf_len = rx_ring->rx_buf_len;
-       rscctrl = IXGBE_READ_REG(hw, IXGBE_RSCCTL(j));
+       if (!(adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED))
+               return;
+
+       rx_buf_len = ring->rx_buf_len;
+       rscctrl = IXGBE_READ_REG(hw, IXGBE_RSCCTL(reg_idx));
        rscctrl |= IXGBE_RSCCTL_RSCEN;
        /*
         * we must limit the number of descriptors so that the
         * total size of max desc * buf_len is not greater
         * than 65535
         */
-       if (rx_ring->flags & IXGBE_RING_RX_PS_ENABLED) {
+       if (ring->flags & IXGBE_RING_RX_PS_ENABLED) {
 #if (MAX_SKB_FRAGS > 16)
                rscctrl |= IXGBE_RSCCTL_MAXDESC_16;
 #elif (MAX_SKB_FRAGS > 8)
@@ -2624,31 +2706,181 @@ static void ixgbe_configure_rscctl(struct ixgbe_adapter *adapter, int index)
                else
                        rscctrl |= IXGBE_RSCCTL_MAXDESC_4;
        }
-       IXGBE_WRITE_REG(hw, IXGBE_RSCCTL(j), rscctrl);
+       IXGBE_WRITE_REG(hw, IXGBE_RSCCTL(reg_idx), rscctrl);
 }
 
 /**
- * ixgbe_configure_rx - Configure 8259x Receive Unit after Reset
- * @adapter: board private structure
+ *  ixgbe_set_uta - Set unicast filter table address
+ *  @adapter: board private structure
  *
- * Configure the Rx unit of the MAC after a reset.
+ *  The unicast table address is a register array of 32-bit registers.
+ *  The table is meant to be used in a way similar to how the MTA is used
+ *  however due to certain limitations in the hardware it is necessary to
+ *  set all the hash bits to 1 and use the VMOLR ROPE bit as a promiscuous
+ *  enable bit to allow vlan tag stripping when promiscuous mode is enabled
  **/
-static void ixgbe_configure_rx(struct ixgbe_adapter *adapter)
+static void ixgbe_set_uta(struct ixgbe_adapter *adapter)
+{
+       struct ixgbe_hw *hw = &adapter->hw;
+       int i;
+
+       /* The UTA table only exists on 82599 hardware and newer */
+       if (hw->mac.type < ixgbe_mac_82599EB)
+               return;
+
+       /* we only need to do this if VMDq is enabled */
+       if (!(adapter->flags & IXGBE_FLAG_SRIOV_ENABLED))
+               return;
+
+       for (i = 0; i < 128; i++)
+               IXGBE_WRITE_REG(hw, IXGBE_UTA(i), ~0);
+}
+
+#define IXGBE_MAX_RX_DESC_POLL 10
+static void ixgbe_rx_desc_queue_enable(struct ixgbe_adapter *adapter,
+                                      struct ixgbe_ring *ring)
+{
+       struct ixgbe_hw *hw = &adapter->hw;
+       int reg_idx = ring->reg_idx;
+       int wait_loop = IXGBE_MAX_RX_DESC_POLL;
+       u32 rxdctl;
+
+       /* RXDCTL.EN will return 0 on 82598 if link is down, so skip it */
+       if (hw->mac.type == ixgbe_mac_82598EB &&
+           !(IXGBE_READ_REG(hw, IXGBE_LINKS) & IXGBE_LINKS_UP))
+               return;
+
+       do {
+               msleep(1);
+               rxdctl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(reg_idx));
+       } while (--wait_loop && !(rxdctl & IXGBE_RXDCTL_ENABLE));
+
+       if (!wait_loop) {
+               e_err(drv, "RXDCTL.ENABLE on Rx queue %d not set within "
+                     "the polling period\n", reg_idx);
+       }
+}
+
+void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
+                            struct ixgbe_ring *ring)
+{
+       struct ixgbe_hw *hw = &adapter->hw;
+       u64 rdba = ring->dma;
+       u32 rxdctl;
+       u16 reg_idx = ring->reg_idx;
+
+       /* disable queue to avoid issues while updating state */
+       rxdctl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(reg_idx));
+       IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx),
+                       rxdctl & ~IXGBE_RXDCTL_ENABLE);
+       IXGBE_WRITE_FLUSH(hw);
+
+       IXGBE_WRITE_REG(hw, IXGBE_RDBAL(reg_idx), (rdba & DMA_BIT_MASK(32)));
+       IXGBE_WRITE_REG(hw, IXGBE_RDBAH(reg_idx), (rdba >> 32));
+       IXGBE_WRITE_REG(hw, IXGBE_RDLEN(reg_idx),
+                       ring->count * sizeof(union ixgbe_adv_rx_desc));
+       IXGBE_WRITE_REG(hw, IXGBE_RDH(reg_idx), 0);
+       IXGBE_WRITE_REG(hw, IXGBE_RDT(reg_idx), 0);
+       ring->head = IXGBE_RDH(reg_idx);
+       ring->tail = IXGBE_RDT(reg_idx);
+
+       ixgbe_configure_srrctl(adapter, ring);
+       ixgbe_configure_rscctl(adapter, ring);
+
+       if (hw->mac.type == ixgbe_mac_82598EB) {
+               /*
+                * enable cache line friendly hardware writes:
+                * PTHRESH=32 descriptors (half the internal cache),
+                * this also removes ugly rx_no_buffer_count increment
+                * HTHRESH=4 descriptors (to minimize latency on fetch)
+                * WTHRESH=8 burst writeback up to two cache lines
+                */
+               rxdctl &= ~0x3FFFFF;
+               rxdctl |=  0x080420;
+       }
+
+       /* enable receive descriptor ring */
+       rxdctl |= IXGBE_RXDCTL_ENABLE;
+       IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(reg_idx), rxdctl);
+
+       ixgbe_rx_desc_queue_enable(adapter, ring);
+       ixgbe_alloc_rx_buffers(adapter, ring, IXGBE_DESC_UNUSED(ring));
+}
+
+static void ixgbe_setup_psrtype(struct ixgbe_adapter *adapter)
+{
+       struct ixgbe_hw *hw = &adapter->hw;
+       int p;
+
+       /* PSRTYPE must be initialized in non 82598 adapters */
+       u32 psrtype = IXGBE_PSRTYPE_TCPHDR |
+                     IXGBE_PSRTYPE_UDPHDR |
+                     IXGBE_PSRTYPE_IPV4HDR |
+                     IXGBE_PSRTYPE_L2HDR |
+                     IXGBE_PSRTYPE_IPV6HDR;
+
+       if (hw->mac.type == ixgbe_mac_82598EB)
+               return;
+
+       if (adapter->flags & IXGBE_FLAG_RSS_ENABLED)
+               psrtype |= (adapter->num_rx_queues_per_pool << 29);
+
+       for (p = 0; p < adapter->num_rx_pools; p++)
+               IXGBE_WRITE_REG(hw, IXGBE_PSRTYPE(adapter->num_vfs + p),
+                               psrtype);
+}
+
+static void ixgbe_configure_virtualization(struct ixgbe_adapter *adapter)
+{
+       struct ixgbe_hw *hw = &adapter->hw;
+       u32 gcr_ext;
+       u32 vt_reg_bits;
+       u32 reg_offset, vf_shift;
+       u32 vmdctl;
+
+       if (!(adapter->flags & IXGBE_FLAG_SRIOV_ENABLED))
+               return;
+
+       vmdctl = IXGBE_READ_REG(hw, IXGBE_VT_CTL);
+       vt_reg_bits = IXGBE_VMD_CTL_VMDQ_EN | IXGBE_VT_CTL_REPLEN;
+       vt_reg_bits |= (adapter->num_vfs << IXGBE_VT_CTL_POOL_SHIFT);
+       IXGBE_WRITE_REG(hw, IXGBE_VT_CTL, vmdctl | vt_reg_bits);
+
+       vf_shift = adapter->num_vfs % 32;
+       reg_offset = (adapter->num_vfs > 32) ? 1 : 0;
+
+       /* Enable only the PF's pool for Tx/Rx */
+       IXGBE_WRITE_REG(hw, IXGBE_VFRE(reg_offset), (1 << vf_shift));
+       IXGBE_WRITE_REG(hw, IXGBE_VFRE(reg_offset ^ 1), 0);
+       IXGBE_WRITE_REG(hw, IXGBE_VFTE(reg_offset), (1 << vf_shift));
+       IXGBE_WRITE_REG(hw, IXGBE_VFTE(reg_offset ^ 1), 0);
+       IXGBE_WRITE_REG(hw, IXGBE_PFDTXGSWC, IXGBE_PFDTXGSWC_VT_LBEN);
+
+       /* Map PF MAC address in RAR Entry 0 to first pool following VFs */
+       hw->mac.ops.set_vmdq(hw, 0, adapter->num_vfs);
+
+       /*
+        * Set up VF register offsets for selected VT Mode,
+        * i.e. 32 or 64 VFs for SR-IOV
+        */
+       gcr_ext = IXGBE_READ_REG(hw, IXGBE_GCR_EXT);
+       gcr_ext |= IXGBE_GCR_EXT_MSIX_EN;
+       gcr_ext |= IXGBE_GCR_EXT_VT_MODE_64;
+       IXGBE_WRITE_REG(hw, IXGBE_GCR_EXT, gcr_ext);
+
+       /* enable Tx loopback for VF/PF communication */
+       IXGBE_WRITE_REG(hw, IXGBE_PFDTXGSWC, IXGBE_PFDTXGSWC_VT_LBEN);
+}
+
+static void ixgbe_set_rx_buffer_len(struct ixgbe_adapter *adapter)
 {
-       u64 rdba;
        struct ixgbe_hw *hw = &adapter->hw;
-       struct ixgbe_ring *rx_ring;
        struct net_device *netdev = adapter->netdev;
        int max_frame = netdev->mtu + ETH_HLEN + ETH_FCS_LEN;
-       int i, j;
-       u32 rdlen, rxctrl, rxcsum;
-       static const u32 seed[10] = { 0xE291D73D, 0x1805EC6C, 0x2A94B30D,
-                         0xA54F2BEC, 0xEA49AF7C, 0xE214AD3D, 0xB855AABE,
-                         0x6A3E67EA, 0x14364D17, 0x3BED200D};
-       u32 fctrl, hlreg0;
-       u32 reta = 0, mrqc = 0;
-       u32 rdrxctl;
        int rx_buf_len;
+       struct ixgbe_ring *rx_ring;
+       int i;
+       u32 mhadd, hlreg0;
 
        /* Decide whether to use packet split mode or not */
        /* Do not use packet split if we're in SR-IOV Mode */
@@ -2658,62 +2890,40 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter)
        /* Set the RX buffer length according to the mode */
        if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) {
                rx_buf_len = IXGBE_RX_HDR_SIZE;
-               if (hw->mac.type == ixgbe_mac_82599EB) {
-                       /* PSRTYPE must be initialized in 82599 */
-                       u32 psrtype = IXGBE_PSRTYPE_TCPHDR |
-                                     IXGBE_PSRTYPE_UDPHDR |
-                                     IXGBE_PSRTYPE_IPV4HDR |
-                                     IXGBE_PSRTYPE_IPV6HDR |
-                                     IXGBE_PSRTYPE_L2HDR;
-                       IXGBE_WRITE_REG(hw,
-                                       IXGBE_PSRTYPE(adapter->num_vfs),
-                                       psrtype);
-               }
        } else {
                if (!(adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED) &&
                    (netdev->mtu <= ETH_DATA_LEN))
                        rx_buf_len = MAXIMUM_ETHERNET_VLAN_SIZE;
                else
-                       rx_buf_len = ALIGN(max_frame, 1024);
+                       rx_buf_len = ALIGN(max_frame + VLAN_HLEN, 1024);
        }
 
-       fctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_FCTRL);
-       fctrl |= IXGBE_FCTRL_BAM;
-       fctrl |= IXGBE_FCTRL_DPF; /* discard pause frames when FC enabled */
-       fctrl |= IXGBE_FCTRL_PMCF;
-       IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, fctrl);
+#ifdef IXGBE_FCOE
+       /* adjust max frame to be able to do baby jumbo for FCoE */
+       if ((adapter->flags & IXGBE_FLAG_FCOE_ENABLED) &&
+           (max_frame < IXGBE_FCOE_JUMBO_FRAME_SIZE))
+               max_frame = IXGBE_FCOE_JUMBO_FRAME_SIZE;
+
+#endif /* IXGBE_FCOE */
+       mhadd = IXGBE_READ_REG(hw, IXGBE_MHADD);
+       if (max_frame != (mhadd >> IXGBE_MHADD_MFS_SHIFT)) {
+               mhadd &= ~IXGBE_MHADD_MFS_MASK;
+               mhadd |= max_frame << IXGBE_MHADD_MFS_SHIFT;
+
+               IXGBE_WRITE_REG(hw, IXGBE_MHADD, mhadd);
+       }
 
        hlreg0 = IXGBE_READ_REG(hw, IXGBE_HLREG0);
-       if (adapter->netdev->mtu <= ETH_DATA_LEN)
-               hlreg0 &= ~IXGBE_HLREG0_JUMBOEN;
-       else
-               hlreg0 |= IXGBE_HLREG0_JUMBOEN;
-#ifdef IXGBE_FCOE
-       if (netdev->features & NETIF_F_FCOE_MTU)
-               hlreg0 |= IXGBE_HLREG0_JUMBOEN;
-#endif
+       /* set jumbo enable since MHADD.MFS is keeping size locked at max_frame */
+       hlreg0 |= IXGBE_HLREG0_JUMBOEN;
        IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hlreg0);
 
-       rdlen = adapter->rx_ring[0]->count * sizeof(union ixgbe_adv_rx_desc);
-       /* disable receives while setting up the descriptors */
-       rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
-       IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, rxctrl & ~IXGBE_RXCTRL_RXEN);
-
        /*
         * Setup the HW Rx Head and Tail Descriptor Pointers and
         * the Base and Length of the Rx Descriptor Ring
         */
        for (i = 0; i < adapter->num_rx_queues; i++) {
                rx_ring = adapter->rx_ring[i];
-               rdba = rx_ring->dma;
-               j = rx_ring->reg_idx;
-               IXGBE_WRITE_REG(hw, IXGBE_RDBAL(j), (rdba & DMA_BIT_MASK(32)));
-               IXGBE_WRITE_REG(hw, IXGBE_RDBAH(j), (rdba >> 32));
-               IXGBE_WRITE_REG(hw, IXGBE_RDLEN(j), rdlen);
-               IXGBE_WRITE_REG(hw, IXGBE_RDH(j), 0);
-               IXGBE_WRITE_REG(hw, IXGBE_RDT(j), 0);
-               rx_ring->head = IXGBE_RDH(j);
-               rx_ring->tail = IXGBE_RDT(j);
                rx_ring->rx_buf_len = rx_buf_len;
 
                if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED)
@@ -2729,15 +2939,21 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter)
                                rx_ring->flags &= ~IXGBE_RING_RX_PS_ENABLED;
                                if (rx_buf_len < IXGBE_FCOE_JUMBO_FRAME_SIZE)
                                        rx_ring->rx_buf_len =
-                                               IXGBE_FCOE_JUMBO_FRAME_SIZE;
+                                               IXGBE_FCOE_JUMBO_FRAME_SIZE;
                        }
                }
-
 #endif /* IXGBE_FCOE */
-               ixgbe_configure_srrctl(adapter, rx_ring);
        }
 
-       if (hw->mac.type == ixgbe_mac_82598EB) {
+}
+
+static void ixgbe_setup_rdrxctl(struct ixgbe_adapter *adapter)
+{
+       struct ixgbe_hw *hw = &adapter->hw;
+       u32 rdrxctl = IXGBE_READ_REG(hw, IXGBE_RDRXCTL);
+
+       switch (hw->mac.type) {
+       case ixgbe_mac_82598EB:
                /*
                 * For VMDq support of different descriptor types or
                 * buffer sizes through the use of multiple SRRCTL
@@ -2748,110 +2964,66 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter)
                 * effects of setting this bit are only that SRRCTL must be
                 * fully programmed [0..15]
                 */
-               rdrxctl = IXGBE_READ_REG(hw, IXGBE_RDRXCTL);
                rdrxctl |= IXGBE_RDRXCTL_MVMEN;
-               IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, rdrxctl);
+               break;
+       case ixgbe_mac_82599EB:
+               /* Disable RSC for ACK packets */
+               IXGBE_WRITE_REG(hw, IXGBE_RSCDBU,
+                  (IXGBE_RSCDBU_RSCACKDIS | IXGBE_READ_REG(hw, IXGBE_RSCDBU)));
+               rdrxctl &= ~IXGBE_RDRXCTL_RSCFRSTSIZE;
+               /* hardware requires some bits to be set by default */
+               rdrxctl |= (IXGBE_RDRXCTL_RSCACKC | IXGBE_RDRXCTL_FCOE_WRFIX);
+               rdrxctl |= IXGBE_RDRXCTL_CRCSTRIP;
+               break;
+       default:
+               /* We should do nothing since we don't know this hardware */
+               return;
        }
 
-       if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED) {
-               u32 vt_reg_bits;
-               u32 reg_offset, vf_shift;
-               u32 vmdctl = IXGBE_READ_REG(hw, IXGBE_VT_CTL);
-               vt_reg_bits = IXGBE_VMD_CTL_VMDQ_EN
-                       | IXGBE_VT_CTL_REPLEN;
-               vt_reg_bits |= (adapter->num_vfs <<
-                               IXGBE_VT_CTL_POOL_SHIFT);
-               IXGBE_WRITE_REG(hw, IXGBE_VT_CTL, vmdctl | vt_reg_bits);
-               IXGBE_WRITE_REG(hw, IXGBE_MRQC, 0);
-
-               vf_shift = adapter->num_vfs % 32;
-               reg_offset = adapter->num_vfs / 32;
-               IXGBE_WRITE_REG(hw, IXGBE_VFRE(0), 0);
-               IXGBE_WRITE_REG(hw, IXGBE_VFRE(1), 0);
-               IXGBE_WRITE_REG(hw, IXGBE_VFTE(0), 0);
-               IXGBE_WRITE_REG(hw, IXGBE_VFTE(1), 0);
-               /* Enable only the PF's pool for Tx/Rx */
-               IXGBE_WRITE_REG(hw, IXGBE_VFRE(reg_offset), (1 << vf_shift));
-               IXGBE_WRITE_REG(hw, IXGBE_VFTE(reg_offset), (1 << vf_shift));
-               IXGBE_WRITE_REG(hw, IXGBE_PFDTXGSWC, IXGBE_PFDTXGSWC_VT_LBEN);
-               ixgbe_set_vmolr(hw, adapter->num_vfs, true);
-       }
-
-       /* Program MRQC for the distribution of queues */
-       mrqc = ixgbe_setup_mrqc(adapter);
-
-       if (adapter->flags & IXGBE_FLAG_RSS_ENABLED) {
-               /* Fill out redirection table */
-               for (i = 0, j = 0; i < 128; i++, j++) {
-                       if (j == adapter->ring_feature[RING_F_RSS].indices)
-                               j = 0;
-                       /* reta = 4-byte sliding window of
-                        * 0x00..(indices-1)(indices-1)00..etc. */
-                       reta = (reta << 8) | (j * 0x11);
-                       if ((i & 3) == 3)
-                               IXGBE_WRITE_REG(hw, IXGBE_RETA(i >> 2), reta);
-               }
-
-               /* Fill out hash function seeds */
-               for (i = 0; i < 10; i++)
-                       IXGBE_WRITE_REG(hw, IXGBE_RSSRK(i), seed[i]);
-
-               if (hw->mac.type == ixgbe_mac_82598EB)
-                       mrqc |= IXGBE_MRQC_RSSEN;
-                   /* Perform hash on these packet types */
-               mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4
-                     | IXGBE_MRQC_RSS_FIELD_IPV4_TCP
-                     | IXGBE_MRQC_RSS_FIELD_IPV6
-                     | IXGBE_MRQC_RSS_FIELD_IPV6_TCP;
-       }
-       IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc);
+       IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, rdrxctl);
+}
 
-       if (adapter->num_vfs) {
-               u32 reg;
+/**
+ * ixgbe_configure_rx - Configure 8259x Receive Unit after Reset
+ * @adapter: board private structure
+ *
+ * Configure the Rx unit of the MAC after a reset.
+ **/
+static void ixgbe_configure_rx(struct ixgbe_adapter *adapter)
+{
+       struct ixgbe_hw *hw = &adapter->hw;
+       int i;
+       u32 rxctrl;
 
-               /* Map PF MAC address in RAR Entry 0 to first pool
-                * following VFs */
-               hw->mac.ops.set_vmdq(hw, 0, adapter->num_vfs);
+       /* disable receives while setting up the descriptors */
+       rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
+       IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, rxctrl & ~IXGBE_RXCTRL_RXEN);
 
-               /* Set up VF register offsets for selected VT Mode, i.e.
-                * 64 VFs for SR-IOV */
-               reg = IXGBE_READ_REG(hw, IXGBE_GCR_EXT);
-               reg |= IXGBE_GCR_EXT_SRIOV;
-               IXGBE_WRITE_REG(hw, IXGBE_GCR_EXT, reg);
-       }
+       ixgbe_setup_psrtype(adapter);
+       ixgbe_setup_rdrxctl(adapter);
 
-       rxcsum = IXGBE_READ_REG(hw, IXGBE_RXCSUM);
+       /* Program registers for the distribution of queues */
+       ixgbe_setup_mrqc(adapter);
 
-       if (adapter->flags & IXGBE_FLAG_RSS_ENABLED ||
-           adapter->flags & IXGBE_FLAG_RX_CSUM_ENABLED) {
-               /* Disable indicating checksum in descriptor, enables
-                * RSS hash */
-               rxcsum |= IXGBE_RXCSUM_PCSD;
-       }
-       if (!(rxcsum & IXGBE_RXCSUM_PCSD)) {
-               /* Enable IPv4 payload checksum for UDP fragments
-                * if PCSD is not set */
-               rxcsum |= IXGBE_RXCSUM_IPPCSE;
-       }
+       ixgbe_set_uta(adapter);
 
-       IXGBE_WRITE_REG(hw, IXGBE_RXCSUM, rxcsum);
+       /* set_rx_buffer_len must be called before ring initialization */
+       ixgbe_set_rx_buffer_len(adapter);
 
-       if (hw->mac.type == ixgbe_mac_82599EB) {
-               rdrxctl = IXGBE_READ_REG(hw, IXGBE_RDRXCTL);
-               rdrxctl |= IXGBE_RDRXCTL_CRCSTRIP;
-               rdrxctl &= ~IXGBE_RDRXCTL_RSCFRSTSIZE;
-               IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, rdrxctl);
-       }
+       /*
+        * Setup the HW Rx Head and Tail Descriptor Pointers and
+        * the Base and Length of the Rx Descriptor Ring
+        */
+       for (i = 0; i < adapter->num_rx_queues; i++)
+               ixgbe_configure_rx_ring(adapter, adapter->rx_ring[i]);
 
-       if (adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED) {
-               /* Enable 82599 HW-RSC */
-               for (i = 0; i < adapter->num_rx_queues; i++)
-                       ixgbe_configure_rscctl(adapter, i);
+       /* disable drop enable for 82598 parts */
+       if (hw->mac.type == ixgbe_mac_82598EB)
+               rxctrl |= IXGBE_RXCTRL_DMBYPS;
 
-               /* Disable RSC for ACK packets */
-               IXGBE_WRITE_REG(hw, IXGBE_RSCDBU,
-                  (IXGBE_RSCDBU_RSCACKDIS | IXGBE_READ_REG(hw, IXGBE_RSCDBU)));
-       }
+       /* enable all receives */
+       rxctrl |= IXGBE_RXCTRL_RXEN;
+       hw->mac.ops.enable_rx_dma(hw, rxctrl);
 }
 
 static void ixgbe_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
@@ -2955,7 +3127,7 @@ static void ixgbe_vlan_filter_enable(struct ixgbe_adapter *adapter)
 }
 
 static void ixgbe_vlan_rx_register(struct net_device *netdev,
-                                   struct vlan_group *grp)
+                                  struct vlan_group *grp)
 {
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
 
@@ -3052,6 +3224,11 @@ void ixgbe_set_rx_mode(struct net_device *netdev)
 
        fctrl = IXGBE_READ_REG(hw, IXGBE_FCTRL);
 
+       /* set all bits that we expect to always be set */
+       fctrl |= IXGBE_FCTRL_BAM;
+       fctrl |= IXGBE_FCTRL_DPF; /* discard pause frames when FC enabled */
+       fctrl |= IXGBE_FCTRL_PMCF;
+
        /* clear the bits we are changing the status of */
        fctrl &= ~(IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE);
 
@@ -3157,6 +3334,15 @@ static void ixgbe_configure_dcb(struct ixgbe_adapter *adapter)
        u32 txdctl;
        int i, j;
 
+       if (!(adapter->flags & IXGBE_FLAG_DCB_ENABLED)) {
+               if (hw->mac.type == ixgbe_mac_82598EB)
+                       netif_set_gso_max_size(adapter->netdev, 65536);
+               return;
+       }
+
+       if (hw->mac.type == ixgbe_mac_82598EB)
+               netif_set_gso_max_size(adapter->netdev, 32768);
+
        ixgbe_dcb_check_config(&adapter->dcb_cfg);
        ixgbe_dcb_calculate_tc_credits(&adapter->dcb_cfg, DCB_TX_CONFIG);
        ixgbe_dcb_calculate_tc_credits(&adapter->dcb_cfg, DCB_RX_CONFIG);
@@ -3188,17 +3374,7 @@ static void ixgbe_configure(struct ixgbe_adapter *adapter)
 
        ixgbe_restore_vlan(adapter);
 #ifdef CONFIG_IXGBE_DCB
-       if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) {
-               if (hw->mac.type == ixgbe_mac_82598EB)
-                       netif_set_gso_max_size(netdev, 32768);
-               else
-                       netif_set_gso_max_size(netdev, 65536);
-               ixgbe_configure_dcb(adapter);
-       } else {
-               netif_set_gso_max_size(netdev, 65536);
-       }
-#else
-       netif_set_gso_max_size(netdev, 65536);
+       ixgbe_configure_dcb(adapter);
 #endif
 
 #ifdef IXGBE_FCOE
@@ -3209,17 +3385,15 @@ static void ixgbe_configure(struct ixgbe_adapter *adapter)
        if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE) {
                for (i = 0; i < adapter->num_tx_queues; i++)
                        adapter->tx_ring[i]->atr_sample_rate =
-                                                      adapter->atr_sample_rate;
+                                                      adapter->atr_sample_rate;
                ixgbe_init_fdir_signature_82599(hw, adapter->fdir_pballoc);
        } else if (adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE) {
                ixgbe_init_fdir_perfect_82599(hw, adapter->fdir_pballoc);
        }
+       ixgbe_configure_virtualization(adapter);
 
        ixgbe_configure_tx(adapter);
        ixgbe_configure_rx(adapter);
-       for (i = 0; i < adapter->num_rx_queues; i++)
-               ixgbe_alloc_rx_buffers(adapter, adapter->rx_ring[i],
-                                      (adapter->rx_ring[i]->count - 1));
 }
 
 static inline bool ixgbe_is_sfp(struct ixgbe_hw *hw)
@@ -3290,7 +3464,8 @@ static int ixgbe_non_sfp_link_config(struct ixgbe_hw *hw)
                goto link_cfg_out;
 
        if (hw->mac.ops.get_link_capabilities)
-               ret = hw->mac.ops.get_link_capabilities(hw, &autoneg, &negotiation);
+               ret = hw->mac.ops.get_link_capabilities(hw, &autoneg,
+                                                       &negotiation);
        if (ret)
                goto link_cfg_out;
 
@@ -3300,62 +3475,15 @@ link_cfg_out:
        return ret;
 }
 
-#define IXGBE_MAX_RX_DESC_POLL 10
-static inline void ixgbe_rx_desc_queue_enable(struct ixgbe_adapter *adapter,
-                                             int rxr)
-{
-       int j = adapter->rx_ring[rxr]->reg_idx;
-       int k;
-
-       for (k = 0; k < IXGBE_MAX_RX_DESC_POLL; k++) {
-               if (IXGBE_READ_REG(&adapter->hw,
-                                  IXGBE_RXDCTL(j)) & IXGBE_RXDCTL_ENABLE)
-                       break;
-               else
-                       msleep(1);
-       }
-       if (k >= IXGBE_MAX_RX_DESC_POLL) {
-               e_err(drv, "RXDCTL.ENABLE on Rx queue %d not set within "
-                     "the polling period\n", rxr);
-       }
-       ixgbe_release_rx_desc(&adapter->hw, adapter->rx_ring[rxr],
-                             (adapter->rx_ring[rxr]->count - 1));
-}
-
-static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
+static void ixgbe_setup_gpie(struct ixgbe_adapter *adapter)
 {
-       struct net_device *netdev = adapter->netdev;
        struct ixgbe_hw *hw = &adapter->hw;
-       int i, j = 0;
-       int num_rx_rings = adapter->num_rx_queues;
-       int err;
-       int max_frame = netdev->mtu + ETH_HLEN + ETH_FCS_LEN;
-       u32 txdctl, rxdctl, mhadd;
-       u32 dmatxctl;
-       u32 gpie;
-       u32 ctrl_ext;
-
-       ixgbe_get_hw_control(adapter);
-
-       if ((adapter->flags & IXGBE_FLAG_MSIX_ENABLED) ||
-           (adapter->flags & IXGBE_FLAG_MSI_ENABLED)) {
-               if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) {
-                       gpie = (IXGBE_GPIE_MSIX_MODE | IXGBE_GPIE_EIAME |
-                               IXGBE_GPIE_PBA_SUPPORT | IXGBE_GPIE_OCD);
-               } else {
-                       /* MSI only */
-                       gpie = 0;
-               }
-               if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED) {
-                       gpie &= ~IXGBE_GPIE_VTMODE_MASK;
-                       gpie |= IXGBE_GPIE_VTMODE_64;
-               }
-               /* XXX: to interrupt immediately for EICS writes, enable this */
-               /* gpie |= IXGBE_GPIE_EIMEN; */
-               IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie);
-       }
+       u32 gpie = 0;
 
        if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) {
+               gpie = IXGBE_GPIE_MSIX_MODE | IXGBE_GPIE_PBA_SUPPORT |
+                      IXGBE_GPIE_OCD;
+               gpie |= IXGBE_GPIE_EIAME;
                /*
                 * use EIAM to auto-mask when MSI-X interrupt is asserted
                 * this saves a register write for every interrupt
@@ -3376,98 +3504,33 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
                IXGBE_WRITE_REG(hw, IXGBE_EIAM, IXGBE_EICS_RTX_QUEUE);
        }
 
-       /* Enable Thermal over heat sensor interrupt */
-       if (adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE) {
-               gpie = IXGBE_READ_REG(hw, IXGBE_GPIE);
-               gpie |= IXGBE_SDP0_GPIEN;
-               IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie);
+       /* XXX: to interrupt immediately for EICS writes, enable this */
+       /* gpie |= IXGBE_GPIE_EIMEN; */
+
+       if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED) {
+               gpie &= ~IXGBE_GPIE_VTMODE_MASK;
+               gpie |= IXGBE_GPIE_VTMODE_64;
        }
 
-       /* Enable fan failure interrupt if media type is copper */
-       if (adapter->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE) {
-               gpie = IXGBE_READ_REG(hw, IXGBE_GPIE);
+       /* Enable fan failure interrupt */
+       if (adapter->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE)
                gpie |= IXGBE_SDP1_GPIEN;
-               IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie);
-       }
 
-       if (hw->mac.type == ixgbe_mac_82599EB) {
-               gpie = IXGBE_READ_REG(hw, IXGBE_GPIE);
+       if (hw->mac.type == ixgbe_mac_82599EB)
                gpie |= IXGBE_SDP1_GPIEN;
                gpie |= IXGBE_SDP2_GPIEN;
-               IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie);
-       }
-
-#ifdef IXGBE_FCOE
-       /* adjust max frame to be able to do baby jumbo for FCoE */
-       if ((netdev->features & NETIF_F_FCOE_MTU) &&
-           (max_frame < IXGBE_FCOE_JUMBO_FRAME_SIZE))
-               max_frame = IXGBE_FCOE_JUMBO_FRAME_SIZE;
 
-#endif /* IXGBE_FCOE */
-       mhadd = IXGBE_READ_REG(hw, IXGBE_MHADD);
-       if (max_frame != (mhadd >> IXGBE_MHADD_MFS_SHIFT)) {
-               mhadd &= ~IXGBE_MHADD_MFS_MASK;
-               mhadd |= max_frame << IXGBE_MHADD_MFS_SHIFT;
-
-               IXGBE_WRITE_REG(hw, IXGBE_MHADD, mhadd);
-       }
-
-       for (i = 0; i < adapter->num_tx_queues; i++) {
-               j = adapter->tx_ring[i]->reg_idx;
-               txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(j));
-               if (adapter->rx_itr_setting == 0) {
-                       /* cannot set wthresh when itr==0 */
-                       txdctl &= ~0x007F0000;
-               } else {
-                       /* enable WTHRESH=8 descriptors, to encourage burst writeback */
-                       txdctl |= (8 << 16);
-               }
-               IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(j), txdctl);
-       }
+       IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie);
+}
 
-       if (hw->mac.type == ixgbe_mac_82599EB) {
-               /* DMATXCTL.EN must be set after all Tx queue config is done */
-               dmatxctl = IXGBE_READ_REG(hw, IXGBE_DMATXCTL);
-               dmatxctl |= IXGBE_DMATXCTL_TE;
-               IXGBE_WRITE_REG(hw, IXGBE_DMATXCTL, dmatxctl);
-       }
-       for (i = 0; i < adapter->num_tx_queues; i++) {
-               j = adapter->tx_ring[i]->reg_idx;
-               txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(j));
-               txdctl |= IXGBE_TXDCTL_ENABLE;
-               IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(j), txdctl);
-               if (hw->mac.type == ixgbe_mac_82599EB) {
-                       int wait_loop = 10;
-                       /* poll for Tx Enable ready */
-                       do {
-                               msleep(1);
-                               txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(j));
-                       } while (--wait_loop &&
-                                !(txdctl & IXGBE_TXDCTL_ENABLE));
-                       if (!wait_loop)
-                               e_err(drv, "Could not enable Tx Queue %d\n", j);
-               }
-       }
+static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
+{
+       struct ixgbe_hw *hw = &adapter->hw;
+       int err;
+       u32 ctrl_ext;
 
-       for (i = 0; i < num_rx_rings; i++) {
-               j = adapter->rx_ring[i]->reg_idx;
-               rxdctl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(j));
-               /* enable PTHRESH=32 descriptors (half the internal cache)
-                * and HTHRESH=0 descriptors (to minimize latency on fetch),
-                * this also removes a pesky rx_no_buffer_count increment */
-               rxdctl |= 0x0020;
-               rxdctl |= IXGBE_RXDCTL_ENABLE;
-               IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(j), rxdctl);
-               if (hw->mac.type == ixgbe_mac_82599EB)
-                       ixgbe_rx_desc_queue_enable(adapter, i);
-       }
-       /* enable all receives */
-       rxdctl = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
-       if (hw->mac.type == ixgbe_mac_82598EB)
-               rxdctl |= (IXGBE_RXCTRL_DMBYPS | IXGBE_RXCTRL_RXEN);
-       else
-               rxdctl |= IXGBE_RXCTRL_RXEN;
-       hw->mac.ops.enable_rx_dma(hw, rxdctl);
+       ixgbe_get_hw_control(adapter);
+       ixgbe_setup_gpie(adapter);
 
        if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED)
                ixgbe_configure_msix(adapter);
@@ -3483,7 +3546,6 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
 
        /* clear any pending interrupts, may auto mask */
        IXGBE_READ_REG(hw, IXGBE_EICR);
-
        ixgbe_irq_enable(adapter);
 
        /*
@@ -3525,12 +3587,8 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
                        e_err(probe, "link_config FAILED %d\n", err);
        }
 
-       for (i = 0; i < adapter->num_tx_queues; i++)
-               set_bit(__IXGBE_FDIR_INIT_DONE,
-                       &(adapter->tx_ring[i]->reinit_state));
-
        /* enable transmits */
-       netif_tx_start_all_queues(netdev);
+       netif_tx_start_all_queues(adapter->netdev);
 
        /* bring the link up in the watchdog, this could race with our first
         * link up interrupt but shouldn't be a problem */
@@ -3609,21 +3667,24 @@ void ixgbe_reset(struct ixgbe_adapter *adapter)
  * @rx_ring: ring to free buffers from
  **/
 static void ixgbe_clean_rx_ring(struct ixgbe_adapter *adapter,
-                                struct ixgbe_ring *rx_ring)
+                               struct ixgbe_ring *rx_ring)
 {
        struct pci_dev *pdev = adapter->pdev;
        unsigned long size;
        unsigned int i;
 
-       /* Free all the Rx ring sk_buffs */
+       /* ring already cleared, nothing to do */
+       if (!rx_ring->rx_buffer_info)
+               return;
 
+       /* Free all the Rx ring sk_buffs */
        for (i = 0; i < rx_ring->count; i++) {
                struct ixgbe_rx_buffer *rx_buffer_info;
 
                rx_buffer_info = &rx_ring->rx_buffer_info[i];
                if (rx_buffer_info->dma) {
                        dma_unmap_single(&pdev->dev, rx_buffer_info->dma,
-                                        rx_ring->rx_buf_len,
+                                        rx_ring->rx_buf_len,
                                         DMA_FROM_DEVICE);
                        rx_buffer_info->dma = 0;
                }
@@ -3635,7 +3696,7 @@ static void ixgbe_clean_rx_ring(struct ixgbe_adapter *adapter,
                                if (IXGBE_RSC_CB(this)->delay_unmap) {
                                        dma_unmap_single(&pdev->dev,
                                                         IXGBE_RSC_CB(this)->dma,
-                                                        rx_ring->rx_buf_len,
+                                                        rx_ring->rx_buf_len,
                                                         DMA_FROM_DEVICE);
                                        IXGBE_RSC_CB(this)->dma = 0;
                                        IXGBE_RSC_CB(skb)->delay_unmap = false;
@@ -3677,14 +3738,17 @@ static void ixgbe_clean_rx_ring(struct ixgbe_adapter *adapter,
  * @tx_ring: ring to be cleaned
  **/
 static void ixgbe_clean_tx_ring(struct ixgbe_adapter *adapter,
-                                struct ixgbe_ring *tx_ring)
+                               struct ixgbe_ring *tx_ring)
 {
        struct ixgbe_tx_buffer *tx_buffer_info;
        unsigned long size;
        unsigned int i;
 
-       /* Free all the Tx ring sk_buffs */
+       /* ring already cleared, nothing to do */
+       if (!tx_ring->tx_buffer_info)
+               return;
 
+       /* Free all the Tx ring sk_buffs */
        for (i = 0; i < tx_ring->count; i++) {
                tx_buffer_info = &tx_ring->tx_buffer_info[i];
                ixgbe_unmap_and_free_tx_resource(adapter, tx_buffer_info);
@@ -3786,13 +3850,13 @@ void ixgbe_down(struct ixgbe_adapter *adapter)
                j = adapter->tx_ring[i]->reg_idx;
                txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(j));
                IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(j),
-                               (txdctl & ~IXGBE_TXDCTL_ENABLE));
+                               (txdctl & ~IXGBE_TXDCTL_ENABLE));
        }
        /* Disable the Tx DMA engine on 82599 */
        if (hw->mac.type == ixgbe_mac_82599EB)
                IXGBE_WRITE_REG(hw, IXGBE_DMATXCTL,
-                               (IXGBE_READ_REG(hw, IXGBE_DMATXCTL) &
-                                ~IXGBE_DMATXCTL_TE));
+                               (IXGBE_READ_REG(hw, IXGBE_DMATXCTL) &
+                                ~IXGBE_DMATXCTL_TE));
 
        /* power down the optics */
        if (hw->phy.multispeed_fiber)
@@ -3822,7 +3886,7 @@ void ixgbe_down(struct ixgbe_adapter *adapter)
 static int ixgbe_poll(struct napi_struct *napi, int budget)
 {
        struct ixgbe_q_vector *q_vector =
-                               container_of(napi, struct ixgbe_q_vector, napi);
+                               container_of(napi, struct ixgbe_q_vector, napi);
        struct ixgbe_adapter *adapter = q_vector->adapter;
        int tx_clean_complete, work_done = 0;
 
@@ -3932,7 +3996,7 @@ static inline bool ixgbe_set_rss_queues(struct ixgbe_adapter *adapter)
  * Rx load across CPUs using RSS.
  *
  **/
-static bool inline ixgbe_set_fdir_queues(struct ixgbe_adapter *adapter)
+static inline bool ixgbe_set_fdir_queues(struct ixgbe_adapter *adapter)
 {
        bool ret = false;
        struct ixgbe_ring_feature *f_fdir = &adapter->ring_feature[RING_F_FDIR];
@@ -4061,7 +4125,7 @@ done:
 }
 
 static void ixgbe_acquire_msix_vectors(struct ixgbe_adapter *adapter,
-                                       int vectors)
+                                      int vectors)
 {
        int err, vector_threshold;
 
@@ -4080,7 +4144,7 @@ static void ixgbe_acquire_msix_vectors(struct ixgbe_adapter *adapter,
         */
        while (vectors >= vector_threshold) {
                err = pci_enable_msix(adapter->pdev, adapter->msix_entries,
-                                     vectors);
+                                     vectors);
                if (!err) /* Success in acquiring all requested vectors. */
                        break;
                else if (err < 0)
@@ -4107,7 +4171,7 @@ static void ixgbe_acquire_msix_vectors(struct ixgbe_adapter *adapter,
                 * vectors we were allocated.
                 */
                adapter->num_msix_vectors = min(vectors,
-                                  adapter->max_msix_q_vectors + NON_Q_VECTORS);
+                                  adapter->max_msix_q_vectors + NON_Q_VECTORS);
        }
 }
 
@@ -4178,12 +4242,12 @@ static inline bool ixgbe_cache_ring_dcb(struct ixgbe_adapter *adapter)
                                }
                                for ( ; i < 5; i++) {
                                        adapter->tx_ring[i]->reg_idx =
-                                                                ((i + 2) << 4);
+                                                                ((i + 2) << 4);
                                        adapter->rx_ring[i]->reg_idx = i << 4;
                                }
                                for ( ; i < dcb_i; i++) {
                                        adapter->tx_ring[i]->reg_idx =
-                                                                ((i + 8) << 3);
+                                                                ((i + 8) << 3);
                                        adapter->rx_ring[i]->reg_idx = i << 4;
                                }
 
@@ -4226,7 +4290,7 @@ static inline bool ixgbe_cache_ring_dcb(struct ixgbe_adapter *adapter)
  * Cache the descriptor ring offsets for Flow Director to the assigned rings.
  *
  **/
-static bool inline ixgbe_cache_ring_fdir(struct ixgbe_adapter *adapter)
+static inline bool ixgbe_cache_ring_fdir(struct ixgbe_adapter *adapter)
 {
        int i;
        bool ret = false;
@@ -4383,7 +4447,7 @@ static int ixgbe_alloc_queues(struct ixgbe_adapter *adapter)
                        adapter->node = cur_node;
                }
                ring = kzalloc_node(sizeof(struct ixgbe_ring), GFP_KERNEL,
-                                   adapter->node);
+                                   adapter->node);
                if (!ring)
                        ring = kzalloc(sizeof(struct ixgbe_ring), GFP_KERNEL);
                if (!ring)
@@ -4407,7 +4471,7 @@ static int ixgbe_alloc_queues(struct ixgbe_adapter *adapter)
                        adapter->node = cur_node;
                }
                ring = kzalloc_node(sizeof(struct ixgbe_ring), GFP_KERNEL,
-                                   adapter->node);
+                                   adapter->node);
                if (!ring)
                        ring = kzalloc(sizeof(struct ixgbe_ring), GFP_KERNEL);
                if (!ring)
@@ -4453,7 +4517,7 @@ static int ixgbe_set_interrupt_capability(struct ixgbe_adapter *adapter)
         * (roughly) the same number of vectors as there are CPU's.
         */
        v_budget = min(adapter->num_rx_queues + adapter->num_tx_queues,
-                      (int)num_online_cpus()) + NON_Q_VECTORS;
+                      (int)num_online_cpus()) + NON_Q_VECTORS;
 
        /*
         * At the same time, hardware can only support a maximum of
@@ -4467,7 +4531,7 @@ static int ixgbe_set_interrupt_capability(struct ixgbe_adapter *adapter)
        /* A failure in MSI-X entry allocation isn't fatal, but it does
         * mean we disable MSI-X capabilities of the adapter. */
        adapter->msix_entries = kcalloc(v_budget,
-                                       sizeof(struct msix_entry), GFP_KERNEL);
+                                       sizeof(struct msix_entry), GFP_KERNEL);
        if (adapter->msix_entries) {
                for (vector = 0; vector < v_budget; vector++)
                        adapter->msix_entries[vector].entry = vector;
@@ -4529,10 +4593,10 @@ static int ixgbe_alloc_q_vectors(struct ixgbe_adapter *adapter)
 
        for (q_idx = 0; q_idx < num_q_vectors; q_idx++) {
                q_vector = kzalloc_node(sizeof(struct ixgbe_q_vector),
-                                       GFP_KERNEL, adapter->node);
+                                       GFP_KERNEL, adapter->node);
                if (!q_vector)
                        q_vector = kzalloc(sizeof(struct ixgbe_q_vector),
-                                          GFP_KERNEL);
+                                          GFP_KERNEL);
                if (!q_vector)
                        goto err_out;
                q_vector->adapter = adapter;
@@ -4693,8 +4757,8 @@ static void ixgbe_sfp_timer(unsigned long data)
 static void ixgbe_sfp_task(struct work_struct *work)
 {
        struct ixgbe_adapter *adapter = container_of(work,
-                                                    struct ixgbe_adapter,
-                                                    sfp_task);
+                                                    struct ixgbe_adapter,
+                                                    sfp_task);
        struct ixgbe_hw *hw = &adapter->hw;
 
        if ((hw->phy.type == ixgbe_phy_nl) &&
@@ -4719,7 +4783,7 @@ static void ixgbe_sfp_task(struct work_struct *work)
 reschedule:
        if (test_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state))
                mod_timer(&adapter->sfp_timer,
-                         round_jiffies(jiffies + (2 * HZ)));
+                         round_jiffies(jiffies + (2 * HZ)));
 }
 
 /**
@@ -4775,7 +4839,7 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter)
                        adapter->atr_sample_rate = 20;
                }
                adapter->ring_feature[RING_F_FDIR].indices =
-                                                        IXGBE_MAX_FDIR_INDICES;
+                                                        IXGBE_MAX_FDIR_INDICES;
                adapter->fdir_pballoc = 0;
 #ifdef IXGBE_FCOE
                adapter->flags |= IXGBE_FLAG_FCOE_CAPABLE;
@@ -4806,7 +4870,7 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter)
        adapter->dcb_cfg.round_robin_enable = false;
        adapter->dcb_set_bitmap = 0x00;
        ixgbe_copy_dcb_cfg(&adapter->dcb_cfg, &adapter->temp_dcb_cfg,
-                          adapter->ring_feature[RING_F_DCB].indices);
+                          adapter->ring_feature[RING_F_DCB].indices);
 
 #endif
 
@@ -4861,7 +4925,7 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter)
  * Return 0 on success, negative on failure
  **/
 int ixgbe_setup_tx_resources(struct ixgbe_adapter *adapter,
-                             struct ixgbe_ring *tx_ring)
+                            struct ixgbe_ring *tx_ring)
 {
        struct pci_dev *pdev = adapter->pdev;
        int size;
@@ -4928,7 +4992,7 @@ static int ixgbe_setup_all_tx_resources(struct ixgbe_adapter *adapter)
  * Returns 0 on success, negative on failure
  **/
 int ixgbe_setup_rx_resources(struct ixgbe_adapter *adapter,
-                             struct ixgbe_ring *rx_ring)
+                            struct ixgbe_ring *rx_ring)
 {
        struct pci_dev *pdev = adapter->pdev;
        int size;
@@ -5001,7 +5065,7 @@ static int ixgbe_setup_all_rx_resources(struct ixgbe_adapter *adapter)
  * Free all transmit software resources
  **/
 void ixgbe_free_tx_resources(struct ixgbe_adapter *adapter,
-                             struct ixgbe_ring *tx_ring)
+                            struct ixgbe_ring *tx_ring)
 {
        struct pci_dev *pdev = adapter->pdev;
 
@@ -5039,7 +5103,7 @@ static void ixgbe_free_all_tx_resources(struct ixgbe_adapter *adapter)
  * Free all receive software resources
  **/
 void ixgbe_free_rx_resources(struct ixgbe_adapter *adapter,
-                             struct ixgbe_ring *rx_ring)
+                            struct ixgbe_ring *rx_ring)
 {
        struct pci_dev *pdev = adapter->pdev;
 
@@ -5333,6 +5397,7 @@ void ixgbe_update_stats(struct ixgbe_adapter *adapter)
        u64 total_mpc = 0;
        u32 i, missed_rx = 0, mpc, bprc, lxon, lxoff, xon_off_tot;
        u64 non_eop_descs = 0, restart_queue = 0;
+       struct ixgbe_hw_stats *hwstats = &adapter->stats;
 
        if (test_bit(__IXGBE_DOWN, &adapter->state) ||
            test_bit(__IXGBE_RESETTING, &adapter->state))
@@ -5343,7 +5408,7 @@ void ixgbe_update_stats(struct ixgbe_adapter *adapter)
                u64 rsc_flush = 0;
                for (i = 0; i < 16; i++)
                        adapter->hw_rx_no_dma_resources +=
-                                            IXGBE_READ_REG(hw, IXGBE_QPRDC(i));
+                               IXGBE_READ_REG(hw, IXGBE_QPRDC(i));
                for (i = 0; i < adapter->num_rx_queues; i++) {
                        rsc_count += adapter->rx_ring[i]->rsc_count;
                        rsc_flush += adapter->rx_ring[i]->rsc_flush;
@@ -5361,119 +5426,118 @@ void ixgbe_update_stats(struct ixgbe_adapter *adapter)
                non_eop_descs += adapter->rx_ring[i]->non_eop_descs;
        adapter->non_eop_descs = non_eop_descs;
 
-       adapter->stats.crcerrs += IXGBE_READ_REG(hw, IXGBE_CRCERRS);
+       hwstats->crcerrs += IXGBE_READ_REG(hw, IXGBE_CRCERRS);
        for (i = 0; i < 8; i++) {
                /* for packet buffers not used, the register should read 0 */
                mpc = IXGBE_READ_REG(hw, IXGBE_MPC(i));
                missed_rx += mpc;
-               adapter->stats.mpc[i] += mpc;
-               total_mpc += adapter->stats.mpc[i];
+               hwstats->mpc[i] += mpc;
+               total_mpc += hwstats->mpc[i];
                if (hw->mac.type == ixgbe_mac_82598EB)
-                       adapter->stats.rnbc[i] += IXGBE_READ_REG(hw, IXGBE_RNBC(i));
-               adapter->stats.qptc[i] += IXGBE_READ_REG(hw, IXGBE_QPTC(i));
-               adapter->stats.qbtc[i] += IXGBE_READ_REG(hw, IXGBE_QBTC(i));
-               adapter->stats.qprc[i] += IXGBE_READ_REG(hw, IXGBE_QPRC(i));
-               adapter->stats.qbrc[i] += IXGBE_READ_REG(hw, IXGBE_QBRC(i));
+                       hwstats->rnbc[i] += IXGBE_READ_REG(hw, IXGBE_RNBC(i));
+               hwstats->qptc[i] += IXGBE_READ_REG(hw, IXGBE_QPTC(i));
+               hwstats->qbtc[i] += IXGBE_READ_REG(hw, IXGBE_QBTC(i));
+               hwstats->qprc[i] += IXGBE_READ_REG(hw, IXGBE_QPRC(i));
+               hwstats->qbrc[i] += IXGBE_READ_REG(hw, IXGBE_QBRC(i));
                if (hw->mac.type == ixgbe_mac_82599EB) {
-                       adapter->stats.pxonrxc[i] += IXGBE_READ_REG(hw,
-                                                           IXGBE_PXONRXCNT(i));
-                       adapter->stats.pxoffrxc[i] += IXGBE_READ_REG(hw,
-                                                          IXGBE_PXOFFRXCNT(i));
-                       adapter->stats.qprdc[i] += IXGBE_READ_REG(hw, IXGBE_QPRDC(i));
+                       hwstats->pxonrxc[i] +=
+                               IXGBE_READ_REG(hw, IXGBE_PXONRXCNT(i));
+                       hwstats->pxoffrxc[i] +=
+                               IXGBE_READ_REG(hw, IXGBE_PXOFFRXCNT(i));
+                       hwstats->qprdc[i] += IXGBE_READ_REG(hw, IXGBE_QPRDC(i));
                } else {
-                       adapter->stats.pxonrxc[i] += IXGBE_READ_REG(hw,
-                                                             IXGBE_PXONRXC(i));
-                       adapter->stats.pxoffrxc[i] += IXGBE_READ_REG(hw,
-                                                            IXGBE_PXOFFRXC(i));
+                       hwstats->pxonrxc[i] +=
+                               IXGBE_READ_REG(hw, IXGBE_PXONRXC(i));
+                       hwstats->pxoffrxc[i] +=
+                               IXGBE_READ_REG(hw, IXGBE_PXOFFRXC(i));
                }
-               adapter->stats.pxontxc[i] += IXGBE_READ_REG(hw,
-                                                           IXGBE_PXONTXC(i));
-               adapter->stats.pxofftxc[i] += IXGBE_READ_REG(hw,
-                                                            IXGBE_PXOFFTXC(i));
+               hwstats->pxontxc[i] += IXGBE_READ_REG(hw, IXGBE_PXONTXC(i));
+               hwstats->pxofftxc[i] += IXGBE_READ_REG(hw, IXGBE_PXOFFTXC(i));
        }
-       adapter->stats.gprc += IXGBE_READ_REG(hw, IXGBE_GPRC);
+       hwstats->gprc += IXGBE_READ_REG(hw, IXGBE_GPRC);
        /* work around hardware counting issue */
-       adapter->stats.gprc -= missed_rx;
+       hwstats->gprc -= missed_rx;
 
        /* 82598 hardware only has a 32 bit counter in the high register */
        if (hw->mac.type == ixgbe_mac_82599EB) {
                u64 tmp;
-               adapter->stats.gorc += IXGBE_READ_REG(hw, IXGBE_GORCL);
-               tmp = IXGBE_READ_REG(hw, IXGBE_GORCH) & 0xF; /* 4 high bits of GORC */
-               adapter->stats.gorc += (tmp << 32);
-               adapter->stats.gotc += IXGBE_READ_REG(hw, IXGBE_GOTCL);
-               tmp = IXGBE_READ_REG(hw, IXGBE_GOTCH) & 0xF; /* 4 high bits of GOTC */
-               adapter->stats.gotc += (tmp << 32);
-               adapter->stats.tor += IXGBE_READ_REG(hw, IXGBE_TORL);
-               IXGBE_READ_REG(hw, IXGBE_TORH); /* to clear */
-               adapter->stats.lxonrxc += IXGBE_READ_REG(hw, IXGBE_LXONRXCNT);
-               adapter->stats.lxoffrxc += IXGBE_READ_REG(hw, IXGBE_LXOFFRXCNT);
-               adapter->stats.fdirmatch += IXGBE_READ_REG(hw, IXGBE_FDIRMATCH);
-               adapter->stats.fdirmiss += IXGBE_READ_REG(hw, IXGBE_FDIRMISS);
+               hwstats->gorc += IXGBE_READ_REG(hw, IXGBE_GORCL);
+               tmp = IXGBE_READ_REG(hw, IXGBE_GORCH) & 0xF;
+                                               /* 4 high bits of GORC */
+               hwstats->gorc += (tmp << 32);
+               hwstats->gotc += IXGBE_READ_REG(hw, IXGBE_GOTCL);
+               tmp = IXGBE_READ_REG(hw, IXGBE_GOTCH) & 0xF;
+                                               /* 4 high bits of GOTC */
+               hwstats->gotc += (tmp << 32);
+               hwstats->tor += IXGBE_READ_REG(hw, IXGBE_TORL);
+               IXGBE_READ_REG(hw, IXGBE_TORH); /* to clear */
+               hwstats->lxonrxc += IXGBE_READ_REG(hw, IXGBE_LXONRXCNT);
+               hwstats->lxoffrxc += IXGBE_READ_REG(hw, IXGBE_LXOFFRXCNT);
+               hwstats->fdirmatch += IXGBE_READ_REG(hw, IXGBE_FDIRMATCH);
+               hwstats->fdirmiss += IXGBE_READ_REG(hw, IXGBE_FDIRMISS);
 #ifdef IXGBE_FCOE
-               adapter->stats.fccrc += IXGBE_READ_REG(hw, IXGBE_FCCRC);
-               adapter->stats.fcoerpdc += IXGBE_READ_REG(hw, IXGBE_FCOERPDC);
-               adapter->stats.fcoeprc += IXGBE_READ_REG(hw, IXGBE_FCOEPRC);
-               adapter->stats.fcoeptc += IXGBE_READ_REG(hw, IXGBE_FCOEPTC);
-               adapter->stats.fcoedwrc += IXGBE_READ_REG(hw, IXGBE_FCOEDWRC);
-               adapter->stats.fcoedwtc += IXGBE_READ_REG(hw, IXGBE_FCOEDWTC);
+               hwstats->fccrc += IXGBE_READ_REG(hw, IXGBE_FCCRC);
+               hwstats->fcoerpdc += IXGBE_READ_REG(hw, IXGBE_FCOERPDC);
+               hwstats->fcoeprc += IXGBE_READ_REG(hw, IXGBE_FCOEPRC);
+               hwstats->fcoeptc += IXGBE_READ_REG(hw, IXGBE_FCOEPTC);
+               hwstats->fcoedwrc += IXGBE_READ_REG(hw, IXGBE_FCOEDWRC);
+               hwstats->fcoedwtc += IXGBE_READ_REG(hw, IXGBE_FCOEDWTC);
 #endif /* IXGBE_FCOE */
        } else {
-               adapter->stats.lxonrxc += IXGBE_READ_REG(hw, IXGBE_LXONRXC);
-               adapter->stats.lxoffrxc += IXGBE_READ_REG(hw, IXGBE_LXOFFRXC);
-               adapter->stats.gorc += IXGBE_READ_REG(hw, IXGBE_GORCH);
-               adapter->stats.gotc += IXGBE_READ_REG(hw, IXGBE_GOTCH);
-               adapter->stats.tor += IXGBE_READ_REG(hw, IXGBE_TORH);
+               hwstats->lxonrxc += IXGBE_READ_REG(hw, IXGBE_LXONRXC);
+               hwstats->lxoffrxc += IXGBE_READ_REG(hw, IXGBE_LXOFFRXC);
+               hwstats->gorc += IXGBE_READ_REG(hw, IXGBE_GORCH);
+               hwstats->gotc += IXGBE_READ_REG(hw, IXGBE_GOTCH);
+               hwstats->tor += IXGBE_READ_REG(hw, IXGBE_TORH);
        }
        bprc = IXGBE_READ_REG(hw, IXGBE_BPRC);
-       adapter->stats.bprc += bprc;
-       adapter->stats.mprc += IXGBE_READ_REG(hw, IXGBE_MPRC);
+       hwstats->bprc += bprc;
+       hwstats->mprc += IXGBE_READ_REG(hw, IXGBE_MPRC);
        if (hw->mac.type == ixgbe_mac_82598EB)
-               adapter->stats.mprc -= bprc;
-       adapter->stats.roc += IXGBE_READ_REG(hw, IXGBE_ROC);
-       adapter->stats.prc64 += IXGBE_READ_REG(hw, IXGBE_PRC64);
-       adapter->stats.prc127 += IXGBE_READ_REG(hw, IXGBE_PRC127);
-       adapter->stats.prc255 += IXGBE_READ_REG(hw, IXGBE_PRC255);
-       adapter->stats.prc511 += IXGBE_READ_REG(hw, IXGBE_PRC511);
-       adapter->stats.prc1023 += IXGBE_READ_REG(hw, IXGBE_PRC1023);
-       adapter->stats.prc1522 += IXGBE_READ_REG(hw, IXGBE_PRC1522);
-       adapter->stats.rlec += IXGBE_READ_REG(hw, IXGBE_RLEC);
+               hwstats->mprc -= bprc;
+       hwstats->roc += IXGBE_READ_REG(hw, IXGBE_ROC);
+       hwstats->prc64 += IXGBE_READ_REG(hw, IXGBE_PRC64);
+       hwstats->prc127 += IXGBE_READ_REG(hw, IXGBE_PRC127);
+       hwstats->prc255 += IXGBE_READ_REG(hw, IXGBE_PRC255);
+       hwstats->prc511 += IXGBE_READ_REG(hw, IXGBE_PRC511);
+       hwstats->prc1023 += IXGBE_READ_REG(hw, IXGBE_PRC1023);
+       hwstats->prc1522 += IXGBE_READ_REG(hw, IXGBE_PRC1522);
+       hwstats->rlec += IXGBE_READ_REG(hw, IXGBE_RLEC);
        lxon = IXGBE_READ_REG(hw, IXGBE_LXONTXC);
-       adapter->stats.lxontxc += lxon;
+       hwstats->lxontxc += lxon;
        lxoff = IXGBE_READ_REG(hw, IXGBE_LXOFFTXC);
-       adapter->stats.lxofftxc += lxoff;
-       adapter->stats.ruc += IXGBE_READ_REG(hw, IXGBE_RUC);
-       adapter->stats.gptc += IXGBE_READ_REG(hw, IXGBE_GPTC);
-       adapter->stats.mptc += IXGBE_READ_REG(hw, IXGBE_MPTC);
+       hwstats->lxofftxc += lxoff;
+       hwstats->ruc += IXGBE_READ_REG(hw, IXGBE_RUC);
+       hwstats->gptc += IXGBE_READ_REG(hw, IXGBE_GPTC);
+       hwstats->mptc += IXGBE_READ_REG(hw, IXGBE_MPTC);
        /*
         * 82598 errata - tx of flow control packets is included in tx counters
         */
        xon_off_tot = lxon + lxoff;
-       adapter->stats.gptc -= xon_off_tot;
-       adapter->stats.mptc -= xon_off_tot;
-       adapter->stats.gotc -= (xon_off_tot * (ETH_ZLEN + ETH_FCS_LEN));
-       adapter->stats.ruc += IXGBE_READ_REG(hw, IXGBE_RUC);
-       adapter->stats.rfc += IXGBE_READ_REG(hw, IXGBE_RFC);
-       adapter->stats.rjc += IXGBE_READ_REG(hw, IXGBE_RJC);
-       adapter->stats.tpr += IXGBE_READ_REG(hw, IXGBE_TPR);
-       adapter->stats.ptc64 += IXGBE_READ_REG(hw, IXGBE_PTC64);
-       adapter->stats.ptc64 -= xon_off_tot;
-       adapter->stats.ptc127 += IXGBE_READ_REG(hw, IXGBE_PTC127);
-       adapter->stats.ptc255 += IXGBE_READ_REG(hw, IXGBE_PTC255);
-       adapter->stats.ptc511 += IXGBE_READ_REG(hw, IXGBE_PTC511);
-       adapter->stats.ptc1023 += IXGBE_READ_REG(hw, IXGBE_PTC1023);
-       adapter->stats.ptc1522 += IXGBE_READ_REG(hw, IXGBE_PTC1522);
-       adapter->stats.bptc += IXGBE_READ_REG(hw, IXGBE_BPTC);
+       hwstats->gptc -= xon_off_tot;
+       hwstats->mptc -= xon_off_tot;
+       hwstats->gotc -= (xon_off_tot * (ETH_ZLEN + ETH_FCS_LEN));
+       hwstats->ruc += IXGBE_READ_REG(hw, IXGBE_RUC);
+       hwstats->rfc += IXGBE_READ_REG(hw, IXGBE_RFC);
+       hwstats->rjc += IXGBE_READ_REG(hw, IXGBE_RJC);
+       hwstats->tpr += IXGBE_READ_REG(hw, IXGBE_TPR);
+       hwstats->ptc64 += IXGBE_READ_REG(hw, IXGBE_PTC64);
+       hwstats->ptc64 -= xon_off_tot;
+       hwstats->ptc127 += IXGBE_READ_REG(hw, IXGBE_PTC127);
+       hwstats->ptc255 += IXGBE_READ_REG(hw, IXGBE_PTC255);
+       hwstats->ptc511 += IXGBE_READ_REG(hw, IXGBE_PTC511);
+       hwstats->ptc1023 += IXGBE_READ_REG(hw, IXGBE_PTC1023);
+       hwstats->ptc1522 += IXGBE_READ_REG(hw, IXGBE_PTC1522);
+       hwstats->bptc += IXGBE_READ_REG(hw, IXGBE_BPTC);
 
        /* Fill out the OS statistics structure */
-       netdev->stats.multicast = adapter->stats.mprc;
+       netdev->stats.multicast = hwstats->mprc;
 
        /* Rx Errors */
-       netdev->stats.rx_errors = adapter->stats.crcerrs +
-                                      adapter->stats.rlec;
+       netdev->stats.rx_errors = hwstats->crcerrs + hwstats->rlec;
        netdev->stats.rx_dropped = 0;
-       netdev->stats.rx_length_errors = adapter->stats.rlec;
-       netdev->stats.rx_crc_errors = adapter->stats.crcerrs;
+       netdev->stats.rx_length_errors = hwstats->rlec;
+       netdev->stats.rx_crc_errors = hwstats->crcerrs;
        netdev->stats.rx_missed_errors = total_mpc;
 }
 
@@ -5532,8 +5596,8 @@ watchdog_short_circuit:
 static void ixgbe_multispeed_fiber_task(struct work_struct *work)
 {
        struct ixgbe_adapter *adapter = container_of(work,
-                                                    struct ixgbe_adapter,
-                                                    multispeed_fiber_task);
+                                                    struct ixgbe_adapter,
+                                                    multispeed_fiber_task);
        struct ixgbe_hw *hw = &adapter->hw;
        u32 autoneg;
        bool negotiation;
@@ -5556,8 +5620,8 @@ static void ixgbe_multispeed_fiber_task(struct work_struct *work)
 static void ixgbe_sfp_config_module_task(struct work_struct *work)
 {
        struct ixgbe_adapter *adapter = container_of(work,
-                                                    struct ixgbe_adapter,
-                                                    sfp_config_module_task);
+                                                    struct ixgbe_adapter,
+                                                    sfp_config_module_task);
        struct ixgbe_hw *hw = &adapter->hw;
        u32 err;
 
@@ -5590,15 +5654,15 @@ static void ixgbe_sfp_config_module_task(struct work_struct *work)
 static void ixgbe_fdir_reinit_task(struct work_struct *work)
 {
        struct ixgbe_adapter *adapter = container_of(work,
-                                                    struct ixgbe_adapter,
-                                                    fdir_reinit_task);
+                                                    struct ixgbe_adapter,
+                                                    fdir_reinit_task);
        struct ixgbe_hw *hw = &adapter->hw;
        int i;
 
        if (ixgbe_reinit_fdir_tables_82599(hw) == 0) {
                for (i = 0; i < adapter->num_tx_queues; i++)
                        set_bit(__IXGBE_FDIR_INIT_DONE,
-                               &(adapter->tx_ring[i]->reinit_state));
+                               &(adapter->tx_ring[i]->reinit_state));
        } else {
                e_err(probe, "failed to finish FDIR re-initialization, "
                      "ignored adding FDIR ATR filters\n");
@@ -5616,8 +5680,8 @@ static DEFINE_MUTEX(ixgbe_watchdog_lock);
 static void ixgbe_watchdog_task(struct work_struct *work)
 {
        struct ixgbe_adapter *adapter = container_of(work,
-                                                    struct ixgbe_adapter,
-                                                    watchdog_task);
+                                                    struct ixgbe_adapter,
+                                                    watchdog_task);
        struct net_device *netdev = adapter->netdev;
        struct ixgbe_hw *hw = &adapter->hw;
        u32 link_speed;
@@ -5648,7 +5712,7 @@ static void ixgbe_watchdog_task(struct work_struct *work)
 
                if (link_up ||
                    time_after(jiffies, (adapter->link_check_timeout +
-                                        IXGBE_TRY_LINK_TIMEOUT))) {
+                                        IXGBE_TRY_LINK_TIMEOUT))) {
                        adapter->flags &= ~IXGBE_FLAG_NEED_LINK_UPDATE;
                        IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMC_LSC);
                }
@@ -5719,8 +5783,8 @@ static void ixgbe_watchdog_task(struct work_struct *work)
 }
 
 static int ixgbe_tso(struct ixgbe_adapter *adapter,
-                     struct ixgbe_ring *tx_ring, struct sk_buff *skb,
-                     u32 tx_flags, u8 *hdr_len)
+                    struct ixgbe_ring *tx_ring, struct sk_buff *skb,
+                    u32 tx_flags, u8 *hdr_len)
 {
        struct ixgbe_adv_tx_context_desc *context_desc;
        unsigned int i;
@@ -5743,28 +5807,28 @@ static int ixgbe_tso(struct ixgbe_adapter *adapter,
                        iph->tot_len = 0;
                        iph->check = 0;
                        tcp_hdr(skb)->check = ~csum_tcpudp_magic(iph->saddr,
-                                                                iph->daddr, 0,
-                                                                IPPROTO_TCP,
-                                                                0);
+                                                                iph->daddr, 0,
+                                                                IPPROTO_TCP,
+                                                                0);
                } else if (skb_is_gso_v6(skb)) {
                        ipv6_hdr(skb)->payload_len = 0;
                        tcp_hdr(skb)->check =
                            ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
-                                            &ipv6_hdr(skb)->daddr,
-                                            0, IPPROTO_TCP, 0);
+                                            &ipv6_hdr(skb)->daddr,
+                                            0, IPPROTO_TCP, 0);
                }
 
                i = tx_ring->next_to_use;
 
                tx_buffer_info = &tx_ring->tx_buffer_info[i];
-               context_desc = IXGBE_TX_CTXTDESC_ADV(*tx_ring, i);
+               context_desc = IXGBE_TX_CTXTDESC_ADV(tx_ring, i);
 
                /* VLAN MACLEN IPLEN */
                if (tx_flags & IXGBE_TX_FLAGS_VLAN)
                        vlan_macip_lens |=
                            (tx_flags & IXGBE_TX_FLAGS_VLAN_MASK);
                vlan_macip_lens |= ((skb_network_offset(skb)) <<
-                                   IXGBE_ADVTXD_MACLEN_SHIFT);
+                                   IXGBE_ADVTXD_MACLEN_SHIFT);
                *hdr_len += skb_network_offset(skb);
                vlan_macip_lens |=
                    (skb_transport_header(skb) - skb_network_header(skb));
@@ -5775,7 +5839,7 @@ static int ixgbe_tso(struct ixgbe_adapter *adapter,
 
                /* ADV DTYP TUCMD MKRLOC/ISCSIHEDLEN */
                type_tucmd_mlhl = (IXGBE_TXD_CMD_DEXT |
-                                  IXGBE_ADVTXD_DTYP_CTXT);
+                                  IXGBE_ADVTXD_DTYP_CTXT);
 
                if (skb->protocol == htons(ETH_P_IP))
                        type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_IPV4;
@@ -5803,9 +5867,53 @@ static int ixgbe_tso(struct ixgbe_adapter *adapter,
        return false;
 }
 
+static u32 ixgbe_psum(struct ixgbe_adapter *adapter, struct sk_buff *skb)
+{
+       u32 rtn = 0;
+       __be16 protocol;
+
+       if (skb->protocol == cpu_to_be16(ETH_P_8021Q))
+               protocol = ((const struct vlan_ethhdr *)skb->data)->
+                                       h_vlan_encapsulated_proto;
+       else
+               protocol = skb->protocol;
+
+       switch (protocol) {
+       case cpu_to_be16(ETH_P_IP):
+               rtn |= IXGBE_ADVTXD_TUCMD_IPV4;
+               switch (ip_hdr(skb)->protocol) {
+               case IPPROTO_TCP:
+                       rtn |= IXGBE_ADVTXD_TUCMD_L4T_TCP;
+                       break;
+               case IPPROTO_SCTP:
+                       rtn |= IXGBE_ADVTXD_TUCMD_L4T_SCTP;
+                       break;
+               }
+               break;
+       case cpu_to_be16(ETH_P_IPV6):
+               /* XXX what about other V6 headers?? */
+               switch (ipv6_hdr(skb)->nexthdr) {
+               case IPPROTO_TCP:
+                       rtn |= IXGBE_ADVTXD_TUCMD_L4T_TCP;
+                       break;
+               case IPPROTO_SCTP:
+                       rtn |= IXGBE_ADVTXD_TUCMD_L4T_SCTP;
+                       break;
+               }
+               break;
+       default:
+               if (unlikely(net_ratelimit()))
+                       e_warn(probe, "partial checksum but proto=%x!\n",
+                              skb->protocol);
+               break;
+       }
+
+       return rtn;
+}
+
 static bool ixgbe_tx_csum(struct ixgbe_adapter *adapter,
-                          struct ixgbe_ring *tx_ring,
-                          struct sk_buff *skb, u32 tx_flags)
+                         struct ixgbe_ring *tx_ring,
+                         struct sk_buff *skb, u32 tx_flags)
 {
        struct ixgbe_adv_tx_context_desc *context_desc;
        unsigned int i;
@@ -5816,63 +5924,25 @@ static bool ixgbe_tx_csum(struct ixgbe_adapter *adapter,
            (tx_flags & IXGBE_TX_FLAGS_VLAN)) {
                i = tx_ring->next_to_use;
                tx_buffer_info = &tx_ring->tx_buffer_info[i];
-               context_desc = IXGBE_TX_CTXTDESC_ADV(*tx_ring, i);
+               context_desc = IXGBE_TX_CTXTDESC_ADV(tx_ring, i);
 
                if (tx_flags & IXGBE_TX_FLAGS_VLAN)
                        vlan_macip_lens |=
                            (tx_flags & IXGBE_TX_FLAGS_VLAN_MASK);
                vlan_macip_lens |= (skb_network_offset(skb) <<
-                                   IXGBE_ADVTXD_MACLEN_SHIFT);
+                                   IXGBE_ADVTXD_MACLEN_SHIFT);
                if (skb->ip_summed == CHECKSUM_PARTIAL)
                        vlan_macip_lens |= (skb_transport_header(skb) -
-                                           skb_network_header(skb));
+                                           skb_network_header(skb));
 
                context_desc->vlan_macip_lens = cpu_to_le32(vlan_macip_lens);
                context_desc->seqnum_seed = 0;
 
                type_tucmd_mlhl |= (IXGBE_TXD_CMD_DEXT |
-                                   IXGBE_ADVTXD_DTYP_CTXT);
-
-               if (skb->ip_summed == CHECKSUM_PARTIAL) {
-                       __be16 protocol;
-
-                       if (skb->protocol == cpu_to_be16(ETH_P_8021Q)) {
-                               const struct vlan_ethhdr *vhdr =
-                                       (const struct vlan_ethhdr *)skb->data;
-
-                               protocol = vhdr->h_vlan_encapsulated_proto;
-                       } else {
-                               protocol = skb->protocol;
-                       }
+                                   IXGBE_ADVTXD_DTYP_CTXT);
 
-                       switch (protocol) {
-                       case cpu_to_be16(ETH_P_IP):
-                               type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_IPV4;
-                               if (ip_hdr(skb)->protocol == IPPROTO_TCP)
-                                       type_tucmd_mlhl |=
-                                               IXGBE_ADVTXD_TUCMD_L4T_TCP;
-                               else if (ip_hdr(skb)->protocol == IPPROTO_SCTP)
-                                       type_tucmd_mlhl |=
-                                               IXGBE_ADVTXD_TUCMD_L4T_SCTP;
-                               break;
-                       case cpu_to_be16(ETH_P_IPV6):
-                               /* XXX what about other V6 headers?? */
-                               if (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP)
-                                       type_tucmd_mlhl |=
-                                               IXGBE_ADVTXD_TUCMD_L4T_TCP;
-                               else if (ipv6_hdr(skb)->nexthdr == IPPROTO_SCTP)
-                                       type_tucmd_mlhl |=
-                                               IXGBE_ADVTXD_TUCMD_L4T_SCTP;
-                               break;
-                       default:
-                               if (unlikely(net_ratelimit())) {
-                                       e_warn(probe, "partial checksum "
-                                              "but proto=%x!\n",
-                                              skb->protocol);
-                               }
-                               break;
-                       }
-               }
+               if (skb->ip_summed == CHECKSUM_PARTIAL)
+                       type_tucmd_mlhl |= ixgbe_psum(adapter, skb);
 
                context_desc->type_tucmd_mlhl = cpu_to_le32(type_tucmd_mlhl);
                /* use index zero for tx checksum offload */
@@ -5893,9 +5963,9 @@ static bool ixgbe_tx_csum(struct ixgbe_adapter *adapter,
 }
 
 static int ixgbe_tx_map(struct ixgbe_adapter *adapter,
-                        struct ixgbe_ring *tx_ring,
-                        struct sk_buff *skb, u32 tx_flags,
-                        unsigned int first)
+                       struct ixgbe_ring *tx_ring,
+                       struct sk_buff *skb, u32 tx_flags,
+                       unsigned int first)
 {
        struct pci_dev *pdev = adapter->pdev;
        struct ixgbe_tx_buffer *tx_buffer_info;
@@ -5990,7 +6060,7 @@ dma_error:
 
        /* clear timestamp and dma mappings for remaining portion of packet */
        while (count--) {
-               if (i==0)
+               if (i == 0)
                        i += tx_ring->count;
                i--;
                tx_buffer_info = &tx_ring->tx_buffer_info[i];
@@ -6001,8 +6071,8 @@ dma_error:
 }
 
 static void ixgbe_tx_queue(struct ixgbe_adapter *adapter,
-                           struct ixgbe_ring *tx_ring,
-                           int tx_flags, int count, u32 paylen, u8 hdr_len)
+                          struct ixgbe_ring *tx_ring,
+                          int tx_flags, int count, u32 paylen, u8 hdr_len)
 {
        union ixgbe_adv_tx_desc *tx_desc = NULL;
        struct ixgbe_tx_buffer *tx_buffer_info;
@@ -6021,17 +6091,17 @@ static void ixgbe_tx_queue(struct ixgbe_adapter *adapter,
                cmd_type_len |= IXGBE_ADVTXD_DCMD_TSE;
 
                olinfo_status |= IXGBE_TXD_POPTS_TXSM <<
-                                IXGBE_ADVTXD_POPTS_SHIFT;
+                                IXGBE_ADVTXD_POPTS_SHIFT;
 
                /* use index 1 context for tso */
                olinfo_status |= (1 << IXGBE_ADVTXD_IDX_SHIFT);
                if (tx_flags & IXGBE_TX_FLAGS_IPV4)
                        olinfo_status |= IXGBE_TXD_POPTS_IXSM <<
-                                        IXGBE_ADVTXD_POPTS_SHIFT;
+                                        IXGBE_ADVTXD_POPTS_SHIFT;
 
        } else if (tx_flags & IXGBE_TX_FLAGS_CSUM)
                olinfo_status |= IXGBE_TXD_POPTS_TXSM <<
-                                IXGBE_ADVTXD_POPTS_SHIFT;
+                                IXGBE_ADVTXD_POPTS_SHIFT;
 
        if (tx_flags & IXGBE_TX_FLAGS_FCOE) {
                olinfo_status |= IXGBE_ADVTXD_CC;
@@ -6045,10 +6115,10 @@ static void ixgbe_tx_queue(struct ixgbe_adapter *adapter,
        i = tx_ring->next_to_use;
        while (count--) {
                tx_buffer_info = &tx_ring->tx_buffer_info[i];
-               tx_desc = IXGBE_TX_DESC_ADV(*tx_ring, i);
+               tx_desc = IXGBE_TX_DESC_ADV(tx_ring, i);
                tx_desc->read.buffer_addr = cpu_to_le64(tx_buffer_info->dma);
                tx_desc->read.cmd_type_len =
-                       cpu_to_le32(cmd_type_len | tx_buffer_info->length);
+                       cpu_to_le32(cmd_type_len | tx_buffer_info->length);
                tx_desc->read.olinfo_status = cpu_to_le32(olinfo_status);
                i++;
                if (i == tx_ring->count)
@@ -6070,7 +6140,7 @@ static void ixgbe_tx_queue(struct ixgbe_adapter *adapter,
 }
 
 static void ixgbe_atr(struct ixgbe_adapter *adapter, struct sk_buff *skb,
-                     int queue, u32 tx_flags)
+                     int queue, u32 tx_flags)
 {
        struct ixgbe_atr_input atr_input;
        struct tcphdr *th;
@@ -6098,7 +6168,7 @@ static void ixgbe_atr(struct ixgbe_adapter *adapter, struct sk_buff *skb,
        memset(&atr_input, 0, sizeof(struct ixgbe_atr_input));
 
        vlan_id = (tx_flags & IXGBE_TX_FLAGS_VLAN_MASK) >>
-                  IXGBE_TX_FLAGS_VLAN_SHIFT;
+                  IXGBE_TX_FLAGS_VLAN_SHIFT;
        src_ipv4_addr = iph->saddr;
        dst_ipv4_addr = iph->daddr;
        flex_bytes = eth->h_proto;
@@ -6117,7 +6187,7 @@ static void ixgbe_atr(struct ixgbe_adapter *adapter, struct sk_buff *skb,
 }
 
 static int __ixgbe_maybe_stop_tx(struct net_device *netdev,
-                                 struct ixgbe_ring *tx_ring, int size)
+                                struct ixgbe_ring *tx_ring, int size)
 {
        netif_stop_subqueue(netdev, tx_ring->queue_index);
        /* Herbert's original patch had:
@@ -6137,7 +6207,7 @@ static int __ixgbe_maybe_stop_tx(struct net_device *netdev,
 }
 
 static int ixgbe_maybe_stop_tx(struct net_device *netdev,
-                              struct ixgbe_ring *tx_ring, int size)
+                             struct ixgbe_ring *tx_ring, int size)
 {
        if (likely(IXGBE_DESC_UNUSED(tx_ring) >= size))
                return 0;
@@ -6183,11 +6253,10 @@ static u16 ixgbe_select_queue(struct net_device *dev, struct sk_buff *skb)
        return skb_tx_hash(dev, skb);
 }
 
-static netdev_tx_t ixgbe_xmit_frame(struct sk_buff *skb,
-                                   struct net_device *netdev)
+netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb, struct net_device *netdev,
+                         struct ixgbe_adapter *adapter,
+                         struct ixgbe_ring *tx_ring)
 {
-       struct ixgbe_adapter *adapter = netdev_priv(netdev);
-       struct ixgbe_ring *tx_ring;
        struct netdev_queue *txq;
        unsigned int first;
        unsigned int tx_flags = 0;
@@ -6211,8 +6280,6 @@ static netdev_tx_t ixgbe_xmit_frame(struct sk_buff *skb,
                tx_flags |= IXGBE_TX_FLAGS_VLAN;
        }
 
-       tx_ring = adapter->tx_ring[skb->queue_mapping];
-
 #ifdef IXGBE_FCOE
        /* for FCoE with DCB, we force the priority to what
         * was specified by the switch */
@@ -6283,10 +6350,10 @@ static netdev_tx_t ixgbe_xmit_frame(struct sk_buff *skb,
                if (tx_ring->atr_sample_rate) {
                        ++tx_ring->atr_count;
                        if ((tx_ring->atr_count >= tx_ring->atr_sample_rate) &&
-                            test_bit(__IXGBE_FDIR_INIT_DONE,
-                                      &tx_ring->reinit_state)) {
+                            test_bit(__IXGBE_FDIR_INIT_DONE,
+                                     &tx_ring->reinit_state)) {
                                ixgbe_atr(adapter, skb, tx_ring->queue_index,
-                                         tx_flags);
+                                         tx_flags);
                                tx_ring->atr_count = 0;
                        }
                }
@@ -6294,7 +6361,7 @@ static netdev_tx_t ixgbe_xmit_frame(struct sk_buff *skb,
                txq->tx_bytes += skb->len;
                txq->tx_packets++;
                ixgbe_tx_queue(adapter, tx_ring, tx_flags, count, skb->len,
-                              hdr_len);
+                              hdr_len);
                ixgbe_maybe_stop_tx(netdev, tx_ring, DESC_NEEDED);
 
        } else {
@@ -6306,6 +6373,15 @@ static netdev_tx_t ixgbe_xmit_frame(struct sk_buff *skb,
        return NETDEV_TX_OK;
 }
 
+static netdev_tx_t ixgbe_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
+{
+       struct ixgbe_adapter *adapter = netdev_priv(netdev);
+       struct ixgbe_ring *tx_ring;
+
+       tx_ring = adapter->tx_ring[skb->queue_mapping];
+       return ixgbe_xmit_frame_ring(skb, netdev, adapter, tx_ring);
+}
+
 /**
  * ixgbe_set_mac - Change the Ethernet Address of the NIC
  * @netdev: network interface device structure
@@ -6437,7 +6513,7 @@ static void ixgbe_netpoll(struct net_device *netdev)
 #endif
 
 static const struct net_device_ops ixgbe_netdev_ops = {
-       .ndo_open               = ixgbe_open,
+       .ndo_open               = ixgbe_open,
        .ndo_stop               = ixgbe_close,
        .ndo_start_xmit         = ixgbe_xmit_frame,
        .ndo_select_queue       = ixgbe_select_queue,
@@ -6532,7 +6608,7 @@ err_novfs:
  * and a hardware reset occur.
  **/
 static int __devinit ixgbe_probe(struct pci_dev *pdev,
-                                 const struct pci_device_id *ent)
+                                const struct pci_device_id *ent)
 {
        struct net_device *netdev;
        struct ixgbe_adapter *adapter = NULL;
@@ -6577,7 +6653,7 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
        }
 
        err = pci_request_selected_regions(pdev, pci_select_bars(pdev,
-                                          IORESOURCE_MEM), ixgbe_driver_name);
+                                          IORESOURCE_MEM), ixgbe_driver_name);
        if (err) {
                dev_err(&pdev->dev,
                        "pci_request_selected_regions failed 0x%x\n", err);
@@ -6617,7 +6693,7 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
        adapter->msg_enable = (1 << DEFAULT_DEBUG_LEVEL_SHIFT) - 1;
 
        hw->hw_addr = ioremap(pci_resource_start(pdev, 0),
-                             pci_resource_len(pdev, 0));
+                             pci_resource_len(pdev, 0));
        if (!hw->hw_addr) {
                err = -EIO;
                goto err_ioremap;
@@ -6661,7 +6737,7 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
         * which might start the timer
         */
        init_timer(&adapter->sfp_timer);
-       adapter->sfp_timer.function = &ixgbe_sfp_timer;
+       adapter->sfp_timer.function = ixgbe_sfp_timer;
        adapter->sfp_timer.data = (unsigned long) adapter;
 
        INIT_WORK(&adapter->sfp_task, ixgbe_sfp_task);
@@ -6671,7 +6747,7 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
 
        /* a new SFP+ module arrival, called from GPI SDP2 context */
        INIT_WORK(&adapter->sfp_config_module_task,
-                 ixgbe_sfp_config_module_task);
+                 ixgbe_sfp_config_module_task);
 
        ii->get_invariants(hw);
 
@@ -6723,10 +6799,10 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
        ixgbe_probe_vf(adapter, ii);
 
        netdev->features = NETIF_F_SG |
-                          NETIF_F_IP_CSUM |
-                          NETIF_F_HW_VLAN_TX |
-                          NETIF_F_HW_VLAN_RX |
-                          NETIF_F_HW_VLAN_FILTER;
+                          NETIF_F_IP_CSUM |
+                          NETIF_F_HW_VLAN_TX |
+                          NETIF_F_HW_VLAN_RX |
+                          NETIF_F_HW_VLAN_FILTER;
 
        netdev->features |= NETIF_F_IPV6_CSUM;
        netdev->features |= NETIF_F_TSO;
@@ -6793,7 +6869,7 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
                hw->mac.ops.disable_tx_laser(hw);
 
        init_timer(&adapter->watchdog_timer);
-       adapter->watchdog_timer.function = &ixgbe_watchdog;
+       adapter->watchdog_timer.function = ixgbe_watchdog;
        adapter->watchdog_timer.data = (unsigned long)adapter;
 
        INIT_WORK(&adapter->reset_task, ixgbe_reset_task);
@@ -6806,7 +6882,7 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
        switch (pdev->device) {
        case IXGBE_DEV_ID_82599_KX4:
                adapter->wol = (IXGBE_WUFC_MAG | IXGBE_WUFC_EX |
-                               IXGBE_WUFC_MC | IXGBE_WUFC_BC);
+                               IXGBE_WUFC_MC | IXGBE_WUFC_BC);
                break;
        default:
                adapter->wol = 0;
@@ -6819,13 +6895,14 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
 
        /* print bus type/speed/width info */
        e_dev_info("(PCI Express:%s:%s) %pM\n",
-               ((hw->bus.speed == ixgbe_bus_speed_5000) ? "5.0Gb/s":
-                (hw->bus.speed == ixgbe_bus_speed_2500) ? "2.5Gb/s":"Unknown"),
-               ((hw->bus.width == ixgbe_bus_width_pcie_x8) ? "Width x8" :
-                (hw->bus.width == ixgbe_bus_width_pcie_x4) ? "Width x4" :
-                (hw->bus.width == ixgbe_bus_width_pcie_x1) ? "Width x1" :
-                "Unknown"),
-               netdev->dev_addr);
+                  (hw->bus.speed == ixgbe_bus_speed_5000 ? "5.0Gb/s" :
+                   hw->bus.speed == ixgbe_bus_speed_2500 ? "2.5Gb/s" :
+                   "Unknown"),
+                  (hw->bus.width == ixgbe_bus_width_pcie_x8 ? "Width x8" :
+                   hw->bus.width == ixgbe_bus_width_pcie_x4 ? "Width x4" :
+                   hw->bus.width == ixgbe_bus_width_pcie_x1 ? "Width x1" :
+                   "Unknown"),
+                  netdev->dev_addr);
        ixgbe_read_pba_num_generic(hw, &part_num);
        if (ixgbe_is_sfp(hw) && hw->phy.sfp_type != ixgbe_sfp_type_not_present)
                e_dev_info("MAC: %d, PHY: %d, SFP+: %d, "
@@ -6872,7 +6949,8 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
                INIT_WORK(&adapter->fdir_reinit_task, ixgbe_fdir_reinit_task);
 
        if (adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE)
-               INIT_WORK(&adapter->check_overtemp_task, ixgbe_check_overtemp_task);
+               INIT_WORK(&adapter->check_overtemp_task,
+                         ixgbe_check_overtemp_task);
 #ifdef CONFIG_IXGBE_DCA
        if (dca_add_requester(&pdev->dev) == 0) {
                adapter->flags |= IXGBE_FLAG_DCA_ENABLED;
@@ -6908,8 +6986,8 @@ err_eeprom:
 err_ioremap:
        free_netdev(netdev);
 err_alloc_etherdev:
-       pci_release_selected_regions(pdev, pci_select_bars(pdev,
-                                    IORESOURCE_MEM));
+       pci_release_selected_regions(pdev,
+                                    pci_select_bars(pdev, IORESOURCE_MEM));
 err_pci_reg:
 err_dma:
        pci_disable_device(pdev);
@@ -6976,7 +7054,7 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev)
 
        iounmap(adapter->hw.hw_addr);
        pci_release_selected_regions(pdev, pci_select_bars(pdev,
-                                    IORESOURCE_MEM));
+                                    IORESOURCE_MEM));
 
        e_dev_info("complete\n");
 
@@ -6996,7 +7074,7 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev)
  * this device has been detected.
  */
 static pci_ers_result_t ixgbe_io_error_detected(struct pci_dev *pdev,
-                                                pci_channel_state_t state)
+                                               pci_channel_state_t state)
 {
        struct net_device *netdev = pci_get_drvdata(pdev);
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
@@ -7102,8 +7180,7 @@ static struct pci_driver ixgbe_driver = {
 static int __init ixgbe_init_module(void)
 {
        int ret;
-       pr_info("%s - version %s\n", ixgbe_driver_string,
-                  ixgbe_driver_version);
+       pr_info("%s - version %s\n", ixgbe_driver_string, ixgbe_driver_version);
        pr_info("%s\n", ixgbe_copyright);
 
 #ifdef CONFIG_IXGBE_DCA
@@ -7132,12 +7209,12 @@ static void __exit ixgbe_exit_module(void)
 
 #ifdef CONFIG_IXGBE_DCA
 static int ixgbe_notify_dca(struct notifier_block *nb, unsigned long event,
-                            void *p)
+                           void *p)
 {
        int ret_val;
 
        ret_val = driver_for_each_device(&ixgbe_driver.driver, NULL, &event,
-                                        __ixgbe_notify_dca);
+                                        __ixgbe_notify_dca);
 
        return ret_val ? NOTIFY_BAD : NOTIFY_DONE;
 }
index 9587d975d66c6eeb31e82f9233ab82f876036134..d3cc6ce7c973a3c71855588029e57ab7dcd82ef6 100644 (file)
 #define IXGBE_RDRXCTL_MVMEN         0x00000020
 #define IXGBE_RDRXCTL_DMAIDONE      0x00000008 /* DMA init cycle done */
 #define IXGBE_RDRXCTL_AGGDIS        0x00010000 /* Aggregation disable */
+#define IXGBE_RDRXCTL_RSCACKC       0x02000000 /* must set 1 when RSC enabled */
+#define IXGBE_RDRXCTL_FCOE_WRFIX    0x04000000 /* must set 1 when RSC enabled */
 
 /* RQTC Bit Masks and Shifts */
 #define IXGBE_RQTC_SHIFT_TC(_i)     ((_i) * 4)
index f7015efbff05cfc91da412e43e664af72594ce41..da4033c6efa20f677342a8f6aff4bbca224548cd 100644 (file)
@@ -243,7 +243,6 @@ struct ixgbevf_adapter {
        /* OS defined structs */
        struct net_device *netdev;
        struct pci_dev *pdev;
-       struct net_device_stats net_stats;
 
        /* structs defined in ixgbe_vf.h */
        struct ixgbe_hw hw;
index 918c00359b0a5355ea9862f6cf6a3963b8b80a04..3eda1bdbbb7a61c31b17644af53b7212afcb877b 100644 (file)
@@ -308,8 +308,8 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_adapter *adapter,
        tx_ring->total_bytes += total_bytes;
        tx_ring->total_packets += total_packets;
 
-       adapter->net_stats.tx_bytes += total_bytes;
-       adapter->net_stats.tx_packets += total_packets;
+       netdev->stats.tx_bytes += total_bytes;
+       netdev->stats.tx_packets += total_packets;
 
        return (count < tx_ring->work_limit);
 }
@@ -356,7 +356,7 @@ static void ixgbevf_receive_skb(struct ixgbevf_q_vector *q_vector,
 static inline void ixgbevf_rx_checksum(struct ixgbevf_adapter *adapter,
                                       u32 status_err, struct sk_buff *skb)
 {
-       skb->ip_summed = CHECKSUM_NONE;
+       skb_checksum_none_assert(skb);
 
        /* Rx csum disabled */
        if (!(adapter->flags & IXGBE_FLAG_RX_CSUM_ENABLED))
@@ -639,8 +639,8 @@ next_desc:
 
        rx_ring->total_packets += total_rx_packets;
        rx_ring->total_bytes += total_rx_bytes;
-       adapter->net_stats.rx_bytes += total_rx_bytes;
-       adapter->net_stats.rx_packets += total_rx_packets;
+       adapter->netdev->stats.rx_bytes += total_rx_bytes;
+       adapter->netdev->stats.rx_packets += total_rx_packets;
 
        return cleaned;
 }
@@ -2297,7 +2297,7 @@ void ixgbevf_update_stats(struct ixgbevf_adapter *adapter)
                                adapter->stats.vfmprc);
 
        /* Fill out the OS statistics structure */
-       adapter->net_stats.multicast = adapter->stats.vfmprc -
+       adapter->netdev->stats.multicast = adapter->stats.vfmprc -
                adapter->stats.base_vfmprc;
 }
 
@@ -3180,21 +3180,6 @@ static int ixgbevf_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
        return NETDEV_TX_OK;
 }
 
-/**
- * ixgbevf_get_stats - Get System Network Statistics
- * @netdev: network interface device structure
- *
- * Returns the address of the device statistics structure.
- * The statistics are actually updated from the timer callback.
- **/
-static struct net_device_stats *ixgbevf_get_stats(struct net_device *netdev)
-{
-       struct ixgbevf_adapter *adapter = netdev_priv(netdev);
-
-       /* only return the current stats */
-       return &adapter->net_stats;
-}
-
 /**
  * ixgbevf_set_mac - Change the Ethernet Address of the NIC
  * @netdev: network interface device structure
@@ -3272,7 +3257,6 @@ static const struct net_device_ops ixgbe_netdev_ops = {
        .ndo_open               = &ixgbevf_open,
        .ndo_stop               = &ixgbevf_close,
        .ndo_start_xmit         = &ixgbevf_xmit_frame,
-       .ndo_get_stats          = &ixgbevf_get_stats,
        .ndo_set_rx_mode        = &ixgbevf_set_rx_mode,
        .ndo_set_multicast_list = &ixgbevf_set_rx_mode,
        .ndo_validate_addr      = eth_validate_addr,
@@ -3426,7 +3410,7 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev,
        }
 
        init_timer(&adapter->watchdog_timer);
-       adapter->watchdog_timer.function = &ixgbevf_watchdog;
+       adapter->watchdog_timer.function = ixgbevf_watchdog;
        adapter->watchdog_timer.data = (unsigned long)adapter;
 
        INIT_WORK(&adapter->reset_task, ixgbevf_reset_task);
index 94b750b8874f492d279fac3b68943c58e566be8f..61f9dc831424143d02497b335387caba5bf65823 100644 (file)
@@ -124,8 +124,6 @@ struct ixgbe_hw {
        void *back;
 
        u8 __iomem *hw_addr;
-       u8 *flash_address;
-       unsigned long io_base;
 
        struct ixgbe_mac_info mac;
        struct ixgbe_mbx_info mbx;
index 99f24f5cac53f6c6a70e25681253593b3b485a6e..c04c096bc6a90b4734237d5ada679db4c8af60d0 100644 (file)
@@ -21,6 +21,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
@@ -73,7 +75,7 @@ read_again:
        }
 
        if (i == 0) {
-               jeprintk(jme->pdev, "phy(%d) read timeout : %d\n", phy, reg);
+               pr_err("phy(%d) read timeout : %d\n", phy, reg);
                return 0;
        }
 
@@ -102,7 +104,7 @@ jme_mdio_write(struct net_device *netdev,
        }
 
        if (i == 0)
-               jeprintk(jme->pdev, "phy(%d) write timeout : %d\n", phy, reg);
+               pr_err("phy(%d) write timeout : %d\n", phy, reg);
 }
 
 static inline void
@@ -227,7 +229,7 @@ jme_reload_eeprom(struct jme_adapter *jme)
                }
 
                if (i == 0) {
-                       jeprintk(jme->pdev, "eeprom reload timeout\n");
+                       pr_err("eeprom reload timeout\n");
                        return -EIO;
                }
        }
@@ -397,8 +399,7 @@ jme_check_link(struct net_device *netdev, int testonly)
                                        phylink = jread32(jme, JME_PHY_LINK);
                        }
                        if (!cnt)
-                               jeprintk(jme->pdev,
-                                       "Waiting speed resolve timeout.\n");
+                               pr_err("Waiting speed resolve timeout\n");
 
                        strcat(linkmsg, "ANed: ");
                }
@@ -480,13 +481,13 @@ jme_check_link(struct net_device *netdev, int testonly)
                strcat(linkmsg, (phylink & PHY_LINK_MDI_STAT) ?
                                        "MDI-X" :
                                        "MDI");
-               netif_info(jme, link, jme->dev, "Link is up at %s.\n", linkmsg);
+               netif_info(jme, link, jme->dev, "Link is up at %s\n", linkmsg);
                netif_carrier_on(netdev);
        } else {
                if (testonly)
                        goto out;
 
-               netif_info(jme, link, jme->dev, "Link is down.\n");
+               netif_info(jme, link, jme->dev, "Link is down\n");
                jme->phylink = 0;
                netif_carrier_off(netdev);
        }
@@ -648,7 +649,7 @@ jme_disable_tx_engine(struct jme_adapter *jme)
        }
 
        if (!i)
-               jeprintk(jme->pdev, "Disable TX engine timeout.\n");
+               pr_err("Disable TX engine timeout\n");
 }
 
 static void
@@ -867,7 +868,7 @@ jme_disable_rx_engine(struct jme_adapter *jme)
        }
 
        if (!i)
-               jeprintk(jme->pdev, "Disable RX engine timeout.\n");
+               pr_err("Disable RX engine timeout\n");
 
 }
 
@@ -887,13 +888,13 @@ jme_rxsum_ok(struct jme_adapter *jme, u16 flags)
        if (unlikely((flags & (RXWBFLAG_MF | RXWBFLAG_UDPON | RXWBFLAG_UDPCS))
                        == RXWBFLAG_UDPON)) {
                if (flags & RXWBFLAG_IPV4)
-                       netif_err(jme, rx_err, jme->dev, "UDP Checksum error.\n");
+                       netif_err(jme, rx_err, jme->dev, "UDP Checksum error\n");
                return false;
        }
 
        if (unlikely((flags & (RXWBFLAG_IPV4 | RXWBFLAG_IPCS))
                        == RXWBFLAG_IPV4)) {
-               netif_err(jme, rx_err, jme->dev, "IPv4 Checksum error.\n");
+               netif_err(jme, rx_err, jme->dev, "IPv4 Checksum error\n");
                return false;
        }
 
@@ -936,7 +937,7 @@ jme_alloc_and_feed_skb(struct jme_adapter *jme, int idx)
                if (jme_rxsum_ok(jme, le16_to_cpu(rxdesc->descwb.flags)))
                        skb->ip_summed = CHECKSUM_UNNECESSARY;
                else
-                       skb->ip_summed = CHECKSUM_NONE;
+                       skb_checksum_none_assert(skb);
 
                if (rxdesc->descwb.flags & cpu_to_le16(RXWBFLAG_TAGON)) {
                        if (jme->vlgrp) {
@@ -1185,9 +1186,9 @@ jme_link_change_tasklet(unsigned long arg)
 
        while (!atomic_dec_and_test(&jme->link_changing)) {
                atomic_inc(&jme->link_changing);
-               netif_info(jme, intr, jme->dev, "Get link change lock failed.\n");
+               netif_info(jme, intr, jme->dev, "Get link change lock failed\n");
                while (atomic_read(&jme->link_changing) != 1)
-                       netif_info(jme, intr, jme->dev, "Waiting link change lock.\n");
+                       netif_info(jme, intr, jme->dev, "Waiting link change lock\n");
        }
 
        if (jme_check_link(netdev, 1) && jme->old_mtu == netdev->mtu)
@@ -1221,15 +1222,13 @@ jme_link_change_tasklet(unsigned long arg)
        if (netif_carrier_ok(netdev)) {
                rc = jme_setup_rx_resources(jme);
                if (rc) {
-                       jeprintk(jme->pdev, "Allocating resources for RX error"
-                               ", Device STOPPED!\n");
+                       pr_err("Allocating resources for RX error, Device STOPPED!\n");
                        goto out_enable_tasklet;
                }
 
                rc = jme_setup_tx_resources(jme);
                if (rc) {
-                       jeprintk(jme->pdev, "Allocating resources for TX error"
-                               ", Device STOPPED!\n");
+                       pr_err("Allocating resources for TX error, Device STOPPED!\n");
                        goto err_out_free_rx_resources;
                }
 
@@ -1324,7 +1323,7 @@ jme_wake_queue_if_stopped(struct jme_adapter *jme)
        smp_wmb();
        if (unlikely(netif_queue_stopped(jme->dev) &&
        atomic_read(&txring->nr_free) >= (jme->tx_wake_threshold))) {
-               netif_info(jme, tx_done, jme->dev, "TX Queue Waked.\n");
+               netif_info(jme, tx_done, jme->dev, "TX Queue Waked\n");
                netif_wake_queue(jme->dev);
        }
 
@@ -1339,7 +1338,7 @@ jme_tx_clean_tasklet(unsigned long arg)
        struct jme_buffer_info *txbi = txring->bufinf, *ctxbi, *ttxbi;
        int i, j, cnt = 0, max, err, mask;
 
-       tx_dbg(jme, "Into txclean.\n");
+       tx_dbg(jme, "Into txclean\n");
 
        if (unlikely(!atomic_dec_and_test(&jme->tx_cleaning)))
                goto out;
@@ -1361,7 +1360,7 @@ jme_tx_clean_tasklet(unsigned long arg)
                !(txdesc[i].descwb.flags & TXWBFLAG_OWN))) {
 
                        tx_dbg(jme, "txclean: %d+%d@%lu\n",
-                                       i, ctxbi->nr_desc, jiffies);
+                              i, ctxbi->nr_desc, jiffies);
 
                        err = txdesc[i].descwb.flags & TXWBFLAG_ALLERR;
 
@@ -1402,7 +1401,7 @@ jme_tx_clean_tasklet(unsigned long arg)
                ctxbi->nr_desc = 0;
        }
 
-       tx_dbg(jme, "txclean: done %d@%lu.\n", i, jiffies);
+       tx_dbg(jme, "txclean: done %d@%lu\n", i, jiffies);
        atomic_set(&txring->next_to_clean, i);
        atomic_add(cnt, &txring->nr_free);
 
@@ -1548,10 +1547,10 @@ jme_request_irq(struct jme_adapter *jme)
        rc = request_irq(jme->pdev->irq, handler, irq_flags, netdev->name,
                          netdev);
        if (rc) {
-               jeprintk(jme->pdev,
-                       "Unable to request %s interrupt (return: %d)\n",
-                       test_bit(JME_FLAG_MSI, &jme->flags) ? "MSI" : "INTx",
-                       rc);
+               netdev_err(netdev,
+                          "Unable to request %s interrupt (return: %d)\n",
+                          test_bit(JME_FLAG_MSI, &jme->flags) ? "MSI" : "INTx",
+                          rc);
 
                if (test_bit(JME_FLAG_MSI, &jme->flags)) {
                        pci_disable_msi(jme->pdev);
@@ -1834,7 +1833,7 @@ jme_tx_csum(struct jme_adapter *jme, struct sk_buff *skb, u8 *flags)
                        *flags |= TXFLAG_UDPCS;
                        break;
                default:
-                       netif_err(jme, tx_err, jme->dev, "Error upper layer protocol.\n");
+                       netif_err(jme, tx_err, jme->dev, "Error upper layer protocol\n");
                        break;
                }
        }
@@ -1909,12 +1908,12 @@ jme_stop_queue_if_full(struct jme_adapter *jme)
        smp_wmb();
        if (unlikely(atomic_read(&txring->nr_free) < (MAX_SKB_FRAGS+2))) {
                netif_stop_queue(jme->dev);
-               netif_info(jme, tx_queued, jme->dev, "TX Queue Paused.\n");
+               netif_info(jme, tx_queued, jme->dev, "TX Queue Paused\n");
                smp_wmb();
                if (atomic_read(&txring->nr_free)
                        >= (jme->tx_wake_threshold)) {
                        netif_wake_queue(jme->dev);
-                       netif_info(jme, tx_queued, jme->dev, "TX Queue Fast Waked.\n");
+                       netif_info(jme, tx_queued, jme->dev, "TX Queue Fast Waked\n");
                }
        }
 
@@ -1922,7 +1921,8 @@ jme_stop_queue_if_full(struct jme_adapter *jme)
                        (jiffies - txbi->start_xmit) >= TX_TIMEOUT &&
                        txbi->skb)) {
                netif_stop_queue(jme->dev);
-               netif_info(jme, tx_queued, jme->dev, "TX Queue Stopped %d@%lu.\n", idx, jiffies);
+               netif_info(jme, tx_queued, jme->dev,
+                          "TX Queue Stopped %d@%lu\n", idx, jiffies);
        }
 }
 
@@ -1945,7 +1945,8 @@ jme_start_xmit(struct sk_buff *skb, struct net_device *netdev)
 
        if (unlikely(idx < 0)) {
                netif_stop_queue(netdev);
-               netif_err(jme, tx_err, jme->dev, "BUG! Tx ring full when queue awake!\n");
+               netif_err(jme, tx_err, jme->dev,
+                         "BUG! Tx ring full when queue awake!\n");
 
                return NETDEV_TX_BUSY;
        }
@@ -1957,9 +1958,8 @@ jme_start_xmit(struct sk_buff *skb, struct net_device *netdev)
                                TXCS_QUEUE0S |
                                TXCS_ENABLE);
 
-       tx_dbg(jme, "xmit: %d+%d@%lu\n", idx,
-                       skb_shinfo(skb)->nr_frags + 2,
-                       jiffies);
+       tx_dbg(jme, "xmit: %d+%d@%lu\n",
+              idx, skb_shinfo(skb)->nr_frags + 2, jiffies);
        jme_stop_queue_if_full(jme);
 
        return NETDEV_TX_OK;
@@ -2501,7 +2501,7 @@ jme_smb_read(struct jme_adapter *jme, unsigned int addr)
                val = jread32(jme, JME_SMBCSR);
        }
        if (!to) {
-               netif_err(jme, hw, jme->dev, "SMB Bus Busy.\n");
+               netif_err(jme, hw, jme->dev, "SMB Bus Busy\n");
                return 0xFF;
        }
 
@@ -2517,7 +2517,7 @@ jme_smb_read(struct jme_adapter *jme, unsigned int addr)
                val = jread32(jme, JME_SMBINTF);
        }
        if (!to) {
-               netif_err(jme, hw, jme->dev, "SMB Bus Busy.\n");
+               netif_err(jme, hw, jme->dev, "SMB Bus Busy\n");
                return 0xFF;
        }
 
@@ -2537,7 +2537,7 @@ jme_smb_write(struct jme_adapter *jme, unsigned int addr, u8 data)
                val = jread32(jme, JME_SMBCSR);
        }
        if (!to) {
-               netif_err(jme, hw, jme->dev, "SMB Bus Busy.\n");
+               netif_err(jme, hw, jme->dev, "SMB Bus Busy\n");
                return;
        }
 
@@ -2554,7 +2554,7 @@ jme_smb_write(struct jme_adapter *jme, unsigned int addr, u8 data)
                val = jread32(jme, JME_SMBINTF);
        }
        if (!to) {
-               netif_err(jme, hw, jme->dev, "SMB Bus Busy.\n");
+               netif_err(jme, hw, jme->dev, "SMB Bus Busy\n");
                return;
        }
 
@@ -2699,26 +2699,26 @@ jme_init_one(struct pci_dev *pdev,
         */
        rc = pci_enable_device(pdev);
        if (rc) {
-               jeprintk(pdev, "Cannot enable PCI device.\n");
+               pr_err("Cannot enable PCI device\n");
                goto err_out;
        }
 
        using_dac = jme_pci_dma64(pdev);
        if (using_dac < 0) {
-               jeprintk(pdev, "Cannot set PCI DMA Mask.\n");
+               pr_err("Cannot set PCI DMA Mask\n");
                rc = -EIO;
                goto err_out_disable_pdev;
        }
 
        if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
-               jeprintk(pdev, "No PCI resource region found.\n");
+               pr_err("No PCI resource region found\n");
                rc = -ENOMEM;
                goto err_out_disable_pdev;
        }
 
        rc = pci_request_regions(pdev, DRV_NAME);
        if (rc) {
-               jeprintk(pdev, "Cannot obtain PCI resource region.\n");
+               pr_err("Cannot obtain PCI resource region\n");
                goto err_out_disable_pdev;
        }
 
@@ -2729,7 +2729,7 @@ jme_init_one(struct pci_dev *pdev,
         */
        netdev = alloc_etherdev(sizeof(*jme));
        if (!netdev) {
-               jeprintk(pdev, "Cannot allocate netdev structure.\n");
+               pr_err("Cannot allocate netdev structure\n");
                rc = -ENOMEM;
                goto err_out_release_regions;
        }
@@ -2767,7 +2767,7 @@ jme_init_one(struct pci_dev *pdev,
        jme->regs = ioremap(pci_resource_start(pdev, 0),
                             pci_resource_len(pdev, 0));
        if (!(jme->regs)) {
-               jeprintk(pdev, "Mapping PCI resource region error.\n");
+               pr_err("Mapping PCI resource region error\n");
                rc = -ENOMEM;
                goto err_out_free_netdev;
        }
@@ -2855,8 +2855,8 @@ jme_init_one(struct pci_dev *pdev,
 
                if (!jme->mii_if.phy_id) {
                        rc = -EIO;
-                       jeprintk(pdev, "Can not find phy_id.\n");
-                        goto err_out_unmap;
+                       pr_err("Can not find phy_id\n");
+                       goto err_out_unmap;
                }
 
                jme->reg_ghc |= GHC_LINK_POLL;
@@ -2883,8 +2883,7 @@ jme_init_one(struct pci_dev *pdev,
        jme_reset_mac_processor(jme);
        rc = jme_reload_eeprom(jme);
        if (rc) {
-               jeprintk(pdev,
-                       "Reload eeprom for reading MAC Address error.\n");
+               pr_err("Reload eeprom for reading MAC Address error\n");
                goto err_out_unmap;
        }
        jme_load_macaddr(netdev);
@@ -2900,7 +2899,7 @@ jme_init_one(struct pci_dev *pdev,
         */
        rc = register_netdev(netdev);
        if (rc) {
-               jeprintk(pdev, "Cannot register net device.\n");
+               pr_err("Cannot register net device\n");
                goto err_out_unmap;
        }
 
@@ -3042,8 +3041,7 @@ static struct pci_driver jme_driver = {
 static int __init
 jme_init_module(void)
 {
-       printk(KERN_INFO PFX "JMicron JMC2XX ethernet "
-              "driver version %s\n", DRV_VERSION);
+       pr_info("JMicron JMC2XX ethernet driver version %s\n", DRV_VERSION);
        return pci_register_driver(&jme_driver);
 }
 
index 07ad3a457185c3f440c65e9d2a04cb6de1214aa3..1360f68861b8c6d22205c7a16019e8723ff322be 100644 (file)
@@ -41,9 +41,6 @@
        NETIF_MSG_TX_ERR | \
        NETIF_MSG_HW)
 
-#define jeprintk(pdev, fmt, args...) \
-       printk(KERN_ERR PFX fmt, ## args)
-
 #ifdef TX_DEBUG
 #define tx_dbg(priv, fmt, args...)                                     \
        printk(KERN_DEBUG "%s: " fmt, (priv)->dev->name, ##args)
index bdf2149e529689b1135603904da6343fcbbbebc2..874ee01e8d9d24c2959956d8ab7a469b6f072ffe 100644 (file)
@@ -760,7 +760,7 @@ static void ll_temac_recv(struct net_device *ndev)
                skb_put(skb, length);
                skb->dev = ndev;
                skb->protocol = eth_type_trans(skb, ndev);
-               skb->ip_summed = CHECKSUM_NONE;
+               skb_checksum_none_assert(skb);
 
                /* if we're doing rx csum offload, set it up */
                if (((lp->temac_features & TEMAC_FEATURE_RX_CSUM) != 0) &&
index 3832fa4961dd6b3ba2a3806e236a07d0ad9c4f8b..f84f5e6ededbe168173644d842b7b9c26ef21911 100644 (file)
@@ -562,19 +562,19 @@ static int __init mac8390_initdev(struct net_device *dev,
 
                case ACCESS_16:
                        /* 16 bit card, register map is reversed */
-                       ei_status.reset_8390 = &mac8390_no_reset;
-                       ei_status.block_input = &slow_sane_block_input;
-                       ei_status.block_output = &slow_sane_block_output;
-                       ei_status.get_8390_hdr = &slow_sane_get_8390_hdr;
+                       ei_status.reset_8390 = mac8390_no_reset;
+                       ei_status.block_input = slow_sane_block_input;
+                       ei_status.block_output = slow_sane_block_output;
+                       ei_status.get_8390_hdr = slow_sane_get_8390_hdr;
                        ei_status.reg_offset = back4_offsets;
                        break;
 
                case ACCESS_32:
                        /* 32 bit card, register map is reversed */
-                       ei_status.reset_8390 = &mac8390_no_reset;
-                       ei_status.block_input = &sane_block_input;
-                       ei_status.block_output = &sane_block_output;
-                       ei_status.get_8390_hdr = &sane_get_8390_hdr;
+                       ei_status.reset_8390 = mac8390_no_reset;
+                       ei_status.block_input = sane_block_input;
+                       ei_status.block_output = sane_block_output;
+                       ei_status.get_8390_hdr = sane_get_8390_hdr;
                        ei_status.reg_offset = back4_offsets;
                        access_bitmode = 1;
                        break;
@@ -586,19 +586,19 @@ static int __init mac8390_initdev(struct net_device *dev,
                 * but overwrite system memory when run at 32 bit.
                 * so we run them all at 16 bit.
                 */
-               ei_status.reset_8390 = &mac8390_no_reset;
-               ei_status.block_input = &slow_sane_block_input;
-               ei_status.block_output = &slow_sane_block_output;
-               ei_status.get_8390_hdr = &slow_sane_get_8390_hdr;
+               ei_status.reset_8390 = mac8390_no_reset;
+               ei_status.block_input = slow_sane_block_input;
+               ei_status.block_output = slow_sane_block_output;
+               ei_status.get_8390_hdr = slow_sane_get_8390_hdr;
                ei_status.reg_offset = back4_offsets;
                break;
 
        case MAC8390_CABLETRON:
                /* 16 bit card, register map is short forward */
-               ei_status.reset_8390 = &mac8390_no_reset;
-               ei_status.block_input = &slow_sane_block_input;
-               ei_status.block_output = &slow_sane_block_output;
-               ei_status.get_8390_hdr = &slow_sane_get_8390_hdr;
+               ei_status.reset_8390 = mac8390_no_reset;
+               ei_status.block_input = slow_sane_block_input;
+               ei_status.block_output = slow_sane_block_output;
+               ei_status.get_8390_hdr = slow_sane_get_8390_hdr;
                ei_status.reg_offset = fwrd2_offsets;
                break;
 
@@ -606,19 +606,19 @@ static int __init mac8390_initdev(struct net_device *dev,
        case MAC8390_KINETICS:
                /* 16 bit memory, register map is forward */
                /* dayna and similar */
-               ei_status.reset_8390 = &mac8390_no_reset;
-               ei_status.block_input = &dayna_block_input;
-               ei_status.block_output = &dayna_block_output;
-               ei_status.get_8390_hdr = &dayna_get_8390_hdr;
+               ei_status.reset_8390 = mac8390_no_reset;
+               ei_status.block_input = dayna_block_input;
+               ei_status.block_output = dayna_block_output;
+               ei_status.get_8390_hdr = dayna_get_8390_hdr;
                ei_status.reg_offset = fwrd4_offsets;
                break;
 
        case MAC8390_INTERLAN:
                /* 16 bit memory, register map is forward */
-               ei_status.reset_8390 = &interlan_reset;
-               ei_status.block_input = &slow_sane_block_input;
-               ei_status.block_output = &slow_sane_block_output;
-               ei_status.get_8390_hdr = &slow_sane_get_8390_hdr;
+               ei_status.reset_8390 = interlan_reset;
+               ei_status.block_input = slow_sane_block_input;
+               ei_status.block_output = slow_sane_block_output;
+               ei_status.get_8390_hdr = slow_sane_get_8390_hdr;
                ei_status.reg_offset = fwrd4_offsets;
                break;
 
index ff2f158ab0b92d88597bf68d1b1a13cf89ca4e41..4297f6e8c4bc0ab571dd571d9a6f08d5493c6e76 100644 (file)
@@ -407,7 +407,7 @@ static int macb_rx_frame(struct macb *bp, unsigned int first_frag,
        }
 
        skb_reserve(skb, RX_OFFSET);
-       skb->ip_summed = CHECKSUM_NONE;
+       skb_checksum_none_assert(skb);
        skb_put(skb, len);
 
        for (frag = first_frag; ; frag = NEXT_RX(frag)) {
index 3b1c54a9c6ef12bc255f0af833ef6de2788da219..42567279843ecfc804efd233b841338f21cef933 100644 (file)
@@ -84,26 +84,45 @@ static const struct proto_ops macvtap_socket_ops;
 static DEFINE_SPINLOCK(macvtap_lock);
 
 /*
- * Choose the next free queue, for now there is only one
+ * get_slot: return a [unused/occupied] slot in vlan->taps[]:
+ *     - if 'q' is NULL, return the first empty slot;
+ *     - otherwise, return the slot this pointer occupies.
  */
+static int get_slot(struct macvlan_dev *vlan, struct macvtap_queue *q)
+{
+       int i;
+
+       for (i = 0; i < MAX_MACVTAP_QUEUES; i++) {
+               if (rcu_dereference(vlan->taps[i]) == q)
+                       return i;
+       }
+
+       /* Should never happen */
+       BUG_ON(1);
+}
+
 static int macvtap_set_queue(struct net_device *dev, struct file *file,
                                struct macvtap_queue *q)
 {
        struct macvlan_dev *vlan = netdev_priv(dev);
+       int index;
        int err = -EBUSY;
 
        spin_lock(&macvtap_lock);
-       if (rcu_dereference(vlan->tap))
+       if (vlan->numvtaps == MAX_MACVTAP_QUEUES)
                goto out;
 
        err = 0;
+       index = get_slot(vlan, NULL);
        rcu_assign_pointer(q->vlan, vlan);
-       rcu_assign_pointer(vlan->tap, q);
+       rcu_assign_pointer(vlan->taps[index], q);
        sock_hold(&q->sk);
 
        q->file = file;
        file->private_data = q;
 
+       vlan->numvtaps++;
+
 out:
        spin_unlock(&macvtap_lock);
        return err;
@@ -124,9 +143,12 @@ static void macvtap_put_queue(struct macvtap_queue *q)
        spin_lock(&macvtap_lock);
        vlan = rcu_dereference(q->vlan);
        if (vlan) {
-               rcu_assign_pointer(vlan->tap, NULL);
+               int index = get_slot(vlan, q);
+
+               rcu_assign_pointer(vlan->taps[index], NULL);
                rcu_assign_pointer(q->vlan, NULL);
                sock_put(&q->sk);
+               --vlan->numvtaps;
        }
 
        spin_unlock(&macvtap_lock);
@@ -136,39 +158,82 @@ static void macvtap_put_queue(struct macvtap_queue *q)
 }
 
 /*
- * Since we only support one queue, just dereference the pointer.
+ * Select a queue based on the rxq of the device on which this packet
+ * arrived. If the incoming device is not mq, calculate a flow hash
+ * to select a queue. If all fails, find the first available queue.
+ * Cache vlan->numvtaps since it can become zero during the execution
+ * of this function.
  */
 static struct macvtap_queue *macvtap_get_queue(struct net_device *dev,
                                               struct sk_buff *skb)
 {
        struct macvlan_dev *vlan = netdev_priv(dev);
+       struct macvtap_queue *tap = NULL;
+       int numvtaps = vlan->numvtaps;
+       __u32 rxq;
+
+       if (!numvtaps)
+               goto out;
+
+       if (likely(skb_rx_queue_recorded(skb))) {
+               rxq = skb_get_rx_queue(skb);
+
+               while (unlikely(rxq >= numvtaps))
+                       rxq -= numvtaps;
+
+               tap = rcu_dereference(vlan->taps[rxq]);
+               if (tap)
+                       goto out;
+       }
+
+       /* Check if we can use flow to select a queue */
+       rxq = skb_get_rxhash(skb);
+       if (rxq) {
+               tap = rcu_dereference(vlan->taps[rxq % numvtaps]);
+               if (tap)
+                       goto out;
+       }
 
-       return rcu_dereference(vlan->tap);
+       /* Everything failed - find first available queue */
+       for (rxq = 0; rxq < MAX_MACVTAP_QUEUES; rxq++) {
+               tap = rcu_dereference(vlan->taps[rxq]);
+               if (tap)
+                       break;
+       }
+
+out:
+       return tap;
 }
 
 /*
  * The net_device is going away, give up the reference
- * that it holds on the queue (all the queues one day)
- * and safely set the pointer from the queues to NULL.
+ * that it holds on all queues and safely set the pointer
+ * from the queues to NULL.
  */
 static void macvtap_del_queues(struct net_device *dev)
 {
        struct macvlan_dev *vlan = netdev_priv(dev);
-       struct macvtap_queue *q;
+       struct macvtap_queue *q, *qlist[MAX_MACVTAP_QUEUES];
+       int i, j = 0;
 
+       /* macvtap_put_queue can free some slots, so go through all slots */
        spin_lock(&macvtap_lock);
-       q = rcu_dereference(vlan->tap);
-       if (!q) {
-               spin_unlock(&macvtap_lock);
-               return;
+       for (i = 0; i < MAX_MACVTAP_QUEUES && vlan->numvtaps; i++) {
+               q = rcu_dereference(vlan->taps[i]);
+               if (q) {
+                       qlist[j++] = q;
+                       rcu_assign_pointer(vlan->taps[i], NULL);
+                       rcu_assign_pointer(q->vlan, NULL);
+                       vlan->numvtaps--;
+               }
        }
-
-       rcu_assign_pointer(vlan->tap, NULL);
-       rcu_assign_pointer(q->vlan, NULL);
+       BUG_ON(vlan->numvtaps != 0);
        spin_unlock(&macvtap_lock);
 
        synchronize_rcu();
-       sock_put(&q->sk);
+
+       for (--j; j >= 0; j--)
+               sock_put(&qlist[j]->sk);
 }
 
 /*
index 1fd068e1d93054ad7e9d72feade1e053d9939673..d1aa45a158541b83168de0fcb8513c297ff32a6e 100644 (file)
@@ -6,4 +6,4 @@ mlx4_core-y :=  alloc.o catas.o cmd.o cq.o eq.o fw.o icm.o intf.o main.o mcg.o \
 obj-$(CONFIG_MLX4_EN)               += mlx4_en.o
 
 mlx4_en-y :=   en_main.o en_tx.o en_rx.o en_ethtool.o en_port.o en_cq.o \
-               en_resources.o en_netdev.o
+               en_resources.o en_netdev.o en_selftest.o
index 8c8515619b8e9b808aafbf08bdab91bb080bb17a..8f4bf1f07c11e824e8e21785f122c5d0d66775c5 100644 (file)
@@ -74,7 +74,7 @@ void mlx4_bitmap_free(struct mlx4_bitmap *bitmap, u32 obj)
 
 u32 mlx4_bitmap_alloc_range(struct mlx4_bitmap *bitmap, int cnt, int align)
 {
-       u32 obj, i;
+       u32 obj;
 
        if (likely(cnt == 1 && align == 1))
                return mlx4_bitmap_alloc(bitmap);
@@ -91,8 +91,7 @@ u32 mlx4_bitmap_alloc_range(struct mlx4_bitmap *bitmap, int cnt, int align)
        }
 
        if (obj < bitmap->max) {
-               for (i = 0; i < cnt; i++)
-                       set_bit(obj + i, bitmap->table);
+               bitmap_set(bitmap->table, obj, cnt);
                if (obj == bitmap->last) {
                        bitmap->last = (obj + cnt);
                        if (bitmap->last >= bitmap->max)
@@ -109,13 +108,10 @@ u32 mlx4_bitmap_alloc_range(struct mlx4_bitmap *bitmap, int cnt, int align)
 
 void mlx4_bitmap_free_range(struct mlx4_bitmap *bitmap, u32 obj, int cnt)
 {
-       u32 i;
-
        obj &= bitmap->max + bitmap->reserved_top - 1;
 
        spin_lock(&bitmap->lock);
-       for (i = 0; i < cnt; i++)
-               clear_bit(obj + i, bitmap->table);
+       bitmap_clear(bitmap->table, obj, cnt);
        bitmap->last = min(bitmap->last, obj);
        bitmap->top = (bitmap->top + bitmap->max + bitmap->reserved_top)
                        & bitmap->mask;
@@ -125,8 +121,6 @@ void mlx4_bitmap_free_range(struct mlx4_bitmap *bitmap, u32 obj, int cnt)
 int mlx4_bitmap_init(struct mlx4_bitmap *bitmap, u32 num, u32 mask,
                     u32 reserved_bot, u32 reserved_top)
 {
-       int i;
-
        /* num must be a power of 2 */
        if (num != roundup_pow_of_two(num))
                return -EINVAL;
@@ -142,8 +136,7 @@ int mlx4_bitmap_init(struct mlx4_bitmap *bitmap, u32 num, u32 mask,
        if (!bitmap->table)
                return -ENOMEM;
 
-       for (i = 0; i < reserved_bot; ++i)
-               set_bit(i, bitmap->table);
+       bitmap_set(bitmap->table, 0, reserved_bot);
 
        return 0;
 }
@@ -188,7 +181,7 @@ int mlx4_buf_alloc(struct mlx4_dev *dev, int size, int max_direct,
                buf->nbufs       = (size + PAGE_SIZE - 1) / PAGE_SIZE;
                buf->npages      = buf->nbufs;
                buf->page_shift  = PAGE_SHIFT;
-               buf->page_list   = kzalloc(buf->nbufs * sizeof *buf->page_list,
+               buf->page_list   = kcalloc(buf->nbufs, sizeof(*buf->page_list),
                                           GFP_KERNEL);
                if (!buf->page_list)
                        return -ENOMEM;
index b275238fe70d347dd89fa59b3152f1fc1fdc162d..056152b3ff58fc051284a7d629f7876218e8b1de 100644 (file)
 #include "en_port.h"
 
 
-static void mlx4_en_update_lro_stats(struct mlx4_en_priv *priv)
-{
-       int i;
-
-       priv->port_stats.lro_aggregated = 0;
-       priv->port_stats.lro_flushed = 0;
-       priv->port_stats.lro_no_desc = 0;
-
-       for (i = 0; i < priv->rx_ring_num; i++) {
-               priv->port_stats.lro_aggregated += priv->rx_ring[i].lro.stats.aggregated;
-               priv->port_stats.lro_flushed += priv->rx_ring[i].lro.stats.flushed;
-               priv->port_stats.lro_no_desc += priv->rx_ring[i].lro.stats.no_desc;
-       }
-}
-
 static void
 mlx4_en_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo)
 {
@@ -112,7 +97,7 @@ static const char main_strings[][ETH_GSTRING_LEN] = {
        "tx_heartbeat_errors", "tx_window_errors",
 
        /* port statistics */
-       "lro_aggregated", "lro_flushed", "lro_no_desc", "tso_packets",
+       "tso_packets",
        "queue_stopped", "wake_queue", "tx_timeout", "rx_alloc_failed",
        "rx_csum_good", "rx_csum_none", "tx_chksum_offload",
 
@@ -125,6 +110,14 @@ static const char main_strings[][ETH_GSTRING_LEN] = {
 #define NUM_MAIN_STATS 21
 #define NUM_ALL_STATS  (NUM_MAIN_STATS + NUM_PORT_STATS + NUM_PKT_STATS + NUM_PERF_STATS)
 
+static const char mlx4_en_test_names[][ETH_GSTRING_LEN]= {
+       "Interupt Test",
+       "Link Test",
+       "Speed Test",
+       "Register Test",
+       "Loopback Test",
+};
+
 static u32 mlx4_en_get_msglevel(struct net_device *dev)
 {
        return ((struct mlx4_en_priv *) netdev_priv(dev))->msg_enable;
@@ -146,10 +139,15 @@ static int mlx4_en_get_sset_count(struct net_device *dev, int sset)
 {
        struct mlx4_en_priv *priv = netdev_priv(dev);
 
-       if (sset != ETH_SS_STATS)
+       switch (sset) {
+       case ETH_SS_STATS:
+               return NUM_ALL_STATS +
+                       (priv->tx_ring_num + priv->rx_ring_num) * 2;
+       case ETH_SS_TEST:
+               return MLX4_EN_NUM_SELF_TEST - !(priv->mdev->dev->caps.loopback_support) * 2;
+       default:
                return -EOPNOTSUPP;
-
-       return NUM_ALL_STATS + (priv->tx_ring_num + priv->rx_ring_num) * 2;
+       }
 }
 
 static void mlx4_en_get_ethtool_stats(struct net_device *dev,
@@ -161,8 +159,6 @@ static void mlx4_en_get_ethtool_stats(struct net_device *dev,
 
        spin_lock_bh(&priv->stats_lock);
 
-       mlx4_en_update_lro_stats(priv);
-
        for (i = 0; i < NUM_MAIN_STATS; i++)
                data[index++] = ((unsigned long *) &priv->stats)[i];
        for (i = 0; i < NUM_PORT_STATS; i++)
@@ -181,6 +177,12 @@ static void mlx4_en_get_ethtool_stats(struct net_device *dev,
 
 }
 
+static void mlx4_en_self_test(struct net_device *dev,
+                             struct ethtool_test *etest, u64 *buf)
+{
+       mlx4_en_ex_selftest(dev, &etest->flags, buf);
+}
+
 static void mlx4_en_get_strings(struct net_device *dev,
                                uint32_t stringset, uint8_t *data)
 {
@@ -188,44 +190,76 @@ static void mlx4_en_get_strings(struct net_device *dev,
        int index = 0;
        int i;
 
-       if (stringset != ETH_SS_STATS)
-               return;
-
-       /* Add main counters */
-       for (i = 0; i < NUM_MAIN_STATS; i++)
-               strcpy(data + (index++) * ETH_GSTRING_LEN, main_strings[i]);
-       for (i = 0; i < NUM_PORT_STATS; i++)
-               strcpy(data + (index++) * ETH_GSTRING_LEN,
+       switch (stringset) {
+       case ETH_SS_TEST:
+               for (i = 0; i < MLX4_EN_NUM_SELF_TEST - 2; i++)
+                       strcpy(data + i * ETH_GSTRING_LEN, mlx4_en_test_names[i]);
+               if (priv->mdev->dev->caps.loopback_support)
+                       for (; i < MLX4_EN_NUM_SELF_TEST; i++)
+                               strcpy(data + i * ETH_GSTRING_LEN, mlx4_en_test_names[i]);
+               break;
+
+       case ETH_SS_STATS:
+               /* Add main counters */
+               for (i = 0; i < NUM_MAIN_STATS; i++)
+                       strcpy(data + (index++) * ETH_GSTRING_LEN, main_strings[i]);
+               for (i = 0; i< NUM_PORT_STATS; i++)
+                       strcpy(data + (index++) * ETH_GSTRING_LEN,
                        main_strings[i + NUM_MAIN_STATS]);
-       for (i = 0; i < priv->tx_ring_num; i++) {
-               sprintf(data + (index++) * ETH_GSTRING_LEN,
-                       "tx%d_packets", i);
-               sprintf(data + (index++) * ETH_GSTRING_LEN,
-                       "tx%d_bytes", i);
-       }
-       for (i = 0; i < priv->rx_ring_num; i++) {
-               sprintf(data + (index++) * ETH_GSTRING_LEN,
-                       "rx%d_packets", i);
-               sprintf(data + (index++) * ETH_GSTRING_LEN,
-                       "rx%d_bytes", i);
-       }
-       for (i = 0; i < NUM_PKT_STATS; i++)
-               strcpy(data + (index++) * ETH_GSTRING_LEN,
+               for (i = 0; i < priv->tx_ring_num; i++) {
+                       sprintf(data + (index++) * ETH_GSTRING_LEN,
+                               "tx%d_packets", i);
+                       sprintf(data + (index++) * ETH_GSTRING_LEN,
+                               "tx%d_bytes", i);
+               }
+               for (i = 0; i < priv->rx_ring_num; i++) {
+                       sprintf(data + (index++) * ETH_GSTRING_LEN,
+                               "rx%d_packets", i);
+                       sprintf(data + (index++) * ETH_GSTRING_LEN,
+                               "rx%d_bytes", i);
+               }
+               for (i = 0; i< NUM_PKT_STATS; i++)
+                       strcpy(data + (index++) * ETH_GSTRING_LEN,
                        main_strings[i + NUM_MAIN_STATS + NUM_PORT_STATS]);
+               break;
+       }
 }
 
 static int mlx4_en_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
+       struct mlx4_en_priv *priv = netdev_priv(dev);
+       int trans_type;
+
        cmd->autoneg = AUTONEG_DISABLE;
        cmd->supported = SUPPORTED_10000baseT_Full;
-       cmd->advertising = ADVERTISED_1000baseT_Full;
+       cmd->advertising = ADVERTISED_10000baseT_Full;
+
+       if (mlx4_en_QUERY_PORT(priv->mdev, priv->port))
+               return -ENOMEM;
+
+       trans_type = priv->port_state.transciver;
        if (netif_carrier_ok(dev)) {
-               cmd->speed = SPEED_10000;
+               cmd->speed = priv->port_state.link_speed;
                cmd->duplex = DUPLEX_FULL;
        } else {
                cmd->speed = -1;
                cmd->duplex = -1;
        }
+
+       if (trans_type > 0 && trans_type <= 0xC) {
+               cmd->port = PORT_FIBRE;
+               cmd->transceiver = XCVR_EXTERNAL;
+               cmd->supported |= SUPPORTED_FIBRE;
+               cmd->advertising |= ADVERTISED_FIBRE;
+       } else if (trans_type == 0x80 || trans_type == 0) {
+               cmd->port = PORT_TP;
+               cmd->transceiver = XCVR_INTERNAL;
+               cmd->supported |= SUPPORTED_TP;
+               cmd->advertising |= ADVERTISED_TP;
+       } else  {
+               cmd->port = -1;
+               cmd->transceiver = -1;
+       }
        return 0;
 }
 
@@ -343,8 +377,9 @@ static int mlx4_en_set_ringparam(struct net_device *dev,
        tx_size = max_t(u32, tx_size, MLX4_EN_MIN_TX_SIZE);
        tx_size = min_t(u32, tx_size, MLX4_EN_MAX_TX_SIZE);
 
-       if (rx_size == priv->prof->rx_ring_size &&
-           tx_size == priv->prof->tx_ring_size)
+       if (rx_size == (priv->port_up ? priv->rx_ring[0].actual_size :
+                                       priv->rx_ring[0].size) &&
+           tx_size == priv->tx_ring[0].size)
                return 0;
 
        mutex_lock(&mdev->state_lock);
@@ -378,49 +413,13 @@ static void mlx4_en_get_ringparam(struct net_device *dev,
                                  struct ethtool_ringparam *param)
 {
        struct mlx4_en_priv *priv = netdev_priv(dev);
-       struct mlx4_en_dev *mdev = priv->mdev;
 
        memset(param, 0, sizeof(*param));
        param->rx_max_pending = MLX4_EN_MAX_RX_SIZE;
        param->tx_max_pending = MLX4_EN_MAX_TX_SIZE;
-       param->rx_pending = mdev->profile.prof[priv->port].rx_ring_size;
-       param->tx_pending = mdev->profile.prof[priv->port].tx_ring_size;
-}
-
-static int mlx4_ethtool_op_set_flags(struct net_device *dev, u32 data)
-{
-       struct mlx4_en_priv *priv = netdev_priv(dev);
-       struct mlx4_en_dev *mdev = priv->mdev;
-       int rc = 0;
-       int changed = 0;
-
-       if (data & ~ETH_FLAG_LRO)
-               return -EOPNOTSUPP;
-
-       if (data & ETH_FLAG_LRO) {
-               if (mdev->profile.num_lro == 0)
-                       return -EOPNOTSUPP;
-               if (!(dev->features & NETIF_F_LRO))
-                       changed = 1;
-       } else if (dev->features & NETIF_F_LRO) {
-               changed = 1;
-       }
-
-       if (changed) {
-               if (netif_running(dev)) {
-                       mutex_lock(&mdev->state_lock);
-                       mlx4_en_stop_port(dev);
-               }
-               dev->features ^= NETIF_F_LRO;
-               if (netif_running(dev)) {
-                       rc = mlx4_en_start_port(dev);
-                       if (rc)
-                               en_err(priv, "Failed to restart port\n");
-                       mutex_unlock(&mdev->state_lock);
-               }
-       }
-
-       return rc;
+       param->rx_pending = priv->port_up ?
+               priv->rx_ring[0].actual_size : priv->rx_ring[0].size;
+       param->tx_pending = priv->tx_ring[0].size;
 }
 
 const struct ethtool_ops mlx4_en_ethtool_ops = {
@@ -441,6 +440,7 @@ const struct ethtool_ops mlx4_en_ethtool_ops = {
        .get_strings = mlx4_en_get_strings,
        .get_sset_count = mlx4_en_get_sset_count,
        .get_ethtool_stats = mlx4_en_get_ethtool_stats,
+       .self_test = mlx4_en_self_test,
        .get_wol = mlx4_en_get_wol,
        .get_msglevel = mlx4_en_get_msglevel,
        .set_msglevel = mlx4_en_set_msglevel,
@@ -451,7 +451,6 @@ const struct ethtool_ops mlx4_en_ethtool_ops = {
        .get_ringparam = mlx4_en_get_ringparam,
        .set_ringparam = mlx4_en_set_ringparam,
        .get_flags = ethtool_op_get_flags,
-       .set_flags = mlx4_ethtool_op_set_flags,
 };
 
 
index 97934f1ec53af83c0dfe40e3b9e8730c83ae1c1e..14390641704881ffb71ded6fd2d19118be07a4d6 100644 (file)
@@ -63,15 +63,12 @@ static const char mlx4_en_version[] =
  */
 
 
-/* Use a XOR rathern than Toeplitz hash function for RSS */
-MLX4_EN_PARM_INT(rss_xor, 0, "Use XOR hash function for RSS");
-
-/* RSS hash type mask - default to <saddr, daddr, sport, dport> */
-MLX4_EN_PARM_INT(rss_mask, 0xf, "RSS hash type bitmask");
-
-/* Number of LRO sessions per Rx ring (rounded up to a power of two) */
-MLX4_EN_PARM_INT(num_lro, MLX4_EN_MAX_LRO_DESCRIPTORS,
-                "Number of LRO sessions per ring or disabled (0)");
+/* Enable RSS TCP traffic */
+MLX4_EN_PARM_INT(tcp_rss, 1,
+                "Enable RSS for incomming TCP traffic or disabled (0)");
+/* Enable RSS UDP traffic */
+MLX4_EN_PARM_INT(udp_rss, 1,
+                "Enable RSS for incomming UDP traffic or disabled (0)");
 
 /* Priority pausing */
 MLX4_EN_PARM_INT(pfctx, 0, "Priority based Flow Control policy on TX[7:0]."
@@ -107,9 +104,12 @@ static int mlx4_en_get_profile(struct mlx4_en_dev *mdev)
        struct mlx4_en_profile *params = &mdev->profile;
        int i;
 
-       params->rss_xor = (rss_xor != 0);
-       params->rss_mask = rss_mask & 0x1f;
-       params->num_lro = min_t(int, num_lro , MLX4_EN_MAX_LRO_DESCRIPTORS);
+       params->tcp_rss = tcp_rss;
+       params->udp_rss = udp_rss;
+       if (params->udp_rss && !mdev->dev->caps.udp_rss) {
+               mlx4_warn(mdev, "UDP RSS is not supported on this device.\n");
+               params->udp_rss = 0;
+       }
        for (i = 1; i <= MLX4_MAX_PORTS; i++) {
                params->prof[i].rx_pause = 1;
                params->prof[i].rx_ppp = pfcrx;
index a0d8a26f5a025be35c67ff29b4a124f34ceb1c78..411bda581c04febc9a6affd350e1266640f281dd 100644 (file)
@@ -109,7 +109,7 @@ static void mlx4_en_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
        mutex_unlock(&mdev->state_lock);
 }
 
-static u64 mlx4_en_mac_to_u64(u8 *addr)
+u64 mlx4_en_mac_to_u64(u8 *addr)
 {
        u64 mac = 0;
        int i;
@@ -513,6 +513,10 @@ static void mlx4_en_do_get_stats(struct work_struct *work)
 
                queue_delayed_work(mdev->workqueue, &priv->stats_task, STATS_DELAY);
        }
+       if (mdev->mac_removed[MLX4_MAX_PORTS + 1 - priv->port]) {
+               queue_work(mdev->workqueue, &priv->mac_task);
+               mdev->mac_removed[MLX4_MAX_PORTS + 1 - priv->port] = 0;
+       }
        mutex_unlock(&mdev->state_lock);
 }
 
@@ -528,10 +532,10 @@ static void mlx4_en_linkstate(struct work_struct *work)
         * report to system log */
        if (priv->last_link_state != linkstate) {
                if (linkstate == MLX4_DEV_EVENT_PORT_DOWN) {
-                       en_dbg(LINK, priv, "Link Down\n");
+                       en_info(priv, "Link Down\n");
                        netif_carrier_off(priv->dev);
                } else {
-                       en_dbg(LINK, priv, "Link Up\n");
+                       en_info(priv, "Link Up\n");
                        netif_carrier_on(priv->dev);
                }
        }
@@ -653,6 +657,7 @@ int mlx4_en_start_port(struct net_device *dev)
                en_err(priv, "Failed setting port mac\n");
                goto tx_err;
        }
+       mdev->mac_removed[priv->port] = 0;
 
        /* Init port */
        en_dbg(HW, priv, "Initializing port\n");
@@ -704,12 +709,12 @@ void mlx4_en_stop_port(struct net_device *dev)
        netif_tx_stop_all_queues(dev);
        netif_tx_unlock_bh(dev);
 
-       /* close port*/
+       /* Set port as not active */
        priv->port_up = false;
-       mlx4_CLOSE_PORT(mdev->dev, priv->port);
 
        /* Unregister Mac address for the port */
        mlx4_unregister_mac(mdev->dev, priv->port, priv->mac_index);
+       mdev->mac_removed[priv->port] = 1;
 
        /* Free TX Rings */
        for (i = 0; i < priv->tx_ring_num; i++) {
@@ -731,6 +736,9 @@ void mlx4_en_stop_port(struct net_device *dev)
                        msleep(1);
                mlx4_en_deactivate_cq(priv, &priv->rx_cq[i]);
        }
+
+       /* close port*/
+       mlx4_CLOSE_PORT(mdev->dev, priv->port);
 }
 
 static void mlx4_en_restart(struct work_struct *work)
@@ -1023,9 +1031,10 @@ 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++)
-               dev->dev_addr[ETH_ALEN - 1 - i] =
-               (u8) (priv->mac >> (8 * 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
@@ -1038,8 +1047,7 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
        dev->features |= NETIF_F_HW_VLAN_TX |
                         NETIF_F_HW_VLAN_RX |
                         NETIF_F_HW_VLAN_FILTER;
-       if (mdev->profile.num_lro)
-               dev->features |= NETIF_F_LRO;
+       dev->features |= NETIF_F_GRO;
        if (mdev->LSO_support) {
                dev->features |= NETIF_F_TSO;
                dev->features |= NETIF_F_TSO6;
index a29abe845d2e83d2d61e6087c8ed489abcdc123d..aa3ef2aee5bf8435575a6f75a8e65502ebc09456 100644 (file)
@@ -142,6 +142,38 @@ int mlx4_SET_PORT_qpn_calc(struct mlx4_dev *dev, u8 port, u32 base_qpn,
        return err;
 }
 
+int mlx4_en_QUERY_PORT(struct mlx4_en_dev *mdev, u8 port)
+{
+       struct mlx4_en_query_port_context *qport_context;
+       struct mlx4_en_priv *priv = netdev_priv(mdev->pndev[port]);
+       struct mlx4_en_port_state *state = &priv->port_state;
+       struct mlx4_cmd_mailbox *mailbox;
+       int err;
+
+       mailbox = mlx4_alloc_cmd_mailbox(mdev->dev);
+       if (IS_ERR(mailbox))
+               return PTR_ERR(mailbox);
+       memset(mailbox->buf, 0, sizeof(*qport_context));
+       err = mlx4_cmd_box(mdev->dev, 0, mailbox->dma, port, 0,
+                          MLX4_CMD_QUERY_PORT, MLX4_CMD_TIME_CLASS_B);
+       if (err)
+               goto out;
+       qport_context = mailbox->buf;
+
+       /* This command is always accessed from Ethtool context
+        * already synchronized, no need in locking */
+       state->link_state = !!(qport_context->link_up & MLX4_EN_LINK_UP_MASK);
+       if ((qport_context->link_speed & MLX4_EN_SPEED_MASK) ==
+           MLX4_EN_1G_SPEED)
+               state->link_speed = 1000;
+       else
+               state->link_speed = 10000;
+       state->transciver = qport_context->transceiver;
+
+out:
+       mlx4_free_cmd_mailbox(mdev->dev, mailbox);
+       return err;
+}
 
 int mlx4_en_DUMP_ETH_STATS(struct mlx4_en_dev *mdev, u8 port, u8 reset)
 {
index e6477f12beb53618db726076584d2dbfc803989a..f6511aa2b7dfba0a8fca919f606189be9b3a2a5b 100644 (file)
@@ -84,6 +84,20 @@ enum {
        MLX4_MCAST_ENABLE       = 2,
 };
 
+struct mlx4_en_query_port_context {
+       u8 link_up;
+#define MLX4_EN_LINK_UP_MASK   0x80
+       u8 reserved;
+       __be16 mtu;
+       u8 reserved2;
+       u8 link_speed;
+#define MLX4_EN_SPEED_MASK     0x3
+#define MLX4_EN_1G_SPEED       0x2
+       u16 reserved3[5];
+       __be64 mac;
+       u8 transceiver;
+};
+
 
 struct mlx4_en_stat_out_mbox {
        /* Received frames with a length of 64 octets */
index 8e2fcb7103c3a12a3072549881a7529d3062bc85..570f2508fb30b423982ae14f228ef1e3539f13b4 100644 (file)
 #include "mlx4_en.h"
 
 
-static int mlx4_en_get_frag_header(struct skb_frag_struct *frags, void **mac_hdr,
-                                  void **ip_hdr, void **tcpudp_hdr,
-                                  u64 *hdr_flags, void *priv)
-{
-       *mac_hdr = page_address(frags->page) + frags->page_offset;
-       *ip_hdr = *mac_hdr + ETH_HLEN;
-       *tcpudp_hdr = (struct tcphdr *)(*ip_hdr + sizeof(struct iphdr));
-       *hdr_flags = LRO_IPV4 | LRO_TCP;
-
-       return 0;
-}
-
 static int mlx4_en_alloc_frag(struct mlx4_en_priv *priv,
                              struct mlx4_en_rx_desc *rx_desc,
                              struct skb_frag_struct *skb_frags,
@@ -251,7 +239,6 @@ reduce_rings:
                        ring->prod--;
                        mlx4_en_free_rx_desc(priv, ring, ring->actual_size);
                }
-               ring->size_mask = ring->actual_size - 1;
        }
 
        return 0;
@@ -313,28 +300,8 @@ int mlx4_en_create_rx_ring(struct mlx4_en_priv *priv,
        }
        ring->buf = ring->wqres.buf.direct.buf;
 
-       /* Configure lro mngr */
-       memset(&ring->lro, 0, sizeof(struct net_lro_mgr));
-       ring->lro.dev = priv->dev;
-       ring->lro.features = LRO_F_NAPI;
-       ring->lro.frag_align_pad = NET_IP_ALIGN;
-       ring->lro.ip_summed = CHECKSUM_UNNECESSARY;
-       ring->lro.ip_summed_aggr = CHECKSUM_UNNECESSARY;
-       ring->lro.max_desc = mdev->profile.num_lro;
-       ring->lro.max_aggr = MAX_SKB_FRAGS;
-       ring->lro.lro_arr = kzalloc(mdev->profile.num_lro *
-                                   sizeof(struct net_lro_desc),
-                                   GFP_KERNEL);
-       if (!ring->lro.lro_arr) {
-               en_err(priv, "Failed to allocate lro array\n");
-               goto err_map;
-       }
-       ring->lro.get_frag_header = mlx4_en_get_frag_header;
-
        return 0;
 
-err_map:
-       mlx4_en_unmap_buffer(&ring->wqres.buf);
 err_hwq:
        mlx4_free_hwq_res(mdev->dev, &ring->wqres, ring->buf_size);
 err_ring:
@@ -389,6 +356,7 @@ int mlx4_en_activate_rx_rings(struct mlx4_en_priv *priv)
        for (ring_ind = 0; ring_ind < priv->rx_ring_num; ring_ind++) {
                ring = &priv->rx_ring[ring_ind];
 
+               ring->size_mask = ring->actual_size - 1;
                mlx4_en_update_rx_prod_db(ring);
        }
 
@@ -412,7 +380,6 @@ void mlx4_en_destroy_rx_ring(struct mlx4_en_priv *priv,
 {
        struct mlx4_en_dev *mdev = priv->mdev;
 
-       kfree(ring->lro.lro_arr);
        mlx4_en_unmap_buffer(&ring->wqres.buf);
        mlx4_free_hwq_res(mdev->dev, &ring->wqres, ring->buf_size + TXBB_SIZE);
        vfree(ring->rx_info);
@@ -459,7 +426,7 @@ static int mlx4_en_complete_rx_desc(struct mlx4_en_priv *priv,
                        goto fail;
 
                /* Unmap buffer */
-               pci_unmap_single(mdev->pdev, dma, skb_frags[nr].size,
+               pci_unmap_single(mdev->pdev, dma, skb_frags_rx[nr].size,
                                 PCI_DMA_FROMDEVICE);
        }
        /* Adjust size of last fragment to match actual length */
@@ -541,6 +508,21 @@ static struct sk_buff *mlx4_en_rx_skb(struct mlx4_en_priv *priv,
        return skb;
 }
 
+static void validate_loopback(struct mlx4_en_priv *priv, struct sk_buff *skb)
+{
+       int i;
+       int offset = ETH_HLEN;
+
+       for (i = 0; i < MLX4_LOOPBACK_TEST_PAYLOAD; i++, offset++) {
+               if (*(skb->data + offset) != (unsigned char) (i & 0xff))
+                       goto out_loopback;
+       }
+       /* Loopback found */
+       priv->loopback_ok = 1;
+
+out_loopback:
+       dev_kfree_skb_any(skb);
+}
 
 int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int budget)
 {
@@ -548,7 +530,6 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
        struct mlx4_cqe *cqe;
        struct mlx4_en_rx_ring *ring = &priv->rx_ring[cq->ring];
        struct skb_frag_struct *skb_frags;
-       struct skb_frag_struct lro_frags[MLX4_EN_MAX_RX_FRAGS];
        struct mlx4_en_rx_desc *rx_desc;
        struct sk_buff *skb;
        int index;
@@ -608,37 +589,35 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
                                 * - TCP/IP (v4)
                                 * - without IP options
                                 * - not an IP fragment */
-                               if (mlx4_en_can_lro(cqe->status) &&
-                                   dev->features & NETIF_F_LRO) {
+                               if (dev->features & NETIF_F_GRO) {
+                                       struct sk_buff *gro_skb = napi_get_frags(&cq->napi);
+                                       if (!gro_skb)
+                                               goto next;
 
                                        nr = mlx4_en_complete_rx_desc(
                                                priv, rx_desc,
-                                               skb_frags, lro_frags,
+                                               skb_frags, skb_shinfo(gro_skb)->frags,
                                                ring->page_alloc, length);
                                        if (!nr)
                                                goto next;
 
+                                       skb_shinfo(gro_skb)->nr_frags = nr;
+                                       gro_skb->len = length;
+                                       gro_skb->data_len = length;
+                                       gro_skb->truesize += length;
+                                       gro_skb->ip_summed = CHECKSUM_UNNECESSARY;
+
                                        if (priv->vlgrp && (cqe->vlan_my_qpn &
-                                                           cpu_to_be32(MLX4_CQE_VLAN_PRESENT_MASK))) {
-                                               lro_vlan_hwaccel_receive_frags(
-                                                      &ring->lro, lro_frags,
-                                                      length, length,
-                                                      priv->vlgrp,
-                                                      be16_to_cpu(cqe->sl_vid),
-                                                      NULL, 0);
-                                       } else
-                                               lro_receive_frags(&ring->lro,
-                                                                 lro_frags,
-                                                                 length,
-                                                                 length,
-                                                                 NULL, 0);
+                                                           cpu_to_be32(MLX4_CQE_VLAN_PRESENT_MASK)))
+                                               vlan_gro_frags(&cq->napi, priv->vlgrp, be16_to_cpu(cqe->sl_vid));
+                                       else
+                                               napi_gro_frags(&cq->napi);
 
                                        goto next;
                                }
 
                                /* LRO not possible, complete processing here */
                                ip_summed = CHECKSUM_UNNECESSARY;
-                               INC_PERF_COUNTER(priv->pstats.lro_misses);
                        } else {
                                ip_summed = CHECKSUM_NONE;
                                priv->port_stats.rx_chksum_none++;
@@ -655,6 +634,11 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
                        goto next;
                }
 
+                if (unlikely(priv->validate_loopback)) {
+                       validate_loopback(priv, skb);
+                       goto next;
+               }
+
                skb->ip_summed = ip_summed;
                skb->protocol = eth_type_trans(skb, dev);
                skb_record_rx_queue(skb, cq->ring);
@@ -674,14 +658,10 @@ next:
                if (++polled == budget) {
                        /* We are here because we reached the NAPI budget -
                         * flush only pending LRO sessions */
-                       lro_flush_all(&ring->lro);
                        goto out;
                }
        }
 
-       /* If CQ is empty flush all LRO sessions unconditionally */
-       lro_flush_all(&ring->lro);
-
 out:
        AVG_PERF_COUNTER(priv->pstats.rx_coal_avg, polled);
        mlx4_cq_set_ci(&cq->mcq);
@@ -816,7 +796,7 @@ static int mlx4_en_config_rss_qp(struct mlx4_en_priv *priv, int qpn,
        qp->event = mlx4_en_sqp_event;
 
        memset(context, 0, sizeof *context);
-       mlx4_en_fill_qp_context(priv, ring->size, ring->stride, 0, 0,
+       mlx4_en_fill_qp_context(priv, ring->actual_size, ring->stride, 0, 0,
                                qpn, ring->cqn, context);
        context->db_rec_addr = cpu_to_be64(ring->wqres.db.dma);
 
@@ -839,8 +819,7 @@ int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv)
        struct mlx4_qp_context context;
        struct mlx4_en_rss_context *rss_context;
        void *ptr;
-       int rss_xor = mdev->profile.rss_xor;
-       u8 rss_mask = mdev->profile.rss_mask;
+       u8 rss_mask = 0x3f;
        int i, qpn;
        int err = 0;
        int good_qps = 0;
@@ -886,9 +865,10 @@ int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv)
        rss_context->base_qpn = cpu_to_be32(ilog2(priv->rx_ring_num) << 24 |
                                            (rss_map->base_qpn));
        rss_context->default_qpn = cpu_to_be32(rss_map->base_qpn);
-       rss_context->hash_fn = rss_xor & 0x3;
-       rss_context->flags = rss_mask << 2;
+       rss_context->flags = rss_mask;
 
+       if (priv->mdev->profile.udp_rss)
+               rss_context->base_qpn_udp = rss_context->default_qpn;
        err = mlx4_qp_to_ready(mdev->dev, &priv->res.mtt, &context,
                               &rss_map->indir_qp, &rss_map->indir_state);
        if (err)
diff --git a/drivers/net/mlx4/en_selftest.c b/drivers/net/mlx4/en_selftest.c
new file mode 100644 (file)
index 0000000..43357d3
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2007 Mellanox Technologies. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/ethtool.h>
+#include <linux/netdevice.h>
+#include <linux/delay.h>
+#include <linux/mlx4/driver.h>
+
+#include "mlx4_en.h"
+
+
+static int mlx4_en_test_registers(struct mlx4_en_priv *priv)
+{
+       return mlx4_cmd(priv->mdev->dev, 0, 0, 0, MLX4_CMD_HW_HEALTH_CHECK,
+                       MLX4_CMD_TIME_CLASS_A);
+}
+
+static int mlx4_en_test_loopback_xmit(struct mlx4_en_priv *priv)
+{
+       struct sk_buff *skb;
+       struct ethhdr *ethh;
+       unsigned char *packet;
+       unsigned int packet_size = MLX4_LOOPBACK_TEST_PAYLOAD;
+       unsigned int i;
+       int err;
+
+
+       /* build the pkt before xmit */
+       skb = netdev_alloc_skb(priv->dev, MLX4_LOOPBACK_TEST_PAYLOAD + ETH_HLEN + NET_IP_ALIGN);
+       if (!skb) {
+               en_err(priv, "-LOOPBACK_TEST_XMIT- failed to create skb for xmit\n");
+               return -ENOMEM;
+       }
+       skb_reserve(skb, NET_IP_ALIGN);
+
+       ethh = (struct ethhdr *)skb_put(skb, sizeof(struct ethhdr));
+       packet  = (unsigned char *)skb_put(skb, packet_size);
+       memcpy(ethh->h_dest, priv->dev->dev_addr, ETH_ALEN);
+       memset(ethh->h_source, 0, ETH_ALEN);
+       ethh->h_proto = htons(ETH_P_ARP);
+       skb_set_mac_header(skb, 0);
+       for (i = 0; i < packet_size; ++i)       /* fill our packet */
+               packet[i] = (unsigned char)(i & 0xff);
+
+       /* xmit the pkt */
+       err = mlx4_en_xmit(skb, priv->dev);
+       return err;
+}
+
+static int mlx4_en_test_loopback(struct mlx4_en_priv *priv)
+{
+       u32 loopback_ok = 0;
+       int i;
+
+
+        priv->loopback_ok = 0;
+       priv->validate_loopback = 1;
+
+       /* xmit */
+       if (mlx4_en_test_loopback_xmit(priv)) {
+               en_err(priv, "Transmitting loopback packet failed\n");
+               goto mlx4_en_test_loopback_exit;
+       }
+
+       /* polling for result */
+       for (i = 0; i < MLX4_EN_LOOPBACK_RETRIES; ++i) {
+               msleep(MLX4_EN_LOOPBACK_TIMEOUT);
+               if (priv->loopback_ok) {
+                       loopback_ok = 1;
+                       break;
+               }
+       }
+       if (!loopback_ok)
+               en_err(priv, "Loopback packet didn't arrive\n");
+
+mlx4_en_test_loopback_exit:
+
+       priv->validate_loopback = 0;
+       return (!loopback_ok);
+}
+
+
+static int mlx4_en_test_link(struct mlx4_en_priv *priv)
+{
+       if (mlx4_en_QUERY_PORT(priv->mdev, priv->port))
+               return -ENOMEM;
+       if (priv->port_state.link_state == 1)
+               return 0;
+       else
+               return 1;
+}
+
+static int mlx4_en_test_speed(struct mlx4_en_priv *priv)
+{
+
+       if (mlx4_en_QUERY_PORT(priv->mdev, priv->port))
+               return -ENOMEM;
+
+       /* The device currently only supports 10G speed */
+       if (priv->port_state.link_speed != SPEED_10000)
+               return priv->port_state.link_speed;
+       return 0;
+}
+
+
+void mlx4_en_ex_selftest(struct net_device *dev, u32 *flags, u64 *buf)
+{
+       struct mlx4_en_priv *priv = netdev_priv(dev);
+       struct mlx4_en_dev *mdev = priv->mdev;
+       struct mlx4_en_tx_ring *tx_ring;
+       int i, carrier_ok;
+
+       memset(buf, 0, sizeof(u64) * MLX4_EN_NUM_SELF_TEST);
+
+       if (*flags & ETH_TEST_FL_OFFLINE) {
+               /* disable the interface */
+               carrier_ok = netif_carrier_ok(dev);
+
+               netif_carrier_off(dev);
+retry_tx:
+               /* Wait untill all tx queues are empty.
+                * there should not be any additional incoming traffic
+                * since we turned the carrier off */
+               msleep(200);
+               for (i = 0; i < priv->tx_ring_num && carrier_ok; i++) {
+                       tx_ring = &priv->tx_ring[i];
+                       if (tx_ring->prod != (tx_ring->cons + tx_ring->last_nr_txbb))
+                               goto retry_tx;
+               }
+
+               if (priv->mdev->dev->caps.loopback_support){
+                       buf[3] = mlx4_en_test_registers(priv);
+                       buf[4] = mlx4_en_test_loopback(priv);
+               }
+
+               if (carrier_ok)
+                       netif_carrier_on(dev);
+
+       }
+       buf[0] = mlx4_test_interrupts(mdev->dev);
+       buf[1] = mlx4_en_test_link(priv);
+       buf[2] = mlx4_en_test_speed(priv);
+
+       for (i = 0; i < MLX4_EN_NUM_SELF_TEST; i++) {
+               if (buf[i])
+                       *flags |= ETH_TEST_FL_FAILED;
+       }
+}
index 580968f304eb9d24f752e38fc368e64208700510..98dd620042a8ed293cf6a6ea656eb88ecb138ab6 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/skbuff.h>
 #include <linux/if_vlan.h>
 #include <linux/vmalloc.h>
+#include <linux/tcp.h>
 
 #include "mlx4_en.h"
 
@@ -600,6 +601,9 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
        struct mlx4_wqe_data_seg *data;
        struct skb_frag_struct *frag;
        struct mlx4_en_tx_info *tx_info;
+       struct ethhdr *ethh;
+       u64 mac;
+       u32 mac_l, mac_h;
        int tx_ind = 0;
        int nr_txbb;
        int desc_size;
@@ -612,6 +616,9 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
        int lso_header_size;
        void *fragptr;
 
+       if (!priv->port_up)
+               goto tx_drop;
+
        real_size = get_real_size(skb, dev, &lso_header_size);
        if (unlikely(!real_size))
                goto tx_drop;
@@ -676,6 +683,19 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
                priv->port_stats.tx_chksum_offload++;
        }
 
+       if (unlikely(priv->validate_loopback)) {
+               /* Copy dst mac address to wqe */
+               skb_reset_mac_header(skb);
+               ethh = eth_hdr(skb);
+               if (ethh && ethh->h_dest) {
+                       mac = mlx4_en_mac_to_u64(ethh->h_dest);
+                       mac_h = (u32) ((mac & 0xffff00000000ULL) >> 16);
+                       mac_l = (u32) (mac & 0xffffffff);
+                       tx_desc->ctrl.srcrb_flags |= cpu_to_be32(mac_h);
+                       tx_desc->ctrl.imm = cpu_to_be32(mac_l);
+               }
+       }
+
        /* Handle LSO (TSO) packets */
        if (lso_header_size) {
                /* Mark opcode as LSO */
index 6d7b2bf210ceb8818a811699d179819304df8510..552d0fce6f671a50da289aa5b7d96f5ce05fb874 100644 (file)
@@ -699,3 +699,47 @@ void mlx4_cleanup_eq_table(struct mlx4_dev *dev)
 
        kfree(priv->eq_table.uar_map);
 }
+
+/* A test that verifies that we can accept interrupts on all
+ * the irq vectors of the device.
+ * Interrupts are checked using the NOP command.
+ */
+int mlx4_test_interrupts(struct mlx4_dev *dev)
+{
+       struct mlx4_priv *priv = mlx4_priv(dev);
+       int i;
+       int err;
+
+       err = mlx4_NOP(dev);
+       /* When not in MSI_X, there is only one irq to check */
+       if (!(dev->flags & MLX4_FLAG_MSI_X))
+               return err;
+
+       /* A loop over all completion vectors, for each vector we will check
+        * whether it works by mapping command completions to that vector
+        * and performing a NOP command
+        */
+       for(i = 0; !err && (i < dev->caps.num_comp_vectors); ++i) {
+               /* Temporary use polling for command completions */
+               mlx4_cmd_use_polling(dev);
+
+               /* Map the new eq to handle all asyncronous events */
+               err = mlx4_MAP_EQ(dev, MLX4_ASYNC_EVENT_MASK, 0,
+                                 priv->eq_table.eq[i].eqn);
+               if (err) {
+                       mlx4_warn(dev, "Failed mapping eq for interrupt test\n");
+                       mlx4_cmd_use_events(dev);
+                       break;
+               }
+
+               /* Go back to using events */
+               mlx4_cmd_use_events(dev);
+               err = mlx4_NOP(dev);
+       }
+
+       /* Return to default */
+       mlx4_MAP_EQ(dev, MLX4_ASYNC_EVENT_MASK, 0,
+                   priv->eq_table.eq[dev->caps.num_comp_vectors].eqn);
+       return err;
+}
+EXPORT_SYMBOL(mlx4_test_interrupts);
index 04f42ae1eda092d9650af5ef23d16a1b9efdbf52..b716e1a1b2982bae0f25b1ed57793c3ccc31aaa7 100644 (file)
@@ -141,6 +141,7 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
        struct mlx4_cmd_mailbox *mailbox;
        u32 *outbox;
        u8 field;
+       u32 field32;
        u16 size;
        u16 stat_rate;
        int err;
@@ -178,6 +179,8 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
 #define QUERY_DEV_CAP_MAX_GID_OFFSET           0x3b
 #define QUERY_DEV_CAP_RATE_SUPPORT_OFFSET      0x3c
 #define QUERY_DEV_CAP_MAX_PKEY_OFFSET          0x3f
+#define QUERY_DEV_CAP_UDP_RSS_OFFSET           0x42
+#define QUERY_DEV_CAP_ETH_UC_LOOPBACK_OFFSET   0x43
 #define QUERY_DEV_CAP_FLAGS_OFFSET             0x44
 #define QUERY_DEV_CAP_RSVD_UAR_OFFSET          0x48
 #define QUERY_DEV_CAP_UAR_SZ_OFFSET            0x49
@@ -268,6 +271,10 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
        dev_cap->max_msg_sz = 1 << (field & 0x1f);
        MLX4_GET(stat_rate, outbox, QUERY_DEV_CAP_RATE_SUPPORT_OFFSET);
        dev_cap->stat_rate_support = stat_rate;
+       MLX4_GET(field, outbox, QUERY_DEV_CAP_UDP_RSS_OFFSET);
+       dev_cap->udp_rss = field & 0x1;
+       MLX4_GET(field, outbox, QUERY_DEV_CAP_ETH_UC_LOOPBACK_OFFSET);
+       dev_cap->loopback_support = field & 0x1;
        MLX4_GET(dev_cap->flags, outbox, QUERY_DEV_CAP_FLAGS_OFFSET);
        MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_UAR_OFFSET);
        dev_cap->reserved_uars = field >> 4;
@@ -365,6 +372,9 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
 #define QUERY_PORT_MAX_MACVLAN_OFFSET          0x0a
 #define QUERY_PORT_MAX_VL_OFFSET               0x0b
 #define QUERY_PORT_MAC_OFFSET                  0x10
+#define QUERY_PORT_TRANS_VENDOR_OFFSET         0x18
+#define QUERY_PORT_WAVELENGTH_OFFSET           0x1c
+#define QUERY_PORT_TRANS_CODE_OFFSET           0x20
 
                for (i = 1; i <= dev_cap->num_ports; ++i) {
                        err = mlx4_cmd_box(dev, 0, mailbox->dma, i, 0, MLX4_CMD_QUERY_PORT,
@@ -388,6 +398,11 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
                        dev_cap->log_max_vlans[i] = field >> 4;
                        MLX4_GET(dev_cap->eth_mtu[i], outbox, QUERY_PORT_ETH_MTU_OFFSET);
                        MLX4_GET(dev_cap->def_mac[i], outbox, QUERY_PORT_MAC_OFFSET);
+                       MLX4_GET(field32, outbox, QUERY_PORT_TRANS_VENDOR_OFFSET);
+                       dev_cap->trans_type[i] = field32 >> 24;
+                       dev_cap->vendor_oui[i] = field32 & 0xffffff;
+                       MLX4_GET(dev_cap->wavelength[i], outbox, QUERY_PORT_WAVELENGTH_OFFSET);
+                       MLX4_GET(dev_cap->trans_code[i], outbox, QUERY_PORT_TRANS_CODE_OFFSET);
                }
        }
 
index 526d7f30c041849da3b27077bbb8d9007222a5aa..65cc72eb899d0491d53b844a0014d6106bee0c6c 100644 (file)
@@ -73,7 +73,13 @@ struct mlx4_dev_cap {
        int max_pkeys[MLX4_MAX_PORTS + 1];
        u64 def_mac[MLX4_MAX_PORTS + 1];
        u16 eth_mtu[MLX4_MAX_PORTS + 1];
+       int trans_type[MLX4_MAX_PORTS + 1];
+       int vendor_oui[MLX4_MAX_PORTS + 1];
+       u16 wavelength[MLX4_MAX_PORTS + 1];
+       u64 trans_code[MLX4_MAX_PORTS + 1];
        u16 stat_rate_support;
+       int udp_rss;
+       int loopback_support;
        u32 flags;
        int reserved_uars;
        int uar_size;
index 5102ab1ac561dbaece380465a9806d886d29f651..569fa3df381f8131bb6b91454a577bde8314500b 100644 (file)
@@ -184,6 +184,10 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
                dev->caps.eth_mtu_cap[i]    = dev_cap->eth_mtu[i];
                dev->caps.def_mac[i]        = dev_cap->def_mac[i];
                dev->caps.supported_type[i] = dev_cap->supported_port_types[i];
+               dev->caps.trans_type[i]     = dev_cap->trans_type[i];
+               dev->caps.vendor_oui[i]     = dev_cap->vendor_oui[i];
+               dev->caps.wavelength[i]     = dev_cap->wavelength[i];
+               dev->caps.trans_code[i]     = dev_cap->trans_code[i];
        }
 
        dev->caps.num_uars           = dev_cap->uar_size / PAGE_SIZE;
@@ -221,6 +225,8 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
        dev->caps.bmme_flags         = dev_cap->bmme_flags;
        dev->caps.reserved_lkey      = dev_cap->reserved_lkey;
        dev->caps.stat_rate_support  = dev_cap->stat_rate_support;
+       dev->caps.udp_rss            = dev_cap->udp_rss;
+       dev->caps.loopback_support   = dev_cap->loopback_support;
        dev->caps.max_gso_sz         = dev_cap->max_gso_sz;
 
        dev->caps.log_num_macs  = log_num_mac;
index 449210994ee9cee94323fb3646af114aa4ca3619..1fc16ab7ad2f0ebc0d6b7b6d604e593ceb223e69 100644 (file)
 #include <linux/list.h>
 #include <linux/mutex.h>
 #include <linux/netdevice.h>
-#include <linux/inet_lro.h>
 
 #include <linux/mlx4/device.h>
 #include <linux/mlx4/qp.h>
 #include <linux/mlx4/cq.h>
 #include <linux/mlx4/srq.h>
 #include <linux/mlx4/doorbell.h>
+#include <linux/mlx4/cmd.h>
 
 #include "en_port.h"
 
 #define DRV_NAME       "mlx4_en"
-#define DRV_VERSION    "1.4.1.1"
-#define DRV_RELDATE    "June 2009"
+#define DRV_VERSION    "1.5.1.6"
+#define DRV_RELDATE    "August 2010"
 
 #define MLX4_EN_MSG_LEVEL      (NETIF_MSG_LINK | NETIF_MSG_IFDOWN)
 
@@ -61,7 +61,6 @@
 
 #define MLX4_EN_PAGE_SHIFT     12
 #define MLX4_EN_PAGE_SIZE      (1 << MLX4_EN_PAGE_SHIFT)
-#define MAX_TX_RINGS           16
 #define MAX_RX_RINGS           16
 #define TXBB_SIZE              64
 #define HEADROOM               (2048 / TXBB_SIZE + 1)
@@ -107,6 +106,7 @@ enum {
 #define MLX4_EN_SMALL_PKT_SIZE         64
 #define MLX4_EN_NUM_TX_RINGS           8
 #define MLX4_EN_NUM_PPP_RINGS          8
+#define MAX_TX_RINGS                   (MLX4_EN_NUM_TX_RINGS + MLX4_EN_NUM_PPP_RINGS)
 #define MLX4_EN_DEF_TX_RING_SIZE       512
 #define MLX4_EN_DEF_RX_RING_SIZE       1024
 
@@ -139,10 +139,14 @@ enum {
 
 #define SMALL_PACKET_SIZE      (256 - NET_IP_ALIGN)
 #define HEADER_COPY_SIZE       (128 - NET_IP_ALIGN)
+#define MLX4_LOOPBACK_TEST_PAYLOAD (HEADER_COPY_SIZE - ETH_HLEN)
 
 #define MLX4_EN_MIN_MTU                46
 #define ETH_BCAST              0xffffffffffffULL
 
+#define MLX4_EN_LOOPBACK_RETRIES       5
+#define MLX4_EN_LOOPBACK_TIMEOUT       100
+
 #ifdef MLX4_EN_PERF_STAT
 /* Number of samples to 'average' */
 #define AVG_SIZE                       128
@@ -249,7 +253,6 @@ struct mlx4_en_rx_desc {
 struct mlx4_en_rx_ring {
        struct mlx4_hwq_resources wqres;
        struct mlx4_en_rx_alloc page_alloc[MLX4_EN_MAX_RX_FRAGS];
-       struct net_lro_mgr lro;
        u32 size ;      /* number of Rx descs*/
        u32 actual_size;
        u32 size_mask;
@@ -313,7 +316,8 @@ struct mlx4_en_port_profile {
 
 struct mlx4_en_profile {
        int rss_xor;
-       int num_lro;
+       int tcp_rss;
+       int udp_rss;
        u8 rss_mask;
        u32 active_ports;
        u32 small_pkt_int;
@@ -337,6 +341,7 @@ struct mlx4_en_dev {
        struct mlx4_mr          mr;
        u32                     priv_pdn;
        spinlock_t              uar_lock;
+       u8                      mac_removed[MLX4_MAX_PORTS + 1];
 };
 
 
@@ -355,6 +360,13 @@ struct mlx4_en_rss_context {
        u8 hash_fn;
        u8 flags;
        __be32 rss_key[10];
+       __be32 base_qpn_udp;
+};
+
+struct mlx4_en_port_state {
+       int link_state;
+       int link_speed;
+       int transciver;
 };
 
 struct mlx4_en_pkt_stats {
@@ -365,9 +377,6 @@ struct mlx4_en_pkt_stats {
 };
 
 struct mlx4_en_port_stats {
-       unsigned long lro_aggregated;
-       unsigned long lro_flushed;
-       unsigned long lro_no_desc;
        unsigned long tso_packets;
        unsigned long queue_stopped;
        unsigned long wake_queue;
@@ -376,7 +385,7 @@ struct mlx4_en_port_stats {
        unsigned long rx_chksum_good;
        unsigned long rx_chksum_none;
        unsigned long tx_chksum_offload;
-#define NUM_PORT_STATS         11
+#define NUM_PORT_STATS         8
 };
 
 struct mlx4_en_perf_stats {
@@ -405,6 +414,7 @@ struct mlx4_en_priv {
        struct vlan_group *vlgrp;
        struct net_device_stats stats;
        struct net_device_stats ret_stats;
+       struct mlx4_en_port_state port_state;
        spinlock_t stats_lock;
 
        unsigned long last_moder_packets;
@@ -423,6 +433,8 @@ struct mlx4_en_priv {
        u16 sample_interval;
        u16 adaptive_rx_coal;
        u32 msg_enable;
+       u32 loopback_ok;
+       u32 validate_loopback;
 
        struct mlx4_hwq_resources res;
        int link_state;
@@ -531,6 +543,11 @@ int mlx4_SET_PORT_qpn_calc(struct mlx4_dev *dev, u8 port, u32 base_qpn,
                           u8 promisc);
 
 int mlx4_en_DUMP_ETH_STATS(struct mlx4_en_dev *mdev, u8 port, u8 reset);
+int mlx4_en_QUERY_PORT(struct mlx4_en_dev *mdev, u8 port);
+
+#define MLX4_EN_NUM_SELF_TEST  5
+void mlx4_en_ex_selftest(struct net_device *dev, u32 *flags, u64 *buf);
+u64 mlx4_en_mac_to_u64(u8 *addr);
 
 /*
  * Globals
@@ -555,6 +572,8 @@ do {                                                                \
        en_print(KERN_WARNING, priv, format, ##arg)
 #define en_err(priv, format, arg...)                   \
        en_print(KERN_ERR, priv, format, ##arg)
+#define en_info(priv, format, arg...)                  \
+       en_print(KERN_INFO, priv, format, ## arg)
 
 #define mlx4_err(mdev, format, arg...)                 \
        pr_err("%s %s: " format, DRV_NAME,              \
index 5caf0115fa5b4e923e3d10d760c6c1284a21c694..e749f82865fee073175182b5451d683dd2ba1707 100644 (file)
@@ -85,7 +85,7 @@ u64 mlx4_make_profile(struct mlx4_dev *dev,
        struct mlx4_resource tmp;
        int i, j;
 
-       profile = kzalloc(MLX4_RES_NUM * sizeof *profile, GFP_KERNEL);
+       profile = kcalloc(MLX4_RES_NUM, sizeof(*profile), GFP_KERNEL);
        if (!profile)
                return -ENOMEM;
 
index fb2c0927d3ccd76135d069f29971f238886b0f5a..24ab8a43c777be4ba631aa84aaad6fc5b087412e 100644 (file)
@@ -3753,8 +3753,8 @@ static void myri10ge_probe_slices(struct myri10ge_priv *mgp)
         * slices. We give up on MSI-X if we can only get a single
         * vector. */
 
-       mgp->msix_vectors = kzalloc(mgp->num_slices *
-                                   sizeof(*mgp->msix_vectors), GFP_KERNEL);
+       mgp->msix_vectors = kcalloc(mgp->num_slices, sizeof(*mgp->msix_vectors),
+                                   GFP_KERNEL);
        if (mgp->msix_vectors == NULL)
                goto disable_msix;
        for (i = 0; i < mgp->num_slices; i++) {
index a6033d48b5ccae7a1efa2377baac061d15075fb6..2fd39630b1e57c0e706165022335428e173cfb35 100644 (file)
@@ -1570,7 +1570,7 @@ static int netdev_open(struct net_device *dev)
        init_timer(&np->timer);
        np->timer.expires = round_jiffies(jiffies + NATSEMI_TIMER_FREQ);
        np->timer.data = (unsigned long)dev;
-       np->timer.function = &netdev_timer; /* timer handler */
+       np->timer.function = netdev_timer; /* timer handler */
        add_timer(&np->timer);
 
        return 0;
index fe6983af6918fe37cdb5589907346557ddeeb8df..8e1859c801a4e0e056457a65473c85cc17070ffa 100644 (file)
@@ -3484,7 +3484,7 @@ static int niu_process_rx_pkt(struct napi_struct *napi, struct niu *np,
                                     RCR_ENTRY_ERROR)))
                                skb->ip_summed = CHECKSUM_UNNECESSARY;
                        else
-                               skb->ip_summed = CHECKSUM_NONE;
+                               skb_checksum_none_assert(skb);
                } else if (!(val & RCR_ENTRY_MULTI))
                        append_size = len - skb->len;
 
@@ -4504,7 +4504,7 @@ static int niu_alloc_channels(struct niu *np)
 
        np->dev->real_num_tx_queues = np->num_tx_rings;
 
-       np->rx_rings = kzalloc(np->num_rx_rings * sizeof(struct rx_ring_info),
+       np->rx_rings = kcalloc(np->num_rx_rings, sizeof(struct rx_ring_info),
                               GFP_KERNEL);
        err = -ENOMEM;
        if (!np->rx_rings)
@@ -4538,7 +4538,7 @@ static int niu_alloc_channels(struct niu *np)
                        return err;
        }
 
-       np->tx_rings = kzalloc(np->num_tx_rings * sizeof(struct tx_ring_info),
+       np->tx_rings = kcalloc(np->num_tx_rings, sizeof(struct tx_ring_info),
                               GFP_KERNEL);
        err = -ENOMEM;
        if (!np->tx_rings)
index 5a3488f76b388f49939a373abb1e03079ca07554..3bbd0aab17e813201eb51ba35f1f4990e80e7887 100644 (file)
@@ -923,7 +923,7 @@ static void rx_irq(struct net_device *ndev)
                        if ((extsts & 0x002a0000) && !(extsts & 0x00540000)) {
                                skb->ip_summed = CHECKSUM_UNNECESSARY;
                        } else {
-                               skb->ip_summed = CHECKSUM_NONE;
+                               skb_checksum_none_assert(skb);
                        }
                        skb->protocol = eth_type_trans(skb, ndev);
 #ifdef NS83820_VLAN_ACCEL_SUPPORT
@@ -1246,7 +1246,6 @@ static int ns83820_get_settings(struct net_device *ndev,
 {
        struct ns83820 *dev = PRIV(ndev);
        u32 cfg, tanar, tbicr;
-       int have_optical = 0;
        int fullduplex   = 0;
 
        /*
@@ -1267,25 +1266,25 @@ static int ns83820_get_settings(struct net_device *ndev,
        tanar = readl(dev->base + TANAR);
        tbicr = readl(dev->base + TBICR);
 
-       if (dev->CFG_cache & CFG_TBI_EN) {
-               /* we have an optical interface */
-               have_optical = 1;
-               fullduplex = (cfg & CFG_DUPSTS) ? 1 : 0;
-
-       } else {
-               /* We have copper */
-               fullduplex = (cfg & CFG_DUPSTS) ? 1 : 0;
-        }
+       fullduplex = (cfg & CFG_DUPSTS) ? 1 : 0;
 
        cmd->supported = SUPPORTED_Autoneg;
 
-       /* we have optical interface */
        if (dev->CFG_cache & CFG_TBI_EN) {
+               /* we have optical interface */
                cmd->supported |= SUPPORTED_1000baseT_Half |
                                        SUPPORTED_1000baseT_Full |
                                        SUPPORTED_FIBRE;
                cmd->port       = PORT_FIBRE;
-       } /* TODO: else copper related  support */
+       } else {
+               /* we have copper */
+               cmd->supported |= SUPPORTED_10baseT_Half |
+                       SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half |
+                       SUPPORTED_100baseT_Full | SUPPORTED_1000baseT_Half |
+                       SUPPORTED_1000baseT_Full |
+                       SUPPORTED_MII;
+               cmd->port = PORT_MII;
+       }
 
        cmd->duplex = fullduplex ? DUPLEX_FULL : DUPLEX_HALF;
        switch (cfg / CFG_SPDSTS0 & 3) {
@@ -1299,7 +1298,8 @@ static int ns83820_get_settings(struct net_device *ndev,
                cmd->speed = SPEED_10;
                break;
        }
-       cmd->autoneg = (tbicr & TBICR_MR_AN_ENABLE) ? 1: 0;
+       cmd->autoneg = (tbicr & TBICR_MR_AN_ENABLE)
+               ? AUTONEG_ENABLE : AUTONEG_DISABLE;
        return 0;
 }
 
@@ -1405,6 +1405,13 @@ static const struct ethtool_ops ops = {
        .get_link        = ns83820_get_link
 };
 
+static inline void ns83820_disable_interrupts(struct ns83820 *dev)
+{
+       writel(0, dev->base + IMR);
+       writel(0, dev->base + IER);
+       readl(dev->base + IER);
+}
+
 /* this function is called in irq context from the ISR */
 static void ns83820_mib_isr(struct ns83820 *dev)
 {
@@ -1557,10 +1564,7 @@ static int ns83820_stop(struct net_device *ndev)
        /* FIXME: protect against interrupt handler? */
        del_timer_sync(&dev->tx_watchdog);
 
-       /* disable interrupts */
-       writel(0, dev->base + IMR);
-       writel(0, dev->base + IER);
-       readl(dev->base + IER);
+       ns83820_disable_interrupts(dev);
 
        dev->rx_info.up = 0;
        synchronize_irq(dev->pci_dev->irq);
@@ -2023,10 +2027,7 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev,
                dev->tx_descs, (long)dev->tx_phy_descs,
                dev->rx_info.descs, (long)dev->rx_info.phy_descs);
 
-       /* disable interrupts */
-       writel(0, dev->base + IMR);
-       writel(0, dev->base + IER);
-       readl(dev->base + IER);
+       ns83820_disable_interrupts(dev);
 
        dev->IMR_cache = 0;
 
@@ -2250,9 +2251,7 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev,
        return 0;
 
 out_cleanup:
-       writel(0, dev->base + IMR);     /* paranoia */
-       writel(0, dev->base + IER);
-       readl(dev->base + IER);
+       ns83820_disable_interrupts(dev); /* paranoia */
 out_free_irq:
        rtnl_unlock();
        free_irq(pci_dev->irq, ndev);
@@ -2277,9 +2276,7 @@ static void __devexit ns83820_remove_one(struct pci_dev *pci_dev)
        if (!ndev)                      /* paranoia */
                return;
 
-       writel(0, dev->base + IMR);     /* paranoia */
-       writel(0, dev->base + IER);
-       readl(dev->base + IER);
+       ns83820_disable_interrupts(dev); /* paranoia */
 
        unregister_netdev(ndev);
        free_irq(dev->pci_dev->irq, ndev);
index 8ab6ae0a61079dd28f606ce3ca4d637dfdf50e52..828e97cacdbfe33bc9351dea24f7d1b894f9e8af 100644 (file)
@@ -808,7 +808,7 @@ static int pasemi_mac_clean_rx(struct pasemi_mac_rxring *rx,
                        skb->csum = (macrx & XCT_MACRX_CSUM_M) >>
                                           XCT_MACRX_CSUM_S;
                } else
-                       skb->ip_summed = CHECKSUM_NONE;
+                       skb_checksum_none_assert(skb);
 
                packets++;
                tot_bytes += len;
index fefa79e34b95c43386ef1488cfbb673f1d4af886..4825959a0efe1288712ce1080d47a45f6daf254b 100644 (file)
@@ -90,21 +90,6 @@ pasemi_mac_ethtool_set_settings(struct net_device *netdev,
        return phy_ethtool_sset(phydev, cmd);
 }
 
-static void
-pasemi_mac_ethtool_get_drvinfo(struct net_device *netdev,
-                              struct ethtool_drvinfo *drvinfo)
-{
-       struct pasemi_mac *mac;
-       mac = netdev_priv(netdev);
-
-       /* clear and fill out info */
-       memset(drvinfo, 0, sizeof(struct ethtool_drvinfo));
-       strncpy(drvinfo->driver, "pasemi_mac", 12);
-       strcpy(drvinfo->version, "N/A");
-       strcpy(drvinfo->fw_version, "N/A");
-       strncpy(drvinfo->bus_info, pci_name(mac->pdev), 32);
-}
-
 static u32
 pasemi_mac_ethtool_get_msglevel(struct net_device *netdev)
 {
@@ -164,7 +149,6 @@ static void pasemi_mac_get_strings(struct net_device *netdev, u32 stringset,
 const struct ethtool_ops pasemi_mac_ethtool_ops = {
        .get_settings           = pasemi_mac_ethtool_get_settings,
        .set_settings           = pasemi_mac_ethtool_set_settings,
-       .get_drvinfo            = pasemi_mac_ethtool_get_drvinfo,
        .get_msglevel           = pasemi_mac_ethtool_get_msglevel,
        .set_msglevel           = pasemi_mac_ethtool_set_msglevel,
        .get_link               = ethtool_op_get_link,
index 56f3fc45dbaa84ab9ecbc9f2e8a29902413c6ef6..8dd03439d994290a016c872a84a0bf439a7e6393 100644 (file)
@@ -1125,7 +1125,7 @@ static int netdrv_open(struct net_device *dev)
        init_timer(&tp->timer);
        tp->timer.expires = jiffies + 3 * HZ;
        tp->timer.data = (unsigned long) dev;
-       tp->timer.function = &netdrv_timer;
+       tp->timer.function = netdrv_timer;
        add_timer(&tp->timer);
 
        DPRINTK("EXIT, returning 0\n");
index c683f77c6f424ebbc873d76f0e07cb386484ea70..042f6777e6b9133865ff207c37d45a65a88dffba 100644 (file)
@@ -69,6 +69,8 @@ earlier 3Com products.
 
 */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -83,7 +85,6 @@ earlier 3Com products.
 #include <linux/skbuff.h>
 #include <linux/if_arp.h>
 #include <linux/ioport.h>
-#include <linux/ethtool.h>
 #include <linux/bitops.h>
 #include <linux/mii.h>
 
@@ -238,7 +239,6 @@ static int el3_rx(struct net_device *dev, int worklimit);
 static int el3_close(struct net_device *dev);
 static void el3_tx_timeout(struct net_device *dev);
 static int el3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static const struct ethtool_ops netdev_ethtool_ops;
 static void set_rx_mode(struct net_device *dev);
 static void set_multicast_list(struct net_device *dev);
 
@@ -285,7 +285,6 @@ static int tc574_probe(struct pcmcia_device *link)
        link->conf.ConfigIndex = 1;
 
        dev->netdev_ops = &el3_netdev_ops;
-       SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
        dev->watchdog_timeo = TX_TIMEOUT;
 
        return tc574_config(link);
@@ -376,8 +375,8 @@ static int tc574_config(struct pcmcia_device *link)
                for (i = 0; i < 3; i++)
                        phys_addr[i] = htons(read_eeprom(ioaddr, i + 10));
                if (phys_addr[0] == htons(0x6060)) {
-                       printk(KERN_NOTICE "3c574_cs: IO port conflict at 0x%03lx"
-                                  "-0x%03lx\n", dev->base_addr, dev->base_addr+15);
+                       pr_notice("IO port conflict at 0x%03lx-0x%03lx\n",
+                                 dev->base_addr, dev->base_addr+15);
                        goto failed;
                }
        }
@@ -391,7 +390,7 @@ static int tc574_config(struct pcmcia_device *link)
                outw(2<<11, ioaddr + RunnerRdCtrl);
                mcr = inb(ioaddr + 2);
                outw(0<<11, ioaddr + RunnerRdCtrl);
-               printk(KERN_INFO "  ASIC rev %d,", mcr>>3);
+               pr_info("  ASIC rev %d,", mcr>>3);
                EL3WINDOW(3);
                config = inl(ioaddr + Wn3_Config);
                lp->default_media = (config & Xcvr) >> Xcvr_shift;
@@ -428,7 +427,7 @@ static int tc574_config(struct pcmcia_device *link)
                        }
                }
                if (phy > 32) {
-                       printk(KERN_NOTICE "  No MII transceivers found!\n");
+                       pr_notice("  No MII transceivers found!\n");
                        goto failed;
                }
                i = mdio_read(ioaddr, lp->phys, 16) | 0x40;
@@ -444,18 +443,16 @@ static int tc574_config(struct pcmcia_device *link)
        SET_NETDEV_DEV(dev, &link->dev);
 
        if (register_netdev(dev) != 0) {
-               printk(KERN_NOTICE "3c574_cs: register_netdev() failed\n");
+               pr_notice("register_netdev() failed\n");
                goto failed;
        }
 
-       printk(KERN_INFO "%s: %s at io %#3lx, irq %d, "
-              "hw_addr %pM.\n",
-              dev->name, cardname, dev->base_addr, dev->irq,
-              dev->dev_addr);
-       printk(" %dK FIFO split %s Rx:Tx, %sMII interface.\n",
-                  8 << config & Ram_size,
-                  ram_split[(config & Ram_split) >> Ram_split_shift],
-                  config & Autoselect ? "autoselect " : "");
+       netdev_info(dev, "%s at io %#3lx, irq %d, hw_addr %pM\n",
+                   cardname, dev->base_addr, dev->irq, dev->dev_addr);
+       netdev_info(dev, " %dK FIFO split %s Rx:Tx, %sMII interface.\n",
+                   8 << config & Ram_size,
+                   ram_split[(config & Ram_split) >> Ram_split_shift],
+                   config & Autoselect ? "autoselect " : "");
 
        return 0;
 
@@ -502,14 +499,14 @@ static void dump_status(struct net_device *dev)
 {
        unsigned int ioaddr = dev->base_addr;
        EL3WINDOW(1);
-       printk(KERN_INFO "  irq status %04x, rx status %04x, tx status "
-                  "%02x, tx free %04x\n", inw(ioaddr+EL3_STATUS),
-                  inw(ioaddr+RxStatus), inb(ioaddr+TxStatus),
-                  inw(ioaddr+TxFree));
+       netdev_info(dev, "  irq status %04x, rx status %04x, tx status %02x, tx free %04x\n",
+                   inw(ioaddr+EL3_STATUS),
+                   inw(ioaddr+RxStatus), inb(ioaddr+TxStatus),
+                   inw(ioaddr+TxFree));
        EL3WINDOW(4);
-       printk(KERN_INFO "  diagnostics: fifo %04x net %04x ethernet %04x"
-                  " media %04x\n", inw(ioaddr+0x04), inw(ioaddr+0x06),
-                  inw(ioaddr+0x08), inw(ioaddr+0x0a));
+       netdev_info(dev, "  diagnostics: fifo %04x net %04x ethernet %04x media %04x\n",
+                   inw(ioaddr+0x04), inw(ioaddr+0x06),
+                   inw(ioaddr+0x08), inw(ioaddr+0x0a));
        EL3WINDOW(1);
 }
 
@@ -523,7 +520,7 @@ static void tc574_wait_for_completion(struct net_device *dev, int cmd)
        while (--i > 0)
                if (!(inw(dev->base_addr + EL3_STATUS) & 0x1000)) break;
        if (i == 0)
-               printk(KERN_NOTICE "%s: command 0x%04x did not complete!\n", dev->name, cmd);
+               netdev_notice(dev, "command 0x%04x did not complete!\n", cmd);
 }
 
 /* Read a word from the EEPROM using the regular EEPROM access register.
@@ -710,7 +707,7 @@ static int el3_open(struct net_device *dev)
        netif_start_queue(dev);
        
        tc574_reset(dev);
-       lp->media.function = &media_check;
+       lp->media.function = media_check;
        lp->media.data = (unsigned long) dev;
        lp->media.expires = jiffies + HZ;
        add_timer(&lp->media);
@@ -725,7 +722,7 @@ static void el3_tx_timeout(struct net_device *dev)
 {
        unsigned int ioaddr = dev->base_addr;
        
-       printk(KERN_NOTICE "%s: Transmit timed out!\n", dev->name);
+       netdev_notice(dev, "Transmit timed out!\n");
        dump_status(dev);
        dev->stats.tx_errors++;
        dev->trans_start = jiffies; /* prevent tx timeout */
@@ -848,8 +845,8 @@ static irqreturn_t el3_interrupt(int irq, void *dev_id)
                                EL3WINDOW(4);
                                fifo_diag = inw(ioaddr + Wn4_FIFODiag);
                                EL3WINDOW(1);
-                               printk(KERN_NOTICE "%s: adapter failure, FIFO diagnostic"
-                                          " register %04x.\n", dev->name, fifo_diag);
+                               netdev_notice(dev, "adapter failure, FIFO diagnostic register %04x\n",
+                                             fifo_diag);
                                if (fifo_diag & 0x0400) {
                                        /* Tx overrun */
                                        tc574_wait_for_completion(dev, TxReset);
@@ -903,7 +900,7 @@ static void media_check(unsigned long arg)
           this, we can limp along even if the interrupt is blocked */
        if ((inw(ioaddr + EL3_STATUS) & IntLatch) && (inb(ioaddr + Timer) == 0xff)) {
                if (!lp->fast_poll)
-                       printk(KERN_INFO "%s: interrupt(s) dropped!\n", dev->name);
+                       netdev_info(dev, "interrupt(s) dropped!\n");
 
                local_irq_save(flags);
                el3_interrupt(dev->irq, dev);
@@ -926,23 +923,21 @@ static void media_check(unsigned long arg)
        
        if (media != lp->media_status) {
                if ((media ^ lp->media_status) & 0x0004)
-                       printk(KERN_INFO "%s: %s link beat\n", dev->name,
-                                  (lp->media_status & 0x0004) ? "lost" : "found");
+                       netdev_info(dev, "%s link beat\n",
+                                   (lp->media_status & 0x0004) ? "lost" : "found");
                if ((media ^ lp->media_status) & 0x0020) {
                        lp->partner = 0;
                        if (lp->media_status & 0x0020) {
-                               printk(KERN_INFO "%s: autonegotiation restarted\n",
-                                          dev->name);
+                               netdev_info(dev, "autonegotiation restarted\n");
                        } else if (partner) {
                                partner &= lp->advertising;
                                lp->partner = partner;
-                               printk(KERN_INFO "%s: autonegotiation complete: "
-                                          "%sbaseT-%cD selected\n", dev->name,
-                                          ((partner & 0x0180) ? "100" : "10"),
-                                          ((partner & 0x0140) ? 'F' : 'H'));
+                               netdev_info(dev, "autonegotiation complete: "
+                                           "%dbaseT-%cD selected\n",
+                                           (partner & 0x0180) ? 100 : 10,
+                                           (partner & 0x0140) ? 'F' : 'H');
                        } else {
-                               printk(KERN_INFO "%s: link partner did not autonegotiate\n",
-                                          dev->name);
+                               netdev_info(dev, "link partner did not autonegotiate\n");
                        }
 
                        EL3WINDOW(3);
@@ -952,10 +947,9 @@ static void media_check(unsigned long arg)
 
                }
                if (media & 0x0010)
-                       printk(KERN_INFO "%s: remote fault detected\n",
-                                  dev->name);
+                       netdev_info(dev, "remote fault detected\n");
                if (media & 0x0002)
-                       printk(KERN_INFO "%s: jabber detected\n", dev->name);
+                       netdev_info(dev, "jabber detected\n");
                lp->media_status = media;
        }
        spin_unlock_irqrestore(&lp->window_lock, flags);
@@ -1065,16 +1059,6 @@ static int el3_rx(struct net_device *dev, int worklimit)
        return worklimit;
 }
 
-static void netdev_get_drvinfo(struct net_device *dev,
-                              struct ethtool_drvinfo *info)
-{
-       strcpy(info->driver, "3c574_cs");
-}
-
-static const struct ethtool_ops netdev_ethtool_ops = {
-       .get_drvinfo            = netdev_get_drvinfo,
-};
-
 /* Provide ioctl() calls to examine the MII xcvr state. */
 static int el3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
index 61f9cf2100ffd8bfdff824ccfa2c3f3013a8eb1f..7f2baf5eae26a1543a87f681379c71df95638d2c 100644 (file)
@@ -19,6 +19,8 @@
 
 ======================================================================*/
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #define DRV_NAME       "3c589_cs"
 #define DRV_VERSION    "1.162-ac"
 
@@ -273,8 +275,7 @@ static int tc589_config(struct pcmcia_device *link)
     phys_addr = (__be16 *)dev->dev_addr;
     /* Is this a 3c562? */
     if (link->manf_id != MANFID_3COM)
-           printk(KERN_INFO "3c589_cs: hmmm, is this really a "
-                  "3Com card??\n");
+           dev_info(&link->dev, "hmmm, is this really a 3Com card??\n");
     multi = (link->card_id == PRODID_3COM_3C562);
 
     link->io_lines = 16;
@@ -315,8 +316,8 @@ static int tc589_config(struct pcmcia_device *link)
        for (i = 0; i < 3; i++)
            phys_addr[i] = htons(read_eeprom(ioaddr, i));
        if (phys_addr[0] == htons(0x6060)) {
-           printk(KERN_ERR "3c589_cs: IO port conflict at 0x%03lx"
-                  "-0x%03lx\n", dev->base_addr, dev->base_addr+15);
+           dev_err(&link->dev, "IO port conflict at 0x%03lx-0x%03lx\n",
+                   dev->base_addr, dev->base_addr+15);
            goto failed;
        }
     }
@@ -330,12 +331,12 @@ static int tc589_config(struct pcmcia_device *link)
     if ((if_port >= 0) && (if_port <= 3))
        dev->if_port = if_port;
     else
-       printk(KERN_ERR "3c589_cs: invalid if_port requested\n");
+       dev_err(&link->dev, "invalid if_port requested\n");
 
     SET_NETDEV_DEV(dev, &link->dev);
 
     if (register_netdev(dev) != 0) {
-       printk(KERN_ERR "3c589_cs: register_netdev() failed\n");
+           dev_err(&link->dev, "register_netdev() failed\n");
        goto failed;
     }
 
@@ -537,7 +538,7 @@ static int el3_open(struct net_device *dev)
 
     tc589_reset(dev);
     init_timer(&lp->media);
-    lp->media.function = &media_check;
+    lp->media.function = media_check;
     lp->media.data = (unsigned long) dev;
     lp->media.expires = jiffies + HZ;
     add_timer(&lp->media);
index 5f05ffb240cc899eb79537ffe8074ceb97d3da11..3f61fde70d736b42fb5e934f65526334329c2174 100644 (file)
@@ -24,6 +24,8 @@
 
 ======================================================================*/
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
@@ -32,7 +34,6 @@
 #include <linux/timer.h>
 #include <linux/delay.h>
 #include <linux/spinlock.h>
-#include <linux/ethtool.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/crc32.h>
@@ -86,7 +87,6 @@ static netdev_tx_t axnet_start_xmit(struct sk_buff *skb,
 static struct net_device_stats *get_stats(struct net_device *dev);
 static void set_multicast_list(struct net_device *dev);
 static void axnet_tx_timeout(struct net_device *dev);
-static const struct ethtool_ops netdev_ethtool_ops;
 static irqreturn_t ei_irq_wrapper(int irq, void *dev_id);
 static void ei_watchdog(u_long arg);
 static void axnet_reset_8390(struct net_device *dev);
@@ -171,7 +171,6 @@ static int axnet_probe(struct pcmcia_device *link)
 
     dev->netdev_ops = &axnet_netdev_ops;
 
-    SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
     dev->watchdog_timeo = TX_TIMEOUT;
 
     return axnet_config(link);
@@ -347,8 +346,8 @@ static int axnet_config(struct pcmcia_device *link)
     dev->base_addr = link->resource[0]->start;
 
     if (!get_prom(link)) {
-       printk(KERN_NOTICE "axnet_cs: this is not an AX88190 card!\n");
-       printk(KERN_NOTICE "axnet_cs: use pcnet_cs instead.\n");
+       pr_notice("this is not an AX88190 card!\n");
+       pr_notice("use pcnet_cs instead.\n");
        goto failed;
     }
 
@@ -357,10 +356,10 @@ static int axnet_config(struct pcmcia_device *link)
     ei_status.tx_start_page = AXNET_START_PG;
     ei_status.rx_start_page = AXNET_START_PG + TX_PAGES;
     ei_status.stop_page = AXNET_STOP_PG;
-    ei_status.reset_8390 = &axnet_reset_8390;
-    ei_status.get_8390_hdr = &get_8390_hdr;
-    ei_status.block_input = &block_input;
-    ei_status.block_output = &block_output;
+    ei_status.reset_8390 = axnet_reset_8390;
+    ei_status.get_8390_hdr = get_8390_hdr;
+    ei_status.block_input = block_input;
+    ei_status.block_output = block_output;
 
     if (inb(dev->base_addr + AXNET_TEST) != 0)
        info->flags |= IS_AX88790;
@@ -393,19 +392,18 @@ static int axnet_config(struct pcmcia_device *link)
     SET_NETDEV_DEV(dev, &link->dev);
 
     if (register_netdev(dev) != 0) {
-       printk(KERN_NOTICE "axnet_cs: register_netdev() failed\n");
+       pr_notice("register_netdev() failed\n");
        goto failed;
     }
 
-    printk(KERN_INFO "%s: Asix AX88%d90: io %#3lx, irq %d, "
-          "hw_addr %pM\n",
-          dev->name, ((info->flags & IS_AX88790) ? 7 : 1),
-          dev->base_addr, dev->irq,
-          dev->dev_addr);
+    netdev_info(dev, "Asix AX88%d90: io %#3lx, irq %d, hw_addr %pM\n",
+               ((info->flags & IS_AX88790) ? 7 : 1),
+               dev->base_addr, dev->irq, dev->dev_addr);
     if (info->phy_id != -1) {
-       dev_dbg(&link->dev, "  MII transceiver at index %d, status %x.\n", info->phy_id, j);
+       netdev_dbg(dev, "  MII transceiver at index %d, status %x\n",
+                  info->phy_id, j);
     } else {
-       printk(KERN_NOTICE "  No MII transceivers found!\n");
+       netdev_notice(dev, "  No MII transceivers found!\n");
     }
     return 0;
 
@@ -532,7 +530,7 @@ static int axnet_open(struct net_device *dev)
 
     info->link_status = 0x00;
     init_timer(&info->watchdog);
-    info->watchdog.function = &ei_watchdog;
+    info->watchdog.function = ei_watchdog;
     info->watchdog.data = (u_long)dev;
     info->watchdog.expires = jiffies + HZ;
     add_timer(&info->watchdog);
@@ -585,8 +583,7 @@ static void axnet_reset_8390(struct net_device *dev)
     outb_p(ENISR_RESET, nic_base + EN0_ISR); /* Ack intr. */
     
     if (i == 100)
-       printk(KERN_ERR "%s: axnet_reset_8390() did not complete.\n",
-              dev->name);
+       netdev_err(dev, "axnet_reset_8390() did not complete\n");
     
 } /* axnet_reset_8390 */
 
@@ -613,7 +610,7 @@ static void ei_watchdog(u_long arg)
        this, we can limp along even if the interrupt is blocked */
     if (info->stale++ && (inb_p(nic_base + EN0_ISR) & ENISR_ALL)) {
        if (!info->fast_poll)
-           printk(KERN_INFO "%s: interrupt(s) dropped!\n", dev->name);
+           netdev_info(dev, "interrupt(s) dropped!\n");
        ei_irq_wrapper(dev->irq, dev);
        info->fast_poll = HZ;
     }
@@ -628,7 +625,7 @@ static void ei_watchdog(u_long arg)
        goto reschedule;
     link = mdio_read(mii_addr, info->phy_id, 1);
     if (!link || (link == 0xffff)) {
-       printk(KERN_INFO "%s: MII is missing!\n", dev->name);
+       netdev_info(dev, "MII is missing!\n");
        info->phy_id = -1;
        goto reschedule;
     }
@@ -636,18 +633,14 @@ static void ei_watchdog(u_long arg)
     link &= 0x0004;
     if (link != info->link_status) {
        u_short p = mdio_read(mii_addr, info->phy_id, 5);
-       printk(KERN_INFO "%s: %s link beat\n", dev->name,
-              (link) ? "found" : "lost");
+       netdev_info(dev, "%s link beat\n", link ? "found" : "lost");
        if (link) {
            info->duplex_flag = (p & 0x0140) ? 0x80 : 0x00;
            if (p)
-               printk(KERN_INFO "%s: autonegotiation complete: "
-                      "%sbaseT-%cD selected\n", dev->name,
-                      ((p & 0x0180) ? "100" : "10"),
-                      ((p & 0x0140) ? 'F' : 'H'));
+               netdev_info(dev, "autonegotiation complete: %dbaseT-%cD selected\n",
+                           (p & 0x0180) ? 100 : 10, (p & 0x0140) ? 'F' : 'H');
            else
-               printk(KERN_INFO "%s: link partner did not autonegotiate\n",
-                      dev->name);
+               netdev_info(dev, "link partner did not autonegotiate\n");
            AX88190_init(dev, 1);
        }
        info->link_status = link;
@@ -658,16 +651,6 @@ reschedule:
     add_timer(&info->watchdog);
 }
 
-static void netdev_get_drvinfo(struct net_device *dev,
-                              struct ethtool_drvinfo *info)
-{
-       strcpy(info->driver, "axnet_cs");
-}
-
-static const struct ethtool_ops netdev_ethtool_ops = {
-       .get_drvinfo            = netdev_get_drvinfo,
-};
-
 /*====================================================================*/
 
 static int axnet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
@@ -855,9 +838,6 @@ module_exit(exit_axnet_cs);
 
   */
 
-static const char version_8390[] = KERN_INFO \
-    "8390.c:v1.10cvs 9/23/94 Donald Becker (becker@scyld.com)\n";
-
 #include <linux/bitops.h>
 #include <asm/irq.h>
 #include <linux/fcntl.h>
@@ -1004,9 +984,11 @@ static void axnet_tx_timeout(struct net_device *dev)
        isr = inb(e8390_base+EN0_ISR);
        spin_unlock_irqrestore(&ei_local->page_lock, flags);
 
-       printk(KERN_DEBUG "%s: Tx timed out, %s TSR=%#2x, ISR=%#2x, t=%d.\n",
-               dev->name, (txsr & ENTSR_ABT) ? "excess collisions." :
-               (isr) ? "lost interrupt?" : "cable problem?", txsr, isr, tickssofar);
+       netdev_printk(KERN_DEBUG, dev,
+                     "Tx timed out, %s TSR=%#2x, ISR=%#2x, t=%d.\n",
+                     (txsr & ENTSR_ABT) ? "excess collisions." :
+                     (isr) ? "lost interrupt?" : "cable problem?",
+                     txsr, isr, tickssofar);
 
        if (!isr && !dev->stats.tx_packets) 
        {
@@ -1076,22 +1058,28 @@ static netdev_tx_t axnet_start_xmit(struct sk_buff *skb,
                output_page = ei_local->tx_start_page;
                ei_local->tx1 = send_length;
                if (ei_debug  &&  ei_local->tx2 > 0)
-                       printk(KERN_DEBUG "%s: idle transmitter tx2=%d, lasttx=%d, txing=%d.\n",
-                               dev->name, ei_local->tx2, ei_local->lasttx, ei_local->txing);
+                       netdev_printk(KERN_DEBUG, dev,
+                                     "idle transmitter tx2=%d, lasttx=%d, txing=%d\n",
+                                     ei_local->tx2, ei_local->lasttx,
+                                     ei_local->txing);
        }
        else if (ei_local->tx2 == 0) 
        {
                output_page = ei_local->tx_start_page + TX_PAGES/2;
                ei_local->tx2 = send_length;
                if (ei_debug  &&  ei_local->tx1 > 0)
-                       printk(KERN_DEBUG "%s: idle transmitter, tx1=%d, lasttx=%d, txing=%d.\n",
-                               dev->name, ei_local->tx1, ei_local->lasttx, ei_local->txing);
+                       netdev_printk(KERN_DEBUG, dev,
+                                     "idle transmitter, tx1=%d, lasttx=%d, txing=%d\n",
+                                     ei_local->tx1, ei_local->lasttx,
+                                     ei_local->txing);
        }
        else
        {       /* We should never get here. */
                if (ei_debug)
-                       printk(KERN_DEBUG "%s: No Tx buffers free! tx1=%d tx2=%d last=%d\n",
-                               dev->name, ei_local->tx1, ei_local->tx2, ei_local->lasttx);
+                       netdev_printk(KERN_DEBUG, dev,
+                                     "No Tx buffers free! tx1=%d tx2=%d last=%d\n",
+                                     ei_local->tx1, ei_local->tx2,
+                                     ei_local->lasttx);
                ei_local->irqlock = 0;
                netif_stop_queue(dev);
                outb_p(ENISR_ALL, e8390_base + EN0_IMR);
@@ -1179,23 +1167,26 @@ static irqreturn_t ax_interrupt(int irq, void *dev_id)
         
        spin_lock_irqsave(&ei_local->page_lock, flags);
 
-       if (ei_local->irqlock) 
-       {
+       if (ei_local->irqlock) {
 #if 1 /* This might just be an interrupt for a PCI device sharing this line */
+               const char *msg;
                /* The "irqlock" check is only for testing. */
-               printk(ei_local->irqlock
-                          ? "%s: Interrupted while interrupts are masked! isr=%#2x imr=%#2x.\n"
-                          : "%s: Reentering the interrupt handler! isr=%#2x imr=%#2x.\n",
-                          dev->name, inb_p(e8390_base + EN0_ISR),
-                          inb_p(e8390_base + EN0_IMR));
+               if (ei_local->irqlock)
+                       msg = "Interrupted while interrupts are masked!";
+               else
+                       msg = "Reentering the interrupt handler!";
+               netdev_info(dev, "%s, isr=%#2x imr=%#2x\n",
+                           msg,
+                           inb_p(e8390_base + EN0_ISR),
+                           inb_p(e8390_base + EN0_IMR));
 #endif
                spin_unlock_irqrestore(&ei_local->page_lock, flags);
                return IRQ_NONE;
        }
     
        if (ei_debug > 3)
-               printk(KERN_DEBUG "%s: interrupt(isr=%#2.2x).\n", dev->name,
-                          inb_p(e8390_base + EN0_ISR));
+               netdev_printk(KERN_DEBUG, dev, "interrupt(isr=%#2.2x)\n",
+                             inb_p(e8390_base + EN0_ISR));
 
        outb_p(0x00, e8390_base + EN0_ISR);
        ei_local->irqlock = 1;
@@ -1206,7 +1197,8 @@ static irqreturn_t ax_interrupt(int irq, void *dev_id)
        {
                if (!netif_running(dev) || (interrupts == 0xff)) {
                        if (ei_debug > 1)
-                               printk(KERN_WARNING "%s: interrupt from stopped card\n", dev->name);
+                               netdev_warn(dev,
+                                           "interrupt from stopped card\n");
                        outb_p(interrupts, e8390_base + EN0_ISR);
                        interrupts = 0;
                        break;
@@ -1249,11 +1241,12 @@ static irqreturn_t ax_interrupt(int irq, void *dev_id)
                {
                        /* 0xFF is valid for a card removal */
                        if(interrupts!=0xFF)
-                               printk(KERN_WARNING "%s: Too much work at interrupt, status %#2.2x\n",
-                                  dev->name, interrupts);
+                               netdev_warn(dev, "Too much work at interrupt, status %#2.2x\n",
+                                           interrupts);
                        outb_p(ENISR_ALL, e8390_base + EN0_ISR); /* Ack. most intrs. */
                } else {
-                       printk(KERN_WARNING "%s: unknown interrupt %#2x\n", dev->name, interrupts);
+                       netdev_warn(dev, "unknown interrupt %#2x\n",
+                                   interrupts);
                        outb_p(0xff, e8390_base + EN0_ISR); /* Ack. all intrs. */
                }
        }
@@ -1287,18 +1280,19 @@ static void ei_tx_err(struct net_device *dev)
        unsigned char tx_was_aborted = txsr & (ENTSR_ABT+ENTSR_FU);
 
 #ifdef VERBOSE_ERROR_DUMP
-       printk(KERN_DEBUG "%s: transmitter error (%#2x): ", dev->name, txsr);
+       netdev_printk(KERN_DEBUG, dev,
+                     "transmitter error (%#2x):", txsr);
        if (txsr & ENTSR_ABT)
-               printk("excess-collisions ");
+               pr_cont(" excess-collisions");
        if (txsr & ENTSR_ND)
-               printk("non-deferral ");
+               pr_cont(" non-deferral");
        if (txsr & ENTSR_CRS)
-               printk("lost-carrier ");
+               pr_cont(" lost-carrier");
        if (txsr & ENTSR_FU)
-               printk("FIFO-underrun ");
+               pr_cont(" FIFO-underrun");
        if (txsr & ENTSR_CDH)
-               printk("lost-heartbeat ");
-       printk("\n");
+               pr_cont(" lost-heartbeat");
+       pr_cont("\n");
 #endif
 
        if (tx_was_aborted)
@@ -1335,8 +1329,9 @@ static void ei_tx_intr(struct net_device *dev)
        if (ei_local->tx1 < 0) 
        {
                if (ei_local->lasttx != 1 && ei_local->lasttx != -1)
-                       printk(KERN_ERR "%s: bogus last_tx_buffer %d, tx1=%d.\n",
-                               ei_local->name, ei_local->lasttx, ei_local->tx1);
+                       netdev_err(dev, "%s: bogus last_tx_buffer %d, tx1=%d\n",
+                                  ei_local->name, ei_local->lasttx,
+                                  ei_local->tx1);
                ei_local->tx1 = 0;
                if (ei_local->tx2 > 0) 
                {
@@ -1351,8 +1346,9 @@ static void ei_tx_intr(struct net_device *dev)
        else if (ei_local->tx2 < 0) 
        {
                if (ei_local->lasttx != 2  &&  ei_local->lasttx != -2)
-                       printk("%s: bogus last_tx_buffer %d, tx2=%d.\n",
-                               ei_local->name, ei_local->lasttx, ei_local->tx2);
+                       netdev_info(dev, "%s: bogus last_tx_buffer %d, tx2=%d\n",
+                                   ei_local->name, ei_local->lasttx,
+                                   ei_local->tx2);
                ei_local->tx2 = 0;
                if (ei_local->tx1 > 0) 
                {
@@ -1365,8 +1361,9 @@ static void ei_tx_intr(struct net_device *dev)
                else
                        ei_local->lasttx = 10, ei_local->txing = 0;
        }
-//     else printk(KERN_WARNING "%s: unexpected TX-done interrupt, lasttx=%d.\n",
-//                     dev->name, ei_local->lasttx);
+//     else
+//             netdev_warn(dev, "unexpected TX-done interrupt, lasttx=%d\n",
+//                         ei_local->lasttx);
 
        /* Minimize Tx latency: update the statistics after we restart TXing. */
        if (status & ENTSR_COL)
@@ -1429,8 +1426,8 @@ static void ei_receive(struct net_device *dev)
                   is that some clones crash in roughly the same way.
                 */
                if (ei_debug > 0  &&  this_frame != ei_local->current_page && (this_frame!=0x0 || rxing_page!=0xFF))
-                       printk(KERN_ERR "%s: mismatched read page pointers %2x vs %2x.\n",
-                                  dev->name, this_frame, ei_local->current_page);
+                   netdev_err(dev, "mismatched read page pointers %2x vs %2x\n",
+                              this_frame, ei_local->current_page);
                
                if (this_frame == rxing_page)   /* Read all the frames? */
                        break;                          /* Done for now */
@@ -1446,9 +1443,10 @@ static void ei_receive(struct net_device *dev)
                if (pkt_len < 60  ||  pkt_len > 1518) 
                {
                        if (ei_debug)
-                               printk(KERN_DEBUG "%s: bogus packet size: %d, status=%#2x nxpg=%#2x.\n",
-                                          dev->name, rx_frame.count, rx_frame.status,
-                                          rx_frame.next);
+                               netdev_printk(KERN_DEBUG, dev,
+                                             "bogus packet size: %d, status=%#2x nxpg=%#2x\n",
+                                             rx_frame.count, rx_frame.status,
+                                             rx_frame.next);
                        dev->stats.rx_errors++;
                        dev->stats.rx_length_errors++;
                }
@@ -1460,8 +1458,9 @@ static void ei_receive(struct net_device *dev)
                        if (skb == NULL) 
                        {
                                if (ei_debug > 1)
-                                       printk(KERN_DEBUG "%s: Couldn't allocate a sk_buff of size %d.\n",
-                                                  dev->name, pkt_len);
+                                       netdev_printk(KERN_DEBUG, dev,
+                                                     "Couldn't allocate a sk_buff of size %d\n",
+                                                     pkt_len);
                                dev->stats.rx_dropped++;
                                break;
                        }
@@ -1481,9 +1480,10 @@ static void ei_receive(struct net_device *dev)
                else 
                {
                        if (ei_debug)
-                               printk(KERN_DEBUG "%s: bogus packet: status=%#2x nxpg=%#2x size=%d\n",
-                                          dev->name, rx_frame.status, rx_frame.next,
-                                          rx_frame.count);
+                               netdev_printk(KERN_DEBUG, dev,
+                                             "bogus packet: status=%#2x nxpg=%#2x size=%d\n",
+                                             rx_frame.status, rx_frame.next,
+                                             rx_frame.count);
                        dev->stats.rx_errors++;
                        /* NB: The NIC counts CRC, frame and missed errors. */
                        if (pkt_stat & ENRSR_FO)
@@ -1493,8 +1493,8 @@ static void ei_receive(struct net_device *dev)
                
                /* This _should_ never happen: it's here for avoiding bad clones. */
                if (next_frame >= ei_local->stop_page) {
-                       printk("%s: next frame inconsistency, %#2x\n", dev->name,
-                                  next_frame);
+                       netdev_info(dev, "next frame inconsistency, %#2x\n",
+                                   next_frame);
                        next_frame = ei_local->rx_start_page;
                }
                ei_local->current_page = next_frame;
@@ -1529,7 +1529,7 @@ static void ei_rx_overrun(struct net_device *dev)
        outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD);
     
        if (ei_debug > 1)
-               printk(KERN_DEBUG "%s: Receiver overrun.\n", dev->name);
+               netdev_printk(KERN_DEBUG, dev, "Receiver overrun\n");
        dev->stats.rx_over_errors++;
     
        /* 
@@ -1726,7 +1726,7 @@ static void AX88190_init(struct net_device *dev, int startp)
        {
                outb_p(dev->dev_addr[i], e8390_base + EN1_PHYS_SHIFT(i));
                if(inb_p(e8390_base + EN1_PHYS_SHIFT(i))!=dev->dev_addr[i])
-                       printk(KERN_ERR "Hw. address read/write mismap %d\n",i);
+                       netdev_err(dev, "Hw. address read/write mismap %d\n", i);
        }
 
        outb_p(ei_local->rx_start_page, e8390_base + EN1_CURPAG);
@@ -1763,8 +1763,7 @@ static void NS8390_trigger_send(struct net_device *dev, unsigned int length,
     
        if (inb_p(e8390_base) & E8390_TRANS) 
        {
-               printk(KERN_WARNING "%s: trigger_send() called with the transmitter busy.\n",
-                       dev->name);
+               netdev_warn(dev, "trigger_send() called with the transmitter busy\n");
                return;
        }
        outb_p(length & 0xff, e8390_base + EN0_TCNTLO);
index 3c400cfa82ae2e88c0e67c3f0582f75491be925e..f065c35cd4b75147f7f8184108f4ccc95df9cdb0 100644 (file)
 
 #define VERSION "arcnet: COM20020 PCMCIA support loaded.\n"
 
-#ifdef DEBUG
 
 static void regdump(struct net_device *dev)
 {
+#ifdef DEBUG
     int ioaddr = dev->base_addr;
     int count;
     
-    printk("com20020 register dump:\n");
+    netdev_dbg(dev, "register dump:\n");
     for (count = ioaddr; count < ioaddr + 16; count++)
     {
        if (!(count % 16))
-           printk("\n%04X: ", count);
-       printk("%02X ", inb(count));
+           pr_cont("%04X:", count);
+       pr_cont(" %02X", inb(count));
     }
-    printk("\n");
+    pr_cont("\n");
     
-    printk("buffer0 dump:\n");
+    netdev_dbg(dev, "buffer0 dump:\n");
        /* set up the address register */
         count = 0;
        outb((count >> 8) | RDDATAflag | AUTOINCflag, _ADDR_HI);
@@ -77,19 +77,15 @@ static void regdump(struct net_device *dev)
     for (count = 0; count < 256+32; count++)
     {
        if (!(count % 16))
-           printk("\n%04X: ", count);
+           pr_cont("%04X:", count);
        
        /* copy the data */
-       printk("%02X ", inb(_MEMDATA));
+       pr_cont(" %02X", inb(_MEMDATA));
     }
-    printk("\n");
+    pr_cont("\n");
+#endif
 }
 
-#else
-
-static inline void regdump(struct net_device *dev) { }
-
-#endif
 
 
 /*====================================================================*/
@@ -301,13 +297,13 @@ static int com20020_config(struct pcmcia_device *link)
     i = com20020_found(dev, 0);        /* calls register_netdev */
     
     if (i != 0) {
-       dev_printk(KERN_NOTICE, &link->dev,
-               "com20020_cs: com20020_found() failed\n");
+       dev_notice(&link->dev,
+                  "com20020_found() failed\n");
        goto failed;
     }
 
-    dev_dbg(&link->dev,KERN_INFO "%s: port %#3lx, irq %d\n",
-           dev->name, dev->base_addr, dev->irq);
+    netdev_dbg(dev, "port %#3lx, irq %d\n",
+              dev->base_addr, dev->irq);
     return 0;
 
 failed:
index 98fffb03ecd7f4714c068d7a47c5acf667423cac..8f26d548d1bb2eb65105a082971ea3438cd76417 100644 (file)
@@ -28,6 +28,8 @@
    
 ======================================================================*/
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #define DRV_NAME       "fmvj18x_cs"
 #define DRV_VERSION    "2.9"
 
@@ -291,7 +293,7 @@ static int mfc_try_io_port(struct pcmcia_device *link)
        link->resource[1]->flags |= IO_DATA_PATH_WIDTH_8;
        if (link->resource[1]->start == 0) {
            link->resource[1]->end = 0;
-           printk(KERN_NOTICE "fmvj18x_cs: out of resource for serial\n");
+           pr_notice("out of resource for serial\n");
        }
        ret = pcmcia_request_io(link);
        if (ret == 0)
@@ -503,7 +505,7 @@ static int fmvj18x_config(struct pcmcia_device *link)
     case XXX10304:
        /* Read MACID from Buggy CIS */
        if (fmvj18x_get_hwinfo(link, buggybuf) == -1) {
-           printk(KERN_NOTICE "fmvj18x_cs: unable to read hardware net address.\n");
+           pr_notice("unable to read hardware net address\n");
            goto failed;
        }
        for (i = 0 ; i < 6; i++) {
@@ -524,15 +526,14 @@ static int fmvj18x_config(struct pcmcia_device *link)
     SET_NETDEV_DEV(dev, &link->dev);
 
     if (register_netdev(dev) != 0) {
-       printk(KERN_NOTICE "fmvj18x_cs: register_netdev() failed\n");
+       pr_notice("register_netdev() failed\n");
        goto failed;
     }
 
     /* print current configuration */
-    printk(KERN_INFO "%s: %s, sram %s, port %#3lx, irq %d, "
-          "hw_addr %pM\n",
-          dev->name, card_name, sram_config == 0 ? "4K TX*2" : "8K TX*2", 
-          dev->base_addr, dev->irq, dev->dev_addr);
+    netdev_info(dev, "%s, sram %s, port %#3lx, irq %d, hw_addr %pM\n",
+               card_name, sram_config == 0 ? "4K TX*2" : "8K TX*2",
+               dev->base_addr, dev->irq, dev->dev_addr);
 
     return 0;
     
@@ -606,7 +607,7 @@ static int fmvj18x_setup_mfc(struct pcmcia_device *link)
 
     lp->base = ioremap(req.Base, req.Size);
     if (lp->base == NULL) {
-       printk(KERN_NOTICE "fmvj18x_cs: ioremap failed\n");
+       netdev_notice(dev, "ioremap failed\n");
        return -1;
     }
 
@@ -800,17 +801,16 @@ static void fjn_tx_timeout(struct net_device *dev)
     struct local_info_t *lp = netdev_priv(dev);
     unsigned int ioaddr = dev->base_addr;
 
-    printk(KERN_NOTICE "%s: transmit timed out with status %04x, %s?\n",
-          dev->name, htons(inw(ioaddr + TX_STATUS)),
-          inb(ioaddr + TX_STATUS) & F_TMT_RDY
-          ? "IRQ conflict" : "network cable problem");
-    printk(KERN_NOTICE "%s: timeout registers: %04x %04x %04x "
-          "%04x %04x %04x %04x %04x.\n",
-          dev->name, htons(inw(ioaddr + 0)),
-          htons(inw(ioaddr + 2)), htons(inw(ioaddr + 4)),
-          htons(inw(ioaddr + 6)), htons(inw(ioaddr + 8)),
-          htons(inw(ioaddr +10)), htons(inw(ioaddr +12)),
-          htons(inw(ioaddr +14)));
+    netdev_notice(dev, "transmit timed out with status %04x, %s?\n",
+                 htons(inw(ioaddr + TX_STATUS)),
+                 inb(ioaddr + TX_STATUS) & F_TMT_RDY
+                 ? "IRQ conflict" : "network cable problem");
+    netdev_notice(dev, "timeout registers: %04x %04x %04x "
+                 "%04x %04x %04x %04x %04x.\n",
+                 htons(inw(ioaddr + 0)), htons(inw(ioaddr + 2)),
+                 htons(inw(ioaddr + 4)), htons(inw(ioaddr + 6)),
+                 htons(inw(ioaddr + 8)), htons(inw(ioaddr + 10)),
+                 htons(inw(ioaddr + 12)), htons(inw(ioaddr + 14)));
     dev->stats.tx_errors++;
     /* ToDo: We should try to restart the adaptor... */
     local_irq_disable();
@@ -845,13 +845,13 @@ static netdev_tx_t fjn_start_xmit(struct sk_buff *skb,
        unsigned char *buf = skb->data;
 
        if (length > ETH_FRAME_LEN) {
-           printk(KERN_NOTICE "%s: Attempting to send a large packet"
-                  " (%d bytes).\n", dev->name, length);
+           netdev_notice(dev, "Attempting to send a large packet (%d bytes)\n",
+                         length);
            return NETDEV_TX_BUSY;
        }
 
-       pr_debug("%s: Transmitting a packet of length %lu.\n",
-             dev->name, (unsigned long)skb->len);
+       netdev_dbg(dev, "Transmitting a packet of length %lu\n",
+                  (unsigned long)skb->len);
        dev->stats.tx_bytes += skb->len;
 
        /* Disable both interrupts. */
@@ -904,7 +904,7 @@ static void fjn_reset(struct net_device *dev)
     unsigned int ioaddr = dev->base_addr;
     int i;
 
-    pr_debug("fjn_reset(%s) called.\n",dev->name);
+    netdev_dbg(dev, "fjn_reset() called\n");
 
     /* Reset controller */
     if( sram_config == 0 ) 
@@ -988,8 +988,8 @@ static void fjn_rx(struct net_device *dev)
     while ((inb(ioaddr + RX_MODE) & F_BUF_EMP) == 0) {
        u_short status = inw(ioaddr + DATAPORT);
 
-       pr_debug("%s: Rxing packet mode %02x status %04x.\n",
-             dev->name, inb(ioaddr + RX_MODE), status);
+       netdev_dbg(dev, "Rxing packet mode %02x status %04x.\n",
+                  inb(ioaddr + RX_MODE), status);
 #ifndef final_version
        if (status == 0) {
            outb(F_SKP_PKT, ioaddr + RX_SKIP);
@@ -1008,16 +1008,16 @@ static void fjn_rx(struct net_device *dev)
            struct sk_buff *skb;
 
            if (pkt_len > 1550) {
-               printk(KERN_NOTICE "%s: The FMV-18x claimed a very "
-                      "large packet, size %d.\n", dev->name, pkt_len);
+               netdev_notice(dev, "The FMV-18x claimed a very large packet, size %d\n",
+                             pkt_len);
                outb(F_SKP_PKT, ioaddr + RX_SKIP);
                dev->stats.rx_errors++;
                break;
            }
            skb = dev_alloc_skb(pkt_len+2);
            if (skb == NULL) {
-               printk(KERN_NOTICE "%s: Memory squeeze, dropping "
-                      "packet (len %d).\n", dev->name, pkt_len);
+               netdev_notice(dev, "Memory squeeze, dropping packet (len %d)\n",
+                             pkt_len);
                outb(F_SKP_PKT, ioaddr + RX_SKIP);
                dev->stats.rx_dropped++;
                break;
index b0d06a3d962fc235fdc22c8f5af840272a5574d3..dc85282193bf2e415ec18249d58fa8e58098a858 100644 (file)
@@ -45,6 +45,8 @@
 
 ======================================================================*/
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/ptrace.h>
@@ -52,7 +54,6 @@
 #include <linux/string.h>
 #include <linux/timer.h>
 #include <linux/module.h>
-#include <linux/ethtool.h>
 #include <linux/netdevice.h>
 #include <linux/trdevice.h>
 #include <linux/ibmtr.h>
@@ -107,16 +108,6 @@ typedef struct ibmtr_dev_t {
     struct tok_info    *ti;
 } ibmtr_dev_t;
 
-static void netdev_get_drvinfo(struct net_device *dev,
-                              struct ethtool_drvinfo *info)
-{
-       strcpy(info->driver, "ibmtr_cs");
-}
-
-static const struct ethtool_ops netdev_ethtool_ops = {
-       .get_drvinfo            = netdev_get_drvinfo,
-};
-
 static irqreturn_t ibmtr_interrupt(int irq, void *dev_id) {
        ibmtr_dev_t *info = dev_id;
        struct net_device *dev = info->dev;
@@ -159,8 +150,6 @@ static int __devinit ibmtr_attach(struct pcmcia_device *link)
 
     info->dev = dev;
 
-    SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
-
     return ibmtr_config(link);
 } /* ibmtr_attach */
 
@@ -285,15 +274,14 @@ static int __devinit ibmtr_config(struct pcmcia_device *link)
 
     i = ibmtr_probe_card(dev);
     if (i != 0) {
-       printk(KERN_NOTICE "ibmtr_cs: register_netdev() failed\n");
+       pr_notice("register_netdev() failed\n");
        goto failed;
     }
 
-    printk(KERN_INFO
-          "%s: port %#3lx, irq %d,  mmio %#5lx, sram %#5lx, hwaddr=%pM\n",
-           dev->name, dev->base_addr, dev->irq,
-          (u_long)ti->mmio, (u_long)(ti->sram_base << 12),
-          dev->dev_addr);
+    netdev_info(dev, "port %#3lx, irq %d, mmio %#5lx, sram %#5lx, hwaddr=%pM\n",
+               dev->base_addr, dev->irq,
+               (u_long)ti->mmio, (u_long)(ti->sram_base << 12),
+               dev->dev_addr);
     return 0;
 
 failed:
index 68f2deeb3ade11722dc5333386f4afd56cc98eb3..89cf63bb8c913a4af6ed1065e7aeaff1d7257276 100644 (file)
@@ -111,6 +111,8 @@ Log: nmclan_cs.c,v
 
 ---------------------------------------------------------------------------- */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #define DRV_NAME       "nmclan_cs"
 #define DRV_VERSION    "0.16"
 
@@ -563,7 +565,7 @@ static int mace_init(mace_private *lp, unsigned int ioaddr, char *enet_addr)
     /* Wait for reset bit to be cleared automatically after <= 200ns */;
     if(++ct > 500)
     {
-       printk(KERN_ERR "mace: reset failed, card removed ?\n");
+       pr_err("reset failed, card removed?\n");
        return -1;
     }
     udelay(1);
@@ -610,7 +612,7 @@ static int mace_init(mace_private *lp, unsigned int ioaddr, char *enet_addr)
   {
        if(++ ct > 500)
        {
-               printk(KERN_ERR "mace: ADDRCHG timeout, card removed ?\n");
+               pr_err("ADDRCHG timeout, card removed?\n");
                return -1;
        }
   }
@@ -678,8 +680,8 @@ static int nmclan_config(struct pcmcia_device *link)
       dev_dbg(&link->dev, "nmclan_cs configured: mace id=%x %x\n",
            sig[0], sig[1]);
     } else {
-      printk(KERN_NOTICE "nmclan_cs: mace id not found: %x %x should"
-            " be 0x40 0x?9\n", sig[0], sig[1]);
+      pr_notice("mace id not found: %x %x should be 0x40 0x?9\n",
+               sig[0], sig[1]);
       return -ENODEV;
     }
   }
@@ -691,20 +693,18 @@ static int nmclan_config(struct pcmcia_device *link)
   if (if_port <= 2)
     dev->if_port = if_port;
   else
-    printk(KERN_NOTICE "nmclan_cs: invalid if_port requested\n");
+    pr_notice("invalid if_port requested\n");
 
   SET_NETDEV_DEV(dev, &link->dev);
 
   i = register_netdev(dev);
   if (i != 0) {
-    printk(KERN_NOTICE "nmclan_cs: register_netdev() failed\n");
+    pr_notice("register_netdev() failed\n");
     goto failed;
   }
 
-  printk(KERN_INFO "%s: nmclan: port %#3lx, irq %d, %s port,"
-        " hw_addr %pM\n",
-        dev->name, dev->base_addr, dev->irq, if_names[dev->if_port],
-        dev->dev_addr);
+  netdev_info(dev, "nmclan: port %#3lx, irq %d, %s port, hw_addr %pM\n",
+             dev->base_addr, dev->irq, if_names[dev->if_port], dev->dev_addr);
   return 0;
 
 failed:
@@ -798,8 +798,7 @@ static int mace_config(struct net_device *dev, struct ifmap *map)
   if ((map->port != (u_char)(-1)) && (map->port != dev->if_port)) {
     if (map->port <= 2) {
       dev->if_port = map->port;
-      printk(KERN_INFO "%s: switched to %s port\n", dev->name,
-            if_names[dev->if_port]);
+      netdev_info(dev, "switched to %s port\n", if_names[dev->if_port]);
     } else
       return -EINVAL;
   }
@@ -878,12 +877,12 @@ static void mace_tx_timeout(struct net_device *dev)
   mace_private *lp = netdev_priv(dev);
   struct pcmcia_device *link = lp->p_dev;
 
-  printk(KERN_NOTICE "%s: transmit timed out -- ", dev->name);
+  netdev_notice(dev, "transmit timed out -- ");
 #if RESET_ON_TIMEOUT
-  printk("resetting card\n");
+  pr_cont("resetting card\n");
   pcmcia_reset_card(link->socket);
 #else /* #if RESET_ON_TIMEOUT */
-  printk("NOT resetting card\n");
+  pr_cont("NOT resetting card\n");
 #endif /* #if RESET_ON_TIMEOUT */
   dev->trans_start = jiffies; /* prevent tx timeout */
   netif_wake_queue(dev);
@@ -965,22 +964,21 @@ static irqreturn_t mace_interrupt(int irq, void *dev_id)
   ioaddr = dev->base_addr;
 
   if (lp->tx_irq_disabled) {
-    printk(
-      (lp->tx_irq_disabled?
-       KERN_NOTICE "%s: Interrupt with tx_irq_disabled "
-       "[isr=%02X, imr=%02X]\n": 
-       KERN_NOTICE "%s: Re-entering the interrupt handler "
-       "[isr=%02X, imr=%02X]\n"),
-      dev->name,
-      inb(ioaddr + AM2150_MACE_BASE + MACE_IR),
-      inb(ioaddr + AM2150_MACE_BASE + MACE_IMR)
-    );
+    const char *msg;
+    if (lp->tx_irq_disabled)
+      msg = "Interrupt with tx_irq_disabled";
+    else
+      msg = "Re-entering the interrupt handler";
+    netdev_notice(dev, "%s [isr=%02X, imr=%02X]\n",
+                 msg,
+                 inb(ioaddr + AM2150_MACE_BASE + MACE_IR),
+                 inb(ioaddr + AM2150_MACE_BASE + MACE_IMR));
     /* WARNING: MACE_IR has been read! */
     return IRQ_NONE;
   }
 
   if (!netif_device_present(dev)) {
-    pr_debug("%s: interrupt from dead card\n", dev->name);
+    netdev_dbg(dev, "interrupt from dead card\n");
     return IRQ_NONE;
   }
 
@@ -1378,8 +1376,8 @@ static void BuildLAF(int *ladrf, int *adr)
     printk(KERN_DEBUG "    adr =%pM\n", adr);
   printk(KERN_DEBUG "    hashcode = %d(decimal), ladrf[0:63] =", hashcode);
   for (i = 0; i < 8; i++)
-    printk(KERN_CONT " %02X", ladrf[i]);
-  printk(KERN_CONT "\n");
+    pr_cont(" %02X", ladrf[i]);
+  pr_cont("\n");
 #endif
 } /* BuildLAF */
 
index 49279b0ee526a54a534c6f8c04e7c48aa4aba0d0..e180832c278ffa9f64d637588b6f611321d801d7 100644 (file)
@@ -28,6 +28,8 @@
 
 ======================================================================*/
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
@@ -35,7 +37,6 @@
 #include <linux/string.h>
 #include <linux/timer.h>
 #include <linux/delay.h>
-#include <linux/ethtool.h>
 #include <linux/netdevice.h>
 #include <linux/log2.h>
 #include <linux/etherdevice.h>
@@ -100,7 +101,6 @@ static void pcnet_release(struct pcmcia_device *link);
 static int pcnet_open(struct net_device *dev);
 static int pcnet_close(struct net_device *dev);
 static int ei_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static const struct ethtool_ops netdev_ethtool_ops;
 static irqreturn_t ei_irq_wrapper(int irq, void *dev_id);
 static void ei_watchdog(u_long arg);
 static void pcnet_reset_8390(struct net_device *dev);
@@ -434,8 +434,6 @@ static hw_info_t *get_ax88190(struct pcmcia_device *link)
        dev->dev_addr[i] = j & 0xff;
        dev->dev_addr[i+1] = j >> 8;
     }
-    printk(KERN_NOTICE "pcnet_cs: this is an AX88190 card!\n");
-    printk(KERN_NOTICE "pcnet_cs: use axnet_cs instead.\n");
     return NULL;
 }
 
@@ -570,15 +568,15 @@ static int pcnet_config(struct pcmcia_device *link)
        if ((if_port == 1) || (if_port == 2))
            dev->if_port = if_port;
        else
-           printk(KERN_NOTICE "pcnet_cs: invalid if_port requested\n");
+           pr_notice("invalid if_port requested\n");
     } else {
        dev->if_port = 0;
     }
 
     if ((link->conf.ConfigBase == 0x03c0) &&
        (link->manf_id == 0x149) && (link->card_id == 0xc1ab)) {
-       printk(KERN_INFO "pcnet_cs: this is an AX88190 card!\n");
-       printk(KERN_INFO "pcnet_cs: use axnet_cs instead.\n");
+       pr_notice("this is an AX88190 card!\n");
+       pr_notice("use axnet_cs instead.\n");
        goto failed;
     }
 
@@ -593,8 +591,8 @@ static int pcnet_config(struct pcmcia_device *link)
        local_hw_info = get_hwired(link);
 
     if (local_hw_info == NULL) {
-       printk(KERN_NOTICE "pcnet_cs: unable to read hardware net"
-              " address for io base %#3lx\n", dev->base_addr);
+       pr_notice("unable to read hardware net address for io base %#3lx\n",
+                 dev->base_addr);
        goto failed;
     }
 
@@ -626,9 +624,7 @@ static int pcnet_config(struct pcmcia_device *link)
 
     ei_status.name = "NE2000";
     ei_status.word16 = 1;
-    ei_status.reset_8390 = &pcnet_reset_8390;
-
-    SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
+    ei_status.reset_8390 = pcnet_reset_8390;
 
     if (info->flags & (IS_DL10019|IS_DL10022))
        mii_phy_probe(dev);
@@ -636,25 +632,25 @@ static int pcnet_config(struct pcmcia_device *link)
     SET_NETDEV_DEV(dev, &link->dev);
 
     if (register_netdev(dev) != 0) {
-       printk(KERN_NOTICE "pcnet_cs: register_netdev() failed\n");
+       pr_notice("register_netdev() failed\n");
        goto failed;
     }
 
     if (info->flags & (IS_DL10019|IS_DL10022)) {
        u_char id = inb(dev->base_addr + 0x1a);
-       printk(KERN_INFO "%s: NE2000 (DL100%d rev %02x): ",
-              dev->name, ((info->flags & IS_DL10022) ? 22 : 19), id);
+       netdev_info(dev, "NE2000 (DL100%d rev %02x): ",
+              (info->flags & IS_DL10022) ? 22 : 19, id);
        if (info->pna_phy)
-           printk("PNA, ");
+           pr_cont("PNA, ");
     } else {
-       printk(KERN_INFO "%s: NE2000 Compatible: ", dev->name);
+       netdev_info(dev, "NE2000 Compatible: ");
     }
-    printk("io %#3lx, irq %d,", dev->base_addr, dev->irq);
+    pr_cont("io %#3lx, irq %d,", dev->base_addr, dev->irq);
     if (info->flags & USE_SHMEM)
-       printk (" mem %#5lx,", dev->mem_start);
+       pr_cont(" mem %#5lx,", dev->mem_start);
     if (info->flags & HAS_MISC_REG)
-       printk(" %s xcvr,", if_names[dev->if_port]);
-    printk(" hw_addr %pM\n", dev->dev_addr);
+       pr_cont(" %s xcvr,", if_names[dev->if_port]);
+    pr_cont(" hw_addr %pM\n", dev->dev_addr);
     return 0;
 
 failed:
@@ -928,7 +924,7 @@ static void mii_phy_probe(struct net_device *dev)
        phyid = tmp << 16;
        phyid |= mdio_read(mii_addr, i, MII_PHYID_REG2);
        phyid &= MII_PHYID_REV_MASK;
-       pr_debug("%s: MII at %d is 0x%08x\n", dev->name, i, phyid);
+       netdev_dbg(dev, "MII at %d is 0x%08x\n", i, phyid);
        if (phyid == AM79C9XX_HOME_PHY) {
            info->pna_phy = i;
        } else if (phyid != AM79C9XX_ETH_PHY) {
@@ -961,7 +957,7 @@ static int pcnet_open(struct net_device *dev)
     info->phy_id = info->eth_phy;
     info->link_status = 0x00;
     init_timer(&info->watchdog);
-    info->watchdog.function = &ei_watchdog;
+    info->watchdog.function = ei_watchdog;
     info->watchdog.data = (u_long)dev;
     info->watchdog.expires = jiffies + HZ;
     add_timer(&info->watchdog);
@@ -1014,8 +1010,8 @@ static void pcnet_reset_8390(struct net_device *dev)
     outb_p(ENISR_RESET, nic_base + EN0_ISR); /* Ack intr. */
 
     if (i == 100)
-       printk(KERN_ERR "%s: pcnet_reset_8390() did not complete.\n",
-              dev->name);
+       netdev_err(dev, "pcnet_reset_8390() did not complete.\n");
+
     set_misc_reg(dev);
 
 } /* pcnet_reset_8390 */
@@ -1031,8 +1027,7 @@ static int set_config(struct net_device *dev, struct ifmap *map)
        else if ((map->port < 1) || (map->port > 2))
            return -EINVAL;
        dev->if_port = map->port;
-       printk(KERN_INFO "%s: switched to %s port\n",
-              dev->name, if_names[dev->if_port]);
+       netdev_info(dev, "switched to %s port\n", if_names[dev->if_port]);
        NS8390_init(dev, 1);
     }
     return 0;
@@ -1067,7 +1062,7 @@ static void ei_watchdog(u_long arg)
        this, we can limp along even if the interrupt is blocked */
     if (info->stale++ && (inb_p(nic_base + EN0_ISR) & ENISR_ALL)) {
        if (!info->fast_poll)
-           printk(KERN_INFO "%s: interrupt(s) dropped!\n", dev->name);
+           netdev_info(dev, "interrupt(s) dropped!\n");
        ei_irq_wrapper(dev->irq, dev);
        info->fast_poll = HZ;
     }
@@ -1087,7 +1082,7 @@ static void ei_watchdog(u_long arg)
        if (info->eth_phy) {
            info->phy_id = info->eth_phy = 0;
        } else {
-           printk(KERN_INFO "%s: MII is missing!\n", dev->name);
+           netdev_info(dev, "MII is missing!\n");
            info->flags &= ~HAS_MII;
        }
        goto reschedule;
@@ -1096,8 +1091,7 @@ static void ei_watchdog(u_long arg)
     link &= 0x0004;
     if (link != info->link_status) {
        u_short p = mdio_read(mii_addr, info->phy_id, 5);
-       printk(KERN_INFO "%s: %s link beat\n", dev->name,
-              (link) ? "found" : "lost");
+       netdev_info(dev, "%s link beat\n", link ? "found" : "lost");
        if (link && (info->flags & IS_DL10022)) {
            /* Disable collision detection on full duplex links */
            outb((p & 0x0140) ? 4 : 0, nic_base + DLINK_DIAG);
@@ -1108,13 +1102,12 @@ static void ei_watchdog(u_long arg)
        if (link) {
            if (info->phy_id == info->eth_phy) {
                if (p)
-                   printk(KERN_INFO "%s: autonegotiation complete: "
-                          "%sbaseT-%cD selected\n", dev->name,
+                   netdev_info(dev, "autonegotiation complete: "
+                          "%sbaseT-%cD selected\n",
                           ((p & 0x0180) ? "100" : "10"),
                           ((p & 0x0140) ? 'F' : 'H'));
                else
-                   printk(KERN_INFO "%s: link partner did not "
-                          "autonegotiate\n", dev->name);
+                   netdev_info(dev, "link partner did not autonegotiate\n");
            }
            NS8390_init(dev, 1);
        }
@@ -1127,7 +1120,7 @@ static void ei_watchdog(u_long arg)
            /* isolate this MII and try flipping to the other one */
            mdio_write(mii_addr, info->phy_id, 0, 0x0400);
            info->phy_id ^= info->pna_phy ^ info->eth_phy;
-           printk(KERN_INFO "%s: switched to %s transceiver\n", dev->name,
+           netdev_info(dev, "switched to %s transceiver\n",
                   (info->phy_id == info->eth_phy) ? "ethernet" : "PNA");
            mdio_write(mii_addr, info->phy_id, 0,
                       (info->phy_id == info->eth_phy) ? 0x1000 : 0);
@@ -1143,18 +1136,6 @@ reschedule:
 
 /*====================================================================*/
 
-static void netdev_get_drvinfo(struct net_device *dev,
-                              struct ethtool_drvinfo *info)
-{
-       strcpy(info->driver, "pcnet_cs");
-}
-
-static const struct ethtool_ops netdev_ethtool_ops = {
-       .get_drvinfo            = netdev_get_drvinfo,
-};
-
-/*====================================================================*/
-
 
 static int ei_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
@@ -1187,9 +1168,9 @@ static void dma_get_8390_hdr(struct net_device *dev,
     unsigned int nic_base = dev->base_addr;
 
     if (ei_status.dmaing) {
-       printk(KERN_NOTICE "%s: DMAing conflict in dma_block_input."
+       netdev_notice(dev, "DMAing conflict in dma_block_input."
               "[DMAstat:%1x][irqlock:%1x]\n",
-              dev->name, ei_status.dmaing, ei_status.irqlock);
+              ei_status.dmaing, ei_status.irqlock);
        return;
     }
 
@@ -1220,11 +1201,11 @@ static void dma_block_input(struct net_device *dev, int count,
     char *buf = skb->data;
 
     if ((ei_debug > 4) && (count != 4))
-       pr_debug("%s: [bi=%d]\n", dev->name, count+4);
+       netdev_dbg(dev, "[bi=%d]\n", count+4);
     if (ei_status.dmaing) {
-       printk(KERN_NOTICE "%s: DMAing conflict in dma_block_input."
+       netdev_notice(dev, "DMAing conflict in dma_block_input."
               "[DMAstat:%1x][irqlock:%1x]\n",
-              dev->name, ei_status.dmaing, ei_status.irqlock);
+              ei_status.dmaing, ei_status.irqlock);
        return;
     }
     ei_status.dmaing |= 0x01;
@@ -1254,9 +1235,9 @@ static void dma_block_input(struct net_device *dev, int count,
                break;
        } while (--tries > 0);
        if (tries <= 0)
-           printk(KERN_NOTICE "%s: RX transfer address mismatch,"
+           netdev_notice(dev, "RX transfer address mismatch,"
                   "%#4.4x (expected) vs. %#4.4x (actual).\n",
-                  dev->name, ring_offset + xfer_count, addr);
+                  ring_offset + xfer_count, addr);
     }
 #endif
     outb_p(ENISR_RDC, nic_base + EN0_ISR);     /* Ack intr. */
@@ -1277,7 +1258,7 @@ static void dma_block_output(struct net_device *dev, int count,
 
 #ifdef PCMCIA_DEBUG
     if (ei_debug > 4)
-       printk(KERN_DEBUG "%s: [bo=%d]\n", dev->name, count);
+       netdev_dbg(dev, "[bo=%d]\n", count);
 #endif
 
     /* Round the count up for word writes.  Do we need to do this?
@@ -1286,9 +1267,9 @@ static void dma_block_output(struct net_device *dev, int count,
     if (count & 0x01)
        count++;
     if (ei_status.dmaing) {
-       printk(KERN_NOTICE "%s: DMAing conflict in dma_block_output."
+       netdev_notice(dev, "DMAing conflict in dma_block_output."
               "[DMAstat:%1x][irqlock:%1x]\n",
-              dev->name, ei_status.dmaing, ei_status.irqlock);
+              ei_status.dmaing, ei_status.irqlock);
        return;
     }
     ei_status.dmaing |= 0x01;
@@ -1325,9 +1306,9 @@ static void dma_block_output(struct net_device *dev, int count,
                break;
        } while (--tries > 0);
        if (tries <= 0) {
-           printk(KERN_NOTICE "%s: Tx packet transfer address mismatch,"
+           netdev_notice(dev, "Tx packet transfer address mismatch,"
                   "%#4.4x (expected) vs. %#4.4x (actual).\n",
-                  dev->name, (start_page << 8) + count, addr);
+                  (start_page << 8) + count, addr);
            if (retries++ == 0)
                goto retry;
        }
@@ -1336,8 +1317,7 @@ static void dma_block_output(struct net_device *dev, int count,
 
     while ((inb_p(nic_base + EN0_ISR) & ENISR_RDC) == 0)
        if (time_after(jiffies, dma_start + PCNET_RDC_TIMEOUT)) {
-           printk(KERN_NOTICE "%s: timeout waiting for Tx RDC.\n",
-                  dev->name);
+           netdev_notice(dev, "timeout waiting for Tx RDC.\n");
            pcnet_reset_8390(dev);
            NS8390_init(dev, 1);
            break;
@@ -1361,9 +1341,9 @@ static int setup_dma_config(struct pcmcia_device *link, int start_pg,
     ei_status.stop_page = stop_pg;
 
     /* set up block i/o functions */
-    ei_status.get_8390_hdr = &dma_get_8390_hdr;
-    ei_status.block_input = &dma_block_input;
-    ei_status.block_output = &dma_block_output;
+    ei_status.get_8390_hdr = dma_get_8390_hdr;
+    ei_status.block_input = dma_block_input;
+    ei_status.block_output = dma_block_output;
 
     return 0;
 }
@@ -1509,9 +1489,9 @@ static int setup_shmem_window(struct pcmcia_device *link, int start_pg,
     ei_status.stop_page = start_pg + ((req.Size - offset) >> 8);
 
     /* set up block i/o functions */
-    ei_status.get_8390_hdr = &shmem_get_8390_hdr;
-    ei_status.block_input = &shmem_block_input;
-    ei_status.block_output = &shmem_block_output;
+    ei_status.get_8390_hdr = shmem_get_8390_hdr;
+    ei_status.block_input = shmem_block_input;
+    ei_status.block_output = shmem_block_output;
 
     info->flags |= USE_SHMEM;
     return 0;
index 377367d03b419dd7907262bfaedaf3acc0d60aca..3d1c549b7038208e894831e771ff2411136fe0a7 100644 (file)
@@ -25,6 +25,8 @@
 
 ======================================================================*/
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -294,7 +296,7 @@ static const struct net_device_ops smc_netdev_ops = {
        .ndo_tx_timeout         = smc_tx_timeout,
        .ndo_set_config         = s9k_config,
        .ndo_set_multicast_list = set_rx_mode,
-       .ndo_do_ioctl           = &smc_ioctl,
+       .ndo_do_ioctl           = smc_ioctl,
        .ndo_change_mtu         = eth_change_mtu,
        .ndo_set_mac_address    = eth_mac_addr,
        .ndo_validate_addr      = eth_validate_addr,
@@ -820,7 +822,7 @@ static int check_sig(struct pcmcia_device *link)
            modconf_t mod = {
                    .Attributes = CONF_IO_CHANGE_WIDTH,
            };
-           printk(KERN_INFO "smc91c92_cs: using 8-bit IO window.\n");
+           pr_info("using 8-bit IO window\n");
 
            smc91c92_suspend(link);
            pcmcia_modify_configuration(link, &mod);
@@ -881,7 +883,7 @@ static int smc91c92_config(struct pcmcia_device *link)
     if ((if_port >= 0) && (if_port <= 2))
        dev->if_port = if_port;
     else
-       printk(KERN_NOTICE "smc91c92_cs: invalid if_port requested\n");
+       dev_notice(&link->dev, "invalid if_port requested\n");
 
     switch (smc->manfid) {
     case MANFID_OSITECH:
@@ -899,7 +901,7 @@ static int smc91c92_config(struct pcmcia_device *link)
     }
 
     if (i != 0) {
-       printk(KERN_NOTICE "smc91c92_cs: Unable to find hardware address.\n");
+       dev_notice(&link->dev, "Unable to find hardware address.\n");
        goto config_failed;
     }
 
@@ -952,30 +954,28 @@ static int smc91c92_config(struct pcmcia_device *link)
     SET_NETDEV_DEV(dev, &link->dev);
 
     if (register_netdev(dev) != 0) {
-       printk(KERN_ERR "smc91c92_cs: register_netdev() failed\n");
+       dev_err(&link->dev, "register_netdev() failed\n");
        goto config_undo;
     }
 
-    printk(KERN_INFO "%s: smc91c%s rev %d: io %#3lx, irq %d, "
-          "hw_addr %pM\n",
-          dev->name, name, (rev & 0x0f), dev->base_addr, dev->irq,
-          dev->dev_addr);
+    netdev_info(dev, "smc91c%s rev %d: io %#3lx, irq %d, hw_addr %pM\n",
+               name, (rev & 0x0f), dev->base_addr, dev->irq, dev->dev_addr);
 
     if (rev > 0) {
        if (mir & 0x3ff)
-           printk(KERN_INFO "  %lu byte", mir);
+           netdev_info(dev, "  %lu byte", mir);
        else
-           printk(KERN_INFO "  %lu kb", mir>>10);
-       printk(" buffer, %s xcvr\n", (smc->cfg & CFG_MII_SELECT) ?
-              "MII" : if_names[dev->if_port]);
+           netdev_info(dev, "  %lu kb", mir>>10);
+       pr_cont(" buffer, %s xcvr\n",
+               (smc->cfg & CFG_MII_SELECT) ? "MII" : if_names[dev->if_port]);
     }
 
     if (smc->cfg & CFG_MII_SELECT) {
        if (smc->mii_if.phy_id != -1) {
-           dev_dbg(&link->dev, "  MII transceiver at index %d, status %x.\n",
-                 smc->mii_if.phy_id, j);
+           netdev_dbg(dev, "  MII transceiver at index %d, status %x\n",
+                      smc->mii_if.phy_id, j);
        } else {
-           printk(KERN_NOTICE "  No MII transceivers found!\n");
+           netdev_notice(dev, "  No MII transceivers found!\n");
        }
     }
     return 0;
@@ -1081,10 +1081,10 @@ static void smc_dump(struct net_device *dev)
     save = inw(ioaddr + BANK_SELECT);
     for (w = 0; w < 4; w++) {
        SMC_SELECT_BANK(w);
-       printk(KERN_DEBUG "bank %d: ", w);
+       netdev_printk(KERN_DEBUG, dev, "bank %d: ", w);
        for (i = 0; i < 14; i += 2)
-           printk(" %04x", inw(ioaddr + i));
-       printk("\n");
+           pr_cont(" %04x", inw(ioaddr + i));
+       pr_cont("\n");
     }
     outw(save, ioaddr + BANK_SELECT);
 }
@@ -1106,7 +1106,7 @@ static int smc_open(struct net_device *dev)
        return -ENODEV;
     /* Physical device present signature. */
     if (check_sig(link) < 0) {
-       printk("smc91c92_cs: Yikes!  Bad chip signature!\n");
+       netdev_info(dev, "Yikes!  Bad chip signature!\n");
        return -ENODEV;
     }
     link->open++;
@@ -1117,7 +1117,7 @@ static int smc_open(struct net_device *dev)
 
     smc_reset(dev);
     init_timer(&smc->media);
-    smc->media.function = &media_check;
+    smc->media.function = media_check;
     smc->media.data = (u_long) dev;
     smc->media.expires = jiffies + HZ;
     add_timer(&smc->media);
@@ -1172,7 +1172,7 @@ static void smc_hardware_send_packet(struct net_device * dev)
     u_char packet_no;
 
     if (!skb) {
-       printk(KERN_ERR "%s: In XMIT with no packet to send.\n", dev->name);
+       netdev_err(dev, "In XMIT with no packet to send\n");
        return;
     }
 
@@ -1180,8 +1180,8 @@ static void smc_hardware_send_packet(struct net_device * dev)
     packet_no = inw(ioaddr + PNR_ARR) >> 8;
     if (packet_no & 0x80) {
        /* If not, there is a hardware problem!  Likely an ejected card. */
-       printk(KERN_WARNING "%s: 91c92 hardware Tx buffer allocation"
-              " failed, status %#2.2x.\n", dev->name, packet_no);
+       netdev_warn(dev, "hardware Tx buffer allocation failed, status %#2.2x\n",
+                   packet_no);
        dev_kfree_skb_irq(skb);
        smc->saved_skb = NULL;
        netif_start_queue(dev);
@@ -1200,8 +1200,7 @@ static void smc_hardware_send_packet(struct net_device * dev)
        u_char *buf = skb->data;
        u_int length = skb->len; /* The chip will pad to ethernet min. */
 
-       pr_debug("%s: Trying to xmit packet of length %d.\n",
-             dev->name, length);
+       netdev_dbg(dev, "Trying to xmit packet of length %d\n", length);
        
        /* send the packet length: +6 for status word, length, and ctl */
        outw(0, ioaddr + DATA_1);
@@ -1233,9 +1232,8 @@ static void smc_tx_timeout(struct net_device *dev)
     struct smc_private *smc = netdev_priv(dev);
     unsigned int ioaddr = dev->base_addr;
 
-    printk(KERN_NOTICE "%s: SMC91c92 transmit timed out, "
-          "Tx_status %2.2x status %4.4x.\n",
-          dev->name, inw(ioaddr)&0xff, inw(ioaddr + 2));
+    netdev_notice(dev, "transmit timed out, Tx_status %2.2x status %4.4x.\n",
+                 inw(ioaddr)&0xff, inw(ioaddr + 2));
     dev->stats.tx_errors++;
     smc_reset(dev);
     dev->trans_start = jiffies; /* prevent tx timeout */
@@ -1254,14 +1252,14 @@ static netdev_tx_t smc_start_xmit(struct sk_buff *skb,
 
     netif_stop_queue(dev);
 
-    pr_debug("%s: smc_start_xmit(length = %d) called,"
-         " status %4.4x.\n", dev->name, skb->len, inw(ioaddr + 2));
+    netdev_dbg(dev, "smc_start_xmit(length = %d) called, status %04x\n",
+              skb->len, inw(ioaddr + 2));
 
     if (smc->saved_skb) {
        /* THIS SHOULD NEVER HAPPEN. */
        dev->stats.tx_aborted_errors++;
-       printk(KERN_DEBUG "%s: Internal error -- sent packet while busy.\n",
-              dev->name);
+       netdev_printk(KERN_DEBUG, dev,
+                     "Internal error -- sent packet while busy\n");
        return NETDEV_TX_BUSY;
     }
     smc->saved_skb = skb;
@@ -1269,7 +1267,7 @@ static netdev_tx_t smc_start_xmit(struct sk_buff *skb,
     num_pages = skb->len >> 8;
 
     if (num_pages > 7) {
-       printk(KERN_ERR "%s: Far too big packet error.\n", dev->name);
+       netdev_err(dev, "Far too big packet error: %d pages\n", num_pages);
        dev_kfree_skb (skb);
        smc->saved_skb = NULL;
        dev->stats.tx_dropped++;
@@ -1339,8 +1337,7 @@ static void smc_tx_err(struct net_device * dev)
     }
 
     if (tx_status & TS_SUCCESS) {
-       printk(KERN_NOTICE "%s: Successful packet caused error "
-              "interrupt?\n", dev->name);
+       netdev_notice(dev, "Successful packet caused error interrupt?\n");
     }
     /* re-enable transmit */
     SMC_SELECT_BANK(0);
@@ -1530,8 +1527,7 @@ static void smc_rx(struct net_device *dev)
     /* Assertion: we are in Window 2. */
 
     if (inw(ioaddr + FIFO_PORTS) & FP_RXEMPTY) {
-       printk(KERN_ERR "%s: smc_rx() with nothing on Rx FIFO.\n",
-              dev->name);
+       netdev_err(dev, "smc_rx() with nothing on Rx FIFO\n");
        return;
     }
 
@@ -1646,8 +1642,7 @@ static int s9k_config(struct net_device *dev, struct ifmap *map)
        else if (map->port > 2)
            return -EINVAL;
        dev->if_port = map->port;
-       printk(KERN_INFO "%s: switched to %s port\n",
-              dev->name, if_names[dev->if_port]);
+       netdev_info(dev, "switched to %s port\n", if_names[dev->if_port]);
        smc_reset(dev);
     }
     return 0;
@@ -1798,7 +1793,7 @@ static void media_check(u_long arg)
        this, we can limp along even if the interrupt is blocked */
     if (smc->watchdog++ && ((i>>8) & i)) {
        if (!smc->fast_poll)
-           printk(KERN_INFO "%s: interrupt(s) dropped!\n", dev->name);
+           netdev_info(dev, "interrupt(s) dropped!\n");
        local_irq_save(flags);
        smc_interrupt(dev->irq, dev);
        local_irq_restore(flags);
@@ -1822,7 +1817,7 @@ static void media_check(u_long arg)
        SMC_SELECT_BANK(3);
        link = mdio_read(dev, smc->mii_if.phy_id, 1);
        if (!link || (link == 0xffff)) {
-           printk(KERN_INFO "%s: MII is missing!\n", dev->name);
+           netdev_info(dev, "MII is missing!\n");
            smc->mii_if.phy_id = -1;
            goto reschedule;
        }
@@ -1830,15 +1825,13 @@ static void media_check(u_long arg)
        link &= 0x0004;
        if (link != smc->link_status) {
            u_short p = mdio_read(dev, smc->mii_if.phy_id, 5);
-           printk(KERN_INFO "%s: %s link beat\n", dev->name,
-               (link) ? "found" : "lost");
+           netdev_info(dev, "%s link beat\n", link ? "found" : "lost");
            smc->duplex = (((p & 0x0100) || ((p & 0x1c0) == 0x40))
                           ? TCR_FDUPLX : 0);
            if (link) {
-               printk(KERN_INFO "%s: autonegotiation complete: "
-                      "%sbaseT-%cD selected\n", dev->name,
-                      ((p & 0x0180) ? "100" : "10"),
-                      (smc->duplex ? 'F' : 'H'));
+               netdev_info(dev, "autonegotiation complete: "
+                           "%dbaseT-%cD selected\n",
+                           (p & 0x0180) ? 100 : 10, smc->duplex ? 'F' : 'H');
            }
            SMC_SELECT_BANK(0);
            outw(inw(ioaddr + TCR) | smc->duplex, ioaddr + TCR);
@@ -1857,25 +1850,23 @@ static void media_check(u_long arg)
     if (media != smc->media_status) {
        if ((media & smc->media_status & 1) &&
            ((smc->media_status ^ media) & EPH_LINK_OK))
-           printk(KERN_INFO "%s: %s link beat\n", dev->name,
-                  (smc->media_status & EPH_LINK_OK ? "lost" : "found"));
+           netdev_info(dev, "%s link beat\n",
+                       smc->media_status & EPH_LINK_OK ? "lost" : "found");
        else if ((media & smc->media_status & 2) &&
                 ((smc->media_status ^ media) & EPH_16COL))
-           printk(KERN_INFO "%s: coax cable %s\n", dev->name,
-                  (media & EPH_16COL ? "problem" : "ok"));
+           netdev_info(dev, "coax cable %s\n",
+                       media & EPH_16COL ? "problem" : "ok");
        if (dev->if_port == 0) {
            if (media & 1) {
                if (media & EPH_LINK_OK)
-                   printk(KERN_INFO "%s: flipped to 10baseT\n",
-                          dev->name);
+                   netdev_info(dev, "flipped to 10baseT\n");
                else
                    smc_set_xcvr(dev, 2);
            } else {
                if (media & EPH_16COL)
                    smc_set_xcvr(dev, 1);
                else
-                   printk(KERN_INFO "%s: flipped to 10base2\n",
-                          dev->name);
+                   netdev_info(dev, "flipped to 10base2\n");
            }
        }
        smc->media_status = media;
index f5819526b5ee90c25a8630a63fc81f04b64ffb0e..d858b5e4c4a7f1601ea856f1591bcb94fd19d9e5 100644 (file)
@@ -63,6 +63,8 @@
  * OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -210,13 +212,6 @@ enum xirc_cmd {        /* Commands */
 
 static const char *if_names[] = { "Auto", "10BaseT", "10Base2", "AUI", "100BaseT" };
 
-
-#define KDBG_XIRC KERN_DEBUG   "xirc2ps_cs: "
-#define KERR_XIRC KERN_ERR     "xirc2ps_cs: "
-#define KWRN_XIRC KERN_WARNING "xirc2ps_cs: "
-#define KNOT_XIRC KERN_NOTICE  "xirc2ps_cs: "
-#define KINF_XIRC KERN_INFO    "xirc2ps_cs: "
-
 /* card types */
 #define XIR_UNKNOWN  0 /* unknown: not supported */
 #define XIR_CE      1  /* (prodid 1) different hardware: not supported */
@@ -350,26 +345,26 @@ PrintRegisters(struct net_device *dev)
     if (pc_debug > 1) {
        int i, page;
 
-       printk(KDBG_XIRC "Register  common: ");
+       printk(KERN_DEBUG pr_fmt("Register  common: "));
        for (i = 0; i < 8; i++)
-           printk(" %2.2x", GetByte(i));
-       printk("\n");
+           pr_cont(" %2.2x", GetByte(i));
+       pr_cont("\n");
        for (page = 0; page <= 8; page++) {
-           printk(KDBG_XIRC "Register page %2x: ", page);
+           printk(KERN_DEBUG pr_fmt("Register page %2x: "), page);
            SelectPage(page);
            for (i = 8; i < 16; i++)
-               printk(" %2.2x", GetByte(i));
-           printk("\n");
+               pr_cont(" %2.2x", GetByte(i));
+           pr_cont("\n");
        }
        for (page=0x40 ; page <= 0x5f; page++) {
                if (page == 0x43 || (page >= 0x46 && page <= 0x4f) ||
                    (page >= 0x51 && page <=0x5e))
                        continue;
-           printk(KDBG_XIRC "Register page %2x: ", page);
+           printk(KERN_DEBUG pr_fmt("Register page %2x: "), page);
            SelectPage(page);
            for (i = 8; i < 16; i++)
-               printk(" %2.2x", GetByte(i));
-           printk("\n");
+               pr_cont(" %2.2x", GetByte(i));
+           pr_cont("\n");
        }
     }
 }
@@ -608,11 +603,11 @@ set_card_type(struct pcmcia_device *link)
     local->modem = 0;
     local->card_type = XIR_UNKNOWN;
     if (!(prodid & 0x40)) {
-       printk(KNOT_XIRC "Ooops: Not a creditcard\n");
+       pr_notice("Oops: Not a creditcard\n");
        return 0;
     }
     if (!(mediaid & 0x01)) {
-       printk(KNOT_XIRC "Not an Ethernet card\n");
+       pr_notice("Not an Ethernet card\n");
        return 0;
     }
     if (mediaid & 0x10) {
@@ -643,12 +638,11 @@ set_card_type(struct pcmcia_device *link)
        }
     }
     if (local->card_type == XIR_CE || local->card_type == XIR_CEM) {
-       printk(KNOT_XIRC "Sorry, this is an old CE card\n");
+       pr_notice("Sorry, this is an old CE card\n");
        return 0;
     }
     if (local->card_type == XIR_UNKNOWN)
-       printk(KNOT_XIRC "unknown card (mediaid=%02x prodid=%02x)\n",
-              mediaid, prodid);
+       pr_notice("unknown card (mediaid=%02x prodid=%02x)\n", mediaid, prodid);
 
     return 1;
 }
@@ -748,7 +742,7 @@ xirc2ps_config(struct pcmcia_device * link)
 
     /* Is this a valid card */
     if (link->has_manf_id == 0) {
-       printk(KNOT_XIRC "manfid not found in CIS\n");
+       pr_notice("manfid not found in CIS\n");
        goto failure;
     }
 
@@ -770,14 +764,14 @@ xirc2ps_config(struct pcmcia_device * link)
        local->manf_str = "Toshiba";
        break;
       default:
-       printk(KNOT_XIRC "Unknown Card Manufacturer ID: 0x%04x\n",
-              (unsigned)link->manf_id);
+       pr_notice("Unknown Card Manufacturer ID: 0x%04x\n",
+                 (unsigned)link->manf_id);
        goto failure;
     }
     dev_dbg(&link->dev, "found %s card\n", local->manf_str);
 
     if (!set_card_type(link)) {
-       printk(KNOT_XIRC "this card is not supported\n");
+       pr_notice("this card is not supported\n");
        goto failure;
     }
 
@@ -803,7 +797,7 @@ xirc2ps_config(struct pcmcia_device * link)
        err = pcmcia_loop_tuple(link, CISTPL_FUNCE, pcmcia_get_mac_ce, dev);
 
     if (err) {
-       printk(KNOT_XIRC "node-id not found in CIS\n");
+       pr_notice("node-id not found in CIS\n");
        goto failure;
     }
 
@@ -838,7 +832,7 @@ xirc2ps_config(struct pcmcia_device * link)
             * try to configure as Ethernet only.
             * .... */
        }
-       printk(KNOT_XIRC "no ports available\n");
+       pr_notice("no ports available\n");
     } else {
        link->resource[0]->end = 16;
        for (ioaddr = 0x300; ioaddr < 0x400; ioaddr += 0x10) {
@@ -911,24 +905,24 @@ xirc2ps_config(struct pcmcia_device * link)
       #if 0
        {
            u_char tmp;
-           printk(KERN_INFO "ECOR:");
+           pr_info("ECOR:");
            for (i=0; i < 7; i++) {
                tmp = readb(local->dingo_ccr + i*2);
-               printk(" %02x", tmp);
+               pr_cont(" %02x", tmp);
            }
-           printk("\n");
-           printk(KERN_INFO "DCOR:");
+           pr_cont("\n");
+           pr_info("DCOR:");
            for (i=0; i < 4; i++) {
                tmp = readb(local->dingo_ccr + 0x20 + i*2);
-               printk(" %02x", tmp);
+               pr_cont(" %02x", tmp);
            }
-           printk("\n");
-           printk(KERN_INFO "SCOR:");
+           pr_cont("\n");
+           pr_info("SCOR:");
            for (i=0; i < 10; i++) {
                tmp = readb(local->dingo_ccr + 0x40 + i*2);
-               printk(" %02x", tmp);
+               pr_cont(" %02x", tmp);
            }
-           printk("\n");
+           pr_cont("\n");
        }
       #endif
 
@@ -947,7 +941,7 @@ xirc2ps_config(struct pcmcia_device * link)
               (local->mohawk && if_port==4))
        dev->if_port = if_port;
     else
-       printk(KNOT_XIRC "invalid if_port requested\n");
+       pr_notice("invalid if_port requested\n");
 
     /* we can now register the device with the net subsystem */
     dev->irq = link->irq;
@@ -959,14 +953,14 @@ xirc2ps_config(struct pcmcia_device * link)
     SET_NETDEV_DEV(dev, &link->dev);
 
     if ((err=register_netdev(dev))) {
-       printk(KNOT_XIRC "register_netdev() failed\n");
+       pr_notice("register_netdev() failed\n");
        goto config_error;
     }
 
     /* give some infos about the hardware */
-    printk(KERN_INFO "%s: %s: port %#3lx, irq %d, hwaddr %pM\n",
-          dev->name, local->manf_str,(u_long)dev->base_addr, (int)dev->irq,
-          dev->dev_addr);
+    netdev_info(dev, "%s: port %#3lx, irq %d, hwaddr %pM\n",
+               local->manf_str, (u_long)dev->base_addr, (int)dev->irq,
+               dev->dev_addr);
 
     return 0;
 
@@ -1098,8 +1092,7 @@ xirc2ps_interrupt(int irq, void *dev_id)
 
            skb = dev_alloc_skb(pktlen+3); /* 1 extra so we can use insw */
            if (!skb) {
-               printk(KNOT_XIRC "low memory, packet dropped (size=%u)\n",
-                      pktlen);
+               pr_notice("low memory, packet dropped (size=%u)\n", pktlen);
                dev->stats.rx_dropped++;
            } else { /* okay get the packet */
                skb_reserve(skb, 2);
@@ -1268,7 +1261,7 @@ xirc_tx_timeout(struct net_device *dev)
 {
     local_info_t *lp = netdev_priv(dev);
     dev->stats.tx_errors++;
-    printk(KERN_NOTICE "%s: transmit timed out\n", dev->name);
+    netdev_notice(dev, "transmit timed out\n");
     schedule_work(&lp->tx_timeout_task);
 }
 
@@ -1435,8 +1428,7 @@ do_config(struct net_device *dev, struct ifmap *map)
            local->probe_port = 0;
            dev->if_port = map->port;
        }
-       printk(KERN_INFO "%s: switching to %s port\n",
-              dev->name, if_names[dev->if_port]);
+       netdev_info(dev, "switching to %s port\n", if_names[dev->if_port]);
        do_reset(dev,1);  /* not the fine way :-) */
     }
     return 0;
@@ -1576,7 +1568,7 @@ do_reset(struct net_device *dev, int full)
     {
        SelectPage(0);
        value = GetByte(XIRCREG_ESR);    /* read the ESR */
-       printk(KERN_DEBUG "%s: ESR is: %#02x\n", dev->name, value);
+       pr_debug("%s: ESR is: %#02x\n", dev->name, value);
     }
   #endif
 
@@ -1626,13 +1618,12 @@ do_reset(struct net_device *dev, int full)
 
     if (full && local->mohawk && init_mii(dev)) {
        if (dev->if_port == 4 || local->dingo || local->new_mii) {
-           printk(KERN_INFO "%s: MII selected\n", dev->name);
+           netdev_info(dev, "MII selected\n");
            SelectPage(2);
            PutByte(XIRCREG2_MSR, GetByte(XIRCREG2_MSR) | 0x08);
            msleep(20);
        } else {
-           printk(KERN_INFO "%s: MII detected; using 10mbs\n",
-                  dev->name);
+           netdev_info(dev, "MII detected; using 10mbs\n");
            SelectPage(0x42);
            if (dev->if_port == 2) /* enable 10Base2 */
                PutByte(XIRCREG42_SWC1, 0xC0);
@@ -1677,8 +1668,8 @@ do_reset(struct net_device *dev, int full)
     }
 
     if (full)
-       printk(KERN_INFO "%s: media %s, silicon revision %d\n",
-              dev->name, if_names[dev->if_port], local->silicon);
+       netdev_info(dev, "media %s, silicon revision %d\n",
+                   if_names[dev->if_port], local->silicon);
     /* We should switch back to page 0 to avoid a bug in revision 0
      * where regs with offset below 8 can't be read after an access
      * to the MAC registers */
@@ -1720,8 +1711,7 @@ init_mii(struct net_device *dev)
     control = mii_rd(ioaddr, 0, 0);
 
     if (control & 0x0400) {
-       printk(KERN_NOTICE "%s can't take PHY out of isolation mode\n",
-              dev->name);
+       netdev_notice(dev, "can't take PHY out of isolation mode\n");
        local->probe_port = 0;
        return 0;
     }
@@ -1739,8 +1729,7 @@ init_mii(struct net_device *dev)
        }
 
        if (!(status & 0x0020)) {
-           printk(KERN_INFO "%s: autonegotiation failed;"
-                  " using 10mbs\n", dev->name);
+           netdev_info(dev, "autonegotiation failed; using 10mbs\n");
            if (!local->new_mii) {
                control = 0x0000;
                mii_wr(ioaddr,  0, 0, control, 16);
@@ -1750,8 +1739,7 @@ init_mii(struct net_device *dev)
            }
        } else {
            linkpartner = mii_rd(ioaddr, 0, 5);
-           printk(KERN_INFO "%s: MII link partner: %04x\n",
-                  dev->name, linkpartner);
+           netdev_info(dev, "MII link partner: %04x\n", linkpartner);
            if (linkpartner & 0x0080) {
                dev->if_port = 4;
            } else
index ec0349e84a8a8cd093977a50d3f9aa0879b291e7..7e82a82422cffd0d248d164b137938f16cd6f4d9 100644 (file)
@@ -1279,7 +1279,6 @@ static void plip_attach (struct parport *port)
                if (!nl->pardev) {
                        printk(KERN_ERR "%s: parport_register failed\n", name);
                        goto err_free_dev;
-                       return;
                }
 
                plip_init_netdev(dev);
diff --git a/drivers/net/pptp.c b/drivers/net/pptp.c
new file mode 100644 (file)
index 0000000..761f0ec
--- /dev/null
@@ -0,0 +1,726 @@
+/*
+ *  Point-to-Point Tunneling Protocol for Linux
+ *
+ *     Authors: Dmitry Kozlov <xeb@mail.ru>
+ *
+ *     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.
+ *
+ */
+
+#include <linux/string.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/net.h>
+#include <linux/skbuff.h>
+#include <linux/vmalloc.h>
+#include <linux/init.h>
+#include <linux/ppp_channel.h>
+#include <linux/ppp_defs.h>
+#include <linux/if_pppox.h>
+#include <linux/if_ppp.h>
+#include <linux/notifier.h>
+#include <linux/file.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter_ipv4.h>
+#include <linux/version.h>
+#include <linux/rcupdate.h>
+#include <linux/spinlock.h>
+
+#include <net/sock.h>
+#include <net/protocol.h>
+#include <net/ip.h>
+#include <net/icmp.h>
+#include <net/route.h>
+#include <net/gre.h>
+
+#include <linux/uaccess.h>
+
+#define PPTP_DRIVER_VERSION "0.8.5"
+
+#define MAX_CALLID 65535
+
+static DECLARE_BITMAP(callid_bitmap, MAX_CALLID + 1);
+static struct pppox_sock **callid_sock;
+
+static DEFINE_SPINLOCK(chan_lock);
+
+static struct proto pptp_sk_proto __read_mostly;
+static struct ppp_channel_ops pptp_chan_ops;
+static const struct proto_ops pptp_ops;
+
+#define PPP_LCP_ECHOREQ 0x09
+#define PPP_LCP_ECHOREP 0x0A
+#define SC_RCV_BITS    (SC_RCV_B7_1|SC_RCV_B7_0|SC_RCV_ODDP|SC_RCV_EVNP)
+
+#define MISSING_WINDOW 20
+#define WRAPPED(curseq, lastseq)\
+       ((((curseq) & 0xffffff00) == 0) &&\
+       (((lastseq) & 0xffffff00) == 0xffffff00))
+
+#define PPTP_GRE_PROTO  0x880B
+#define PPTP_GRE_VER    0x1
+
+#define PPTP_GRE_FLAG_C        0x80
+#define PPTP_GRE_FLAG_R        0x40
+#define PPTP_GRE_FLAG_K        0x20
+#define PPTP_GRE_FLAG_S        0x10
+#define PPTP_GRE_FLAG_A        0x80
+
+#define PPTP_GRE_IS_C(f) ((f)&PPTP_GRE_FLAG_C)
+#define PPTP_GRE_IS_R(f) ((f)&PPTP_GRE_FLAG_R)
+#define PPTP_GRE_IS_K(f) ((f)&PPTP_GRE_FLAG_K)
+#define PPTP_GRE_IS_S(f) ((f)&PPTP_GRE_FLAG_S)
+#define PPTP_GRE_IS_A(f) ((f)&PPTP_GRE_FLAG_A)
+
+#define PPTP_HEADER_OVERHEAD (2+sizeof(struct pptp_gre_header))
+struct pptp_gre_header {
+       u8  flags;
+       u8  ver;
+       u16 protocol;
+       u16 payload_len;
+       u16 call_id;
+       u32 seq;
+       u32 ack;
+} __packed;
+
+static struct pppox_sock *lookup_chan(u16 call_id, __be32 s_addr)
+{
+       struct pppox_sock *sock;
+       struct pptp_opt *opt;
+
+       rcu_read_lock();
+       sock = rcu_dereference(callid_sock[call_id]);
+       if (sock) {
+               opt = &sock->proto.pptp;
+               if (opt->dst_addr.sin_addr.s_addr != s_addr)
+                       sock = NULL;
+               else
+                       sock_hold(sk_pppox(sock));
+       }
+       rcu_read_unlock();
+
+       return sock;
+}
+
+static int lookup_chan_dst(u16 call_id, __be32 d_addr)
+{
+       struct pppox_sock *sock;
+       struct pptp_opt *opt;
+       int i;
+
+       rcu_read_lock();
+       for (i = find_next_bit(callid_bitmap, MAX_CALLID, 1); i < MAX_CALLID;
+            i = find_next_bit(callid_bitmap, MAX_CALLID, i + 1)) {
+               sock = rcu_dereference(callid_sock[i]);
+               if (!sock)
+                       continue;
+               opt = &sock->proto.pptp;
+               if (opt->dst_addr.call_id == call_id &&
+                         opt->dst_addr.sin_addr.s_addr == d_addr)
+                       break;
+       }
+       rcu_read_unlock();
+
+       return i < MAX_CALLID;
+}
+
+static int add_chan(struct pppox_sock *sock)
+{
+       static int call_id;
+
+       spin_lock(&chan_lock);
+       if (!sock->proto.pptp.src_addr.call_id) {
+               call_id = find_next_zero_bit(callid_bitmap, MAX_CALLID, call_id + 1);
+               if (call_id == MAX_CALLID) {
+                       call_id = find_next_zero_bit(callid_bitmap, MAX_CALLID, 1);
+                       if (call_id == MAX_CALLID)
+                               goto out_err;
+               }
+               sock->proto.pptp.src_addr.call_id = call_id;
+       } else if (test_bit(sock->proto.pptp.src_addr.call_id, callid_bitmap))
+               goto out_err;
+
+       set_bit(sock->proto.pptp.src_addr.call_id, callid_bitmap);
+       rcu_assign_pointer(callid_sock[sock->proto.pptp.src_addr.call_id], sock);
+       spin_unlock(&chan_lock);
+
+       return 0;
+
+out_err:
+       spin_unlock(&chan_lock);
+       return -1;
+}
+
+static void del_chan(struct pppox_sock *sock)
+{
+       spin_lock(&chan_lock);
+       clear_bit(sock->proto.pptp.src_addr.call_id, callid_bitmap);
+       rcu_assign_pointer(callid_sock[sock->proto.pptp.src_addr.call_id], NULL);
+       spin_unlock(&chan_lock);
+       synchronize_rcu();
+}
+
+static int pptp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
+{
+       struct sock *sk = (struct sock *) chan->private;
+       struct pppox_sock *po = pppox_sk(sk);
+       struct pptp_opt *opt = &po->proto.pptp;
+       struct pptp_gre_header *hdr;
+       unsigned int header_len = sizeof(*hdr);
+       int err = 0;
+       int islcp;
+       int len;
+       unsigned char *data;
+       __u32 seq_recv;
+
+
+       struct rtable *rt;
+       struct net_device *tdev;
+       struct iphdr  *iph;
+       int    max_headroom;
+
+       if (sk_pppox(po)->sk_state & PPPOX_DEAD)
+               goto tx_error;
+
+       {
+               struct flowi fl = { .oif = 0,
+                       .nl_u = {
+                               .ip4_u = {
+                                       .daddr = opt->dst_addr.sin_addr.s_addr,
+                                       .saddr = opt->src_addr.sin_addr.s_addr,
+                                       .tos = RT_TOS(0) } },
+                       .proto = IPPROTO_GRE };
+               err = ip_route_output_key(&init_net, &rt, &fl);
+               if (err)
+                       goto tx_error;
+       }
+       tdev = rt->dst.dev;
+
+       max_headroom = LL_RESERVED_SPACE(tdev) + sizeof(*iph) + sizeof(*hdr) + 2;
+
+       if (skb_headroom(skb) < max_headroom || skb_cloned(skb) || skb_shared(skb)) {
+               struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom);
+               if (!new_skb) {
+                       ip_rt_put(rt);
+                       goto tx_error;
+               }
+               if (skb->sk)
+                       skb_set_owner_w(new_skb, skb->sk);
+               kfree_skb(skb);
+               skb = new_skb;
+       }
+
+       data = skb->data;
+       islcp = ((data[0] << 8) + data[1]) == PPP_LCP && 1 <= data[2] && data[2] <= 7;
+
+       /* compress protocol field */
+       if ((opt->ppp_flags & SC_COMP_PROT) && data[0] == 0 && !islcp)
+               skb_pull(skb, 1);
+
+       /* Put in the address/control bytes if necessary */
+       if ((opt->ppp_flags & SC_COMP_AC) == 0 || islcp) {
+               data = skb_push(skb, 2);
+               data[0] = PPP_ALLSTATIONS;
+               data[1] = PPP_UI;
+       }
+
+       len = skb->len;
+
+       seq_recv = opt->seq_recv;
+
+       if (opt->ack_sent == seq_recv)
+               header_len -= sizeof(hdr->ack);
+
+       /* Push down and install GRE header */
+       skb_push(skb, header_len);
+       hdr = (struct pptp_gre_header *)(skb->data);
+
+       hdr->flags       = PPTP_GRE_FLAG_K;
+       hdr->ver         = PPTP_GRE_VER;
+       hdr->protocol    = htons(PPTP_GRE_PROTO);
+       hdr->call_id     = htons(opt->dst_addr.call_id);
+
+       hdr->flags      |= PPTP_GRE_FLAG_S;
+       hdr->seq         = htonl(++opt->seq_sent);
+       if (opt->ack_sent != seq_recv)  {
+               /* send ack with this message */
+               hdr->ver |= PPTP_GRE_FLAG_A;
+               hdr->ack  = htonl(seq_recv);
+               opt->ack_sent = seq_recv;
+       }
+       hdr->payload_len = htons(len);
+
+       /*      Push down and install the IP header. */
+
+       skb_reset_transport_header(skb);
+       skb_push(skb, sizeof(*iph));
+       skb_reset_network_header(skb);
+       memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
+       IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED | IPSKB_REROUTED);
+
+       iph =   ip_hdr(skb);
+       iph->version =  4;
+       iph->ihl =      sizeof(struct iphdr) >> 2;
+       if (ip_dont_fragment(sk, &rt->dst))
+               iph->frag_off   =       htons(IP_DF);
+       else
+               iph->frag_off   =       0;
+       iph->protocol = IPPROTO_GRE;
+       iph->tos      = 0;
+       iph->daddr    = rt->rt_dst;
+       iph->saddr    = rt->rt_src;
+       iph->ttl      = dst_metric(&rt->dst, RTAX_HOPLIMIT);
+       iph->tot_len  = htons(skb->len);
+
+       skb_dst_drop(skb);
+       skb_dst_set(skb, &rt->dst);
+
+       nf_reset(skb);
+
+       skb->ip_summed = CHECKSUM_NONE;
+       ip_select_ident(iph, &rt->dst, NULL);
+       ip_send_check(iph);
+
+       ip_local_out(skb);
+
+tx_error:
+       return 1;
+}
+
+static int pptp_rcv_core(struct sock *sk, struct sk_buff *skb)
+{
+       struct pppox_sock *po = pppox_sk(sk);
+       struct pptp_opt *opt = &po->proto.pptp;
+       int headersize, payload_len, seq;
+       __u8 *payload;
+       struct pptp_gre_header *header;
+
+       if (!(sk->sk_state & PPPOX_CONNECTED)) {
+               if (sock_queue_rcv_skb(sk, skb))
+                       goto drop;
+               return NET_RX_SUCCESS;
+       }
+
+       header = (struct pptp_gre_header *)(skb->data);
+
+       /* test if acknowledgement present */
+       if (PPTP_GRE_IS_A(header->ver)) {
+               __u32 ack = (PPTP_GRE_IS_S(header->flags)) ?
+                               header->ack : header->seq; /* ack in different place if S = 0 */
+
+               ack = ntohl(ack);
+
+               if (ack > opt->ack_recv)
+                       opt->ack_recv = ack;
+               /* also handle sequence number wrap-around  */
+               if (WRAPPED(ack, opt->ack_recv))
+                       opt->ack_recv = ack;
+       }
+
+       /* test if payload present */
+       if (!PPTP_GRE_IS_S(header->flags))
+               goto drop;
+
+       headersize  = sizeof(*header);
+       payload_len = ntohs(header->payload_len);
+       seq         = ntohl(header->seq);
+
+       /* no ack present? */
+       if (!PPTP_GRE_IS_A(header->ver))
+               headersize -= sizeof(header->ack);
+       /* check for incomplete packet (length smaller than expected) */
+       if (skb->len - headersize < payload_len)
+               goto drop;
+
+       payload = skb->data + headersize;
+       /* check for expected sequence number */
+       if (seq < opt->seq_recv + 1 || WRAPPED(opt->seq_recv, seq)) {
+               if ((payload[0] == PPP_ALLSTATIONS) && (payload[1] == PPP_UI) &&
+                               (PPP_PROTOCOL(payload) == PPP_LCP) &&
+                               ((payload[4] == PPP_LCP_ECHOREQ) || (payload[4] == PPP_LCP_ECHOREP)))
+                       goto allow_packet;
+       } else {
+               opt->seq_recv = seq;
+allow_packet:
+               skb_pull(skb, headersize);
+
+               if (payload[0] == PPP_ALLSTATIONS && payload[1] == PPP_UI) {
+                       /* chop off address/control */
+                       if (skb->len < 3)
+                               goto drop;
+                       skb_pull(skb, 2);
+               }
+
+               if ((*skb->data) & 1) {
+                       /* protocol is compressed */
+                       skb_push(skb, 1)[0] = 0;
+               }
+
+               skb->ip_summed = CHECKSUM_NONE;
+               skb_set_network_header(skb, skb->head-skb->data);
+               ppp_input(&po->chan, skb);
+
+               return NET_RX_SUCCESS;
+       }
+drop:
+       kfree_skb(skb);
+       return NET_RX_DROP;
+}
+
+static int pptp_rcv(struct sk_buff *skb)
+{
+       struct pppox_sock *po;
+       struct pptp_gre_header *header;
+       struct iphdr *iph;
+
+       if (skb->pkt_type != PACKET_HOST)
+               goto drop;
+
+       if (!pskb_may_pull(skb, 12))
+               goto drop;
+
+       iph = ip_hdr(skb);
+
+       header = (struct pptp_gre_header *)skb->data;
+
+       if (ntohs(header->protocol) != PPTP_GRE_PROTO || /* PPTP-GRE protocol for PPTP */
+               PPTP_GRE_IS_C(header->flags) ||                /* flag C should be clear */
+               PPTP_GRE_IS_R(header->flags) ||                /* flag R should be clear */
+               !PPTP_GRE_IS_K(header->flags) ||               /* flag K should be set */
+               (header->flags&0xF) != 0)                      /* routing and recursion ctrl = 0 */
+               /* if invalid, discard this packet */
+               goto drop;
+
+       po = lookup_chan(htons(header->call_id), iph->saddr);
+       if (po) {
+               skb_dst_drop(skb);
+               nf_reset(skb);
+               return sk_receive_skb(sk_pppox(po), skb, 0);
+       }
+drop:
+       kfree_skb(skb);
+       return NET_RX_DROP;
+}
+
+static int pptp_bind(struct socket *sock, struct sockaddr *uservaddr,
+       int sockaddr_len)
+{
+       struct sock *sk = sock->sk;
+       struct sockaddr_pppox *sp = (struct sockaddr_pppox *) uservaddr;
+       struct pppox_sock *po = pppox_sk(sk);
+       struct pptp_opt *opt = &po->proto.pptp;
+       int error = 0;
+
+       lock_sock(sk);
+
+       opt->src_addr = sp->sa_addr.pptp;
+       if (add_chan(po)) {
+               release_sock(sk);
+               error = -EBUSY;
+       }
+
+       release_sock(sk);
+       return error;
+}
+
+static int pptp_connect(struct socket *sock, struct sockaddr *uservaddr,
+       int sockaddr_len, int flags)
+{
+       struct sock *sk = sock->sk;
+       struct sockaddr_pppox *sp = (struct sockaddr_pppox *) uservaddr;
+       struct pppox_sock *po = pppox_sk(sk);
+       struct pptp_opt *opt = &po->proto.pptp;
+       struct rtable *rt;
+       int error = 0;
+
+       if (sp->sa_protocol != PX_PROTO_PPTP)
+               return -EINVAL;
+
+       if (lookup_chan_dst(sp->sa_addr.pptp.call_id, sp->sa_addr.pptp.sin_addr.s_addr))
+               return -EALREADY;
+
+       lock_sock(sk);
+       /* Check for already bound sockets */
+       if (sk->sk_state & PPPOX_CONNECTED) {
+               error = -EBUSY;
+               goto end;
+       }
+
+       /* Check for already disconnected sockets, on attempts to disconnect */
+       if (sk->sk_state & PPPOX_DEAD) {
+               error = -EALREADY;
+               goto end;
+       }
+
+       if (!opt->src_addr.sin_addr.s_addr || !sp->sa_addr.pptp.sin_addr.s_addr) {
+               error = -EINVAL;
+               goto end;
+       }
+
+       po->chan.private = sk;
+       po->chan.ops = &pptp_chan_ops;
+
+       {
+               struct flowi fl = {
+                       .nl_u = {
+                               .ip4_u = {
+                                       .daddr = opt->dst_addr.sin_addr.s_addr,
+                                       .saddr = opt->src_addr.sin_addr.s_addr,
+                                       .tos = RT_CONN_FLAGS(sk) } },
+                       .proto = IPPROTO_GRE };
+               security_sk_classify_flow(sk, &fl);
+               if (ip_route_output_key(&init_net, &rt, &fl)) {
+                       error = -EHOSTUNREACH;
+                       goto end;
+               }
+               sk_setup_caps(sk, &rt->dst);
+       }
+       po->chan.mtu = dst_mtu(&rt->dst);
+       if (!po->chan.mtu)
+               po->chan.mtu = PPP_MTU;
+       ip_rt_put(rt);
+       po->chan.mtu -= PPTP_HEADER_OVERHEAD;
+
+       po->chan.hdrlen = 2 + sizeof(struct pptp_gre_header);
+       error = ppp_register_channel(&po->chan);
+       if (error) {
+               pr_err("PPTP: failed to register PPP channel (%d)\n", error);
+               goto end;
+       }
+
+       opt->dst_addr = sp->sa_addr.pptp;
+       sk->sk_state = PPPOX_CONNECTED;
+
+ end:
+       release_sock(sk);
+       return error;
+}
+
+static int pptp_getname(struct socket *sock, struct sockaddr *uaddr,
+       int *usockaddr_len, int peer)
+{
+       int len = sizeof(struct sockaddr_pppox);
+       struct sockaddr_pppox sp;
+
+       sp.sa_family      = AF_PPPOX;
+       sp.sa_protocol  = PX_PROTO_PPTP;
+       sp.sa_addr.pptp = pppox_sk(sock->sk)->proto.pptp.src_addr;
+
+       memcpy(uaddr, &sp, len);
+
+       *usockaddr_len = len;
+
+       return 0;
+}
+
+static int pptp_release(struct socket *sock)
+{
+       struct sock *sk = sock->sk;
+       struct pppox_sock *po;
+       struct pptp_opt *opt;
+       int error = 0;
+
+       if (!sk)
+               return 0;
+
+       lock_sock(sk);
+
+       if (sock_flag(sk, SOCK_DEAD)) {
+               release_sock(sk);
+               return -EBADF;
+       }
+
+       po = pppox_sk(sk);
+       opt = &po->proto.pptp;
+       del_chan(po);
+
+       pppox_unbind_sock(sk);
+       sk->sk_state = PPPOX_DEAD;
+
+       sock_orphan(sk);
+       sock->sk = NULL;
+
+       release_sock(sk);
+       sock_put(sk);
+
+       return error;
+}
+
+static void pptp_sock_destruct(struct sock *sk)
+{
+       if (!(sk->sk_state & PPPOX_DEAD)) {
+               del_chan(pppox_sk(sk));
+               pppox_unbind_sock(sk);
+       }
+       skb_queue_purge(&sk->sk_receive_queue);
+}
+
+static int pptp_create(struct net *net, struct socket *sock)
+{
+       int error = -ENOMEM;
+       struct sock *sk;
+       struct pppox_sock *po;
+       struct pptp_opt *opt;
+
+       sk = sk_alloc(net, PF_PPPOX, GFP_KERNEL, &pptp_sk_proto);
+       if (!sk)
+               goto out;
+
+       sock_init_data(sock, sk);
+
+       sock->state = SS_UNCONNECTED;
+       sock->ops   = &pptp_ops;
+
+       sk->sk_backlog_rcv = pptp_rcv_core;
+       sk->sk_state       = PPPOX_NONE;
+       sk->sk_type        = SOCK_STREAM;
+       sk->sk_family      = PF_PPPOX;
+       sk->sk_protocol    = PX_PROTO_PPTP;
+       sk->sk_destruct    = pptp_sock_destruct;
+
+       po = pppox_sk(sk);
+       opt = &po->proto.pptp;
+
+       opt->seq_sent = 0; opt->seq_recv = 0;
+       opt->ack_recv = 0; opt->ack_sent = 0;
+
+       error = 0;
+out:
+       return error;
+}
+
+static int pptp_ppp_ioctl(struct ppp_channel *chan, unsigned int cmd,
+       unsigned long arg)
+{
+       struct sock *sk = (struct sock *) chan->private;
+       struct pppox_sock *po = pppox_sk(sk);
+       struct pptp_opt *opt = &po->proto.pptp;
+       void __user *argp = (void __user *)arg;
+       int __user *p = argp;
+       int err, val;
+
+       err = -EFAULT;
+       switch (cmd) {
+       case PPPIOCGFLAGS:
+               val = opt->ppp_flags;
+               if (put_user(val, p))
+                       break;
+               err = 0;
+               break;
+       case PPPIOCSFLAGS:
+               if (get_user(val, p))
+                       break;
+               opt->ppp_flags = val & ~SC_RCV_BITS;
+               err = 0;
+               break;
+       default:
+               err = -ENOTTY;
+       }
+
+       return err;
+}
+
+static struct ppp_channel_ops pptp_chan_ops = {
+       .start_xmit = pptp_xmit,
+       .ioctl      = pptp_ppp_ioctl,
+};
+
+static struct proto pptp_sk_proto __read_mostly = {
+       .name     = "PPTP",
+       .owner    = THIS_MODULE,
+       .obj_size = sizeof(struct pppox_sock),
+};
+
+static const struct proto_ops pptp_ops = {
+       .family     = AF_PPPOX,
+       .owner      = THIS_MODULE,
+       .release    = pptp_release,
+       .bind       = pptp_bind,
+       .connect    = pptp_connect,
+       .socketpair = sock_no_socketpair,
+       .accept     = sock_no_accept,
+       .getname    = pptp_getname,
+       .poll       = sock_no_poll,
+       .listen     = sock_no_listen,
+       .shutdown   = sock_no_shutdown,
+       .setsockopt = sock_no_setsockopt,
+       .getsockopt = sock_no_getsockopt,
+       .sendmsg    = sock_no_sendmsg,
+       .recvmsg    = sock_no_recvmsg,
+       .mmap       = sock_no_mmap,
+       .ioctl      = pppox_ioctl,
+};
+
+static struct pppox_proto pppox_pptp_proto = {
+       .create = pptp_create,
+       .owner  = THIS_MODULE,
+};
+
+static struct gre_protocol gre_pptp_protocol = {
+       .handler = pptp_rcv,
+};
+
+static int __init pptp_init_module(void)
+{
+       int err = 0;
+       pr_info("PPTP driver version " PPTP_DRIVER_VERSION "\n");
+
+       callid_sock = __vmalloc((MAX_CALLID + 1) * sizeof(void *),
+               GFP_KERNEL | __GFP_ZERO, PAGE_KERNEL);
+       if (!callid_sock) {
+               pr_err("PPTP: cann't allocate memory\n");
+               return -ENOMEM;
+       }
+
+       err = gre_add_protocol(&gre_pptp_protocol, GREPROTO_PPTP);
+       if (err) {
+               pr_err("PPTP: can't add gre protocol\n");
+               goto out_mem_free;
+       }
+
+       err = proto_register(&pptp_sk_proto, 0);
+       if (err) {
+               pr_err("PPTP: can't register sk_proto\n");
+               goto out_gre_del_protocol;
+       }
+
+       err = register_pppox_proto(PX_PROTO_PPTP, &pppox_pptp_proto);
+       if (err) {
+               pr_err("PPTP: can't register pppox_proto\n");
+               goto out_unregister_sk_proto;
+       }
+
+       return 0;
+
+out_unregister_sk_proto:
+       proto_unregister(&pptp_sk_proto);
+out_gre_del_protocol:
+       gre_del_protocol(&gre_pptp_protocol, GREPROTO_PPTP);
+out_mem_free:
+       vfree(callid_sock);
+
+       return err;
+}
+
+static void __exit pptp_exit_module(void)
+{
+       unregister_pppox_proto(PX_PROTO_PPTP);
+       proto_unregister(&pptp_sk_proto);
+       gre_del_protocol(&gre_pptp_protocol, GREPROTO_PPTP);
+       vfree(callid_sock);
+}
+
+module_init(pptp_init_module);
+module_exit(pptp_exit_module);
+
+MODULE_DESCRIPTION("Point-to-Point Tunneling Protocol");
+MODULE_AUTHOR("D. Kozlov (xeb@mail.ru)");
+MODULE_LICENSE("GPL");
index 87d6b8f3630470cce8219a4738352377e9d6cac6..5526ab4895e64163c7edb950765823b67b7b2cf4 100644 (file)
@@ -956,9 +956,9 @@ static void gelic_net_pass_skb_up(struct gelic_descr *descr,
                    (!(data_error & GELIC_DESCR_DATA_ERROR_CHK_MASK)))
                        skb->ip_summed = CHECKSUM_UNNECESSARY;
                else
-                       skb->ip_summed = CHECKSUM_NONE;
+                       skb_checksum_none_assert(skb);
        } else
-               skb->ip_summed = CHECKSUM_NONE;
+               skb_checksum_none_assert(skb);
 
        /* update netdevice statistics */
        netdev->stats.rx_packets++;
index 85eddda276bdf350f17660fd2361b86e059b9001..75c2ff99d66d3f89bce42e9f128bae9e6e0d9ed8 100644 (file)
@@ -42,8 +42,6 @@
 #include <linux/types.h>
 #include <asm/pgtable.h>
 #include <asm/system.h>
-#include <linux/delay.h>
-#include <linux/dma-mapping.h>
 #include <asm/cacheflush.h>
 #include <linux/pxa168_eth.h>
 
@@ -850,7 +848,6 @@ static int rxq_process(struct net_device *dev, int budget)
                        skb->protocol = eth_type_trans(skb, dev);
                        netif_receive_skb(skb);
                }
-               dev->last_rx = jiffies;
        }
        /* Fill RX ring with skb's */
        rxq_refill(dev);
index 6168a130f33fc1a18548427a73918d572db19107..7496ed2c34aba61aa06f616774cd2b139c578342 100644 (file)
@@ -2029,7 +2029,7 @@ static void ql_process_mac_rx_intr(struct ql3_adapter *qdev,
                         dma_unmap_len(lrg_buf_cb2, maplen),
                         PCI_DMA_FROMDEVICE);
        prefetch(skb->data);
-       skb->ip_summed = CHECKSUM_NONE;
+       skb_checksum_none_assert(skb);
        skb->protocol = eth_type_trans(skb, qdev->ndev);
 
        netif_receive_skb(skb);
@@ -2076,7 +2076,7 @@ static void ql_process_macip_rx_intr(struct ql3_adapter *qdev,
                         PCI_DMA_FROMDEVICE);
        prefetch(skb2->data);
 
-       skb2->ip_summed = CHECKSUM_NONE;
+       skb_checksum_none_assert(skb2);
        if (qdev->device_id == QL3022_DEVICE_ID) {
                /*
                 * Copy the ethhdr from first buffer to second. This
index 970389331bbc4cb5c91da180fd04d282db872ac5..cc8385a6727ed5196326aa27a9d3f0637654615d 100644 (file)
 
 #define _QLCNIC_LINUX_MAJOR 5
 #define _QLCNIC_LINUX_MINOR 0
-#define _QLCNIC_LINUX_SUBVERSION 7
-#define QLCNIC_LINUX_VERSIONID  "5.0.7"
+#define _QLCNIC_LINUX_SUBVERSION 9
+#define QLCNIC_LINUX_VERSIONID  "5.0.9"
 #define QLCNIC_DRV_IDC_VER  0x01
+#define QLCNIC_DRIVER_VERSION  ((_QLCNIC_LINUX_MAJOR << 16) |\
+                (_QLCNIC_LINUX_MINOR << 8) | (_QLCNIC_LINUX_SUBVERSION))
 
 #define QLCNIC_VERSION_CODE(a, b, c)   (((a) << 24) + ((b) << 16) + (c))
 #define _major(v)      (((v) >> 24) & 0xff)
 
 #define DEFAULT_RCV_DESCRIPTORS_1G     2048
 #define DEFAULT_RCV_DESCRIPTORS_10G    4096
+#define MAX_RDS_RINGS                   2
 
 #define get_next_index(index, length)  \
        (((index) + 1) & ((length) - 1))
        ((_desc)->port_ctxid = ((_port) & 0xf) | (((_port) << 4) & 0xf0))
 
 #define qlcnic_set_tx_flags_opcode(_desc, _flags, _opcode) \
-       ((_desc)->flags_opcode = \
+       ((_desc)->flags_opcode |= \
        cpu_to_le16(((_flags) & 0x7f) | (((_opcode) & 0x3f) << 7)))
 
 #define qlcnic_set_tx_frags_len(_desc, _frags, _len) \
@@ -221,7 +224,8 @@ struct rcv_desc {
 #define QLCNIC_LRO_DESC        0x12
 
 /* for status field in status_desc */
-#define STATUS_CKSUM_OK                (2)
+#define STATUS_CKSUM_LOOP      0
+#define STATUS_CKSUM_OK                2
 
 /* owner bits of status_desc */
 #define STATUS_OWNER_HOST      (0x1ULL << 56)
@@ -555,6 +559,8 @@ struct qlcnic_recv_context {
 #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_RCODE_SUCCESS           0
 #define QLCNIC_RCODE_TIMEOUT           17
@@ -717,6 +723,8 @@ struct qlcnic_cardrsp_tx_ctx {
 #define QLCNIC_MAC_NOOP        0
 #define QLCNIC_MAC_ADD 1
 #define QLCNIC_MAC_DEL 2
+#define QLCNIC_MAC_VLAN_ADD    3
+#define QLCNIC_MAC_VLAN_DEL    4
 
 struct qlcnic_mac_list_s {
        struct list_head list;
@@ -893,9 +901,14 @@ struct qlcnic_mac_req {
 #define QLCNIC_MSI_ENABLED             0x02
 #define QLCNIC_MSIX_ENABLED            0x04
 #define QLCNIC_LRO_ENABLED             0x08
+#define QLCNIC_LRO_DISABLED            0x00
 #define QLCNIC_BRIDGE_ENABLED          0X10
 #define QLCNIC_DIAG_ENABLED            0x20
 #define QLCNIC_ESWITCH_ENABLED         0x40
+#define QLCNIC_ADAPTER_INITIALIZED     0x80
+#define QLCNIC_TAGGING_ENABLED         0x100
+#define QLCNIC_MACSPOOF                        0x200
+#define QLCNIC_MAC_OVERRIDE_DISABLED   0x400
 #define QLCNIC_IS_MSI_FAMILY(adapter) \
        ((adapter)->flags & (QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED))
 
@@ -916,6 +929,22 @@ struct qlcnic_mac_req {
 #define QLCNIC_INTERRUPT_TEST          1
 #define QLCNIC_LOOPBACK_TEST           2
 
+#define QLCNIC_FILTER_AGE      80
+#define QLCNIC_LB_MAX_FILTERS  64
+
+struct qlcnic_filter {
+       struct hlist_node fnode;
+       u8 faddr[ETH_ALEN];
+       u16 vlan_id;
+       unsigned long ftime;
+};
+
+struct qlcnic_filter_hash {
+       struct hlist_head *fhead;
+       u8 fnum;
+       u8 fmax;
+};
+
 struct qlcnic_adapter {
        struct qlcnic_hardware_context ahw;
 
@@ -924,6 +953,7 @@ struct qlcnic_adapter {
        struct list_head mac_list;
 
        spinlock_t tx_clean_lock;
+       spinlock_t mac_learn_lock;
 
        u16 num_txd;
        u16 num_rxd;
@@ -931,7 +961,6 @@ struct qlcnic_adapter {
 
        u8 max_rds_rings;
        u8 max_sds_rings;
-       u8 driver_mismatch;
        u8 msix_supported;
        u8 rx_csum;
        u8 portnum;
@@ -961,6 +990,7 @@ struct qlcnic_adapter {
        u16 max_tx_ques;
        u16 max_rx_ques;
        u16 max_mtu;
+       u16 pvid;
 
        u32 fw_hal_version;
        u32 capabilities;
@@ -969,7 +999,7 @@ struct qlcnic_adapter {
        u32 temp;
 
        u32 int_vec_bit;
-       u32 heartbit;
+       u32 heartbeat;
 
        u8 max_mac_filters;
        u8 dev_state;
@@ -1003,6 +1033,8 @@ struct qlcnic_adapter {
 
        struct qlcnic_nic_intr_coalesce coal;
 
+       struct qlcnic_filter_hash fhash;
+
        unsigned long state;
        __le32 file_prd_off;    /*File fw product offset*/
        u32 fw_version;
@@ -1042,7 +1074,7 @@ struct qlcnic_pci_info {
 };
 
 struct qlcnic_npar_info {
-       u16     vlan_id;
+       u16     pvid;
        u16     min_bw;
        u16     max_bw;
        u8      phy_port;
@@ -1050,11 +1082,13 @@ struct qlcnic_npar_info {
        u8      active;
        u8      enable_pm;
        u8      dest_npar;
-       u8      host_vlan_tag;
-       u8      promisc_mode;
        u8      discard_tagged;
-       u8      mac_learning;
+       u8      mac_override;
+       u8      mac_anti_spoof;
+       u8      promisc_mode;
+       u8      offload_flags;
 };
+
 struct qlcnic_eswitch {
        u8      port;
        u8      active_vports;
@@ -1086,7 +1120,6 @@ struct qlcnic_eswitch {
 #define IS_VALID_BW(bw)                (bw >= MIN_BW && bw <= MAX_BW)
 #define IS_VALID_TX_QUEUES(que)        (que > 0 && que <= MAX_TX_QUEUES)
 #define IS_VALID_RX_QUEUES(que)        (que > 0 && que <= MAX_RX_QUEUES)
-#define IS_VALID_MODE(mode)    (mode == 0 || mode == 1)
 
 struct qlcnic_pci_func_cfg {
        u16     func_type;
@@ -1118,12 +1151,41 @@ struct qlcnic_pm_func_cfg {
 
 struct qlcnic_esw_func_cfg {
        u16     vlan_id;
+       u8      op_mode;
+       u8      op_type;
        u8      pci_func;
        u8      host_vlan_tag;
        u8      promisc_mode;
        u8      discard_tagged;
-       u8      mac_learning;
-       u8      reserved;
+       u8      mac_override;
+       u8      mac_anti_spoof;
+       u8      offload_flags;
+       u8      reserved[5];
+};
+
+#define QLCNIC_STATS_VERSION           1
+#define QLCNIC_STATS_PORT              1
+#define QLCNIC_STATS_ESWITCH           2
+#define QLCNIC_QUERY_RX_COUNTER                0
+#define QLCNIC_QUERY_TX_COUNTER                1
+struct __qlcnic_esw_statistics {
+       __le16 context_id;
+       __le16 version;
+       __le16 size;
+       __le16 unused;
+       __le64 unicast_frames;
+       __le64 multicast_frames;
+       __le64 broadcast_frames;
+       __le64 dropped_frames;
+       __le64 errors;
+       __le64 local_frames;
+       __le64 numbytes;
+       __le64 rsvd[3];
+};
+
+struct qlcnic_esw_statistics {
+       struct __qlcnic_esw_statistics rx;
+       struct __qlcnic_esw_statistics tx;
 };
 
 int qlcnic_fw_cmd_query_phy(struct qlcnic_adapter *adapter, u32 reg, u32 *val);
@@ -1171,6 +1233,8 @@ void qlcnic_pcie_sem_unlock(struct qlcnic_adapter *, int);
 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);
 
 /* Functions from qlcnic_init.c */
 int qlcnic_load_firmware(struct qlcnic_adapter *adapter);
@@ -1199,7 +1263,7 @@ void qlcnic_reset_rx_buffers_list(struct qlcnic_adapter *adapter);
 void qlcnic_release_rx_buffers(struct qlcnic_adapter *adapter);
 void qlcnic_release_tx_buffers(struct qlcnic_adapter *adapter);
 
-int qlcnic_init_firmware(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, u32 ringid,
                struct qlcnic_host_rds_ring *rds_ring);
@@ -1220,7 +1284,6 @@ 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_adapter *adapter,
                struct qlcnic_host_tx_ring *tx_ring);
-int qlcnic_get_mac_addr(struct qlcnic_adapter *adapter, u8 *mac);
 void qlcnic_clear_ilb_mode(struct qlcnic_adapter *adapter);
 int qlcnic_set_ilb_mode(struct qlcnic_adapter *adapter);
 void qlcnic_fetch_mac(struct qlcnic_adapter *, u32, u32, u8, u8 *);
@@ -1249,9 +1312,16 @@ int qlcnic_get_eswitch_capabilities(struct qlcnic_adapter *, u8,
 int qlcnic_get_eswitch_status(struct qlcnic_adapter *, u8,
                                struct qlcnic_eswitch *);
 int qlcnic_toggle_eswitch(struct qlcnic_adapter *, u8, u8);
-int qlcnic_config_switch_port(struct qlcnic_adapter *, u8, int, u8, u8,
-                       u8, u8, u16);
+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);
+int qlcnic_get_port_stats(struct qlcnic_adapter *, const u8, const u8,
+                                       struct __qlcnic_esw_statistics *);
+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);
 extern int qlcnic_config_tso;
 
 /*
@@ -1280,6 +1350,8 @@ static const struct qlcnic_brdinfo qlcnic_boards[] = {
                "3200 Series Quad Port 1Gb Intelligent Ethernet Adapter"},
        {0x1077, 0x8020, 0x1077, 0x20f,
                "3200 Series Single Port 10Gb Intelligent Ethernet Adapter"},
+       {0x1077, 0x8020, 0x103c, 0x3733,
+               "NC523SFP 10Gb 2-port Flex-10 Server Adapter"},
        {0x1077, 0x8020, 0x0, 0x0, "cLOM8214 1/10GbE Controller"},
 };
 
@@ -1298,7 +1370,6 @@ static inline u32 qlcnic_tx_avail(struct qlcnic_host_tx_ring *tx_ring)
 extern const struct ethtool_ops qlcnic_ethtool_ops;
 
 struct qlcnic_nic_template {
-       int (*get_mac_addr) (struct qlcnic_adapter *, u8*);
        int (*config_bridged_mode) (struct qlcnic_adapter *, u32);
        int (*config_led) (struct qlcnic_adapter *, u32, u32);
        int (*start_firmware) (struct qlcnic_adapter *);
index cc5d861d9a128bfc932da00a6bb0917a7ac26931..95a821e0b66ff82cbb7332f2204c6f161247467b 100644 (file)
@@ -813,9 +813,8 @@ int qlcnic_get_eswitch_capabilities(struct qlcnic_adapter *adapter, u8 port,
                arg2 = QLCRD32(adapter, QLCNIC_ARG2_CRB_OFFSET);
 
                eswitch->port = arg1 & 0xf;
-               eswitch->active_vports = LSB(arg2);
-               eswitch->max_ucast_filters = MSB(arg2);
-               eswitch->max_active_vlans = LSB(MSW(arg2));
+               eswitch->max_ucast_filters = LSW(arg2);
+               eswitch->max_active_vlans = MSW(arg2) & 0xfff;
                if (arg1 & BIT_6)
                        eswitch->flags |= QLCNIC_SWITCH_VLAN_FILTERING;
                if (arg1 & BIT_7)
@@ -943,43 +942,271 @@ int qlcnic_config_port_mirroring(struct qlcnic_adapter *adapter, u8 id,
        return err;
 }
 
-/* Configure eSwitch port */
-int qlcnic_config_switch_port(struct qlcnic_adapter *adapter, u8 id,
-               int vlan_tagging, u8 discard_tagged, u8 promsc_mode,
-               u8 mac_learn, u8 pci_func, u16 vlan_id)
+int qlcnic_get_port_stats(struct qlcnic_adapter *adapter, const u8 func,
+               const u8 rx_tx, struct __qlcnic_esw_statistics *esw_stats) {
+
+       size_t stats_size = sizeof(struct __qlcnic_esw_statistics);
+       struct __qlcnic_esw_statistics *stats;
+       dma_addr_t stats_dma_t;
+       void *stats_addr;
+       u32 arg1;
+       int err;
+
+       if (esw_stats == NULL)
+               return -ENOMEM;
+
+       if (adapter->op_mode != QLCNIC_MGMT_FUNC &&
+           func != adapter->ahw.pci_func) {
+               dev_err(&adapter->pdev->dev,
+                       "Not privilege to query stats for func=%d", func);
+               return -EIO;
+       }
+
+       stats_addr = pci_alloc_consistent(adapter->pdev, stats_size,
+                       &stats_dma_t);
+       if (!stats_addr) {
+               dev_err(&adapter->pdev->dev, "Unable to allocate memory\n");
+               return -ENOMEM;
+       }
+       memset(stats_addr, 0, stats_size);
+
+       arg1 = func | QLCNIC_STATS_VERSION << 8 | QLCNIC_STATS_PORT << 12;
+       arg1 |= rx_tx << 15 | stats_size << 16;
+
+       err = qlcnic_issue_cmd(adapter,
+                       adapter->ahw.pci_func,
+                       adapter->fw_hal_version,
+                       arg1,
+                       MSD(stats_dma_t),
+                       LSD(stats_dma_t),
+                       QLCNIC_CDRP_CMD_GET_ESWITCH_STATS);
+
+       if (!err) {
+               stats = (struct __qlcnic_esw_statistics *)stats_addr;
+               esw_stats->context_id = le16_to_cpu(stats->context_id);
+               esw_stats->version = le16_to_cpu(stats->version);
+               esw_stats->size = le16_to_cpu(stats->size);
+               esw_stats->multicast_frames =
+                               le64_to_cpu(stats->multicast_frames);
+               esw_stats->broadcast_frames =
+                               le64_to_cpu(stats->broadcast_frames);
+               esw_stats->unicast_frames = le64_to_cpu(stats->unicast_frames);
+               esw_stats->dropped_frames = le64_to_cpu(stats->dropped_frames);
+               esw_stats->local_frames = le64_to_cpu(stats->local_frames);
+               esw_stats->errors = le64_to_cpu(stats->errors);
+               esw_stats->numbytes = le64_to_cpu(stats->numbytes);
+       }
+
+       pci_free_consistent(adapter->pdev, stats_size, stats_addr,
+               stats_dma_t);
+       return err;
+}
+
+int qlcnic_get_eswitch_stats(struct qlcnic_adapter *adapter, const u8 eswitch,
+               const u8 rx_tx, struct __qlcnic_esw_statistics *esw_stats) {
+
+       struct __qlcnic_esw_statistics port_stats;
+       u8 i;
+       int ret = -EIO;
+
+       if (esw_stats == NULL)
+               return -ENOMEM;
+       if (adapter->op_mode != QLCNIC_MGMT_FUNC)
+               return -EIO;
+       if (adapter->npars == NULL)
+               return -EIO;
+
+       memset(esw_stats, 0, sizeof(struct __qlcnic_esw_statistics));
+       esw_stats->context_id = eswitch;
+
+       for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
+               if (adapter->npars[i].phy_port != eswitch)
+                       continue;
+
+               memset(&port_stats, 0, sizeof(struct __qlcnic_esw_statistics));
+               if (qlcnic_get_port_stats(adapter, i, rx_tx, &port_stats))
+                       continue;
+
+               esw_stats->size = port_stats.size;
+               esw_stats->version = port_stats.version;
+               esw_stats->unicast_frames += port_stats.unicast_frames;
+               esw_stats->multicast_frames += port_stats.multicast_frames;
+               esw_stats->broadcast_frames += port_stats.broadcast_frames;
+               esw_stats->dropped_frames += port_stats.dropped_frames;
+               esw_stats->errors += port_stats.errors;
+               esw_stats->local_frames += port_stats.local_frames;
+               esw_stats->numbytes += port_stats.numbytes;
+
+               ret = 0;
+       }
+       return ret;
+}
+
+int qlcnic_clear_esw_stats(struct qlcnic_adapter *adapter, const u8 func_esw,
+               const u8 port, const u8 rx_tx)
 {
-       int err = -EIO;
+
        u32 arg1;
-       struct qlcnic_eswitch *eswitch;
 
        if (adapter->op_mode != QLCNIC_MGMT_FUNC)
-               return err;
+               return -EIO;
 
-       eswitch = &adapter->eswitch[id];
-       if (!(eswitch->flags & QLCNIC_SWITCH_ENABLE))
+       if (func_esw == QLCNIC_STATS_PORT) {
+               if (port >= QLCNIC_MAX_PCI_FUNC)
+                       goto err_ret;
+       } else if (func_esw == QLCNIC_STATS_ESWITCH) {
+               if (port >= QLCNIC_NIU_MAX_XG_PORTS)
+                       goto err_ret;
+       } else {
+               goto err_ret;
+       }
+
+       if (rx_tx > QLCNIC_QUERY_TX_COUNTER)
+               goto err_ret;
+
+       arg1 = port | QLCNIC_STATS_VERSION << 8 | func_esw << 12;
+       arg1 |= BIT_14 | rx_tx << 15;
+
+       return qlcnic_issue_cmd(adapter,
+                       adapter->ahw.pci_func,
+                       adapter->fw_hal_version,
+                       arg1,
+                       0,
+                       0,
+                       QLCNIC_CDRP_CMD_GET_ESWITCH_STATS);
+
+err_ret:
+       dev_err(&adapter->pdev->dev, "Invalid argument func_esw=%d port=%d"
+               "rx_ctx=%d\n", func_esw, port, rx_tx);
+       return -EIO;
+}
+
+static int
+__qlcnic_get_eswitch_port_config(struct qlcnic_adapter *adapter,
+                                       u32 *arg1, u32 *arg2)
+{
+       int err = -EIO;
+       u8 pci_func;
+       pci_func = (*arg1 >> 8);
+       err = qlcnic_issue_cmd(adapter,
+                       adapter->ahw.pci_func,
+                       adapter->fw_hal_version,
+                       *arg1,
+                       0,
+                       0,
+                       QLCNIC_CDRP_CMD_GET_ESWITCH_PORT_CONFIG);
+
+       if (err == QLCNIC_RCODE_SUCCESS) {
+               *arg1 = QLCRD32(adapter, QLCNIC_ARG1_CRB_OFFSET);
+               *arg2 = QLCRD32(adapter, QLCNIC_ARG2_CRB_OFFSET);
+               dev_info(&adapter->pdev->dev,
+                       "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
+op_mode = 0 for setting default port behavior
+op_mode = 1 for setting  vlan id
+op_mode = 2 for deleting vlan id
+op_type = 0 for vlan_id
+op_type = 1 for port vlan_id
+*/
+int qlcnic_config_switch_port(struct qlcnic_adapter *adapter,
+               struct qlcnic_esw_func_cfg *esw_cfg)
+{
+       int err = -EIO;
+       u32 arg1, arg2 = 0;
+       u8 pci_func;
+
+       if (adapter->op_mode != QLCNIC_MGMT_FUNC)
                return err;
+       pci_func = esw_cfg->pci_func;
+       arg1 = (adapter->npars[pci_func].phy_port & BIT_0);
+       arg1 |= (pci_func << 8);
 
-       arg1 = eswitch->port | (discard_tagged ? BIT_4 : 0);
-       arg1 |= (promsc_mode ? BIT_6 : 0) | (mac_learn ? BIT_7 : 0);
-       arg1 |= pci_func << 8;
-       if (vlan_tagging)
-               arg1 |= BIT_5 | (vlan_id << 16);
+       if (__qlcnic_get_eswitch_port_config(adapter, &arg1, &arg2))
+               return err;
+       arg1 &= ~(0x0ff << 8);
+       arg1 |= (pci_func << 8);
+       arg1 &= ~(BIT_2 | BIT_3);
+       switch (esw_cfg->op_mode) {
+       case QLCNIC_PORT_DEFAULTS:
+               arg1 |= (BIT_4 | BIT_6 | BIT_7);
+               arg2 |= (BIT_0 | BIT_1);
+               if (adapter->capabilities & QLCNIC_FW_CAPABILITY_TSO)
+                       arg2 |= (BIT_2 | BIT_3);
+               if (!(esw_cfg->discard_tagged))
+                       arg1 &= ~BIT_4;
+               if (!(esw_cfg->promisc_mode))
+                       arg1 &= ~BIT_6;
+               if (!(esw_cfg->mac_override))
+                       arg1 &= ~BIT_7;
+               if (!(esw_cfg->mac_anti_spoof))
+                       arg2 &= ~BIT_0;
+               if (!(esw_cfg->offload_flags & BIT_0))
+                       arg2 &= ~(BIT_1 | BIT_2 | BIT_3);
+               if (!(esw_cfg->offload_flags & BIT_1))
+                       arg2 &= ~BIT_2;
+               if (!(esw_cfg->offload_flags & BIT_2))
+                       arg2 &= ~BIT_3;
+               break;
+       case QLCNIC_ADD_VLAN:
+                       arg1 |= (BIT_2 | BIT_5);
+                       arg1 |= (esw_cfg->vlan_id << 16);
+                       break;
+       case QLCNIC_DEL_VLAN:
+                       arg1 |= (BIT_3 | BIT_5);
+                       arg1 &= ~(0x0ffff << 16);
+                       break;
+       default:
+               return err;
+       }
 
        err = qlcnic_issue_cmd(adapter,
                        adapter->ahw.pci_func,
                        adapter->fw_hal_version,
                        arg1,
-                       0,
+                       arg2,
                        0,
                        QLCNIC_CDRP_CMD_CONFIGURE_ESWITCH);
 
        if (err != QLCNIC_RCODE_SUCCESS) {
                dev_err(&adapter->pdev->dev,
-                       "Failed to configure eswitch port%d\n", eswitch->port);
+                       "Failed to configure eswitch pci func %d\n", pci_func);
        } else {
                dev_info(&adapter->pdev->dev,
-                       "Configured eSwitch for port %d\n", eswitch->port);
+                       "Configured eSwitch for pci func %d\n", pci_func);
        }
 
        return err;
 }
+
+int
+qlcnic_get_eswitch_port_config(struct qlcnic_adapter *adapter,
+                       struct qlcnic_esw_func_cfg *esw_cfg)
+{
+       u32 arg1, arg2;
+       u8 phy_port;
+       if (adapter->op_mode == QLCNIC_MGMT_FUNC)
+               phy_port = adapter->npars[esw_cfg->pci_func].phy_port;
+       else
+               phy_port = adapter->physical_port;
+       arg1 = phy_port;
+       arg1 |= (esw_cfg->pci_func << 8);
+       if (__qlcnic_get_eswitch_port_config(adapter, &arg1, &arg2))
+               return -EIO;
+
+       esw_cfg->discard_tagged = !!(arg1 & BIT_4);
+       esw_cfg->host_vlan_tag = !!(arg1 & BIT_5);
+       esw_cfg->promisc_mode = !!(arg1 & BIT_6);
+       esw_cfg->mac_override = !!(arg1 & BIT_7);
+       esw_cfg->vlan_id = LSW(arg1 >> 16);
+       esw_cfg->mac_anti_spoof = (arg2 & 0x1);
+       esw_cfg->offload_flags = ((arg2 >> 1) & 0x7);
+
+       return 0;
+}
index 9328d59e21e0c6c2ff8011b19eb30f5f041fed5d..cb9463bd6b1e60ce2fa5fbe5dd1407531fdcd6f9 100644 (file)
@@ -99,7 +99,7 @@ static const u32 diag_registers[] = {
        CRB_XG_STATE_P3,
        CRB_FW_CAPABILITIES_1,
        ISR_INT_STATE_REG,
-       QLCNIC_CRB_DEV_REF_COUNT,
+       QLCNIC_CRB_DRV_ACTIVE,
        QLCNIC_CRB_DEV_STATE,
        QLCNIC_CRB_DRV_STATE,
        QLCNIC_CRB_DRV_SCRATCH,
@@ -115,9 +115,13 @@ static const u32 diag_registers[] = {
        -1
 };
 
+#define QLCNIC_MGMT_API_VERSION        2
+#define QLCNIC_DEV_INFO_SIZE   1
+#define QLCNIC_ETHTOOL_REGS_VER        2
 static int qlcnic_get_regs_len(struct net_device *dev)
 {
-       return sizeof(diag_registers) + QLCNIC_RING_REGS_LEN;
+       return sizeof(diag_registers) + QLCNIC_RING_REGS_LEN +
+                               QLCNIC_DEV_INFO_SIZE + 1;
 }
 
 static int qlcnic_get_eeprom_len(struct net_device *dev)
@@ -342,10 +346,13 @@ qlcnic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p)
        int ring, i = 0;
 
        memset(p, 0, qlcnic_get_regs_len(dev));
-       regs->version = (1 << 24) | (adapter->ahw.revision_id << 16) |
-           (adapter->pdev)->device;
+       regs->version = (QLCNIC_ETHTOOL_REGS_VER << 24) |
+               (adapter->ahw.revision_id << 16) | (adapter->pdev)->device;
 
-       for (i = 0; diag_registers[i] != -1; i++)
+       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[i] != -1; i++)
                regs_buff[i] = QLCRD32(adapter, diag_registers[i]);
 
        if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
@@ -747,6 +754,14 @@ qlcnic_diag_test(struct net_device *dev, struct ethtool_test *eth_test,
 {
        memset(data, 0, sizeof(u64) * QLCNIC_TEST_LEN);
 
+       data[0] = qlcnic_reg_test(dev);
+       if (data[0])
+               eth_test->flags |= ETH_TEST_FL_FAILED;
+
+       data[1] = (u64) qlcnic_test_link(dev);
+       if (data[1])
+               eth_test->flags |= ETH_TEST_FL_FAILED;
+
        if (eth_test->flags == ETH_TEST_FL_OFFLINE) {
                data[2] = qlcnic_irq_test(dev);
                if (data[2])
@@ -757,15 +772,6 @@ qlcnic_diag_test(struct net_device *dev, struct ethtool_test *eth_test,
                        eth_test->flags |= ETH_TEST_FL_FAILED;
 
        }
-
-       data[0] = qlcnic_reg_test(dev);
-       if (data[0])
-               eth_test->flags |= ETH_TEST_FL_FAILED;
-
-       /* link test */
-       data[1] = (u64) qlcnic_test_link(dev);
-       if (data[1])
-               eth_test->flags |= ETH_TEST_FL_FAILED;
 }
 
 static void
@@ -805,6 +811,20 @@ qlcnic_get_ethtool_stats(struct net_device *dev,
        }
 }
 
+static int qlcnic_set_tx_csum(struct net_device *dev, u32 data)
+{
+       struct qlcnic_adapter *adapter = netdev_priv(dev);
+
+       if ((adapter->flags & QLCNIC_ESWITCH_ENABLED))
+               return -EOPNOTSUPP;
+       if (data)
+               dev->features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
+       else
+               dev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
+
+       return 0;
+
+}
 static u32 qlcnic_get_tx_csum(struct net_device *dev)
 {
        return dev->features & NETIF_F_IP_CSUM;
@@ -819,7 +839,23 @@ static u32 qlcnic_get_rx_csum(struct net_device *dev)
 static int qlcnic_set_rx_csum(struct net_device *dev, u32 data)
 {
        struct qlcnic_adapter *adapter = netdev_priv(dev);
+
+       if ((adapter->flags & QLCNIC_ESWITCH_ENABLED))
+               return -EOPNOTSUPP;
+       if (!!data) {
+               adapter->rx_csum = !!data;
+               return 0;
+       }
+
+       if (adapter->flags & QLCNIC_LRO_ENABLED) {
+               if (qlcnic_config_hw_lro(adapter, QLCNIC_LRO_DISABLED))
+                       return -EIO;
+
+               dev->features &= ~NETIF_F_LRO;
+               qlcnic_send_lro_cleanup(adapter);
+       }
        adapter->rx_csum = !!data;
+       dev_info(&adapter->pdev->dev, "disabling LRO as rx_csum is off\n");
        return 0;
 }
 
@@ -1002,6 +1038,15 @@ static int qlcnic_set_flags(struct net_device *netdev, u32 data)
        if (!(adapter->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO))
                return -EINVAL;
 
+       if (!adapter->rx_csum) {
+               dev_info(&adapter->pdev->dev, "rx csum is off, "
+                       "cannot toggle lro\n");
+               return -EINVAL;
+       }
+
+       if ((data & ETH_FLAG_LRO) && (adapter->flags & QLCNIC_LRO_ENABLED))
+               return 0;
+
        if (data & ETH_FLAG_LRO) {
                hw_lro = QLCNIC_LRO_ENABLED;
                netdev->features |= NETIF_F_LRO;
@@ -1048,7 +1093,7 @@ const struct ethtool_ops qlcnic_ethtool_ops = {
        .get_pauseparam = qlcnic_get_pauseparam,
        .set_pauseparam = qlcnic_set_pauseparam,
        .get_tx_csum = qlcnic_get_tx_csum,
-       .set_tx_csum = ethtool_op_set_tx_csum,
+       .set_tx_csum = qlcnic_set_tx_csum,
        .set_sg = ethtool_op_set_sg,
        .get_tso = qlcnic_get_tso,
        .set_tso = qlcnic_set_tso,
index 15fc32070be3dfd689c7acece6658e866b22f59b..716203e41dc7a8ee49bf3e5a319eb64b7430bcf6 100644 (file)
@@ -698,7 +698,7 @@ enum {
 #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_DEV_REF_COUNT       (QLCNIC_CAM_RAM(0x138))
+#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))
@@ -718,8 +718,9 @@ enum {
 #define QLCNIC_DEV_FAILED              0x6
 #define QLCNIC_DEV_QUISCENT            0x7
 
-#define QLCNIC_DEV_NPAR_NOT_RDY        0
-#define QLCNIC_DEV_NPAR_RDY            1
+#define QLCNIC_DEV_NPAR_NON_OPER       0 /* NON Operational */
+#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)))
@@ -744,6 +745,15 @@ enum {
 #define FW_POLL_DELAY          (1 * HZ)
 #define FW_FAIL_THRESH         2
 
+#define QLCNIC_RESET_TIMEOUT_SECS      10
+#define QLCNIC_INIT_TIMEOUT_SECS       30
+#define QLCNIC_RCVPEG_CHECK_RETRY_COUNT        2000
+#define QLCNIC_RCVPEG_CHECK_DELAY      10
+#define QLCNIC_CMDPEG_CHECK_RETRY_COUNT        60
+#define QLCNIC_CMDPEG_CHECK_DELAY      500
+#define QLCNIC_HEARTBEAT_PERIOD_MSECS  200
+#define QLCNIC_HEARTBEAT_CHECK_RETRY_COUNT     45
+
 #define        ISR_MSI_INT_TRIGGER(FUNC) (QLCNIC_PCIX_PS_REG(PCIX_MSI_F(FUNC)))
 #define ISR_LEGACY_INT_TRIGGERED(VAL)  (((VAL) & 0x300) == 0x200)
 
@@ -770,6 +780,7 @@ struct qlcnic_legacy_intr_set {
 #define QLCNIC_DRV_OP_MODE     0x1b2170
 #define QLCNIC_MSIX_BASE       0x132110
 #define QLCNIC_MAX_PCI_FUNC    8
+#define QLCNIC_MAX_VLAN_FILTERS        64
 
 /* PCI function operational mode */
 enum {
@@ -778,6 +789,12 @@ enum {
        QLCNIC_NON_PRIV_FUNC    = 2
 };
 
+enum {
+       QLCNIC_PORT_DEFAULTS    = 0,
+       QLCNIC_ADD_VLAN = 1,
+       QLCNIC_DEL_VLAN = 2
+};
+
 #define QLC_DEV_DRV_DEFAULT 0x11111111
 
 #define LSB(x) ((uint8_t)(x))
index e08c8b0556a47bf2692d272d7d6a1cd029b69608..c198df90ff3ce91b90728543d5e6d7fc5d74b506 100644 (file)
@@ -297,8 +297,8 @@ qlcnic_pcie_sem_lock(struct qlcnic_adapter *adapter, int sem, u32 id_reg)
                        break;
                if (++timeout >= QLCNIC_PCIE_SEM_TIMEOUT) {
                        dev_err(&adapter->pdev->dev,
-                               "Failed to acquire sem=%d lock;reg_id=%d\n",
-                               sem, id_reg);
+                               "Failed to acquire sem=%d lock; holdby=%d\n",
+                               sem, id_reg ? QLCRD32(adapter, id_reg) : -1);
                        return -EIO;
                }
                msleep(1);
@@ -375,7 +375,7 @@ qlcnic_send_cmd_descs(struct qlcnic_adapter *adapter,
 
 static int
 qlcnic_sre_macaddr_change(struct qlcnic_adapter *adapter, u8 *addr,
-                               unsigned op)
+                               u16 vlan_id, unsigned op)
 {
        struct qlcnic_nic_req req;
        struct qlcnic_mac_req *mac_req;
@@ -391,6 +391,8 @@ qlcnic_sre_macaddr_change(struct qlcnic_adapter *adapter, u8 *addr,
        mac_req->op = op;
        memcpy(mac_req->mac_addr, addr, 6);
 
+       req.words[1] = cpu_to_le64(vlan_id);
+
        return qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
 }
 
@@ -415,7 +417,7 @@ static int qlcnic_nic_add_mac(struct qlcnic_adapter *adapter, u8 *addr)
        memcpy(cur->mac_addr, addr, ETH_ALEN);
 
        if (qlcnic_sre_macaddr_change(adapter,
-                               cur->mac_addr, QLCNIC_MAC_ADD)) {
+                               cur->mac_addr, 0, QLCNIC_MAC_ADD)) {
                kfree(cur);
                return -EIO;
        }
@@ -485,12 +487,63 @@ void qlcnic_free_mac_list(struct qlcnic_adapter *adapter)
        while (!list_empty(head)) {
                cur = list_entry(head->next, struct qlcnic_mac_list_s, list);
                qlcnic_sre_macaddr_change(adapter,
-                               cur->mac_addr, QLCNIC_MAC_DEL);
+                               cur->mac_addr, 0, QLCNIC_MAC_DEL);
                list_del(&cur->list);
                kfree(cur);
        }
 }
 
+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;
+
+       for (i = 0; i < adapter->fhash.fmax; 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)) {
+                               qlcnic_sre_macaddr_change(adapter,
+                                       tmp_fil->faddr, tmp_fil->vlan_id,
+                                       tmp_fil->vlan_id ? QLCNIC_MAC_VLAN_DEL :
+                                       QLCNIC_MAC_DEL);
+                               spin_lock_bh(&adapter->mac_learn_lock);
+                               adapter->fhash.fnum--;
+                               hlist_del(&tmp_fil->fnode);
+                               spin_unlock_bh(&adapter->mac_learn_lock);
+                               kfree(tmp_fil);
+                       }
+               }
+       }
+}
+
+void qlcnic_delete_lb_filters(struct qlcnic_adapter *adapter)
+{
+       struct qlcnic_filter *tmp_fil;
+       struct hlist_node *tmp_hnode, *n;
+       struct hlist_head *head;
+       int i;
+
+       for (i = 0; i < adapter->fhash.fmax; 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);
+                       spin_lock_bh(&adapter->mac_learn_lock);
+                       adapter->fhash.fnum--;
+                       hlist_del(&tmp_fil->fnode);
+                       spin_unlock_bh(&adapter->mac_learn_lock);
+                       kfree(tmp_fil);
+               }
+       }
+}
+
 #define        QLCNIC_CONFIG_INTR_COALESCE     3
 
 /*
@@ -715,19 +768,6 @@ int qlcnic_change_mtu(struct net_device *netdev, int mtu)
        return rc;
 }
 
-int qlcnic_get_mac_addr(struct qlcnic_adapter *adapter, u8 *mac)
-{
-       u32 crbaddr;
-       int pci_func = adapter->ahw.pci_func;
-
-       crbaddr = CRB_MAC_BLOCK_START +
-               (4 * ((pci_func/2) * 3)) + (4 * (pci_func & 1));
-
-       qlcnic_fetch_mac(adapter, crbaddr, crbaddr+4, pci_func & 1, mac);
-
-       return 0;
-}
-
 /*
  * Changes the CRB window to the specified window.
  */
@@ -1245,4 +1285,5 @@ void qlcnic_clear_ilb_mode(struct qlcnic_adapter *adapter)
                mode = VPORT_MISS_MODE_ACCEPT_MULTI;
 
        qlcnic_nic_set_promisc(adapter, mode);
+       msleep(1000);
 }
index 75ba744b173c89d0f598d1d61183fd5d9dca1675..26a7d6bca5c73958eb88c9b56417e56bac5be79e 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/netdevice.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
+#include <linux/if_vlan.h>
 #include "qlcnic.h"
 
 struct crb_addr_pair {
@@ -45,6 +46,9 @@ static void
 qlcnic_post_rx_buffers_nodb(struct qlcnic_adapter *adapter,
                struct qlcnic_host_rds_ring *rds_ring);
 
+static int
+qlcnic_check_fw_hearbeat(struct qlcnic_adapter *adapter);
+
 static void crb_addr_transform_setup(void)
 {
        crb_addr_transform(XDMA);
@@ -136,8 +140,6 @@ void qlcnic_reset_rx_buffers_list(struct qlcnic_adapter *adapter)
        for (ring = 0; ring < adapter->max_rds_rings; ring++) {
                rds_ring = &recv_ctx->rds_rings[ring];
 
-               spin_lock(&rds_ring->lock);
-
                INIT_LIST_HEAD(&rds_ring->free_list);
 
                rx_buf = rds_ring->rx_buf_arr;
@@ -146,8 +148,6 @@ void qlcnic_reset_rx_buffers_list(struct qlcnic_adapter *adapter)
                                        &rds_ring->free_list);
                        rx_buf++;
                }
-
-               spin_unlock(&rds_ring->lock);
        }
 }
 
@@ -439,11 +439,14 @@ int qlcnic_pinit_from_rom(struct qlcnic_adapter *adapter)
        u32 off;
        struct pci_dev *pdev = adapter->pdev;
 
-       /* resetall */
+       QLCWR32(adapter, CRB_CMDPEG_STATE, 0);
+       QLCWR32(adapter, CRB_RCVPEG_STATE, 0);
+
        qlcnic_rom_lock(adapter);
        QLCWR32(adapter, QLCNIC_ROMUSB_GLB_SW_RESET, 0xfeffffff);
        qlcnic_rom_unlock(adapter);
 
+       /* Init HW CRB block */
        if (qlcnic_rom_fast_read(adapter, 0, &n) != 0 || (n != 0xcafecafe) ||
                        qlcnic_rom_fast_read(adapter, 4, &n) != 0) {
                dev_err(&pdev->dev, "ERROR Reading crb_init area: val:%x\n", n);
@@ -524,13 +527,10 @@ int qlcnic_pinit_from_rom(struct qlcnic_adapter *adapter)
        }
        kfree(buf);
 
-       /* p2dn replyCount */
+       /* Initialize protocol process engine */
        QLCWR32(adapter, QLCNIC_CRB_PEG_NET_D + 0xec, 0x1e);
-       /* disable_peg_cache 0 & 1*/
        QLCWR32(adapter, QLCNIC_CRB_PEG_NET_D + 0x4c, 8);
        QLCWR32(adapter, QLCNIC_CRB_PEG_NET_I + 0x4c, 8);
-
-       /* peg_clr_all */
        QLCWR32(adapter, QLCNIC_CRB_PEG_NET_0 + 0x8, 0);
        QLCWR32(adapter, QLCNIC_CRB_PEG_NET_0 + 0xc, 0);
        QLCWR32(adapter, QLCNIC_CRB_PEG_NET_1 + 0x8, 0);
@@ -539,9 +539,87 @@ int qlcnic_pinit_from_rom(struct qlcnic_adapter *adapter)
        QLCWR32(adapter, QLCNIC_CRB_PEG_NET_2 + 0xc, 0);
        QLCWR32(adapter, QLCNIC_CRB_PEG_NET_3 + 0x8, 0);
        QLCWR32(adapter, QLCNIC_CRB_PEG_NET_3 + 0xc, 0);
+       QLCWR32(adapter, QLCNIC_CRB_PEG_NET_4 + 0x8, 0);
+       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);
+       return 0;
+}
+
+static int qlcnic_cmd_peg_ready(struct qlcnic_adapter *adapter)
+{
+       u32 val;
+       int retries = QLCNIC_CMDPEG_CHECK_RETRY_COUNT;
+
+       do {
+               val = QLCRD32(adapter, CRB_CMDPEG_STATE);
+
+               switch (val) {
+               case PHAN_INITIALIZE_COMPLETE:
+               case PHAN_INITIALIZE_ACK:
+                       return 0;
+               case PHAN_INITIALIZE_FAILED:
+                       goto out_err;
+               default:
+                       break;
+               }
+
+               msleep(QLCNIC_CMDPEG_CHECK_DELAY);
+
+       } while (--retries);
+
+       QLCWR32(adapter, CRB_CMDPEG_STATE, PHAN_INITIALIZE_FAILED);
+
+out_err:
+       dev_err(&adapter->pdev->dev, "Command Peg initialization not "
+                     "complete, state: 0x%x.\n", val);
+       return -EIO;
+}
+
+static int
+qlcnic_receive_peg_ready(struct qlcnic_adapter *adapter)
+{
+       u32 val;
+       int retries = QLCNIC_RCVPEG_CHECK_RETRY_COUNT;
+
+       do {
+               val = QLCRD32(adapter, CRB_RCVPEG_STATE);
+
+               if (val == PHAN_PEG_RCV_INITIALIZED)
+                       return 0;
+
+               msleep(QLCNIC_RCVPEG_CHECK_DELAY);
+
+       } while (--retries);
+
+       if (!retries) {
+               dev_err(&adapter->pdev->dev, "Receive Peg initialization not "
+                             "complete, state: 0x%x.\n", val);
+               return -EIO;
+       }
+
        return 0;
 }
 
+int
+qlcnic_check_fw_status(struct qlcnic_adapter *adapter)
+{
+       int err;
+
+       err = qlcnic_cmd_peg_ready(adapter);
+       if (err)
+               return err;
+
+       err = qlcnic_receive_peg_ready(adapter);
+       if (err)
+               return err;
+
+       QLCWR32(adapter, CRB_CMDPEG_STATE, PHAN_INITIALIZE_ACK);
+
+       return err;
+}
+
 int
 qlcnic_setup_idc_param(struct qlcnic_adapter *adapter) {
 
@@ -557,12 +635,12 @@ qlcnic_setup_idc_param(struct qlcnic_adapter *adapter) {
        }
        adapter->physical_port = (val >> 2);
        if (qlcnic_rom_fast_read(adapter, QLCNIC_ROM_DEV_INIT_TIMEOUT, &timeo))
-               timeo = 30;
+               timeo = QLCNIC_INIT_TIMEOUT_SECS;
 
        adapter->dev_init_timeo = timeo;
 
        if (qlcnic_rom_fast_read(adapter, QLCNIC_ROM_DRV_RESET_TIMEOUT, &timeo))
-               timeo = 10;
+               timeo = QLCNIC_RESET_TIMEOUT_SECS;
 
        adapter->reset_ack_timeo = timeo;
 
@@ -906,38 +984,45 @@ qlcnic_get_bios_version(struct qlcnic_adapter *adapter)
        return (bios_ver << 16) + ((bios_ver >> 8) & 0xff00) + (bios_ver >> 24);
 }
 
-int
-qlcnic_need_fw_reset(struct qlcnic_adapter *adapter)
+static void qlcnic_rom_lock_recovery(struct qlcnic_adapter *adapter)
 {
-       u32 count, old_count;
-       u32 val, version, major, minor, build;
-       int i, timeout;
-
-       if (adapter->need_fw_reset)
-               return 1;
+       if (qlcnic_pcie_sem_lock(adapter, 2, QLCNIC_ROM_LOCK_ID))
+               dev_info(&adapter->pdev->dev, "Resetting rom_lock\n");
 
-       /* last attempt had failed */
-       if (QLCRD32(adapter, CRB_CMDPEG_STATE) == PHAN_INITIALIZE_FAILED)
-               return 1;
+       qlcnic_pcie_sem_unlock(adapter, 2);
+}
 
-       old_count = QLCRD32(adapter, QLCNIC_PEG_ALIVE_COUNTER);
+static int
+qlcnic_check_fw_hearbeat(struct qlcnic_adapter *adapter)
+{
+       u32 heartbeat, ret = -EIO;
+       int retries = QLCNIC_HEARTBEAT_CHECK_RETRY_COUNT;
 
-       for (i = 0; i < 10; i++) {
+       adapter->heartbeat = QLCRD32(adapter, QLCNIC_PEG_ALIVE_COUNTER);
 
-               timeout = msleep_interruptible(200);
-               if (timeout) {
-                       QLCWR32(adapter, CRB_CMDPEG_STATE,
-                                       PHAN_INITIALIZE_FAILED);
-                       return -EINTR;
+       do {
+               msleep(QLCNIC_HEARTBEAT_PERIOD_MSECS);
+               heartbeat = QLCRD32(adapter, QLCNIC_PEG_ALIVE_COUNTER);
+               if (heartbeat != adapter->heartbeat) {
+                       ret = QLCNIC_RCODE_SUCCESS;
+                       break;
                }
+       } while (--retries);
 
-               count = QLCRD32(adapter, QLCNIC_PEG_ALIVE_COUNTER);
-               if (count != old_count)
-                       break;
+       return ret;
+}
+
+int
+qlcnic_need_fw_reset(struct qlcnic_adapter *adapter)
+{
+       u32 val, version, major, minor, build;
+
+       if (qlcnic_check_fw_hearbeat(adapter)) {
+               qlcnic_rom_lock_recovery(adapter);
+               return 1;
        }
 
-       /* firmware is dead */
-       if (count == old_count)
+       if (adapter->need_fw_reset)
                return 1;
 
        /* check if we have got newer or different file firmware */
@@ -1162,78 +1247,6 @@ qlcnic_release_firmware(struct qlcnic_adapter *adapter)
        adapter->fw = NULL;
 }
 
-static int qlcnic_cmd_peg_ready(struct qlcnic_adapter *adapter)
-{
-       u32 val;
-       int retries = 60;
-
-       do {
-               val = QLCRD32(adapter, CRB_CMDPEG_STATE);
-
-               switch (val) {
-               case PHAN_INITIALIZE_COMPLETE:
-               case PHAN_INITIALIZE_ACK:
-                       return 0;
-               case PHAN_INITIALIZE_FAILED:
-                       goto out_err;
-               default:
-                       break;
-               }
-
-               msleep(500);
-
-       } while (--retries);
-
-       QLCWR32(adapter, CRB_CMDPEG_STATE, PHAN_INITIALIZE_FAILED);
-
-out_err:
-       dev_err(&adapter->pdev->dev, "Command Peg initialization not "
-                     "complete, state: 0x%x.\n", val);
-       return -EIO;
-}
-
-static int
-qlcnic_receive_peg_ready(struct qlcnic_adapter *adapter)
-{
-       u32 val;
-       int retries = 2000;
-
-       do {
-               val = QLCRD32(adapter, CRB_RCVPEG_STATE);
-
-               if (val == PHAN_PEG_RCV_INITIALIZED)
-                       return 0;
-
-               msleep(10);
-
-       } while (--retries);
-
-       if (!retries) {
-               dev_err(&adapter->pdev->dev, "Receive Peg initialization not "
-                             "complete, state: 0x%x.\n", val);
-               return -EIO;
-       }
-
-       return 0;
-}
-
-int qlcnic_init_firmware(struct qlcnic_adapter *adapter)
-{
-       int err;
-
-       err = qlcnic_cmd_peg_ready(adapter);
-       if (err)
-               return err;
-
-       err = qlcnic_receive_peg_ready(adapter);
-       if (err)
-               return err;
-
-       QLCWR32(adapter, CRB_CMDPEG_STATE, PHAN_INITIALIZE_ACK);
-
-       return err;
-}
-
 static void
 qlcnic_handle_linkevent(struct qlcnic_adapter *adapter,
                                struct qlcnic_fw_msg *msg)
@@ -1351,11 +1364,12 @@ static struct sk_buff *qlcnic_process_rxbuf(struct qlcnic_adapter *adapter,
 
        skb = buffer->skb;
 
-       if (likely(adapter->rx_csum && cksum == STATUS_CKSUM_OK)) {
+       if (likely(adapter->rx_csum && (cksum == STATUS_CKSUM_OK ||
+                                               cksum == STATUS_CKSUM_LOOP))) {
                adapter->stats.csummed++;
                skb->ip_summed = CHECKSUM_UNNECESSARY;
        } else {
-               skb->ip_summed = CHECKSUM_NONE;
+               skb_checksum_none_assert(skb);
        }
 
        skb->dev = adapter->netdev;
@@ -1365,6 +1379,27 @@ static struct sk_buff *qlcnic_process_rxbuf(struct qlcnic_adapter *adapter,
        return skb;
 }
 
+static int
+qlcnic_check_rx_tagging(struct qlcnic_adapter *adapter, struct sk_buff *skb)
+{
+       u16 vlan_tag;
+       struct ethhdr *eth_hdr;
+
+       if (!__vlan_get_tag(skb, &vlan_tag)) {
+               if (vlan_tag == adapter->pvid) {
+                       /* strip the tag from the packet and send it up */
+                       eth_hdr = (struct ethhdr *) skb->data;
+                       memmove(skb->data + VLAN_HLEN, eth_hdr, ETH_ALEN * 2);
+                       skb_pull(skb, VLAN_HLEN);
+                       return 0;
+               }
+       }
+       if (adapter->flags & QLCNIC_TAGGING_ENABLED)
+               return 0;
+
+       return -EIO;
+}
+
 static struct qlcnic_rx_buffer *
 qlcnic_process_rcv(struct qlcnic_adapter *adapter,
                struct qlcnic_host_sds_ring *sds_ring,
@@ -1405,6 +1440,15 @@ qlcnic_process_rcv(struct qlcnic_adapter *adapter,
                skb_pull(skb, pkt_offset);
 
        skb->truesize = skb->len + sizeof(struct sk_buff);
+
+       if (unlikely(adapter->pvid)) {
+               if (qlcnic_check_rx_tagging(adapter, skb)) {
+                       adapter->stats.rxdropped++;
+                       dev_kfree_skb_any(skb);
+                       return buffer;
+               }
+       }
+
        skb->protocol = eth_type_trans(skb, netdev);
 
        napi_gro_receive(&sds_ring->napi, skb);
@@ -1469,6 +1513,14 @@ qlcnic_process_lro(struct qlcnic_adapter *adapter,
        skb->truesize = skb->len + sizeof(struct sk_buff) + skb_headroom(skb);
 
        skb_pull(skb, l2_hdr_offset);
+
+       if (unlikely(adapter->pvid)) {
+               if (qlcnic_check_rx_tagging(adapter, skb)) {
+                       adapter->stats.rxdropped++;
+                       dev_kfree_skb_any(skb);
+                       return buffer;
+               }
+       }
        skb->protocol = eth_type_trans(skb, netdev);
 
        iph = (struct iphdr *)skb->data;
@@ -1587,8 +1639,6 @@ qlcnic_post_rx_buffers(struct qlcnic_adapter *adapter, u32 ringid,
        int producer, count = 0;
        struct list_head *head;
 
-       spin_lock(&rds_ring->lock);
-
        producer = rds_ring->producer;
 
        head = &rds_ring->free_list;
@@ -1618,7 +1668,6 @@ qlcnic_post_rx_buffers(struct qlcnic_adapter *adapter, u32 ringid,
                writel((producer-1) & (rds_ring->num_desc-1),
                                rds_ring->crb_rcv_producer);
        }
-       spin_unlock(&rds_ring->lock);
 }
 
 static void
index 66eea59720209f85278cf223b6d723f879337aac..5fd2abd1eb6710a6ea3f08d54edf553ef643a775 100644 (file)
@@ -50,6 +50,10 @@ static int port_mode = QLCNIC_PORT_MODE_AUTO_NEG;
 /* Default to restricted 1G auto-neg mode */
 static int wol_port_mode = 5;
 
+static int qlcnic_mac_learn;
+module_param(qlcnic_mac_learn, int, 0644);
+MODULE_PARM_DESC(qlcnic_mac_learn, "Mac Filter (0=disabled, 1=enabled)");
+
 static int use_msi = 1;
 module_param(use_msi, int, 0644);
 MODULE_PARM_DESC(use_msi, "MSI interrupt (0=disabled, 1=enabled");
@@ -94,7 +98,7 @@ static void qlcnic_create_diag_entries(struct qlcnic_adapter *adapter);
 static void qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter);
 
 static void qlcnic_idc_debug_info(struct qlcnic_adapter *adapter, u8 encoding);
-static void qlcnic_clr_all_drv_state(struct qlcnic_adapter *adapter);
+static void qlcnic_clr_all_drv_state(struct qlcnic_adapter *adapter, u8);
 static int qlcnic_can_start_firmware(struct qlcnic_adapter *adapter);
 
 static irqreturn_t qlcnic_tmp_intr(int irq, void *data);
@@ -106,10 +110,14 @@ static struct net_device_stats *qlcnic_get_stats(struct net_device *netdev);
 static void qlcnic_config_indev_addr(struct net_device *dev, unsigned long);
 static int qlcnic_start_firmware(struct qlcnic_adapter *);
 
+static void qlcnic_alloc_lb_filters_mem(struct qlcnic_adapter *adapter);
+static void qlcnic_free_lb_filters_mem(struct qlcnic_adapter *adapter);
 static void qlcnic_dev_set_npar_ready(struct qlcnic_adapter *);
 static int qlcnicvf_config_led(struct qlcnic_adapter *, u32, u32);
 static int qlcnicvf_config_bridged_mode(struct qlcnic_adapter *, u32);
 static int qlcnicvf_start_firmware(struct qlcnic_adapter *);
+static void qlcnic_set_netdev_features(struct qlcnic_adapter *,
+                               struct qlcnic_esw_func_cfg *);
 /*  PCI Device ID Table  */
 #define ENTRY(device) \
        {PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, (device)), \
@@ -320,7 +328,7 @@ qlcnic_read_mac_addr(struct qlcnic_adapter *adapter)
        struct net_device *netdev = adapter->netdev;
        struct pci_dev *pdev = adapter->pdev;
 
-       if (adapter->nic_ops->get_mac_addr(adapter, mac_addr) != 0)
+       if (qlcnic_get_mac_address(adapter, mac_addr) != 0)
                return -EIO;
 
        memcpy(netdev->dev_addr, mac_addr, ETH_ALEN);
@@ -341,6 +349,9 @@ static int qlcnic_set_mac(struct net_device *netdev, void *p)
        struct qlcnic_adapter *adapter = netdev_priv(netdev);
        struct sockaddr *addr = p;
 
+       if ((adapter->flags & QLCNIC_MAC_OVERRIDE_DISABLED))
+               return -EOPNOTSUPP;
+
        if (!is_valid_ether_addr(addr->sa_data))
                return -EINVAL;
 
@@ -376,14 +387,12 @@ static const struct net_device_ops qlcnic_netdev_ops = {
 };
 
 static struct qlcnic_nic_template qlcnic_ops = {
-       .get_mac_addr = qlcnic_get_mac_address,
        .config_bridged_mode = qlcnic_config_bridged_mode,
        .config_led = qlcnic_config_led,
        .start_firmware = qlcnic_start_firmware
 };
 
 static struct qlcnic_nic_template qlcnic_vf_ops = {
-       .get_mac_addr = qlcnic_get_mac_address,
        .config_bridged_mode = qlcnicvf_config_bridged_mode,
        .config_led = qlcnicvf_config_led,
        .start_firmware = qlcnicvf_start_firmware
@@ -474,7 +483,7 @@ static int
 qlcnic_init_pci_info(struct qlcnic_adapter *adapter)
 {
        struct qlcnic_pci_info *pci_info;
-       int i, ret = 0, err;
+       int i, ret = 0;
        u8 pfn;
 
        pci_info = kcalloc(QLCNIC_MAX_PCI_FUNC, sizeof(*pci_info), GFP_KERNEL);
@@ -484,14 +493,14 @@ qlcnic_init_pci_info(struct qlcnic_adapter *adapter)
        adapter->npars = kzalloc(sizeof(struct qlcnic_npar_info) *
                                QLCNIC_MAX_PCI_FUNC, GFP_KERNEL);
        if (!adapter->npars) {
-               err = -ENOMEM;
+               ret = -ENOMEM;
                goto err_pci_info;
        }
 
        adapter->eswitch = kzalloc(sizeof(struct qlcnic_eswitch) *
                                QLCNIC_NIU_MAX_XG_PORTS, GFP_KERNEL);
        if (!adapter->eswitch) {
-               err = -ENOMEM;
+               ret = -ENOMEM;
                goto err_npars;
        }
 
@@ -506,7 +515,6 @@ qlcnic_init_pci_info(struct qlcnic_adapter *adapter)
                adapter->npars[pfn].active = pci_info[i].active;
                adapter->npars[pfn].type = pci_info[i].type;
                adapter->npars[pfn].phy_port = pci_info[i].default_port;
-               adapter->npars[pfn].mac_learning = DEFAULT_MAC_LEARN;
                adapter->npars[pfn].min_bw = pci_info[i].tx_min_bw;
                adapter->npars[pfn].max_bw = pci_info[i].tx_max_bw;
        }
@@ -539,12 +547,10 @@ qlcnic_set_function_modes(struct qlcnic_adapter *adapter)
        void __iomem *priv_op = adapter->ahw.pci_base0 + QLCNIC_DRV_OP_MODE;
 
        /* If other drivers are not in use set their privilege level */
-       ref_count = QLCRD32(adapter, QLCNIC_CRB_DEV_REF_COUNT);
+       ref_count = QLCRD32(adapter, QLCNIC_CRB_DRV_ACTIVE);
        ret = qlcnic_api_lock(adapter);
        if (ret)
                goto err_lock;
-       if (QLC_DEV_CLR_REF_CNT(ref_count, adapter->ahw.pci_func))
-               goto err_npar;
 
        if (qlcnic_config_npars) {
                for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
@@ -562,18 +568,16 @@ qlcnic_set_function_modes(struct qlcnic_adapter *adapter)
                        adapter->ahw.pci_func));
        }
        writel(data, priv_op);
-err_npar:
        qlcnic_api_unlock(adapter);
 err_lock:
        return ret;
 }
 
-static u32
-qlcnic_get_driver_mode(struct qlcnic_adapter *adapter)
+static void
+qlcnic_check_vf(struct qlcnic_adapter *adapter)
 {
        void __iomem *msix_base_addr;
        void __iomem *priv_op;
-       struct qlcnic_info nic_info;
        u32 func;
        u32 msix_base;
        u32 op_mode, priv_level;
@@ -588,20 +592,6 @@ qlcnic_get_driver_mode(struct qlcnic_adapter *adapter)
        func = (func - msix_base)/QLCNIC_MSIX_TBL_PGSIZE;
        adapter->ahw.pci_func = func;
 
-       if (!qlcnic_get_nic_info(adapter, &nic_info, adapter->ahw.pci_func)) {
-               adapter->capabilities = nic_info.capabilities;
-
-               if (adapter->capabilities & BIT_6)
-                       adapter->flags |= QLCNIC_ESWITCH_ENABLED;
-               else
-                       adapter->flags &= ~QLCNIC_ESWITCH_ENABLED;
-       }
-
-       if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED)) {
-               adapter->nic_ops = &qlcnic_ops;
-               return adapter->fw_hal_version;
-       }
-
        /* Determine function privilege level */
        priv_op = adapter->ahw.pci_base0 + QLCNIC_DRV_OP_MODE;
        op_mode = readl(priv_op);
@@ -610,37 +600,14 @@ qlcnic_get_driver_mode(struct qlcnic_adapter *adapter)
        else
                priv_level = QLC_DEV_GET_DRV(op_mode, adapter->ahw.pci_func);
 
-       switch (priv_level) {
-       case QLCNIC_MGMT_FUNC:
-               adapter->op_mode = QLCNIC_MGMT_FUNC;
-               adapter->nic_ops = &qlcnic_ops;
-               qlcnic_init_pci_info(adapter);
-               /* Set privilege level for other functions */
-               qlcnic_set_function_modes(adapter);
-               dev_info(&adapter->pdev->dev,
-                       "HAL Version: %d, Management function\n",
-                       adapter->fw_hal_version);
-               break;
-       case QLCNIC_PRIV_FUNC:
-               adapter->op_mode = QLCNIC_PRIV_FUNC;
-               dev_info(&adapter->pdev->dev,
-                       "HAL Version: %d, Privileged function\n",
-                       adapter->fw_hal_version);
-               adapter->nic_ops = &qlcnic_ops;
-               break;
-       case QLCNIC_NON_PRIV_FUNC:
+       if (priv_level == QLCNIC_NON_PRIV_FUNC) {
                adapter->op_mode = QLCNIC_NON_PRIV_FUNC;
                dev_info(&adapter->pdev->dev,
                        "HAL Version: %d Non Privileged function\n",
                        adapter->fw_hal_version);
                adapter->nic_ops = &qlcnic_vf_ops;
-               break;
-       default:
-               dev_info(&adapter->pdev->dev, "Unknown function mode: %d\n",
-                       priv_level);
-               return 0;
-       }
-       return adapter->fw_hal_version;
+       } else
+               adapter->nic_ops = &qlcnic_ops;
 }
 
 static int
@@ -673,10 +640,7 @@ qlcnic_setup_pci_map(struct qlcnic_adapter *adapter)
        adapter->ahw.pci_base0 = mem_ptr0;
        adapter->ahw.pci_len0 = pci_len0;
 
-       if (!qlcnic_get_driver_mode(adapter)) {
-               iounmap(adapter->ahw.pci_base0);
-               return -EIO;
-       }
+       qlcnic_check_vf(adapter);
 
        adapter->ahw.ocm_win_crb = qlcnic_get_ioaddr(adapter,
                QLCNIC_PCIX_PS_REG(PCIX_OCM_WINDOW_REG(adapter->ahw.pci_func)));
@@ -711,25 +675,7 @@ static void
 qlcnic_check_options(struct qlcnic_adapter *adapter)
 {
        u32 fw_major, fw_minor, fw_build;
-       char brd_name[QLCNIC_MAX_BOARD_NAME_LEN];
-       char serial_num[32];
-       int i, offset, val;
-       int *ptr32;
        struct pci_dev *pdev = adapter->pdev;
-       struct qlcnic_info nic_info;
-       adapter->driver_mismatch = 0;
-
-       ptr32 = (int *)&serial_num;
-       offset = QLCNIC_FW_SERIAL_NUM_OFFSET;
-       for (i = 0; i < 8; i++) {
-               if (qlcnic_rom_fast_read(adapter, offset, &val) == -1) {
-                       dev_err(&pdev->dev, "error reading board info\n");
-                       adapter->driver_mismatch = 1;
-                       return;
-               }
-               ptr32[i] = cpu_to_le32(val);
-               offset += sizeof(u32);
-       }
 
        fw_major = QLCRD32(adapter, QLCNIC_FW_VERSION_MAJOR);
        fw_minor = QLCRD32(adapter, QLCNIC_FW_VERSION_MINOR);
@@ -737,14 +683,6 @@ qlcnic_check_options(struct qlcnic_adapter *adapter)
 
        adapter->fw_version = QLCNIC_VERSION_CODE(fw_major, fw_minor, fw_build);
 
-       if (adapter->portnum == 0) {
-               get_brd_name(adapter, brd_name);
-
-               pr_info("%s: %s Board Chip rev 0x%x\n",
-                               module_name(THIS_MODULE),
-                               brd_name, adapter->ahw.revision_id);
-       }
-
        dev_info(&pdev->dev, "firmware v%d.%d.%d\n",
                        fw_major, fw_minor, fw_build);
 
@@ -758,109 +696,333 @@ qlcnic_check_options(struct qlcnic_adapter *adapter)
                adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_1G;
        }
 
-       if (!qlcnic_get_nic_info(adapter, &nic_info, adapter->ahw.pci_func)) {
-               adapter->physical_port = nic_info.phys_port;
-               adapter->switch_mode = nic_info.switch_mode;
-               adapter->max_tx_ques = nic_info.max_tx_ques;
-               adapter->max_rx_ques = nic_info.max_rx_ques;
-               adapter->capabilities = nic_info.capabilities;
-               adapter->max_mac_filters = nic_info.max_mac_filters;
-               adapter->max_mtu = nic_info.max_mtu;
-       }
-
        adapter->msix_supported = !!use_msi_x;
        adapter->rss_supported = !!use_msi_x;
 
        adapter->num_txd = MAX_CMD_DESCRIPTORS;
 
-       adapter->max_rds_rings = 2;
+       adapter->max_rds_rings = MAX_RDS_RINGS;
+}
+
+static int
+qlcnic_initialize_nic(struct qlcnic_adapter *adapter)
+{
+       int err;
+       struct qlcnic_info nic_info;
+
+       err = qlcnic_get_nic_info(adapter, &nic_info, adapter->ahw.pci_func);
+       if (err)
+               return err;
+
+       adapter->physical_port = nic_info.phys_port;
+       adapter->switch_mode = nic_info.switch_mode;
+       adapter->max_tx_ques = nic_info.max_tx_ques;
+       adapter->max_rx_ques = nic_info.max_rx_ques;
+       adapter->capabilities = nic_info.capabilities;
+       adapter->max_mac_filters = nic_info.max_mac_filters;
+       adapter->max_mtu = nic_info.max_mtu;
+
+       if (adapter->capabilities & BIT_6)
+               adapter->flags |= QLCNIC_ESWITCH_ENABLED;
+       else
+               adapter->flags &= ~QLCNIC_ESWITCH_ENABLED;
+
+       return err;
+}
+
+static void
+qlcnic_set_vlan_config(struct qlcnic_adapter *adapter,
+               struct qlcnic_esw_func_cfg *esw_cfg)
+{
+       if (esw_cfg->discard_tagged)
+               adapter->flags &= ~QLCNIC_TAGGING_ENABLED;
+       else
+               adapter->flags |= QLCNIC_TAGGING_ENABLED;
+
+       if (esw_cfg->vlan_id)
+               adapter->pvid = esw_cfg->vlan_id;
+       else
+               adapter->pvid = 0;
+}
+
+static void
+qlcnic_set_eswitch_port_features(struct qlcnic_adapter *adapter,
+               struct qlcnic_esw_func_cfg *esw_cfg)
+{
+       adapter->flags &= ~QLCNIC_MACSPOOF;
+       adapter->flags &= ~QLCNIC_MAC_OVERRIDE_DISABLED;
+
+       if (esw_cfg->mac_anti_spoof)
+               adapter->flags |= QLCNIC_MACSPOOF;
+
+       if (!esw_cfg->mac_override)
+               adapter->flags |= QLCNIC_MAC_OVERRIDE_DISABLED;
+
+       qlcnic_set_netdev_features(adapter, esw_cfg);
+}
+
+static int
+qlcnic_set_eswitch_port_config(struct qlcnic_adapter *adapter)
+{
+       struct qlcnic_esw_func_cfg esw_cfg;
+
+       if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
+               return 0;
+
+       esw_cfg.pci_func = adapter->ahw.pci_func;
+       if (qlcnic_get_eswitch_port_config(adapter, &esw_cfg))
+                       return -EIO;
+       qlcnic_set_vlan_config(adapter, &esw_cfg);
+       qlcnic_set_eswitch_port_features(adapter, &esw_cfg);
+
+       return 0;
+}
+
+static void
+qlcnic_set_netdev_features(struct qlcnic_adapter *adapter,
+               struct qlcnic_esw_func_cfg *esw_cfg)
+{
+       struct net_device *netdev = adapter->netdev;
+       unsigned long features, vlan_features;
+
+       features = (NETIF_F_SG | NETIF_F_IP_CSUM |
+                       NETIF_F_IPV6_CSUM | NETIF_F_GRO);
+       vlan_features = (NETIF_F_SG | NETIF_F_IP_CSUM |
+                       NETIF_F_IPV6_CSUM);
+
+       if (adapter->capabilities & QLCNIC_FW_CAPABILITY_TSO) {
+               features |= (NETIF_F_TSO | NETIF_F_TSO6);
+               vlan_features |= (NETIF_F_TSO | NETIF_F_TSO6);
+       }
+       if (adapter->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO)
+               features |= NETIF_F_LRO;
+
+       if (esw_cfg->offload_flags & BIT_0) {
+               netdev->features |= features;
+               adapter->rx_csum = 1;
+               if (!(esw_cfg->offload_flags & BIT_1))
+                       netdev->features &= ~NETIF_F_TSO;
+               if (!(esw_cfg->offload_flags & BIT_2))
+                       netdev->features &= ~NETIF_F_TSO6;
+       } else {
+               netdev->features &= ~features;
+               adapter->rx_csum = 0;
+       }
+
+       netdev->vlan_features = (features & vlan_features);
+}
+
+static int
+qlcnic_check_eswitch_mode(struct qlcnic_adapter *adapter)
+{
+       void __iomem *priv_op;
+       u32 op_mode, priv_level;
+       int err = 0;
+
+       err = qlcnic_initialize_nic(adapter);
+       if (err)
+               return err;
+
+       if (adapter->flags & QLCNIC_ADAPTER_INITIALIZED)
+               return 0;
+
+       priv_op = adapter->ahw.pci_base0 + QLCNIC_DRV_OP_MODE;
+       op_mode = readl(priv_op);
+       priv_level = QLC_DEV_GET_DRV(op_mode, adapter->ahw.pci_func);
+
+       if (op_mode == QLC_DEV_DRV_DEFAULT)
+               priv_level = QLCNIC_MGMT_FUNC;
+       else
+               priv_level = QLC_DEV_GET_DRV(op_mode, adapter->ahw.pci_func);
+
+       if (adapter->flags & QLCNIC_ESWITCH_ENABLED) {
+               if (priv_level == QLCNIC_MGMT_FUNC) {
+                       adapter->op_mode = QLCNIC_MGMT_FUNC;
+                       err = qlcnic_init_pci_info(adapter);
+                       if (err)
+                               return err;
+                       /* Set privilege level for other functions */
+                       qlcnic_set_function_modes(adapter);
+                       dev_info(&adapter->pdev->dev,
+                               "HAL Version: %d, Management function\n",
+                               adapter->fw_hal_version);
+               } else if (priv_level == QLCNIC_PRIV_FUNC) {
+                       adapter->op_mode = QLCNIC_PRIV_FUNC;
+                       dev_info(&adapter->pdev->dev,
+                               "HAL Version: %d, Privileged function\n",
+                               adapter->fw_hal_version);
+               }
+       }
+
+       adapter->flags |= QLCNIC_ADAPTER_INITIALIZED;
+
+       return err;
+}
+
+static int
+qlcnic_set_default_offload_settings(struct qlcnic_adapter *adapter)
+{
+       struct qlcnic_esw_func_cfg esw_cfg;
+       struct qlcnic_npar_info *npar;
+       u8 i;
+
+       if (adapter->need_fw_reset)
+               return 0;
+
+       for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
+               if (adapter->npars[i].type != QLCNIC_TYPE_NIC)
+                       continue;
+               memset(&esw_cfg, 0, sizeof(struct qlcnic_esw_func_cfg));
+               esw_cfg.pci_func = i;
+               esw_cfg.offload_flags = BIT_0;
+               esw_cfg.mac_override = BIT_0;
+               if (adapter->capabilities  & QLCNIC_FW_CAPABILITY_TSO)
+                       esw_cfg.offload_flags |= (BIT_1 | BIT_2);
+               if (qlcnic_config_switch_port(adapter, &esw_cfg))
+                       return -EIO;
+               npar = &adapter->npars[i];
+               npar->pvid = esw_cfg.vlan_id;
+               npar->mac_override = esw_cfg.mac_override;
+               npar->mac_anti_spoof = esw_cfg.mac_anti_spoof;
+               npar->discard_tagged = esw_cfg.discard_tagged;
+               npar->promisc_mode = esw_cfg.promisc_mode;
+               npar->offload_flags = esw_cfg.offload_flags;
+       }
+
+       return 0;
+}
+
+static int
+qlcnic_reset_eswitch_config(struct qlcnic_adapter *adapter,
+                       struct qlcnic_npar_info *npar, int pci_func)
+{
+       struct qlcnic_esw_func_cfg esw_cfg;
+       esw_cfg.op_mode = QLCNIC_PORT_DEFAULTS;
+       esw_cfg.pci_func = pci_func;
+       esw_cfg.vlan_id = npar->pvid;
+       esw_cfg.mac_override = npar->mac_override;
+       esw_cfg.discard_tagged = npar->discard_tagged;
+       esw_cfg.mac_anti_spoof = npar->mac_anti_spoof;
+       esw_cfg.offload_flags = npar->offload_flags;
+       esw_cfg.promisc_mode = npar->promisc_mode;
+       if (qlcnic_config_switch_port(adapter, &esw_cfg))
+               return -EIO;
+
+       esw_cfg.op_mode = QLCNIC_ADD_VLAN;
+       if (qlcnic_config_switch_port(adapter, &esw_cfg))
+               return -EIO;
+
+       return 0;
 }
 
 static int
 qlcnic_reset_npar_config(struct qlcnic_adapter *adapter)
 {
-       int i, err = 0;
+       int i, err;
        struct qlcnic_npar_info *npar;
        struct qlcnic_info nic_info;
 
-       if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED) ||
-           !adapter->need_fw_reset)
+       if (!adapter->need_fw_reset)
                return 0;
 
-       if (adapter->op_mode == QLCNIC_MGMT_FUNC) {
-               /* Set the NPAR config data after FW reset */
-               for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
-                       npar = &adapter->npars[i];
-                       if (npar->type != QLCNIC_TYPE_NIC)
-                               continue;
-                       err = qlcnic_get_nic_info(adapter, &nic_info, i);
-                       if (err)
-                               goto err_out;
-                       nic_info.min_tx_bw = npar->min_bw;
-                       nic_info.max_tx_bw = npar->max_bw;
-                       err = qlcnic_set_nic_info(adapter, &nic_info);
+       /* Set the NPAR config data after FW reset */
+       for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
+               npar = &adapter->npars[i];
+               if (npar->type != QLCNIC_TYPE_NIC)
+                       continue;
+               err = qlcnic_get_nic_info(adapter, &nic_info, i);
+               if (err)
+                       return err;
+               nic_info.min_tx_bw = npar->min_bw;
+               nic_info.max_tx_bw = npar->max_bw;
+               err = qlcnic_set_nic_info(adapter, &nic_info);
+               if (err)
+                       return err;
+
+               if (npar->enable_pm) {
+                       err = qlcnic_config_port_mirroring(adapter,
+                                                       npar->dest_npar, 1, i);
                        if (err)
-                               goto err_out;
+                               return err;
+               }
+               err = qlcnic_reset_eswitch_config(adapter, npar, i);
+               if (err)
+                       return err;
+       }
+       return 0;
+}
 
-                       if (npar->enable_pm) {
-                               err = qlcnic_config_port_mirroring(adapter,
-                                               npar->dest_npar, 1, i);
-                               if (err)
-                                       goto err_out;
+static int qlcnic_check_npar_opertional(struct qlcnic_adapter *adapter)
+{
+       u8 npar_opt_timeo = QLCNIC_DEV_NPAR_OPER_TIMEO;
+       u32 npar_state;
 
-                       }
-                       npar->mac_learning = DEFAULT_MAC_LEARN;
-                       npar->host_vlan_tag = 0;
-                       npar->promisc_mode = 0;
-                       npar->discard_tagged = 0;
-                       npar->vlan_id = 0;
-               }
+       if (adapter->op_mode == QLCNIC_MGMT_FUNC)
+               return 0;
+
+       npar_state = QLCRD32(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);
        }
-err_out:
+       if (!npar_opt_timeo) {
+               dev_err(&adapter->pdev->dev,
+                       "Waiting for NPAR state to opertional timeout\n");
+               return -EIO;
+       }
+       return 0;
+}
+
+static int
+qlcnic_set_mgmt_operations(struct qlcnic_adapter *adapter)
+{
+       int err;
+
+       if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED) ||
+                   adapter->op_mode != QLCNIC_MGMT_FUNC)
+               return 0;
+
+       err = qlcnic_set_default_offload_settings(adapter);
+       if (err)
+               return err;
+
+       err = qlcnic_reset_npar_config(adapter);
+       if (err)
+               return err;
+
+       qlcnic_dev_set_npar_ready(adapter);
+
        return err;
 }
 
 static int
 qlcnic_start_firmware(struct qlcnic_adapter *adapter)
 {
-       int val, err, first_boot;
+       int err;
 
        err = qlcnic_can_start_firmware(adapter);
        if (err < 0)
                return err;
        else if (!err)
-               goto wait_init;
-
-       first_boot = QLCRD32(adapter, QLCNIC_CAM_RAM(0x1fc));
-       if (first_boot == 0x55555555)
-               /* This is the first boot after power up */
-               QLCWR32(adapter, QLCNIC_CAM_RAM(0x1fc), QLCNIC_BDINFO_MAGIC);
+               goto check_fw_status;
 
        if (load_fw_file)
                qlcnic_request_firmware(adapter);
        else {
-               if (qlcnic_check_flash_fw_ver(adapter))
+               err = qlcnic_check_flash_fw_ver(adapter);
+               if (err)
                        goto err_out;
 
                adapter->fw_type = QLCNIC_FLASH_ROMIMAGE;
        }
 
        err = qlcnic_need_fw_reset(adapter);
-       if (err < 0)
-               goto err_out;
        if (err == 0)
-               goto wait_init;
-
-       if (first_boot != 0x55555555) {
-               QLCWR32(adapter, CRB_CMDPEG_STATE, 0);
-               QLCWR32(adapter, CRB_RCVPEG_STATE, 0);
-               qlcnic_pinit_from_rom(adapter);
-               msleep(1);
-       }
-
-       QLCWR32(adapter, QLCNIC_PEG_HALT_STATUS1, 0);
-       QLCWR32(adapter, QLCNIC_PEG_HALT_STATUS2, 0);
+               goto check_fw_status;
 
+       err = qlcnic_pinit_from_rom(adapter);
+       if (err)
+               goto err_out;
        qlcnic_set_port_mode(adapter);
 
        err = qlcnic_load_firmware(adapter);
@@ -868,26 +1030,27 @@ qlcnic_start_firmware(struct qlcnic_adapter *adapter)
                goto err_out;
 
        qlcnic_release_firmware(adapter);
+       QLCWR32(adapter, CRB_DRIVER_VERSION, QLCNIC_DRIVER_VERSION);
 
-       val = (_QLCNIC_LINUX_MAJOR << 16)
-               | ((_QLCNIC_LINUX_MINOR << 8))
-               | (_QLCNIC_LINUX_SUBVERSION);
-       QLCWR32(adapter, CRB_DRIVER_VERSION, val);
-
-wait_init:
-       /* Handshake with the card before we register the devices. */
-       err = qlcnic_init_firmware(adapter);
+check_fw_status:
+       err = qlcnic_check_fw_status(adapter);
        if (err)
                goto err_out;
 
        QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_READY);
        qlcnic_idc_debug_info(adapter, 1);
 
-       qlcnic_check_options(adapter);
-       if (qlcnic_reset_npar_config(adapter))
+       err = qlcnic_check_eswitch_mode(adapter);
+       if (err) {
+               dev_err(&adapter->pdev->dev,
+                       "Memory allocation failed for eswitch\n");
+               goto err_out;
+       }
+       err = qlcnic_set_mgmt_operations(adapter);
+       if (err)
                goto err_out;
-       qlcnic_dev_set_npar_ready(adapter);
 
+       qlcnic_check_options(adapter);
        adapter->need_fw_reset = 0;
 
        qlcnic_release_firmware(adapter);
@@ -896,6 +1059,7 @@ wait_init:
 err_out:
        QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_FAILED);
        dev_err(&adapter->pdev->dev, "Device state set to failed\n");
+
        qlcnic_release_firmware(adapter);
        return err;
 }
@@ -979,6 +1143,8 @@ __qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev)
 
        if (test_bit(__QLCNIC_DEV_UP, &adapter->state))
                return 0;
+       if (qlcnic_set_eswitch_port_config(adapter))
+               return -EIO;
 
        if (qlcnic_fw_create_ctx(adapter))
                return -EIO;
@@ -998,7 +1164,7 @@ __qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev)
 
        qlcnic_config_intr_coalesce(adapter);
 
-       if (adapter->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO)
+       if (netdev->features & NETIF_F_LRO)
                qlcnic_config_hw_lro(adapter, QLCNIC_LRO_ENABLED);
 
        qlcnic_napi_enable(adapter);
@@ -1041,6 +1207,9 @@ __qlcnic_down(struct qlcnic_adapter *adapter, struct net_device *netdev)
 
        qlcnic_free_mac_list(adapter);
 
+       if (adapter->fhash.fnum)
+               qlcnic_delete_lb_filters(adapter);
+
        qlcnic_nic_set_promisc(adapter, QLCNIC_NIU_NON_PROMISC_MODE);
 
        qlcnic_napi_disable(adapter);
@@ -1296,12 +1465,8 @@ qlcnic_setup_netdev(struct qlcnic_adapter *adapter,
 
        if (adapter->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO)
                netdev->features |= NETIF_F_LRO;
-
        netdev->irq = adapter->msix_entries[0].vector;
 
-       if (qlcnic_read_mac_addr(adapter))
-               dev_warn(&pdev->dev, "failed to read mac addr\n");
-
        netif_carrier_off(netdev);
        netif_stop_queue(netdev);
 
@@ -1338,6 +1503,7 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        int err;
        uint8_t revision_id;
        uint8_t pci_using_dac;
+       char brd_name[QLCNIC_MAX_BOARD_NAME_LEN];
 
        err = pci_enable_device(pdev);
        if (err)
@@ -1395,10 +1561,8 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                goto err_out_iounmap;
        }
 
-       if (qlcnic_read_mac_addr(adapter))
-               dev_warn(&pdev->dev, "failed to read mac addr\n");
-
-       if (qlcnic_setup_idc_param(adapter))
+       err = qlcnic_setup_idc_param(adapter);
+       if (err)
                goto err_out_iounmap;
 
        err = adapter->nic_ops->start_firmware(adapter);
@@ -1407,6 +1571,17 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                goto err_out_decr_ref;
        }
 
+       if (qlcnic_read_mac_addr(adapter))
+               dev_warn(&pdev->dev, "failed to read mac addr\n");
+
+       if (adapter->portnum == 0) {
+               get_brd_name(adapter, brd_name);
+
+               pr_info("%s: %s Board Chip rev 0x%x\n",
+                               module_name(THIS_MODULE),
+                               brd_name, adapter->ahw.revision_id);
+       }
+
        qlcnic_clear_stats(adapter);
 
        qlcnic_setup_intr(adapter);
@@ -1430,6 +1605,7 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                break;
        }
 
+       qlcnic_alloc_lb_filters_mem(adapter);
        qlcnic_create_diag_entries(adapter);
 
        return 0;
@@ -1438,7 +1614,7 @@ err_out_disable_msi:
        qlcnic_teardown_intr(adapter);
 
 err_out_decr_ref:
-       qlcnic_clr_all_drv_state(adapter);
+       qlcnic_clr_all_drv_state(adapter, 0);
 
 err_out_iounmap:
        qlcnic_cleanup_pci_map(adapter);
@@ -1477,10 +1653,12 @@ static void __devexit qlcnic_remove(struct pci_dev *pdev)
        if (adapter->eswitch != NULL)
                kfree(adapter->eswitch);
 
-       qlcnic_clr_all_drv_state(adapter);
+       qlcnic_clr_all_drv_state(adapter, 0);
 
        clear_bit(__QLCNIC_RESETTING, &adapter->state);
 
+       qlcnic_free_lb_filters_mem(adapter);
+
        qlcnic_teardown_intr(adapter);
 
        qlcnic_remove_diag_entries(adapter);
@@ -1509,7 +1687,7 @@ static int __qlcnic_shutdown(struct pci_dev *pdev)
        if (netif_running(netdev))
                qlcnic_down(adapter, netdev);
 
-       qlcnic_clr_all_drv_state(adapter);
+       qlcnic_clr_all_drv_state(adapter, 0);
 
        clear_bit(__QLCNIC_RESETTING, &adapter->state);
 
@@ -1587,9 +1765,6 @@ static int qlcnic_open(struct net_device *netdev)
        struct qlcnic_adapter *adapter = netdev_priv(netdev);
        int err;
 
-       if (adapter->driver_mismatch)
-               return -EIO;
-
        err = qlcnic_attach(adapter);
        if (err)
                return err;
@@ -1602,20 +1777,133 @@ static int qlcnic_open(struct net_device *netdev)
 
        return 0;
 
-err_out:
-       qlcnic_detach(adapter);
-       return err;
-}
+err_out:
+       qlcnic_detach(adapter);
+       return err;
+}
+
+/*
+ * qlcnic_close - Disables a network interface entry point
+ */
+static int qlcnic_close(struct net_device *netdev)
+{
+       struct qlcnic_adapter *adapter = netdev_priv(netdev);
+
+       __qlcnic_down(adapter, netdev);
+       return 0;
+}
+
+static void
+qlcnic_alloc_lb_filters_mem(struct qlcnic_adapter *adapter)
+{
+       void *head;
+       int i;
+
+       if (!qlcnic_mac_learn)
+               return;
+
+       spin_lock_init(&adapter->mac_learn_lock);
+
+       head = kcalloc(QLCNIC_LB_MAX_FILTERS, sizeof(struct hlist_head),
+                                                               GFP_KERNEL);
+       if (!head)
+               return;
+
+       adapter->fhash.fmax = QLCNIC_LB_MAX_FILTERS;
+       adapter->fhash.fhead = (struct hlist_head *)head;
+
+       for (i = 0; i < adapter->fhash.fmax; i++)
+               INIT_HLIST_HEAD(&adapter->fhash.fhead[i]);
+}
+
+static void qlcnic_free_lb_filters_mem(struct qlcnic_adapter *adapter)
+{
+       if (adapter->fhash.fmax && adapter->fhash.fhead)
+               kfree(adapter->fhash.fhead);
+
+       adapter->fhash.fhead = NULL;
+       adapter->fhash.fmax = 0;
+}
+
+static void qlcnic_change_filter(struct qlcnic_adapter *adapter,
+               u64 uaddr, u16 vlan_id, struct qlcnic_host_tx_ring *tx_ring)
+{
+       struct cmd_desc_type0 *hwdesc;
+       struct qlcnic_nic_req *req;
+       struct qlcnic_mac_req *mac_req;
+       u32 producer;
+       u64 word;
+
+       producer = tx_ring->producer;
+       hwdesc = &tx_ring->desc_head[tx_ring->producer];
+
+       req = (struct qlcnic_nic_req *)hwdesc;
+       memset(req, 0, sizeof(struct qlcnic_nic_req));
+       req->qhdr = cpu_to_le64(QLCNIC_REQUEST << 23);
+
+       word = QLCNIC_MAC_EVENT | ((u64)(adapter->portnum) << 16);
+       req->req_hdr = cpu_to_le64(word);
+
+       mac_req = (struct qlcnic_mac_req *)&(req->words[0]);
+       mac_req->op = vlan_id ? QLCNIC_MAC_VLAN_ADD : QLCNIC_MAC_ADD;
+       memcpy(mac_req->mac_addr, &uaddr, ETH_ALEN);
+
+       req->words[1] = cpu_to_le64(vlan_id);
+
+       tx_ring->producer = get_next_index(producer, tx_ring->num_desc);
+}
+
+#define QLCNIC_MAC_HASH(MAC)\
+       ((((MAC) & 0x70000) >> 0x10) | (((MAC) & 0x70000000000ULL) >> 0x25))
+
+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;
+       u64 src_addr = 0;
+       u16 vlan_id = 0;
+       u8 hindex;
+
+       if (!compare_ether_addr(phdr->h_source, adapter->mac_addr))
+               return;
+
+       if (adapter->fhash.fnum >= adapter->fhash.fmax)
+               return;
+
+       /* 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);
+       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->ftime = jiffies;
+                       return;
+               }
+       }
+
+       fil = kzalloc(sizeof(struct qlcnic_filter), GFP_ATOMIC);
+       if (!fil)
+               return;
 
-/*
- * qlcnic_close - Disables a network interface entry point
- */
-static int qlcnic_close(struct net_device *netdev)
-{
-       struct qlcnic_adapter *adapter = netdev_priv(netdev);
+       qlcnic_change_filter(adapter, src_addr, vlan_id, tx_ring);
 
-       __qlcnic_down(adapter, netdev);
-       return 0;
+       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);
 }
 
 static void
@@ -1626,26 +1914,13 @@ qlcnic_tso_check(struct net_device *netdev,
 {
        u8 opcode = TX_ETHER_PKT;
        __be16 protocol = skb->protocol;
-       u16 flags = 0, vid = 0;
-       int copied, offset, copy_len, hdr_len = 0, tso = 0, vlan_oob = 0;
+       u16 flags = 0;
+       int copied, offset, copy_len, hdr_len = 0, tso = 0;
        struct cmd_desc_type0 *hwdesc;
        struct vlan_ethhdr *vh;
        struct qlcnic_adapter *adapter = netdev_priv(netdev);
        u32 producer = tx_ring->producer;
-
-       if (protocol == cpu_to_be16(ETH_P_8021Q)) {
-
-               vh = (struct vlan_ethhdr *)skb->data;
-               protocol = vh->h_vlan_encapsulated_proto;
-               flags = FLAGS_VLAN_TAGGED;
-
-       } else if (vlan_tx_tag_present(skb)) {
-
-               flags = FLAGS_VLAN_OOB;
-               vid = vlan_tx_tag_get(skb);
-               qlcnic_set_tx_vlan_tci(first_desc, vid);
-               vlan_oob = 1;
-       }
+       int vlan_oob = first_desc->flags_opcode & cpu_to_le16(FLAGS_VLAN_OOB);
 
        if (*(skb->data) & BIT_0) {
                flags |= BIT_0;
@@ -1716,7 +1991,7 @@ qlcnic_tso_check(struct net_device *netdev,
                vh = (struct vlan_ethhdr *)((char *)hwdesc + 2);
                skb_copy_from_linear_data(skb, vh, 12);
                vh->h_vlan_proto = htons(ETH_P_8021Q);
-               vh->h_vlan_TCI = htons(vid);
+               vh->h_vlan_TCI = htons(first_desc->vlan_TCI);
                skb_copy_from_linear_data_offset(skb, 12,
                                (char *)vh + 16, copy_len - 16);
 
@@ -1796,11 +2071,47 @@ out_err:
        return -ENOMEM;
 }
 
+static int
+qlcnic_check_tx_tagging(struct qlcnic_adapter *adapter,
+                       struct sk_buff *skb,
+                       struct cmd_desc_type0 *first_desc)
+{
+       u8 opcode = 0;
+       u16 flags = 0;
+       __be16 protocol = skb->protocol;
+       struct vlan_ethhdr *vh;
+
+       if (protocol == cpu_to_be16(ETH_P_8021Q)) {
+               vh = (struct vlan_ethhdr *)skb->data;
+               protocol = vh->h_vlan_encapsulated_proto;
+               flags = FLAGS_VLAN_TAGGED;
+               qlcnic_set_tx_vlan_tci(first_desc, ntohs(vh->h_vlan_TCI));
+       } else if (vlan_tx_tag_present(skb)) {
+               flags = FLAGS_VLAN_OOB;
+               qlcnic_set_tx_vlan_tci(first_desc, vlan_tx_tag_get(skb));
+       }
+       if (unlikely(adapter->pvid)) {
+               if (first_desc->vlan_TCI &&
+                               !(adapter->flags & QLCNIC_TAGGING_ENABLED))
+                       return -EIO;
+               if (first_desc->vlan_TCI &&
+                               (adapter->flags & QLCNIC_TAGGING_ENABLED))
+                       goto set_flags;
+
+               flags = FLAGS_VLAN_OOB;
+               qlcnic_set_tx_vlan_tci(first_desc, adapter->pvid);
+       }
+set_flags:
+       qlcnic_set_tx_flags_opcode(first_desc, flags, opcode);
+       return 0;
+}
+
 static inline void
 qlcnic_clear_cmddesc(u64 *desc)
 {
        desc[0] = 0ULL;
        desc[2] = 0ULL;
+       desc[7] = 0ULL;
 }
 
 netdev_tx_t
@@ -1812,6 +2123,7 @@ qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
        struct qlcnic_skb_frag *buffrag;
        struct cmd_desc_type0 *hwdesc, *first_desc;
        struct pci_dev *pdev;
+       struct ethhdr *phdr;
        int i, k;
 
        u32 producer;
@@ -1823,6 +2135,13 @@ qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
                return NETDEV_TX_BUSY;
        }
 
+       if (adapter->flags & QLCNIC_MACSPOOF) {
+               phdr = (struct ethhdr *)skb->data;
+               if (compare_ether_addr(phdr->h_source,
+                                       adapter->mac_addr))
+                       goto drop_packet;
+       }
+
        frag_count = skb_shinfo(skb)->nr_frags + 1;
 
        /* 4 fragments per cmd des */
@@ -1844,6 +2163,12 @@ qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
 
        pdev = adapter->pdev;
 
+       first_desc = hwdesc = &tx_ring->desc_head[producer];
+       qlcnic_clear_cmddesc((u64 *)hwdesc);
+
+       if (qlcnic_check_tx_tagging(adapter, skb, first_desc))
+               goto drop_packet;
+
        if (qlcnic_map_tx_skb(pdev, skb, pbuf)) {
                adapter->stats.tx_dma_map_error++;
                goto drop_packet;
@@ -1852,9 +2177,6 @@ qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
        pbuf->skb = skb;
        pbuf->frag_count = frag_count;
 
-       first_desc = hwdesc = &tx_ring->desc_head[producer];
-       qlcnic_clear_cmddesc((u64 *)hwdesc);
-
        qlcnic_set_tx_frags_len(first_desc, frag_count, skb->len);
        qlcnic_set_tx_port(first_desc, adapter->portnum);
 
@@ -1893,6 +2215,9 @@ qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
 
        qlcnic_tso_check(netdev, tx_ring, first_desc, skb);
 
+       if (qlcnic_mac_learn)
+               qlcnic_send_filter(adapter, tx_ring, first_desc, skb);
+
        qlcnic_update_cmd_producer(adapter, tx_ring);
 
        adapter->stats.txbytes += skb->len;
@@ -1947,14 +2272,14 @@ void qlcnic_advert_link_change(struct qlcnic_adapter *adapter, int linkup)
        struct net_device *netdev = adapter->netdev;
 
        if (adapter->ahw.linkup && !linkup) {
-               dev_info(&netdev->dev, "NIC Link is down\n");
+               netdev_info(netdev, "NIC Link is down\n");
                adapter->ahw.linkup = 0;
                if (netif_running(netdev)) {
                        netif_carrier_off(netdev);
                        netif_stop_queue(netdev);
                }
        } else if (!adapter->ahw.linkup && linkup) {
-               dev_info(&netdev->dev, "NIC Link is up\n");
+               netdev_info(netdev, "NIC Link is up\n");
                adapter->ahw.linkup = 1;
                if (netif_running(netdev)) {
                        netif_carrier_on(netdev);
@@ -2258,18 +2583,22 @@ qlcnic_clr_drv_state(struct qlcnic_adapter *adapter)
 }
 
 static void
-qlcnic_clr_all_drv_state(struct qlcnic_adapter *adapter)
+qlcnic_clr_all_drv_state(struct qlcnic_adapter *adapter, u8 failed)
 {
        u32  val;
 
        if (qlcnic_api_lock(adapter))
                goto err;
 
-       val = QLCRD32(adapter, QLCNIC_CRB_DEV_REF_COUNT);
+       val = QLCRD32(adapter, QLCNIC_CRB_DRV_ACTIVE);
        QLC_DEV_CLR_REF_CNT(val, adapter->portnum);
-       QLCWR32(adapter, QLCNIC_CRB_DEV_REF_COUNT, val);
+       QLCWR32(adapter, QLCNIC_CRB_DRV_ACTIVE, val);
 
-       if (!(val & 0x11111111))
+       if (failed) {
+               QLCWR32(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);
 
        val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
@@ -2290,7 +2619,7 @@ qlcnic_check_drv_state(struct qlcnic_adapter *adapter)
        int act, state;
 
        state = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
-       act = QLCRD32(adapter, QLCNIC_CRB_DEV_REF_COUNT);
+       act = QLCRD32(adapter, QLCNIC_CRB_DRV_ACTIVE);
 
        if (((state & 0x11111111) == (act & 0x11111111)) ||
                        ((act & 0x11111111) == ((state >> 1) & 0x11111111)))
@@ -2325,10 +2654,10 @@ qlcnic_can_start_firmware(struct qlcnic_adapter *adapter)
        if (qlcnic_api_lock(adapter))
                return -1;
 
-       val = QLCRD32(adapter, QLCNIC_CRB_DEV_REF_COUNT);
+       val = QLCRD32(adapter, QLCNIC_CRB_DRV_ACTIVE);
        if (!(val & (1 << (portnum * 4)))) {
                QLC_DEV_SET_REF_CNT(val, portnum);
-               QLCWR32(adapter, QLCNIC_CRB_DEV_REF_COUNT, val);
+               QLCWR32(adapter, QLCNIC_CRB_DRV_ACTIVE, val);
        }
 
        prev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
@@ -2403,7 +2732,7 @@ qlcnic_fwinit_work(struct work_struct *work)
 {
        struct qlcnic_adapter *adapter = container_of(work,
                        struct qlcnic_adapter, fw_work.work);
-       u32 dev_state = 0xf, npar_state;
+       u32 dev_state = 0xf;
 
        if (qlcnic_api_lock(adapter))
                goto err_ret;
@@ -2417,16 +2746,8 @@ qlcnic_fwinit_work(struct work_struct *work)
        }
 
        if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC) {
-               npar_state = QLCRD32(adapter, QLCNIC_CRB_DEV_NPAR_STATE);
-               if (npar_state == QLCNIC_DEV_NPAR_RDY) {
-                       qlcnic_api_unlock(adapter);
-                       goto wait_npar;
-               } else {
-                       qlcnic_schedule_work(adapter, qlcnic_fwinit_work,
-                               FW_POLL_DELAY);
-                       qlcnic_api_unlock(adapter);
-                       return;
-               }
+               qlcnic_api_unlock(adapter);
+               goto wait_npar;
        }
 
        if (adapter->fw_wait_cnt++ > adapter->reset_ack_timeo) {
@@ -2463,6 +2784,7 @@ skip_ack_check:
 
                if (!adapter->nic_ops->start_firmware(adapter)) {
                        qlcnic_schedule_work(adapter, qlcnic_attach_work, 0);
+                       adapter->fw_wait_cnt = 0;
                        return;
                }
                goto err_ret;
@@ -2475,27 +2797,25 @@ wait_npar:
        QLCDB(adapter, HW, "Func waiting: Device state=%u\n", dev_state);
 
        switch (dev_state) {
-       case QLCNIC_DEV_QUISCENT:
-       case QLCNIC_DEV_NEED_QUISCENT:
-       case QLCNIC_DEV_NEED_RESET:
-               qlcnic_schedule_work(adapter,
-                       qlcnic_fwinit_work, FW_POLL_DELAY);
-               return;
-       case QLCNIC_DEV_FAILED:
-               break;
-
-       default:
+       case QLCNIC_DEV_READY:
                if (!adapter->nic_ops->start_firmware(adapter)) {
                        qlcnic_schedule_work(adapter, qlcnic_attach_work, 0);
+                       adapter->fw_wait_cnt = 0;
                        return;
                }
+       case QLCNIC_DEV_FAILED:
+               break;
+       default:
+               qlcnic_schedule_work(adapter,
+                       qlcnic_fwinit_work, FW_POLL_DELAY);
+               return;
        }
 
 err_ret:
        dev_err(&adapter->pdev->dev, "Fwinit work failed state=%u "
                "fw_wait_cnt=%u\n", dev_state, adapter->fw_wait_cnt);
        netif_device_attach(adapter->netdev);
-       qlcnic_clr_all_drv_state(adapter);
+       qlcnic_clr_all_drv_state(adapter, 0);
 }
 
 static void
@@ -2531,8 +2851,23 @@ err_ret:
        dev_err(&adapter->pdev->dev, "detach failed; status=%d temp=%d\n",
                        status, adapter->temp);
        netif_device_attach(netdev);
-       qlcnic_clr_all_drv_state(adapter);
+       qlcnic_clr_all_drv_state(adapter, 1);
+}
+
+/*Transit NPAR state to NON Operational */
+static void
+qlcnic_set_npar_non_operational(struct qlcnic_adapter *adapter)
+{
+       u32 state;
+
+       state = QLCRD32(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);
+       qlcnic_api_unlock(adapter);
 }
 
 /*Transit to RESET state from READY state only */
@@ -2553,6 +2888,7 @@ qlcnic_dev_request_reset(struct qlcnic_adapter *adapter)
                qlcnic_idc_debug_info(adapter, 0);
        }
 
+       QLCWR32(adapter, QLCNIC_CRB_DEV_NPAR_STATE, QLCNIC_DEV_NPAR_NON_OPER);
        qlcnic_api_unlock(adapter);
 }
 
@@ -2560,21 +2896,11 @@ qlcnic_dev_request_reset(struct qlcnic_adapter *adapter)
 static void
 qlcnic_dev_set_npar_ready(struct qlcnic_adapter *adapter)
 {
-       u32 state;
-
-       if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED) ||
-               adapter->op_mode == QLCNIC_NON_PRIV_FUNC)
-               return;
        if (qlcnic_api_lock(adapter))
                return;
 
-       state = QLCRD32(adapter, QLCNIC_CRB_DEV_NPAR_STATE);
-
-       if (state != QLCNIC_DEV_NPAR_RDY) {
-               QLCWR32(adapter, QLCNIC_CRB_DEV_NPAR_STATE,
-                       QLCNIC_DEV_NPAR_RDY);
-               QLCDB(adapter, DRV, "NPAR READY state set\n");
-       }
+       QLCWR32(adapter, QLCNIC_CRB_DEV_NPAR_STATE, QLCNIC_DEV_NPAR_OPER);
+       QLCDB(adapter, DRV, "NPAR operational state set\n");
 
        qlcnic_api_unlock(adapter);
 }
@@ -2605,7 +2931,21 @@ qlcnic_attach_work(struct work_struct *work)
        struct qlcnic_adapter *adapter = container_of(work,
                                struct qlcnic_adapter, fw_work.work);
        struct net_device *netdev = adapter->netdev;
+       u32 npar_state;
 
+       if (adapter->op_mode != QLCNIC_MGMT_FUNC) {
+               npar_state = QLCRD32(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)
+                       qlcnic_schedule_work(adapter, qlcnic_attach_work,
+                                                       FW_POLL_DELAY);
+               else
+                       goto attach;
+               QLCDB(adapter, DRV, "Waiting for NPAR state to operational\n");
+               return;
+       }
+attach:
        if (netif_running(netdev)) {
                if (qlcnic_up(adapter, netdev))
                        goto done;
@@ -2626,7 +2966,7 @@ done:
 static int
 qlcnic_check_health(struct qlcnic_adapter *adapter)
 {
-       u32 state = 0, heartbit;
+       u32 state = 0, heartbeat;
        struct net_device *netdev = adapter->netdev;
 
        if (qlcnic_check_temp(adapter))
@@ -2636,12 +2976,15 @@ qlcnic_check_health(struct qlcnic_adapter *adapter)
                qlcnic_dev_request_reset(adapter);
 
        state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
-       if (state == QLCNIC_DEV_NEED_RESET || state == QLCNIC_DEV_NEED_QUISCENT)
+       if (state == QLCNIC_DEV_NEED_RESET ||
+           state == QLCNIC_DEV_NEED_QUISCENT) {
+               qlcnic_set_npar_non_operational(adapter);
                adapter->need_fw_reset = 1;
+       }
 
-       heartbit = QLCRD32(adapter, QLCNIC_PEG_ALIVE_COUNTER);
-       if (heartbit != adapter->heartbit) {
-               adapter->heartbit = heartbit;
+       heartbeat = QLCRD32(adapter, QLCNIC_PEG_ALIVE_COUNTER);
+       if (heartbeat != adapter->heartbeat) {
+               adapter->heartbeat = heartbeat;
                adapter->fw_fail_cnt = 0;
                if (adapter->need_fw_reset)
                        goto detach;
@@ -2692,6 +3035,9 @@ qlcnic_fw_poll_work(struct work_struct *work)
        if (qlcnic_check_health(adapter))
                return;
 
+       if (adapter->fhash.fnum)
+               qlcnic_prune_lb_filters(adapter);
+
 reschedule:
        qlcnic_schedule_work(adapter, qlcnic_fw_poll_work, FW_POLL_DELAY);
 }
@@ -2738,7 +3084,7 @@ static int qlcnic_attach_func(struct pci_dev *pdev)
        if (qlcnic_api_lock(adapter))
                return -EINVAL;
 
-       if (first_func) {
+       if (adapter->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);
@@ -2756,7 +3102,7 @@ static int qlcnic_attach_func(struct pci_dev *pdev)
        if (netif_running(netdev)) {
                err = qlcnic_attach(adapter);
                if (err) {
-                       qlcnic_clr_all_drv_state(adapter);
+                       qlcnic_clr_all_drv_state(adapter, 1);
                        clear_bit(__QLCNIC_AER, &adapter->state);
                        netif_device_attach(netdev);
                        return err;
@@ -2822,7 +3168,6 @@ static void qlcnic_io_resume(struct pci_dev *pdev)
                                                FW_POLL_DELAY);
 }
 
-
 static int
 qlcnicvf_start_firmware(struct qlcnic_adapter *adapter)
 {
@@ -2832,8 +3177,20 @@ qlcnicvf_start_firmware(struct qlcnic_adapter *adapter)
        if (err)
                return err;
 
+       err = qlcnic_check_npar_opertional(adapter);
+       if (err)
+               return err;
+
+       err = qlcnic_initialize_nic(adapter);
+       if (err)
+               return err;
+
        qlcnic_check_options(adapter);
 
+       err = qlcnic_set_eswitch_port_config(adapter);
+       if (err)
+               return err;
+
        adapter->need_fw_reset = 0;
 
        return err;
@@ -3093,9 +3450,6 @@ validate_pm_config(struct qlcnic_adapter *adapter,
                if (adapter->npars[dest_pci_func].type != QLCNIC_TYPE_NIC)
                        return QL_STATUS_INVALID_PARAM;
 
-               if (!IS_VALID_MODE(pm_cfg[i].action))
-                       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;
 
@@ -3129,7 +3483,7 @@ qlcnic_sysfs_write_pm_config(struct file *filp, struct kobject *kobj,
                return ret;
        for (i = 0; i < count; i++) {
                pci_func = pm_cfg[i].pci_func;
-               action = pm_cfg[i].action;
+               action = !!pm_cfg[i].action;
                id = adapter->npars[pci_func].phy_port;
                ret = qlcnic_config_port_mirroring(adapter, id,
                                                action, pci_func);
@@ -3140,7 +3494,7 @@ qlcnic_sysfs_write_pm_config(struct file *filp, struct kobject *kobj,
        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].enable_pm = !!pm_cfg[i].action;
                adapter->npars[pci_func].dest_npar = id;
        }
        return size;
@@ -3172,30 +3526,45 @@ qlcnic_sysfs_read_pm_config(struct file *filp, struct kobject *kobj,
 
 static int
 validate_esw_config(struct qlcnic_adapter *adapter,
-                       struct qlcnic_esw_func_cfg *esw_cfg, int count)
+       struct qlcnic_esw_func_cfg *esw_cfg, int count)
 {
+       u32 op_mode;
        u8 pci_func;
        int i;
 
+       op_mode = readl(adapter->ahw.pci_base0 + QLCNIC_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->npars[i].type != QLCNIC_TYPE_NIC)
-                       return QL_STATUS_INVALID_PARAM;
+               if (adapter->op_mode == QLCNIC_MGMT_FUNC)
+                       if (adapter->npars[pci_func].type != QLCNIC_TYPE_NIC)
+                               return QL_STATUS_INVALID_PARAM;
 
-               if (esw_cfg->host_vlan_tag == 1)
+               switch (esw_cfg[i].op_mode) {
+               case QLCNIC_PORT_DEFAULTS:
+                       if (QLC_DEV_GET_DRV(op_mode, pci_func) !=
+                                               QLCNIC_NON_PRIV_FUNC) {
+                               esw_cfg[i].mac_anti_spoof = 0;
+                               esw_cfg[i].mac_override = 1;
+                       }
+                       break;
+               case QLCNIC_ADD_VLAN:
                        if (!IS_VALID_VLAN(esw_cfg[i].vlan_id))
                                return QL_STATUS_INVALID_PARAM;
-
-               if (!IS_VALID_MODE(esw_cfg[i].promisc_mode)
-                               || !IS_VALID_MODE(esw_cfg[i].host_vlan_tag)
-                               || !IS_VALID_MODE(esw_cfg[i].mac_learning)
-                               || !IS_VALID_MODE(esw_cfg[i].discard_tagged))
+                       if (!esw_cfg[i].op_type)
+                               return QL_STATUS_INVALID_PARAM;
+                       break;
+               case QLCNIC_DEL_VLAN:
+                       if (!esw_cfg[i].op_type)
+                               return QL_STATUS_INVALID_PARAM;
+                       break;
+               default:
                        return QL_STATUS_INVALID_PARAM;
+               }
        }
-
        return 0;
 }
 
@@ -3206,8 +3575,9 @@ qlcnic_sysfs_write_esw_config(struct file *file, struct kobject *kobj,
        struct device *dev = container_of(kobj, struct device, kobj);
        struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
        struct qlcnic_esw_func_cfg *esw_cfg;
+       struct qlcnic_npar_info *npar;
        int count, rem, i, ret;
-       u8 id, pci_func;
+       u8 pci_func, op_mode = 0;
 
        count   = size / sizeof(struct qlcnic_esw_func_cfg);
        rem     = size % sizeof(struct qlcnic_esw_func_cfg);
@@ -3220,30 +3590,55 @@ qlcnic_sysfs_write_esw_config(struct file *file, struct kobject *kobj,
                return ret;
 
        for (i = 0; i < count; i++) {
-               pci_func = esw_cfg[i].pci_func;
-               id = adapter->npars[pci_func].phy_port;
-               ret = qlcnic_config_switch_port(adapter, id,
-                                               esw_cfg[i].host_vlan_tag,
-                                               esw_cfg[i].discard_tagged,
-                                               esw_cfg[i].promisc_mode,
-                                               esw_cfg[i].mac_learning,
-                                               esw_cfg[i].pci_func,
-                                               esw_cfg[i].vlan_id);
-               if (ret)
-                       return ret;
+               if (adapter->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;
+
+               op_mode = esw_cfg[i].op_mode;
+               qlcnic_get_eswitch_port_config(adapter, &esw_cfg[i]);
+               esw_cfg[i].op_mode = op_mode;
+               esw_cfg[i].pci_func = adapter->ahw.pci_func;
+
+               switch (esw_cfg[i].op_mode) {
+               case QLCNIC_PORT_DEFAULTS:
+                       qlcnic_set_eswitch_port_features(adapter, &esw_cfg[i]);
+                       break;
+               case QLCNIC_ADD_VLAN:
+                       qlcnic_set_vlan_config(adapter, &esw_cfg[i]);
+                       break;
+               case QLCNIC_DEL_VLAN:
+                       esw_cfg[i].vlan_id = 0;
+                       qlcnic_set_vlan_config(adapter, &esw_cfg[i]);
+                       break;
+               }
        }
 
+       if (adapter->op_mode != QLCNIC_MGMT_FUNC)
+               goto out;
+
        for (i = 0; i < count; i++) {
                pci_func = esw_cfg[i].pci_func;
-               adapter->npars[pci_func].promisc_mode = esw_cfg[i].promisc_mode;
-               adapter->npars[pci_func].mac_learning = esw_cfg[i].mac_learning;
-               adapter->npars[pci_func].vlan_id = esw_cfg[i].vlan_id;
-               adapter->npars[pci_func].discard_tagged =
-                                               esw_cfg[i].discard_tagged;
-               adapter->npars[pci_func].host_vlan_tag =
-                                               esw_cfg[i].host_vlan_tag;
+               npar = &adapter->npars[pci_func];
+               switch (esw_cfg[i].op_mode) {
+               case QLCNIC_PORT_DEFAULTS:
+                       npar->promisc_mode = esw_cfg[i].promisc_mode;
+                       npar->mac_override = esw_cfg[i].mac_override;
+                       npar->offload_flags = esw_cfg[i].offload_flags;
+                       npar->mac_anti_spoof = esw_cfg[i].mac_anti_spoof;
+                       npar->discard_tagged = esw_cfg[i].discard_tagged;
+                       break;
+               case QLCNIC_ADD_VLAN:
+                       npar->pvid = esw_cfg[i].vlan_id;
+                       break;
+               case QLCNIC_DEL_VLAN:
+                       npar->pvid = 0;
+                       break;
+               }
        }
-
+out:
        return size;
 }
 
@@ -3254,7 +3649,7 @@ qlcnic_sysfs_read_esw_config(struct file *file, struct kobject *kobj,
        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];
-       int i;
+       u8 i;
 
        if (size != sizeof(esw_cfg))
                return QL_STATUS_INVALID_PARAM;
@@ -3262,12 +3657,9 @@ qlcnic_sysfs_read_esw_config(struct file *file, struct kobject *kobj,
        for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
                if (adapter->npars[i].type != QLCNIC_TYPE_NIC)
                        continue;
-
-               esw_cfg[i].host_vlan_tag = adapter->npars[i].host_vlan_tag;
-               esw_cfg[i].promisc_mode = adapter->npars[i].promisc_mode;
-               esw_cfg[i].discard_tagged = adapter->npars[i].discard_tagged;
-               esw_cfg[i].vlan_id = adapter->npars[i].vlan_id;
-               esw_cfg[i].mac_learning = adapter->npars[i].mac_learning;
+               esw_cfg[i].pci_func = i;
+               if (qlcnic_get_eswitch_port_config(adapter, &esw_cfg[i]))
+                       return QL_STATUS_INVALID_PARAM;
        }
        memcpy(buf, &esw_cfg, size);
 
@@ -3369,6 +3761,115 @@ qlcnic_sysfs_read_npar_config(struct file *file, struct kobject *kobj,
        return size;
 }
 
+static ssize_t
+qlcnic_sysfs_get_port_stats(struct file *file, struct kobject *kobj,
+       struct bin_attribute *attr, 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);
+       struct qlcnic_esw_statistics port_stats;
+       int ret;
+
+       if (size != sizeof(struct qlcnic_esw_statistics))
+               return QL_STATUS_INVALID_PARAM;
+
+       if (offset >= QLCNIC_MAX_PCI_FUNC)
+               return QL_STATUS_INVALID_PARAM;
+
+       memset(&port_stats, 0, size);
+       ret = qlcnic_get_port_stats(adapter, offset, QLCNIC_QUERY_RX_COUNTER,
+                                                               &port_stats.rx);
+       if (ret)
+               return ret;
+
+       ret = qlcnic_get_port_stats(adapter, offset, QLCNIC_QUERY_TX_COUNTER,
+                                                               &port_stats.tx);
+       if (ret)
+               return ret;
+
+       memcpy(buf, &port_stats, size);
+       return size;
+}
+
+static ssize_t
+qlcnic_sysfs_get_esw_stats(struct file *file, struct kobject *kobj,
+       struct bin_attribute *attr, 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);
+       struct qlcnic_esw_statistics esw_stats;
+       int ret;
+
+       if (size != sizeof(struct qlcnic_esw_statistics))
+               return QL_STATUS_INVALID_PARAM;
+
+       if (offset >= QLCNIC_NIU_MAX_XG_PORTS)
+               return QL_STATUS_INVALID_PARAM;
+
+       memset(&esw_stats, 0, size);
+       ret = qlcnic_get_eswitch_stats(adapter, offset, QLCNIC_QUERY_RX_COUNTER,
+                                                               &esw_stats.rx);
+       if (ret)
+               return ret;
+
+       ret = qlcnic_get_eswitch_stats(adapter, offset, QLCNIC_QUERY_TX_COUNTER,
+                                                               &esw_stats.tx);
+       if (ret)
+               return ret;
+
+       memcpy(buf, &esw_stats, size);
+       return size;
+}
+
+static ssize_t
+qlcnic_sysfs_clear_esw_stats(struct file *file, struct kobject *kobj,
+       struct bin_attribute *attr, 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 (offset >= QLCNIC_NIU_MAX_XG_PORTS)
+               return QL_STATUS_INVALID_PARAM;
+
+       ret = qlcnic_clear_esw_stats(adapter, QLCNIC_STATS_ESWITCH, offset,
+                                               QLCNIC_QUERY_RX_COUNTER);
+       if (ret)
+               return ret;
+
+       ret = qlcnic_clear_esw_stats(adapter, QLCNIC_STATS_ESWITCH, offset,
+                                               QLCNIC_QUERY_TX_COUNTER);
+       if (ret)
+               return ret;
+
+       return size;
+}
+
+static ssize_t
+qlcnic_sysfs_clear_port_stats(struct file *file, struct kobject *kobj,
+       struct bin_attribute *attr, 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 (offset >= QLCNIC_MAX_PCI_FUNC)
+               return QL_STATUS_INVALID_PARAM;
+
+       ret = qlcnic_clear_esw_stats(adapter, QLCNIC_STATS_PORT, offset,
+                                               QLCNIC_QUERY_RX_COUNTER);
+       if (ret)
+               return ret;
+
+       ret = qlcnic_clear_esw_stats(adapter, QLCNIC_STATS_PORT, offset,
+                                               QLCNIC_QUERY_TX_COUNTER);
+       if (ret)
+               return ret;
+
+       return size;
+}
+
 static ssize_t
 qlcnic_sysfs_read_pci_config(struct file *file, struct kobject *kobj,
        struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
@@ -3418,6 +3919,20 @@ static struct bin_attribute bin_attr_pci_config = {
        .write = NULL,
 };
 
+static struct bin_attribute bin_attr_port_stats = {
+       .attr = {.name = "port_stats", .mode = (S_IRUGO | S_IWUSR)},
+       .size = 0,
+       .read = qlcnic_sysfs_get_port_stats,
+       .write = qlcnic_sysfs_clear_port_stats,
+};
+
+static struct bin_attribute bin_attr_esw_stats = {
+       .attr = {.name = "esw_stats", .mode = (S_IRUGO | S_IWUSR)},
+       .size = 0,
+       .read = qlcnic_sysfs_get_esw_stats,
+       .write = qlcnic_sysfs_clear_esw_stats,
+};
+
 static struct bin_attribute bin_attr_esw_config = {
        .attr = {.name = "esw_config", .mode = (S_IRUGO | S_IWUSR)},
        .size = 0,
@@ -3457,6 +3972,9 @@ qlcnic_create_diag_entries(struct qlcnic_adapter *adapter)
 {
        struct device *dev = &adapter->pdev->dev;
 
+       if (device_create_bin_file(dev, &bin_attr_port_stats))
+               dev_info(dev, "failed to create port stats sysfs entry");
+
        if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC)
                return;
        if (device_create_file(dev, &dev_attr_diag_mode))
@@ -3465,18 +3983,20 @@ qlcnic_create_diag_entries(struct qlcnic_adapter *adapter)
                dev_info(dev, "failed to create crb sysfs entry\n");
        if (device_create_bin_file(dev, &bin_attr_mem))
                dev_info(dev, "failed to create mem sysfs entry\n");
-       if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED) ||
-                       adapter->op_mode != QLCNIC_MGMT_FUNC)
+       if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
+               return;
+       if (device_create_bin_file(dev, &bin_attr_esw_config))
+               dev_info(dev, "failed to create esw config sysfs entry");
+       if (adapter->op_mode != QLCNIC_MGMT_FUNC)
                return;
        if (device_create_bin_file(dev, &bin_attr_pci_config))
                dev_info(dev, "failed to create pci config sysfs entry");
        if (device_create_bin_file(dev, &bin_attr_npar_config))
                dev_info(dev, "failed to create npar config sysfs entry");
-       if (device_create_bin_file(dev, &bin_attr_esw_config))
-               dev_info(dev, "failed to create esw config sysfs entry");
        if (device_create_bin_file(dev, &bin_attr_pm_config))
                dev_info(dev, "failed to create pm config sysfs entry");
-
+       if (device_create_bin_file(dev, &bin_attr_esw_stats))
+               dev_info(dev, "failed to create eswitch stats sysfs entry");
 }
 
 static void
@@ -3484,18 +4004,22 @@ qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter)
 {
        struct device *dev = &adapter->pdev->dev;
 
+       device_remove_bin_file(dev, &bin_attr_port_stats);
+
        if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC)
                return;
        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 (!(adapter->flags & QLCNIC_ESWITCH_ENABLED) ||
-                       adapter->op_mode != QLCNIC_MGMT_FUNC)
+       if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
+               return;
+       device_remove_bin_file(dev, &bin_attr_esw_config);
+       if (adapter->op_mode != QLCNIC_MGMT_FUNC)
                return;
        device_remove_bin_file(dev, &bin_attr_pci_config);
        device_remove_bin_file(dev, &bin_attr_npar_config);
-       device_remove_bin_file(dev, &bin_attr_esw_config);
        device_remove_bin_file(dev, &bin_attr_pm_config);
+       device_remove_bin_file(dev, &bin_attr_esw_stats);
 }
 
 #ifdef CONFIG_INET
index 5f89e83501f4f5c1892ac15a84681a76ade08c19..4ffebe83d883f2c23a828411a87c74a9c5dcfb81 100644 (file)
@@ -1566,7 +1566,7 @@ static void ql_process_mac_rx_page(struct ql_adapter *qdev,
        rx_ring->rx_packets++;
        rx_ring->rx_bytes += skb->len;
        skb->protocol = eth_type_trans(skb, ndev);
-       skb->ip_summed = CHECKSUM_NONE;
+       skb_checksum_none_assert(skb);
 
        if (qdev->rx_csum &&
                !(ib_mac_rsp->flags1 & IB_MAC_CSUM_ERR_MASK)) {
@@ -1676,7 +1676,7 @@ static void ql_process_mac_rx_skb(struct ql_adapter *qdev,
        rx_ring->rx_packets++;
        rx_ring->rx_bytes += skb->len;
        skb->protocol = eth_type_trans(skb, ndev);
-       skb->ip_summed = CHECKSUM_NONE;
+       skb_checksum_none_assert(skb);
 
        /* If rx checksum is on, and there are no
         * csum or frame errors.
@@ -1996,7 +1996,7 @@ static void ql_process_mac_split_rx_intr(struct ql_adapter *qdev,
        }
 
        skb->protocol = eth_type_trans(skb, ndev);
-       skb->ip_summed = CHECKSUM_NONE;
+       skb_checksum_none_assert(skb);
 
        /* If rx checksum is on, and there are no
         * csum or frame errors.
@@ -2222,10 +2222,11 @@ static int ql_clean_outbound_rx_ring(struct rx_ring *rx_ring)
                ql_update_cq(rx_ring);
                prod = ql_read_sh_reg(rx_ring->prod_idx_sh_reg);
        }
+       if (!net_rsp)
+               return 0;
        ql_write_cq_idx(rx_ring);
        tx_ring = &qdev->tx_ring[net_rsp->txq_idx];
-       if (__netif_subqueue_stopped(qdev->ndev, tx_ring->wq_id) &&
-                                       net_rsp != NULL) {
+       if (__netif_subqueue_stopped(qdev->ndev, tx_ring->wq_id)) {
                if (atomic_read(&tx_ring->queue_stopped) &&
                    (atomic_read(&tx_ring->tx_count) > (tx_ring->wq_len / 4)))
                        /*
@@ -3888,11 +3889,8 @@ int ql_wol(struct ql_adapter *qdev)
        return status;
 }
 
-static int ql_adapter_down(struct ql_adapter *qdev)
+static void ql_cancel_all_work_sync(struct ql_adapter *qdev)
 {
-       int i, status = 0;
-
-       ql_link_off(qdev);
 
        /* Don't kill the reset worker thread if we
         * are in the process of recovery.
@@ -3904,6 +3902,15 @@ static int ql_adapter_down(struct ql_adapter *qdev)
        cancel_delayed_work_sync(&qdev->mpi_idc_work);
        cancel_delayed_work_sync(&qdev->mpi_core_to_log);
        cancel_delayed_work_sync(&qdev->mpi_port_cfg_work);
+}
+
+static int ql_adapter_down(struct ql_adapter *qdev)
+{
+       int i, status = 0;
+
+       ql_link_off(qdev);
+
+       ql_cancel_all_work_sync(qdev);
 
        for (i = 0; i < qdev->rss_ring_count; i++)
                napi_disable(&qdev->rx_ring[i].napi);
@@ -4726,6 +4733,7 @@ static void __devexit qlge_remove(struct pci_dev *pdev)
        struct net_device *ndev = pci_get_drvdata(pdev);
        struct ql_adapter *qdev = netdev_priv(ndev);
        del_timer_sync(&qdev->timer);
+       ql_cancel_all_work_sync(qdev);
        unregister_netdev(ndev);
        ql_release_all(pdev);
        pci_disable_device(pdev);
@@ -4745,13 +4753,7 @@ static void ql_eeh_close(struct net_device *ndev)
 
        /* Disabling the timer */
        del_timer_sync(&qdev->timer);
-       if (test_bit(QL_ADAPTER_UP, &qdev->flags))
-               cancel_delayed_work_sync(&qdev->asic_reset_work);
-       cancel_delayed_work_sync(&qdev->mpi_reset_work);
-       cancel_delayed_work_sync(&qdev->mpi_work);
-       cancel_delayed_work_sync(&qdev->mpi_idc_work);
-       cancel_delayed_work_sync(&qdev->mpi_core_to_log);
-       cancel_delayed_work_sync(&qdev->mpi_port_cfg_work);
+       ql_cancel_all_work_sync(qdev);
 
        for (i = 0; i < qdev->rss_ring_count; i++)
                netif_napi_del(&qdev->rx_ring[i].napi);
index 142c381e1d73e0644eac3df74fea212385ad1115..63db065508f4e6da9b03c94dd8f70549f5fda1d9 100644 (file)
@@ -200,7 +200,7 @@ struct r6040_private {
        int old_duplex;
 };
 
-static char version[] __devinitdata = KERN_INFO DRV_NAME
+static char version[] __devinitdata = DRV_NAME
        ": RDC R6040 NAPI net driver,"
        "version "DRV_VERSION " (" DRV_RELDATE ")";
 
@@ -224,7 +224,8 @@ static int r6040_phy_read(void __iomem *ioaddr, int phy_addr, int reg)
 }
 
 /* Write a word data from PHY Chip */
-static void r6040_phy_write(void __iomem *ioaddr, int phy_addr, int reg, u16 val)
+static void r6040_phy_write(void __iomem *ioaddr,
+                                       int phy_addr, int reg, u16 val)
 {
        int limit = 2048;
        u16 cmd;
@@ -348,8 +349,8 @@ static int r6040_alloc_rxbufs(struct net_device *dev)
                }
                desc->skb_ptr = skb;
                desc->buf = cpu_to_le32(pci_map_single(lp->pdev,
-                                               desc->skb_ptr->data,
-                                               MAX_BUF_SIZE, PCI_DMA_FROMDEVICE));
+                                       desc->skb_ptr->data,
+                                       MAX_BUF_SIZE, PCI_DMA_FROMDEVICE));
                desc->status = DSC_OWNER_MAC;
                desc = desc->vndescp;
        } while (desc != lp->rx_ring);
@@ -491,12 +492,14 @@ static int r6040_close(struct net_device *dev)
 
        /* Free Descriptor memory */
        if (lp->rx_ring) {
-               pci_free_consistent(pdev, RX_DESC_SIZE, lp->rx_ring, lp->rx_ring_dma);
+               pci_free_consistent(pdev,
+                               RX_DESC_SIZE, lp->rx_ring, lp->rx_ring_dma);
                lp->rx_ring = NULL;
        }
 
        if (lp->tx_ring) {
-               pci_free_consistent(pdev, TX_DESC_SIZE, lp->tx_ring, lp->tx_ring_dma);
+               pci_free_consistent(pdev,
+                               TX_DESC_SIZE, lp->tx_ring, lp->tx_ring_dma);
                lp->tx_ring = NULL;
        }
 
@@ -547,7 +550,7 @@ static int r6040_rx(struct net_device *dev, int limit)
                        }
                        goto next_descr;
                }
-               
+
                /* Packet successfully received */
                new_skb = netdev_alloc_skb(dev, MAX_BUF_SIZE);
                if (!new_skb) {
@@ -556,13 +559,13 @@ static int r6040_rx(struct net_device *dev, int limit)
                }
                skb_ptr = descptr->skb_ptr;
                skb_ptr->dev = priv->dev;
-               
+
                /* Do not count the CRC */
                skb_put(skb_ptr, descptr->len - 4);
                pci_unmap_single(priv->pdev, le32_to_cpu(descptr->buf),
                                        MAX_BUF_SIZE, PCI_DMA_FROMDEVICE);
                skb_ptr->protocol = eth_type_trans(skb_ptr, priv->dev);
-               
+
                /* Send to upper layer */
                netif_receive_skb(skb_ptr);
                dev->stats.rx_packets++;
@@ -710,8 +713,10 @@ static int r6040_up(struct net_device *dev)
                return ret;
 
        /* improve performance (by RDC guys) */
-       r6040_phy_write(ioaddr, 30, 17, (r6040_phy_read(ioaddr, 30, 17) | 0x4000));
-       r6040_phy_write(ioaddr, 30, 17, ~((~r6040_phy_read(ioaddr, 30, 17)) | 0x2000));
+       r6040_phy_write(ioaddr, 30, 17,
+                       (r6040_phy_read(ioaddr, 30, 17) | 0x4000));
+       r6040_phy_write(ioaddr, 30, 17,
+                       ~((~r6040_phy_read(ioaddr, 30, 17)) | 0x2000));
        r6040_phy_write(ioaddr, 0, 19, 0x0000);
        r6040_phy_write(ioaddr, 0, 30, 0x01F0);
 
@@ -751,7 +756,7 @@ static int r6040_open(struct net_device *dev)
        ret = request_irq(dev->irq, r6040_interrupt,
                IRQF_SHARED, dev->name, dev);
        if (ret)
-               return ret;
+               goto out;
 
        /* Set MAC address */
        r6040_mac_address(dev);
@@ -759,30 +764,37 @@ static int r6040_open(struct net_device *dev)
        /* Allocate Descriptor memory */
        lp->rx_ring =
                pci_alloc_consistent(lp->pdev, RX_DESC_SIZE, &lp->rx_ring_dma);
-       if (!lp->rx_ring)
-               return -ENOMEM;
+       if (!lp->rx_ring) {
+               ret = -ENOMEM;
+               goto err_free_irq;
+       }
 
        lp->tx_ring =
                pci_alloc_consistent(lp->pdev, TX_DESC_SIZE, &lp->tx_ring_dma);
        if (!lp->tx_ring) {
-               pci_free_consistent(lp->pdev, RX_DESC_SIZE, lp->rx_ring,
-                                    lp->rx_ring_dma);
-               return -ENOMEM;
+               ret = -ENOMEM;
+               goto err_free_rx_ring;
        }
 
        ret = r6040_up(dev);
-       if (ret) {
-               pci_free_consistent(lp->pdev, TX_DESC_SIZE, lp->tx_ring,
-                                                       lp->tx_ring_dma);
-               pci_free_consistent(lp->pdev, RX_DESC_SIZE, lp->rx_ring,
-                                                       lp->rx_ring_dma);
-               return ret;
-       }
+       if (ret)
+               goto err_free_tx_ring;
 
        napi_enable(&lp->napi);
        netif_start_queue(dev);
 
        return 0;
+
+err_free_tx_ring:
+       pci_free_consistent(lp->pdev, TX_DESC_SIZE, lp->tx_ring,
+                       lp->tx_ring_dma);
+err_free_rx_ring:
+       pci_free_consistent(lp->pdev, RX_DESC_SIZE, lp->rx_ring,
+                       lp->rx_ring_dma);
+err_free_irq:
+       free_irq(dev->irq, dev);
+out:
+       return ret;
 }
 
 static netdev_tx_t r6040_start_xmit(struct sk_buff *skb,
@@ -946,7 +958,7 @@ static const struct net_device_ops r6040_netdev_ops = {
        .ndo_set_multicast_list = r6040_multicast_list,
        .ndo_change_mtu         = eth_change_mtu,
        .ndo_validate_addr      = eth_validate_addr,
-       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_set_mac_address    = eth_mac_addr,
        .ndo_do_ioctl           = r6040_ioctl,
        .ndo_tx_timeout         = r6040_tx_timeout,
 #ifdef CONFIG_NET_POLL_CONTROLLER
@@ -1039,7 +1051,7 @@ static int __devinit r6040_init_one(struct pci_dev *pdev,
        u16 *adrp;
        int i;
 
-       printk("%s\n", version);
+       pr_info("%s\n", version);
 
        err = pci_enable_device(pdev);
        if (err)
@@ -1113,7 +1125,8 @@ static int __devinit r6040_init_one(struct pci_dev *pdev,
        /* Some bootloader/BIOSes do not initialize
         * MAC address, warn about that */
        if (!(adrp[0] || adrp[1] || adrp[2])) {
-               netdev_warn(dev, "MAC address not initialized, generating random\n");
+               netdev_warn(dev, "MAC address not initialized, "
+                                       "generating random\n");
                random_ether_addr(dev->dev_addr);
        }
 
index 078bbf4e6f1933f3ee1e95e2c0dccfea92157088..54900332f12d87faf40386505b6f150fab86b1d0 100644 (file)
@@ -1076,7 +1076,12 @@ static int rtl8169_rx_vlan_skb(struct rtl8169_private *tp, struct RxDesc *desc,
        int ret;
 
        if (vlgrp && (opts2 & RxVlanTag)) {
-               __vlan_hwaccel_rx(skb, vlgrp, swab16(opts2 & 0xffff), polling);
+               u16 vtag = swab16(opts2 & 0xffff);
+
+               if (likely(polling))
+                       vlan_gro_receive(&tp->napi, vlgrp, vtag, skb);
+               else
+                       __vlan_hwaccel_rx(skb, vlgrp, vtag, polling);
                ret = 0;
        } else
                ret = -1;
@@ -3186,6 +3191,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 #ifdef CONFIG_R8169_VLAN
        dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
 #endif
+       dev->features |= NETIF_F_GRO;
 
        tp->intr_mask = 0xffff;
        tp->align = cfg->align;
@@ -4450,9 +4456,8 @@ static inline int rtl8169_fragmented_frame(u32 status)
        return (status & (FirstFrag | LastFrag)) != (FirstFrag | LastFrag);
 }
 
-static inline void rtl8169_rx_csum(struct sk_buff *skb, struct RxDesc *desc)
+static inline void rtl8169_rx_csum(struct sk_buff *skb, u32 opts1)
 {
-       u32 opts1 = le32_to_cpu(desc->opts1);
        u32 status = opts1 & RxProtoMask;
 
        if (((status == RxProtoTCP) && !(opts1 & TCPFail)) ||
@@ -4460,7 +4465,7 @@ static inline void rtl8169_rx_csum(struct sk_buff *skb, struct RxDesc *desc)
            ((status == RxProtoIP) && !(opts1 & IPFail)))
                skb->ip_summed = CHECKSUM_UNNECESSARY;
        else
-               skb->ip_summed = CHECKSUM_NONE;
+               skb_checksum_none_assert(skb);
 }
 
 static inline bool rtl8169_try_rx_copy(struct sk_buff **sk_buff,
@@ -4546,8 +4551,6 @@ static int rtl8169_rx_interrupt(struct net_device *dev,
                                continue;
                        }
 
-                       rtl8169_rx_csum(skb, desc);
-
                        if (rtl8169_try_rx_copy(&skb, tp, pkt_size, addr)) {
                                pci_dma_sync_single_for_device(pdev, addr,
                                        pkt_size, PCI_DMA_FROMDEVICE);
@@ -4558,12 +4561,13 @@ static int rtl8169_rx_interrupt(struct net_device *dev,
                                tp->Rx_skbuff[entry] = NULL;
                        }
 
+                       rtl8169_rx_csum(skb, status);
                        skb_put(skb, pkt_size);
                        skb->protocol = eth_type_trans(skb, dev);
 
                        if (rtl8169_rx_vlan_skb(tp, desc, skb, polling) < 0) {
                                if (likely(polling))
-                                       netif_receive_skb(skb);
+                                       napi_gro_receive(&tp->napi, skb);
                                else
                                        netif_rx(skb);
                        }
index e26e107f93e0c4ee18156a3c188bdc673c7c3691..e68c941926f16cf44feebe7ef103947592b0263e 100644 (file)
@@ -1245,7 +1245,7 @@ static int rr_open(struct net_device *dev)
        init_timer(&rrpriv->timer);
        rrpriv->timer.expires = RUN_AT(5*HZ);           /* 5 sec. watchdog */
        rrpriv->timer.data = (unsigned long)dev;
-       rrpriv->timer.function = &rr_timer;               /* timer handler */
+       rrpriv->timer.function = rr_timer;               /* timer handler */
        add_timer(&rrpriv->timer);
 
        netif_start_queue(dev);
index 18bc5b718bbb51875dd5e2fbf14be6f626d0fa88..c70ad515383add23bbac3a489d197b5245d4e091 100644 (file)
@@ -38,8 +38,6 @@
  * Tx descriptors that can be associated with each corresponding FIFO.
  * intr_type: This defines the type of interrupt. The values can be 0(INTA),
  *     2(MSI_X). Default value is '2(MSI_X)'
- * lro: Specifies whether to enable Large Receive Offload (LRO) or not.
- *     Possible values '1' for enable '0' for disable. Default is '0'
  * lro_max_pkts: This parameter defines maximum number of packets can be
  *     aggregated as a single large packet
  * napi: This parameter used to enable/disable NAPI (polling Rx)
@@ -90,7 +88,7 @@
 #include "s2io.h"
 #include "s2io-regs.h"
 
-#define DRV_VERSION "2.0.26.26"
+#define DRV_VERSION "2.0.26.27"
 
 /* S2io Driver name & version. */
 static char s2io_driver_name[] = "Neterion";
@@ -496,8 +494,6 @@ S2IO_PARM_INT(rxsync_frequency, 3);
 /* Interrupt type. Values can be 0(INTA), 2(MSI_X) */
 S2IO_PARM_INT(intr_type, 2);
 /* Large receive offload feature */
-static unsigned int lro_enable = 1;
-module_param_named(lro, lro_enable, uint, 0);
 
 /* Max pkts to be aggregated by LRO at one time. If not specified,
  * aggregation happens until we hit max IP pkt size(64K)
@@ -5124,8 +5120,6 @@ static void s2io_set_multicast(struct net_device *dev)
                /* Create the new Rx filter list and update the same in H/W. */
                i = 0;
                netdev_for_each_mc_addr(ha, dev) {
-                       memcpy(sp->usr_addrs[i].addr, ha->addr,
-                              ETH_ALEN);
                        mac_addr = 0;
                        for (j = 0; j < ETH_ALEN; j++) {
                                mac_addr |= ha->addr[j];
@@ -6735,13 +6729,10 @@ static int s2io_ethtool_set_flags(struct net_device *dev, u32 data)
                return -EINVAL;
 
        if (data & ETH_FLAG_LRO) {
-               if (lro_enable) {
-                       if (!(dev->features & NETIF_F_LRO)) {
-                               dev->features |= NETIF_F_LRO;
-                               changed = 1;
-                       }
-               } else
-                       rc = -EINVAL;
+               if (!(dev->features & NETIF_F_LRO)) {
+                       dev->features |= NETIF_F_LRO;
+                       changed = 1;
+               }
        } else if (dev->features & NETIF_F_LRO) {
                dev->features &= ~NETIF_F_LRO;
                changed = 1;
@@ -6750,7 +6741,6 @@ static int s2io_ethtool_set_flags(struct net_device *dev, u32 data)
        if (changed && netif_running(dev)) {
                s2io_stop_all_tx_queue(sp);
                s2io_card_down(sp);
-               sp->lro = !!(dev->features & NETIF_F_LRO);
                rc = s2io_card_up(sp);
                if (rc)
                        s2io_reset(sp);
@@ -7307,7 +7297,7 @@ static int s2io_card_up(struct s2io_nic *sp)
                struct ring_info *ring = &mac_control->rings[i];
 
                ring->mtu = dev->mtu;
-               ring->lro = sp->lro;
+               ring->lro = !!(dev->features & NETIF_F_LRO);
                ret = fill_rx_buffers(sp, ring, 1);
                if (ret) {
                        DBG_PRINT(ERR_DBG, "%s: Out of memory in Open\n",
@@ -7341,7 +7331,7 @@ static int s2io_card_up(struct s2io_nic *sp)
        /* Setting its receive mode */
        s2io_set_multicast(dev);
 
-       if (sp->lro) {
+       if (dev->features & NETIF_F_LRO) {
                /* Initialize max aggregatable pkts per session based on MTU */
                sp->lro_max_aggr_per_sess = ((1<<16) - 1) / dev->mtu;
                /* Check if we can use (if specified) user provided value */
@@ -7613,10 +7603,10 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp)
                         * Packet with erroneous checksum, let the
                         * upper layers deal with it.
                         */
-                       skb->ip_summed = CHECKSUM_NONE;
+                       skb_checksum_none_assert(skb);
                }
        } else
-               skb->ip_summed = CHECKSUM_NONE;
+               skb_checksum_none_assert(skb);
 
        swstats->mem_freed += skb->truesize;
 send_up:
@@ -7911,7 +7901,6 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
        else
                sp->device_type = XFRAME_I_DEVICE;
 
-       sp->lro = lro_enable;
 
        /* Initialize some PCI/PCI-X fields of the NIC. */
        s2io_init_pci(sp);
@@ -8047,8 +8036,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
        dev->netdev_ops = &s2io_netdev_ops;
        SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
        dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
-       if (lro_enable)
-               dev->features |= NETIF_F_LRO;
+       dev->features |= NETIF_F_LRO;
        dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
        if (sp->high_dma_flag == true)
                dev->features |= NETIF_F_HIGHDMA;
@@ -8283,9 +8271,8 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
                          dev->name);
        }
 
-       if (sp->lro)
-               DBG_PRINT(ERR_DBG, "%s: Large receive offload enabled\n",
-                         dev->name);
+       DBG_PRINT(ERR_DBG, "%s: Large receive offload enabled\n",
+                 dev->name);
        if (ufo)
                DBG_PRINT(ERR_DBG,
                          "%s: UDP Fragmentation Offload(UFO) enabled\n",
index 0af0335339053f8512280077d66b0ab4f41a2941..00b8614efe48bcac4e85c88dbd11d2cfdc65b5ef 100644 (file)
@@ -816,12 +816,6 @@ struct mac_info {
        struct stat_block *stats_info;  /* Logical address of the stat block */
 };
 
-/* structure representing the user defined MAC addresses */
-struct usr_addr {
-       char addr[ETH_ALEN];
-       int usage_cnt;
-};
-
 /* Default Tunable parameters of the NIC. */
 #define DEFAULT_FIFO_0_LEN 4096
 #define DEFAULT_FIFO_1_7_LEN 512
@@ -894,9 +888,7 @@ struct s2io_nic {
 #define ALL_MULTI   2
 
 #define MAX_ADDRS_SUPPORTED 64
-       u16 usr_addr_count;
        u16 mc_addr_count;
-       struct usr_addr usr_addrs[256];
 
        u16 m_cast_flg;
        u16 all_multi_pos;
@@ -971,7 +963,6 @@ struct s2io_nic {
 
        unsigned long   clubbed_frms_cnt;
        unsigned long   sending_both;
-       u8              lro;
        u16             lro_max_aggr_per_sess;
        volatile unsigned long state;
        u64             general_int_mask;
index 8e6bd45b9f311f4ea4c164d6d2528455cb64ae8e..d8249d7653c6abdc108b87a1de3ff1ceb1ec05d4 100644 (file)
@@ -1170,7 +1170,7 @@ again:
                                                sb->ip_summed = CHECKSUM_UNNECESSARY;
                                                /* don't need to set sb->csum */
                                        } else {
-                                               sb->ip_summed = CHECKSUM_NONE;
+                                               skb_checksum_none_assert(sb);
                                        }
                                }
                                prefetch(sb->data);
index 8c4067af32b0fbc671d2d38652a09e0594268611..31b92f5f32cb60dc2a2404850a868ac00398ee97 100644 (file)
@@ -1251,16 +1251,6 @@ static int sc92031_ethtool_set_settings(struct net_device *dev,
        return 0;
 }
 
-static void sc92031_ethtool_get_drvinfo(struct net_device *dev,
-               struct ethtool_drvinfo *drvinfo)
-{
-       struct sc92031_priv *priv = netdev_priv(dev);
-       struct pci_dev *pdev = priv->pdev;
-
-       strcpy(drvinfo->driver, SC92031_NAME);
-       strcpy(drvinfo->bus_info, pci_name(pdev));
-}
-
 static void sc92031_ethtool_get_wol(struct net_device *dev,
                struct ethtool_wolinfo *wolinfo)
 {
@@ -1382,7 +1372,6 @@ static void sc92031_ethtool_get_ethtool_stats(struct net_device *dev,
 static const struct ethtool_ops sc92031_ethtool_ops = {
        .get_settings           = sc92031_ethtool_get_settings,
        .set_settings           = sc92031_ethtool_set_settings,
-       .get_drvinfo            = sc92031_ethtool_get_drvinfo,
        .get_wol                = sc92031_ethtool_get_wol,
        .set_wol                = sc92031_ethtool_set_wol,
        .nway_reset             = sc92031_ethtool_nway_reset,
index 799c461ce7b850c91fbdbff627c4993880a43c43..acb372e841b293363c4adddb141f5ce9561a6cca 100644 (file)
@@ -615,7 +615,7 @@ void __efx_rx_packet(struct efx_channel *channel,
        EFX_BUG_ON_PARANOID(!skb);
 
        /* Set the SKB flags */
-       skb->ip_summed = CHECKSUM_NONE;
+       skb_checksum_none_assert(skb);
 
        /* Pass the packet up */
        netif_receive_skb(skb);
index 79fd02bc69fd0854f14e0fdac452980cd7fed74b..50259dfec5836772570d96f8bd402cd7a482a706 100644 (file)
@@ -798,7 +798,7 @@ static int sh_eth_rx(struct net_device *ndev)
                        skb->dev = ndev;
                        sh_eth_set_receive_align(skb);
 
-                       skb->ip_summed = CHECKSUM_NONE;
+                       skb_checksum_none_assert(skb);
                        rxdesc->addr = virt_to_phys(PTR_ALIGN(skb->data, 4));
                }
                if (entry >= RX_RING_SIZE - 1)
@@ -1031,7 +1031,7 @@ static int sh_eth_phy_init(struct net_device *ndev)
        mdp->duplex = -1;
 
        /* Try connect to PHY */
-       phydev = phy_connect(ndev, phy_id, &sh_eth_adjust_link,
+       phydev = phy_connect(ndev, phy_id, sh_eth_adjust_link,
                                0, PHY_INTERFACE_MODE_MII);
        if (IS_ERR(phydev)) {
                dev_err(&ndev->dev, "phy_connect failed\n");
index bbbded76ff14d28e561edeed2bfcfa6b91db7187..ffdd8591d4bc18b161509a78ff1627de22096e4e 100644 (file)
@@ -1042,7 +1042,7 @@ sis900_open(struct net_device *net_dev)
        init_timer(&sis_priv->timer);
        sis_priv->timer.expires = jiffies + HZ;
        sis_priv->timer.data = (unsigned long)net_dev;
-       sis_priv->timer.function = &sis900_timer;
+       sis_priv->timer.function = sis900_timer;
        add_timer(&sis_priv->timer);
 
        return 0;
index 40e5c46e7571ad46f1c7abf655d0235f89762bfd..a8a63581d63dfc913c567aa6aa2150fe23c641d0 100644 (file)
@@ -3178,8 +3178,7 @@ static int skge_poll(struct napi_struct *napi, int to_do)
 
                skb = skge_rx_get(dev, e, control, rd->status, rd->csum2);
                if (likely(skb)) {
-                       netif_receive_skb(skb);
-
+                       napi_gro_receive(napi, skb);
                        ++work_done;
                }
        }
@@ -3192,6 +3191,7 @@ static int skge_poll(struct napi_struct *napi, int to_do)
        if (work_done < to_do) {
                unsigned long flags;
 
+               napi_gro_flush(napi);
                spin_lock_irqsave(&hw->hw_lock, flags);
                __napi_complete(napi);
                hw->intr_mask |= napimask[skge->port];
@@ -3849,6 +3849,7 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port,
                dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
                skge->rx_csum = 1;
        }
+       dev->features |= NETIF_F_GRO;
 
        /* read the mac address */
        memcpy_fromio(dev->dev_addr, hw->regs + B2_MAC_1 + port*8, ETH_ALEN);
index fa434fb8fb7c087df16bacaf9108dfa3646e35db..38547a8938fe7e57edc3c5973adb43dc40ef19de 100644 (file)
@@ -271,7 +271,7 @@ static int sl_realloc_bufs(struct slip *sl, int mtu)
                        memcpy(sl->xbuff, sl->xhead, sl->xleft);
                } else  {
                        sl->xleft = 0;
-                       sl->tx_dropped++;
+                       dev->stats.tx_dropped++;
                }
        }
        sl->xhead = sl->xbuff;
@@ -281,7 +281,7 @@ static int sl_realloc_bufs(struct slip *sl, int mtu)
                        memcpy(sl->rbuff, rbuff, sl->rcount);
                } else  {
                        sl->rcount = 0;
-                       sl->rx_over_errors++;
+                       dev->stats.rx_over_errors++;
                        set_bit(SLF_ERROR, &sl->flags);
                }
        }
@@ -319,6 +319,7 @@ static inline void sl_unlock(struct slip *sl)
 /* Send one completely decapsulated IP datagram to the IP layer. */
 static void sl_bump(struct slip *sl)
 {
+       struct net_device *dev = sl->dev;
        struct sk_buff *skb;
        int count;
 
@@ -329,13 +330,13 @@ static void sl_bump(struct slip *sl)
                if (c & SL_TYPE_COMPRESSED_TCP) {
                        /* ignore compressed packets when CSLIP is off */
                        if (!(sl->mode & SL_MODE_CSLIP)) {
-                               printk(KERN_WARNING "%s: compressed packet ignored\n", sl->dev->name);
+                               printk(KERN_WARNING "%s: compressed packet ignored\n", dev->name);
                                return;
                        }
                        /* make sure we've reserved enough space for uncompress
                           to use */
                        if (count + 80 > sl->buffsize) {
-                               sl->rx_over_errors++;
+                               dev->stats.rx_over_errors++;
                                return;
                        }
                        count = slhc_uncompress(sl->slcomp, sl->rbuff, count);
@@ -346,7 +347,7 @@ static void sl_bump(struct slip *sl)
                                /* turn on header compression */
                                sl->mode |= SL_MODE_CSLIP;
                                sl->mode &= ~SL_MODE_ADAPTIVE;
-                               printk(KERN_INFO "%s: header compression turned on\n", sl->dev->name);
+                               printk(KERN_INFO "%s: header compression turned on\n", dev->name);
                        }
                        sl->rbuff[0] &= 0x4f;
                        if (slhc_remember(sl->slcomp, sl->rbuff, count) <= 0)
@@ -355,20 +356,20 @@ static void sl_bump(struct slip *sl)
        }
 #endif  /* SL_INCLUDE_CSLIP */
 
-       sl->rx_bytes += count;
+       dev->stats.rx_bytes += count;
 
        skb = dev_alloc_skb(count);
        if (skb == NULL) {
-               printk(KERN_WARNING "%s: memory squeeze, dropping packet.\n", sl->dev->name);
-               sl->rx_dropped++;
+               printk(KERN_WARNING "%s: memory squeeze, dropping packet.\n", dev->name);
+               dev->stats.rx_dropped++;
                return;
        }
-       skb->dev = sl->dev;
+       skb->dev = dev;
        memcpy(skb_put(skb, count), sl->rbuff, count);
        skb_reset_mac_header(skb);
        skb->protocol = htons(ETH_P_IP);
        netif_rx(skb);
-       sl->rx_packets++;
+       dev->stats.rx_packets++;
 }
 
 /* Encapsulate one IP datagram and stuff into a TTY queue. */
@@ -379,7 +380,7 @@ static void sl_encaps(struct slip *sl, unsigned char *icp, int len)
 
        if (len > sl->mtu) {            /* Sigh, shouldn't occur BUT ... */
                printk(KERN_WARNING "%s: truncating oversized transmit packet!\n", sl->dev->name);
-               sl->tx_dropped++;
+               sl->dev->stats.tx_dropped++;
                sl_unlock(sl);
                return;
        }
@@ -433,7 +434,7 @@ static void slip_write_wakeup(struct tty_struct *tty)
        if (sl->xleft <= 0)  {
                /* Now serial buffer is almost free & we can start
                 * transmission of another packet */
-               sl->tx_packets++;
+               sl->dev->stats.tx_packets++;
                clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
                sl_unlock(sl);
                return;
@@ -496,7 +497,7 @@ sl_xmit(struct sk_buff *skb, struct net_device *dev)
        }
 
        sl_lock(sl);
-       sl->tx_bytes += skb->len;
+       dev->stats.tx_bytes += skb->len;
        sl_encaps(sl, skb->data, skb->len);
        spin_unlock(&sl->lock);
 
@@ -558,39 +559,39 @@ static int sl_change_mtu(struct net_device *dev, int new_mtu)
 
 /* Netdevice get statistics request */
 
-static struct net_device_stats *
-sl_get_stats(struct net_device *dev)
+static struct rtnl_link_stats64 *
+sl_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
 {
-       static struct net_device_stats stats;
-       struct slip *sl = netdev_priv(dev);
+       struct net_device_stats *devstats = &dev->stats;
+       unsigned long c_rx_dropped = 0;
 #ifdef SL_INCLUDE_CSLIP
-       struct slcompress *comp;
-#endif
+       unsigned long c_rx_fifo_errors = 0;
+       unsigned long c_tx_fifo_errors = 0;
+       unsigned long c_collisions = 0;
+       struct slip *sl = netdev_priv(dev);
+       struct slcompress *comp = sl->slcomp;
 
-       memset(&stats, 0, sizeof(struct net_device_stats));
-
-       stats.rx_packets     = sl->rx_packets;
-       stats.tx_packets     = sl->tx_packets;
-       stats.rx_bytes       = sl->rx_bytes;
-       stats.tx_bytes       = sl->tx_bytes;
-       stats.rx_dropped     = sl->rx_dropped;
-       stats.tx_dropped     = sl->tx_dropped;
-       stats.tx_errors      = sl->tx_errors;
-       stats.rx_errors      = sl->rx_errors;
-       stats.rx_over_errors = sl->rx_over_errors;
-#ifdef SL_INCLUDE_CSLIP
-       stats.rx_fifo_errors = sl->rx_compressed;
-       stats.tx_fifo_errors = sl->tx_compressed;
-       stats.collisions     = sl->tx_misses;
-       comp = sl->slcomp;
        if (comp) {
-               stats.rx_fifo_errors += comp->sls_i_compressed;
-               stats.rx_dropped     += comp->sls_i_tossed;
-               stats.tx_fifo_errors += comp->sls_o_compressed;
-               stats.collisions     += comp->sls_o_misses;
+               c_rx_fifo_errors = comp->sls_i_compressed;
+               c_rx_dropped     = comp->sls_i_tossed;
+               c_tx_fifo_errors = comp->sls_o_compressed;
+               c_collisions     = comp->sls_o_misses;
        }
-#endif /* CONFIG_INET */
-       return (&stats);
+       stats->rx_fifo_errors = sl->rx_compressed + c_rx_fifo_errors;
+       stats->tx_fifo_errors = sl->tx_compressed + c_tx_fifo_errors;
+       stats->collisions     = sl->tx_misses + c_collisions;
+#endif
+       stats->rx_packets     = devstats->rx_packets;
+       stats->tx_packets     = devstats->tx_packets;
+       stats->rx_bytes       = devstats->rx_bytes;
+       stats->tx_bytes       = devstats->tx_bytes;
+       stats->rx_dropped     = devstats->rx_dropped + c_rx_dropped;
+       stats->tx_dropped     = devstats->tx_dropped;
+       stats->tx_errors      = devstats->tx_errors;
+       stats->rx_errors      = devstats->rx_errors;
+       stats->rx_over_errors = devstats->rx_over_errors;
+
+       return stats;
 }
 
 /* Netdevice register callback */
@@ -633,7 +634,7 @@ static const struct net_device_ops sl_netdev_ops = {
        .ndo_open               = sl_open,
        .ndo_stop               = sl_close,
        .ndo_start_xmit         = sl_xmit,
-       .ndo_get_stats          = sl_get_stats,
+       .ndo_get_stats64        = sl_get_stats64,
        .ndo_change_mtu         = sl_change_mtu,
        .ndo_tx_timeout         = sl_tx_timeout,
 #ifdef CONFIG_SLIP_SMART
@@ -681,7 +682,7 @@ static void slip_receive_buf(struct tty_struct *tty, const unsigned char *cp,
        while (count--) {
                if (fp && *fp++) {
                        if (!test_and_set_bit(SLF_ERROR, &sl->flags))
-                               sl->rx_errors++;
+                               sl->dev->stats.rx_errors++;
                        cp++;
                        continue;
                }
@@ -981,7 +982,7 @@ static void slip_unesc(struct slip *sl, unsigned char s)
                        sl->rbuff[sl->rcount++] = s;
                        return;
                }
-               sl->rx_over_errors++;
+               sl->dev->stats.rx_over_errors++;
                set_bit(SLF_ERROR, &sl->flags);
        }
 }
@@ -1057,7 +1058,7 @@ static void slip_unesc6(struct slip *sl, unsigned char s)
                                        sl->rbuff[sl->rcount++] = c;
                                        return;
                                }
-                               sl->rx_over_errors++;
+                               sl->dev->stats.rx_over_errors++;
                                set_bit(SLF_ERROR, &sl->flags);
                        }
                }
index 9ea5c11287d26594f8daee415b7b65239a9ed33e..914e958abbfc88fb74b2a13bf22dff007d79ee70 100644 (file)
@@ -67,15 +67,6 @@ struct slip {
   int                   xleft;          /* bytes left in XMIT queue     */
 
   /* SLIP interface statistics. */
-  unsigned long                rx_packets;     /* inbound frames counter       */
-  unsigned long         tx_packets;     /* outbound frames counter      */
-  unsigned long                rx_bytes;       /* inbound byte counte          */
-  unsigned long         tx_bytes;       /* outbound byte counter       */
-  unsigned long         rx_errors;      /* Parity, etc. errors          */
-  unsigned long         tx_errors;      /* Planned stuff                */
-  unsigned long         rx_dropped;     /* No memory for skb            */
-  unsigned long         tx_dropped;     /* When MTU change              */
-  unsigned long         rx_over_errors; /* Frame bigger than SLIP buf.  */
 #ifdef SL_INCLUDE_CSLIP
   unsigned long                tx_compressed;
   unsigned long                rx_compressed;
index 0909ae934ad0fcee52c5eb67101240e77fb70dde..13ddcd4872005830f09bdf3ee9c02c5e7d572eb6 100644 (file)
@@ -1048,7 +1048,7 @@ static int smsc911x_poll(struct napi_struct *napi, int budget)
                smsc911x_rx_readfifo(pdata, (unsigned int *)skb->head,
                                     pktwords);
                skb->protocol = eth_type_trans(skb, dev);
-               skb->ip_summed = CHECKSUM_NONE;
+               skb_checksum_none_assert(skb);
                netif_receive_skb(skb);
 
                /* Update counters */
index 1636a34d95dd60ca6e8c4c6e0ea4871366ad220b..cb6bcca9d541d2287e5a963bbacad8c540b58f27 100644 (file)
@@ -1000,9 +1000,9 @@ spider_net_pass_skb_up(struct spider_net_descr *descr,
                     !(data_error & SPIDER_NET_DATA_ERR_CKSUM_MASK))
                        skb->ip_summed = CHECKSUM_UNNECESSARY;
                else
-                       skb->ip_summed = CHECKSUM_NONE;
+                       skb_checksum_none_assert(skb);
        } else
-               skb->ip_summed = CHECKSUM_NONE;
+               skb_checksum_none_assert(skb);
 
        if (data_status & SPIDER_NET_VLAN_PACKET) {
                /* further enhancements: HW-accel VLAN
index a42b6873370b04924af204596baf17342319121b..4adf124227877e704fe66a7bb74919738bbd46c5 100644 (file)
@@ -148,7 +148,7 @@ static int full_duplex[MAX_UNITS] = {0, };
  * This SUCKS.
  * We need a much better method to determine if dma_addr_t is 64-bit.
  */
-#if (defined(__i386__) && defined(CONFIG_HIGHMEM64G)) || defined(__x86_64__) || defined (__ia64__) || defined(__alpha__) || defined(__mips64__) || (defined(__mips__) && defined(CONFIG_HIGHMEM) && defined(CONFIG_64BIT_PHYS_ADDR))
+#if (defined(__i386__) && defined(CONFIG_HIGHMEM64G)) || defined(__x86_64__) || defined (__ia64__) || defined(__alpha__) || defined(__mips64__) || (defined(__mips__) && defined(CONFIG_HIGHMEM) && defined(CONFIG_64BIT_PHYS_ADDR)) || (defined(__powerpc64__) || defined(CONFIG_PHYS_64BIT))
 /* 64-bit dma_addr_t */
 #define ADDR_64BITS    /* This chip uses 64 bit addresses. */
 #define netdrv_addr_t __le64
@@ -302,7 +302,7 @@ enum chipset {
 };
 
 static DEFINE_PCI_DEVICE_TABLE(starfire_pci_tbl) = {
-       { 0x9004, 0x6915, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_6915 },
+       { PCI_VDEVICE(ADAPTEC, 0x6915), CH_6915 },
        { 0, }
 };
 MODULE_DEVICE_TABLE(pci, starfire_pci_tbl);
@@ -2078,11 +2078,7 @@ static int __init starfire_init (void)
        printk(KERN_INFO DRV_NAME ": polling (NAPI) enabled\n");
 #endif
 
-       /* we can do this test only at run-time... sigh */
-       if (sizeof(dma_addr_t) != sizeof(netdrv_addr_t)) {
-               printk("This driver has dma_addr_t issues, please send email to maintainer\n");
-               return -ENODEV;
-       }
+       BUILD_BUG_ON(sizeof(dma_addr_t) != sizeof(netdrv_addr_t));
 
        return pci_register_driver(&starfire_driver);
 }
index eb63d44748a76cd3182e002284afe84296552d1e..3c2af7c6a39b7575d700e90902aac544f693f461 100644 (file)
@@ -3,10 +3,10 @@ config STMMAC_ETH
        select MII
        select PHYLIB
        select CRC32
-       depends on NETDEVICES && CPU_SUBTYPE_ST40
+       depends on NETDEVICES
        help
          This is the driver for the Ethernet IPs are built around a
-         Synopsys IP Core and fully tested on the STMicroelectronics
+         Synopsys IP Core and only tested on the STMicroelectronics
          platforms.
 
 if STMMAC_ETH
@@ -32,6 +32,7 @@ config STMMAC_DUAL_MAC
 config STMMAC_TIMER
        bool "STMMAC Timer optimisation"
        default n
+       depends on RTC_HCTOSYS_DEVICE
        help
          Use an external timer for mitigating the number of network
          interrupts. Currently, for SH architectures, it is possible
index 66b9da0260fe70b6177c6980604f24184dcdb431..e8cbcb5c206eaea4ca7945d1def5d96b7acbce3d 100644 (file)
@@ -167,7 +167,7 @@ struct stmmac_desc_ops {
        int (*get_tx_ls) (struct dma_desc *p);
        /* Return the transmit status looking at the TDES1 */
        int (*tx_status) (void *data, struct stmmac_extra_stats *x,
-                         struct dma_desc *p, unsigned long ioaddr);
+                         struct dma_desc *p, void __iomem *ioaddr);
        /* Get the buffer size from the descriptor */
        int (*get_tx_len) (struct dma_desc *p);
        /* Handle extra events on specific interrupts hw dependent */
@@ -182,44 +182,44 @@ struct stmmac_desc_ops {
 
 struct stmmac_dma_ops {
        /* DMA core initialization */
-       int (*init) (unsigned long ioaddr, int pbl, u32 dma_tx, u32 dma_rx);
+       int (*init) (void __iomem *ioaddr, int pbl, u32 dma_tx, u32 dma_rx);
        /* Dump DMA registers */
-       void (*dump_regs) (unsigned long ioaddr);
+       void (*dump_regs) (void __iomem *ioaddr);
        /* Set tx/rx threshold in the csr6 register
         * An invalid value enables the store-and-forward mode */
-       void (*dma_mode) (unsigned long ioaddr, int txmode, int rxmode);
+       void (*dma_mode) (void __iomem *ioaddr, int txmode, int rxmode);
        /* To track extra statistic (if supported) */
        void (*dma_diagnostic_fr) (void *data, struct stmmac_extra_stats *x,
-                                  unsigned long ioaddr);
-       void (*enable_dma_transmission) (unsigned long ioaddr);
-       void (*enable_dma_irq) (unsigned long ioaddr);
-       void (*disable_dma_irq) (unsigned long ioaddr);
-       void (*start_tx) (unsigned long ioaddr);
-       void (*stop_tx) (unsigned long ioaddr);
-       void (*start_rx) (unsigned long ioaddr);
-       void (*stop_rx) (unsigned long ioaddr);
-       int (*dma_interrupt) (unsigned long ioaddr,
+                                  void __iomem *ioaddr);
+       void (*enable_dma_transmission) (void __iomem *ioaddr);
+       void (*enable_dma_irq) (void __iomem *ioaddr);
+       void (*disable_dma_irq) (void __iomem *ioaddr);
+       void (*start_tx) (void __iomem *ioaddr);
+       void (*stop_tx) (void __iomem *ioaddr);
+       void (*start_rx) (void __iomem *ioaddr);
+       void (*stop_rx) (void __iomem *ioaddr);
+       int (*dma_interrupt) (void __iomem *ioaddr,
                              struct stmmac_extra_stats *x);
 };
 
 struct stmmac_ops {
        /* MAC core initialization */
-       void (*core_init) (unsigned long ioaddr) ____cacheline_aligned;
+       void (*core_init) (void __iomem *ioaddr) ____cacheline_aligned;
        /* Dump MAC registers */
-       void (*dump_regs) (unsigned long ioaddr);
+       void (*dump_regs) (void __iomem *ioaddr);
        /* Handle extra events on specific interrupts hw dependent */
-       void (*host_irq_status) (unsigned long ioaddr);
+       void (*host_irq_status) (void __iomem *ioaddr);
        /* Multicast filter setting */
        void (*set_filter) (struct net_device *dev);
        /* Flow control setting */
-       void (*flow_ctrl) (unsigned long ioaddr, unsigned int duplex,
+       void (*flow_ctrl) (void __iomem *ioaddr, unsigned int duplex,
                           unsigned int fc, unsigned int pause_time);
        /* Set power management mode (e.g. magic frame) */
-       void (*pmt) (unsigned long ioaddr, unsigned long mode);
+       void (*pmt) (void __iomem *ioaddr, unsigned long mode);
        /* Set/Get Unicast MAC addresses */
-       void (*set_umac_addr) (unsigned long ioaddr, unsigned char *addr,
+       void (*set_umac_addr) (void __iomem *ioaddr, unsigned char *addr,
                               unsigned int reg_n);
-       void (*get_umac_addr) (unsigned long ioaddr, unsigned char *addr,
+       void (*get_umac_addr) (void __iomem *ioaddr, unsigned char *addr,
                               unsigned int reg_n);
 };
 
@@ -243,11 +243,11 @@ struct mac_device_info {
        struct mac_link link;
 };
 
-struct mac_device_info *dwmac1000_setup(unsigned long addr);
-struct mac_device_info *dwmac100_setup(unsigned long addr);
+struct mac_device_info *dwmac1000_setup(void __iomem *ioaddr);
+struct mac_device_info *dwmac100_setup(void __iomem *ioaddr);
 
-extern void stmmac_set_mac_addr(unsigned long ioaddr, u8 addr[6],
+extern void stmmac_set_mac_addr(void __iomem *ioaddr, u8 addr[6],
                                unsigned int high, unsigned int low);
-extern void stmmac_get_mac_addr(unsigned long ioaddr, unsigned char *addr,
+extern void stmmac_get_mac_addr(void __iomem *ioaddr, unsigned char *addr,
                                unsigned int high, unsigned int low);
-extern void dwmac_dma_flush_tx_fifo(unsigned long ioaddr);
+extern void dwmac_dma_flush_tx_fifo(void __iomem *ioaddr);
index 2b2f5c8caf1c52ea010843789417bfb40768366b..f1f426146f403be79ed4f20832392bfb53215d88 100644 (file)
@@ -30,7 +30,7 @@
 #include <linux/slab.h>
 #include "dwmac1000.h"
 
-static void dwmac1000_core_init(unsigned long ioaddr)
+static void dwmac1000_core_init(void __iomem *ioaddr)
 {
        u32 value = readl(ioaddr + GMAC_CONTROL);
        value |= GMAC_CORE_INIT;
@@ -50,10 +50,10 @@ static void dwmac1000_core_init(unsigned long ioaddr)
 #endif
 }
 
-static void dwmac1000_dump_regs(unsigned long ioaddr)
+static void dwmac1000_dump_regs(void __iomem *ioaddr)
 {
        int i;
-       pr_info("\tDWMAC1000 regs (base addr = 0x%8x)\n", (unsigned int)ioaddr);
+       pr_info("\tDWMAC1000 regs (base addr = 0x%p)\n", ioaddr);
 
        for (i = 0; i < 55; i++) {
                int offset = i * 4;
@@ -62,14 +62,14 @@ static void dwmac1000_dump_regs(unsigned long ioaddr)
        }
 }
 
-static void dwmac1000_set_umac_addr(unsigned long ioaddr, unsigned char *addr,
+static void dwmac1000_set_umac_addr(void __iomem *ioaddr, unsigned char *addr,
                                unsigned int reg_n)
 {
        stmmac_set_mac_addr(ioaddr, addr, GMAC_ADDR_HIGH(reg_n),
                                GMAC_ADDR_LOW(reg_n));
 }
 
-static void dwmac1000_get_umac_addr(unsigned long ioaddr, unsigned char *addr,
+static void dwmac1000_get_umac_addr(void __iomem *ioaddr, unsigned char *addr,
                                unsigned int reg_n)
 {
        stmmac_get_mac_addr(ioaddr, addr, GMAC_ADDR_HIGH(reg_n),
@@ -78,7 +78,7 @@ static void dwmac1000_get_umac_addr(unsigned long ioaddr, unsigned char *addr,
 
 static void dwmac1000_set_filter(struct net_device *dev)
 {
-       unsigned long ioaddr = dev->base_addr;
+       void __iomem *ioaddr = (void __iomem *) dev->base_addr;
        unsigned int value = 0;
 
        CHIP_DBG(KERN_INFO "%s: # mcasts %d, # unicast %d\n",
@@ -139,7 +139,7 @@ static void dwmac1000_set_filter(struct net_device *dev)
            readl(ioaddr + GMAC_HASH_HIGH), readl(ioaddr + GMAC_HASH_LOW));
 }
 
-static void dwmac1000_flow_ctrl(unsigned long ioaddr, unsigned int duplex,
+static void dwmac1000_flow_ctrl(void __iomem *ioaddr, unsigned int duplex,
                           unsigned int fc, unsigned int pause_time)
 {
        unsigned int flow = 0;
@@ -162,7 +162,7 @@ static void dwmac1000_flow_ctrl(unsigned long ioaddr, unsigned int duplex,
        writel(flow, ioaddr + GMAC_FLOW_CTRL);
 }
 
-static void dwmac1000_pmt(unsigned long ioaddr, unsigned long mode)
+static void dwmac1000_pmt(void __iomem *ioaddr, unsigned long mode)
 {
        unsigned int pmt = 0;
 
@@ -178,7 +178,7 @@ static void dwmac1000_pmt(unsigned long ioaddr, unsigned long mode)
 }
 
 
-static void dwmac1000_irq_status(unsigned long ioaddr)
+static void dwmac1000_irq_status(void __iomem *ioaddr)
 {
        u32 intr_status = readl(ioaddr + GMAC_INT_STATUS);
 
@@ -211,7 +211,7 @@ struct stmmac_ops dwmac1000_ops = {
        .get_umac_addr = dwmac1000_get_umac_addr,
 };
 
-struct mac_device_info *dwmac1000_setup(unsigned long ioaddr)
+struct mac_device_info *dwmac1000_setup(void __iomem *ioaddr)
 {
        struct mac_device_info *mac;
        u32 uid = readl(ioaddr + GMAC_VERSION);
index 415805057cb0ff12e116bd7621fa2246831efeca..2ef5a56370e94f07d48993e7f5d151fe84860e8f 100644 (file)
@@ -29,7 +29,7 @@
 #include "dwmac1000.h"
 #include "dwmac_dma.h"
 
-static int dwmac1000_dma_init(unsigned long ioaddr, int pbl, u32 dma_tx,
+static int dwmac1000_dma_init(void __iomem *ioaddr, int pbl, u32 dma_tx,
                              u32 dma_rx)
 {
        u32 value = readl(ioaddr + DMA_BUS_MODE);
@@ -58,7 +58,7 @@ static int dwmac1000_dma_init(unsigned long ioaddr, int pbl, u32 dma_tx,
        return 0;
 }
 
-static void dwmac1000_dma_operation_mode(unsigned long ioaddr, int txmode,
+static void dwmac1000_dma_operation_mode(void __iomem *ioaddr, int txmode,
                                    int rxmode)
 {
        u32 csr6 = readl(ioaddr + DMA_CONTROL);
@@ -111,12 +111,12 @@ static void dwmac1000_dma_operation_mode(unsigned long ioaddr, int txmode,
 
 /* Not yet implemented --- no RMON module */
 static void dwmac1000_dma_diagnostic_fr(void *data,
-                 struct stmmac_extra_stats *x, unsigned long ioaddr)
+                 struct stmmac_extra_stats *x, void __iomem *ioaddr)
 {
        return;
 }
 
-static void dwmac1000_dump_dma_regs(unsigned long ioaddr)
+static void dwmac1000_dump_dma_regs(void __iomem *ioaddr)
 {
        int i;
        pr_info(" DMA registers\n");
index 2fb165fa2ba075b256533a7d1058ea00c36f2b33..db06c04ce4802621d61d6fdab5e17b174b14da1d 100644 (file)
@@ -31,7 +31,7 @@
 #include <linux/crc32.h>
 #include "dwmac100.h"
 
-static void dwmac100_core_init(unsigned long ioaddr)
+static void dwmac100_core_init(void __iomem *ioaddr)
 {
        u32 value = readl(ioaddr + MAC_CONTROL);
 
@@ -42,12 +42,12 @@ static void dwmac100_core_init(unsigned long ioaddr)
 #endif
 }
 
-static void dwmac100_dump_mac_regs(unsigned long ioaddr)
+static void dwmac100_dump_mac_regs(void __iomem *ioaddr)
 {
        pr_info("\t----------------------------------------------\n"
-               "\t  DWMAC 100 CSR (base addr = 0x%8x)\n"
+               "\t  DWMAC 100 CSR (base addr = 0x%p)\n"
                "\t----------------------------------------------\n",
-               (unsigned int)ioaddr);
+               ioaddr);
        pr_info("\tcontrol reg (offset 0x%x): 0x%08x\n", MAC_CONTROL,
                readl(ioaddr + MAC_CONTROL));
        pr_info("\taddr HI (offset 0x%x): 0x%08x\n ", MAC_ADDR_HIGH,
@@ -77,18 +77,18 @@ static void dwmac100_dump_mac_regs(unsigned long ioaddr)
                MMC_LOW_INTR_MASK, readl(ioaddr + MMC_LOW_INTR_MASK));
 }
 
-static void dwmac100_irq_status(unsigned long ioaddr)
+static void dwmac100_irq_status(void __iomem *ioaddr)
 {
        return;
 }
 
-static void dwmac100_set_umac_addr(unsigned long ioaddr, unsigned char *addr,
+static void dwmac100_set_umac_addr(void __iomem *ioaddr, unsigned char *addr,
                                   unsigned int reg_n)
 {
        stmmac_set_mac_addr(ioaddr, addr, MAC_ADDR_HIGH, MAC_ADDR_LOW);
 }
 
-static void dwmac100_get_umac_addr(unsigned long ioaddr, unsigned char *addr,
+static void dwmac100_get_umac_addr(void __iomem *ioaddr, unsigned char *addr,
                                   unsigned int reg_n)
 {
        stmmac_get_mac_addr(ioaddr, addr, MAC_ADDR_HIGH, MAC_ADDR_LOW);
@@ -96,7 +96,7 @@ static void dwmac100_get_umac_addr(unsigned long ioaddr, unsigned char *addr,
 
 static void dwmac100_set_filter(struct net_device *dev)
 {
-       unsigned long ioaddr = dev->base_addr;
+       void __iomem *ioaddr = (void __iomem *) dev->base_addr;
        u32 value = readl(ioaddr + MAC_CONTROL);
 
        if (dev->flags & IFF_PROMISC) {
@@ -145,7 +145,7 @@ static void dwmac100_set_filter(struct net_device *dev)
            readl(ioaddr + MAC_HASH_HIGH), readl(ioaddr + MAC_HASH_LOW));
 }
 
-static void dwmac100_flow_ctrl(unsigned long ioaddr, unsigned int duplex,
+static void dwmac100_flow_ctrl(void __iomem *ioaddr, unsigned int duplex,
                               unsigned int fc, unsigned int pause_time)
 {
        unsigned int flow = MAC_FLOW_CTRL_ENABLE;
@@ -158,7 +158,7 @@ static void dwmac100_flow_ctrl(unsigned long ioaddr, unsigned int duplex,
 /* No PMT module supported for this Ethernet Controller.
  * Tested on ST platforms only.
  */
-static void dwmac100_pmt(unsigned long ioaddr, unsigned long mode)
+static void dwmac100_pmt(void __iomem *ioaddr, unsigned long mode)
 {
        return;
 }
@@ -174,7 +174,7 @@ struct stmmac_ops dwmac100_ops = {
        .get_umac_addr = dwmac100_get_umac_addr,
 };
 
-struct mac_device_info *dwmac100_setup(unsigned long ioaddr)
+struct mac_device_info *dwmac100_setup(void __iomem *ioaddr)
 {
        struct mac_device_info *mac;
 
index 2fece7b727279a96a369313208f51b1f63eafd36..c7279d2b946b634927d9dc9f4e05d010eee4f88c 100644 (file)
@@ -31,7 +31,7 @@
 #include "dwmac100.h"
 #include "dwmac_dma.h"
 
-static int dwmac100_dma_init(unsigned long ioaddr, int pbl, u32 dma_tx,
+static int dwmac100_dma_init(void __iomem *ioaddr, int pbl, u32 dma_tx,
                             u32 dma_rx)
 {
        u32 value = readl(ioaddr + DMA_BUS_MODE);
@@ -58,7 +58,7 @@ static int dwmac100_dma_init(unsigned long ioaddr, int pbl, u32 dma_tx,
 /* Store and Forward capability is not used at all..
  * The transmit threshold can be programmed by
  * setting the TTC bits in the DMA control register.*/
-static void dwmac100_dma_operation_mode(unsigned long ioaddr, int txmode,
+static void dwmac100_dma_operation_mode(void __iomem *ioaddr, int txmode,
                                        int rxmode)
 {
        u32 csr6 = readl(ioaddr + DMA_CONTROL);
@@ -73,7 +73,7 @@ static void dwmac100_dma_operation_mode(unsigned long ioaddr, int txmode,
        writel(csr6, ioaddr + DMA_CONTROL);
 }
 
-static void dwmac100_dump_dma_regs(unsigned long ioaddr)
+static void dwmac100_dump_dma_regs(void __iomem *ioaddr)
 {
        int i;
 
@@ -91,7 +91,7 @@ static void dwmac100_dump_dma_regs(unsigned long ioaddr)
 /* DMA controller has two counters to track the number of
  * the receive missed frames. */
 static void dwmac100_dma_diagnostic_fr(void *data, struct stmmac_extra_stats *x,
-                                      unsigned long ioaddr)
+                                      void __iomem *ioaddr)
 {
        struct net_device_stats *stats = (struct net_device_stats *)data;
        u32 csr8 = readl(ioaddr + DMA_MISSED_FRAME_CTR);
index 7b815a1b7b8cb82e8a9d6e85302f1ee8ac07bc4b..da3f5ccf83d300e09d1b7804717ad2c16e722977 100644 (file)
 #define DMA_STATUS_TI  0x00000001      /* Transmit Interrupt */
 #define DMA_CONTROL_FTF                0x00100000 /* Flush transmit FIFO */
 
-extern void dwmac_enable_dma_transmission(unsigned long ioaddr);
-extern void dwmac_enable_dma_irq(unsigned long ioaddr);
-extern void dwmac_disable_dma_irq(unsigned long ioaddr);
-extern void dwmac_dma_start_tx(unsigned long ioaddr);
-extern void dwmac_dma_stop_tx(unsigned long ioaddr);
-extern void dwmac_dma_start_rx(unsigned long ioaddr);
-extern void dwmac_dma_stop_rx(unsigned long ioaddr);
-extern int dwmac_dma_interrupt(unsigned long ioaddr,
+extern void dwmac_enable_dma_transmission(void __iomem *ioaddr);
+extern void dwmac_enable_dma_irq(void __iomem *ioaddr);
+extern void dwmac_disable_dma_irq(void __iomem *ioaddr);
+extern void dwmac_dma_start_tx(void __iomem *ioaddr);
+extern void dwmac_dma_stop_tx(void __iomem *ioaddr);
+extern void dwmac_dma_start_rx(void __iomem *ioaddr);
+extern void dwmac_dma_stop_rx(void __iomem *ioaddr);
+extern int dwmac_dma_interrupt(void __iomem *ioaddr,
                                struct stmmac_extra_stats *x);
index a85415216ef4e326a3ae21afa833c03be1ca6e52..d65fab1ba790dfd0dba7af94bbf2506fc5566d7f 100644 (file)
 #endif
 
 /* CSR1 enables the transmit DMA to check for new descriptor */
-void dwmac_enable_dma_transmission(unsigned long ioaddr)
+void dwmac_enable_dma_transmission(void __iomem *ioaddr)
 {
        writel(1, ioaddr + DMA_XMT_POLL_DEMAND);
 }
 
-void dwmac_enable_dma_irq(unsigned long ioaddr)
+void dwmac_enable_dma_irq(void __iomem *ioaddr)
 {
        writel(DMA_INTR_DEFAULT_MASK, ioaddr + DMA_INTR_ENA);
 }
 
-void dwmac_disable_dma_irq(unsigned long ioaddr)
+void dwmac_disable_dma_irq(void __iomem *ioaddr)
 {
        writel(0, ioaddr + DMA_INTR_ENA);
 }
 
-void dwmac_dma_start_tx(unsigned long ioaddr)
+void dwmac_dma_start_tx(void __iomem *ioaddr)
 {
        u32 value = readl(ioaddr + DMA_CONTROL);
        value |= DMA_CONTROL_ST;
        writel(value, ioaddr + DMA_CONTROL);
 }
 
-void dwmac_dma_stop_tx(unsigned long ioaddr)
+void dwmac_dma_stop_tx(void __iomem *ioaddr)
 {
        u32 value = readl(ioaddr + DMA_CONTROL);
        value &= ~DMA_CONTROL_ST;
        writel(value, ioaddr + DMA_CONTROL);
 }
 
-void dwmac_dma_start_rx(unsigned long ioaddr)
+void dwmac_dma_start_rx(void __iomem *ioaddr)
 {
        u32 value = readl(ioaddr + DMA_CONTROL);
        value |= DMA_CONTROL_SR;
        writel(value, ioaddr + DMA_CONTROL);
 }
 
-void dwmac_dma_stop_rx(unsigned long ioaddr)
+void dwmac_dma_stop_rx(void __iomem *ioaddr)
 {
        u32 value = readl(ioaddr + DMA_CONTROL);
        value &= ~DMA_CONTROL_SR;
@@ -145,7 +145,7 @@ static void show_rx_process_state(unsigned int status)
 }
 #endif
 
-int dwmac_dma_interrupt(unsigned long ioaddr,
+int dwmac_dma_interrupt(void __iomem *ioaddr,
                        struct stmmac_extra_stats *x)
 {
        int ret = 0;
@@ -219,7 +219,7 @@ int dwmac_dma_interrupt(unsigned long ioaddr,
        return ret;
 }
 
-void dwmac_dma_flush_tx_fifo(unsigned long ioaddr)
+void dwmac_dma_flush_tx_fifo(void __iomem *ioaddr)
 {
        u32 csr6 = readl(ioaddr + DMA_CONTROL);
        writel((csr6 | DMA_CONTROL_FTF), ioaddr + DMA_CONTROL);
@@ -227,7 +227,7 @@ void dwmac_dma_flush_tx_fifo(unsigned long ioaddr)
        do {} while ((readl(ioaddr + DMA_CONTROL) & DMA_CONTROL_FTF));
 }
 
-void stmmac_set_mac_addr(unsigned long ioaddr, u8 addr[6],
+void stmmac_set_mac_addr(void __iomem *ioaddr, u8 addr[6],
                         unsigned int high, unsigned int low)
 {
        unsigned long data;
@@ -238,7 +238,7 @@ void stmmac_set_mac_addr(unsigned long ioaddr, u8 addr[6],
        writel(data, ioaddr + low);
 }
 
-void stmmac_get_mac_addr(unsigned long ioaddr, unsigned char *addr,
+void stmmac_get_mac_addr(void __iomem *ioaddr, unsigned char *addr,
                         unsigned int high, unsigned int low)
 {
        unsigned int hi_addr, lo_addr;
index f612f986a7e16b186ba5c5c1aafcc4ae98fa2313..77ff88c3958b7c0f2f4e5bd090a1b62d9e8b1807 100644 (file)
@@ -25,7 +25,7 @@
 #include "common.h"
 
 static int enh_desc_get_tx_status(void *data, struct stmmac_extra_stats *x,
-                                 struct dma_desc *p, unsigned long ioaddr)
+                                 struct dma_desc *p, void __iomem *ioaddr)
 {
        int ret = 0;
        struct net_device_stats *stats = (struct net_device_stats *)data;
index 31ad53643792f17bf72f2815216e6ac5380b02f3..51f4440ab98bddeb1521daa25ad27eb8641300fb 100644 (file)
@@ -25,7 +25,7 @@
 #include "common.h"
 
 static int ndesc_get_tx_status(void *data, struct stmmac_extra_stats *x,
-                              struct dma_desc *p, unsigned long ioaddr)
+                              struct dma_desc *p, void __iomem *ioaddr)
 {
        int ret = 0;
        struct net_device_stats *stats = (struct net_device_stats *)data;
index ebebc644b1b8cf7b503fb07ef137cdf323d70a2c..d0ddab0d21c227c4a7b69c835acc542e89be054c 100644 (file)
@@ -21,6 +21,7 @@
 *******************************************************************************/
 
 #define DRV_MODULE_VERSION     "Apr_2010"
+#include <linux/platform_device.h>
 #include <linux/stmmac.h>
 
 #include "common.h"
@@ -54,6 +55,7 @@ struct stmmac_priv {
        unsigned int dma_buf_sz;
        struct device *device;
        struct mac_device_info *hw;
+       void __iomem *ioaddr;
 
        struct stmmac_extra_stats xstats;
        struct napi_struct napi;
@@ -65,7 +67,7 @@ struct stmmac_priv {
        int phy_mask;
        int (*phy_reset) (void *priv);
        void (*fix_mac_speed) (void *priv, unsigned int speed);
-       void (*bus_setup)(unsigned long ioaddr);
+       void (*bus_setup)(void __iomem *ioaddr);
        void *bsp_priv;
 
        int phy_irq;
index f080509923f03eae4f787e9fc5615e1f9e03f2f5..63b68e61afce3ebfadd07efa1b49c55dc821bbae 100644 (file)
@@ -177,21 +177,21 @@ void stmmac_ethtool_gregs(struct net_device *dev,
        if (!priv->is_gmac) {
                /* MAC registers */
                for (i = 0; i < 12; i++)
-                       reg_space[i] = readl(dev->base_addr + (i * 4));
+                       reg_space[i] = readl(priv->ioaddr + (i * 4));
                /* DMA registers */
                for (i = 0; i < 9; i++)
                        reg_space[i + 12] =
-                           readl(dev->base_addr + (DMA_BUS_MODE + (i * 4)));
-               reg_space[22] = readl(dev->base_addr + DMA_CUR_TX_BUF_ADDR);
-               reg_space[23] = readl(dev->base_addr + DMA_CUR_RX_BUF_ADDR);
+                           readl(priv->ioaddr + (DMA_BUS_MODE + (i * 4)));
+               reg_space[22] = readl(priv->ioaddr + DMA_CUR_TX_BUF_ADDR);
+               reg_space[23] = readl(priv->ioaddr + DMA_CUR_RX_BUF_ADDR);
        } else {
                /* MAC registers */
                for (i = 0; i < 55; i++)
-                       reg_space[i] = readl(dev->base_addr + (i * 4));
+                       reg_space[i] = readl(priv->ioaddr + (i * 4));
                /* DMA registers */
                for (i = 0; i < 22; i++)
                        reg_space[i + 55] =
-                           readl(dev->base_addr + (DMA_BUS_MODE + (i * 4)));
+                           readl(priv->ioaddr + (DMA_BUS_MODE + (i * 4)));
        }
 }
 
@@ -263,11 +263,9 @@ stmmac_set_pauseparam(struct net_device *netdev,
                        cmd.phy_address = phy->addr;
                        ret = phy_ethtool_sset(phy, &cmd);
                }
-       } else {
-               unsigned long ioaddr = netdev->base_addr;
-               priv->hw->mac->flow_ctrl(ioaddr, phy->duplex,
+       } else
+               priv->hw->mac->flow_ctrl(priv->ioaddr, phy->duplex,
                                         priv->flow_ctrl, priv->pause);
-       }
        spin_unlock(&priv->lock);
        return ret;
 }
@@ -276,12 +274,11 @@ static void stmmac_get_ethtool_stats(struct net_device *dev,
                                 struct ethtool_stats *dummy, u64 *data)
 {
        struct stmmac_priv *priv = netdev_priv(dev);
-       unsigned long ioaddr = dev->base_addr;
        int i;
 
        /* Update HW stats if supported */
        priv->hw->dma->dma_diagnostic_fr(&dev->stats, (void *) &priv->xstats,
-                                        ioaddr);
+                                        priv->ioaddr);
 
        for (i = 0; i < STMMAC_STATS_LEN; i++) {
                char *p = (char *)priv + stmmac_gstrings_stats[i].stat_offset;
index ea0461eb2dbe4314c223ab2ad47f17ea9b90e740..03c160c6d75c3c3474a78b4cb1d1dd0d83149121 100644 (file)
@@ -202,7 +202,6 @@ static void stmmac_adjust_link(struct net_device *dev)
 {
        struct stmmac_priv *priv = netdev_priv(dev);
        struct phy_device *phydev = priv->phydev;
-       unsigned long ioaddr = dev->base_addr;
        unsigned long flags;
        int new_state = 0;
        unsigned int fc = priv->flow_ctrl, pause_time = priv->pause;
@@ -215,7 +214,7 @@ static void stmmac_adjust_link(struct net_device *dev)
 
        spin_lock_irqsave(&priv->lock, flags);
        if (phydev->link) {
-               u32 ctrl = readl(ioaddr + MAC_CTRL_REG);
+               u32 ctrl = readl(priv->ioaddr + MAC_CTRL_REG);
 
                /* Now we make sure that we can be in full duplex mode.
                 * If not, we operate in half-duplex mode. */
@@ -229,7 +228,7 @@ static void stmmac_adjust_link(struct net_device *dev)
                }
                /* Flow Control operation */
                if (phydev->pause)
-                       priv->hw->mac->flow_ctrl(ioaddr, phydev->duplex,
+                       priv->hw->mac->flow_ctrl(priv->ioaddr, phydev->duplex,
                                                 fc, pause_time);
 
                if (phydev->speed != priv->speed) {
@@ -238,6 +237,9 @@ static void stmmac_adjust_link(struct net_device *dev)
                        case 1000:
                                if (likely(priv->is_gmac))
                                        ctrl &= ~priv->hw->link.port;
+                               if (likely(priv->fix_mac_speed))
+                                       priv->fix_mac_speed(priv->bsp_priv,
+                                                           phydev->speed);
                                break;
                        case 100:
                        case 10:
@@ -265,7 +267,7 @@ static void stmmac_adjust_link(struct net_device *dev)
                        priv->speed = phydev->speed;
                }
 
-               writel(ctrl, ioaddr + MAC_CTRL_REG);
+               writel(ctrl, priv->ioaddr + MAC_CTRL_REG);
 
                if (!priv->oldlink) {
                        new_state = 1;
@@ -342,7 +344,7 @@ static int stmmac_init_phy(struct net_device *dev)
        return 0;
 }
 
-static inline void stmmac_mac_enable_rx(unsigned long ioaddr)
+static inline void stmmac_mac_enable_rx(void __iomem *ioaddr)
 {
        u32 value = readl(ioaddr + MAC_CTRL_REG);
        value |= MAC_RNABLE_RX;
@@ -350,7 +352,7 @@ static inline void stmmac_mac_enable_rx(unsigned long ioaddr)
        writel(value, ioaddr + MAC_CTRL_REG);
 }
 
-static inline void stmmac_mac_enable_tx(unsigned long ioaddr)
+static inline void stmmac_mac_enable_tx(void __iomem *ioaddr)
 {
        u32 value = readl(ioaddr + MAC_CTRL_REG);
        value |= MAC_ENABLE_TX;
@@ -358,14 +360,14 @@ static inline void stmmac_mac_enable_tx(unsigned long ioaddr)
        writel(value, ioaddr + MAC_CTRL_REG);
 }
 
-static inline void stmmac_mac_disable_rx(unsigned long ioaddr)
+static inline void stmmac_mac_disable_rx(void __iomem *ioaddr)
 {
        u32 value = readl(ioaddr + MAC_CTRL_REG);
        value &= ~MAC_RNABLE_RX;
        writel(value, ioaddr + MAC_CTRL_REG);
 }
 
-static inline void stmmac_mac_disable_tx(unsigned long ioaddr)
+static inline void stmmac_mac_disable_tx(void __iomem *ioaddr)
 {
        u32 value = readl(ioaddr + MAC_CTRL_REG);
        value &= ~MAC_ENABLE_TX;
@@ -574,17 +576,17 @@ static void stmmac_dma_operation_mode(struct stmmac_priv *priv)
 {
        if (!priv->is_gmac) {
                /* MAC 10/100 */
-               priv->hw->dma->dma_mode(priv->dev->base_addr, tc, 0);
+               priv->hw->dma->dma_mode(priv->ioaddr, tc, 0);
                priv->tx_coe = NO_HW_CSUM;
        } else {
                if ((priv->dev->mtu <= ETH_DATA_LEN) && (tx_coe)) {
-                       priv->hw->dma->dma_mode(priv->dev->base_addr,
+                       priv->hw->dma->dma_mode(priv->ioaddr,
                                                SF_DMA_MODE, SF_DMA_MODE);
                        tc = SF_DMA_MODE;
                        priv->tx_coe = HW_CSUM;
                } else {
                        /* Checksum computation is performed in software. */
-                       priv->hw->dma->dma_mode(priv->dev->base_addr, tc,
+                       priv->hw->dma->dma_mode(priv->ioaddr, tc,
                                                SF_DMA_MODE);
                        priv->tx_coe = NO_HW_CSUM;
                }
@@ -600,7 +602,6 @@ static void stmmac_dma_operation_mode(struct stmmac_priv *priv)
 static void stmmac_tx(struct stmmac_priv *priv)
 {
        unsigned int txsize = priv->dma_tx_size;
-       unsigned long ioaddr = priv->dev->base_addr;
 
        while (priv->dirty_tx != priv->cur_tx) {
                int last;
@@ -618,7 +619,7 @@ static void stmmac_tx(struct stmmac_priv *priv)
                        int tx_error =
                                priv->hw->desc->tx_status(&priv->dev->stats,
                                                          &priv->xstats, p,
-                                                         ioaddr);
+                                                         priv->ioaddr);
                        if (likely(tx_error == 0)) {
                                priv->dev->stats.tx_packets++;
                                priv->xstats.tx_pkt_n++;
@@ -674,7 +675,7 @@ static inline void stmmac_enable_irq(struct stmmac_priv *priv)
                priv->tm->timer_start(tmrate);
        else
 #endif
-               priv->hw->dma->enable_dma_irq(priv->dev->base_addr);
+               priv->hw->dma->enable_dma_irq(priv->ioaddr);
 }
 
 static inline void stmmac_disable_irq(struct stmmac_priv *priv)
@@ -684,7 +685,7 @@ static inline void stmmac_disable_irq(struct stmmac_priv *priv)
                priv->tm->timer_stop();
        else
 #endif
-               priv->hw->dma->disable_dma_irq(priv->dev->base_addr);
+               priv->hw->dma->disable_dma_irq(priv->ioaddr);
 }
 
 static int stmmac_has_work(struct stmmac_priv *priv)
@@ -739,14 +740,15 @@ static void stmmac_no_timer_stopped(void)
  */
 static void stmmac_tx_err(struct stmmac_priv *priv)
 {
+
        netif_stop_queue(priv->dev);
 
-       priv->hw->dma->stop_tx(priv->dev->base_addr);
+       priv->hw->dma->stop_tx(priv->ioaddr);
        dma_free_tx_skbufs(priv);
        priv->hw->desc->init_tx_desc(priv->dma_tx, priv->dma_tx_size);
        priv->dirty_tx = 0;
        priv->cur_tx = 0;
-       priv->hw->dma->start_tx(priv->dev->base_addr);
+       priv->hw->dma->start_tx(priv->ioaddr);
 
        priv->dev->stats.tx_errors++;
        netif_wake_queue(priv->dev);
@@ -755,11 +757,9 @@ static void stmmac_tx_err(struct stmmac_priv *priv)
 
 static void stmmac_dma_interrupt(struct stmmac_priv *priv)
 {
-       unsigned long ioaddr = priv->dev->base_addr;
        int status;
 
-       status = priv->hw->dma->dma_interrupt(priv->dev->base_addr,
-                                             &priv->xstats);
+       status = priv->hw->dma->dma_interrupt(priv->ioaddr, &priv->xstats);
        if (likely(status == handle_tx_rx))
                _stmmac_schedule(priv);
 
@@ -767,7 +767,7 @@ static void stmmac_dma_interrupt(struct stmmac_priv *priv)
                /* Try to bump up the dma threshold on this failure */
                if (unlikely(tc != SF_DMA_MODE) && (tc <= 256)) {
                        tc += 64;
-                       priv->hw->dma->dma_mode(ioaddr, tc, SF_DMA_MODE);
+                       priv->hw->dma->dma_mode(priv->ioaddr, tc, SF_DMA_MODE);
                        priv->xstats.threshold = tc;
                }
                stmmac_tx_err(priv);
@@ -787,7 +787,6 @@ static void stmmac_dma_interrupt(struct stmmac_priv *priv)
 static int stmmac_open(struct net_device *dev)
 {
        struct stmmac_priv *priv = netdev_priv(dev);
-       unsigned long ioaddr = dev->base_addr;
        int ret;
 
        /* Check that the MAC address is valid.  If its not, refuse
@@ -843,7 +842,8 @@ static int stmmac_open(struct net_device *dev)
        init_dma_desc_rings(dev);
 
        /* DMA initialization and SW reset */
-       if (unlikely(priv->hw->dma->init(ioaddr, priv->pbl, priv->dma_tx_phy,
+       if (unlikely(priv->hw->dma->init(priv->ioaddr, priv->pbl,
+                                        priv->dma_tx_phy,
                                         priv->dma_rx_phy) < 0)) {
 
                pr_err("%s: DMA initialization failed\n", __func__);
@@ -851,22 +851,22 @@ static int stmmac_open(struct net_device *dev)
        }
 
        /* Copy the MAC addr into the HW  */
-       priv->hw->mac->set_umac_addr(ioaddr, dev->dev_addr, 0);
+       priv->hw->mac->set_umac_addr(priv->ioaddr, dev->dev_addr, 0);
        /* If required, perform hw setup of the bus. */
        if (priv->bus_setup)
-               priv->bus_setup(ioaddr);
+               priv->bus_setup(priv->ioaddr);
        /* Initialize the MAC Core */
-       priv->hw->mac->core_init(ioaddr);
+       priv->hw->mac->core_init(priv->ioaddr);
 
        priv->shutdown = 0;
 
        /* Initialise the MMC (if present) to disable all interrupts. */
-       writel(0xffffffff, ioaddr + MMC_HIGH_INTR_MASK);
-       writel(0xffffffff, ioaddr + MMC_LOW_INTR_MASK);
+       writel(0xffffffff, priv->ioaddr + MMC_HIGH_INTR_MASK);
+       writel(0xffffffff, priv->ioaddr + MMC_LOW_INTR_MASK);
 
        /* Enable the MAC Rx/Tx */
-       stmmac_mac_enable_rx(ioaddr);
-       stmmac_mac_enable_tx(ioaddr);
+       stmmac_mac_enable_rx(priv->ioaddr);
+       stmmac_mac_enable_tx(priv->ioaddr);
 
        /* Set the HW DMA mode and the COE */
        stmmac_dma_operation_mode(priv);
@@ -877,16 +877,16 @@ static int stmmac_open(struct net_device *dev)
 
        /* Start the ball rolling... */
        DBG(probe, DEBUG, "%s: DMA RX/TX processes started...\n", dev->name);
-       priv->hw->dma->start_tx(ioaddr);
-       priv->hw->dma->start_rx(ioaddr);
+       priv->hw->dma->start_tx(priv->ioaddr);
+       priv->hw->dma->start_rx(priv->ioaddr);
 
 #ifdef CONFIG_STMMAC_TIMER
        priv->tm->timer_start(tmrate);
 #endif
        /* Dump DMA/MAC registers */
        if (netif_msg_hw(priv)) {
-               priv->hw->mac->dump_regs(ioaddr);
-               priv->hw->dma->dump_regs(ioaddr);
+               priv->hw->mac->dump_regs(priv->ioaddr);
+               priv->hw->dma->dump_regs(priv->ioaddr);
        }
 
        if (priv->phydev)
@@ -930,15 +930,15 @@ static int stmmac_release(struct net_device *dev)
        free_irq(dev->irq, dev);
 
        /* Stop TX/RX DMA and clear the descriptors */
-       priv->hw->dma->stop_tx(dev->base_addr);
-       priv->hw->dma->stop_rx(dev->base_addr);
+       priv->hw->dma->stop_tx(priv->ioaddr);
+       priv->hw->dma->stop_rx(priv->ioaddr);
 
        /* Release and free the Rx/Tx resources */
        free_dma_desc_resources(priv);
 
        /* Disable the MAC core */
-       stmmac_mac_disable_tx(dev->base_addr);
-       stmmac_mac_disable_rx(dev->base_addr);
+       stmmac_mac_disable_tx(priv->ioaddr);
+       stmmac_mac_disable_rx(priv->ioaddr);
 
        netif_carrier_off(dev);
 
@@ -1140,7 +1140,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
 
        dev->stats.tx_bytes += skb->len;
 
-       priv->hw->dma->enable_dma_transmission(dev->base_addr);
+       priv->hw->dma->enable_dma_transmission(priv->ioaddr);
 
        return NETDEV_TX_OK;
 }
@@ -1256,7 +1256,7 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit)
 
                        if (unlikely(status == csum_none)) {
                                /* always for the old mac 10/100 */
-                               skb->ip_summed = CHECKSUM_NONE;
+                               skb_checksum_none_assert(skb);
                                netif_receive_skb(skb);
                        } else {
                                skb->ip_summed = CHECKSUM_UNNECESSARY;
@@ -1405,11 +1405,9 @@ static irqreturn_t stmmac_interrupt(int irq, void *dev_id)
                return IRQ_NONE;
        }
 
-       if (priv->is_gmac) {
-               unsigned long ioaddr = dev->base_addr;
+       if (priv->is_gmac)
                /* To handle GMAC own interrupts */
-               priv->hw->mac->host_irq_status(ioaddr);
-       }
+               priv->hw->mac->host_irq_status((void __iomem *) dev->base_addr);
 
        stmmac_dma_interrupt(priv);
 
@@ -1522,7 +1520,8 @@ static int stmmac_probe(struct net_device *dev)
        netif_napi_add(dev, &priv->napi, stmmac_poll, 64);
 
        /* Get the MAC address */
-       priv->hw->mac->get_umac_addr(dev->base_addr, dev->dev_addr, 0);
+       priv->hw->mac->get_umac_addr((void __iomem *) dev->base_addr,
+                                    dev->dev_addr, 0);
 
        if (!is_valid_ether_addr(dev->dev_addr))
                pr_warning("\tno valid MAC address;"
@@ -1552,14 +1551,13 @@ static int stmmac_probe(struct net_device *dev)
 static int stmmac_mac_device_setup(struct net_device *dev)
 {
        struct stmmac_priv *priv = netdev_priv(dev);
-       unsigned long ioaddr = dev->base_addr;
 
        struct mac_device_info *device;
 
        if (priv->is_gmac)
-               device = dwmac1000_setup(ioaddr);
+               device = dwmac1000_setup(priv->ioaddr);
        else
-               device = dwmac100_setup(ioaddr);
+               device = dwmac100_setup(priv->ioaddr);
 
        if (!device)
                return -ENOMEM;
@@ -1653,7 +1651,7 @@ static int stmmac_dvr_probe(struct platform_device *pdev)
 {
        int ret = 0;
        struct resource *res;
-       unsigned int *addr = NULL;
+       void __iomem *addr = NULL;
        struct net_device *ndev = NULL;
        struct stmmac_priv *priv;
        struct plat_stmmacenet_data *plat_dat;
@@ -1708,6 +1706,7 @@ static int stmmac_dvr_probe(struct platform_device *pdev)
        priv->pbl = plat_dat->pbl;      /* TLI */
        priv->is_gmac = plat_dat->has_gmac;     /* GMAC is on board */
        priv->enh_desc = plat_dat->enh_desc;
+       priv->ioaddr = addr;
 
        platform_set_drvdata(pdev, ndev);
 
@@ -1743,8 +1742,8 @@ static int stmmac_dvr_probe(struct platform_device *pdev)
        priv->bsp_priv = plat_dat->bsp_priv;
 
        pr_info("\t%s - (dev. name: %s - id: %d, IRQ #%d\n"
-              "\tIO base addr: 0x%08x)\n", ndev->name, pdev->name,
-              pdev->id, ndev->irq, (unsigned int)addr);
+              "\tIO base addr: 0x%p)\n", ndev->name, pdev->name,
+              pdev->id, ndev->irq, addr);
 
        /* MDIO bus Registration */
        pr_debug("\tMDIO bus (id: %d)...", priv->bus_id);
@@ -1779,11 +1778,11 @@ static int stmmac_dvr_remove(struct platform_device *pdev)
 
        pr_info("%s:\n\tremoving driver", __func__);
 
-       priv->hw->dma->stop_rx(ndev->base_addr);
-       priv->hw->dma->stop_tx(ndev->base_addr);
+       priv->hw->dma->stop_rx(priv->ioaddr);
+       priv->hw->dma->stop_tx(priv->ioaddr);
 
-       stmmac_mac_disable_rx(ndev->base_addr);
-       stmmac_mac_disable_tx(ndev->base_addr);
+       stmmac_mac_disable_rx(priv->ioaddr);
+       stmmac_mac_disable_tx(priv->ioaddr);
 
        netif_carrier_off(ndev);
 
@@ -1792,7 +1791,7 @@ static int stmmac_dvr_remove(struct platform_device *pdev)
        platform_set_drvdata(pdev, NULL);
        unregister_netdev(ndev);
 
-       iounmap((void *)ndev->base_addr);
+       iounmap((void *)priv->ioaddr);
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        release_mem_region(res->start, resource_size(res));
 
@@ -1827,22 +1826,21 @@ static int stmmac_suspend(struct platform_device *pdev, pm_message_t state)
                napi_disable(&priv->napi);
 
                /* Stop TX/RX DMA */
-               priv->hw->dma->stop_tx(dev->base_addr);
-               priv->hw->dma->stop_rx(dev->base_addr);
+               priv->hw->dma->stop_tx(priv->ioaddr);
+               priv->hw->dma->stop_rx(priv->ioaddr);
                /* Clear the Rx/Tx descriptors */
                priv->hw->desc->init_rx_desc(priv->dma_rx, priv->dma_rx_size,
                                             dis_ic);
                priv->hw->desc->init_tx_desc(priv->dma_tx, priv->dma_tx_size);
 
-               stmmac_mac_disable_tx(dev->base_addr);
+               stmmac_mac_disable_tx(priv->ioaddr);
 
                if (device_may_wakeup(&(pdev->dev))) {
                        /* Enable Power down mode by programming the PMT regs */
                        if (priv->wolenabled == PMT_SUPPORTED)
-                               priv->hw->mac->pmt(dev->base_addr,
-                                                  priv->wolopts);
+                               priv->hw->mac->pmt(priv->ioaddr, priv->wolopts);
                } else {
-                       stmmac_mac_disable_rx(dev->base_addr);
+                       stmmac_mac_disable_rx(priv->ioaddr);
                }
        } else {
                priv->shutdown = 1;
@@ -1860,7 +1858,6 @@ static int stmmac_resume(struct platform_device *pdev)
 {
        struct net_device *dev = platform_get_drvdata(pdev);
        struct stmmac_priv *priv = netdev_priv(dev);
-       unsigned long ioaddr = dev->base_addr;
 
        if (!netif_running(dev))
                return 0;
@@ -1881,15 +1878,15 @@ static int stmmac_resume(struct platform_device *pdev)
         * from another devices (e.g. serial console). */
        if (device_may_wakeup(&(pdev->dev)))
                if (priv->wolenabled == PMT_SUPPORTED)
-                       priv->hw->mac->pmt(dev->base_addr, 0);
+                       priv->hw->mac->pmt(priv->ioaddr, 0);
 
        netif_device_attach(dev);
 
        /* Enable the MAC and DMA */
-       stmmac_mac_enable_rx(ioaddr);
-       stmmac_mac_enable_tx(ioaddr);
-       priv->hw->dma->start_tx(ioaddr);
-       priv->hw->dma->start_rx(ioaddr);
+       stmmac_mac_enable_rx(priv->ioaddr);
+       stmmac_mac_enable_tx(priv->ioaddr);
+       priv->hw->dma->start_tx(priv->ioaddr);
+       priv->hw->dma->start_rx(priv->ioaddr);
 
 #ifdef CONFIG_STMMAC_TIMER
        priv->tm->timer_start(tmrate);
index 40b2c79297192455e954ad73f7ea195709fc56e1..03dea1401571e960a822661e15f0fc44402ad572 100644 (file)
@@ -47,7 +47,6 @@ static int stmmac_mdio_read(struct mii_bus *bus, int phyaddr, int phyreg)
 {
        struct net_device *ndev = bus->priv;
        struct stmmac_priv *priv = netdev_priv(ndev);
-       unsigned long ioaddr = ndev->base_addr;
        unsigned int mii_address = priv->hw->mii.addr;
        unsigned int mii_data = priv->hw->mii.data;
 
@@ -56,12 +55,12 @@ static int stmmac_mdio_read(struct mii_bus *bus, int phyaddr, int phyreg)
                        ((phyreg << 6) & (0x000007C0)));
        regValue |= MII_BUSY;   /* in case of GMAC */
 
-       do {} while (((readl(ioaddr + mii_address)) & MII_BUSY) == 1);
-       writel(regValue, ioaddr + mii_address);
-       do {} while (((readl(ioaddr + mii_address)) & MII_BUSY) == 1);
+       do {} while (((readl(priv->ioaddr + mii_address)) & MII_BUSY) == 1);
+       writel(regValue, priv->ioaddr + mii_address);
+       do {} while (((readl(priv->ioaddr + mii_address)) & MII_BUSY) == 1);
 
        /* Read the data from the MII data register */
-       data = (int)readl(ioaddr + mii_data);
+       data = (int)readl(priv->ioaddr + mii_data);
 
        return data;
 }
@@ -79,7 +78,6 @@ static int stmmac_mdio_write(struct mii_bus *bus, int phyaddr, int phyreg,
 {
        struct net_device *ndev = bus->priv;
        struct stmmac_priv *priv = netdev_priv(ndev);
-       unsigned long ioaddr = ndev->base_addr;
        unsigned int mii_address = priv->hw->mii.addr;
        unsigned int mii_data = priv->hw->mii.data;
 
@@ -90,14 +88,14 @@ static int stmmac_mdio_write(struct mii_bus *bus, int phyaddr, int phyreg,
        value |= MII_BUSY;
 
        /* Wait until any existing MII operation is complete */
-       do {} while (((readl(ioaddr + mii_address)) & MII_BUSY) == 1);
+       do {} while (((readl(priv->ioaddr + mii_address)) & MII_BUSY) == 1);
 
        /* Set the MII address register to write */
-       writel(phydata, ioaddr + mii_data);
-       writel(value, ioaddr + mii_address);
+       writel(phydata, priv->ioaddr + mii_data);
+       writel(value, priv->ioaddr + mii_address);
 
        /* Wait until any existing MII operation is complete */
-       do {} while (((readl(ioaddr + mii_address)) & MII_BUSY) == 1);
+       do {} while (((readl(priv->ioaddr + mii_address)) & MII_BUSY) == 1);
 
        return 0;
 }
@@ -111,7 +109,6 @@ static int stmmac_mdio_reset(struct mii_bus *bus)
 {
        struct net_device *ndev = bus->priv;
        struct stmmac_priv *priv = netdev_priv(ndev);
-       unsigned long ioaddr = ndev->base_addr;
        unsigned int mii_address = priv->hw->mii.addr;
 
        if (priv->phy_reset) {
@@ -123,7 +120,7 @@ static int stmmac_mdio_reset(struct mii_bus *bus)
         * It doesn't complete its reset until at least one clock cycle
         * on MDC, so perform a dummy mdio read.
         */
-       writel(0, ioaddr + mii_address);
+       writel(0, priv->ioaddr + mii_address);
 
        return 0;
 }
index 618643e3ca3ed36b64cc405e352d21babb35599f..0a6a5ced3c1cc88d71f0a3fce501b6b14cebf4e3 100644 (file)
@@ -617,7 +617,7 @@ static void bigmac_begin_auto_negotiation(struct bigmac *bp)
        bp->timer_ticks = 0;
        bp->bigmac_timer.expires = jiffies + (12 * HZ) / 10;
        bp->bigmac_timer.data = (unsigned long) bp;
-       bp->bigmac_timer.function = &bigmac_timer;
+       bp->bigmac_timer.function = bigmac_timer;
        add_timer(&bp->bigmac_timer);
 }
 
index 2678588ea4b201bdd6a1c9395f5abeeae9d9216f..3fa949789b42d6f3984edde52c9325b705563bda 100644 (file)
@@ -874,7 +874,7 @@ static int netdev_open(struct net_device *dev)
        init_timer(&np->timer);
        np->timer.expires = jiffies + 3*HZ;
        np->timer.data = (unsigned long)dev;
-       np->timer.function = &netdev_timer;                             /* timer handler */
+       np->timer.function = netdev_timer;                              /* timer handler */
        add_timer(&np->timer);
 
        /* Enable interrupts by setting the interrupt mask. */
index 434f9d735333663919c199b3e929dd74de924549..4ceb3cf6a9a96750931b01a78b444de40d788014 100644 (file)
@@ -31,6 +31,8 @@
  *    about when we can start taking interrupts or get xmit() called...
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
@@ -105,7 +107,6 @@ MODULE_DESCRIPTION("Sun GEM Gbit ethernet driver");
 MODULE_LICENSE("GPL");
 
 #define GEM_MODULE_NAME        "gem"
-#define PFX GEM_MODULE_NAME ": "
 
 static DEFINE_PCI_DEVICE_TABLE(gem_pci_tbl) = {
        { PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_GEM,
@@ -262,8 +263,7 @@ static int gem_pcs_interrupt(struct net_device *dev, struct gem *gp, u32 gem_sta
                        gp->dev->name, pcs_istat);
 
        if (!(pcs_istat & PCS_ISTAT_LSC)) {
-               printk(KERN_ERR "%s: PCS irq but no link status change???\n",
-                      dev->name);
+               netdev_err(dev, "PCS irq but no link status change???\n");
                return 0;
        }
 
@@ -282,20 +282,16 @@ static int gem_pcs_interrupt(struct net_device *dev, struct gem *gp, u32 gem_sta
                 * when autoneg has completed.
                 */
                if (pcs_miistat & PCS_MIISTAT_RF)
-                       printk(KERN_INFO "%s: PCS AutoNEG complete, "
-                              "RemoteFault\n", dev->name);
+                       netdev_info(dev, "PCS AutoNEG complete, RemoteFault\n");
                else
-                       printk(KERN_INFO "%s: PCS AutoNEG complete.\n",
-                              dev->name);
+                       netdev_info(dev, "PCS AutoNEG complete\n");
        }
 
        if (pcs_miistat & PCS_MIISTAT_LS) {
-               printk(KERN_INFO "%s: PCS link is now up.\n",
-                      dev->name);
+               netdev_info(dev, "PCS link is now up\n");
                netif_carrier_on(gp->dev);
        } else {
-               printk(KERN_INFO "%s: PCS link is now down.\n",
-                      dev->name);
+               netdev_info(dev, "PCS link is now down\n");
                netif_carrier_off(gp->dev);
                /* If this happens and the link timer is not running,
                 * reset so we re-negotiate.
@@ -323,14 +319,12 @@ static int gem_txmac_interrupt(struct net_device *dev, struct gem *gp, u32 gem_s
                return 0;
 
        if (txmac_stat & MAC_TXSTAT_URUN) {
-               printk(KERN_ERR "%s: TX MAC xmit underrun.\n",
-                      dev->name);
+               netdev_err(dev, "TX MAC xmit underrun\n");
                gp->net_stats.tx_fifo_errors++;
        }
 
        if (txmac_stat & MAC_TXSTAT_MPE) {
-               printk(KERN_ERR "%s: TX MAC max packet size error.\n",
-                      dev->name);
+               netdev_err(dev, "TX MAC max packet size error\n");
                gp->net_stats.tx_errors++;
        }
 
@@ -377,8 +371,7 @@ static int gem_rxmac_reset(struct gem *gp)
                udelay(10);
        }
        if (limit == 5000) {
-               printk(KERN_ERR "%s: RX MAC will not reset, resetting whole "
-                       "chip.\n", dev->name);
+               netdev_err(dev, "RX MAC will not reset, resetting whole chip\n");
                return 1;
        }
 
@@ -390,8 +383,7 @@ static int gem_rxmac_reset(struct gem *gp)
                udelay(10);
        }
        if (limit == 5000) {
-               printk(KERN_ERR "%s: RX MAC will not disable, resetting whole "
-                      "chip.\n", dev->name);
+               netdev_err(dev, "RX MAC will not disable, resetting whole chip\n");
                return 1;
        }
 
@@ -403,8 +395,7 @@ static int gem_rxmac_reset(struct gem *gp)
                udelay(10);
        }
        if (limit == 5000) {
-               printk(KERN_ERR "%s: RX DMA will not disable, resetting whole "
-                      "chip.\n", dev->name);
+               netdev_err(dev, "RX DMA will not disable, resetting whole chip\n");
                return 1;
        }
 
@@ -419,8 +410,7 @@ static int gem_rxmac_reset(struct gem *gp)
                udelay(10);
        }
        if (limit == 5000) {
-               printk(KERN_ERR "%s: RX reset command will not execute, resetting "
-                      "whole chip.\n", dev->name);
+               netdev_err(dev, "RX reset command will not execute, resetting whole chip\n");
                return 1;
        }
 
@@ -429,8 +419,7 @@ static int gem_rxmac_reset(struct gem *gp)
                struct gem_rxd *rxd = &gp->init_block->rxd[i];
 
                if (gp->rx_skbs[i] == NULL) {
-                       printk(KERN_ERR "%s: Parts of RX ring empty, resetting "
-                              "whole chip.\n", dev->name);
+                       netdev_err(dev, "Parts of RX ring empty, resetting whole chip\n");
                        return 1;
                }
 
@@ -479,8 +468,7 @@ static int gem_rxmac_interrupt(struct net_device *dev, struct gem *gp, u32 gem_s
        if (rxmac_stat & MAC_RXSTAT_OFLW) {
                u32 smac = readl(gp->regs + MAC_SMACHINE);
 
-               printk(KERN_ERR "%s: RX MAC fifo overflow smac[%08x].\n",
-                               dev->name, smac);
+               netdev_err(dev, "RX MAC fifo overflow smac[%08x]\n", smac);
                gp->net_stats.rx_over_errors++;
                gp->net_stats.rx_fifo_errors++;
 
@@ -542,19 +530,18 @@ static int gem_pci_interrupt(struct net_device *dev, struct gem *gp, u32 gem_sta
 
        if (gp->pdev->vendor == PCI_VENDOR_ID_SUN &&
            gp->pdev->device == PCI_DEVICE_ID_SUN_GEM) {
-               printk(KERN_ERR "%s: PCI error [%04x] ",
-                      dev->name, pci_estat);
+               netdev_err(dev, "PCI error [%04x]", pci_estat);
 
                if (pci_estat & GREG_PCIESTAT_BADACK)
-                       printk("<No ACK64# during ABS64 cycle> ");
+                       pr_cont(" <No ACK64# during ABS64 cycle>");
                if (pci_estat & GREG_PCIESTAT_DTRTO)
-                       printk("<Delayed transaction timeout> ");
+                       pr_cont(" <Delayed transaction timeout>");
                if (pci_estat & GREG_PCIESTAT_OTHER)
-                       printk("<other>");
-               printk("\n");
+                       pr_cont(" <other>");
+               pr_cont("\n");
        } else {
                pci_estat |= GREG_PCIESTAT_OTHER;
-               printk(KERN_ERR "%s: PCI error\n", dev->name);
+               netdev_err(dev, "PCI error\n");
        }
 
        if (pci_estat & GREG_PCIESTAT_OTHER) {
@@ -565,26 +552,20 @@ static int gem_pci_interrupt(struct net_device *dev, struct gem *gp, u32 gem_sta
                 */
                pci_read_config_word(gp->pdev, PCI_STATUS,
                                     &pci_cfg_stat);
-               printk(KERN_ERR "%s: Read PCI cfg space status [%04x]\n",
-                      dev->name, pci_cfg_stat);
+               netdev_err(dev, "Read PCI cfg space status [%04x]\n",
+                          pci_cfg_stat);
                if (pci_cfg_stat & PCI_STATUS_PARITY)
-                       printk(KERN_ERR "%s: PCI parity error detected.\n",
-                              dev->name);
+                       netdev_err(dev, "PCI parity error detected\n");
                if (pci_cfg_stat & PCI_STATUS_SIG_TARGET_ABORT)
-                       printk(KERN_ERR "%s: PCI target abort.\n",
-                              dev->name);
+                       netdev_err(dev, "PCI target abort\n");
                if (pci_cfg_stat & PCI_STATUS_REC_TARGET_ABORT)
-                       printk(KERN_ERR "%s: PCI master acks target abort.\n",
-                              dev->name);
+                       netdev_err(dev, "PCI master acks target abort\n");
                if (pci_cfg_stat & PCI_STATUS_REC_MASTER_ABORT)
-                       printk(KERN_ERR "%s: PCI master abort.\n",
-                              dev->name);
+                       netdev_err(dev, "PCI master abort\n");
                if (pci_cfg_stat & PCI_STATUS_SIG_SYSTEM_ERROR)
-                       printk(KERN_ERR "%s: PCI system error SERR#.\n",
-                              dev->name);
+                       netdev_err(dev, "PCI system error SERR#\n");
                if (pci_cfg_stat & PCI_STATUS_DETECTED_PARITY)
-                       printk(KERN_ERR "%s: PCI parity error.\n",
-                              dev->name);
+                       netdev_err(dev, "PCI parity error\n");
 
                /* Write the error bits back to clear them. */
                pci_cfg_stat &= (PCI_STATUS_PARITY |
@@ -874,8 +855,7 @@ static int gem_rx(struct gem *gp, int work_to_do)
        gp->rx_new = entry;
 
        if (drops)
-               printk(KERN_INFO "%s: Memory squeeze, deferring packet.\n",
-                      gp->dev->name);
+               netdev_info(gp->dev, "Memory squeeze, deferring packet\n");
 
        return work_done;
 }
@@ -981,21 +961,19 @@ static void gem_tx_timeout(struct net_device *dev)
 {
        struct gem *gp = netdev_priv(dev);
 
-       printk(KERN_ERR "%s: transmit timed out, resetting\n", dev->name);
+       netdev_err(dev, "transmit timed out, resetting\n");
        if (!gp->running) {
-               printk("%s: hrm.. hw not running !\n", dev->name);
+               netdev_err(dev, "hrm.. hw not running !\n");
                return;
        }
-       printk(KERN_ERR "%s: TX_STATE[%08x:%08x:%08x]\n",
-              dev->name,
-              readl(gp->regs + TXDMA_CFG),
-              readl(gp->regs + MAC_TXSTAT),
-              readl(gp->regs + MAC_TXCFG));
-       printk(KERN_ERR "%s: RX_STATE[%08x:%08x:%08x]\n",
-              dev->name,
-              readl(gp->regs + RXDMA_CFG),
-              readl(gp->regs + MAC_RXSTAT),
-              readl(gp->regs + MAC_RXCFG));
+       netdev_err(dev, "TX_STATE[%08x:%08x:%08x]\n",
+                  readl(gp->regs + TXDMA_CFG),
+                  readl(gp->regs + MAC_TXSTAT),
+                  readl(gp->regs + MAC_TXCFG));
+       netdev_err(dev, "RX_STATE[%08x:%08x:%08x]\n",
+                  readl(gp->regs + RXDMA_CFG),
+                  readl(gp->regs + MAC_RXSTAT),
+                  readl(gp->regs + MAC_RXCFG));
 
        spin_lock_irq(&gp->lock);
        spin_lock(&gp->tx_lock);
@@ -1048,8 +1026,7 @@ static netdev_tx_t gem_start_xmit(struct sk_buff *skb,
        if (TX_BUFFS_AVAIL(gp) <= (skb_shinfo(skb)->nr_frags + 1)) {
                netif_stop_queue(dev);
                spin_unlock_irqrestore(&gp->tx_lock, flags);
-               printk(KERN_ERR PFX "%s: BUG! Tx Ring full when queue awake!\n",
-                      dev->name);
+               netdev_err(dev, "BUG! Tx Ring full when queue awake!\n");
                return NETDEV_TX_BUSY;
        }
 
@@ -1158,8 +1135,7 @@ static void gem_pcs_reset(struct gem *gp)
                        break;
        }
        if (limit < 0)
-               printk(KERN_WARNING "%s: PCS reset bit would not clear.\n",
-                      gp->dev->name);
+               netdev_warn(gp->dev, "PCS reset bit would not clear\n");
 }
 
 static void gem_pcs_reinit_adv(struct gem *gp)
@@ -1230,7 +1206,7 @@ static void gem_reset(struct gem *gp)
        } while (val & (GREG_SWRST_TXRST | GREG_SWRST_RXRST));
 
        if (limit < 0)
-               printk(KERN_ERR "%s: SW reset is ghetto.\n", gp->dev->name);
+               netdev_err(gp->dev, "SW reset is ghetto\n");
 
        if (gp->phy_type == phy_serialink || gp->phy_type == phy_serdes)
                gem_pcs_reinit_adv(gp);
@@ -1395,9 +1371,8 @@ static int gem_set_link_modes(struct gem *gp)
                speed = SPEED_1000;
        }
 
-       if (netif_msg_link(gp))
-               printk(KERN_INFO "%s: Link is up at %d Mbps, %s-duplex.\n",
-                       gp->dev->name, speed, (full_duplex ? "full" : "half"));
+       netif_info(gp, link, gp->dev, "Link is up at %d Mbps, %s-duplex\n",
+                  speed, (full_duplex ? "full" : "half"));
 
        if (!gp->running)
                return 0;
@@ -1451,15 +1426,13 @@ static int gem_set_link_modes(struct gem *gp)
 
        if (netif_msg_link(gp)) {
                if (pause) {
-                       printk(KERN_INFO "%s: Pause is enabled "
-                              "(rxfifo: %d off: %d on: %d)\n",
-                              gp->dev->name,
-                              gp->rx_fifo_sz,
-                              gp->rx_pause_off,
-                              gp->rx_pause_on);
+                       netdev_info(gp->dev,
+                                   "Pause is enabled (rxfifo: %d off: %d on: %d)\n",
+                                   gp->rx_fifo_sz,
+                                   gp->rx_pause_off,
+                                   gp->rx_pause_on);
                } else {
-                       printk(KERN_INFO "%s: Pause is disabled\n",
-                              gp->dev->name);
+                       netdev_info(gp->dev, "Pause is disabled\n");
                }
        }
 
@@ -1484,9 +1457,8 @@ static int gem_mdio_link_not_up(struct gem *gp)
 {
        switch (gp->lstate) {
        case link_force_ret:
-               if (netif_msg_link(gp))
-                       printk(KERN_INFO "%s: Autoneg failed again, keeping"
-                               " forced mode\n", gp->dev->name);
+               netif_info(gp, link, gp->dev,
+                          "Autoneg failed again, keeping forced mode\n");
                gp->phy_mii.def->ops->setup_forced(&gp->phy_mii,
                        gp->last_forced_speed, DUPLEX_HALF);
                gp->timer_ticks = 5;
@@ -1499,9 +1471,7 @@ static int gem_mdio_link_not_up(struct gem *gp)
                 */
                if (gp->phy_mii.def->magic_aneg)
                        return 1;
-               if (netif_msg_link(gp))
-                       printk(KERN_INFO "%s: switching to forced 100bt\n",
-                               gp->dev->name);
+               netif_info(gp, link, gp->dev, "switching to forced 100bt\n");
                /* Try forced modes. */
                gp->phy_mii.def->ops->setup_forced(&gp->phy_mii, SPEED_100,
                        DUPLEX_HALF);
@@ -1517,9 +1487,8 @@ static int gem_mdio_link_not_up(struct gem *gp)
                        gp->phy_mii.def->ops->setup_forced(&gp->phy_mii, SPEED_10,
                                DUPLEX_HALF);
                        gp->timer_ticks = 5;
-                       if (netif_msg_link(gp))
-                               printk(KERN_INFO "%s: switching to forced 10bt\n",
-                                       gp->dev->name);
+                       netif_info(gp, link, gp->dev,
+                                  "switching to forced 10bt\n");
                        return 0;
                } else
                        return 1;
@@ -1574,8 +1543,8 @@ static void gem_link_timer(unsigned long data)
                        gp->last_forced_speed = gp->phy_mii.speed;
                        gp->timer_ticks = 5;
                        if (netif_msg_link(gp))
-                               printk(KERN_INFO "%s: Got link after fallback, retrying"
-                                       " autoneg once...\n", gp->dev->name);
+                               netdev_info(gp->dev,
+                                           "Got link after fallback, retrying autoneg once...\n");
                        gp->phy_mii.def->ops->setup_aneg(&gp->phy_mii, gp->phy_mii.advertising);
                } else if (gp->lstate != link_up) {
                        gp->lstate = link_up;
@@ -1589,9 +1558,7 @@ static void gem_link_timer(unsigned long data)
                 */
                if (gp->lstate == link_up) {
                        gp->lstate = link_down;
-                       if (netif_msg_link(gp))
-                               printk(KERN_INFO "%s: Link down\n",
-                                       gp->dev->name);
+                       netif_info(gp, link, gp->dev, "Link down\n");
                        netif_carrier_off(gp->dev);
                        gp->reset_task_pending = 1;
                        schedule_work(&gp->reset_task);
@@ -1746,8 +1713,7 @@ static void gem_init_phy(struct gem *gp)
                        if (phy_read(gp, MII_BMCR) != 0xffff)
                                break;
                        if (i == 2)
-                               printk(KERN_WARNING "%s: GMAC PHY not responding !\n",
-                                      gp->dev->name);
+                               netdev_warn(gp->dev, "GMAC PHY not responding !\n");
                }
        }
 
@@ -2038,7 +2004,7 @@ static int gem_check_invariants(struct gem *gp)
                 * as this chip has no gigabit PHY.
                 */
                if ((mif_cfg & (MIF_CFG_MDI0 | MIF_CFG_MDI1)) == 0) {
-                       printk(KERN_ERR PFX "RIO GEM lacks MII phy, mif_cfg[%08x]\n",
+                       pr_err("RIO GEM lacks MII phy, mif_cfg[%08x]\n",
                               mif_cfg);
                        return -1;
                }
@@ -2078,7 +2044,7 @@ static int gem_check_invariants(struct gem *gp)
                }
                if (i == 32) {
                        if (pdev->device != PCI_DEVICE_ID_SUN_GEM) {
-                               printk(KERN_ERR PFX "RIO MII phy will not respond.\n");
+                               pr_err("RIO MII phy will not respond\n");
                                return -1;
                        }
                        gp->phy_type = phy_serdes;
@@ -2093,7 +2059,7 @@ static int gem_check_invariants(struct gem *gp)
                if (pdev->device == PCI_DEVICE_ID_SUN_GEM) {
                        if (gp->tx_fifo_sz != (9 * 1024) ||
                            gp->rx_fifo_sz != (20 * 1024)) {
-                               printk(KERN_ERR PFX "GEM has bogus fifo sizes tx(%d) rx(%d)\n",
+                               pr_err("GEM has bogus fifo sizes tx(%d) rx(%d)\n",
                                       gp->tx_fifo_sz, gp->rx_fifo_sz);
                                return -1;
                        }
@@ -2101,7 +2067,7 @@ static int gem_check_invariants(struct gem *gp)
                } else {
                        if (gp->tx_fifo_sz != (2 * 1024) ||
                            gp->rx_fifo_sz != (2 * 1024)) {
-                               printk(KERN_ERR PFX "RIO GEM has bogus fifo sizes tx(%d) rx(%d)\n",
+                               pr_err("RIO GEM has bogus fifo sizes tx(%d) rx(%d)\n",
                                       gp->tx_fifo_sz, gp->rx_fifo_sz);
                                return -1;
                        }
@@ -2239,7 +2205,7 @@ static int gem_do_start(struct net_device *dev)
 
        if (request_irq(gp->pdev->irq, gem_interrupt,
                                   IRQF_SHARED, dev->name, (void *)dev)) {
-               printk(KERN_ERR "%s: failed to request irq !\n", gp->dev->name);
+               netdev_err(dev, "failed to request irq !\n");
 
                spin_lock_irqsave(&gp->lock, flags);
                spin_lock(&gp->tx_lock);
@@ -2378,9 +2344,8 @@ static int gem_suspend(struct pci_dev *pdev, pm_message_t state)
 
        mutex_lock(&gp->pm_mutex);
 
-       printk(KERN_INFO "%s: suspending, WakeOnLan %s\n",
-              dev->name,
-              (gp->wake_on_lan && gp->opened) ? "enabled" : "disabled");
+       netdev_info(dev, "suspending, WakeOnLan %s\n",
+                   (gp->wake_on_lan && gp->opened) ? "enabled" : "disabled");
 
        /* Keep the cell enabled during the entire operation */
        spin_lock_irqsave(&gp->lock, flags);
@@ -2440,7 +2405,7 @@ static int gem_resume(struct pci_dev *pdev)
        struct gem *gp = netdev_priv(dev);
        unsigned long flags;
 
-       printk(KERN_INFO "%s: resuming\n", dev->name);
+       netdev_info(dev, "resuming\n");
 
        mutex_lock(&gp->pm_mutex);
 
@@ -2452,8 +2417,7 @@ static int gem_resume(struct pci_dev *pdev)
 
        /* Make sure PCI access and bus master are enabled */
        if (pci_enable_device(gp->pdev)) {
-               printk(KERN_ERR "%s: Can't re-enable chip !\n",
-                      dev->name);
+               netdev_err(dev, "Can't re-enable chip !\n");
                /* Put cell and forget it for now, it will be considered as
                 * still asleep, a new sleep cycle may bring it back
                 */
@@ -2938,7 +2902,7 @@ static int __devinit gem_get_device_address(struct gem *gp)
                addr = idprom->id_ethaddr;
 #else
                printk("\n");
-               printk(KERN_ERR "%s: can't get mac-address\n", dev->name);
+               pr_err("%s: can't get mac-address\n", dev->name);
                return -1;
 #endif
        }
@@ -3009,14 +2973,12 @@ static const struct net_device_ops gem_netdev_ops = {
 static int __devinit gem_init_one(struct pci_dev *pdev,
                                  const struct pci_device_id *ent)
 {
-       static int gem_version_printed = 0;
        unsigned long gemreg_base, gemreg_len;
        struct net_device *dev;
        struct gem *gp;
        int err, pci_using_dac;
 
-       if (gem_version_printed++ == 0)
-               printk(KERN_INFO "%s", version);
+       printk_once(KERN_INFO "%s", version);
 
        /* Apple gmac note: during probe, the chip is powered up by
         * the arch code to allow the code below to work (and to let
@@ -3026,8 +2988,7 @@ static int __devinit gem_init_one(struct pci_dev *pdev,
         */
        err = pci_enable_device(pdev);
        if (err) {
-               printk(KERN_ERR PFX "Cannot enable MMIO operation, "
-                      "aborting.\n");
+               pr_err("Cannot enable MMIO operation, aborting\n");
                return err;
        }
        pci_set_master(pdev);
@@ -3048,8 +3009,7 @@ static int __devinit gem_init_one(struct pci_dev *pdev,
        } else {
                err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
                if (err) {
-                       printk(KERN_ERR PFX "No usable DMA configuration, "
-                              "aborting.\n");
+                       pr_err("No usable DMA configuration, aborting\n");
                        goto err_disable_device;
                }
                pci_using_dac = 0;
@@ -3059,15 +3019,14 @@ static int __devinit gem_init_one(struct pci_dev *pdev,
        gemreg_len = pci_resource_len(pdev, 0);
 
        if ((pci_resource_flags(pdev, 0) & IORESOURCE_IO) != 0) {
-               printk(KERN_ERR PFX "Cannot find proper PCI device "
-                      "base address, aborting.\n");
+               pr_err("Cannot find proper PCI device base address, aborting\n");
                err = -ENODEV;
                goto err_disable_device;
        }
 
        dev = alloc_etherdev(sizeof(*gp));
        if (!dev) {
-               printk(KERN_ERR PFX "Etherdev alloc failed, aborting.\n");
+               pr_err("Etherdev alloc failed, aborting\n");
                err = -ENOMEM;
                goto err_disable_device;
        }
@@ -3077,8 +3036,7 @@ static int __devinit gem_init_one(struct pci_dev *pdev,
 
        err = pci_request_regions(pdev, DRV_NAME);
        if (err) {
-               printk(KERN_ERR PFX "Cannot obtain PCI resources, "
-                      "aborting.\n");
+               pr_err("Cannot obtain PCI resources, aborting\n");
                goto err_out_free_netdev;
        }
 
@@ -3104,8 +3062,7 @@ static int __devinit gem_init_one(struct pci_dev *pdev,
 
        gp->regs = ioremap(gemreg_base, gemreg_len);
        if (!gp->regs) {
-               printk(KERN_ERR PFX "Cannot map device registers, "
-                      "aborting.\n");
+               pr_err("Cannot map device registers, aborting\n");
                err = -EIO;
                goto err_out_free_res;
        }
@@ -3150,8 +3107,7 @@ static int __devinit gem_init_one(struct pci_dev *pdev,
                pci_alloc_consistent(pdev, sizeof(struct gem_init_block),
                                     &gp->gblock_dvma);
        if (!gp->init_block) {
-               printk(KERN_ERR PFX "Cannot allocate init block, "
-                      "aborting.\n");
+               pr_err("Cannot allocate init block, aborting\n");
                err = -ENOMEM;
                goto err_out_iounmap;
        }
@@ -3180,19 +3136,18 @@ static int __devinit gem_init_one(struct pci_dev *pdev,
 
        /* Register with kernel */
        if (register_netdev(dev)) {
-               printk(KERN_ERR PFX "Cannot register net device, "
-                      "aborting.\n");
+               pr_err("Cannot register net device, aborting\n");
                err = -ENOMEM;
                goto err_out_free_consistent;
        }
 
-       printk(KERN_INFO "%s: Sun GEM (PCI) 10/100/1000BaseT Ethernet %pM\n",
-              dev->name, dev->dev_addr);
+       netdev_info(dev, "Sun GEM (PCI) 10/100/1000BaseT Ethernet %pM\n",
+                   dev->dev_addr);
 
        if (gp->phy_type == phy_mii_mdio0 ||
            gp->phy_type == phy_mii_mdio1)
-               printk(KERN_INFO "%s: Found %s PHY\n", dev->name,
-                       gp->phy_mii.def ? gp->phy_mii.def->name : "no");
+               netdev_info(dev, "Found %s PHY\n",
+                           gp->phy_mii.def ? gp->phy_mii.def->name : "no");
 
        /* GEM can do it all... */
        dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_LLTX;
index 78f8cee5fd7428b96e447e568d07c0cafb959f47..4a4fac630337695793032f0aeb031cbdc6c6162b 100644 (file)
@@ -1175,7 +1175,8 @@ int mii_phy_probe(struct mii_phy *phy, int mii_id)
 
        /* Read ID and find matching entry */
        id = (phy_read(phy, MII_PHYSID1) << 16 | phy_read(phy, MII_PHYSID2));
-       printk(KERN_DEBUG "PHY ID: %x, addr: %x\n", id, mii_id);
+       printk(KERN_DEBUG KBUILD_MODNAME ": " "PHY ID: %x, addr: %x\n",
+              id, mii_id);
        for (i=0; (def = mii_phy_table[i]) != NULL; i++)
                if ((id & def->phy_id_mask) == def->phy_id)
                        break;
index bd0df1c1495587e9f6cf5f03ed85f98fbce5c2c7..45f315ed1868d02ba2737e018215c3e4a67c7fa0 100644 (file)
@@ -1409,7 +1409,7 @@ force_link:
        hp->timer_ticks = 0;
        hp->happy_timer.expires = jiffies + (12 * HZ)/10;  /* 1.2 sec. */
        hp->happy_timer.data = (unsigned long) hp;
-       hp->happy_timer.function = &happy_meal_timer;
+       hp->happy_timer.function = happy_meal_timer;
        add_timer(&hp->happy_timer);
 }
 
@@ -2808,7 +2808,8 @@ static int __devinit happy_meal_sbus_probe_one(struct platform_device *op, int i
        happy_meal_set_initial_advertisement(hp);
        spin_unlock_irq(&hp->happy_lock);
 
-       if (register_netdev(hp->dev)) {
+       err = register_netdev(hp->dev);
+       if (err) {
                printk(KERN_ERR "happymeal: Cannot register net device, "
                       "aborting.\n");
                goto err_out_free_coherent;
@@ -3130,7 +3131,8 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev,
        happy_meal_set_initial_advertisement(hp);
        spin_unlock_irq(&hp->happy_lock);
 
-       if (register_netdev(hp->dev)) {
+       err = register_netdev(hp->dev);
+       if (err) {
                printk(KERN_ERR "happymeal(PCI): Cannot register net device, "
                       "aborting.\n");
                goto err_out_iounmap;
index 8dcb858f216859c600a8c251ac5d714bc938976b..2cf84e5968b2b3217fd487c53f82420d31f71868 100644 (file)
@@ -1483,7 +1483,7 @@ no_link_test:
         */
        init_timer(&lp->multicast_timer);
        lp->multicast_timer.data = (unsigned long) dev;
-       lp->multicast_timer.function = &lance_set_multicast_retry;
+       lp->multicast_timer.function = lance_set_multicast_retry;
 
        if (register_netdev(dev)) {
                printk(KERN_ERR "SunLance: Cannot register device.\n");
index d281a7b34701060d4ab23f3f2c764b684bf7bb0d..bf3c762de6204ac7c2536e210e1b89a16e5a28d0 100644 (file)
@@ -3,6 +3,8 @@
  * Copyright (C) 2007, 2008 David S. Miller <davem@davemloft.net>
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
@@ -20,7 +22,6 @@
 #include "sunvnet.h"
 
 #define DRV_MODULE_NAME                "sunvnet"
-#define PFX DRV_MODULE_NAME    ": "
 #define DRV_MODULE_VERSION     "1.0"
 #define DRV_MODULE_RELDATE     "June 25, 2007"
 
@@ -45,9 +46,9 @@ static int vnet_handle_unknown(struct vnet_port *port, void *arg)
 {
        struct vio_msg_tag *pkt = arg;
 
-       printk(KERN_ERR PFX "Received unknown msg [%02x:%02x:%04x:%08x]\n",
+       pr_err("Received unknown msg [%02x:%02x:%04x:%08x]\n",
               pkt->type, pkt->stype, pkt->stype_env, pkt->sid);
-       printk(KERN_ERR PFX "Resetting connection.\n");
+       pr_err("Resetting connection\n");
 
        ldc_disconnect(port->vio.lp);
 
@@ -400,8 +401,8 @@ static int vnet_rx(struct vnet_port *port, void *msgbuf)
        if (unlikely(pkt->tag.stype_env != VIO_DRING_DATA))
                return 0;
        if (unlikely(pkt->seq != dr->rcv_nxt)) {
-               printk(KERN_ERR PFX "RX out of sequence seq[0x%llx] "
-                      "rcv_nxt[0x%llx]\n", pkt->seq, dr->rcv_nxt);
+               pr_err("RX out of sequence seq[0x%llx] rcv_nxt[0x%llx]\n",
+                      pkt->seq, dr->rcv_nxt);
                return 0;
        }
 
@@ -464,8 +465,7 @@ static int handle_mcast(struct vnet_port *port, void *msgbuf)
        struct vio_net_mcast_info *pkt = msgbuf;
 
        if (pkt->tag.stype != VIO_SUBTYPE_ACK)
-               printk(KERN_ERR PFX "%s: Got unexpected MCAST reply "
-                      "[%02x:%02x:%04x:%08x]\n",
+               pr_err("%s: Got unexpected MCAST reply [%02x:%02x:%04x:%08x]\n",
                       port->vp->dev->name,
                       pkt->tag.type,
                       pkt->tag.stype,
@@ -520,7 +520,7 @@ static void vnet_event(void *arg, int event)
        }
 
        if (unlikely(event != LDC_EVENT_DATA_READY)) {
-               printk(KERN_WARNING PFX "Unexpected LDC event %d\n", event);
+               pr_warning("Unexpected LDC event %d\n", event);
                spin_unlock_irqrestore(&vio->lock, flags);
                return;
        }
@@ -662,8 +662,7 @@ static int vnet_start_xmit(struct sk_buff *skb, struct net_device *dev)
                        netif_stop_queue(dev);
 
                        /* This is a hard error, log it. */
-                       printk(KERN_ERR PFX "%s: BUG! Tx Ring full when "
-                              "queue awake!\n", dev->name);
+                       netdev_err(dev, "BUG! Tx Ring full when queue awake!\n");
                        dev->stats.tx_errors++;
                }
                spin_unlock_irqrestore(&port->vio.lock, flags);
@@ -696,8 +695,7 @@ static int vnet_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        err = __vnet_tx_trigger(port);
        if (unlikely(err < 0)) {
-               printk(KERN_INFO PFX "%s: TX trigger error %d\n",
-                      dev->name, err);
+               netdev_info(dev, "TX trigger error %d\n", err);
                d->hdr.state = VIO_DESC_FREE;
                dev->stats.tx_carrier_errors++;
                goto out_dropped_unlock;
@@ -952,12 +950,12 @@ static int __devinit vnet_port_alloc_tx_bufs(struct vnet_port *port)
 
                err = -ENOMEM;
                if (!buf) {
-                       printk(KERN_ERR "TX buffer allocation failure\n");
+                       pr_err("TX buffer allocation failure\n");
                        goto err_out;
                }
                err = -EFAULT;
                if ((unsigned long)buf & (8UL - 1)) {
-                       printk(KERN_ERR "TX buffer misaligned\n");
+                       pr_err("TX buffer misaligned\n");
                        kfree(buf);
                        goto err_out;
                }
@@ -1030,7 +1028,7 @@ static struct vnet * __devinit vnet_new(const u64 *local_mac)
 
        dev = alloc_etherdev(sizeof(*vp));
        if (!dev) {
-               printk(KERN_ERR PFX "Etherdev alloc failed, aborting.\n");
+               pr_err("Etherdev alloc failed, aborting\n");
                return ERR_PTR(-ENOMEM);
        }
 
@@ -1056,12 +1054,11 @@ static struct vnet * __devinit vnet_new(const u64 *local_mac)
 
        err = register_netdev(dev);
        if (err) {
-               printk(KERN_ERR PFX "Cannot register net device, "
-                      "aborting.\n");
+               pr_err("Cannot register net device, aborting\n");
                goto err_out_free_dev;
        }
 
-       printk(KERN_INFO "%s: Sun LDOM vnet %pM\n", dev->name, dev->dev_addr);
+       netdev_info(dev, "Sun LDOM vnet %pM\n", dev->dev_addr);
 
        list_add(&vp->list, &vnet_list);
 
@@ -1133,10 +1130,7 @@ static struct vio_driver_ops vnet_vio_ops = {
 
 static void __devinit print_version(void)
 {
-       static int version_printed;
-
-       if (version_printed++ == 0)
-               printk(KERN_INFO "%s", version);
+       printk_once(KERN_INFO "%s", version);
 }
 
 const char *remote_macaddr_prop = "remote-mac-address";
@@ -1157,7 +1151,7 @@ static int __devinit vnet_port_probe(struct vio_dev *vdev,
 
        vp = vnet_find_parent(hp, vdev->mp);
        if (IS_ERR(vp)) {
-               printk(KERN_ERR PFX "Cannot find port parent vnet.\n");
+               pr_err("Cannot find port parent vnet\n");
                err = PTR_ERR(vp);
                goto err_out_put_mdesc;
        }
@@ -1165,15 +1159,14 @@ static int __devinit vnet_port_probe(struct vio_dev *vdev,
        rmac = mdesc_get_property(hp, vdev->mp, remote_macaddr_prop, &len);
        err = -ENODEV;
        if (!rmac) {
-               printk(KERN_ERR PFX "Port lacks %s property.\n",
-                      remote_macaddr_prop);
+               pr_err("Port lacks %s property\n", remote_macaddr_prop);
                goto err_out_put_mdesc;
        }
 
        port = kzalloc(sizeof(*port), GFP_KERNEL);
        err = -ENOMEM;
        if (!port) {
-               printk(KERN_ERR PFX "Cannot allocate vnet_port.\n");
+               pr_err("Cannot allocate vnet_port\n");
                goto err_out_put_mdesc;
        }
 
@@ -1214,9 +1207,8 @@ static int __devinit vnet_port_probe(struct vio_dev *vdev,
 
        dev_set_drvdata(&vdev->dev, port);
 
-       printk(KERN_INFO "%s: PORT ( remote-mac %pM%s )\n",
-              vp->dev->name, port->raddr,
-              switch_port ? " switch-port" : "");
+       pr_info("%s: PORT ( remote-mac %pM%s )\n",
+               vp->dev->name, port->raddr, switch_port ? " switch-port" : "");
 
        vio_port_up(&port->vio);
 
index 737df6032bbc1d4bd9635b78210a52bcfa7efea2..8b3dc1eb401541e8e1c3de31ce5308d84f477845 100644 (file)
@@ -92,7 +92,7 @@ static void bdx_rx_free(struct bdx_priv *priv);
 static void bdx_tx_free(struct bdx_priv *priv);
 
 /* Definitions needed by bdx_probe */
-static void bdx_ethtool_ops(struct net_device *netdev);
+static void bdx_set_ethtool_ops(struct net_device *netdev);
 
 /*************************************************************************
  *    Print Info                                                         *
@@ -927,13 +927,6 @@ static void bdx_update_stats(struct bdx_priv *priv)
        BDX_ASSERT((sizeof(struct bdx_stats) / sizeof(u64)) != i);
 }
 
-static struct net_device_stats *bdx_get_stats(struct net_device *ndev)
-{
-       struct bdx_priv *priv = netdev_priv(ndev);
-       struct net_device_stats *net_stat = &priv->net_stats;
-       return net_stat;
-}
-
 static void print_rxdd(struct rxd_desc *rxdd, u32 rxd_val1, u16 len,
                       u16 rxd_vlan);
 static void print_rxfd(struct rxf_desc *rxfd);
@@ -1220,6 +1213,7 @@ static void bdx_recycle_skb(struct bdx_priv *priv, struct rxd_desc *rxdd)
 
 static int bdx_rx_receive(struct bdx_priv *priv, struct rxd_fifo *f, int budget)
 {
+       struct net_device *ndev = priv->ndev;
        struct sk_buff *skb, *skb2;
        struct rxd_desc *rxdd;
        struct rx_map *dm;
@@ -1273,7 +1267,7 @@ static int bdx_rx_receive(struct bdx_priv *priv, struct rxd_fifo *f, int budget)
 
                if (unlikely(GET_RXD_ERR(rxd_val1))) {
                        DBG("rxd_err = 0x%x\n", GET_RXD_ERR(rxd_val1));
-                       priv->net_stats.rx_errors++;
+                       ndev->stats.rx_errors++;
                        bdx_recycle_skb(priv, rxdd);
                        continue;
                }
@@ -1300,15 +1294,16 @@ static int bdx_rx_receive(struct bdx_priv *priv, struct rxd_fifo *f, int budget)
                        bdx_rxdb_free_elem(db, rxdd->va_lo);
                }
 
-               priv->net_stats.rx_bytes += len;
+               ndev->stats.rx_bytes += len;
 
                skb_put(skb, len);
-               skb->ip_summed = CHECKSUM_UNNECESSARY;
-               skb->protocol = eth_type_trans(skb, priv->ndev);
+               skb->protocol = eth_type_trans(skb, ndev);
 
                /* Non-IP packets aren't checksum-offloaded */
                if (GET_RXD_PKT_ID(rxd_val1) == 0)
-                       skb->ip_summed = CHECKSUM_NONE;
+                       skb_checksum_none_assert(skb);
+               else
+                       skb->ip_summed = CHECKSUM_UNNECESSARY;
 
                NETIF_RX_MUX(priv, rxd_val1, rxd_vlan, skb);
 
@@ -1316,7 +1311,7 @@ static int bdx_rx_receive(struct bdx_priv *priv, struct rxd_fifo *f, int budget)
                        break;
        }
 
-       priv->net_stats.rx_packets += done;
+       ndev->stats.rx_packets += done;
 
        /* FIXME: do smth to minimize pci accesses    */
        WRITE_REG(priv, f->m.reg_RPTR, f->m.rptr & TXF_WPTR_WR_PTR);
@@ -1712,8 +1707,8 @@ static netdev_tx_t bdx_tx_transmit(struct sk_buff *skb,
 #ifdef BDX_LLTX
        ndev->trans_start = jiffies; /* NETIF_F_LLTX driver :( */
 #endif
-       priv->net_stats.tx_packets++;
-       priv->net_stats.tx_bytes += skb->len;
+       ndev->stats.tx_packets++;
+       ndev->stats.tx_bytes += skb->len;
 
        if (priv->tx_level < BDX_MIN_TX_LEVEL) {
                DBG("%s: %s: TX Q STOP level %d\n",
@@ -1888,7 +1883,6 @@ static const struct net_device_ops bdx_netdev_ops = {
        .ndo_validate_addr      = eth_validate_addr,
        .ndo_do_ioctl           = bdx_ioctl,
        .ndo_set_multicast_list = bdx_setmulti,
-       .ndo_get_stats          = bdx_get_stats,
        .ndo_change_mtu         = bdx_change_mtu,
        .ndo_set_mac_address    = bdx_set_mac,
        .ndo_vlan_rx_register   = bdx_vlan_rx_register,
@@ -2012,7 +2006,7 @@ bdx_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                ndev->netdev_ops = &bdx_netdev_ops;
                ndev->tx_queue_len = BDX_NDEV_TXQ_LEN;
 
-               bdx_ethtool_ops(ndev);  /* ethtool interface */
+               bdx_set_ethtool_ops(ndev);      /* ethtool interface */
 
                /* these fields are used for info purposes only
                 * so we can have them same for all ports of the board */
@@ -2417,10 +2411,10 @@ static void bdx_get_ethtool_stats(struct net_device *netdev,
 }
 
 /*
- * bdx_ethtool_ops - ethtool interface implementation
+ * bdx_set_ethtool_ops - ethtool interface implementation
  * @netdev
  */
-static void bdx_ethtool_ops(struct net_device *netdev)
+static void bdx_set_ethtool_ops(struct net_device *netdev)
 {
        static const struct ethtool_ops bdx_ethtool_ops = {
                .get_settings = bdx_get_settings,
index 67e3b71bf7059de90cb861cc2f23e8d6ff252020..b6ba8601e2b538b70e892273a23107ca04192cc5 100644 (file)
@@ -269,7 +269,6 @@ struct bdx_priv {
        u32 msg_enable;
        int stats_flag;
        struct bdx_stats hw_stats;
-       struct net_device_stats net_stats;
        struct pci_dev *pdev;
 
        struct pci_nic *nic;
index bc3af78a869ff52881077b89cf6e5e544b6e8a91..9f6ffffc8376ad84a8085f526608e6e248c45c79 100644 (file)
@@ -4719,7 +4719,7 @@ static int tg3_rx(struct tg3_napi *tnapi, int budget)
                      >> RXD_TCPCSUM_SHIFT) == 0xffff))
                        skb->ip_summed = CHECKSUM_UNNECESSARY;
                else
-                       skb->ip_summed = CHECKSUM_NONE;
+                       skb_checksum_none_assert(skb);
 
                skb->protocol = eth_type_trans(skb, tp->dev);
 
index ccee3eddc5f4c24b4afcdf6cb4dcaf8759165b7a..0564ca05963d8f6ff0be63b2b7484f16bd2fbab0 100644 (file)
@@ -393,7 +393,7 @@ TLan_SetTimer( struct net_device *dev, u32 ticks, u32 type )
                        spin_unlock_irqrestore(&priv->lock, flags);
                return;
        }
-       priv->timer.function = &TLan_Timer;
+       priv->timer.function = TLan_Timer;
        if (!in_irq())
                spin_unlock_irqrestore(&priv->lock, flags);
 
@@ -1453,7 +1453,7 @@ static u32 TLan_HandleTxEOF( struct net_device *dev, u16 host_int )
                TLan_DioWrite8( dev->base_addr,
                                TLAN_LED_REG, TLAN_LED_LINK | TLAN_LED_ACT );
                if ( priv->timer.function == NULL ) {
-                        priv->timer.function = &TLan_Timer;
+                        priv->timer.function = TLan_Timer;
                         priv->timer.data = (unsigned long) dev;
                         priv->timer.expires = jiffies + TLAN_TIMER_ACT_DELAY;
                         priv->timerSetAt = jiffies;
@@ -1601,7 +1601,7 @@ drop_and_reuse:
                TLan_DioWrite8( dev->base_addr,
                                TLAN_LED_REG, TLAN_LED_LINK | TLAN_LED_ACT );
                if ( priv->timer.function == NULL )  {
-                       priv->timer.function = &TLan_Timer;
+                       priv->timer.function = TLan_Timer;
                        priv->timer.data = (unsigned long) dev;
                        priv->timer.expires = jiffies + TLAN_TIMER_ACT_DELAY;
                        priv->timerSetAt = jiffies;
@@ -1897,7 +1897,7 @@ static void TLan_Timer( unsigned long data )
                                        TLan_DioWrite8( dev->base_addr,
                                                        TLAN_LED_REG, TLAN_LED_LINK );
                                } else  {
-                                       priv->timer.function = &TLan_Timer;
+                                       priv->timer.function = TLan_Timer;
                                        priv->timer.expires = priv->timerSetAt
                                                + TLAN_TIMER_ACT_DELAY;
                                        spin_unlock_irqrestore(&priv->lock, flags);
index 435ef7d5470fd8e8e6c4849c1d3dc930a13e1b3f..08182fde3dcdd5684044c860cc564fd17f6497f2 100644 (file)
@@ -1321,14 +1321,12 @@ static int tms380tr_reset_adapter(struct net_device *dev)
 
                        /* Clear CPHALT and start BUD */
                        SIFWRITEW(c, SIFACL);
-                       if (fw_entry)
-                               release_firmware(fw_entry);
+                       release_firmware(fw_entry);
                        return (1);
                }
        } while(count == 0);
 
-       if (fw_entry)
-               release_firmware(fw_entry);
+       release_firmware(fw_entry);
        printk(KERN_INFO "%s: Adapter Download Failed\n", dev->name);
        return (-1);
 }
index 0bc4f3030a806e53c7bb9a1528ec1933e62a0e8d..a9f7d5d1a2695f95a968001a93c1449b9ac998be 100644 (file)
@@ -599,7 +599,7 @@ static int dmfe_open(struct DEVICE *dev)
        init_timer(&db->timer);
        db->timer.expires = DMFE_TIMER_WUT + HZ * 2;
        db->timer.data = (unsigned long)dev;
-       db->timer.function = &dmfe_timer;
+       db->timer.function = dmfe_timer;
        add_timer(&db->timer);
 
        return 0;
index 1faf7a4d72024da4ffd864dfddb99502edd6fcc6..0013642903eecda0e8226579176de6f2f93babc5 100644 (file)
@@ -180,21 +180,24 @@ int tulip_poll(struct napi_struct *napi, int budget)
                                                        dev_warn(&dev->dev,
                                                                "Oversized Ethernet frame spanned multiple buffers, status %08x!\n",
                                                                status);
-                                               tp->stats.rx_length_errors++;
-                                       }
+                                               dev->stats.rx_length_errors++;
+                                       }
                               } else {
                                 /* There was a fatal error. */
                                        if (tulip_debug > 2)
                                                printk(KERN_DEBUG "%s: Receive error, Rx status %08x\n",
                                                       dev->name, status);
-                                       tp->stats.rx_errors++; /* end of a packet.*/
-                                      if (pkt_len > 1518 ||
-                                          (status & RxDescRunt))
-                                              tp->stats.rx_length_errors++;
-
-                                       if (status & 0x0004) tp->stats.rx_frame_errors++;
-                                       if (status & 0x0002) tp->stats.rx_crc_errors++;
-                                       if (status & 0x0001) tp->stats.rx_fifo_errors++;
+                                       dev->stats.rx_errors++; /* end of a packet.*/
+                                       if (pkt_len > 1518 ||
+                                           (status & RxDescRunt))
+                                               dev->stats.rx_length_errors++;
+
+                                       if (status & 0x0004)
+                                               dev->stats.rx_frame_errors++;
+                                       if (status & 0x0002)
+                                               dev->stats.rx_crc_errors++;
+                                       if (status & 0x0001)
+                                               dev->stats.rx_fifo_errors++;
                                }
                        } else {
                                struct sk_buff *skb;
@@ -244,8 +247,8 @@ int tulip_poll(struct napi_struct *napi, int budget)
 
                                netif_receive_skb(skb);
 
-                               tp->stats.rx_packets++;
-                               tp->stats.rx_bytes += pkt_len;
+                               dev->stats.rx_packets++;
+                               dev->stats.rx_bytes += pkt_len;
                        }
 #ifdef CONFIG_TULIP_NAPI_HW_MITIGATION
                       received++;
@@ -404,20 +407,23 @@ static int tulip_rx(struct net_device *dev)
                                                dev_warn(&dev->dev,
                                                         "Oversized Ethernet frame spanned multiple buffers, status %08x!\n",
                                                         status);
-                                       tp->stats.rx_length_errors++;
+                                       dev->stats.rx_length_errors++;
                                }
                        } else {
                                /* There was a fatal error. */
                                if (tulip_debug > 2)
                                        printk(KERN_DEBUG "%s: Receive error, Rx status %08x\n",
                                               dev->name, status);
-                               tp->stats.rx_errors++; /* end of a packet.*/
+                               dev->stats.rx_errors++; /* end of a packet.*/
                                if (pkt_len > 1518 ||
                                    (status & RxDescRunt))
-                                       tp->stats.rx_length_errors++;
-                               if (status & 0x0004) tp->stats.rx_frame_errors++;
-                               if (status & 0x0002) tp->stats.rx_crc_errors++;
-                               if (status & 0x0001) tp->stats.rx_fifo_errors++;
+                                       dev->stats.rx_length_errors++;
+                               if (status & 0x0004)
+                                       dev->stats.rx_frame_errors++;
+                               if (status & 0x0002)
+                                       dev->stats.rx_crc_errors++;
+                               if (status & 0x0001)
+                                       dev->stats.rx_fifo_errors++;
                        }
                } else {
                        struct sk_buff *skb;
@@ -467,8 +473,8 @@ static int tulip_rx(struct net_device *dev)
 
                        netif_rx(skb);
 
-                       tp->stats.rx_packets++;
-                       tp->stats.rx_bytes += pkt_len;
+                       dev->stats.rx_packets++;
+                       dev->stats.rx_bytes += pkt_len;
                }
                received++;
                entry = (++tp->cur_rx) % RX_RING_SIZE;
@@ -602,18 +608,22 @@ irqreturn_t tulip_interrupt(int irq, void *dev_instance)
                                                printk(KERN_DEBUG "%s: Transmit error, Tx status %08x\n",
                                                       dev->name, status);
 #endif
-                                       tp->stats.tx_errors++;
-                                       if (status & 0x4104) tp->stats.tx_aborted_errors++;
-                                       if (status & 0x0C00) tp->stats.tx_carrier_errors++;
-                                       if (status & 0x0200) tp->stats.tx_window_errors++;
-                                       if (status & 0x0002) tp->stats.tx_fifo_errors++;
+                                       dev->stats.tx_errors++;
+                                       if (status & 0x4104)
+                                               dev->stats.tx_aborted_errors++;
+                                       if (status & 0x0C00)
+                                               dev->stats.tx_carrier_errors++;
+                                       if (status & 0x0200)
+                                               dev->stats.tx_window_errors++;
+                                       if (status & 0x0002)
+                                               dev->stats.tx_fifo_errors++;
                                        if ((status & 0x0080) && tp->full_duplex == 0)
-                                               tp->stats.tx_heartbeat_errors++;
+                                               dev->stats.tx_heartbeat_errors++;
                                } else {
-                                       tp->stats.tx_bytes +=
+                                       dev->stats.tx_bytes +=
                                                tp->tx_buffers[entry].skb->len;
-                                       tp->stats.collisions += (status >> 3) & 15;
-                                       tp->stats.tx_packets++;
+                                       dev->stats.collisions += (status >> 3) & 15;
+                                       dev->stats.tx_packets++;
                                }
 
                                pci_unmap_single(tp->pdev, tp->tx_buffers[entry].mapping,
@@ -655,7 +665,8 @@ irqreturn_t tulip_interrupt(int irq, void *dev_instance)
                if (csr5 & AbnormalIntr) {      /* Abnormal error summary bit. */
                        if (csr5 == 0xffffffff)
                                break;
-                       if (csr5 & TxJabber) tp->stats.tx_errors++;
+                       if (csr5 & TxJabber)
+                               dev->stats.tx_errors++;
                        if (csr5 & TxFIFOUnderflow) {
                                if ((tp->csr6 & 0xC000) != 0xC000)
                                        tp->csr6 += 0x4000;     /* Bump up the Tx threshold */
@@ -672,8 +683,8 @@ irqreturn_t tulip_interrupt(int irq, void *dev_instance)
                                }
                        }
                        if (csr5 & RxDied) {            /* Missed a Rx frame. */
-                                tp->stats.rx_missed_errors += ioread32(ioaddr + CSR8) & 0xffff;
-                               tp->stats.rx_errors++;
+                               dev->stats.rx_missed_errors += ioread32(ioaddr + CSR8) & 0xffff;
+                               dev->stats.rx_errors++;
                                tulip_start_rxtx(tp);
                        }
                        /*
@@ -789,7 +800,7 @@ irqreturn_t tulip_interrupt(int irq, void *dev_instance)
 #endif /* CONFIG_TULIP_NAPI */
 
        if ((missed = ioread32(ioaddr + CSR8) & 0x1ffff)) {
-               tp->stats.rx_dropped += missed & 0x10000 ? 0x10000 : missed;
+               dev->stats.rx_dropped += missed & 0x10000 ? 0x10000 : missed;
        }
 
        if (tulip_debug > 4)
index e525875ed67d4b0aaadcea64d4d0a8c87620776f..ed66a16711dceadc550db0316bd52c8bef15688d 100644 (file)
@@ -417,7 +417,6 @@ struct tulip_private {
        int revision;
        int flags;
        struct napi_struct napi;
-       struct net_device_stats stats;
        struct timer_list timer;        /* Media selection timer. */
        struct timer_list oom_timer;    /* Out of memory timer. */
        u32 mc_filter[2];
@@ -570,7 +569,7 @@ static inline void tulip_tx_timeout_complete(struct tulip_private *tp, void __io
        /* Trigger an immediate transmit demand. */
        iowrite32(0, ioaddr + CSR1);
 
-       tp->stats.tx_errors++;
+       tp->dev->stats.tx_errors++;
 }
 
 #endif /* __NET_TULIP_H__ */
index 3a8d7efa2acf554c6015de56a66b3390fc7503a1..2c39f25912167fd144f4dae7f9681648e924c446 100644 (file)
@@ -725,7 +725,7 @@ static void tulip_clean_tx_ring(struct tulip_private *tp)
                int status = le32_to_cpu(tp->tx_ring[entry].status);
 
                if (status < 0) {
-                       tp->stats.tx_errors++;  /* It wasn't Txed */
+                       tp->dev->stats.tx_errors++;     /* It wasn't Txed */
                        tp->tx_ring[entry].status = 0;
                }
 
@@ -781,8 +781,8 @@ static void tulip_down (struct net_device *dev)
        /* release any unconsumed transmit buffers */
        tulip_clean_tx_ring(tp);
 
-       if (ioread32 (ioaddr + CSR6) != 0xffffffff)
-               tp->stats.rx_missed_errors += ioread32 (ioaddr + CSR8) & 0xffff;
+       if (ioread32(ioaddr + CSR6) != 0xffffffff)
+               dev->stats.rx_missed_errors += ioread32(ioaddr + CSR8) & 0xffff;
 
        spin_unlock_irqrestore (&tp->lock, flags);
 
@@ -864,12 +864,12 @@ static struct net_device_stats *tulip_get_stats(struct net_device *dev)
 
                spin_lock_irqsave (&tp->lock, flags);
 
-               tp->stats.rx_missed_errors += ioread32(ioaddr + CSR8) & 0xffff;
+               dev->stats.rx_missed_errors += ioread32(ioaddr + CSR8) & 0xffff;
 
                spin_unlock_irqrestore(&tp->lock, flags);
        }
 
-       return &tp->stats;
+       return &dev->stats;
 }
 
 
index 96de5829b940806729f02fa26eeb7537713e821d..1dc27a55727565f5b576365644efeb80306bea1d 100644 (file)
@@ -480,7 +480,7 @@ static int uli526x_open(struct net_device *dev)
        init_timer(&db->timer);
        db->timer.expires = ULI526X_TIMER_WUT + HZ * 2;
        db->timer.data = (unsigned long)dev;
-       db->timer.function = &uli526x_timer;
+       db->timer.function = uli526x_timer;
        add_timer(&db->timer);
 
        return 0;
index 66d41cf8da29fb5e233f3be923278142ee61b7a4..f0b231035dee9f2450c43e1b68da0aafafc892ed 100644 (file)
@@ -662,7 +662,7 @@ static int netdev_open(struct net_device *dev)
        init_timer(&np->timer);
        np->timer.expires = jiffies + 1*HZ;
        np->timer.data = (unsigned long)dev;
-       np->timer.function = &netdev_timer;                             /* timer handler */
+       np->timer.function = netdev_timer;                              /* timer handler */
        add_timer(&np->timer);
        return 0;
 out_err:
index a439e93be22d24132f29e6b146b9d1a0af430178..5a73752be2ca2cdf455968855f82ae5b3bfa8f9e 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/skbuff.h>
 #include <linux/delay.h>
 #include <linux/init.h>
-#include <linux/ethtool.h>
 #include <linux/bitops.h>
 
 #include <asm/uaccess.h>
@@ -181,19 +180,6 @@ static void print_binary(unsigned int number)
 }
 #endif
 
-static void netdev_get_drvinfo(struct net_device *dev,
-                              struct ethtool_drvinfo *info)
-{
-       struct xircom_private *private = netdev_priv(dev);
-
-       strcpy(info->driver, "xircom_cb");
-       strcpy(info->bus_info, pci_name(private->pdev));
-}
-
-static const struct ethtool_ops netdev_ethtool_ops = {
-       .get_drvinfo            = netdev_get_drvinfo,
-};
-
 static const struct net_device_ops netdev_ops = {
        .ndo_open               = xircom_open,
        .ndo_stop               = xircom_close,
@@ -279,7 +265,6 @@ static int __devinit xircom_probe(struct pci_dev *pdev, const struct pci_device_
        setup_descriptors(private);
 
        dev->netdev_ops = &netdev_ops;
-       SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
        pci_set_drvdata(pdev, dev);
 
        if (register_netdev(dev)) {
index 2e50077ff450b249a9042259375b5288f41965c6..5dfb39539b3eefa9cb872bd6549ded40f49c7ee5 100644 (file)
@@ -962,36 +962,34 @@ typhoon_do_get_stats(struct typhoon *tp)
         * The extra status reported would be a good candidate for
         * ethtool_ops->get_{strings,stats}()
         */
-       stats->tx_packets = le32_to_cpu(s->txPackets);
-       stats->tx_bytes = le64_to_cpu(s->txBytes);
-       stats->tx_errors = le32_to_cpu(s->txCarrierLost);
-       stats->tx_carrier_errors = le32_to_cpu(s->txCarrierLost);
-       stats->collisions = le32_to_cpu(s->txMultipleCollisions);
-       stats->rx_packets = le32_to_cpu(s->rxPacketsGood);
-       stats->rx_bytes = le64_to_cpu(s->rxBytesGood);
-       stats->rx_fifo_errors = le32_to_cpu(s->rxFifoOverruns);
+       stats->tx_packets = le32_to_cpu(s->txPackets) +
+                       saved->tx_packets;
+       stats->tx_bytes = le64_to_cpu(s->txBytes) +
+                       saved->tx_bytes;
+       stats->tx_errors = le32_to_cpu(s->txCarrierLost) +
+                       saved->tx_errors;
+       stats->tx_carrier_errors = le32_to_cpu(s->txCarrierLost) +
+                       saved->tx_carrier_errors;
+       stats->collisions = le32_to_cpu(s->txMultipleCollisions) +
+                       saved->collisions;
+       stats->rx_packets = le32_to_cpu(s->rxPacketsGood) +
+                       saved->rx_packets;
+       stats->rx_bytes = le64_to_cpu(s->rxBytesGood) +
+                       saved->rx_bytes;
+       stats->rx_fifo_errors = le32_to_cpu(s->rxFifoOverruns) +
+                       saved->rx_fifo_errors;
        stats->rx_errors = le32_to_cpu(s->rxFifoOverruns) +
-                       le32_to_cpu(s->BadSSD) + le32_to_cpu(s->rxCrcErrors);
-       stats->rx_crc_errors = le32_to_cpu(s->rxCrcErrors);
-       stats->rx_length_errors = le32_to_cpu(s->rxOversized);
+                       le32_to_cpu(s->BadSSD) + le32_to_cpu(s->rxCrcErrors) +
+                       saved->rx_errors;
+       stats->rx_crc_errors = le32_to_cpu(s->rxCrcErrors) +
+                       saved->rx_crc_errors;
+       stats->rx_length_errors = le32_to_cpu(s->rxOversized) +
+                       saved->rx_length_errors;
        tp->speed = (s->linkStatus & TYPHOON_LINK_100MBPS) ?
                        SPEED_100 : SPEED_10;
        tp->duplex = (s->linkStatus & TYPHOON_LINK_FULL_DUPLEX) ?
                        DUPLEX_FULL : DUPLEX_HALF;
 
-       /* add in the saved statistics
-        */
-       stats->tx_packets += saved->tx_packets;
-       stats->tx_bytes += saved->tx_bytes;
-       stats->tx_errors += saved->tx_errors;
-       stats->collisions += saved->collisions;
-       stats->rx_packets += saved->rx_packets;
-       stats->rx_bytes += saved->rx_bytes;
-       stats->rx_fifo_errors += saved->rx_fifo_errors;
-       stats->rx_errors += saved->rx_errors;
-       stats->rx_crc_errors += saved->rx_crc_errors;
-       stats->rx_length_errors += saved->rx_length_errors;
-
        return 0;
 }
 
@@ -1762,7 +1760,7 @@ typhoon_rx(struct typhoon *tp, struct basic_ring *rxRing, volatile __le32 * read
                   (TYPHOON_RX_IP_CHK_GOOD | TYPHOON_RX_UDP_CHK_GOOD)) {
                        new_skb->ip_summed = CHECKSUM_UNNECESSARY;
                } else
-                       new_skb->ip_summed = CHECKSUM_NONE;
+                       skb_checksum_none_assert(new_skb);
 
                spin_lock(&tp->state_lock);
                if(tp->vlgrp != NULL && rx->rxStatus & TYPHOON_RX_VLAN)
index d7b7018a1de1d180a003af42e43d967b5441b38e..52ffabe6db0eac43cc39a14ece7326f1d686b5aa 100644 (file)
@@ -358,6 +358,14 @@ config USB_NET_ZAURUS
          really need this non-conformant variant of CDC Ethernet (or in
          some cases CDC MDLM) protocol, not "g_ether".
 
+config USB_NET_CX82310_ETH
+       tristate "Conexant CX82310 USB ethernet port"
+       depends on USB_USBNET
+       help
+         Choose this option if you're using a Conexant CX82310-based ADSL
+         router with USB ethernet port. This driver is for routers only,
+         it will not work with ADSL modems (use cxacru driver instead).
+
 config USB_HSO
        tristate "Option USB High Speed Mobile Devices"
        depends on USB && RFKILL
index b13a279663ba11b250a838c85619186d5e08eb56..a19b0259ae16c118165be08720553f0bbfa4d289 100644 (file)
@@ -25,4 +25,5 @@ obj-$(CONFIG_USB_NET_INT51X1) += int51x1.o
 obj-$(CONFIG_USB_CDC_PHONET)   += cdc-phonet.o
 obj-$(CONFIG_USB_IPHETH)       += ipheth.o
 obj-$(CONFIG_USB_SIERRA_NET)   += sierra_net.o
+obj-$(CONFIG_USB_NET_CX82310_ETH)      += cx82310_eth.o
 
diff --git a/drivers/net/usb/cx82310_eth.c b/drivers/net/usb/cx82310_eth.c
new file mode 100644 (file)
index 0000000..6fbe032
--- /dev/null
@@ -0,0 +1,354 @@
+/*
+ * Driver for USB ethernet port of Conexant CX82310-based ADSL routers
+ * Copyright (C) 2010 by Ondrej Zary
+ * some parts inspired by the cxacru driver
+ *
+ * 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.
+ *
+ * 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
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/workqueue.h>
+#include <linux/mii.h>
+#include <linux/usb.h>
+#include <linux/usb/usbnet.h>
+
+enum cx82310_cmd {
+       CMD_START               = 0x84, /* no effect? */
+       CMD_STOP                = 0x85, /* no effect? */
+       CMD_GET_STATUS          = 0x90, /* returns nothing? */
+       CMD_GET_MAC_ADDR        = 0x91, /* read MAC address */
+       CMD_GET_LINK_STATUS     = 0x92, /* not useful, link is always up */
+       CMD_ETHERNET_MODE       = 0x99, /* unknown, needed during init */
+};
+
+enum cx82310_status {
+       STATUS_UNDEFINED,
+       STATUS_SUCCESS,
+       STATUS_ERROR,
+       STATUS_UNSUPPORTED,
+       STATUS_UNIMPLEMENTED,
+       STATUS_PARAMETER_ERROR,
+       STATUS_DBG_LOOPBACK,
+};
+
+#define CMD_PACKET_SIZE        64
+/* first command after power on can take around 8 seconds */
+#define CMD_TIMEOUT    15000
+#define CMD_REPLY_RETRY 5
+
+#define CX82310_MTU    1514
+#define CMD_EP         0x01
+
+/*
+ * execute control command
+ *  - optionally send some data (command parameters)
+ *  - optionally wait for the reply
+ *  - optionally read some data from the reply
+ */
+static int cx82310_cmd(struct usbnet *dev, enum cx82310_cmd cmd, bool reply,
+                      u8 *wdata, int wlen, u8 *rdata, int rlen)
+{
+       int actual_len, retries, ret;
+       struct usb_device *udev = dev->udev;
+       u8 *buf = kzalloc(CMD_PACKET_SIZE, GFP_KERNEL);
+
+       if (!buf)
+               return -ENOMEM;
+
+       /* create command packet */
+       buf[0] = cmd;
+       if (wdata)
+               memcpy(buf + 4, wdata, min_t(int, wlen, CMD_PACKET_SIZE - 4));
+
+       /* send command packet */
+       ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, CMD_EP), buf,
+                          CMD_PACKET_SIZE, &actual_len, CMD_TIMEOUT);
+       if (ret < 0) {
+               dev_err(&dev->udev->dev, "send command %#x: error %d\n",
+                       cmd, ret);
+               goto end;
+       }
+
+       if (reply) {
+               /* wait for reply, retry if it's empty */
+               for (retries = 0; retries < CMD_REPLY_RETRY; retries++) {
+                       ret = usb_bulk_msg(udev, usb_rcvbulkpipe(udev, CMD_EP),
+                                          buf, CMD_PACKET_SIZE, &actual_len,
+                                          CMD_TIMEOUT);
+                       if (ret < 0) {
+                               dev_err(&dev->udev->dev,
+                                       "reply receive error %d\n", ret);
+                               goto end;
+                       }
+                       if (actual_len > 0)
+                               break;
+               }
+               if (actual_len == 0) {
+                       dev_err(&dev->udev->dev, "no reply to command %#x\n",
+                               cmd);
+                       ret = -EIO;
+                       goto end;
+               }
+               if (buf[0] != cmd) {
+                       dev_err(&dev->udev->dev,
+                               "got reply to command %#x, expected: %#x\n",
+                               buf[0], cmd);
+                       ret = -EIO;
+                       goto end;
+               }
+               if (buf[1] != STATUS_SUCCESS) {
+                       dev_err(&dev->udev->dev, "command %#x failed: %#x\n",
+                               cmd, buf[1]);
+                       ret = -EIO;
+                       goto end;
+               }
+               if (rdata)
+                       memcpy(rdata, buf + 4,
+                              min_t(int, rlen, CMD_PACKET_SIZE - 4));
+       }
+end:
+       kfree(buf);
+       return ret;
+}
+
+#define partial_len    data[0]         /* length of partial packet data */
+#define partial_rem    data[1]         /* remaining (missing) data length */
+#define partial_data   data[2]         /* partial packet data */
+
+static int cx82310_bind(struct usbnet *dev, struct usb_interface *intf)
+{
+       int ret;
+       char buf[15];
+       struct usb_device *udev = dev->udev;
+
+       /* avoid ADSL modems - continue only if iProduct is "USB NET CARD" */
+       if (udev->descriptor.iProduct &&
+           usb_string(udev, udev->descriptor.iProduct, buf, sizeof(buf)) &&
+           strcmp(buf, "USB NET CARD")) {
+               dev_err(&udev->dev,
+                       "probably an ADSL modem, use cxacru driver instead\n");
+               return -ENODEV;
+       }
+
+       ret = usbnet_get_endpoints(dev, intf);
+       if (ret)
+               return ret;
+
+       /*
+        * this must not include ethernet header as the device can send partial
+        * packets with no header (URB is at least 2 bytes long, so 2 is OK)
+        */
+       dev->net->hard_header_len = 2;
+       /* we can send at most 1514 bytes of data (+ 2-byte header) per URB */
+       dev->hard_mtu = CX82310_MTU + dev->net->hard_header_len;
+       /* we can receive URBs up to 4KB from the device */
+       dev->rx_urb_size = 4096;
+
+       dev->partial_data = (unsigned long) kmalloc(dev->hard_mtu, GFP_KERNEL);
+       if (!dev->partial_data)
+               return -ENOMEM;
+
+       /* enable ethernet mode (?) */
+       ret = cx82310_cmd(dev, CMD_ETHERNET_MODE, true, "\x01", 1, NULL, 0);
+       if (ret) {
+               dev_err(&udev->dev, "unable to enable ethernet mode: %d\n",
+                       ret);
+               goto err;
+       }
+
+       /* get the MAC address */
+       ret = cx82310_cmd(dev, CMD_GET_MAC_ADDR, true, NULL, 0,
+                         dev->net->dev_addr, ETH_ALEN);
+       if (ret) {
+               dev_err(&udev->dev, "unable to read MAC address: %d\n", ret);
+               goto err;
+       }
+
+       /* start (does not seem to have any effect?) */
+       ret = cx82310_cmd(dev, CMD_START, false, NULL, 0, NULL, 0);
+       if (ret)
+               goto err;
+
+       return 0;
+err:
+       kfree((void *)dev->partial_data);
+       return ret;
+}
+
+static void cx82310_unbind(struct usbnet *dev, struct usb_interface *intf)
+{
+       kfree((void *)dev->partial_data);
+}
+
+/*
+ * RX is NOT easy - we can receive multiple packets per skb, each having 2-byte
+ * packet length at the beginning.
+ * The last packet might be incomplete (when it crosses the 4KB URB size),
+ * continuing in the next skb (without any headers).
+ * If a packet has odd length, there is one extra byte at the end (before next
+ * packet or at the end of the URB).
+ */
+static int cx82310_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
+{
+       int len;
+       struct sk_buff *skb2;
+
+       /*
+        * If the last skb ended with an incomplete packet, this skb contains
+        * end of that packet at the beginning.
+        */
+       if (dev->partial_rem) {
+               len = dev->partial_len + dev->partial_rem;
+               skb2 = alloc_skb(len, GFP_ATOMIC);
+               if (!skb2)
+                       return 0;
+               skb_put(skb2, len);
+               memcpy(skb2->data, (void *)dev->partial_data,
+                      dev->partial_len);
+               memcpy(skb2->data + dev->partial_len, skb->data,
+                      dev->partial_rem);
+               usbnet_skb_return(dev, skb2);
+               skb_pull(skb, (dev->partial_rem + 1) & ~1);
+               dev->partial_rem = 0;
+               if (skb->len < 2)
+                       return 1;
+       }
+
+       if (skb->len < 2) {
+               dev_err(&dev->udev->dev, "RX frame too short: %d B\n",
+                       skb->len);
+               return 0;
+       }
+
+       /* a skb can contain multiple packets */
+       while (skb->len > 1) {
+               /* first two bytes are packet length */
+               len = skb->data[0] | (skb->data[1] << 8);
+               skb_pull(skb, 2);
+
+               /* if last packet in the skb, let usbnet to process it */
+               if (len == skb->len || len + 1 == skb->len) {
+                       skb_trim(skb, len);
+                       break;
+               }
+
+               if (len > CX82310_MTU) {
+                       dev_err(&dev->udev->dev, "RX packet too long: %d B\n",
+                               len);
+                       return 0;
+               }
+
+               /* incomplete packet, save it for the next skb */
+               if (len > skb->len) {
+                       dev->partial_len = skb->len;
+                       dev->partial_rem = len - skb->len;
+                       memcpy((void *)dev->partial_data, skb->data,
+                              dev->partial_len);
+                       skb_pull(skb, skb->len);
+                       break;
+               }
+
+               skb2 = alloc_skb(len, GFP_ATOMIC);
+               if (!skb2)
+                       return 0;
+               skb_put(skb2, len);
+               memcpy(skb2->data, skb->data, len);
+               /* process the packet */
+               usbnet_skb_return(dev, skb2);
+
+               skb_pull(skb, (len + 1) & ~1);
+       }
+
+       /* let usbnet process the last packet */
+       return 1;
+}
+
+/* TX is easy, just add 2 bytes of length at the beginning */
+static struct sk_buff *cx82310_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
+                                      gfp_t flags)
+{
+       int len = skb->len;
+
+       if (skb_headroom(skb) < 2) {
+               struct sk_buff *skb2 = skb_copy_expand(skb, 2, 0, flags);
+               dev_kfree_skb_any(skb);
+               skb = skb2;
+               if (!skb)
+                       return NULL;
+       }
+       skb_push(skb, 2);
+
+       skb->data[0] = len;
+       skb->data[1] = len >> 8;
+
+       return skb;
+}
+
+
+static const struct driver_info        cx82310_info = {
+       .description    = "Conexant CX82310 USB ethernet",
+       .flags          = FLAG_ETHER,
+       .bind           = cx82310_bind,
+       .unbind         = cx82310_unbind,
+       .rx_fixup       = cx82310_rx_fixup,
+       .tx_fixup       = cx82310_tx_fixup,
+};
+
+#define USB_DEVICE_CLASS(vend, prod, cl, sc, pr) \
+       .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \
+                      USB_DEVICE_ID_MATCH_DEV_INFO, \
+       .idVendor = (vend), \
+       .idProduct = (prod), \
+       .bDeviceClass = (cl), \
+       .bDeviceSubClass = (sc), \
+       .bDeviceProtocol = (pr)
+
+static const struct usb_device_id products[] = {
+       {
+               USB_DEVICE_CLASS(0x0572, 0xcb01, 0xff, 0, 0),
+               .driver_info = (unsigned long) &cx82310_info
+       },
+       { },
+};
+MODULE_DEVICE_TABLE(usb, products);
+
+static struct usb_driver cx82310_driver = {
+       .name           = "cx82310_eth",
+       .id_table       = products,
+       .probe          = usbnet_probe,
+       .disconnect     = usbnet_disconnect,
+       .suspend        = usbnet_suspend,
+       .resume         = usbnet_resume,
+};
+
+static int __init cx82310_init(void)
+{
+       return usb_register(&cx82310_driver);
+}
+module_init(cx82310_init);
+
+static void __exit cx82310_exit(void)
+{
+       usb_deregister(&cx82310_driver);
+}
+module_exit(cx82310_exit);
+
+MODULE_AUTHOR("Ondrej Zary");
+MODULE_DESCRIPTION("Conexant CX82310-based ADSL router USB ethernet driver");
+MODULE_LICENSE("GPL");
index 6efca66b87663a84ec7f36529c190aa5a107d401..4f123f869bdc8a26d97a90d5d8622d15dd366db9 100644 (file)
@@ -843,16 +843,7 @@ static netdev_tx_t hso_net_start_xmit(struct sk_buff *skb,
        return NETDEV_TX_OK;
 }
 
-static void hso_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info)
-{
-       struct hso_net *odev = netdev_priv(net);
-
-       strncpy(info->driver, driver_name, ETHTOOL_BUSINFO_LEN);
-       usb_make_path(odev->parent->usb, info->bus_info, sizeof info->bus_info);
-}
-
 static const struct ethtool_ops ops = {
-       .get_drvinfo = hso_get_drvinfo,
        .get_link = ethtool_op_get_link
 };
 
index 2b7b39cad1ce954f7eec5511fefb7f86611c45a1..5e98643a4a214b2734d738cc7a24b55ef0225298 100644 (file)
@@ -759,14 +759,6 @@ static int kaweth_close(struct net_device *net)
        return 0;
 }
 
-static void kaweth_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
-{
-       struct kaweth_device *kaweth = netdev_priv(dev);
-
-       strlcpy(info->driver, driver_name, sizeof(info->driver));
-       usb_make_path(kaweth->dev, info->bus_info, sizeof (info->bus_info));
-}
-
 static u32 kaweth_get_link(struct net_device *dev)
 {
        struct kaweth_device *kaweth = netdev_priv(dev);
@@ -775,7 +767,6 @@ static u32 kaweth_get_link(struct net_device *dev)
 }
 
 static const struct ethtool_ops ops = {
-       .get_drvinfo    = kaweth_get_drvinfo,
        .get_link       = kaweth_get_link
 };
 
index f53412368ce1e1745a7796a8cc8181b16027e797..6884813b809c642f86775b99d479afa97f8088eb 100644 (file)
@@ -1954,7 +1954,7 @@ static int velocity_tx_srv(struct velocity_info *vptr)
  */
 static inline void velocity_rx_csum(struct rx_desc *rd, struct sk_buff *skb)
 {
-       skb->ip_summed = CHECKSUM_NONE;
+       skb_checksum_none_assert(skb);
 
        if (rd->rdesc1.CSM & CSM_IPKT) {
                if (rd->rdesc1.CSM & CSM_IPOK) {
index 4598e9d2608f7ca4c098d8745432a8a6151de757..bb6b67f6b0cc731df707cbfc06006a2c8c39b198 100644 (file)
@@ -705,19 +705,6 @@ static int virtnet_close(struct net_device *dev)
        return 0;
 }
 
-static void virtnet_get_drvinfo(struct net_device *dev,
-                               struct ethtool_drvinfo *drvinfo)
-{
-       struct virtnet_info *vi = netdev_priv(dev);
-       struct virtio_device *vdev = vi->vdev;
-
-       strncpy(drvinfo->driver, KBUILD_MODNAME, ARRAY_SIZE(drvinfo->driver));
-       strncpy(drvinfo->version, "N/A", ARRAY_SIZE(drvinfo->version));
-       strncpy(drvinfo->fw_version, "N/A", ARRAY_SIZE(drvinfo->fw_version));
-       strncpy(drvinfo->bus_info, dev_name(&vdev->dev),
-               ARRAY_SIZE(drvinfo->bus_info));
-}
-
 static int virtnet_set_tx_csum(struct net_device *dev, u32 data)
 {
        struct virtnet_info *vi = netdev_priv(dev);
@@ -830,7 +817,6 @@ static void virtnet_vlan_rx_kill_vid(struct net_device *dev, u16 vid)
 }
 
 static const struct ethtool_ops virtnet_ethtool_ops = {
-       .get_drvinfo = virtnet_get_drvinfo,
        .set_tx_csum = virtnet_set_tx_csum,
        .set_sg = ethtool_op_set_sg,
        .set_tso = ethtool_op_set_tso,
index abe0ff53daf353c1be44876b19cf37f4cefe4403..198ce92af0c3b928dabbdbdcbe9764671c1ed950 100644 (file)
@@ -1042,11 +1042,11 @@ vmxnet3_rx_csum(struct vmxnet3_adapter *adapter,
                                skb->csum = htons(gdesc->rcd.csum);
                                skb->ip_summed = CHECKSUM_PARTIAL;
                        } else {
-                               skb->ip_summed = CHECKSUM_NONE;
+                               skb_checksum_none_assert(skb);
                        }
                }
        } else {
-               skb->ip_summed = CHECKSUM_NONE;
+               skb_checksum_none_assert(skb);
        }
 }
 
index c7c5605b3728384069e0e3aa187a30b0e85bd512..5378b849f54f8cb5451f00826d7ceaa1dd6dfb26 100644 (file)
@@ -501,7 +501,7 @@ vxge_rx_1b_compl(struct __vxge_hw_ring *ringh, void *dtr,
                    ext_info.l4_cksum == VXGE_HW_L4_CKSUM_OK)
                        skb->ip_summed = CHECKSUM_UNNECESSARY;
                else
-                       skb->ip_summed = CHECKSUM_NONE;
+                       skb_checksum_none_assert(skb);
 
                vxge_rx_complete(ring, skb, ext_info.vlan,
                        pkt_length, &ext_info);
@@ -2159,8 +2159,8 @@ start:
        /* Alarm MSIX Vectors count */
        vdev->intr_cnt++;
 
-       vdev->entries = kzalloc(vdev->intr_cnt * sizeof(struct msix_entry),
-                                               GFP_KERNEL);
+       vdev->entries = kcalloc(vdev->intr_cnt, sizeof(struct msix_entry),
+                               GFP_KERNEL);
        if (!vdev->entries) {
                vxge_debug_init(VXGE_ERR,
                        "%s: memory allocation failed",
@@ -2169,9 +2169,9 @@ start:
                goto alloc_entries_failed;
        }
 
-       vdev->vxge_entries =
-               kzalloc(vdev->intr_cnt * sizeof(struct vxge_msix_entry),
-                               GFP_KERNEL);
+       vdev->vxge_entries = kcalloc(vdev->intr_cnt,
+                                    sizeof(struct vxge_msix_entry),
+                                    GFP_KERNEL);
        if (!vdev->vxge_entries) {
                vxge_debug_init(VXGE_ERR, "%s: memory allocation failed",
                        VXGE_DRIVER_NAME);
@@ -2914,26 +2914,18 @@ static int vxge_change_mtu(struct net_device *dev, int new_mtu)
 }
 
 /**
- * vxge_get_stats
+ * vxge_get_stats64
  * @dev: pointer to the device structure
+ * @stats: pointer to struct rtnl_link_stats64
  *
- * Updates the device statistics structure. This function updates the device
- * statistics structure in the net_device structure and returns a pointer
- * to the same.
  */
-static struct net_device_stats *
-vxge_get_stats(struct net_device *dev)
+static struct rtnl_link_stats64 *
+vxge_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *net_stats)
 {
-       struct vxgedev *vdev;
-       struct net_device_stats *net_stats;
+       struct vxgedev *vdev = netdev_priv(dev);
        int k;
 
-       vdev = netdev_priv(dev);
-
-       net_stats = &vdev->stats.net_stats;
-
-       memset(net_stats, 0, sizeof(struct net_device_stats));
-
+       /* net_stats already zeroed by caller */
        for (k = 0; k < vdev->no_of_vpath; k++) {
                net_stats->rx_packets += vdev->vpaths[k].ring.stats.rx_frms;
                net_stats->rx_bytes += vdev->vpaths[k].ring.stats.rx_bytes;
@@ -3102,7 +3094,7 @@ vxge_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
 static const struct net_device_ops vxge_netdev_ops = {
        .ndo_open               = vxge_open,
        .ndo_stop               = vxge_close,
-       .ndo_get_stats          = vxge_get_stats,
+       .ndo_get_stats64        = vxge_get_stats64,
        .ndo_start_xmit         = vxge_xmit,
        .ndo_validate_addr      = eth_validate_addr,
        .ndo_set_multicast_list = vxge_set_multicast,
index 2e3b064b8e4ba0322772f5487a6524e28a9f0665..d4be07eaacd72d007faa4cfdeba4dc61bf645ee8 100644 (file)
@@ -172,7 +172,6 @@ struct vxge_msix_entry {
 
 struct vxge_sw_stats {
        /* Network Stats (interface stats) */
-       struct net_device_stats net_stats;
 
        /* Tx */
        u64 tx_frms;
index 0bd898c947594fbdef1affaccbd86734f80aacc8..4ac85a09c5a6724785435dbf640ec4450afe5f24 100644 (file)
@@ -264,7 +264,7 @@ static int c101_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                    new_line.clock_type != CLOCK_TXFROMRX &&
                    new_line.clock_type != CLOCK_INT &&
                    new_line.clock_type != CLOCK_TXINT)
-               return -EINVAL; /* No such clock setting */
+                       return -EINVAL; /* No such clock setting */
 
                if (new_line.loopback != 0 && new_line.loopback != 1)
                        return -EINVAL;
index a5ddc6c8963e3e189f65e8213e0110b9941841e6..164c3624ba895c0720a6604638a7983947a242af 100644 (file)
@@ -73,7 +73,7 @@ static int reset_cyc2x(void __iomem *addr);
 static int detect_cyc2x(void __iomem *addr);
 
 /* Miscellaneous functions */
-static int get_option_index(long *optlist, long optval);
+static int get_option_index(const long *optlist, long optval);
 static u16 checksum(u8 *buf, u32 len);
 
 #define wait_cyc(addr) cycx_exec(addr + CMD_OFFSET)
@@ -81,23 +81,23 @@ static u16 checksum(u8 *buf, u32 len);
 /* Global Data */
 
 /* private data */
-static char modname[] = "cycx_drv";
-static char fullname[] = "Cyclom 2X Support Module";
-static char copyright[] = "(c) 1998-2003 Arnaldo Carvalho de Melo "
+static const char modname[] = "cycx_drv";
+static const char fullname[] = "Cyclom 2X Support Module";
+static const char copyright[] = "(c) 1998-2003 Arnaldo Carvalho de Melo "
                          "<acme@conectiva.com.br>";
 
 /* Hardware configuration options.
  * These are arrays of configuration options used by verification routines.
  * The first element of each array is its size (i.e. number of options).
  */
-static long cyc2x_dpmbase_options[] = {
+static const long cyc2x_dpmbase_options[] = {
        20,
        0xA0000, 0xA4000, 0xA8000, 0xAC000, 0xB0000, 0xB4000, 0xB8000,
        0xBC000, 0xC0000, 0xC4000, 0xC8000, 0xCC000, 0xD0000, 0xD4000,
        0xD8000, 0xDC000, 0xE0000, 0xE4000, 0xE8000, 0xEC000
 };
 
-static long cycx_2x_irq_options[]  = { 7, 3, 5, 9, 10, 11, 12, 15 };
+static const long cycx_2x_irq_options[]  = { 7, 3, 5, 9, 10, 11, 12, 15 };
 
 /* Kernel Loadable Module Entry Points */
 /* Module 'insert' entry point.
@@ -529,7 +529,7 @@ static int detect_cyc2x(void __iomem *addr)
 /* Miscellaneous */
 /* Get option's index into the options list.
  *     Return option's index (1 .. N) or zero if option is invalid. */
-static int get_option_index(long *optlist, long optval)
+static int get_option_index(const long *optlist, long optval)
 {
        int i = 1;
 
index a0e8611ad8e81e167ac5cf566f82ab7dcf1eeb84..859dba9b972ea883da8a91b7fef0cb0d9d5ded35 100644 (file)
@@ -81,9 +81,9 @@ static irqreturn_t cycx_isr(int irq, void *dev_id);
  */
 
 /* private data */
-static char cycx_drvname[] = "cyclomx";
-static char cycx_fullname[] = "CYCLOM 2X(tm) Sync Card Driver";
-static char cycx_copyright[] = "(c) 1998-2003 Arnaldo Carvalho de Melo "
+static const char cycx_drvname[] = "cyclomx";
+static const char cycx_fullname[] = "CYCLOM 2X(tm) Sync Card Driver";
+static const char cycx_copyright[] = "(c) 1998-2003 Arnaldo Carvalho de Melo "
                          "<acme@conectiva.com.br>";
 static int cycx_ncards = CONFIG_CYCX_CARDS;
 static struct cycx_device *cycx_card_array;    /* adapter data space */
index 4d4dc38c72902e9ca62e8b7655cb9b70388a1a17..7f5bb913c8b928ad20b8aa9bb8a0b84b5adcbbab 100644 (file)
@@ -46,7 +46,7 @@
 
 #include <net/x25device.h>
 
-static char bcast_addr[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+static const u8 bcast_addr[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
 
 /* If this number is made larger, check that the temporary string buffer
  * in lapbeth_new_device is large enough to store the probe device name.*/
index e2c6f7f4f51c16a36bea5d11daff068200ed125d..43af85b8e45e68f4a5d1d71e3708c37dd835dfd7 100644 (file)
@@ -1105,7 +1105,7 @@ static int lmc_open(struct net_device *dev)
     init_timer (&sc->timer);
     sc->timer.expires = jiffies + HZ;
     sc->timer.data = (unsigned long) dev;
-    sc->timer.function = &lmc_watchdog;
+    sc->timer.function = lmc_watchdog;
     add_timer (&sc->timer);
 
     lmc_trace(dev, "lmc_open out");
index 5394b51bdb2f768f36d3d4ac705d46abc23b7187..7a3720f09ce31bf8b09568c298db9c9bc2732c40 100644 (file)
@@ -282,7 +282,7 @@ static int n2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                    new_line.clock_type != CLOCK_TXFROMRX &&
                    new_line.clock_type != CLOCK_INT &&
                    new_line.clock_type != CLOCK_TXINT)
-               return -EINVAL; /* No such clock setting */
+                       return -EINVAL; /* No such clock setting */
 
                if (new_line.loopback != 0 && new_line.loopback != 1)
                        return -EINVAL;
index c6aa66e5b52f34aedd5736e3c7e8c967870c24d2..fbf1175a07f19faa4b2a03471aba041c83a57eb3 100644 (file)
@@ -1,5 +1,5 @@
 #define        USE_PCI_CLOCK
-static char rcsid[] = 
+static const char rcsid[] =
 "Revision: 3.4.5 Date: 2002/03/07 ";
 
 /*
index e2cff64a446a1bb102cabdcb263b260c2b59ecc3..fd7375955e41f07d583becc71be10c437e153c0a 100644 (file)
@@ -220,7 +220,7 @@ static int pci200_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                    new_line.clock_type != CLOCK_TXFROMRX &&
                    new_line.clock_type != CLOCK_INT &&
                    new_line.clock_type != CLOCK_TXINT)
-               return -EINVAL; /* No such clock setting */
+                       return -EINVAL; /* No such clock setting */
 
                if (new_line.loopback != 0 && new_line.loopback != 1)
                        return -EINVAL;
index fbf5e843d48c1fd9f88b55ef993ea74474488041..93956861ea210eb08d773461827a172b7493294f 100644 (file)
@@ -766,7 +766,7 @@ irqreturn_t z8530_interrupt(int irq, void *dev_id)
 
 EXPORT_SYMBOL(z8530_interrupt);
 
-static char reg_init[16]=
+static const u8 reg_init[16]=
 {
        0,0,0,0,
        0,0,0,0,
@@ -1206,7 +1206,7 @@ EXPORT_SYMBOL(z8530_sync_txdma_close);
  *     it exists...
  */
  
-static char *z8530_type_name[]={
+static const char *z8530_type_name[]={
        "Z8530",
        "Z85C30",
        "Z85230"
index eb72c67699abb50f30e8b8bf7d30b43c52b73daa..f1549fff0edc981662addc0a486cfd1b069c3e5f 100644 (file)
@@ -342,10 +342,10 @@ static int __init wd_probe1(struct net_device *dev, int ioaddr)
        printk(" %s, IRQ %d, shared memory at %#lx-%#lx.\n",
                   model_name, dev->irq, dev->mem_start, dev->mem_end-1);
 
-       ei_status.reset_8390 = &wd_reset_8390;
-       ei_status.block_input = &wd_block_input;
-       ei_status.block_output = &wd_block_output;
-       ei_status.get_8390_hdr = &wd_get_8390_hdr;
+       ei_status.reset_8390 = wd_reset_8390;
+       ei_status.block_input = wd_block_input;
+       ei_status.block_output = wd_block_output;
+       ei_status.get_8390_hdr = wd_get_8390_hdr;
 
        dev->netdev_ops = &wd_netdev_ops;
        NS8390_init(dev, 0);
index 1d05445d4ba397cb04545d1ba105e1040c864176..7d26506957d7e167a0d3e72790f6420c582c89cc 100644 (file)
@@ -2723,9 +2723,8 @@ static int airo_networks_allocate(struct airo_info *ai)
        if (ai->networks)
                return 0;
 
-       ai->networks =
-           kzalloc(AIRO_MAX_NETWORK_COUNT * sizeof(BSSListElement),
-                   GFP_KERNEL);
+       ai->networks = kcalloc(AIRO_MAX_NETWORK_COUNT, sizeof(BSSListElement),
+                              GFP_KERNEL);
        if (!ai->networks) {
                airo_print_warn("", "Out of memory allocating beacons");
                return -ENOMEM;
index 1128fa8c9ed5ef3d0b9be5191edc4bd7320baf90..91c5f73b5ba33d5d21e98aa138806224d65eadd1 100644 (file)
@@ -2061,11 +2061,12 @@ static int at76_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 
        int i;
 
-       at76_dbg(DBG_MAC80211, "%s(): cmd %d key->alg %d key->keyidx %d "
+       at76_dbg(DBG_MAC80211, "%s(): cmd %d key->cipher %d key->keyidx %d "
                 "key->keylen %d",
-                __func__, cmd, key->alg, key->keyidx, key->keylen);
+                __func__, cmd, key->cipher, key->keyidx, key->keylen);
 
-       if (key->alg != ALG_WEP)
+       if ((key->cipher != WLAN_CIPHER_SUITE_WEP40) &&
+           (key->cipher != WLAN_CIPHER_SUITE_WEP104))
                return -EOPNOTSUPP;
 
        key->hw_key_idx = key->keyidx;
index debfb0fbc7c5e7316931b2e0ac0c4913ff7428d6..32bf79e6a320ff2b04722b8a17d9cd7b38088303 100644 (file)
@@ -1190,14 +1190,13 @@ static int ar9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb)
        if (info->control.hw_key) {
                icv = info->control.hw_key->icv_len;
 
-               switch (info->control.hw_key->alg) {
-               case ALG_WEP:
+               switch (info->control.hw_key->cipher) {
+               case WLAN_CIPHER_SUITE_WEP40:
+               case WLAN_CIPHER_SUITE_WEP104:
+               case WLAN_CIPHER_SUITE_TKIP:
                        keytype = AR9170_TX_MAC_ENCR_RC4;
                        break;
-               case ALG_TKIP:
-                       keytype = AR9170_TX_MAC_ENCR_RC4;
-                       break;
-               case ALG_CCMP:
+               case WLAN_CIPHER_SUITE_CCMP:
                        keytype = AR9170_TX_MAC_ENCR_AES;
                        break;
                default:
@@ -1778,17 +1777,17 @@ static int ar9170_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
        if ((!ar->vif) || (ar->disable_offload))
                return -EOPNOTSUPP;
 
-       switch (key->alg) {
-       case ALG_WEP:
-               if (key->keylen == WLAN_KEY_LEN_WEP40)
-                       ktype = AR9170_ENC_ALG_WEP64;
-               else
-                       ktype = AR9170_ENC_ALG_WEP128;
+       switch (key->cipher) {
+       case WLAN_CIPHER_SUITE_WEP40:
+               ktype = AR9170_ENC_ALG_WEP64;
+               break;
+       case WLAN_CIPHER_SUITE_WEP104:
+               ktype = AR9170_ENC_ALG_WEP128;
                break;
-       case ALG_TKIP:
+       case WLAN_CIPHER_SUITE_TKIP:
                ktype = AR9170_ENC_ALG_TKIP;
                break;
-       case ALG_CCMP:
+       case WLAN_CIPHER_SUITE_CCMP:
                ktype = AR9170_ENC_ALG_AESCCMP;
                break;
        default:
@@ -1827,7 +1826,7 @@ static int ar9170_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
                if (err)
                        goto out;
 
-               if (key->alg == ALG_TKIP) {
+               if (key->cipher == WLAN_CIPHER_SUITE_TKIP) {
                        err = ar9170_upload_key(ar, i, sta ? sta->addr : NULL,
                                                ktype, 1, key->key + 16, 16);
                        if (err)
@@ -1864,7 +1863,7 @@ static int ar9170_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
                        if (err)
                                goto out;
 
-                       if (key->alg == ALG_TKIP) {
+                       if (key->cipher == WLAN_CIPHER_SUITE_TKIP) {
                                err = ar9170_upload_key(ar, key->hw_key_idx,
                                                        NULL,
                                                        AR9170_ENC_ALG_NONE, 1,
index d32f2828b098ee63241e3b1e83c82d96ab2944df..a706202fa67c9360f70e3fc6ec2351b8f68e943f 100644 (file)
@@ -119,6 +119,7 @@ struct ath_common {
 
        u32 keymax;
        DECLARE_BITMAP(keymap, ATH_KEYMAX);
+       DECLARE_BITMAP(tkip_keymap, ATH_KEYMAX);
        u8 splitmic;
 
        struct ath_regulatory regulatory;
index 26dbe65fedb05fbc8dfe737d381b49b61bd24eaf..e4a5f046bba47146135136ea9040a55144c607b5 100644 (file)
@@ -552,9 +552,9 @@ ath5k_ani_mib_intr(struct ath5k_hw *ah)
        if (ah->ah_sc->ani_state.ani_mode != ATH5K_ANI_MODE_AUTO)
                return;
 
-       /* if one of the errors triggered, we can get a superfluous second
-        * interrupt, even though we have already reset the register. the
-        * function detects that so we can return early */
+       /* If one of the errors triggered, we can get a superfluous second
+        * interrupt, even though we have already reset the register. The
+        * function detects that so we can return early. */
        if (ath5k_ani_save_and_clear_phy_errors(ah, as) == 0)
                return;
 
index ea6362a8988de33a51d4c916c5f82c55cd576e2e..f399c4dd8e6980297a409005ebc8f786109bf816 100644 (file)
 #define AR5K_TUNE_ADDITIONAL_SWBA_BACKOFF      0
 #define AR5K_TUNE_RADAR_ALERT                  false
 #define AR5K_TUNE_MIN_TX_FIFO_THRES            1
-#define AR5K_TUNE_MAX_TX_FIFO_THRES            ((IEEE80211_MAX_LEN / 64) + 1)
+#define AR5K_TUNE_MAX_TX_FIFO_THRES    ((IEEE80211_MAX_FRAME_LEN / 64) + 1)
 #define AR5K_TUNE_REGISTER_TIMEOUT             20000
 /* Register for RSSI threshold has a mask of 0xff, so 255 seems to
  * be the max value. */
@@ -343,9 +343,6 @@ struct ath5k_srev_name {
 #define AR5K_SREV_PHY_5413     0x61
 #define AR5K_SREV_PHY_2425     0x70
 
-/* IEEE defs */
-#define IEEE80211_MAX_LEN       2500
-
 /* TODO add support to mac80211 for vendor-specific rates and modes */
 
 /*
@@ -1190,7 +1187,7 @@ extern int ath5k_hw_set_opmode(struct ath5k_hw *ah, enum nl80211_iftype opmode);
 void ath5k_hw_set_coverage_class(struct ath5k_hw *ah, u8 coverage_class);
 /* BSSID Functions */
 int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac);
-void ath5k_hw_set_associd(struct ath5k_hw *ah);
+void ath5k_hw_set_bssid(struct ath5k_hw *ah);
 void ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask);
 /* Receive start/stop functions */
 void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah);
index b32e28caeee2b6c730a48c2c91aefb7b5708be25..aabad4f13e2a47d3f826a5848f164d99f255b793 100644 (file)
@@ -139,12 +139,12 @@ int ath5k_hw_attach(struct ath5k_softc *sc)
        else
                ah->ah_version = AR5K_AR5212;
 
-       /*Fill the ath5k_hw struct with the needed functions*/
+       /* Fill the ath5k_hw struct with the needed functions */
        ret = ath5k_hw_init_desc_functions(ah);
        if (ret)
                goto err_free;
 
-       /* Bring device out of sleep and reset it's units */
+       /* Bring device out of sleep and reset its units */
        ret = ath5k_hw_nic_wakeup(ah, 0, true);
        if (ret)
                goto err_free;
@@ -158,7 +158,7 @@ int ath5k_hw_attach(struct ath5k_softc *sc)
                        CHANNEL_5GHZ);
        ah->ah_phy = AR5K_PHY(0);
 
-       /* Try to identify radio chip based on it's srev */
+       /* Try to identify radio chip based on its srev */
        switch (ah->ah_radio_5ghz_revision & 0xf0) {
        case AR5K_SREV_RAD_5111:
                ah->ah_radio = AR5K_RF5111;
@@ -329,7 +329,7 @@ int ath5k_hw_attach(struct ath5k_softc *sc)
 
        /* Set BSSID to bcast address: ff:ff:ff:ff:ff:ff for now */
        memcpy(common->curbssid, ath_bcast_mac, ETH_ALEN);
-       ath5k_hw_set_associd(ah);
+       ath5k_hw_set_bssid(ah);
        ath5k_hw_set_opmode(ah, sc->opmode);
 
        ath5k_hw_rfgain_opt_init(ah);
index d77ce9906b6ccb1bf1031b1260dfd2510fd9e116..116ac66c6e3ecd60d19800a46af184926cfafc76 100644 (file)
@@ -612,7 +612,7 @@ ath5k_pci_probe(struct pci_dev *pdev,
                goto err_free;
        }
 
-       /*If we passed the test malloc a ath5k_hw struct*/
+       /* If we passed the test, malloc an ath5k_hw struct */
        sc->ah = kzalloc(sizeof(struct ath5k_hw), GFP_KERNEL);
        if (!sc->ah) {
                ret = -ENOMEM;
@@ -700,10 +700,10 @@ ath5k_pci_probe(struct pci_dev *pdev,
        return 0;
 err_ah:
        ath5k_hw_detach(sc->ah);
-err_irq:
-       free_irq(pdev->irq, sc);
 err_free_ah:
        kfree(sc->ah);
+err_irq:
+       free_irq(pdev->irq, sc);
 err_free:
        ieee80211_free_hw(hw);
 err_map:
@@ -786,8 +786,8 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
        /*
         * Check if the MAC has multi-rate retry support.
         * We do this by trying to setup a fake extended
-        * descriptor.  MAC's that don't have support will
-        * return false w/o doing anything.  MAC's that do
+        * descriptor.  MACs that don't have support will
+        * return false w/o doing anything.  MACs that do
         * support it will return true w/o doing anything.
         */
        ret = ath5k_hw_setup_mrr_tx_desc(ah, NULL, 0, 0, 0, 0, 0, 0);
@@ -827,7 +827,7 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
        /*
         * Allocate hardware transmit queues: one queue for
         * beacon frames and one data queue for each QoS
-        * priority.  Note that hw functions handle reseting
+        * priority.  Note that hw functions handle resetting
         * these queues at the needed time.
         */
        ret = ath5k_beaconq_setup(ah);
@@ -909,7 +909,7 @@ ath5k_detach(struct pci_dev *pdev, struct ieee80211_hw *hw)
        /*
         * NB: the order of these is important:
         * o call the 802.11 layer before detaching ath5k_hw to
-        *   insure callbacks into the driver to delete global
+        *   ensure callbacks into the driver to delete global
         *   key cache entries can be handled
         * o reclaim the tx queue data structures after calling
         *   the 802.11 layer as we'll get called back to reclaim
@@ -1518,7 +1518,7 @@ ath5k_txq_setup(struct ath5k_softc *sc,
        /*
         * Enable interrupts only for EOL and DESC conditions.
         * We mark tx descriptors to receive a DESC interrupt
-        * when a tx queue gets deep; otherwise waiting for the
+        * when a tx queue gets deep; otherwise we wait for the
         * EOL to reap descriptors.  Note that this is done to
         * reduce interrupt load and this only defers reaping
         * descriptors, never transmitting frames.  Aside from
@@ -1713,7 +1713,7 @@ ath5k_rx_start(struct ath5k_softc *sc)
        struct ath5k_buf *bf;
        int ret;
 
-       common->rx_bufsize = roundup(IEEE80211_MAX_LEN, common->cachelsz);
+       common->rx_bufsize = roundup(IEEE80211_MAX_FRAME_LEN, common->cachelsz);
 
        ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "cachelsz %u rx_bufsize %u\n",
                  common->cachelsz, common->rx_bufsize);
@@ -1863,7 +1863,7 @@ ath5k_update_beacon_rssi(struct ath5k_softc *sc, struct sk_buff *skb, int rssi)
 }
 
 /*
- * Compute padding position. skb must contains an IEEE 802.11 frame
+ * Compute padding position. skb must contain an IEEE 802.11 frame
  */
 static int ath5k_common_padpos(struct sk_buff *skb)
 {
@@ -1882,10 +1882,9 @@ static int ath5k_common_padpos(struct sk_buff *skb)
 }
 
 /*
- * This function expects a 802.11 frame and returns the number of
- * bytes added, or -1 if we don't have enought header room.
+ * This function expects an 802.11 frame and returns the number of
+ * bytes added, or -1 if we don't have enough header room.
  */
-
 static int ath5k_add_padding(struct sk_buff *skb)
 {
        int padpos = ath5k_common_padpos(skb);
@@ -1905,10 +1904,18 @@ static int ath5k_add_padding(struct sk_buff *skb)
 }
 
 /*
- * This function expects a 802.11 frame and returns the number of
- * bytes removed
+ * The MAC header is padded to have 32-bit boundary if the
+ * packet payload is non-zero. The general calculation for
+ * padsize would take into account odd header lengths:
+ * padsize = 4 - (hdrlen & 3); however, since only
+ * even-length headers are used, padding can only be 0 or 2
+ * bytes and we can optimize this a bit.  We must not try to
+ * remove padding from short control frames that do not have a
+ * payload.
+ *
+ * This function expects an 802.11 frame and returns the number of
+ * bytes removed.
  */
-
 static int ath5k_remove_padding(struct sk_buff *skb)
 {
        int padpos = ath5k_common_padpos(skb);
@@ -1929,14 +1936,6 @@ ath5k_receive_frame(struct ath5k_softc *sc, struct sk_buff *skb,
 {
        struct ieee80211_rx_status *rxs;
 
-       /* The MAC header is padded to have 32-bit boundary if the
-        * packet payload is non-zero. The general calculation for
-        * padsize would take into account odd header lengths:
-        * padsize = (4 - hdrlen % 4) % 4; However, since only
-        * even-length headers are used, padding can only be 0 or 2
-        * bytes and we can optimize this a bit. In addition, we must
-        * not try to remove padding from short control frames that do
-        * not have payload. */
        ath5k_remove_padding(skb);
 
        rxs = IEEE80211_SKB_RXCB(skb);
@@ -2040,9 +2039,8 @@ ath5k_receive_frame_ok(struct ath5k_softc *sc, struct ath5k_rx_status *rs)
                        return true;
                }
 
-               /* let crypto-error packets fall through in MNTR */
-               if ((rs->rs_status & ~(AR5K_RXERR_DECRYPT|AR5K_RXERR_MIC)) ||
-                   sc->opmode != NL80211_IFTYPE_MONITOR)
+               /* reject any frames with non-crypto errors */
+               if (rs->rs_status & ~(AR5K_RXERR_DECRYPT))
                        return false;
        }
 
@@ -2285,10 +2283,11 @@ ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
         * default antenna which is supposed to be an omni.
         *
         * Note2: On sectored scenarios it's possible to have
-        * multiple antennas (1omni -the default- and 14 sectors)
-        * so if we choose to actually support this mode we need
-        * to allow user to set how many antennas we have and tweak
-        * the code below to send beacons on all of them.
+        * multiple antennas (1 omni -- the default -- and 14
+        * sectors), so if we choose to actually support this
+        * mode, we need to allow the user to set how many antennas
+        * we have and tweak the code below to send beacons
+        * on all of them.
         */
        if (ah->ah_ant_mode == AR5K_ANTMODE_SECTOR_AP)
                antenna = sc->bsent & 4 ? 2 : 1;
@@ -2330,14 +2329,13 @@ ath5k_beacon_send(struct ath5k_softc *sc)
 
        ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON, "in beacon_send\n");
 
-       if (unlikely(bf->skb == NULL || sc->opmode == NL80211_IFTYPE_STATION ||
-                       sc->opmode == NL80211_IFTYPE_MONITOR)) {
+       if (unlikely(bf->skb == NULL || sc->opmode == NL80211_IFTYPE_STATION)) {
                ATH5K_WARN(sc, "bf=%p bf_skb=%p\n", bf, bf ? bf->skb : NULL);
                return;
        }
        /*
         * Check if the previous beacon has gone out.  If
-        * not don't don't try to post another, skip this
+        * not, don't don't try to post another: skip this
         * period and wait for the next.  Missed beacons
         * indicate a problem and should not occur.  If we
         * miss too many consecutive beacons reset the device.
@@ -2905,12 +2903,9 @@ static int ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb,
 
        ath5k_debug_dump_skb(sc, skb, "TX  ", 1);
 
-       if (sc->opmode == NL80211_IFTYPE_MONITOR)
-               ATH5K_DBG(sc, ATH5K_DEBUG_XMIT, "tx in monitor (scan?)\n");
-
        /*
-        * the hardware expects the header padded to 4 byte boundaries
-        * if this is not the case we add the padding after the header
+        * The hardware expects the header padded to 4 byte boundaries.
+        * If this is not the case, we add the padding after the header.
         */
        padsize = ath5k_add_padding(skb);
        if (padsize < 0) {
@@ -3053,7 +3048,6 @@ static int ath5k_add_interface(struct ieee80211_hw *hw,
        case NL80211_IFTYPE_STATION:
        case NL80211_IFTYPE_ADHOC:
        case NL80211_IFTYPE_MESH_POINT:
-       case NL80211_IFTYPE_MONITOR:
                sc->opmode = vif->type;
                break;
        default:
@@ -3237,9 +3231,9 @@ static void ath5k_configure_filter(struct ieee80211_hw *hw,
                rfilt |= AR5K_RX_FILTER_PHYERR;
 
        /* FIF_BCN_PRBRESP_PROMISC really means to enable beacons
-       * and probes for any BSSID, this needs testing */
+       * and probes for any BSSID */
        if (*new_flags & FIF_BCN_PRBRESP_PROMISC)
-               rfilt |= AR5K_RX_FILTER_BEACON | AR5K_RX_FILTER_PROBEREQ;
+               rfilt |= AR5K_RX_FILTER_BEACON;
 
        /* FIF_CONTROL doc says that if FIF_PROMISC_IN_BSS is not
         * set we should only pass on control frames for this
@@ -3255,7 +3249,6 @@ static void ath5k_configure_filter(struct ieee80211_hw *hw,
 
        switch (sc->opmode) {
        case NL80211_IFTYPE_MESH_POINT:
-       case NL80211_IFTYPE_MONITOR:
                rfilt |= AR5K_RX_FILTER_CONTROL |
                         AR5K_RX_FILTER_BEACON |
                         AR5K_RX_FILTER_PROBEREQ |
@@ -3278,7 +3271,7 @@ static void ath5k_configure_filter(struct ieee80211_hw *hw,
 
        /* Set multicast bits */
        ath5k_hw_set_mcast_filter(ah, mfilt[0], mfilt[1]);
-       /* Set the cached hw filter flags, this will alter actually
+       /* Set the cached hw filter flags, this will later actually
         * be set in HW */
        sc->filter_flags = rfilt;
 
@@ -3301,11 +3294,12 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
        if (sc->opmode == NL80211_IFTYPE_AP)
                return -EOPNOTSUPP;
 
-       switch (key->alg) {
-       case ALG_WEP:
-       case ALG_TKIP:
+       switch (key->cipher) {
+       case WLAN_CIPHER_SUITE_WEP40:
+       case WLAN_CIPHER_SUITE_WEP104:
+       case WLAN_CIPHER_SUITE_TKIP:
                break;
-       case ALG_CCMP:
+       case WLAN_CIPHER_SUITE_CCMP:
                if (sc->ah->ah_aes_support)
                        break;
 
@@ -3479,7 +3473,7 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw,
                /* Cache for later use during resets */
                memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
                common->curaid = 0;
-               ath5k_hw_set_associd(ah);
+               ath5k_hw_set_bssid(ah);
                mmiowb();
        }
 
@@ -3497,7 +3491,7 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw,
                                  "Bss Info ASSOC %d, bssid: %pM\n",
                                  bss_conf->aid, common->curbssid);
                        common->curaid = bss_conf->aid;
-                       ath5k_hw_set_associd(ah);
+                       ath5k_hw_set_bssid(ah);
                        /* Once ANI is available you would start it here */
                }
        }
index 4cccc29964f6ddd0c7665369b034651d099a90cc..1b7c6d7fde93c1e7ca76520c503c5272247a1bd9 100644 (file)
@@ -312,6 +312,7 @@ static const struct {
        { ATH5K_DEBUG_DUMP_TX,  "dumptx",       "print transmit skb content" },
        { ATH5K_DEBUG_DUMPBANDS, "dumpbands",   "dump bands" },
        { ATH5K_DEBUG_ANI,      "ani",          "adaptive noise immunity" },
+       { ATH5K_DEBUG_DESC,     "desc",         "descriptor chains" },
        { ATH5K_DEBUG_ANY,      "all",          "show all debug levels" },
 };
 
@@ -955,7 +956,7 @@ ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah)
        struct ath5k_rx_status rs = {};
        int status;
 
-       if (likely(!(sc->debug.level & ATH5K_DEBUG_RESET)))
+       if (likely(!(sc->debug.level & ATH5K_DEBUG_DESC)))
                return;
 
        printk(KERN_DEBUG "rxdp %x, rxlink %p\n",
@@ -997,7 +998,7 @@ ath5k_debug_printtxbuf(struct ath5k_softc *sc, struct ath5k_buf *bf)
        struct ath5k_tx_status ts = {};
        int done;
 
-       if (likely(!(sc->debug.level & ATH5K_DEBUG_RESET)))
+       if (likely(!(sc->debug.level & ATH5K_DEBUG_DESC)))
                return;
 
        done = sc->ah->ah_proc_tx_desc(sc->ah, bf->desc, &ts);
index 606ae94a9157806b736f3c9d890c36a2f1edb762..9b22722a95f04a420da49ff22395d3629cc965ca 100644 (file)
@@ -95,6 +95,7 @@ struct ath5k_dbg_info {
  * @ATH5K_DEBUG_DUMP_TX: print transmit skb content
  * @ATH5K_DEBUG_DUMPBANDS: dump bands
  * @ATH5K_DEBUG_TRACE: trace function calls
+ * @ATH5K_DEBUG_DESC: descriptor setup
  * @ATH5K_DEBUG_ANY: show at any debug level
  *
  * The debug level is used to control the amount and type of debugging output
@@ -117,6 +118,7 @@ enum ath5k_debug_level {
        ATH5K_DEBUG_DUMP_TX     = 0x00000200,
        ATH5K_DEBUG_DUMPBANDS   = 0x00000400,
        ATH5K_DEBUG_ANI         = 0x00002000,
+       ATH5K_DEBUG_DESC        = 0x00004000,
        ATH5K_DEBUG_ANY         = 0xffffffff
 };
 
index 484f31870ba8f2c287e8817a22563a4d61f40f4e..58bb6c5dda7b8ee982af8a4641326b87d18978a9 100644 (file)
@@ -377,11 +377,11 @@ int ath5k_hw_set_txdp(struct ath5k_hw *ah, unsigned int queue, u32 phys_addr)
  *
  * This function increases/decreases the tx trigger level for the tx fifo
  * buffer (aka FIFO threshold) that is used to indicate when PCU flushes
- * the buffer and transmits it's data. Lowering this results sending small
+ * the buffer and transmits its data. Lowering this results sending small
  * frames more quickly but can lead to tx underruns, raising it a lot can
  * result other problems (i think bmiss is related). Right now we start with
  * the lowest possible (64Bytes) and if we get tx underrun we increase it using
- * the increase flag. Returns -EIO if we have have reached maximum/minimum.
+ * the increase flag. Returns -EIO if we have reached maximum/minimum.
  *
  * XXX: Link this with tx DMA size ?
  * XXX: Use it to save interrupts ?
index ae316fec4a6ae527817bda21cfd214210111e3b0..39722dd73e433ae606f2ef6804b18c1ff23b70fa 100644 (file)
@@ -661,7 +661,7 @@ ath5k_eeprom_init_11bg_2413(struct ath5k_hw *ah, unsigned int mode, int offset)
  * (eeprom versions < 4). For RF5111 we have 11 pre-defined PCDAC
  * steps that match with the power values we read from eeprom. On
  * older eeprom versions (< 3.2) these steps are equaly spaced at
- * 10% of the pcdac curve -until the curve reaches it's maximum-
+ * 10% of the pcdac curve -until the curve reaches its maximum-
  * (11 steps from 0 to 100%) but on newer eeprom versions (>= 3.2)
  * these 11 steps are spaced in a different way. This function returns
  * the pcdac steps based on eeprom version and curve min/max so that we
@@ -1113,7 +1113,7 @@ ath5k_eeprom_read_pcal_info_5112(struct ath5k_hw *ah, int mode)
  */
 
 /* For RF2413 power calibration data doesn't start on a fixed location and
- * if a mode is not supported, it's section is missing -not zeroed-.
+ * if a mode is not supported, its section is missing -not zeroed-.
  * So we need to calculate the starting offset for each section by using
  * these two functions */
 
index 86fdb6ddfaaa52d0abba9116c989438c0b44f851..bb2e21553d1be4d7b8e3cf47c1f86166951e2dc4 100644 (file)
@@ -137,11 +137,11 @@ void ath5k_hw_update_mib_counters(struct ath5k_hw *ah)
  * ath5k_hw_set_ack_bitrate - set bitrate for ACKs
  *
  * @ah: The &struct ath5k_hw
- * @high: Flag to determine if we want to use high transmition rate
+ * @high: Flag to determine if we want to use high transmission rate
  * for ACKs or not
  *
  * If high flag is set, we tell hw to use a set of control rates based on
- * the current transmition rate (check out control_rates array inside reset.c).
+ * the current transmission rate (check out control_rates array inside reset.c).
  * If not hw just uses the lowest rate available for the current modulation
  * scheme being used (1Mbit for CCK and 6Mbits for OFDM).
  */
@@ -308,27 +308,26 @@ int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac)
 }
 
 /**
- * ath5k_hw_set_associd - Set BSSID for association
+ * ath5k_hw_set_bssid - Set current BSSID on hw
  *
  * @ah: The &struct ath5k_hw
- * @bssid: BSSID
- * @assoc_id: Assoc id
  *
- * Sets the BSSID which trigers the "SME Join" operation
+ * Sets the current BSSID and BSSID mask we have from the
+ * common struct into the hardware
  */
-void ath5k_hw_set_associd(struct ath5k_hw *ah)
+void ath5k_hw_set_bssid(struct ath5k_hw *ah)
 {
        struct ath_common *common = ath5k_hw_common(ah);
        u16 tim_offset = 0;
 
        /*
-        * Set simple BSSID mask on 5212
+        * Set BSSID mask on 5212
         */
        if (ah->ah_version == AR5K_AR5212)
                ath_hw_setbssidmask(common);
 
        /*
-        * Set BSSID which triggers the "SME Join" operation
+        * Set BSSID
         */
        ath5k_hw_reg_write(ah,
                           get_unaligned_le32(common->curbssid),
@@ -695,21 +694,18 @@ int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry)
 static
 int ath5k_keycache_type(const struct ieee80211_key_conf *key)
 {
-       switch (key->alg) {
-       case ALG_TKIP:
+       switch (key->cipher) {
+       case WLAN_CIPHER_SUITE_TKIP:
                return AR5K_KEYTABLE_TYPE_TKIP;
-       case ALG_CCMP:
+       case WLAN_CIPHER_SUITE_CCMP:
                return AR5K_KEYTABLE_TYPE_CCM;
-       case ALG_WEP:
-               if (key->keylen == WLAN_KEY_LEN_WEP40)
-                       return AR5K_KEYTABLE_TYPE_40;
-               else if (key->keylen == WLAN_KEY_LEN_WEP104)
-                       return AR5K_KEYTABLE_TYPE_104;
-               return -EINVAL;
+       case WLAN_CIPHER_SUITE_WEP40:
+               return AR5K_KEYTABLE_TYPE_40;
+       case WLAN_CIPHER_SUITE_WEP104:
+               return AR5K_KEYTABLE_TYPE_104;
        default:
                return -EINVAL;
        }
-       return -EINVAL;
 }
 
 /*
@@ -728,7 +724,7 @@ int ath5k_hw_set_key(struct ath5k_hw *ah, u16 entry,
        bool is_tkip;
        const u8 *key_ptr;
 
-       is_tkip = (key->alg == ALG_TKIP);
+       is_tkip = (key->cipher == WLAN_CIPHER_SUITE_TKIP);
 
        /*
         * key->keylen comes in from mac80211 in bytes.
index 6284c389ba18ba6480b65dbf61c17e1f9f4632e0..984ba92c7df3781fef83719fb8f07431e36ea9be 100644 (file)
@@ -115,7 +115,7 @@ static unsigned int ath5k_hw_rfb_op(struct ath5k_hw *ah,
 \**********************/
 
 /*
- * This code is used to optimize rf gain on different environments
+ * This code is used to optimize RF gain on different environments
  * (temperature mostly) based on feedback from a power detector.
  *
  * It's only used on RF5111 and RF5112, later RF chips seem to have
@@ -302,7 +302,7 @@ static bool ath5k_hw_rf_check_gainf_readback(struct ath5k_hw *ah)
 }
 
 /* Perform gain_F adjustment by choosing the right set
- * of parameters from rf gain optimization ladder */
+ * of parameters from RF gain optimization ladder */
 static s8 ath5k_hw_rf_gainf_adjust(struct ath5k_hw *ah)
 {
        const struct ath5k_gain_opt *go;
@@ -367,7 +367,7 @@ done:
        return ret;
 }
 
-/* Main callback for thermal rf gain calibration engine
+/* Main callback for thermal RF gain calibration engine
  * Check for a new gain reading and schedule an adjustment
  * if needed.
  *
@@ -433,7 +433,7 @@ done:
        return ah->ah_gain.g_state;
 }
 
-/* Write initial rf gain table to set the RF sensitivity
+/* Write initial RF gain table to set the RF sensitivity
  * this one works on all RF chips and has nothing to do
  * with gain_F calibration */
 int ath5k_hw_rfgain_init(struct ath5k_hw *ah, unsigned int freq)
@@ -496,7 +496,7 @@ int ath5k_hw_rfgain_init(struct ath5k_hw *ah, unsigned int freq)
 
 
 /*
- * Setup RF registers by writing rf buffer on hw
+ * Setup RF registers by writing RF buffer on hw
  */
 int ath5k_hw_rfregs_init(struct ath5k_hw *ah, struct ieee80211_channel *channel,
                unsigned int mode)
@@ -571,7 +571,7 @@ int ath5k_hw_rfregs_init(struct ath5k_hw *ah, struct ieee80211_channel *channel,
                return -EINVAL;
        }
 
-       /* If it's the first time we set rf buffer, allocate
+       /* If it's the first time we set RF buffer, allocate
         * ah->ah_rf_banks based on ah->ah_rf_banks_size
         * we set above */
        if (ah->ah_rf_banks == NULL) {
@@ -1582,7 +1582,7 @@ ath5k_hw_set_spur_mitigation_filter(struct ath5k_hw *ah,
                        else if (curr_sym_off >= 31 && curr_sym_off <= 46)
                                mag_mask[2] |=
                                        plt_mag_map << (curr_sym_off - 31) * 2;
-                       else if (curr_sym_off >= 46 && curr_sym_off <= 53)
+                       else if (curr_sym_off >= 47 && curr_sym_off <= 53)
                                mag_mask[3] |=
                                        plt_mag_map << (curr_sym_off - 47) * 2;
 
@@ -2987,7 +2987,7 @@ ath5k_setup_rate_powertable(struct ath5k_hw *ah, u16 max_pwr,
 
 
 /*
- * Set transmition power
+ * Set transmission power
  */
 int
 ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel,
@@ -3035,9 +3035,6 @@ ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel,
        /* Limit max power if we have a CTL available */
        ath5k_get_max_ctl_power(ah, channel);
 
-       /* FIXME: Tx power limit for this regdomain
-        * XXX: Mac80211/CRDA will do that anyway ? */
-
        /* FIXME: Antenna reduction stuff */
 
        /* FIXME: Limit power on turbo modes */
index 55b4ac6d236f1d93192ae72ae6323acbdc9f670c..05ef587ad2b4eb6295c94e134dfb1a7d4d90ca53 100644 (file)
 #define        AR5K_PHY_TURBO                  0x9804                  /* Register Address */
 #define        AR5K_PHY_TURBO_MODE             0x00000001      /* Enable turbo mode */
 #define        AR5K_PHY_TURBO_SHORT            0x00000002      /* Set short symbols to turbo mode */
-#define        AR5K_PHY_TURBO_MIMO             0x00000004      /* Set turbo for mimo mimo */
+#define        AR5K_PHY_TURBO_MIMO             0x00000004      /* Set turbo for mimo */
 
 /*
  * PHY agility command register
index 498aa28ea9e69bd58ba12cf889b1f2df23e3ed30..58912cd762d9808c199f78fbdb6ab97f5261e03f 100644 (file)
@@ -326,7 +326,7 @@ commit:
  * register). After this MAC and Baseband are
  * disabled and a full reset is needed to come
  * back. This way we save as much power as possible
- * without puting the card on full sleep.
+ * without putting the card on full sleep.
  */
 int ath5k_hw_on_hold(struct ath5k_hw *ah)
 {
@@ -344,7 +344,7 @@ int ath5k_hw_on_hold(struct ath5k_hw *ah)
        /*
         * Put chipset on warm reset...
         *
-        * Note: puting PCI core on warm reset on PCI-E cards
+        * Note: putting PCI core on warm reset on PCI-E cards
         * results card to hang and always return 0xffff... so
         * we ingore that flag for PCI-E cards. On PCI cards
         * this flag gets cleared after 64 PCI clocks.
@@ -400,7 +400,7 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
        /*
         * Put chipset on warm reset...
         *
-        * Note: puting PCI core on warm reset on PCI-E cards
+        * Note: putting PCI core on warm reset on PCI-E cards
         * results card to hang and always return 0xffff... so
         * we ingore that flag for PCI-E cards. On PCI cards
         * this flag gets cleared after 64 PCI clocks.
@@ -959,7 +959,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
                                                AR5K_QUEUE_DCU_SEQNUM(0));
                        }
 
-                       /* TSF accelerates on AR5211 durring reset
+                       /* TSF accelerates on AR5211 during reset
                         * As a workaround save it here and restore
                         * it later so that it's back in time after
                         * reset. This way it'll get re-synced on the
@@ -1080,7 +1080,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
                                return ret;
 
                        /* Spur info is available only from EEPROM versions
-                        * bigger than 5.3 but but the EEPOM routines will use
+                        * greater than 5.3, but the EEPROM routines will use
                         * static values for older versions */
                        if (ah->ah_mac_srev >= AR5K_SREV_AR5424)
                                ath5k_hw_set_spur_mitigation_filter(ah,
@@ -1160,7 +1160,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
         */
 
        /* Restore bssid and bssid mask */
-       ath5k_hw_set_associd(ah);
+       ath5k_hw_set_bssid(ah);
 
        /* Set PCU config */
        ath5k_hw_set_opmode(ah, op_mode);
@@ -1173,11 +1173,11 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
        /* Set RSSI/BRSSI thresholds
         *
         * Note: If we decide to set this value
-        * dynamicaly, have in mind that when AR5K_RSSI_THR
-        * register is read it might return 0x40 if we haven't
-        * wrote anything to it plus BMISS RSSI threshold is zeroed.
+        * dynamically, keep in mind that when AR5K_RSSI_THR
+        * register is read, it might return 0x40 if we haven't
+        * written anything to it.  Also, BMISS RSSI threshold is zeroed.
         * So doing a save/restore procedure here isn't the right
-        * choice. Instead store it on ath5k_hw */
+        * choice. Instead, store it in ath5k_hw */
        ath5k_hw_reg_write(ah, (AR5K_TUNE_RSSI_THRES |
                                AR5K_TUNE_BMISS_THRES <<
                                AR5K_RSSI_THR_BMISS_S),
@@ -1235,7 +1235,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
 
        /*
         * Perform ADC test to see if baseband is ready
-        * Set tx hold and check adc test register
+        * Set TX hold and check ADC test register
         */
        phy_tst1 = ath5k_hw_reg_read(ah, AR5K_PHY_TST1);
        ath5k_hw_reg_write(ah, AR5K_PHY_TST1_TXHOLD, AR5K_PHY_TST1);
@@ -1254,15 +1254,15 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
         *
         * This method is used to calibrate some static offsets
         * used together with on-the fly I/Q calibration (the
-        * one performed via ath5k_hw_phy_calibrate), that doesn't
+        * one performed via ath5k_hw_phy_calibrate), which doesn't
         * interrupt rx path.
         *
         * While rx path is re-routed to the power detector we also
-        * start a noise floor calibration, to measure the
+        * start a noise floor calibration to measure the
         * card's noise floor (the noise we measure when we are not
-        * transmiting or receiving anything).
+        * transmitting or receiving anything).
         *
-        * If we are in a noisy environment AGC calibration may time
+        * If we are in a noisy environment, AGC calibration may time
         * out and/or noise floor calibration might timeout.
         */
        AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL,
index e50baff66175a969a36110b36256b31f59c7c195..3ac4cff4239de9d8457246e8089caf8a9b5906c2 100644 (file)
  *
  * We don't write on those registers directly but
  * we send a data packet on the chip, using a special register,
- * that holds all the settings we need. After we 've sent the
+ * that holds all the settings we need. After we've sent the
  * data packet, we write on another special register to notify hw
  * to apply the settings. This is done so that control registers
- * can be dynamicaly programmed during operation and the settings
+ * can be dynamically programmed during operation and the settings
  * are applied faster on the hw.
  *
  * We call each data packet an "RF Bank" and all the data we write
index 973ae4f49f35fbd122f5eeec4c352a397c10c33e..4555e99839032ec10a77c5b729cbc508cdc3fa1e 100644 (file)
@@ -46,6 +46,7 @@ ath9k_htc-y +=        htc_hst.o \
                htc_drv_txrx.o \
                htc_drv_main.o \
                htc_drv_beacon.o \
-               htc_drv_init.o
+               htc_drv_init.o \
+               htc_drv_gpio.o
 
 obj-$(CONFIG_ATH9K_HTC) += ath9k_htc.o
index 5b995bee70ae4a931e6337c6723618edef4df725..a462da23e87e7735e632cdd582e9344d39ee1c35 100644 (file)
@@ -185,7 +185,7 @@ static bool ar9003_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
                        ath_print(common, ATH_DBG_INTERRUPT,
                                  "AR_INTR_SYNC_LOCAL_TIMEOUT\n");
 
-                       REG_WRITE(ah, AR_INTR_SYNC_CAUSE_CLR, sync_cause);
+               REG_WRITE(ah, AR_INTR_SYNC_CAUSE_CLR, sync_cause);
                (void) REG_READ(ah, AR_INTR_SYNC_CAUSE_CLR);
 
        }
index 07f26ee7a7235ac0f3c48c7966630ce849217cfc..f0197a6046aba3dad7d299b0f1989b528bc7ceeb 100644 (file)
@@ -423,6 +423,7 @@ int ath_beaconq_config(struct ath_softc *sc);
 #define ATH_AP_SHORT_CALINTERVAL  100     /* 100 ms */
 #define ATH_ANI_POLLINTERVAL_OLD  100     /* 100 ms */
 #define ATH_ANI_POLLINTERVAL_NEW  1000    /* 1000 ms */
+#define ATH_LONG_CALINTERVAL_INT  1000    /* 1000 ms */
 #define ATH_LONG_CALINTERVAL      30000   /* 30 seconds */
 #define ATH_RESTART_CALINTERVAL   1200000 /* 20 minutes */
 
@@ -436,14 +437,6 @@ void ath_ani_calibrate(unsigned long data);
 /* BTCOEX */
 /**********/
 
-/* Defines the BT AR_BT_COEX_WGHT used */
-enum ath_stomp_type {
-       ATH_BTCOEX_NO_STOMP,
-       ATH_BTCOEX_STOMP_ALL,
-       ATH_BTCOEX_STOMP_LOW,
-       ATH_BTCOEX_STOMP_NONE
-};
-
 struct ath_btcoex {
        bool hw_timer_enabled;
        spinlock_t btcoex_lock;
index 4d4b22d52dfd230a7a61b3f0dd8b5b612c38af1f..081192e78a466169936bd956257b4e6348d6ae8f 100644 (file)
@@ -359,11 +359,12 @@ void ath_beacon_tasklet(unsigned long data)
                sc->beacon.bmisscnt++;
 
                if (sc->beacon.bmisscnt < BSTUCK_THRESH) {
-                       ath_print(common, ATH_DBG_BEACON,
+                       ath_print(common, ATH_DBG_BSTUCK,
                                  "missed %u consecutive beacons\n",
                                  sc->beacon.bmisscnt);
+                       ath9k_hw_bstuck_nfcal(ah);
                } else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) {
-                       ath_print(common, ATH_DBG_BEACON,
+                       ath_print(common, ATH_DBG_BSTUCK,
                                  "beacon is officially stuck\n");
                        sc->sc_flags |= SC_OP_TSF_RESET;
                        ath_reset(sc, false);
@@ -373,7 +374,7 @@ void ath_beacon_tasklet(unsigned long data)
        }
 
        if (sc->beacon.bmisscnt != 0) {
-               ath_print(common, ATH_DBG_BEACON,
+               ath_print(common, ATH_DBG_BSTUCK,
                          "resume beacon xmit after %u misses\n",
                          sc->beacon.bmisscnt);
                sc->beacon.bmisscnt = 0;
index fb4ac15f3b9317487f060e0b7b51cbe59ef09654..6a92e57fddf0dc2c8127ef544dcdfd36d4d41d38 100644 (file)
@@ -168,6 +168,7 @@ EXPORT_SYMBOL(ath9k_hw_btcoex_set_weight);
 static void ath9k_hw_btcoex_enable_3wire(struct ath_hw *ah)
 {
        struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
+       u32  val;
 
        /*
         * Program coex mode and weight registers to
@@ -177,6 +178,12 @@ static void ath9k_hw_btcoex_enable_3wire(struct ath_hw *ah)
        REG_WRITE(ah, AR_BT_COEX_WEIGHT, btcoex_hw->bt_coex_weights);
        REG_WRITE(ah, AR_BT_COEX_MODE2, btcoex_hw->bt_coex_mode2);
 
+       if (AR_SREV_9271(ah)) {
+               val = REG_READ(ah, 0x50040);
+               val &= 0xFFFFFEFF;
+               REG_WRITE(ah, 0x50040, val);
+       }
+
        REG_RMW_FIELD(ah, AR_QUIET1, AR_QUIET1_QUIET_ACK_CTS_ENABLE, 1);
        REG_RMW_FIELD(ah, AR_PCU_MISC, AR_PCU_BT_ANT_PREVENT_RX, 0);
 
index 45208690c0ec3d5cf747d0ac18218ddeedaf20f8..67ee5d735cc12a30b5f642c0d0860531a4242ed1 100644 (file)
@@ -19,8 +19,7 @@
 
 /* Common calibration code */
 
-/* We can tune this as we go by monitoring really low values */
-#define ATH9K_NF_TOO_LOW       -60
+#define ATH9K_NF_TOO_HIGH      -60
 
 static int16_t ath9k_hw_get_nf_hist_mid(int16_t *nfCalBuffer)
 {
@@ -45,11 +44,39 @@ static int16_t ath9k_hw_get_nf_hist_mid(int16_t *nfCalBuffer)
        return nfval;
 }
 
-static void ath9k_hw_update_nfcal_hist_buffer(struct ath9k_nfcal_hist *h,
+static struct ath_nf_limits *ath9k_hw_get_nf_limits(struct ath_hw *ah,
+                                                   struct ath9k_channel *chan)
+{
+       struct ath_nf_limits *limit;
+
+       if (!chan || IS_CHAN_2GHZ(chan))
+               limit = &ah->nf_2g;
+       else
+               limit = &ah->nf_5g;
+
+       return limit;
+}
+
+static s16 ath9k_hw_get_default_nf(struct ath_hw *ah,
+                                  struct ath9k_channel *chan)
+{
+       return ath9k_hw_get_nf_limits(ah, chan)->nominal;
+}
+
+
+static void ath9k_hw_update_nfcal_hist_buffer(struct ath_hw *ah,
+                                             struct ath9k_hw_cal_data *cal,
                                              int16_t *nfarray)
 {
+       struct ath_common *common = ath9k_hw_common(ah);
+       struct ath_nf_limits *limit;
+       struct ath9k_nfcal_hist *h;
+       bool high_nf_mid = false;
        int i;
 
+       h = cal->nfCalHist;
+       limit = ath9k_hw_get_nf_limits(ah, ah->curchan);
+
        for (i = 0; i < NUM_NF_READINGS; i++) {
                h[i].nfCalBuffer[h[i].currIndex] = nfarray[i];
 
@@ -63,7 +90,39 @@ static void ath9k_hw_update_nfcal_hist_buffer(struct ath9k_nfcal_hist *h,
                        h[i].privNF =
                                ath9k_hw_get_nf_hist_mid(h[i].nfCalBuffer);
                }
+
+               if (!h[i].privNF)
+                       continue;
+
+               if (h[i].privNF > limit->max) {
+                       high_nf_mid = true;
+
+                       ath_print(common, ATH_DBG_CALIBRATE,
+                                 "NFmid[%d] (%d) > MAX (%d), %s\n",
+                                 i, h[i].privNF, limit->max,
+                                 (cal->nfcal_interference ?
+                                  "not corrected (due to interference)" :
+                                  "correcting to MAX"));
+
+                       /*
+                        * Normally we limit the average noise floor by the
+                        * hardware specific maximum here. However if we have
+                        * encountered stuck beacons because of interference,
+                        * we bypass this limit here in order to better deal
+                        * with our environment.
+                        */
+                       if (!cal->nfcal_interference)
+                               h[i].privNF = limit->max;
+               }
        }
+
+       /*
+        * If the noise floor seems normal for all chains, assume that
+        * there is no significant interference in the environment anymore.
+        * Re-enable the enforcement of the NF maximum again.
+        */
+       if (!high_nf_mid)
+               cal->nfcal_interference = false;
 }
 
 static bool ath9k_hw_get_nf_thresh(struct ath_hw *ah,
@@ -104,19 +163,6 @@ void ath9k_hw_reset_calibration(struct ath_hw *ah,
        ah->cal_samples = 0;
 }
 
-static s16 ath9k_hw_get_default_nf(struct ath_hw *ah,
-                                  struct ath9k_channel *chan)
-{
-       struct ath_nf_limits *limit;
-
-       if (!chan || IS_CHAN_2GHZ(chan))
-               limit = &ah->nf_2g;
-       else
-               limit = &ah->nf_5g;
-
-       return limit->nominal;
-}
-
 /* This is done for the currently configured channel */
 bool ath9k_hw_reset_calvalid(struct ath_hw *ah)
 {
@@ -277,10 +323,10 @@ static void ath9k_hw_nf_sanitize(struct ath_hw *ah, s16 *nf)
                          "NF calibrated [%s] [chain %d] is %d\n",
                          (i >= 3 ? "ext" : "ctl"), i % 3, nf[i]);
 
-               if (nf[i] > limit->max) {
+               if (nf[i] > ATH9K_NF_TOO_HIGH) {
                        ath_print(common, ATH_DBG_CALIBRATE,
                                  "NF[%d] (%d) > MAX (%d), correcting to MAX",
-                                 i, nf[i], limit->max);
+                                 i, nf[i], ATH9K_NF_TOO_HIGH);
                        nf[i] = limit->max;
                } else if (nf[i] < limit->min) {
                        ath_print(common, ATH_DBG_CALIBRATE,
@@ -326,7 +372,7 @@ bool ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan)
 
        h = caldata->nfCalHist;
        caldata->nfcal_pending = false;
-       ath9k_hw_update_nfcal_hist_buffer(h, nfarray);
+       ath9k_hw_update_nfcal_hist_buffer(ah, caldata, nfarray);
        caldata->rawNoiseFloor = h[0].privNF;
        return true;
 }
@@ -361,3 +407,28 @@ s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan)
        return ah->caldata->rawNoiseFloor;
 }
 EXPORT_SYMBOL(ath9k_hw_getchan_noise);
+
+void ath9k_hw_bstuck_nfcal(struct ath_hw *ah)
+{
+       struct ath9k_hw_cal_data *caldata = ah->caldata;
+
+       if (unlikely(!caldata))
+               return;
+
+       /*
+        * If beacons are stuck, the most likely cause is interference.
+        * Triggering a noise floor calibration at this point helps the
+        * hardware adapt to a noisy environment much faster.
+        * To ensure that we recover from stuck beacons quickly, let
+        * the baseband update the internal NF value itself, similar to
+        * what is being done after a full reset.
+        */
+       if (!caldata->nfcal_pending)
+               ath9k_hw_start_nfcal(ah, true);
+       else if (!(REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF))
+               ath9k_hw_getnf(ah, ah->curchan);
+
+       caldata->nfcal_interference = true;
+}
+EXPORT_SYMBOL(ath9k_hw_bstuck_nfcal);
+
index 0a304b3eeeb6dad1e414ee362888900a9d811e24..5b053a6260b27f4c9021c0cd27d84b75e24cda48 100644 (file)
@@ -113,6 +113,7 @@ void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan);
 bool ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan);
 void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah,
                                  struct ath9k_channel *chan);
+void ath9k_hw_bstuck_nfcal(struct ath_hw *ah);
 s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan);
 void ath9k_hw_reset_calibration(struct ath_hw *ah,
                                struct ath9k_cal_list *currCal);
index c86f7d3593ab48a3c1c1248443f0f2f599a327f8..2dab64bb23a8dc4aebb51d0d9f406e222059c670 100644 (file)
@@ -46,12 +46,17 @@ int ath9k_cmn_get_hw_crypto_keytype(struct sk_buff *skb)
        struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
 
        if (tx_info->control.hw_key) {
-               if (tx_info->control.hw_key->alg == ALG_WEP)
+               switch (tx_info->control.hw_key->cipher) {
+               case WLAN_CIPHER_SUITE_WEP40:
+               case WLAN_CIPHER_SUITE_WEP104:
                        return ATH9K_KEY_TYPE_WEP;
-               else if (tx_info->control.hw_key->alg == ALG_TKIP)
+               case WLAN_CIPHER_SUITE_TKIP:
                        return ATH9K_KEY_TYPE_TKIP;
-               else if (tx_info->control.hw_key->alg == ALG_CCMP)
+               case WLAN_CIPHER_SUITE_CCMP:
                        return ATH9K_KEY_TYPE_AES;
+               default:
+                       break;
+               }
        }
 
        return ATH9K_KEY_TYPE_CLEAR;
@@ -212,11 +217,11 @@ static int ath_reserve_key_cache_slot_tkip(struct ath_common *common)
 }
 
 static int ath_reserve_key_cache_slot(struct ath_common *common,
-                                     enum ieee80211_key_alg alg)
+                                     u32 cipher)
 {
        int i;
 
-       if (alg == ALG_TKIP)
+       if (cipher == WLAN_CIPHER_SUITE_TKIP)
                return ath_reserve_key_cache_slot_tkip(common);
 
        /* First, try to find slots that would not be available for TKIP. */
@@ -293,14 +298,15 @@ int ath9k_cmn_key_config(struct ath_common *common,
 
        memset(&hk, 0, sizeof(hk));
 
-       switch (key->alg) {
-       case ALG_WEP:
+       switch (key->cipher) {
+       case WLAN_CIPHER_SUITE_WEP40:
+       case WLAN_CIPHER_SUITE_WEP104:
                hk.kv_type = ATH9K_CIPHER_WEP;
                break;
-       case ALG_TKIP:
+       case WLAN_CIPHER_SUITE_TKIP:
                hk.kv_type = ATH9K_CIPHER_TKIP;
                break;
-       case ALG_CCMP:
+       case WLAN_CIPHER_SUITE_CCMP:
                hk.kv_type = ATH9K_CIPHER_AES_CCM;
                break;
        default:
@@ -316,7 +322,7 @@ int ath9k_cmn_key_config(struct ath_common *common,
                        memcpy(gmac, vif->addr, ETH_ALEN);
                        gmac[0] |= 0x01;
                        mac = gmac;
-                       idx = ath_reserve_key_cache_slot(common, key->alg);
+                       idx = ath_reserve_key_cache_slot(common, key->cipher);
                        break;
                case NL80211_IFTYPE_ADHOC:
                        if (!sta) {
@@ -326,7 +332,7 @@ int ath9k_cmn_key_config(struct ath_common *common,
                        memcpy(gmac, sta->addr, ETH_ALEN);
                        gmac[0] |= 0x01;
                        mac = gmac;
-                       idx = ath_reserve_key_cache_slot(common, key->alg);
+                       idx = ath_reserve_key_cache_slot(common, key->cipher);
                        break;
                default:
                        idx = key->keyidx;
@@ -348,13 +354,13 @@ int ath9k_cmn_key_config(struct ath_common *common,
                        return -EOPNOTSUPP;
                mac = sta->addr;
 
-               idx = ath_reserve_key_cache_slot(common, key->alg);
+               idx = ath_reserve_key_cache_slot(common, key->cipher);
        }
 
        if (idx < 0)
                return -ENOSPC; /* no free key cache entries */
 
-       if (key->alg == ALG_TKIP)
+       if (key->cipher == WLAN_CIPHER_SUITE_TKIP)
                ret = ath_setkey_tkip(common, idx, key->key, &hk, mac,
                                      vif->type == NL80211_IFTYPE_AP);
        else
@@ -364,11 +370,15 @@ int ath9k_cmn_key_config(struct ath_common *common,
                return -EIO;
 
        set_bit(idx, common->keymap);
-       if (key->alg == ALG_TKIP) {
+       if (key->cipher == WLAN_CIPHER_SUITE_TKIP) {
                set_bit(idx + 64, common->keymap);
+               set_bit(idx, common->tkip_keymap);
+               set_bit(idx + 64, common->tkip_keymap);
                if (common->splitmic) {
                        set_bit(idx + 32, common->keymap);
                        set_bit(idx + 64 + 32, common->keymap);
+                       set_bit(idx + 32, common->tkip_keymap);
+                       set_bit(idx + 64 + 32, common->tkip_keymap);
                }
        }
 
@@ -389,14 +399,21 @@ void ath9k_cmn_key_delete(struct ath_common *common,
                return;
 
        clear_bit(key->hw_key_idx, common->keymap);
-       if (key->alg != ALG_TKIP)
+       if (key->cipher != WLAN_CIPHER_SUITE_TKIP)
                return;
 
        clear_bit(key->hw_key_idx + 64, common->keymap);
+
+       clear_bit(key->hw_key_idx, common->tkip_keymap);
+       clear_bit(key->hw_key_idx + 64, common->tkip_keymap);
+
        if (common->splitmic) {
                ath9k_hw_keyreset(ah, key->hw_key_idx + 32);
                clear_bit(key->hw_key_idx + 32, common->keymap);
                clear_bit(key->hw_key_idx + 64 + 32, common->keymap);
+
+               clear_bit(key->hw_key_idx + 32, common->tkip_keymap);
+               clear_bit(key->hw_key_idx + 64 + 32, common->tkip_keymap);
        }
 }
 EXPORT_SYMBOL(ath9k_cmn_key_delete);
@@ -414,6 +431,37 @@ int ath9k_cmn_count_streams(unsigned int chainmask, int max)
 }
 EXPORT_SYMBOL(ath9k_cmn_count_streams);
 
+/*
+ * Configures appropriate weight based on stomp type.
+ */
+void ath9k_cmn_btcoex_bt_stomp(struct ath_common *common,
+                                 enum ath_stomp_type stomp_type)
+{
+       struct ath_hw *ah = common->ah;
+
+       switch (stomp_type) {
+       case ATH_BTCOEX_STOMP_ALL:
+               ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
+                                          AR_STOMP_ALL_WLAN_WGHT);
+               break;
+       case ATH_BTCOEX_STOMP_LOW:
+               ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
+                                          AR_STOMP_LOW_WLAN_WGHT);
+               break;
+       case ATH_BTCOEX_STOMP_NONE:
+               ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
+                                          AR_STOMP_NONE_WLAN_WGHT);
+               break;
+       default:
+               ath_print(common, ATH_DBG_BTCOEX,
+                         "Invalid Stomptype\n");
+               break;
+       }
+
+       ath9k_hw_btcoex_enable(ah);
+}
+EXPORT_SYMBOL(ath9k_cmn_btcoex_bt_stomp);
+
 static int __init ath9k_cmn_init(void)
 {
        return 0;
index 97809d39c73fc81f1eb59ea14879a1d9618fb404..4aa4e7dbe4d21022369eacf7f12214e73dea9f1e 100644 (file)
 #define ATH_EP_RND(x, mul)                                             \
        ((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul))
 
+/* Defines the BT AR_BT_COEX_WGHT used */
+enum ath_stomp_type {
+       ATH_BTCOEX_NO_STOMP,
+       ATH_BTCOEX_STOMP_ALL,
+       ATH_BTCOEX_STOMP_LOW,
+       ATH_BTCOEX_STOMP_NONE
+};
+
 int ath9k_cmn_padpos(__le16 frame_control);
 int ath9k_cmn_get_hw_crypto_keytype(struct sk_buff *skb);
 void ath9k_cmn_update_ichannel(struct ieee80211_hw *hw,
@@ -65,3 +73,5 @@ int ath9k_cmn_key_config(struct ath_common *common,
 void ath9k_cmn_key_delete(struct ath_common *common,
                          struct ieee80211_key_conf *key);
 int ath9k_cmn_count_streams(unsigned int chainmask, int max);
+void ath9k_cmn_btcoex_bt_stomp(struct ath_common *common,
+                                 enum ath_stomp_type stomp_type);
index 3a8ee999da5dc111414b6aebf284930dff75cae9..4a9a68bba324790b5a549332e71723867a46eaf4 100644 (file)
@@ -251,36 +251,6 @@ static void ath_detect_bt_priority(struct ath_softc *sc)
        }
 }
 
-/*
- * Configures appropriate weight based on stomp type.
- */
-static void ath9k_btcoex_bt_stomp(struct ath_softc *sc,
-                                 enum ath_stomp_type stomp_type)
-{
-       struct ath_hw *ah = sc->sc_ah;
-
-       switch (stomp_type) {
-       case ATH_BTCOEX_STOMP_ALL:
-               ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
-                                          AR_STOMP_ALL_WLAN_WGHT);
-               break;
-       case ATH_BTCOEX_STOMP_LOW:
-               ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
-                                          AR_STOMP_LOW_WLAN_WGHT);
-               break;
-       case ATH_BTCOEX_STOMP_NONE:
-               ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
-                                          AR_STOMP_NONE_WLAN_WGHT);
-               break;
-       default:
-               ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX,
-                         "Invalid Stomptype\n");
-               break;
-       }
-
-       ath9k_hw_btcoex_enable(ah);
-}
-
 static void ath9k_gen_timer_start(struct ath_hw *ah,
                                  struct ath_gen_timer *timer,
                                  u32 timer_next,
@@ -319,6 +289,7 @@ static void ath_btcoex_period_timer(unsigned long data)
        struct ath_softc *sc = (struct ath_softc *) data;
        struct ath_hw *ah = sc->sc_ah;
        struct ath_btcoex *btcoex = &sc->btcoex;
+       struct ath_common *common = ath9k_hw_common(ah);
        u32 timer_period;
        bool is_btscan;
 
@@ -328,7 +299,7 @@ static void ath_btcoex_period_timer(unsigned long data)
 
        spin_lock_bh(&btcoex->btcoex_lock);
 
-       ath9k_btcoex_bt_stomp(sc, is_btscan ? ATH_BTCOEX_STOMP_ALL :
+       ath9k_cmn_btcoex_bt_stomp(common, is_btscan ? ATH_BTCOEX_STOMP_ALL :
                              btcoex->bt_stomp_type);
 
        spin_unlock_bh(&btcoex->btcoex_lock);
@@ -359,17 +330,18 @@ static void ath_btcoex_no_stomp_timer(void *arg)
        struct ath_softc *sc = (struct ath_softc *)arg;
        struct ath_hw *ah = sc->sc_ah;
        struct ath_btcoex *btcoex = &sc->btcoex;
+       struct ath_common *common = ath9k_hw_common(ah);
        bool is_btscan = sc->sc_flags & SC_OP_BT_SCAN;
 
-       ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX,
+       ath_print(common, ATH_DBG_BTCOEX,
                  "no stomp timer running\n");
 
        spin_lock_bh(&btcoex->btcoex_lock);
 
        if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW || is_btscan)
-               ath9k_btcoex_bt_stomp(sc, ATH_BTCOEX_STOMP_NONE);
+               ath9k_cmn_btcoex_bt_stomp(common, ATH_BTCOEX_STOMP_NONE);
         else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL)
-               ath9k_btcoex_bt_stomp(sc, ATH_BTCOEX_STOMP_LOW);
+               ath9k_cmn_btcoex_bt_stomp(common, ATH_BTCOEX_STOMP_LOW);
 
        spin_unlock_bh(&btcoex->btcoex_lock);
 }
index 17e7a9a367e70340a42d13c57beb167bfd4979d3..495f18950ac9d487d217f393495ffcba9562eb5d 100644 (file)
@@ -920,7 +920,8 @@ static int ath9k_hif_usb_probe(struct usb_interface *interface,
        }
 
        ret = ath9k_htc_hw_init(hif_dev->htc_handle,
-                               &hif_dev->udev->dev, hif_dev->device_id);
+                               &hif_dev->udev->dev, hif_dev->device_id,
+                               hif_dev->udev->product);
        if (ret) {
                ret = -EINVAL;
                goto err_htc_hw_init;
index 43b9e21bc56284da1246ec1020cd23907a11d0df..75ecf6a30d25c6ac68d346c5ac862a0255ba4be1 100644 (file)
@@ -316,17 +316,32 @@ struct htc_beacon_config {
        u8 dtim_count;
 };
 
-#define OP_INVALID        BIT(0)
-#define OP_SCANNING       BIT(1)
-#define OP_FULL_RESET     BIT(2)
-#define OP_LED_ASSOCIATED BIT(3)
-#define OP_LED_ON         BIT(4)
-#define OP_PREAMBLE_SHORT BIT(5)
-#define OP_PROTECT_ENABLE BIT(6)
-#define OP_ASSOCIATED     BIT(7)
-#define OP_ENABLE_BEACON  BIT(8)
-#define OP_LED_DEINIT     BIT(9)
-#define OP_UNPLUGGED      BIT(10)
+struct ath_btcoex {
+       u32 bt_priority_cnt;
+       unsigned long bt_priority_time;
+       int bt_stomp_type; /* Types of BT stomping */
+       u32 btcoex_no_stomp;
+       u32 btcoex_period;
+       u32 btscan_no_stomp;
+};
+
+void ath_htc_init_btcoex_work(struct ath9k_htc_priv *priv);
+void ath_htc_resume_btcoex_work(struct ath9k_htc_priv *priv);
+void ath_htc_cancel_btcoex_work(struct ath9k_htc_priv *priv);
+
+#define OP_INVALID                BIT(0)
+#define OP_SCANNING               BIT(1)
+#define OP_FULL_RESET             BIT(2)
+#define OP_LED_ASSOCIATED         BIT(3)
+#define OP_LED_ON                 BIT(4)
+#define OP_PREAMBLE_SHORT         BIT(5)
+#define OP_PROTECT_ENABLE         BIT(6)
+#define OP_ASSOCIATED             BIT(7)
+#define OP_ENABLE_BEACON          BIT(8)
+#define OP_LED_DEINIT             BIT(9)
+#define OP_UNPLUGGED              BIT(10)
+#define OP_BT_PRIORITY_DETECTED           BIT(11)
+#define OP_BT_SCAN                BIT(12)
 
 struct ath9k_htc_priv {
        struct device *dev;
@@ -391,6 +406,9 @@ struct ath9k_htc_priv {
        int cabq;
        int hwq_map[WME_NUM_AC];
 
+       struct ath_btcoex btcoex;
+       struct delayed_work coex_period_work;
+       struct delayed_work duty_cycle_work;
 #ifdef CONFIG_ATH9K_HTC_DEBUGFS
        struct ath9k_debug debug;
 #endif
@@ -443,7 +461,7 @@ void ath9k_init_leds(struct ath9k_htc_priv *priv);
 void ath9k_deinit_leds(struct ath9k_htc_priv *priv);
 
 int ath9k_htc_probe_device(struct htc_target *htc_handle, struct device *dev,
-                          u16 devid);
+                          u16 devid, char *product);
 void ath9k_htc_disconnect_device(struct htc_target *htc_handle, bool hotunplug);
 #ifdef CONFIG_PM
 int ath9k_htc_resume(struct htc_target *htc_handle);
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c
new file mode 100644 (file)
index 0000000..50eec9a
--- /dev/null
@@ -0,0 +1,134 @@
+#include "htc.h"
+
+/******************/
+/*     BTCOEX     */
+/******************/
+
+/*
+ * Detects if there is any priority bt traffic
+ */
+static void ath_detect_bt_priority(struct ath9k_htc_priv *priv)
+{
+       struct ath_btcoex *btcoex = &priv->btcoex;
+       struct ath_hw *ah = priv->ah;
+
+       if (ath9k_hw_gpio_get(ah, ah->btcoex_hw.btpriority_gpio))
+               btcoex->bt_priority_cnt++;
+
+       if (time_after(jiffies, btcoex->bt_priority_time +
+                       msecs_to_jiffies(ATH_BT_PRIORITY_TIME_THRESHOLD))) {
+               priv->op_flags &= ~(OP_BT_PRIORITY_DETECTED | OP_BT_SCAN);
+               /* Detect if colocated bt started scanning */
+               if (btcoex->bt_priority_cnt >= ATH_BT_CNT_SCAN_THRESHOLD) {
+                       ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX,
+                                 "BT scan detected");
+                       priv->op_flags |= (OP_BT_SCAN |
+                                        OP_BT_PRIORITY_DETECTED);
+               } else if (btcoex->bt_priority_cnt >= ATH_BT_CNT_THRESHOLD) {
+                       ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX,
+                                   "BT priority traffic detected");
+                       priv->op_flags |= OP_BT_PRIORITY_DETECTED;
+               }
+
+               btcoex->bt_priority_cnt = 0;
+               btcoex->bt_priority_time = jiffies;
+       }
+}
+
+/*
+ * This is the master bt coex work which runs for every
+ * 45ms, bt traffic will be given priority during 55% of this
+ * period while wlan gets remaining 45%
+ */
+static void ath_btcoex_period_work(struct work_struct *work)
+{
+       struct ath9k_htc_priv *priv = container_of(work, struct ath9k_htc_priv,
+                                                  coex_period_work.work);
+       struct ath_btcoex *btcoex = &priv->btcoex;
+       struct ath_common *common = ath9k_hw_common(priv->ah);
+       u32 timer_period;
+       bool is_btscan;
+       int ret;
+       u8 cmd_rsp, aggr;
+
+       ath_detect_bt_priority(priv);
+
+       is_btscan = !!(priv->op_flags & OP_BT_SCAN);
+
+       aggr = priv->op_flags & OP_BT_PRIORITY_DETECTED;
+
+       WMI_CMD_BUF(WMI_AGGR_LIMIT_CMD, &aggr);
+
+       ath9k_cmn_btcoex_bt_stomp(common, is_btscan ? ATH_BTCOEX_STOMP_ALL :
+                       btcoex->bt_stomp_type);
+
+       timer_period = is_btscan ? btcoex->btscan_no_stomp :
+               btcoex->btcoex_no_stomp;
+       ieee80211_queue_delayed_work(priv->hw, &priv->duty_cycle_work,
+                                    msecs_to_jiffies(timer_period));
+       ieee80211_queue_delayed_work(priv->hw, &priv->coex_period_work,
+                                    msecs_to_jiffies(btcoex->btcoex_period));
+}
+
+/*
+ * Work to time slice between wlan and bt traffic and
+ * configure weight registers
+ */
+static void ath_btcoex_duty_cycle_work(struct work_struct *work)
+{
+       struct ath9k_htc_priv *priv = container_of(work, struct ath9k_htc_priv,
+                                                  duty_cycle_work.work);
+       struct ath_hw *ah = priv->ah;
+       struct ath_btcoex *btcoex = &priv->btcoex;
+       struct ath_common *common = ath9k_hw_common(ah);
+       bool is_btscan = priv->op_flags & OP_BT_SCAN;
+
+       ath_print(common, ATH_DBG_BTCOEX,
+                 "time slice work for bt and wlan\n");
+
+       if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW || is_btscan)
+               ath9k_cmn_btcoex_bt_stomp(common, ATH_BTCOEX_STOMP_NONE);
+       else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL)
+               ath9k_cmn_btcoex_bt_stomp(common, ATH_BTCOEX_STOMP_LOW);
+}
+
+void ath_htc_init_btcoex_work(struct ath9k_htc_priv *priv)
+{
+       struct ath_btcoex *btcoex = &priv->btcoex;
+
+       btcoex->btcoex_period = ATH_BTCOEX_DEF_BT_PERIOD;
+       btcoex->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) *
+               btcoex->btcoex_period / 100;
+       btcoex->btscan_no_stomp = (100 - ATH_BTCOEX_BTSCAN_DUTY_CYCLE) *
+                                  btcoex->btcoex_period / 100;
+       INIT_DELAYED_WORK(&priv->coex_period_work, ath_btcoex_period_work);
+       INIT_DELAYED_WORK(&priv->duty_cycle_work, ath_btcoex_duty_cycle_work);
+}
+
+/*
+ * (Re)start btcoex work
+ */
+
+void ath_htc_resume_btcoex_work(struct ath9k_htc_priv *priv)
+{
+       struct ath_btcoex *btcoex = &priv->btcoex;
+       struct ath_hw *ah = priv->ah;
+
+       ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX,
+                 "Starting btcoex work");
+
+       btcoex->bt_priority_cnt = 0;
+       btcoex->bt_priority_time = jiffies;
+       priv->op_flags &= ~(OP_BT_PRIORITY_DETECTED | OP_BT_SCAN);
+       ieee80211_queue_delayed_work(priv->hw, &priv->coex_period_work, 0);
+}
+
+
+/*
+ * Cancel btcoex and bt duty cycle work.
+ */
+void ath_htc_cancel_btcoex_work(struct ath9k_htc_priv *priv)
+{
+       cancel_delayed_work_sync(&priv->coex_period_work);
+       cancel_delayed_work_sync(&priv->duty_cycle_work);
+}
index 2d4279191d7a7d6d1690d12a809cf9eb6dd8ef8a..695e2b088d105c4859aba2892c1305dfa6a5b655 100644 (file)
@@ -41,6 +41,8 @@ MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption");
        .max_power = 20, \
 }
 
+#define ATH_HTC_BTCOEX_PRODUCT_ID "wb193"
+
 static struct ieee80211_channel ath9k_2ghz_channels[] = {
        CHAN2G(2412, 0), /* Channel 1 */
        CHAN2G(2417, 1), /* Channel 2 */
@@ -605,7 +607,31 @@ static void ath9k_init_misc(struct ath9k_htc_priv *priv)
        priv->ah->opmode = NL80211_IFTYPE_STATION;
 }
 
-static int ath9k_init_priv(struct ath9k_htc_priv *priv, u16 devid)
+static void ath9k_init_btcoex(struct ath9k_htc_priv *priv)
+{
+       int qnum;
+
+       switch (priv->ah->btcoex_hw.scheme) {
+       case ATH_BTCOEX_CFG_NONE:
+               break;
+       case ATH_BTCOEX_CFG_3WIRE:
+               priv->ah->btcoex_hw.btactive_gpio = 7;
+               priv->ah->btcoex_hw.btpriority_gpio = 6;
+               priv->ah->btcoex_hw.wlanactive_gpio = 8;
+               priv->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW;
+               ath9k_hw_btcoex_init_3wire(priv->ah);
+               ath_htc_init_btcoex_work(priv);
+               qnum = priv->hwq_map[WME_AC_BE];
+               ath9k_hw_init_btcoex_hw(priv->ah, qnum);
+               break;
+       default:
+               WARN_ON(1);
+               break;
+       }
+}
+
+static int ath9k_init_priv(struct ath9k_htc_priv *priv,
+                          u16 devid, char *product)
 {
        struct ath_hw *ah = NULL;
        struct ath_common *common;
@@ -672,6 +698,11 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv, u16 devid)
        ath9k_init_channels_rates(priv);
        ath9k_init_misc(priv);
 
+       if (product && strncmp(product, ATH_HTC_BTCOEX_PRODUCT_ID, 5) == 0) {
+               ah->btcoex_hw.scheme = ATH_BTCOEX_CFG_3WIRE;
+               ath9k_init_btcoex(priv);
+       }
+
        return 0;
 
 err_queues:
@@ -734,7 +765,8 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv,
        SET_IEEE80211_PERM_ADDR(hw, common->macaddr);
 }
 
-static int ath9k_init_device(struct ath9k_htc_priv *priv, u16 devid)
+static int ath9k_init_device(struct ath9k_htc_priv *priv,
+                            u16 devid, char *product)
 {
        struct ieee80211_hw *hw = priv->hw;
        struct ath_common *common;
@@ -743,7 +775,7 @@ static int ath9k_init_device(struct ath9k_htc_priv *priv, u16 devid)
        struct ath_regulatory *reg;
 
        /* Bring up device */
-       error = ath9k_init_priv(priv, devid);
+       error = ath9k_init_priv(priv, devid, product);
        if (error != 0)
                goto err_init;
 
@@ -801,7 +833,7 @@ err_init:
 }
 
 int ath9k_htc_probe_device(struct htc_target *htc_handle, struct device *dev,
-                          u16 devid)
+                          u16 devid, char *product)
 {
        struct ieee80211_hw *hw;
        struct ath9k_htc_priv *priv;
@@ -835,7 +867,7 @@ int ath9k_htc_probe_device(struct htc_target *htc_handle, struct device *dev,
        /* The device may have been unplugged earlier. */
        priv->op_flags &= ~OP_UNPLUGGED;
 
-       ret = ath9k_init_device(priv, devid);
+       ret = ath9k_init_device(priv, devid, product);
        if (ret)
                goto err_init;
 
index 7d09b4b17bbd4b5e1146fa295ea6a22ffb571014..f4672073ac0a3e37db701c6b99d37c5f6a5181d1 100644 (file)
@@ -1210,6 +1210,12 @@ static int ath9k_htc_start(struct ieee80211_hw *hw)
 
        ieee80211_wake_queues(hw);
 
+       if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) {
+               ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
+                                          AR_STOMP_LOW_WLAN_WGHT);
+               ath9k_hw_btcoex_enable(ah);
+               ath_htc_resume_btcoex_work(priv);
+       }
        mutex_unlock(&priv->mutex);
 
        return ret;
@@ -1233,7 +1239,6 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw)
 
        /* Cancel all the running timers/work .. */
        cancel_work_sync(&priv->ps_work);
-       cancel_delayed_work_sync(&priv->ath9k_ani_work);
        cancel_delayed_work_sync(&priv->ath9k_led_blink_work);
        ath9k_led_stop_brightness(priv);
 
@@ -1254,6 +1259,12 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw)
                                  "Monitor interface removed\n");
        }
 
+       if (ah->btcoex_hw.enabled) {
+               ath9k_hw_btcoex_disable(ah);
+               if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE)
+                       ath_htc_cancel_btcoex_work(priv);
+       }
+
        ath9k_hw_phy_disable(ah);
        ath9k_hw_disable(ah);
        ath9k_hw_configpcipowersave(ah, 1, 1);
@@ -1585,9 +1596,10 @@ static int ath9k_htc_set_key(struct ieee80211_hw *hw,
                        key->hw_key_idx = ret;
                        /* push IV and Michael MIC generation to stack */
                        key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
-                       if (key->alg == ALG_TKIP)
+                       if (key->cipher == WLAN_CIPHER_SUITE_TKIP)
                                key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
-                       if (priv->ah->sw_mgmt_crypto && key->alg == ALG_CCMP)
+                       if (priv->ah->sw_mgmt_crypto &&
+                           key->cipher == WLAN_CIPHER_SUITE_CCMP)
                                key->flags |= IEEE80211_KEY_FLAG_SW_MGMT;
                        ret = 0;
                }
@@ -1774,7 +1786,8 @@ static void ath9k_htc_sw_scan_start(struct ieee80211_hw *hw)
        priv->op_flags |= OP_SCANNING;
        spin_unlock_bh(&priv->beacon_lock);
        cancel_work_sync(&priv->ps_work);
-       cancel_delayed_work_sync(&priv->ath9k_ani_work);
+       if (priv->op_flags & OP_ASSOCIATED)
+               cancel_delayed_work_sync(&priv->ath9k_ani_work);
        mutex_unlock(&priv->mutex);
 }
 
@@ -1788,9 +1801,10 @@ static void ath9k_htc_sw_scan_complete(struct ieee80211_hw *hw)
        priv->op_flags &= ~OP_SCANNING;
        spin_unlock_bh(&priv->beacon_lock);
        priv->op_flags |= OP_FULL_RESET;
-       if (priv->op_flags & OP_ASSOCIATED)
+       if (priv->op_flags & OP_ASSOCIATED) {
                ath9k_htc_beacon_config(priv, priv->vif);
-       ath_start_ani(priv);
+               ath_start_ani(priv);
+       }
        ath9k_htc_ps_restore(priv);
        mutex_unlock(&priv->mutex);
 }
index 705c0f342e1c0342ea4000c5ea747ececf31dfce..861ec92693096d07bfca64d4a16e0076fa390ce6 100644 (file)
@@ -462,9 +462,9 @@ void ath9k_htc_hw_free(struct htc_target *htc)
 }
 
 int ath9k_htc_hw_init(struct htc_target *target,
-                     struct device *dev, u16 devid)
+                     struct device *dev, u16 devid, char *product)
 {
-       if (ath9k_htc_probe_device(target, dev, devid)) {
+       if (ath9k_htc_probe_device(target, dev, devid, product)) {
                printk(KERN_ERR "Failed to initialize the device\n");
                return -ENODEV;
        }
index faba6790328b42ae20520ffee47cf90799e788f0..07b6509d58964681a141c92266fa5fb9c8a6cfff 100644 (file)
@@ -239,7 +239,7 @@ struct htc_target *ath9k_htc_hw_alloc(void *hif_handle,
                                      struct device *dev);
 void ath9k_htc_hw_free(struct htc_target *htc);
 int ath9k_htc_hw_init(struct htc_target *target,
-                     struct device *dev, u16 devid);
+                     struct device *dev, u16 devid, char *product);
 void ath9k_htc_hw_deinit(struct htc_target *target, bool hot_unplug);
 
 #endif /* HTC_HST_H */
index 399f7c1283cdf32ba4cdb5eef198c4cd2ed085bd..1601dd43989064b9bc070fa58741b7978cfbda88 100644 (file)
@@ -355,6 +355,7 @@ struct ath9k_hw_cal_data {
        int16_t rawNoiseFloor;
        bool paprd_done;
        bool nfcal_pending;
+       bool nfcal_interference;
        u16 small_signal_gain[AR9300_MAX_CHAINS];
        u32 pa_table[AR9300_MAX_CHAINS][PAPRD_TABLE_SZ];
        struct ath9k_nfcal_hist nfCalHist[NUM_NF_READINGS];
index 243c1775f343f0b3400b0675708ee292bcb54e74..3dbff8d077667a224660464eddfcc2c1e008ea61 100644 (file)
@@ -33,7 +33,7 @@ int modparam_nohwcrypt;
 module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444);
 MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption");
 
-int led_blink = 1;
+int led_blink;
 module_param_named(blink, led_blink, int, 0444);
 MODULE_PARM_DESC(blink, "Enable LED blink on activity");
 
index e955bb9d98cbe0380ef5d070005b373c1a132b8d..0b7d1253f0c0de6fbddb6eeba3b0c23af7831b08 100644 (file)
@@ -711,7 +711,8 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds,
                        rs->rs_phyerr = phyerr;
                } else if (ads.ds_rxstatus8 & AR_DecryptCRCErr)
                        rs->rs_status |= ATH9K_RXERR_DECRYPT;
-               else if (ads.ds_rxstatus8 & AR_MichaelErr)
+               else if ((ads.ds_rxstatus8 & AR_MichaelErr) &&
+                        rs->rs_keyix != ATH9K_RXKEYIX_INVALID)
                        rs->rs_status |= ATH9K_RXERR_MIC;
        }
 
index 3caa32316e7b4567c5cbb7372aef8330b8d2a747..1165f909ef04605edc283a50cf48cc58cd611781 100644 (file)
@@ -226,9 +226,10 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
                caldata = &aphy->caldata;
 
        ath_print(common, ATH_DBG_CONFIG,
-                 "(%u MHz) -> (%u MHz), conf_is_ht40: %d\n",
+                 "(%u MHz) -> (%u MHz), conf_is_ht40: %d fastcc: %d\n",
                  sc->sc_ah->curchan->channel,
-                 channel->center_freq, conf_is_ht40(conf));
+                 channel->center_freq, conf_is_ht40(conf),
+                 fastcc);
 
        spin_lock_bh(&sc->sc_resetlock);
 
@@ -395,7 +396,12 @@ void ath_ani_calibrate(unsigned long data)
        bool shortcal = false;
        bool aniflag = false;
        unsigned int timestamp = jiffies_to_msecs(jiffies);
-       u32 cal_interval, short_cal_interval;
+       u32 cal_interval, short_cal_interval, long_cal_interval;
+
+       if (ah->caldata && ah->caldata->nfcal_interference)
+               long_cal_interval = ATH_LONG_CALINTERVAL_INT;
+       else
+               long_cal_interval = ATH_LONG_CALINTERVAL;
 
        short_cal_interval = (ah->opmode == NL80211_IFTYPE_AP) ?
                ATH_AP_SHORT_CALINTERVAL : ATH_STA_SHORT_CALINTERVAL;
@@ -407,7 +413,7 @@ void ath_ani_calibrate(unsigned long data)
        ath9k_ps_wakeup(sc);
 
        /* Long calibration runs independently of short calibration. */
-       if ((timestamp - common->ani.longcal_timer) >= ATH_LONG_CALINTERVAL) {
+       if ((timestamp - common->ani.longcal_timer) >= long_cal_interval) {
                longcal = true;
                ath_print(common, ATH_DBG_ANI, "longcal @%lu\n", jiffies);
                common->ani.longcal_timer = timestamp;
@@ -1776,9 +1782,10 @@ static int ath9k_set_key(struct ieee80211_hw *hw,
                        key->hw_key_idx = ret;
                        /* push IV and Michael MIC generation to stack */
                        key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
-                       if (key->alg == ALG_TKIP)
+                       if (key->cipher == WLAN_CIPHER_SUITE_TKIP)
                                key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
-                       if (sc->sc_ah->sw_mgmt_crypto && key->alg == ALG_CCMP)
+                       if (sc->sc_ah->sw_mgmt_crypto &&
+                           key->cipher == WLAN_CIPHER_SUITE_CCMP)
                                key->flags |= IEEE80211_KEY_FLAG_SW_MGMT;
                        ret = 0;
                }
index a3fc987ebab003bd5fda0545fa581863b71ba806..534a91bcc1d980a28d26ae3ebdef57e2c99566ca 100644 (file)
@@ -870,15 +870,18 @@ static bool ath9k_rx_accept(struct ath_common *common,
                if (rx_stats->rs_status & ATH9K_RXERR_DECRYPT) {
                        *decrypt_error = true;
                } else if (rx_stats->rs_status & ATH9K_RXERR_MIC) {
-                       if (ieee80211_is_ctl(fc))
-                               /*
-                                * Sometimes, we get invalid
-                                * MIC failures on valid control frames.
-                                * Remove these mic errors.
-                                */
-                               rx_stats->rs_status &= ~ATH9K_RXERR_MIC;
-                       else
+                       /*
+                        * The MIC error bit is only valid if the frame
+                        * is not a control frame or fragment, and it was
+                        * decrypted using a valid TKIP key.
+                        */
+                       if (!ieee80211_is_ctl(fc) &&
+                           !ieee80211_has_morefrags(fc) &&
+                           !(le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG) &&
+                           test_bit(rx_stats->rs_keyix, common->tkip_keymap))
                                rxs->flag |= RX_FLAG_MMIC_ERROR;
+                       else
+                               rx_stats->rs_status &= ~ATH9K_RXERR_MIC;
                }
                /*
                 * Reject error frames with the exception of
index 6260faa658a262ebd16017425deb2cdd28aa48ae..45fe9cac797141495ce3c1f0c19cba13e7f55d81 100644 (file)
@@ -85,6 +85,8 @@ static const char *wmi_cmd_to_name(enum wmi_cmd_id wmi_cmd)
                return "WMI_TGT_DETACH_CMDID";
        case WMI_TGT_TXQ_ENABLE_CMDID:
                return "WMI_TGT_TXQ_ENABLE_CMDID";
+       case WMI_AGGR_LIMIT_CMD:
+               return "WMI_AGGR_LIMIT_CMD";
        }
 
        return "Bogus";
index 765db5faa2d3d01291f790680bb87ca76bc8736d..a0bf857625df016920e0957918d127a9532bee5e 100644 (file)
@@ -71,6 +71,7 @@ enum wmi_cmd_id {
        WMI_TX_AGGR_ENABLE_CMDID,
        WMI_TGT_DETACH_CMDID,
        WMI_TGT_TXQ_ENABLE_CMDID,
+       WMI_AGGR_LIMIT_CMD = 0x0026,
 };
 
 enum wmi_event_id {
index 4dda14e3622781babd1d7e296e395ed18bca135c..457f07692ac7d2fcd3d6230c86d7acea4dc1424c 100644 (file)
@@ -1407,22 +1407,6 @@ static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb)
        return htype;
 }
 
-static int get_hw_crypto_keytype(struct sk_buff *skb)
-{
-       struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
-
-       if (tx_info->control.hw_key) {
-               if (tx_info->control.hw_key->alg == ALG_WEP)
-                       return ATH9K_KEY_TYPE_WEP;
-               else if (tx_info->control.hw_key->alg == ALG_TKIP)
-                       return ATH9K_KEY_TYPE_TKIP;
-               else if (tx_info->control.hw_key->alg == ALG_CCMP)
-                       return ATH9K_KEY_TYPE_AES;
-       }
-
-       return ATH9K_KEY_TYPE_CLEAR;
-}
-
 static void assign_aggr_tid_seqno(struct sk_buff *skb,
                                  struct ath_buf *bf)
 {
@@ -1661,7 +1645,7 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf,
                bf->bf_state.bfs_paprd_timestamp = jiffies;
        bf->bf_flags = setup_tx_flags(skb, use_ldpc);
 
-       bf->bf_keytype = get_hw_crypto_keytype(skb);
+       bf->bf_keytype = ath9k_cmn_get_hw_crypto_keytype(skb);
        if (bf->bf_keytype != ATH9K_KEY_TYPE_CLEAR) {
                bf->bf_frmlen += tx_info->control.hw_key->icv_len;
                bf->bf_keyix = tx_info->control.hw_key->hw_key_idx;
index 873bf526e11f7f1ec5507112660bc53953c53436..fd3a020682dc2dee0dbb2339b4ea1b25d36c4303 100644 (file)
@@ -36,6 +36,7 @@
  * @ATH_DBG_PS: power save processing
  * @ATH_DBG_HWTIMER: hardware timer handling
  * @ATH_DBG_BTCOEX: bluetooth coexistance
+ * @ATH_DBG_BSTUCK: stuck beacons
  * @ATH_DBG_ANY: enable all debugging
  *
  * The debug level is used to control the amount and type of debugging output
@@ -60,6 +61,7 @@ enum ATH_DEBUG {
        ATH_DBG_HWTIMER         = 0x00001000,
        ATH_DBG_BTCOEX          = 0x00002000,
        ATH_DBG_WMI             = 0x00004000,
+       ATH_DBG_BSTUCK          = 0x00008000,
        ATH_DBG_ANY             = 0xffffffff
 };
 
index 20631ae2ddd77bb5893ec101912f79152eb28957..a1186525c70d03f33a936ff15dc90a6bda877e1a 100644 (file)
@@ -2280,6 +2280,7 @@ out:
 
 static int b43_upload_microcode(struct b43_wldev *dev)
 {
+       struct wiphy *wiphy = dev->wl->hw->wiphy;
        const size_t hdr_len = sizeof(struct b43_fw_header);
        const __be32 *data;
        unsigned int i, len;
@@ -2405,6 +2406,10 @@ static int b43_upload_microcode(struct b43_wldev *dev)
                }
        }
 
+       snprintf(wiphy->fw_version, sizeof(wiphy->fw_version), "%u.%u",
+                       dev->fw.rev, dev->fw.patch);
+       wiphy->hw_version = dev->dev->id.coreid;
+
        if (b43_is_old_txhdr_format(dev)) {
                /* We're over the deadline, but we keep support for old fw
                 * until it turns out to be in major conflict with something new. */
@@ -3754,17 +3759,17 @@ static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
        }
 
        err = -EINVAL;
-       switch (key->alg) {
-       case ALG_WEP:
-               if (key->keylen == WLAN_KEY_LEN_WEP40)
-                       algorithm = B43_SEC_ALGO_WEP40;
-               else
-                       algorithm = B43_SEC_ALGO_WEP104;
+       switch (key->cipher) {
+       case WLAN_CIPHER_SUITE_WEP40:
+               algorithm = B43_SEC_ALGO_WEP40;
+               break;
+       case WLAN_CIPHER_SUITE_WEP104:
+               algorithm = B43_SEC_ALGO_WEP104;
                break;
-       case ALG_TKIP:
+       case WLAN_CIPHER_SUITE_TKIP:
                algorithm = B43_SEC_ALGO_TKIP;
                break;
-       case ALG_CCMP:
+       case WLAN_CIPHER_SUITE_CCMP:
                algorithm = B43_SEC_ALGO_AES;
                break;
        default:
@@ -4250,6 +4255,10 @@ static void b43_wireless_core_exit(struct b43_wldev *dev)
        B43_WARN_ON(dev && b43_status(dev) > B43_STAT_INITIALIZED);
        if (!dev || b43_status(dev) != B43_STAT_INITIALIZED)
                return;
+
+       /* Unregister HW RNG driver */
+       b43_rng_exit(dev->wl);
+
        b43_set_status(dev, B43_STAT_UNINIT);
 
        /* Stop the microcode PSM. */
@@ -4379,6 +4388,9 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
 
        b43_set_status(dev, B43_STAT_INITIALIZED);
 
+       /* Register HW RNG driver */
+       b43_rng_init(dev->wl);
+
 out:
        return err;
 
@@ -4984,7 +4996,6 @@ static int b43_probe(struct ssb_device *dev, const struct ssb_device_id *id)
                if (err)
                        goto err_one_core_detach;
                b43_leds_register(wl->current_dev);
-               b43_rng_init(wl);
        }
 
       out:
@@ -5020,7 +5031,6 @@ static void b43_remove(struct ssb_device *dev)
        b43_one_core_detach(dev);
 
        if (list_empty(&wl->devlist)) {
-               b43_rng_exit(wl);
                b43_leds_unregister(wl);
                /* Last core on the chip unregistered.
                 * We can destroy common struct b43_wl.
index 5a725703770cb6d9a01236f0121b052f6cd0cc4b..2466c0a52e5d12f548528673f39337b2b1de11eb 100644 (file)
@@ -893,7 +893,7 @@ static void b43_nphy_adjust_lna_gain_table(struct b43_wldev *dev)
 }
 
 /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/WorkaroundsGainCtrl */
-static void b43_nphy_gain_crtl_workarounds(struct b43_wldev *dev)
+static void b43_nphy_gain_ctrl_workarounds(struct b43_wldev *dev)
 {
        struct b43_phy_n *nphy = dev->phy.n;
        u8 i, j;
@@ -1094,11 +1094,12 @@ static void b43_nphy_workarounds(struct b43_wldev *dev)
                b43_nphy_set_rf_sequence(dev, 0, events1, delays1, 7);
                b43_nphy_set_rf_sequence(dev, 1, events2, delays2, 7);
 
-               b43_nphy_gain_crtl_workarounds(dev);
+               b43_nphy_gain_ctrl_workarounds(dev);
 
                if (dev->phy.rev < 2) {
                        if (b43_phy_read(dev, B43_NPHY_RXCTL) & 0x2)
-                               ; /*TODO: b43_mhf(dev, 2, 0x0010, 0x0010, 3);*/
+                               b43_hf_write(dev, b43_hf_read(dev) |
+                                               B43_HF_MLADVW);
                } else if (dev->phy.rev == 2) {
                        b43_phy_write(dev, B43_NPHY_CRSCHECK2, 0);
                        b43_phy_write(dev, B43_NPHY_CRSCHECK3, 0);
@@ -1182,7 +1183,7 @@ static u16 b43_nphy_gen_load_samples(struct b43_wldev *dev, u32 freq, u16 max,
                len = bw << 1;
        }
 
-       samples = kzalloc(len * sizeof(struct b43_c32), GFP_KERNEL);
+       samples = kcalloc(len, sizeof(struct b43_c32), GFP_KERNEL);
        if (!samples) {
                b43err(dev->wl, "allocation for samples generation failed\n");
                return 0;
@@ -3073,6 +3074,57 @@ static int b43_nphy_cal_rx_iq(struct b43_wldev *dev,
                return b43_nphy_rev2_cal_rx_iq(dev, target, type, debug);
 }
 
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/MacPhyClkSet */
+static void b43_nphy_mac_phy_clock_set(struct b43_wldev *dev, bool on)
+{
+       u32 tmslow = ssb_read32(dev->dev, SSB_TMSLOW);
+       if (on)
+               tmslow |= SSB_TMSLOW_PHYCLK;
+       else
+               tmslow &= ~SSB_TMSLOW_PHYCLK;
+       ssb_write32(dev->dev, SSB_TMSLOW, tmslow);
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RxCoreSetState */
+static void b43_nphy_set_rx_core_state(struct b43_wldev *dev, u8 mask)
+{
+       struct b43_phy *phy = &dev->phy;
+       struct b43_phy_n *nphy = phy->n;
+       u16 buf[16];
+
+       nphy->phyrxchain = mask;
+
+       if (0 /* FIXME clk */)
+               return;
+
+       b43_mac_suspend(dev);
+
+       if (nphy->hang_avoid)
+               b43_nphy_stay_in_carrier_search(dev, true);
+
+       b43_phy_maskset(dev, B43_NPHY_RFSEQCA, ~B43_NPHY_RFSEQCA_RXEN,
+                       (mask & 0x3) << B43_NPHY_RFSEQCA_RXEN_SHIFT);
+
+       if ((mask & 0x3) != 0x3) {
+               b43_phy_write(dev, B43_NPHY_HPANT_SWTHRES, 1);
+               if (dev->phy.rev >= 3) {
+                       /* TODO */
+               }
+       } else {
+               b43_phy_write(dev, B43_NPHY_HPANT_SWTHRES, 0x1E);
+               if (dev->phy.rev >= 3) {
+                       /* TODO */
+               }
+       }
+
+       b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX);
+
+       if (nphy->hang_avoid)
+               b43_nphy_stay_in_carrier_search(dev, false);
+
+       b43_mac_enable(dev);
+}
+
 /*
  * Init N-PHY
  * http://bcm-v4.sipsolutions.net/802.11/PHY/Init/N
@@ -3173,7 +3225,7 @@ int b43_phy_initn(struct b43_wldev *dev)
        b43_phy_write(dev, B43_NPHY_BBCFG, tmp & ~B43_NPHY_BBCFG_RSTCCA);
        b43_nphy_bmac_clock_fgc(dev, 0);
 
-       /* TODO N PHY MAC PHY Clock Set with argument 1 */
+       b43_nphy_mac_phy_clock_set(dev, true);
 
        b43_nphy_pa_override(dev, false);
        b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RX2TX);
@@ -3199,7 +3251,7 @@ int b43_phy_initn(struct b43_wldev *dev)
        }
 
        if (nphy->phyrxchain != 3)
-               ;/* TODO N PHY RX Core Set State with phyrxchain as argument */
+               b43_nphy_set_rx_core_state(dev, nphy->phyrxchain);
        if (nphy->mphase_cal_phase_id > 0)
                ;/* TODO PHY Periodic Calibration Multi-Phase Restart */
 
index 1713f5f7a58b0571c57876cdee4ac6b4f4b63019..67f18ecdb3bf5ae366743454484f2ed5a30b4b4b 100644 (file)
@@ -1623,6 +1623,7 @@ error:
 
 static int b43legacy_upload_microcode(struct b43legacy_wldev *dev)
 {
+       struct wiphy *wiphy = dev->wl->hw->wiphy;
        const size_t hdr_len = sizeof(struct b43legacy_fw_header);
        const __be32 *data;
        unsigned int i;
@@ -1732,6 +1733,10 @@ static int b43legacy_upload_microcode(struct b43legacy_wldev *dev)
        dev->fw.rev = fwrev;
        dev->fw.patch = fwpatch;
 
+       snprintf(wiphy->fw_version, sizeof(wiphy->fw_version), "%u.%u",
+                       dev->fw.rev, dev->fw.patch);
+       wiphy->hw_version = dev->dev->id.coreid;
+
        return 0;
 
 error:
index a85e43a8d75823142bdc3b986adf7954e1e65d61..6038633ef361fa824595531c5466969303c08e62 100644 (file)
@@ -1696,7 +1696,7 @@ static int prism2_request_scan(struct net_device *dev)
                hostap_set_word(dev, HFA384X_RID_CNFROAMINGMODE,
                                HFA384X_ROAMING_FIRMWARE);
 
-       return 0;
+       return ret;
 }
 
 #else /* !PRISM2_NO_STATION_MODES */
index 996e9d7d7586b240847526bec92e721ef8a20d9c..61915f371416e490cbf73d89d65595aadc1e6a98 100644 (file)
@@ -1921,9 +1921,9 @@ static int ipw2100_net_init(struct net_device *dev)
 
                bg_band->band = IEEE80211_BAND_2GHZ;
                bg_band->n_channels = geo->bg_channels;
-               bg_band->channels =
-                       kzalloc(geo->bg_channels *
-                               sizeof(struct ieee80211_channel), GFP_KERNEL);
+               bg_band->channels = kcalloc(geo->bg_channels,
+                                           sizeof(struct ieee80211_channel),
+                                           GFP_KERNEL);
                if (!bg_band->channels) {
                        ipw2100_down(priv);
                        return -ENOMEM;
@@ -3056,9 +3056,9 @@ static void ipw2100_tx_send_commands(struct ipw2100_priv *priv)
 
                packet = list_entry(element, struct ipw2100_tx_packet, list);
 
-               IPW_DEBUG_TX("using TBD at virt=%p, phys=%p\n",
+               IPW_DEBUG_TX("using TBD at virt=%p, phys=%04X\n",
                             &txq->drv[txq->next],
-                            (void *)(txq->nic + txq->next *
+                            (u32) (txq->nic + txq->next *
                                      sizeof(struct ipw2100_bd)));
 
                packet->index = txq->next;
index cb2552a6777c1a26573b5684320933486747d20c..0f2508384c751c35422e598f1c561e1db2372d43 100644 (file)
@@ -11467,9 +11467,9 @@ static int ipw_net_init(struct net_device *dev)
 
                bg_band->band = IEEE80211_BAND_2GHZ;
                bg_band->n_channels = geo->bg_channels;
-               bg_band->channels =
-                       kzalloc(geo->bg_channels *
-                               sizeof(struct ieee80211_channel), GFP_KERNEL);
+               bg_band->channels = kcalloc(geo->bg_channels,
+                                           sizeof(struct ieee80211_channel),
+                                           GFP_KERNEL);
                /* translate geo->bg to bg_band.channels */
                for (i = 0; i < geo->bg_channels; i++) {
                        bg_band->channels[i].band = IEEE80211_BAND_2GHZ;
@@ -11502,9 +11502,9 @@ static int ipw_net_init(struct net_device *dev)
 
                a_band->band = IEEE80211_BAND_5GHZ;
                a_band->n_channels = geo->a_channels;
-               a_band->channels =
-                       kzalloc(geo->a_channels *
-                               sizeof(struct ieee80211_channel), GFP_KERNEL);
+               a_band->channels = kcalloc(geo->a_channels,
+                                          sizeof(struct ieee80211_channel),
+                                          GFP_KERNEL);
                /* translate geo->bg to a_band.channels */
                for (i = 0; i < geo->a_channels; i++) {
                        a_band->channels[i].band = IEEE80211_BAND_2GHZ;
index a51e4da1bdfc5d7149074c8adc7555d51fac0250..b82364258dc5e180133985df9a2d1a48a8a2ba95 100644 (file)
@@ -3,6 +3,9 @@ config IWLWIFI
        depends on PCI && MAC80211
        select FW_LOADER
 
+menu "Debugging Options"
+       depends on IWLWIFI
+
 config IWLWIFI_DEBUG
        bool "Enable full debugging output in iwlagn and iwl3945 drivers"
        depends on IWLWIFI
@@ -36,6 +39,12 @@ config IWLWIFI_DEBUGFS
          is a low-impact option that allows getting insight into the
          driver's state at runtime.
 
+config IWLWIFI_DEBUG_EXPERIMENTAL_UCODE
+        bool "Experimental uCode support"
+        depends on IWLWIFI && IWLWIFI_DEBUG
+        ---help---
+         Enable use of experimental ucode for testing and debugging.
+
 config IWLWIFI_DEVICE_TRACING
        bool "iwlwifi device access tracing"
        depends on IWLWIFI
@@ -53,6 +62,7 @@ config IWLWIFI_DEVICE_TRACING
 
          If unsure, say Y so we can help you better when problems
          occur.
+endmenu
 
 config IWLAGN
        tristate "Intel Wireless WiFi Next Gen AGN (iwlagn)"
index 728bb858ba9760cefc0367618cf262d42fb529ee..493163925a4588d1733b08a37ec30c5b045e2267 100644 (file)
@@ -12,6 +12,7 @@ obj-$(CONFIG_IWLAGN)  += iwlagn.o
 iwlagn-objs            := iwl-agn.o iwl-agn-rs.o iwl-agn-led.o iwl-agn-ict.o
 iwlagn-objs            += iwl-agn-ucode.o iwl-agn-hcmd.o iwl-agn-tx.o
 iwlagn-objs            += iwl-agn-lib.o iwl-agn-rx.o iwl-agn-calib.o
+iwlagn-objs            += iwl-agn-tt.o
 iwlagn-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-agn-debugfs.o
 
 iwlagn-$(CONFIG_IWL4965) += iwl-4965.o
index 0b779a41a1426b9153a55f30a59a052a9e66f618..674fb93ae17f0829d02906173326f7b59e98e15c 100644 (file)
@@ -130,7 +130,7 @@ static int iwl1000_hw_set_hw_params(struct iwl_priv *priv)
                        sizeof(struct iwlagn_scd_bc_tbl);
        priv->hw_params.tfd_size = sizeof(struct iwl_tfd);
        priv->hw_params.max_stations = IWLAGN_STATION_COUNT;
-       priv->hw_params.bcast_sta_id = IWLAGN_BROADCAST_ID;
+       priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id = IWLAGN_BROADCAST_ID;
 
        priv->hw_params.max_data_size = IWLAGN_RTC_DATA_SIZE;
        priv->hw_params.max_inst_size = IWLAGN_RTC_INST_SIZE;
@@ -217,7 +217,7 @@ static struct iwl_lib_ops iwl1000_lib = {
                .set_ct_kill = iwl1000_set_ct_threshold,
         },
        .manage_ibss_station = iwlagn_manage_ibss_station,
-       .update_bcast_station = iwl_update_bcast_station,
+       .update_bcast_stations = iwl_update_bcast_stations,
        .debugfs_ops = {
                .rx_stats_read = iwl_ucode_rx_stats_read,
                .tx_stats_read = iwl_ucode_tx_stats_read,
@@ -229,6 +229,11 @@ static struct iwl_lib_ops iwl1000_lib = {
        .check_ack_health = iwl_good_ack_health,
        .txfifo_flush = iwlagn_txfifo_flush,
        .dev_txfifo_flush = iwlagn_dev_txfifo_flush,
+       .tt_ops = {
+               .lower_power_detection = iwl_tt_is_low_power_state,
+               .tt_power_mode = iwl_tt_current_power_mode,
+               .ct_kill_check = iwl_check_for_ct_kill,
+       }
 };
 
 static const struct iwl_ops iwl1000_ops = {
index 7c731a79363252915243fc01350b8077b50bce58..65b5834da28c719b516fb8e55c022ad1beed08e7 100644 (file)
@@ -62,7 +62,7 @@
  *****************************************************************************/
 /*
  * Please use this file (iwl-3945-hw.h) only for hardware-related definitions.
- * Please use iwl-3945-commands.h for uCode API definitions.
+ * Please use iwl-commands.h for uCode API definitions.
  * Please use iwl-3945.h for driver implementation definitions.
  */
 
@@ -226,6 +226,7 @@ struct iwl3945_eeprom {
 
 /* 4 DATA + 1 CMD. There are 2 HCCA queues that are not used. */
 #define IWL39_NUM_QUEUES        5
+#define IWL39_CMD_QUEUE_NUM    4
 
 #define IWL_DEFAULT_TX_RETRY  15
 
index 8e84a08ff9519ae28031853c62cf3941adf0e93e..d707f5bb1a8b88f3678c3bad53032597691206a4 100644 (file)
@@ -343,7 +343,7 @@ void iwl3945_rs_rate_init(struct iwl_priv *priv, struct ieee80211_sta *sta, u8 s
        int i;
 
        IWL_DEBUG_INFO(priv, "enter\n");
-       if (sta_id == priv->hw_params.bcast_sta_id)
+       if (sta_id == priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id)
                goto out;
 
        psta = (struct iwl3945_sta_priv *) sta->drv_priv;
@@ -932,7 +932,7 @@ void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id)
 
        rcu_read_lock();
 
-       sta = ieee80211_find_sta(priv->vif,
+       sta = ieee80211_find_sta(priv->contexts[IWL_RXON_CTX_BSS].vif,
                                 priv->stations[sta_id].sta.sta.addr);
        if (!sta) {
                IWL_DEBUG_RATE(priv, "Unable to find station to initialize rate scaling.\n");
@@ -949,7 +949,8 @@ void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id)
        switch (priv->band) {
        case IEEE80211_BAND_2GHZ:
                /* TODO: this always does G, not a regression */
-               if (priv->active_rxon.flags & RXON_FLG_TGG_PROTECT_MSK) {
+               if (priv->contexts[IWL_RXON_CTX_BSS].active.flags &
+                                               RXON_FLG_TGG_PROTECT_MSK) {
                        rs_sta->tgg = 1;
                        rs_sta->expected_tpt = iwl3945_expected_tpt_g_prot;
                } else
index 8ccfcd08218d894895524c3995fca28f2695aa6c..5d09686c33895c89c7cb8d91124cc6f539cd2c80 100644 (file)
@@ -245,7 +245,7 @@ int iwl3945_rs_next_rate(struct iwl_priv *priv, int rate)
                break;
        case IEEE80211_BAND_2GHZ:
                if (!(priv->_3945.sta_supp_rates & IWL_OFDM_RATES_MASK) &&
-                   iwl_is_associated(priv)) {
+                   iwl_is_associated(priv, IWL_RXON_CTX_BSS)) {
                        if (rate == IWL_RATE_11M_INDEX)
                                next_rate = IWL_RATE_5M_INDEX;
                }
@@ -273,7 +273,7 @@ static void iwl3945_tx_queue_reclaim(struct iwl_priv *priv,
        struct iwl_queue *q = &txq->q;
        struct iwl_tx_info *tx_info;
 
-       BUG_ON(txq_id == IWL_CMD_QUEUE_NUM);
+       BUG_ON(txq_id == IWL39_CMD_QUEUE_NUM);
 
        for (index = iwl_queue_inc_wrap(index, q->n_bd); q->read_ptr != index;
                q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
@@ -285,7 +285,7 @@ static void iwl3945_tx_queue_reclaim(struct iwl_priv *priv,
        }
 
        if (iwl_queue_space(q) > q->low_mark && (txq_id >= 0) &&
-                       (txq_id != IWL_CMD_QUEUE_NUM) &&
+                       (txq_id != IWL39_CMD_QUEUE_NUM) &&
                        priv->mac80211_registered)
                iwl_wake_queue(priv, txq_id);
 }
@@ -760,7 +760,7 @@ void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv,
                data_retry_limit = IWL_DEFAULT_TX_RETRY;
        tx_cmd->data_retry_limit = data_retry_limit;
 
-       if (tx_id >= IWL_CMD_QUEUE_NUM)
+       if (tx_id >= IWL39_CMD_QUEUE_NUM)
                rts_retry_limit = 3;
        else
                rts_retry_limit = 7;
@@ -909,7 +909,7 @@ static int iwl3945_txq_ctx_reset(struct iwl_priv *priv)
 
        /* Tx queue(s) */
        for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
-               slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ?
+               slots_num = (txq_id == IWL39_CMD_QUEUE_NUM) ?
                                TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
                rc = iwl_tx_queue_init(priv, &priv->txq[txq_id], slots_num,
                                       txq_id);
@@ -1072,7 +1072,7 @@ void iwl3945_hw_txq_ctx_free(struct iwl_priv *priv)
        if (priv->txq)
                for (txq_id = 0; txq_id < priv->hw_params.max_txq_num;
                     txq_id++)
-                       if (txq_id == IWL_CMD_QUEUE_NUM)
+                       if (txq_id == IWL39_CMD_QUEUE_NUM)
                                iwl_cmd_queue_free(priv);
                        else
                                iwl_tx_queue_free(priv, txq_id);
@@ -1439,17 +1439,18 @@ static int iwl3945_send_tx_power(struct iwl_priv *priv)
        int rate_idx, i;
        const struct iwl_channel_info *ch_info = NULL;
        struct iwl3945_txpowertable_cmd txpower = {
-               .channel = priv->active_rxon.channel,
+               .channel = priv->contexts[IWL_RXON_CTX_BSS].active.channel,
        };
+       u16 chan;
+
+       chan = le16_to_cpu(priv->contexts[IWL_RXON_CTX_BSS].active.channel);
 
        txpower.band = (priv->band == IEEE80211_BAND_5GHZ) ? 0 : 1;
-       ch_info = iwl_get_channel_info(priv,
-                                      priv->band,
-                                      le16_to_cpu(priv->active_rxon.channel));
+       ch_info = iwl_get_channel_info(priv, priv->band, chan);
        if (!ch_info) {
                IWL_ERR(priv,
                        "Failed to get channel info for channel %d [%d]\n",
-                       le16_to_cpu(priv->active_rxon.channel), priv->band);
+                       chan, priv->band);
                return -EINVAL;
        }
 
@@ -1710,7 +1711,8 @@ int iwl3945_hw_reg_set_txpower(struct iwl_priv *priv, s8 power)
        return 0;
 }
 
-static int iwl3945_send_rxon_assoc(struct iwl_priv *priv)
+static int iwl3945_send_rxon_assoc(struct iwl_priv *priv,
+                                  struct iwl_rxon_context *ctx)
 {
        int rc = 0;
        struct iwl_rx_packet *pkt;
@@ -1721,8 +1723,8 @@ static int iwl3945_send_rxon_assoc(struct iwl_priv *priv)
                .flags = CMD_WANT_SKB,
                .data = &rxon_assoc,
        };
-       const struct iwl_rxon_cmd *rxon1 = &priv->staging_rxon;
-       const struct iwl_rxon_cmd *rxon2 = &priv->active_rxon;
+       const struct iwl_rxon_cmd *rxon1 = &ctx->staging;
+       const struct iwl_rxon_cmd *rxon2 = &ctx->active;
 
        if ((rxon1->flags == rxon2->flags) &&
            (rxon1->filter_flags == rxon2->filter_flags) &&
@@ -1732,10 +1734,10 @@ static int iwl3945_send_rxon_assoc(struct iwl_priv *priv)
                return 0;
        }
 
-       rxon_assoc.flags = priv->staging_rxon.flags;
-       rxon_assoc.filter_flags = priv->staging_rxon.filter_flags;
-       rxon_assoc.ofdm_basic_rates = priv->staging_rxon.ofdm_basic_rates;
-       rxon_assoc.cck_basic_rates = priv->staging_rxon.cck_basic_rates;
+       rxon_assoc.flags = ctx->staging.flags;
+       rxon_assoc.filter_flags = ctx->staging.filter_flags;
+       rxon_assoc.ofdm_basic_rates = ctx->staging.ofdm_basic_rates;
+       rxon_assoc.cck_basic_rates = ctx->staging.cck_basic_rates;
        rxon_assoc.reserved = 0;
 
        rc = iwl_send_cmd_sync(priv, &cmd);
@@ -1761,14 +1763,14 @@ static int iwl3945_send_rxon_assoc(struct iwl_priv *priv)
  * function correctly transitions out of the RXON_ASSOC_MSK state if
  * a HW tune is required based on the RXON structure changes.
  */
-static int iwl3945_commit_rxon(struct iwl_priv *priv)
+static int iwl3945_commit_rxon(struct iwl_priv *priv,
+                              struct iwl_rxon_context *ctx)
 {
        /* cast away the const for active_rxon in this function */
-       struct iwl3945_rxon_cmd *active_rxon = (void *)&priv->active_rxon;
-       struct iwl3945_rxon_cmd *staging_rxon = (void *)&priv->staging_rxon;
+       struct iwl3945_rxon_cmd *active_rxon = (void *)&ctx->active;
+       struct iwl3945_rxon_cmd *staging_rxon = (void *)&ctx->staging;
        int rc = 0;
-       bool new_assoc =
-               !!(priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK);
+       bool new_assoc = !!(staging_rxon->filter_flags & RXON_FILTER_ASSOC_MSK);
 
        if (!iwl_is_alive(priv))
                return -1;
@@ -1781,7 +1783,7 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv)
            ~(RXON_FLG_DIS_DIV_MSK | RXON_FLG_ANT_SEL_MSK);
        staging_rxon->flags |= iwl3945_get_antenna_flags(priv);
 
-       rc = iwl_check_rxon_cmd(priv);
+       rc = iwl_check_rxon_cmd(priv, ctx);
        if (rc) {
                IWL_ERR(priv, "Invalid RXON configuration.  Not committing.\n");
                return -EINVAL;
@@ -1790,8 +1792,9 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv)
        /* If we don't need to send a full RXON, we can use
         * iwl3945_rxon_assoc_cmd which is used to reconfigure filter
         * and other flags for the current radio configuration. */
-       if (!iwl_full_rxon_required(priv)) {
-               rc = iwl_send_rxon_assoc(priv);
+       if (!iwl_full_rxon_required(priv, &priv->contexts[IWL_RXON_CTX_BSS])) {
+               rc = iwl_send_rxon_assoc(priv,
+                                        &priv->contexts[IWL_RXON_CTX_BSS]);
                if (rc) {
                        IWL_ERR(priv, "Error setting RXON_ASSOC "
                                  "configuration (%d).\n", rc);
@@ -1807,7 +1810,7 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv)
         * an RXON_ASSOC and the new config wants the associated mask enabled,
         * we must clear the associated from the active configuration
         * before we apply the new config */
-       if (iwl_is_associated(priv) && new_assoc) {
+       if (iwl_is_associated(priv, IWL_RXON_CTX_BSS) && new_assoc) {
                IWL_DEBUG_INFO(priv, "Toggling associated bit on current RXON\n");
                active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
 
@@ -1819,7 +1822,7 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv)
                active_rxon->reserved5 = 0;
                rc = iwl_send_cmd_pdu(priv, REPLY_RXON,
                                      sizeof(struct iwl3945_rxon_cmd),
-                                     &priv->active_rxon);
+                                     &priv->contexts[IWL_RXON_CTX_BSS].active);
 
                /* If the mask clearing failed then we set
                 * active_rxon back to what it was previously */
@@ -1829,8 +1832,9 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv)
                                  "configuration (%d).\n", rc);
                        return rc;
                }
-               iwl_clear_ucode_stations(priv);
-               iwl_restore_stations(priv);
+               iwl_clear_ucode_stations(priv,
+                                        &priv->contexts[IWL_RXON_CTX_BSS]);
+               iwl_restore_stations(priv, &priv->contexts[IWL_RXON_CTX_BSS]);
        }
 
        IWL_DEBUG_INFO(priv, "Sending RXON\n"
@@ -1848,7 +1852,7 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv)
        staging_rxon->reserved4 = 0;
        staging_rxon->reserved5 = 0;
 
-       iwl_set_rxon_hwcrypto(priv, !iwl3945_mod_params.sw_crypto);
+       iwl_set_rxon_hwcrypto(priv, ctx, !iwl3945_mod_params.sw_crypto);
 
        /* Apply the new configuration */
        rc = iwl_send_cmd_pdu(priv, REPLY_RXON,
@@ -1862,8 +1866,9 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv)
        memcpy(active_rxon, staging_rxon, sizeof(*active_rxon));
 
        if (!new_assoc) {
-               iwl_clear_ucode_stations(priv);
-               iwl_restore_stations(priv);
+               iwl_clear_ucode_stations(priv,
+                                        &priv->contexts[IWL_RXON_CTX_BSS]);
+               iwl_restore_stations(priv, &priv->contexts[IWL_RXON_CTX_BSS]);
        }
 
        /* If we issue a new RXON command which required a tune then we must
@@ -2302,8 +2307,10 @@ static int iwl3945_manage_ibss_station(struct iwl_priv *priv,
        int ret;
 
        if (add) {
-               ret = iwl_add_bssid_station(priv, vif->bss_conf.bssid, false,
-                                           &vif_priv->ibss_bssid_sta_id);
+               ret = iwl_add_bssid_station(
+                               priv, &priv->contexts[IWL_RXON_CTX_BSS],
+                               vif->bss_conf.bssid, false,
+                               &vif_priv->ibss_bssid_sta_id);
                if (ret)
                        return ret;
 
@@ -2366,7 +2373,7 @@ int iwl3945_init_hw_rate_table(struct iwl_priv *priv)
                 * 1M CCK rates */
 
                if (!(priv->_3945.sta_supp_rates & IWL_OFDM_RATES_MASK) &&
-                   iwl_is_associated(priv)) {
+                   iwl_is_associated(priv, IWL_RXON_CTX_BSS)) {
 
                        index = IWL_FIRST_CCK_RATE;
                        for (i = IWL_RATE_6M_INDEX_TABLE;
@@ -2421,7 +2428,9 @@ int iwl3945_hw_set_hw_params(struct iwl_priv *priv)
        priv->hw_params.max_rxq_size = RX_QUEUE_SIZE;
        priv->hw_params.max_rxq_log = RX_QUEUE_SIZE_LOG;
        priv->hw_params.max_stations = IWL3945_STATION_COUNT;
-       priv->hw_params.bcast_sta_id = IWL3945_BROADCAST_ID;
+       priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id = IWL3945_BROADCAST_ID;
+
+       priv->sta_key_max_num = STA_KEY_MAX_NUM;
 
        priv->hw_params.rx_wrt_ptr_reg = FH39_RSCSR_CHNL0_WPTR;
        priv->hw_params.max_beacon_itrvl = IWL39_MAX_UCODE_BEACON_INTERVAL;
@@ -2439,7 +2448,8 @@ unsigned int iwl3945_hw_get_beacon_cmd(struct iwl_priv *priv,
        tx_beacon_cmd = (struct iwl3945_tx_beacon_cmd *)&frame->u;
        memset(tx_beacon_cmd, 0, sizeof(*tx_beacon_cmd));
 
-       tx_beacon_cmd->tx.sta_id = priv->hw_params.bcast_sta_id;
+       tx_beacon_cmd->tx.sta_id =
+               priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id;
        tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
 
        frame_size = iwl3945_fill_beacon_frame(priv,
index d92b729092336523a5c0a2a541bfbd7cb1b4b640..1d6a46d4db594dbf9fe8ae34f4dc702ebb05063f 100644 (file)
@@ -347,7 +347,7 @@ static void iwl4965_chain_noise_reset(struct iwl_priv *priv)
        struct iwl_chain_noise_data *data = &(priv->chain_noise_data);
 
        if ((data->state == IWL_CHAIN_NOISE_ALIVE) &&
-            iwl_is_associated(priv)) {
+           iwl_is_any_associated(priv)) {
                struct iwl_calib_diff_gain_cmd cmd;
 
                /* clear data for chain noise calibration algorithm */
@@ -576,7 +576,7 @@ static int iwl4965_alive_notify(struct iwl_priv *priv)
        /* Activate all Tx DMA/FIFO channels */
        priv->cfg->ops->lib->txq_set_sched(priv, IWL_MASK(0, 6));
 
-       iwl4965_set_wr_ptrs(priv, IWL_CMD_QUEUE_NUM, 0);
+       iwl4965_set_wr_ptrs(priv, IWL_DEFAULT_CMD_QUEUE_NUM, 0);
 
        /* make sure all queue are not stopped */
        memset(&priv->queue_stopped[0], 0, sizeof(priv->queue_stopped));
@@ -587,6 +587,7 @@ static int iwl4965_alive_notify(struct iwl_priv *priv)
        priv->txq_ctx_active_msk = 0;
        /* Map each Tx/cmd queue to its corresponding fifo */
        BUILD_BUG_ON(ARRAY_SIZE(default_queue_to_tx_fifo) != 7);
+
        for (i = 0; i < ARRAY_SIZE(default_queue_to_tx_fifo); i++) {
                int ac = default_queue_to_tx_fifo[i];
 
@@ -656,7 +657,7 @@ static int iwl4965_hw_set_hw_params(struct iwl_priv *priv)
                        sizeof(struct iwl4965_scd_bc_tbl);
        priv->hw_params.tfd_size = sizeof(struct iwl_tfd);
        priv->hw_params.max_stations = IWL4965_STATION_COUNT;
-       priv->hw_params.bcast_sta_id = IWL4965_BROADCAST_ID;
+       priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id = IWL4965_BROADCAST_ID;
        priv->hw_params.max_data_size = IWL49_RTC_DATA_SIZE;
        priv->hw_params.max_inst_size = IWL49_RTC_INST_SIZE;
        priv->hw_params.max_bsm_size = BSM_SRAM_SIZE;
@@ -1374,6 +1375,7 @@ static int iwl4965_send_tx_power(struct iwl_priv *priv)
        u8 band = 0;
        bool is_ht40 = false;
        u8 ctrl_chan_high = 0;
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
 
        if (test_bit(STATUS_SCANNING, &priv->status)) {
                /* If this gets hit a lot, switch it to a BUG() and catch
@@ -1385,17 +1387,16 @@ static int iwl4965_send_tx_power(struct iwl_priv *priv)
 
        band = priv->band == IEEE80211_BAND_2GHZ;
 
-       is_ht40 =  is_ht40_channel(priv->active_rxon.flags);
+       is_ht40 = is_ht40_channel(ctx->active.flags);
 
-       if (is_ht40 &&
-           (priv->active_rxon.flags & RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK))
+       if (is_ht40 && (ctx->active.flags & RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK))
                ctrl_chan_high = 1;
 
        cmd.band = band;
-       cmd.channel = priv->active_rxon.channel;
+       cmd.channel = ctx->active.channel;
 
        ret = iwl4965_fill_txpower_tbl(priv, band,
-                               le16_to_cpu(priv->active_rxon.channel),
+                               le16_to_cpu(ctx->active.channel),
                                is_ht40, ctrl_chan_high, &cmd.tx_power);
        if (ret)
                goto out;
@@ -1406,12 +1407,13 @@ out:
        return ret;
 }
 
-static int iwl4965_send_rxon_assoc(struct iwl_priv *priv)
+static int iwl4965_send_rxon_assoc(struct iwl_priv *priv,
+                                  struct iwl_rxon_context *ctx)
 {
        int ret = 0;
        struct iwl4965_rxon_assoc_cmd rxon_assoc;
-       const struct iwl_rxon_cmd *rxon1 = &priv->staging_rxon;
-       const struct iwl_rxon_cmd *rxon2 = &priv->active_rxon;
+       const struct iwl_rxon_cmd *rxon1 = &ctx->staging;
+       const struct iwl_rxon_cmd *rxon2 = &ctx->active;
 
        if ((rxon1->flags == rxon2->flags) &&
            (rxon1->filter_flags == rxon2->filter_flags) &&
@@ -1426,16 +1428,16 @@ static int iwl4965_send_rxon_assoc(struct iwl_priv *priv)
                return 0;
        }
 
-       rxon_assoc.flags = priv->staging_rxon.flags;
-       rxon_assoc.filter_flags = priv->staging_rxon.filter_flags;
-       rxon_assoc.ofdm_basic_rates = priv->staging_rxon.ofdm_basic_rates;
-       rxon_assoc.cck_basic_rates = priv->staging_rxon.cck_basic_rates;
+       rxon_assoc.flags = ctx->staging.flags;
+       rxon_assoc.filter_flags = ctx->staging.filter_flags;
+       rxon_assoc.ofdm_basic_rates = ctx->staging.ofdm_basic_rates;
+       rxon_assoc.cck_basic_rates = ctx->staging.cck_basic_rates;
        rxon_assoc.reserved = 0;
        rxon_assoc.ofdm_ht_single_stream_basic_rates =
-           priv->staging_rxon.ofdm_ht_single_stream_basic_rates;
+           ctx->staging.ofdm_ht_single_stream_basic_rates;
        rxon_assoc.ofdm_ht_dual_stream_basic_rates =
-           priv->staging_rxon.ofdm_ht_dual_stream_basic_rates;
-       rxon_assoc.rx_chain_select_flags = priv->staging_rxon.rx_chain;
+           ctx->staging.ofdm_ht_dual_stream_basic_rates;
+       rxon_assoc.rx_chain_select_flags = ctx->staging.rx_chain;
 
        ret = iwl_send_cmd_pdu_async(priv, REPLY_RXON_ASSOC,
                                     sizeof(rxon_assoc), &rxon_assoc, NULL);
@@ -1448,6 +1450,7 @@ static int iwl4965_send_rxon_assoc(struct iwl_priv *priv)
 static int iwl4965_hw_channel_switch(struct iwl_priv *priv,
                                     struct ieee80211_channel_switch *ch_switch)
 {
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
        int rc;
        u8 band = 0;
        bool is_ht40 = false;
@@ -1458,22 +1461,22 @@ static int iwl4965_hw_channel_switch(struct iwl_priv *priv,
        u16 ch;
        u32 tsf_low;
        u8 switch_count;
-       u16 beacon_interval = le16_to_cpu(priv->rxon_timing.beacon_interval);
-       struct ieee80211_vif *vif = priv->vif;
+       u16 beacon_interval = le16_to_cpu(ctx->timing.beacon_interval);
+       struct ieee80211_vif *vif = ctx->vif;
        band = priv->band == IEEE80211_BAND_2GHZ;
 
-       is_ht40 = is_ht40_channel(priv->staging_rxon.flags);
+       is_ht40 = is_ht40_channel(ctx->staging.flags);
 
        if (is_ht40 &&
-           (priv->staging_rxon.flags & RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK))
+           (ctx->staging.flags & RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK))
                ctrl_chan_high = 1;
 
        cmd.band = band;
        cmd.expect_beacon = 0;
-       ch = ieee80211_frequency_to_channel(ch_switch->channel->center_freq);
+       ch = ch_switch->channel->hw_value;
        cmd.channel = cpu_to_le16(ch);
-       cmd.rxon_flags = priv->staging_rxon.flags;
-       cmd.rxon_filter_flags = priv->staging_rxon.filter_flags;
+       cmd.rxon_flags = ctx->staging.flags;
+       cmd.rxon_filter_flags = ctx->staging.filter_flags;
        switch_count = ch_switch->count;
        tsf_low = ch_switch->timestamp & 0x0ffffffff;
        /*
@@ -1508,7 +1511,7 @@ static int iwl4965_hw_channel_switch(struct iwl_priv *priv,
                cmd.expect_beacon = is_channel_radar(ch_info);
        else {
                IWL_ERR(priv, "invalid channel switch from %u to %u\n",
-                       priv->active_rxon.channel, ch);
+                       ctx->active.channel, ch);
                return -EFAULT;
        }
 
@@ -2007,7 +2010,7 @@ static u8 iwl_find_station(struct iwl_priv *priv, const u8 *addr)
                start = IWL_STA_ID;
 
        if (is_broadcast_ether_addr(addr))
-               return priv->hw_params.bcast_sta_id;
+               return priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id;
 
        spin_lock_irqsave(&priv->sta_lock, flags);
        for (i = start; i < priv->hw_params.max_stations; i++)
@@ -2280,7 +2283,7 @@ static struct iwl_lib_ops iwl4965_lib = {
                .set_ct_kill = iwl4965_set_ct_threshold,
        },
        .manage_ibss_station = iwlagn_manage_ibss_station,
-       .update_bcast_station = iwl_update_bcast_station,
+       .update_bcast_stations = iwl_update_bcast_stations,
        .debugfs_ops = {
                .rx_stats_read = iwl_ucode_rx_stats_read,
                .tx_stats_read = iwl_ucode_tx_stats_read,
index 146e6431ae950686b266f6d42f38c42b2be06470..3975e45e750065fd76df7417a441208184e7a1d4 100644 (file)
@@ -62,7 +62,7 @@
  *****************************************************************************/
 /*
  * Please use this file (iwl-5000-hw.h) only for hardware-related definitions.
- * Use iwl-5000-commands.h for uCode API definitions.
+ * Use iwl-commands.h for uCode API definitions.
  */
 
 #ifndef __iwl_5000_hw_h__
index 48bdcd8d2e94c3355c877a55d8e7815249350fdc..1dbb1246c083e98ed54f8d5f016794f74b5ee1be 100644 (file)
@@ -180,7 +180,7 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
                        sizeof(struct iwlagn_scd_bc_tbl);
        priv->hw_params.tfd_size = sizeof(struct iwl_tfd);
        priv->hw_params.max_stations = IWLAGN_STATION_COUNT;
-       priv->hw_params.bcast_sta_id = IWLAGN_BROADCAST_ID;
+       priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id = IWLAGN_BROADCAST_ID;
 
        priv->hw_params.max_data_size = IWLAGN_RTC_DATA_SIZE;
        priv->hw_params.max_inst_size = IWLAGN_RTC_INST_SIZE;
@@ -227,7 +227,7 @@ static int iwl5150_hw_set_hw_params(struct iwl_priv *priv)
                        sizeof(struct iwlagn_scd_bc_tbl);
        priv->hw_params.tfd_size = sizeof(struct iwl_tfd);
        priv->hw_params.max_stations = IWLAGN_STATION_COUNT;
-       priv->hw_params.bcast_sta_id = IWLAGN_BROADCAST_ID;
+       priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id = IWLAGN_BROADCAST_ID;
 
        priv->hw_params.max_data_size = IWLAGN_RTC_DATA_SIZE;
        priv->hw_params.max_inst_size = IWLAGN_RTC_INST_SIZE;
@@ -275,14 +275,19 @@ static void iwl5150_temperature(struct iwl_priv *priv)
 static int iwl5000_hw_channel_switch(struct iwl_priv *priv,
                                     struct ieee80211_channel_switch *ch_switch)
 {
+       /*
+        * MULTI-FIXME
+        * See iwl_mac_channel_switch.
+        */
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
        struct iwl5000_channel_switch_cmd cmd;
        const struct iwl_channel_info *ch_info;
        u32 switch_time_in_usec, ucode_switch_time;
        u16 ch;
        u32 tsf_low;
        u8 switch_count;
-       u16 beacon_interval = le16_to_cpu(priv->rxon_timing.beacon_interval);
-       struct ieee80211_vif *vif = priv->vif;
+       u16 beacon_interval = le16_to_cpu(ctx->timing.beacon_interval);
+       struct ieee80211_vif *vif = ctx->vif;
        struct iwl_host_cmd hcmd = {
                .id = REPLY_CHANNEL_SWITCH,
                .len = sizeof(cmd),
@@ -291,12 +296,12 @@ static int iwl5000_hw_channel_switch(struct iwl_priv *priv,
        };
 
        cmd.band = priv->band == IEEE80211_BAND_2GHZ;
-       ch = ieee80211_frequency_to_channel(ch_switch->channel->center_freq);
+       ch = ch_switch->channel->hw_value;
        IWL_DEBUG_11H(priv, "channel switch from %d to %d\n",
-               priv->active_rxon.channel, ch);
+                     ctx->active.channel, ch);
        cmd.channel = cpu_to_le16(ch);
-       cmd.rxon_flags = priv->staging_rxon.flags;
-       cmd.rxon_filter_flags = priv->staging_rxon.filter_flags;
+       cmd.rxon_flags = ctx->staging.flags;
+       cmd.rxon_filter_flags = ctx->staging.filter_flags;
        switch_count = ch_switch->count;
        tsf_low = ch_switch->timestamp & 0x0ffffffff;
        /*
@@ -331,7 +336,7 @@ static int iwl5000_hw_channel_switch(struct iwl_priv *priv,
                cmd.expect_beacon = is_channel_radar(ch_info);
        else {
                IWL_ERR(priv, "invalid channel switch from %u to %u\n",
-                       priv->active_rxon.channel, ch);
+                       ctx->active.channel, ch);
                return -EFAULT;
        }
        priv->switch_rxon.channel = cmd.channel;
@@ -393,7 +398,7 @@ static struct iwl_lib_ops iwl5000_lib = {
                .set_ct_kill = iwl5000_set_ct_threshold,
         },
        .manage_ibss_station = iwlagn_manage_ibss_station,
-       .update_bcast_station = iwl_update_bcast_station,
+       .update_bcast_stations = iwl_update_bcast_stations,
        .debugfs_ops = {
                .rx_stats_read = iwl_ucode_rx_stats_read,
                .tx_stats_read = iwl_ucode_tx_stats_read,
@@ -405,6 +410,11 @@ static struct iwl_lib_ops iwl5000_lib = {
        .check_ack_health = iwl_good_ack_health,
        .txfifo_flush = iwlagn_txfifo_flush,
        .dev_txfifo_flush = iwlagn_dev_txfifo_flush,
+       .tt_ops = {
+               .lower_power_detection = iwl_tt_is_low_power_state,
+               .tt_power_mode = iwl_tt_current_power_mode,
+               .ct_kill_check = iwl_check_for_ct_kill,
+       }
 };
 
 static struct iwl_lib_ops iwl5150_lib = {
@@ -459,7 +469,7 @@ static struct iwl_lib_ops iwl5150_lib = {
                .set_ct_kill = iwl5150_set_ct_threshold,
         },
        .manage_ibss_station = iwlagn_manage_ibss_station,
-       .update_bcast_station = iwl_update_bcast_station,
+       .update_bcast_stations = iwl_update_bcast_stations,
        .debugfs_ops = {
                .rx_stats_read = iwl_ucode_rx_stats_read,
                .tx_stats_read = iwl_ucode_tx_stats_read,
@@ -470,6 +480,11 @@ static struct iwl_lib_ops iwl5150_lib = {
        .check_ack_health = iwl_good_ack_health,
        .txfifo_flush = iwlagn_txfifo_flush,
        .dev_txfifo_flush = iwlagn_dev_txfifo_flush,
+       .tt_ops = {
+               .lower_power_detection = iwl_tt_is_low_power_state,
+               .tt_power_mode = iwl_tt_current_power_mode,
+               .ct_kill_check = iwl_check_for_ct_kill,
+       }
 };
 
 static const struct iwl_ops iwl5000_ops = {
index ddba39999997a05027b78b4b44f95ed302eba422..47891e16a75805f3d8c40ba98ae01099a58d0e27 100644 (file)
@@ -62,7 +62,7 @@
  *****************************************************************************/
 /*
  * Please use this file (iwl-6000-hw.h) only for hardware-related definitions.
- * Use iwl-5000-commands.h for uCode API definitions.
+ * Use iwl-commands.h for uCode API definitions.
  */
 
 #ifndef __iwl_6000_hw_h__
index cee06b968de807a642adb4db4e08e62cfe2237ab..2fdba088bd276d5c3ef5fb7f31b6944a0be4e911 100644 (file)
@@ -52,7 +52,7 @@
 /* Highest firmware API version supported */
 #define IWL6000_UCODE_API_MAX 4
 #define IWL6050_UCODE_API_MAX 4
-#define IWL6000G2_UCODE_API_MAX 4
+#define IWL6000G2_UCODE_API_MAX 5
 
 /* Lowest firmware API version supported */
 #define IWL6000_UCODE_API_MIN 4
@@ -161,7 +161,7 @@ static int iwl6000_hw_set_hw_params(struct iwl_priv *priv)
                        sizeof(struct iwlagn_scd_bc_tbl);
        priv->hw_params.tfd_size = sizeof(struct iwl_tfd);
        priv->hw_params.max_stations = IWLAGN_STATION_COUNT;
-       priv->hw_params.bcast_sta_id = IWLAGN_BROADCAST_ID;
+       priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id = IWLAGN_BROADCAST_ID;
 
        priv->hw_params.max_data_size = IWL60_RTC_DATA_SIZE;
        priv->hw_params.max_inst_size = IWL60_RTC_INST_SIZE;
@@ -198,14 +198,19 @@ static int iwl6000_hw_set_hw_params(struct iwl_priv *priv)
 static int iwl6000_hw_channel_switch(struct iwl_priv *priv,
                                     struct ieee80211_channel_switch *ch_switch)
 {
+       /*
+        * MULTI-FIXME
+        * See iwl_mac_channel_switch.
+        */
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
        struct iwl6000_channel_switch_cmd cmd;
        const struct iwl_channel_info *ch_info;
        u32 switch_time_in_usec, ucode_switch_time;
        u16 ch;
        u32 tsf_low;
        u8 switch_count;
-       u16 beacon_interval = le16_to_cpu(priv->rxon_timing.beacon_interval);
-       struct ieee80211_vif *vif = priv->vif;
+       u16 beacon_interval = le16_to_cpu(ctx->timing.beacon_interval);
+       struct ieee80211_vif *vif = ctx->vif;
        struct iwl_host_cmd hcmd = {
                .id = REPLY_CHANNEL_SWITCH,
                .len = sizeof(cmd),
@@ -214,12 +219,12 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv,
        };
 
        cmd.band = priv->band == IEEE80211_BAND_2GHZ;
-       ch = ieee80211_frequency_to_channel(ch_switch->channel->center_freq);
+       ch = ch_switch->channel->hw_value;
        IWL_DEBUG_11H(priv, "channel switch from %u to %u\n",
-                     priv->active_rxon.channel, ch);
+                     ctx->active.channel, ch);
        cmd.channel = cpu_to_le16(ch);
-       cmd.rxon_flags = priv->staging_rxon.flags;
-       cmd.rxon_filter_flags = priv->staging_rxon.filter_flags;
+       cmd.rxon_flags = ctx->staging.flags;
+       cmd.rxon_filter_flags = ctx->staging.filter_flags;
        switch_count = ch_switch->count;
        tsf_low = ch_switch->timestamp & 0x0ffffffff;
        /*
@@ -254,7 +259,7 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv,
                cmd.expect_beacon = is_channel_radar(ch_info);
        else {
                IWL_ERR(priv, "invalid channel switch from %u to %u\n",
-                       priv->active_rxon.channel, ch);
+                       ctx->active.channel, ch);
                return -EFAULT;
        }
        priv->switch_rxon.channel = cmd.channel;
@@ -318,7 +323,7 @@ static struct iwl_lib_ops iwl6000_lib = {
                .set_calib_version = iwl6000_set_calib_version,
         },
        .manage_ibss_station = iwlagn_manage_ibss_station,
-       .update_bcast_station = iwl_update_bcast_station,
+       .update_bcast_stations = iwl_update_bcast_stations,
        .debugfs_ops = {
                .rx_stats_read = iwl_ucode_rx_stats_read,
                .tx_stats_read = iwl_ucode_tx_stats_read,
@@ -330,6 +335,86 @@ static struct iwl_lib_ops iwl6000_lib = {
        .check_ack_health = iwl_good_ack_health,
        .txfifo_flush = iwlagn_txfifo_flush,
        .dev_txfifo_flush = iwlagn_dev_txfifo_flush,
+       .tt_ops = {
+               .lower_power_detection = iwl_tt_is_low_power_state,
+               .tt_power_mode = iwl_tt_current_power_mode,
+               .ct_kill_check = iwl_check_for_ct_kill,
+       }
+};
+
+static struct iwl_lib_ops iwl6000g2b_lib = {
+       .set_hw_params = iwl6000_hw_set_hw_params,
+       .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl,
+       .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl,
+       .txq_set_sched = iwlagn_txq_set_sched,
+       .txq_agg_enable = iwlagn_txq_agg_enable,
+       .txq_agg_disable = iwlagn_txq_agg_disable,
+       .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd,
+       .txq_free_tfd = iwl_hw_txq_free_tfd,
+       .txq_init = iwl_hw_tx_queue_init,
+       .rx_handler_setup = iwlagn_bt_rx_handler_setup,
+       .setup_deferred_work = iwlagn_bt_setup_deferred_work,
+       .cancel_deferred_work = iwlagn_bt_cancel_deferred_work,
+       .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr,
+       .load_ucode = iwlagn_load_ucode,
+       .dump_nic_event_log = iwl_dump_nic_event_log,
+       .dump_nic_error_log = iwl_dump_nic_error_log,
+       .dump_csr = iwl_dump_csr,
+       .dump_fh = iwl_dump_fh,
+       .init_alive_start = iwlagn_init_alive_start,
+       .alive_notify = iwlagn_alive_notify,
+       .send_tx_power = iwlagn_send_tx_power,
+       .update_chain_flags = iwl_update_chain_flags,
+       .set_channel_switch = iwl6000_hw_channel_switch,
+       .apm_ops = {
+               .init = iwl_apm_init,
+               .stop = iwl_apm_stop,
+               .config = iwl6000_nic_config,
+               .set_pwr_src = iwl_set_pwr_src,
+       },
+       .eeprom_ops = {
+               .regulatory_bands = {
+                       EEPROM_REG_BAND_1_CHANNELS,
+                       EEPROM_REG_BAND_2_CHANNELS,
+                       EEPROM_REG_BAND_3_CHANNELS,
+                       EEPROM_REG_BAND_4_CHANNELS,
+                       EEPROM_REG_BAND_5_CHANNELS,
+                       EEPROM_6000_REG_BAND_24_HT40_CHANNELS,
+                       EEPROM_REG_BAND_52_HT40_CHANNELS
+               },
+               .verify_signature  = iwlcore_eeprom_verify_signature,
+               .acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
+               .release_semaphore = iwlcore_eeprom_release_semaphore,
+               .calib_version  = iwlagn_eeprom_calib_version,
+               .query_addr = iwlagn_eeprom_query_addr,
+               .update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower,
+       },
+       .post_associate = iwl_post_associate,
+       .isr = iwl_isr_ict,
+       .config_ap = iwl_config_ap,
+       .temp_ops = {
+               .temperature = iwlagn_temperature,
+               .set_ct_kill = iwl6000_set_ct_threshold,
+               .set_calib_version = iwl6000_set_calib_version,
+        },
+       .manage_ibss_station = iwlagn_manage_ibss_station,
+       .update_bcast_stations = iwl_update_bcast_stations,
+       .debugfs_ops = {
+               .rx_stats_read = iwl_ucode_rx_stats_read,
+               .tx_stats_read = iwl_ucode_tx_stats_read,
+               .general_stats_read = iwl_ucode_general_stats_read,
+               .bt_stats_read = iwl_ucode_bt_stats_read,
+       },
+       .recover_from_tx_stall = iwl_bg_monitor_recover,
+       .check_plcp_health = iwl_good_plcp_health,
+       .check_ack_health = iwl_good_ack_health,
+       .txfifo_flush = iwlagn_txfifo_flush,
+       .dev_txfifo_flush = iwlagn_dev_txfifo_flush,
+       .tt_ops = {
+               .lower_power_detection = iwl_tt_is_low_power_state,
+               .tt_power_mode = iwl_tt_current_power_mode,
+               .ct_kill_check = iwl_check_for_ct_kill,
+       }
 };
 
 static const struct iwl_ops iwl6000_ops = {
@@ -339,21 +424,9 @@ static const struct iwl_ops iwl6000_ops = {
        .led = &iwlagn_led_ops,
 };
 
-static void do_not_send_bt_config(struct iwl_priv *priv)
-{
-}
-
-static struct iwl_hcmd_ops iwl6000g2b_hcmd = {
-       .rxon_assoc = iwlagn_send_rxon_assoc,
-       .commit_rxon = iwl_commit_rxon,
-       .set_rxon_chain = iwl_set_rxon_chain,
-       .set_tx_ant = iwlagn_send_tx_ant_config,
-       .send_bt_config = do_not_send_bt_config,
-};
-
 static const struct iwl_ops iwl6000g2b_ops = {
-       .lib = &iwl6000_lib,
-       .hcmd = &iwl6000g2b_hcmd,
+       .lib = &iwl6000g2b_lib,
+       .hcmd = &iwlagn_bt_hcmd,
        .utils = &iwlagn_hcmd_utils,
        .led = &iwlagn_led_ops,
 };
@@ -494,7 +567,7 @@ struct iwl_cfg iwl6000g2b_2agn_cfg = {
        .supports_idle = true,
        .adv_thermal_throttle = true,
        .support_ct_kill_exit = true,
-       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE,
        .chain_noise_scale = 1000,
        .monitor_recover_period = IWL_LONG_MONITORING_PERIOD,
        .max_event_log_size = 512,
@@ -502,6 +575,11 @@ struct iwl_cfg iwl6000g2b_2agn_cfg = {
        .chain_noise_calib_by_driver = true,
        .need_dc_calib = true,
        .bt_statistics = true,
+       /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */
+       .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A,
+       .advanced_bt_coexist = true,
+       .bt_init_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_NONE,
+       .bt_prio_boost = IWLAGN_BT_PRIO_BOOST_DEFAULT,
 };
 
 struct iwl_cfg iwl6000g2b_2abg_cfg = {
@@ -530,7 +608,7 @@ struct iwl_cfg iwl6000g2b_2abg_cfg = {
        .supports_idle = true,
        .adv_thermal_throttle = true,
        .support_ct_kill_exit = true,
-       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE,
        .chain_noise_scale = 1000,
        .monitor_recover_period = IWL_LONG_MONITORING_PERIOD,
        .max_event_log_size = 512,
@@ -538,6 +616,11 @@ struct iwl_cfg iwl6000g2b_2abg_cfg = {
        .chain_noise_calib_by_driver = true,
        .need_dc_calib = true,
        .bt_statistics = true,
+       /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */
+       .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A,
+       .advanced_bt_coexist = true,
+       .bt_init_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_NONE,
+       .bt_prio_boost = IWLAGN_BT_PRIO_BOOST_DEFAULT,
 };
 
 struct iwl_cfg iwl6000g2b_2bgn_cfg = {
@@ -568,7 +651,7 @@ struct iwl_cfg iwl6000g2b_2bgn_cfg = {
        .supports_idle = true,
        .adv_thermal_throttle = true,
        .support_ct_kill_exit = true,
-       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE,
        .chain_noise_scale = 1000,
        .monitor_recover_period = IWL_LONG_MONITORING_PERIOD,
        .max_event_log_size = 512,
@@ -576,6 +659,11 @@ struct iwl_cfg iwl6000g2b_2bgn_cfg = {
        .chain_noise_calib_by_driver = true,
        .need_dc_calib = true,
        .bt_statistics = true,
+       /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */
+       .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A,
+       .advanced_bt_coexist = true,
+       .bt_init_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_NONE,
+       .bt_prio_boost = IWLAGN_BT_PRIO_BOOST_DEFAULT,
 };
 
 struct iwl_cfg iwl6000g2b_2bg_cfg = {
@@ -604,7 +692,7 @@ struct iwl_cfg iwl6000g2b_2bg_cfg = {
        .supports_idle = true,
        .adv_thermal_throttle = true,
        .support_ct_kill_exit = true,
-       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE,
        .chain_noise_scale = 1000,
        .monitor_recover_period = IWL_LONG_MONITORING_PERIOD,
        .max_event_log_size = 512,
@@ -612,6 +700,11 @@ struct iwl_cfg iwl6000g2b_2bg_cfg = {
        .chain_noise_calib_by_driver = true,
        .need_dc_calib = true,
        .bt_statistics = true,
+       /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */
+       .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A,
+       .advanced_bt_coexist = true,
+       .bt_init_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_NONE,
+       .bt_prio_boost = IWLAGN_BT_PRIO_BOOST_DEFAULT,
 };
 
 struct iwl_cfg iwl6000g2b_bgn_cfg = {
@@ -642,7 +735,7 @@ struct iwl_cfg iwl6000g2b_bgn_cfg = {
        .supports_idle = true,
        .adv_thermal_throttle = true,
        .support_ct_kill_exit = true,
-       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE,
        .chain_noise_scale = 1000,
        .monitor_recover_period = IWL_LONG_MONITORING_PERIOD,
        .max_event_log_size = 512,
@@ -650,6 +743,11 @@ struct iwl_cfg iwl6000g2b_bgn_cfg = {
        .chain_noise_calib_by_driver = true,
        .need_dc_calib = true,
        .bt_statistics = true,
+       /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */
+       .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A,
+       .advanced_bt_coexist = true,
+       .bt_init_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_NONE,
+       .bt_prio_boost = IWLAGN_BT_PRIO_BOOST_DEFAULT,
 };
 
 struct iwl_cfg iwl6000g2b_bg_cfg = {
@@ -678,7 +776,7 @@ struct iwl_cfg iwl6000g2b_bg_cfg = {
        .supports_idle = true,
        .adv_thermal_throttle = true,
        .support_ct_kill_exit = true,
-       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE,
        .chain_noise_scale = 1000,
        .monitor_recover_period = IWL_LONG_MONITORING_PERIOD,
        .max_event_log_size = 512,
@@ -686,6 +784,11 @@ struct iwl_cfg iwl6000g2b_bg_cfg = {
        .chain_noise_calib_by_driver = true,
        .need_dc_calib = true,
        .bt_statistics = true,
+       /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */
+       .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A,
+       .advanced_bt_coexist = true,
+       .bt_init_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_NONE,
+       .bt_prio_boost = IWLAGN_BT_PRIO_BOOST_DEFAULT,
 };
 
 /*
index c4c5691032a601a0dcc34e9d7f44fa8f81f1eab2..84ad62958535ed455ac4d32e2b5501efb9e5d6da 100644 (file)
@@ -625,7 +625,7 @@ void iwl_sensitivity_calibration(struct iwl_priv *priv, void *resp)
 
        data = &(priv->sensitivity_data);
 
-       if (!iwl_is_associated(priv)) {
+       if (!iwl_is_any_associated(priv)) {
                IWL_DEBUG_CALIB(priv, "<< - not associated\n");
                return;
        }
@@ -763,6 +763,12 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp)
        unsigned long flags;
        struct statistics_rx_non_phy *rx_info;
        u8 first_chain;
+       /*
+        * MULTI-FIXME:
+        * When we support multiple interfaces on different channels,
+        * this must be modified/fixed.
+        */
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
 
        if (priv->disable_chain_noise_cal)
                return;
@@ -793,8 +799,8 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp)
                return;
        }
 
-       rxon_band24 = !!(priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK);
-       rxon_chnum = le16_to_cpu(priv->staging_rxon.channel);
+       rxon_band24 = !!(ctx->staging.flags & RXON_FLG_BAND_24G_MSK);
+       rxon_chnum = le16_to_cpu(ctx->staging.channel);
        if (priv->cfg->bt_statistics) {
                stat_band24 = !!(((struct iwl_bt_notif_statistics *)
                                 stat_resp)->flag &
@@ -914,7 +920,11 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp)
         * To be safe, simply mask out any chains that we know
         * are not on the device.
         */
-       active_chains &= priv->hw_params.valid_rx_ant;
+       if (priv->cfg->advanced_bt_coexist && priv->bt_full_concurrent) {
+               /* operated as 1x1 in full concurrency mode */
+               active_chains &= first_antenna(priv->hw_params.valid_rx_ant);
+       } else
+               active_chains &= priv->hw_params.valid_rx_ant;
 
        num_tx_chains = 0;
        for (i = 0; i < NUM_RX_CHAINS; i++) {
index 75b901b3eb1ebff8cb5a7adbbd380db5cd8bc88f..6fb52abafc8d46e305328754564d25827cd8a16a 100644 (file)
 #include "iwl-io.h"
 #include "iwl-agn.h"
 
-int iwlagn_send_rxon_assoc(struct iwl_priv *priv)
+int iwlagn_send_rxon_assoc(struct iwl_priv *priv,
+                          struct iwl_rxon_context *ctx)
 {
        int ret = 0;
        struct iwl5000_rxon_assoc_cmd rxon_assoc;
-       const struct iwl_rxon_cmd *rxon1 = &priv->staging_rxon;
-       const struct iwl_rxon_cmd *rxon2 = &priv->active_rxon;
+       const struct iwl_rxon_cmd *rxon1 = &ctx->staging;
+       const struct iwl_rxon_cmd *rxon2 = &ctx->active;
 
        if ((rxon1->flags == rxon2->flags) &&
            (rxon1->filter_flags == rxon2->filter_flags) &&
@@ -60,23 +61,23 @@ int iwlagn_send_rxon_assoc(struct iwl_priv *priv)
                return 0;
        }
 
-       rxon_assoc.flags = priv->staging_rxon.flags;
-       rxon_assoc.filter_flags = priv->staging_rxon.filter_flags;
-       rxon_assoc.ofdm_basic_rates = priv->staging_rxon.ofdm_basic_rates;
-       rxon_assoc.cck_basic_rates = priv->staging_rxon.cck_basic_rates;
+       rxon_assoc.flags = ctx->staging.flags;
+       rxon_assoc.filter_flags = ctx->staging.filter_flags;
+       rxon_assoc.ofdm_basic_rates = ctx->staging.ofdm_basic_rates;
+       rxon_assoc.cck_basic_rates = ctx->staging.cck_basic_rates;
        rxon_assoc.reserved1 = 0;
        rxon_assoc.reserved2 = 0;
        rxon_assoc.reserved3 = 0;
        rxon_assoc.ofdm_ht_single_stream_basic_rates =
-           priv->staging_rxon.ofdm_ht_single_stream_basic_rates;
+           ctx->staging.ofdm_ht_single_stream_basic_rates;
        rxon_assoc.ofdm_ht_dual_stream_basic_rates =
-           priv->staging_rxon.ofdm_ht_dual_stream_basic_rates;
-       rxon_assoc.rx_chain_select_flags = priv->staging_rxon.rx_chain;
+           ctx->staging.ofdm_ht_dual_stream_basic_rates;
+       rxon_assoc.rx_chain_select_flags = ctx->staging.rx_chain;
        rxon_assoc.ofdm_ht_triple_stream_basic_rates =
-                priv->staging_rxon.ofdm_ht_triple_stream_basic_rates;
-       rxon_assoc.acquisition_data = priv->staging_rxon.acquisition_data;
+                ctx->staging.ofdm_ht_triple_stream_basic_rates;
+       rxon_assoc.acquisition_data = ctx->staging.acquisition_data;
 
-       ret = iwl_send_cmd_pdu_async(priv, REPLY_RXON_ASSOC,
+       ret = iwl_send_cmd_pdu_async(priv, ctx->rxon_assoc_cmd,
                                     sizeof(rxon_assoc), &rxon_assoc, NULL);
        if (ret)
                return ret;
@@ -184,7 +185,7 @@ static void iwlagn_chain_noise_reset(struct iwl_priv *priv)
        int ret;
 
        if ((data->state == IWL_CHAIN_NOISE_ALIVE) &&
-            iwl_is_associated(priv)) {
+           iwl_is_any_associated(priv)) {
                struct iwl_calib_chain_noise_reset_cmd cmd;
 
                /* clear data for chain noise calibration algorithm */
@@ -235,13 +236,13 @@ static int iwlagn_calc_rssi(struct iwl_priv *priv,
        /* data from PHY/DSP regarding signal strength, etc.,
         *   contents are always there, not configurable by host
         */
-       struct iwl5000_non_cfg_phy *ncphy =
-               (struct iwl5000_non_cfg_phy *)rx_resp->non_cfg_phy_buf;
+       struct iwlagn_non_cfg_phy *ncphy =
+               (struct iwlagn_non_cfg_phy *)rx_resp->non_cfg_phy_buf;
        u32 val, rssi_a, rssi_b, rssi_c, max_rssi;
        u8 agc;
 
-       val  = le32_to_cpu(ncphy->non_cfg_phy[IWL50_RX_RES_AGC_IDX]);
-       agc = (val & IWL50_OFDM_AGC_MSK) >> IWL50_OFDM_AGC_BIT_POS;
+       val  = le32_to_cpu(ncphy->non_cfg_phy[IWLAGN_RX_RES_AGC_IDX]);
+       agc = (val & IWLAGN_OFDM_AGC_MSK) >> IWLAGN_OFDM_AGC_BIT_POS;
 
        /* Find max rssi among 3 possible receivers.
         * These values are measured by the digital signal processor (DSP).
@@ -249,11 +250,14 @@ static int iwlagn_calc_rssi(struct iwl_priv *priv,
         *   if the radio's automatic gain control (AGC) is working right.
         * AGC value (see below) will provide the "interesting" info.
         */
-       val = le32_to_cpu(ncphy->non_cfg_phy[IWL50_RX_RES_RSSI_AB_IDX]);
-       rssi_a = (val & IWL50_OFDM_RSSI_A_MSK) >> IWL50_OFDM_RSSI_A_BIT_POS;
-       rssi_b = (val & IWL50_OFDM_RSSI_B_MSK) >> IWL50_OFDM_RSSI_B_BIT_POS;
-       val = le32_to_cpu(ncphy->non_cfg_phy[IWL50_RX_RES_RSSI_C_IDX]);
-       rssi_c = (val & IWL50_OFDM_RSSI_C_MSK) >> IWL50_OFDM_RSSI_C_BIT_POS;
+       val = le32_to_cpu(ncphy->non_cfg_phy[IWLAGN_RX_RES_RSSI_AB_IDX]);
+       rssi_a = (val & IWLAGN_OFDM_RSSI_INBAND_A_BITMSK) >>
+               IWLAGN_OFDM_RSSI_A_BIT_POS;
+       rssi_b = (val & IWLAGN_OFDM_RSSI_INBAND_B_BITMSK) >>
+               IWLAGN_OFDM_RSSI_B_BIT_POS;
+       val = le32_to_cpu(ncphy->non_cfg_phy[IWLAGN_RX_RES_RSSI_C_IDX]);
+       rssi_c = (val & IWLAGN_OFDM_RSSI_INBAND_C_BITMSK) >>
+               IWLAGN_OFDM_RSSI_C_BIT_POS;
 
        max_rssi = max_t(u32, rssi_a, rssi_b);
        max_rssi = max_t(u32, max_rssi, rssi_c);
@@ -266,12 +270,95 @@ static int iwlagn_calc_rssi(struct iwl_priv *priv,
        return max_rssi - agc - IWLAGN_RSSI_OFFSET;
 }
 
+static int iwlagn_set_pan_params(struct iwl_priv *priv)
+{
+       struct iwl_wipan_params_cmd cmd;
+       struct iwl_rxon_context *ctx_bss, *ctx_pan;
+       int slot0 = 300, slot1 = 0;
+       int ret;
+
+       if (priv->valid_contexts == BIT(IWL_RXON_CTX_BSS))
+               return 0;
+
+       BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2);
+
+       lockdep_assert_held(&priv->mutex);
+
+       ctx_bss = &priv->contexts[IWL_RXON_CTX_BSS];
+       ctx_pan = &priv->contexts[IWL_RXON_CTX_PAN];
+
+       memset(&cmd, 0, sizeof(cmd));
+
+       /* only 2 slots are currently allowed */
+       cmd.num_slots = 2;
+
+       cmd.slots[0].type = 0; /* BSS */
+       cmd.slots[1].type = 1; /* PAN */
+
+       if (ctx_bss->vif && ctx_pan->vif) {
+               int bcnint = ctx_pan->vif->bss_conf.beacon_int;
+
+               /* should be set, but seems unused?? */
+               cmd.flags |= cpu_to_le16(IWL_WIPAN_PARAMS_FLG_SLOTTED_MODE);
+
+               if (ctx_pan->vif->type == NL80211_IFTYPE_AP &&
+                   bcnint &&
+                   bcnint != ctx_bss->vif->bss_conf.beacon_int) {
+                       IWL_ERR(priv,
+                               "beacon intervals don't match (%d, %d)\n",
+                               ctx_bss->vif->bss_conf.beacon_int,
+                               ctx_pan->vif->bss_conf.beacon_int);
+               } else
+                       bcnint = max_t(int, bcnint,
+                                      ctx_bss->vif->bss_conf.beacon_int);
+               if (!bcnint)
+                       bcnint = 100;
+               slot0 = bcnint / 2;
+               slot1 = bcnint - slot0;
+
+               if (test_bit(STATUS_SCAN_HW, &priv->status) ||
+                   (!ctx_bss->vif->bss_conf.idle &&
+                    !ctx_bss->vif->bss_conf.assoc)) {
+                       slot0 = bcnint * 3 - 20;
+                       slot1 = 20;
+               } else if (!ctx_pan->vif->bss_conf.idle &&
+                           !ctx_pan->vif->bss_conf.assoc) {
+                       slot1 = bcnint * 3 - 20;
+                       slot0 = 20;
+               }
+       } else if (ctx_pan->vif) {
+               slot0 = 0;
+               slot1 = max_t(int, 1, ctx_pan->vif->bss_conf.dtim_period) *
+                                       ctx_pan->vif->bss_conf.beacon_int;
+               slot1 = max_t(int, 100, slot1);
+       }
+
+       cmd.slots[0].width = cpu_to_le16(slot0);
+       cmd.slots[1].width = cpu_to_le16(slot1);
+
+       ret = iwl_send_cmd_pdu(priv, REPLY_WIPAN_PARAMS, sizeof(cmd), &cmd);
+       if (ret)
+               IWL_ERR(priv, "Error setting PAN parameters (%d)\n", ret);
+
+       return ret;
+}
+
 struct iwl_hcmd_ops iwlagn_hcmd = {
        .rxon_assoc = iwlagn_send_rxon_assoc,
        .commit_rxon = iwl_commit_rxon,
        .set_rxon_chain = iwl_set_rxon_chain,
        .set_tx_ant = iwlagn_send_tx_ant_config,
        .send_bt_config = iwl_send_bt_config,
+       .set_pan_params = iwlagn_set_pan_params,
+};
+
+struct iwl_hcmd_ops iwlagn_bt_hcmd = {
+       .rxon_assoc = iwlagn_send_rxon_assoc,
+       .commit_rxon = iwl_commit_rxon,
+       .set_rxon_chain = iwl_set_rxon_chain,
+       .set_tx_ant = iwlagn_send_tx_ant_config,
+       .send_bt_config = iwlagn_send_advance_bt_config,
+       .set_pan_params = iwlagn_set_pan_params,
 };
 
 struct iwl_hcmd_utils_ops iwlagn_hcmd_utils = {
index 9dd9e64c2b0b1a69f11a6d40a5e0e2cbc84d8b22..a8f2adfd799e790e009192a5bed1594ed602e87c 100644 (file)
@@ -247,7 +247,14 @@ static void iwlagn_rx_reply_tx(struct iwl_priv *priv,
                struct iwl_ht_agg *agg;
 
                agg = &priv->stations[sta_id].tid[tid].agg;
-
+               /*
+                * If the BT kill count is non-zero, we'll get this
+                * notification again.
+                */
+               if (tx_resp->bt_kill_count && tx_resp->frame_count == 1 &&
+                   priv->cfg->advanced_bt_coexist) {
+                       IWL_WARN(priv, "receive reply tx with bt_kill\n");
+               }
                iwlagn_tx_status_reply_tx(priv, agg, tx_resp, txq_id, index);
 
                /* check if BAR is needed */
@@ -1098,7 +1105,7 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv,
                if (chan->band != band)
                        continue;
 
-               channel = ieee80211_frequency_to_channel(chan->center_freq);
+               channel = chan->hw_value;
                scan_ch->channel = cpu_to_le16(channel);
 
                ch_info = iwl_get_channel_info(priv, band, channel);
@@ -1156,6 +1163,7 @@ void iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
        };
        struct iwl_scan_cmd *scan;
        struct ieee80211_conf *conf = NULL;
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
        u32 rate_flags = 0;
        u16 cmd_len;
        u16 rx_chain = 0;
@@ -1168,6 +1176,9 @@ void iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
        u8 active_chains;
        u8 scan_tx_antennas = priv->hw_params.valid_tx_ant;
 
+       if (vif)
+               ctx = iwl_rxon_ctx_from_vif(vif);
+
        conf = ieee80211_get_hw_conf(priv->hw);
 
        cancel_delayed_work(&priv->scan_check);
@@ -1225,7 +1236,7 @@ void iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
        scan->quiet_plcp_th = IWL_PLCP_QUIET_THRESH;
        scan->quiet_time = IWL_ACTIVE_QUIET_TIME;
 
-       if (iwl_is_associated(priv)) {
+       if (iwl_is_any_associated(priv)) {
                u16 interval = 0;
                u32 extra;
                u32 suspend_time = 100;
@@ -1276,13 +1287,15 @@ void iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
                IWL_DEBUG_SCAN(priv, "Start passive scan.\n");
 
        scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK;
-       scan->tx_cmd.sta_id = priv->hw_params.bcast_sta_id;
+       scan->tx_cmd.sta_id = ctx->bcast_sta_id;
        scan->tx_cmd.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
 
        switch (priv->scan_band) {
        case IEEE80211_BAND_2GHZ:
                scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK;
-               chan_mod = le32_to_cpu(priv->active_rxon.flags & RXON_FLG_CHANNEL_MODE_MSK)
+               chan_mod = le32_to_cpu(
+                       priv->contexts[IWL_RXON_CTX_BSS].active.flags &
+                                               RXON_FLG_CHANNEL_MODE_MSK)
                                       >> RXON_FLG_CHANNEL_MODE_POS;
                if (chan_mod == CHANNEL_MODE_PURE_40) {
                        rate = IWL_RATE_6M_PLCP;
@@ -1290,6 +1303,12 @@ void iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
                        rate = IWL_RATE_1M_PLCP;
                        rate_flags = RATE_MCS_CCK_MSK;
                }
+               /*
+                * Internal scans are passive, so we can indiscriminately set
+                * the BT ignore flag on 2.4 GHz since it applies to TX only.
+                */
+               if (priv->cfg->advanced_bt_coexist)
+                       scan->tx_cmd.tx_flags |= TX_CMD_FLG_IGNORE_BT;
                scan->good_CRC_th = IWL_GOOD_CRC_TH_DISABLED;
                break;
        case IEEE80211_BAND_5GHZ:
@@ -1327,6 +1346,12 @@ void iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
        if (priv->cfg->scan_tx_antennas[band])
                scan_tx_antennas = priv->cfg->scan_tx_antennas[band];
 
+       if (priv->cfg->advanced_bt_coexist && priv->bt_full_concurrent) {
+               /* operated as 1x1 in full concurrency mode */
+               scan_tx_antennas =
+                       first_antenna(priv->cfg->scan_tx_antennas[band]);
+       }
+
        priv->scan_tx_ant[band] = iwl_toggle_tx_ant(priv, priv->scan_tx_ant[band],
                                                    scan_tx_antennas);
        rate_flags |= iwl_ant_idx_to_flags(priv->scan_tx_ant[band]);
@@ -1345,6 +1370,11 @@ void iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
 
                rx_ant = first_antenna(active_chains);
        }
+       if (priv->cfg->advanced_bt_coexist && priv->bt_full_concurrent) {
+               /* operated as 1x1 in full concurrency mode */
+               rx_ant = first_antenna(rx_ant);
+       }
+
        /* MIMO is not used here, but value is required */
        rx_chain |= priv->hw_params.valid_rx_ant << RXON_RX_CHAIN_VALID_POS;
        rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS;
@@ -1394,6 +1424,11 @@ void iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
        scan->len = cpu_to_le16(cmd.len);
 
        set_bit(STATUS_SCAN_HW, &priv->status);
+
+       if (priv->cfg->ops->hcmd->set_pan_params &&
+           priv->cfg->ops->hcmd->set_pan_params(priv))
+               goto done;
+
        if (iwl_send_cmd_sync(priv, &cmd))
                goto done;
 
@@ -1420,7 +1455,8 @@ int iwlagn_manage_ibss_station(struct iwl_priv *priv,
        struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
 
        if (add)
-               return iwl_add_bssid_station(priv, vif->bss_conf.bssid, true,
+               return iwl_add_bssid_station(priv, vif_priv->ctx,
+                                            vif->bss_conf.bssid, true,
                                             &vif_priv->ibss_bssid_sta_id);
        return iwl_remove_station(priv, vif_priv->ibss_bssid_sta_id,
                                  vif->bss_conf.bssid);
@@ -1453,7 +1489,7 @@ int iwlagn_wait_tx_queue_empty(struct iwl_priv *priv)
 
        /* waiting for all the tx frames complete might take a while */
        for (cnt = 0; cnt < priv->hw_params.max_txq_num; cnt++) {
-               if (cnt == IWL_CMD_QUEUE_NUM)
+               if (cnt == priv->cmd_queue)
                        continue;
                txq = &priv->txq[cnt];
                q = &txq->q;
@@ -1518,3 +1554,377 @@ done:
        ieee80211_wake_queues(priv->hw);
        mutex_unlock(&priv->mutex);
 }
+
+/*
+ * BT coex
+ */
+/*
+ * Macros to access the lookup table.
+ *
+ * The lookup table has 7 inputs: bt3_prio, bt3_txrx, bt_rf_act, wifi_req,
+* wifi_prio, wifi_txrx and wifi_sh_ant_req.
+ *
+ * It has three outputs: WLAN_ACTIVE, WLAN_KILL and ANT_SWITCH
+ *
+ * The format is that "registers" 8 through 11 contain the WLAN_ACTIVE bits
+ * one after another in 32-bit registers, and "registers" 0 through 7 contain
+ * the WLAN_KILL and ANT_SWITCH bits interleaved (in that order).
+ *
+ * These macros encode that format.
+ */
+#define LUT_VALUE(bt3_prio, bt3_txrx, bt_rf_act, wifi_req, wifi_prio, \
+                 wifi_txrx, wifi_sh_ant_req) \
+       (bt3_prio | (bt3_txrx << 1) | (bt_rf_act << 2) | (wifi_req << 3) | \
+       (wifi_prio << 4) | (wifi_txrx << 5) | (wifi_sh_ant_req << 6))
+
+#define LUT_PTA_WLAN_ACTIVE_OP(lut, op, val) \
+       lut[8 + ((val) >> 5)] op (cpu_to_le32(BIT((val) & 0x1f)))
+#define LUT_TEST_PTA_WLAN_ACTIVE(lut, bt3_prio, bt3_txrx, bt_rf_act, wifi_req, \
+                                wifi_prio, wifi_txrx, wifi_sh_ant_req) \
+       (!!(LUT_PTA_WLAN_ACTIVE_OP(lut, &, LUT_VALUE(bt3_prio, bt3_txrx, \
+                                  bt_rf_act, wifi_req, wifi_prio, wifi_txrx, \
+                                  wifi_sh_ant_req))))
+#define LUT_SET_PTA_WLAN_ACTIVE(lut, bt3_prio, bt3_txrx, bt_rf_act, wifi_req, \
+                               wifi_prio, wifi_txrx, wifi_sh_ant_req) \
+       LUT_PTA_WLAN_ACTIVE_OP(lut, |=, LUT_VALUE(bt3_prio, bt3_txrx, \
+                              bt_rf_act, wifi_req, wifi_prio, wifi_txrx, \
+                              wifi_sh_ant_req))
+#define LUT_CLEAR_PTA_WLAN_ACTIVE(lut, bt3_prio, bt3_txrx, bt_rf_act, \
+                                 wifi_req, wifi_prio, wifi_txrx, \
+                                 wifi_sh_ant_req) \
+       LUT_PTA_WLAN_ACTIVE_OP(lut, &= ~, LUT_VALUE(bt3_prio, bt3_txrx, \
+                              bt_rf_act, wifi_req, wifi_prio, wifi_txrx, \
+                              wifi_sh_ant_req))
+
+#define LUT_WLAN_KILL_OP(lut, op, val) \
+       lut[(val) >> 4] op (cpu_to_le32(BIT(((val) << 1) & 0x1e)))
+#define LUT_TEST_WLAN_KILL(lut, bt3_prio, bt3_txrx, bt_rf_act, wifi_req, \
+                          wifi_prio, wifi_txrx, wifi_sh_ant_req) \
+       (!!(LUT_WLAN_KILL_OP(lut, &, LUT_VALUE(bt3_prio, bt3_txrx, bt_rf_act, \
+                            wifi_req, wifi_prio, wifi_txrx, wifi_sh_ant_req))))
+#define LUT_SET_WLAN_KILL(lut, bt3_prio, bt3_txrx, bt_rf_act, wifi_req, \
+                         wifi_prio, wifi_txrx, wifi_sh_ant_req) \
+       LUT_WLAN_KILL_OP(lut, |=, LUT_VALUE(bt3_prio, bt3_txrx, bt_rf_act, \
+                        wifi_req, wifi_prio, wifi_txrx, wifi_sh_ant_req))
+#define LUT_CLEAR_WLAN_KILL(lut, bt3_prio, bt3_txrx, bt_rf_act, wifi_req, \
+                           wifi_prio, wifi_txrx, wifi_sh_ant_req) \
+       LUT_WLAN_KILL_OP(lut, &= ~, LUT_VALUE(bt3_prio, bt3_txrx, bt_rf_act, \
+                        wifi_req, wifi_prio, wifi_txrx, wifi_sh_ant_req))
+
+#define LUT_ANT_SWITCH_OP(lut, op, val) \
+       lut[(val) >> 4] op (cpu_to_le32(BIT((((val) << 1) & 0x1e) + 1)))
+#define LUT_TEST_ANT_SWITCH(lut, bt3_prio, bt3_txrx, bt_rf_act, wifi_req, \
+                           wifi_prio, wifi_txrx, wifi_sh_ant_req) \
+       (!!(LUT_ANT_SWITCH_OP(lut, &, LUT_VALUE(bt3_prio, bt3_txrx, bt_rf_act, \
+                             wifi_req, wifi_prio, wifi_txrx, \
+                             wifi_sh_ant_req))))
+#define LUT_SET_ANT_SWITCH(lut, bt3_prio, bt3_txrx, bt_rf_act, wifi_req, \
+                          wifi_prio, wifi_txrx, wifi_sh_ant_req) \
+       LUT_ANT_SWITCH_OP(lut, |=, LUT_VALUE(bt3_prio, bt3_txrx, bt_rf_act, \
+                         wifi_req, wifi_prio, wifi_txrx, wifi_sh_ant_req))
+#define LUT_CLEAR_ANT_SWITCH(lut, bt3_prio, bt3_txrx, bt_rf_act, wifi_req, \
+                            wifi_prio, wifi_txrx, wifi_sh_ant_req) \
+       LUT_ANT_SWITCH_OP(lut, &= ~, LUT_VALUE(bt3_prio, bt3_txrx, bt_rf_act, \
+                         wifi_req, wifi_prio, wifi_txrx, wifi_sh_ant_req))
+
+static const __le32 iwlagn_def_3w_lookup[12] = {
+       cpu_to_le32(0xaaaaaaaa),
+       cpu_to_le32(0xaaaaaaaa),
+       cpu_to_le32(0xaeaaaaaa),
+       cpu_to_le32(0xaaaaaaaa),
+       cpu_to_le32(0xcc00ff28),
+       cpu_to_le32(0x0000aaaa),
+       cpu_to_le32(0xcc00aaaa),
+       cpu_to_le32(0x0000aaaa),
+       cpu_to_le32(0xc0004000),
+       cpu_to_le32(0x00004000),
+       cpu_to_le32(0xf0005000),
+       cpu_to_le32(0xf0004000),
+};
+
+static const __le32 iwlagn_concurrent_lookup[12] = {
+       cpu_to_le32(0xaaaaaaaa),
+       cpu_to_le32(0xaaaaaaaa),
+       cpu_to_le32(0xaaaaaaaa),
+       cpu_to_le32(0xaaaaaaaa),
+       cpu_to_le32(0xaaaaaaaa),
+       cpu_to_le32(0xaaaaaaaa),
+       cpu_to_le32(0xaaaaaaaa),
+       cpu_to_le32(0xaaaaaaaa),
+       cpu_to_le32(0x00000000),
+       cpu_to_le32(0x00000000),
+       cpu_to_le32(0x00000000),
+       cpu_to_le32(0x00000000),
+};
+
+void iwlagn_send_advance_bt_config(struct iwl_priv *priv)
+{
+       struct iwlagn_bt_cmd bt_cmd = {
+               .max_kill = IWLAGN_BT_MAX_KILL_DEFAULT,
+               .bt3_timer_t7_value = IWLAGN_BT3_T7_DEFAULT,
+               .bt3_prio_sample_time = IWLAGN_BT3_PRIO_SAMPLE_DEFAULT,
+               .bt3_timer_t2_value = IWLAGN_BT3_T2_DEFAULT,
+       };
+
+       BUILD_BUG_ON(sizeof(iwlagn_def_3w_lookup) !=
+                       sizeof(bt_cmd.bt3_lookup_table));
+
+       bt_cmd.prio_boost = priv->cfg->bt_prio_boost;
+       bt_cmd.kill_ack_mask = priv->kill_ack_mask;
+       bt_cmd.kill_cts_mask = priv->kill_cts_mask;
+       bt_cmd.valid = priv->bt_valid;
+
+       /*
+        * Configure BT coex mode to "no coexistence" when the
+        * user disabled BT coexistence, we have no interface
+        * (might be in monitor mode), or the interface is in
+        * IBSS mode (no proper uCode support for coex then).
+        */
+       if (!bt_coex_active || priv->iw_mode == NL80211_IFTYPE_ADHOC) {
+               bt_cmd.flags = 0;
+       } else {
+               bt_cmd.flags = IWLAGN_BT_FLAG_COEX_MODE_3W <<
+                                       IWLAGN_BT_FLAG_COEX_MODE_SHIFT;
+               if (priv->bt_ch_announce)
+                       bt_cmd.flags |= IWLAGN_BT_FLAG_CHANNEL_INHIBITION;
+               IWL_DEBUG_INFO(priv, "BT coex flag: 0X%x\n", bt_cmd.flags);
+       }
+       if (priv->bt_full_concurrent)
+               memcpy(bt_cmd.bt3_lookup_table, iwlagn_concurrent_lookup,
+                       sizeof(iwlagn_concurrent_lookup));
+       else
+               memcpy(bt_cmd.bt3_lookup_table, iwlagn_def_3w_lookup,
+                       sizeof(iwlagn_def_3w_lookup));
+
+       IWL_DEBUG_INFO(priv, "BT coex %s in %s mode\n",
+                      bt_cmd.flags ? "active" : "disabled",
+                      priv->bt_full_concurrent ?
+                      "full concurrency" : "3-wire");
+
+       if (iwl_send_cmd_pdu(priv, REPLY_BT_CONFIG, sizeof(bt_cmd), &bt_cmd))
+               IWL_ERR(priv, "failed to send BT Coex Config\n");
+
+       /*
+        * When we are doing a restart, need to also reconfigure BT
+        * SCO to the device. If not doing a restart, bt_sco_active
+        * will always be false, so there's no need to have an extra
+        * variable to check for it.
+        */
+       if (priv->bt_sco_active) {
+               struct iwlagn_bt_sco_cmd sco_cmd = { .flags = 0 };
+
+               if (priv->bt_sco_active)
+                       sco_cmd.flags |= IWLAGN_BT_SCO_ACTIVE;
+               if (iwl_send_cmd_pdu(priv, REPLY_BT_COEX_SCO,
+                                    sizeof(sco_cmd), &sco_cmd))
+                       IWL_ERR(priv, "failed to send BT SCO command\n");
+       }
+}
+
+static void iwlagn_bt_traffic_change_work(struct work_struct *work)
+{
+       struct iwl_priv *priv =
+               container_of(work, struct iwl_priv, bt_traffic_change_work);
+       struct iwl_rxon_context *ctx;
+       int smps_request = -1;
+
+       IWL_DEBUG_INFO(priv, "BT traffic load changes: %d\n",
+                      priv->bt_traffic_load);
+
+       switch (priv->bt_traffic_load) {
+       case IWL_BT_COEX_TRAFFIC_LOAD_NONE:
+               smps_request = IEEE80211_SMPS_AUTOMATIC;
+               break;
+       case IWL_BT_COEX_TRAFFIC_LOAD_LOW:
+               smps_request = IEEE80211_SMPS_DYNAMIC;
+               break;
+       case IWL_BT_COEX_TRAFFIC_LOAD_HIGH:
+       case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS:
+               smps_request = IEEE80211_SMPS_STATIC;
+               break;
+       default:
+               IWL_ERR(priv, "Invalid BT traffic load: %d\n",
+                       priv->bt_traffic_load);
+               break;
+       }
+
+       mutex_lock(&priv->mutex);
+
+       if (priv->cfg->ops->lib->update_chain_flags)
+               priv->cfg->ops->lib->update_chain_flags(priv);
+
+       if (smps_request != -1) {
+               for_each_context(priv, ctx) {
+                       if (ctx->vif && ctx->vif->type == NL80211_IFTYPE_STATION)
+                               ieee80211_request_smps(ctx->vif, smps_request);
+               }
+       }
+
+       mutex_unlock(&priv->mutex);
+}
+
+static void iwlagn_print_uartmsg(struct iwl_priv *priv,
+                               struct iwl_bt_uart_msg *uart_msg)
+{
+       IWL_DEBUG_NOTIF(priv, "Message Type = 0x%X, SSN = 0x%X, "
+                       "Update Req = 0x%X",
+               (BT_UART_MSG_FRAME1MSGTYPE_MSK & uart_msg->frame1) >>
+                       BT_UART_MSG_FRAME1MSGTYPE_POS,
+               (BT_UART_MSG_FRAME1SSN_MSK & uart_msg->frame1) >>
+                       BT_UART_MSG_FRAME1SSN_POS,
+               (BT_UART_MSG_FRAME1UPDATEREQ_MSK & uart_msg->frame1) >>
+                       BT_UART_MSG_FRAME1UPDATEREQ_POS);
+
+       IWL_DEBUG_NOTIF(priv, "Open connections = 0x%X, Traffic load = 0x%X, "
+                       "Chl_SeqN = 0x%X, In band = 0x%X",
+               (BT_UART_MSG_FRAME2OPENCONNECTIONS_MSK & uart_msg->frame2) >>
+                       BT_UART_MSG_FRAME2OPENCONNECTIONS_POS,
+               (BT_UART_MSG_FRAME2TRAFFICLOAD_MSK & uart_msg->frame2) >>
+                       BT_UART_MSG_FRAME2TRAFFICLOAD_POS,
+               (BT_UART_MSG_FRAME2CHLSEQN_MSK & uart_msg->frame2) >>
+                       BT_UART_MSG_FRAME2CHLSEQN_POS,
+               (BT_UART_MSG_FRAME2INBAND_MSK & uart_msg->frame2) >>
+                       BT_UART_MSG_FRAME2INBAND_POS);
+
+       IWL_DEBUG_NOTIF(priv, "SCO/eSCO = 0x%X, Sniff = 0x%X, A2DP = 0x%X, "
+                       "ACL = 0x%X, Master = 0x%X, OBEX = 0x%X",
+               (BT_UART_MSG_FRAME3SCOESCO_MSK & uart_msg->frame3) >>
+                       BT_UART_MSG_FRAME3SCOESCO_POS,
+               (BT_UART_MSG_FRAME3SNIFF_MSK & uart_msg->frame3) >>
+                       BT_UART_MSG_FRAME3SNIFF_POS,
+               (BT_UART_MSG_FRAME3A2DP_MSK & uart_msg->frame3) >>
+                       BT_UART_MSG_FRAME3A2DP_POS,
+               (BT_UART_MSG_FRAME3ACL_MSK & uart_msg->frame3) >>
+                       BT_UART_MSG_FRAME3ACL_POS,
+               (BT_UART_MSG_FRAME3MASTER_MSK & uart_msg->frame3) >>
+                       BT_UART_MSG_FRAME3MASTER_POS,
+               (BT_UART_MSG_FRAME3OBEX_MSK & uart_msg->frame3) >>
+                       BT_UART_MSG_FRAME3OBEX_POS);
+
+       IWL_DEBUG_NOTIF(priv, "Idle duration = 0x%X",
+               (BT_UART_MSG_FRAME4IDLEDURATION_MSK & uart_msg->frame4) >>
+                       BT_UART_MSG_FRAME4IDLEDURATION_POS);
+
+       IWL_DEBUG_NOTIF(priv, "Tx Activity = 0x%X, Rx Activity = 0x%X, "
+                       "eSCO Retransmissions = 0x%X",
+               (BT_UART_MSG_FRAME5TXACTIVITY_MSK & uart_msg->frame5) >>
+                       BT_UART_MSG_FRAME5TXACTIVITY_POS,
+               (BT_UART_MSG_FRAME5RXACTIVITY_MSK & uart_msg->frame5) >>
+                       BT_UART_MSG_FRAME5RXACTIVITY_POS,
+               (BT_UART_MSG_FRAME5ESCORETRANSMIT_MSK & uart_msg->frame5) >>
+                       BT_UART_MSG_FRAME5ESCORETRANSMIT_POS);
+
+       IWL_DEBUG_NOTIF(priv, "Sniff Interval = 0x%X, Discoverable = 0x%X",
+               (BT_UART_MSG_FRAME6SNIFFINTERVAL_MSK & uart_msg->frame6) >>
+                       BT_UART_MSG_FRAME6SNIFFINTERVAL_POS,
+               (BT_UART_MSG_FRAME6DISCOVERABLE_MSK & uart_msg->frame6) >>
+                       BT_UART_MSG_FRAME6DISCOVERABLE_POS);
+
+       IWL_DEBUG_NOTIF(priv, "Sniff Activity = 0x%X, Inquiry/Page SR Mode = "
+                       "0x%X, Connectable = 0x%X",
+               (BT_UART_MSG_FRAME7SNIFFACTIVITY_MSK & uart_msg->frame7) >>
+                       BT_UART_MSG_FRAME7SNIFFACTIVITY_POS,
+               (BT_UART_MSG_FRAME7INQUIRYPAGESRMODE_MSK & uart_msg->frame7) >>
+                       BT_UART_MSG_FRAME7INQUIRYPAGESRMODE_POS,
+               (BT_UART_MSG_FRAME7CONNECTABLE_MSK & uart_msg->frame7) >>
+                       BT_UART_MSG_FRAME7CONNECTABLE_POS);
+}
+
+static void iwlagn_set_kill_ack_msk(struct iwl_priv *priv,
+                                    struct iwl_bt_uart_msg *uart_msg)
+{
+       u8 kill_ack_msk;
+       __le32 bt_kill_ack_msg[2] = {
+                       cpu_to_le32(0xFFFFFFF), cpu_to_le32(0xFFFFFC00) };
+
+       kill_ack_msk = (((BT_UART_MSG_FRAME3A2DP_MSK |
+                       BT_UART_MSG_FRAME3SNIFF_MSK |
+                       BT_UART_MSG_FRAME3SCOESCO_MSK) &
+                       uart_msg->frame3) == 0) ? 1 : 0;
+       if (priv->kill_ack_mask != bt_kill_ack_msg[kill_ack_msk]) {
+               priv->bt_valid |= IWLAGN_BT_VALID_KILL_ACK_MASK;
+               priv->kill_ack_mask = bt_kill_ack_msg[kill_ack_msk];
+               /* schedule to send runtime bt_config */
+               queue_work(priv->workqueue, &priv->bt_runtime_config);
+       }
+
+}
+
+void iwlagn_bt_coex_profile_notif(struct iwl_priv *priv,
+                                            struct iwl_rx_mem_buffer *rxb)
+{
+       unsigned long flags;
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
+       struct iwl_bt_coex_profile_notif *coex = &pkt->u.bt_coex_profile_notif;
+       struct iwlagn_bt_sco_cmd sco_cmd = { .flags = 0 };
+       struct iwl_bt_uart_msg *uart_msg = &coex->last_bt_uart_msg;
+       u8 last_traffic_load;
+
+       IWL_DEBUG_NOTIF(priv, "BT Coex notification:\n");
+       IWL_DEBUG_NOTIF(priv, "    status: %d\n", coex->bt_status);
+       IWL_DEBUG_NOTIF(priv, "    traffic load: %d\n", coex->bt_traffic_load);
+       IWL_DEBUG_NOTIF(priv, "    CI compliance: %d\n",
+                       coex->bt_ci_compliance);
+       iwlagn_print_uartmsg(priv, uart_msg);
+
+       last_traffic_load = priv->notif_bt_traffic_load;
+       priv->notif_bt_traffic_load = coex->bt_traffic_load;
+       if (priv->iw_mode != NL80211_IFTYPE_ADHOC) {
+               if (priv->bt_status != coex->bt_status ||
+                   last_traffic_load != coex->bt_traffic_load) {
+                       if (coex->bt_status) {
+                               /* BT on */
+                               if (!priv->bt_ch_announce)
+                                       priv->bt_traffic_load =
+                                               IWL_BT_COEX_TRAFFIC_LOAD_HIGH;
+                               else
+                                       priv->bt_traffic_load =
+                                               coex->bt_traffic_load;
+                       } else {
+                               /* BT off */
+                               priv->bt_traffic_load =
+                                       IWL_BT_COEX_TRAFFIC_LOAD_NONE;
+                       }
+                       priv->bt_status = coex->bt_status;
+                       queue_work(priv->workqueue,
+                                  &priv->bt_traffic_change_work);
+               }
+               if (priv->bt_sco_active !=
+                   (uart_msg->frame3 & BT_UART_MSG_FRAME3SCOESCO_MSK)) {
+                       priv->bt_sco_active = uart_msg->frame3 &
+                               BT_UART_MSG_FRAME3SCOESCO_MSK;
+                       if (priv->bt_sco_active)
+                               sco_cmd.flags |= IWLAGN_BT_SCO_ACTIVE;
+                       iwl_send_cmd_pdu_async(priv, REPLY_BT_COEX_SCO,
+                                      sizeof(sco_cmd), &sco_cmd, NULL);
+               }
+       }
+
+       iwlagn_set_kill_ack_msk(priv, uart_msg);
+
+       /* FIXME: based on notification, adjust the prio_boost */
+
+       spin_lock_irqsave(&priv->lock, flags);
+       priv->bt_ci_compliance = coex->bt_ci_compliance;
+       spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+void iwlagn_bt_rx_handler_setup(struct iwl_priv *priv)
+{
+       iwlagn_rx_handler_setup(priv);
+       priv->rx_handlers[REPLY_BT_COEX_PROFILE_NOTIF] =
+               iwlagn_bt_coex_profile_notif;
+}
+
+void iwlagn_bt_setup_deferred_work(struct iwl_priv *priv)
+{
+       iwlagn_setup_deferred_work(priv);
+
+       INIT_WORK(&priv->bt_traffic_change_work,
+                 iwlagn_bt_traffic_change_work);
+}
+
+void iwlagn_bt_cancel_deferred_work(struct iwl_priv *priv)
+{
+       cancel_work_sync(&priv->bt_traffic_change_work);
+}
index 23e5c42e7d7eb31798aa72f7e995f3537d98a86f..57629fba3a7ddbb17fd013ac7623b283a6d0d57a 100644 (file)
@@ -82,6 +82,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
                                   struct iwl_lq_sta *lq_sta);
 static void rs_fill_link_cmd(struct iwl_priv *priv,
                             struct iwl_lq_sta *lq_sta, u32 rate_n_flags);
+static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search);
 
 
 #ifdef CONFIG_MAC80211_DEBUGFS
@@ -300,7 +301,19 @@ static int rs_tl_turn_on_agg_for_tid(struct iwl_priv *priv,
                                      struct ieee80211_sta *sta)
 {
        int ret = -EAGAIN;
-       u32 load = rs_tl_get_load(lq_data, tid);
+       u32 load;
+
+       /*
+        * Don't create TX aggregation sessions when in high
+        * BT traffic, as they would just be disrupted by BT.
+        */
+       if (priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH) {
+               IWL_ERR(priv, "BT traffic (%d), no aggregation allowed\n",
+                       priv->bt_traffic_load);
+               return ret;
+       }
+
+       load = rs_tl_get_load(lq_data, tid);
 
        if (load > IWL_AGG_LOAD_THRESHOLD) {
                IWL_DEBUG_HT(priv, "Starting Tx agg: STA: %pM tid: %d\n",
@@ -502,6 +515,7 @@ static int rs_get_tbl_info_from_mcs(const u32 rate_n_flags,
        u8 num_of_ant = get_num_of_ant_from_rate(rate_n_flags);
        u8 mcs;
 
+       memset(tbl, 0, sizeof(struct iwl_scale_tbl_info));
        *rate_idx = iwl_hwrate_to_plcp_idx(rate_n_flags);
 
        if (*rate_idx  == IWL_RATE_INVALID) {
@@ -588,11 +602,13 @@ static int rs_toggle_antenna(u32 valid_ant, u32 *rate_n_flags,
  * Green-field mode is valid if the station supports it and
  * there are no non-GF stations present in the BSS.
  */
-static inline u8 rs_use_green(struct ieee80211_sta *sta,
-                             struct iwl_ht_config *ht_conf)
+static bool rs_use_green(struct ieee80211_sta *sta)
 {
+       struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
+       struct iwl_rxon_context *ctx = sta_priv->common.ctx;
+
        return (sta->ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD) &&
-               !(ht_conf->non_GF_STA_present);
+               !(ctx->ht.non_gf_sta_present);
 }
 
 /**
@@ -744,6 +760,32 @@ static bool table_type_matches(struct iwl_scale_tbl_info *a,
                (a->is_SGI == b->is_SGI);
 }
 
+static void rs_bt_update_lq(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
+                           struct iwl_lq_sta *lq_sta)
+{
+       struct iwl_scale_tbl_info *tbl;
+       bool full_concurrent;
+       unsigned long flags;
+
+       spin_lock_irqsave(&priv->lock, flags);
+       if (priv->bt_ci_compliance && priv->bt_ant_couple_ok)
+               full_concurrent = true;
+       else
+               full_concurrent = false;
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       if (priv->bt_full_concurrent != full_concurrent) {
+               priv->bt_full_concurrent = full_concurrent;
+
+               /* Update uCode's rate table. */
+               tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
+               rs_fill_link_cmd(priv, lq_sta, tbl->current_rate);
+               iwl_send_lq_cmd(priv, ctx, &lq_sta->lq, CMD_ASYNC, false);
+
+               queue_work(priv->workqueue, &priv->bt_full_concurrency);
+       }
+}
+
 /*
  * mac80211 sends us Tx status
  */
@@ -763,6 +805,8 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,
        u32 tx_rate;
        struct iwl_scale_tbl_info tbl_type;
        struct iwl_scale_tbl_info *curr_tbl, *other_tbl, *tmp_tbl;
+       struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
+       struct iwl_rxon_context *ctx = sta_priv->common.ctx;
 
        IWL_DEBUG_RATE_LIMIT(priv, "get frame ack response, update rate scale window\n");
 
@@ -829,7 +873,7 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,
                lq_sta->missed_rate_counter++;
                if (lq_sta->missed_rate_counter > IWL_MISSED_RATE_MAX) {
                        lq_sta->missed_rate_counter = 0;
-                       iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC, false);
+                       iwl_send_lq_cmd(priv, ctx, &lq_sta->lq, CMD_ASYNC, false);
                }
                /* Regardless, ignore this status info for outdated rate */
                return;
@@ -848,7 +892,20 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,
                other_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
        } else {
                IWL_DEBUG_RATE(priv, "Neither active nor search matches tx rate\n");
-               return;
+               tmp_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
+               IWL_DEBUG_RATE(priv, "active- lq:%x, ant:%x, SGI:%d\n",
+                       tmp_tbl->lq_type, tmp_tbl->ant_type, tmp_tbl->is_SGI);
+               tmp_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]);
+               IWL_DEBUG_RATE(priv, "search- lq:%x, ant:%x, SGI:%d\n",
+                       tmp_tbl->lq_type, tmp_tbl->ant_type, tmp_tbl->is_SGI);
+               IWL_DEBUG_RATE(priv, "actual- lq:%x, ant:%x, SGI:%d\n",
+                       tbl_type.lq_type, tbl_type.ant_type, tbl_type.is_SGI);
+               /*
+                * no matching table found, let's by-pass the data collection
+                * and continue to perform rate scale to find the rate table
+                */
+               rs_stay_in_table(lq_sta, true);
+               goto done;
        }
 
        /*
@@ -909,10 +966,14 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,
        }
        /* The last TX rate is cached in lq_sta; it's set in if/else above */
        lq_sta->last_rate_n_flags = tx_rate;
-
+done:
        /* See if there's a better rate or modulation mode to try. */
        if (sta && sta->supp_rates[sband->band])
                rs_rate_scale_perform(priv, skb, sta, lq_sta);
+
+       /* Is there a need to switch between full concurrency and 3-wire? */
+       if (priv->bt_ant_couple_ok)
+               rs_bt_update_lq(priv, ctx, lq_sta);
 }
 
 /*
@@ -1106,6 +1167,8 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv,
        u16 rate_mask;
        s32 rate;
        s8 is_green = lq_sta->is_green;
+       struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
+       struct iwl_rxon_context *ctx = sta_priv->common.ctx;
 
        if (!conf_is_ht(conf) || !sta->ht_cap.ht_supported)
                return -1;
@@ -1126,7 +1189,7 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv,
        tbl->max_search = IWL_MAX_SEARCH;
        rate_mask = lq_sta->active_mimo2_rate;
 
-       if (iwl_is_ht40_tx_allowed(priv, &sta->ht_cap))
+       if (iwl_is_ht40_tx_allowed(priv, ctx, &sta->ht_cap))
                tbl->is_ht40 = 1;
        else
                tbl->is_ht40 = 0;
@@ -1160,6 +1223,8 @@ static int rs_switch_to_mimo3(struct iwl_priv *priv,
        u16 rate_mask;
        s32 rate;
        s8 is_green = lq_sta->is_green;
+       struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
+       struct iwl_rxon_context *ctx = sta_priv->common.ctx;
 
        if (!conf_is_ht(conf) || !sta->ht_cap.ht_supported)
                return -1;
@@ -1180,7 +1245,7 @@ static int rs_switch_to_mimo3(struct iwl_priv *priv,
        tbl->max_search = IWL_MAX_11N_MIMO3_SEARCH;
        rate_mask = lq_sta->active_mimo3_rate;
 
-       if (iwl_is_ht40_tx_allowed(priv, &sta->ht_cap))
+       if (iwl_is_ht40_tx_allowed(priv, ctx, &sta->ht_cap))
                tbl->is_ht40 = 1;
        else
                tbl->is_ht40 = 0;
@@ -1215,6 +1280,8 @@ static int rs_switch_to_siso(struct iwl_priv *priv,
        u16 rate_mask;
        u8 is_green = lq_sta->is_green;
        s32 rate;
+       struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
+       struct iwl_rxon_context *ctx = sta_priv->common.ctx;
 
        if (!conf_is_ht(conf) || !sta->ht_cap.ht_supported)
                return -1;
@@ -1227,7 +1294,7 @@ static int rs_switch_to_siso(struct iwl_priv *priv,
        tbl->max_search = IWL_MAX_SEARCH;
        rate_mask = lq_sta->active_siso_rate;
 
-       if (iwl_is_ht40_tx_allowed(priv, &sta->ht_cap))
+       if (iwl_is_ht40_tx_allowed(priv, ctx, &sta->ht_cap))
                tbl->is_ht40 = 1;
        else
                tbl->is_ht40 = 0;
@@ -1265,18 +1332,52 @@ static int rs_move_legacy_other(struct iwl_priv *priv,
        struct iwl_rate_scale_data *window = &(tbl->win[index]);
        u32 sz = (sizeof(struct iwl_scale_tbl_info) -
                  (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
-       u8 start_action = tbl->action;
+       u8 start_action;
        u8 valid_tx_ant = priv->hw_params.valid_tx_ant;
        u8 tx_chains_num = priv->hw_params.tx_chains_num;
        int ret = 0;
        u8 update_search_tbl_counter = 0;
 
+       switch (priv->bt_traffic_load) {
+       case IWL_BT_COEX_TRAFFIC_LOAD_NONE:
+               /* nothing */
+               break;
+       case IWL_BT_COEX_TRAFFIC_LOAD_LOW:
+               /* avoid antenna B unless MIMO */
+               valid_tx_ant = first_antenna(priv->hw_params.valid_tx_ant);
+               if (tbl->action == IWL_LEGACY_SWITCH_ANTENNA2)
+                       tbl->action = IWL_LEGACY_SWITCH_ANTENNA1;
+               break;
+       case IWL_BT_COEX_TRAFFIC_LOAD_HIGH:
+       case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS:
+               /* avoid antenna B and MIMO */
+               valid_tx_ant = first_antenna(priv->hw_params.valid_tx_ant);
+               if (tbl->action >= IWL_LEGACY_SWITCH_ANTENNA2 &&
+                   tbl->action != IWL_LEGACY_SWITCH_SISO)
+                       tbl->action = IWL_LEGACY_SWITCH_SISO;
+               break;
+       default:
+               IWL_ERR(priv, "Invalid BT load %d", priv->bt_traffic_load);
+               break;
+       }
+
        if (!iwl_ht_enabled(priv))
                /* stay in Legacy */
                tbl->action = IWL_LEGACY_SWITCH_ANTENNA1;
        else if (iwl_tx_ant_restriction(priv) == IWL_ANT_OK_SINGLE &&
                   tbl->action > IWL_LEGACY_SWITCH_SISO)
                tbl->action = IWL_LEGACY_SWITCH_SISO;
+
+       /* configure as 1x1 if bt full concurrency */
+       if (priv->bt_full_concurrent) {
+               if (!iwl_ht_enabled(priv))
+                       tbl->action = IWL_LEGACY_SWITCH_ANTENNA1;
+               else if (tbl->action >= IWL_LEGACY_SWITCH_ANTENNA2)
+                       tbl->action = IWL_LEGACY_SWITCH_SISO;
+               valid_tx_ant = first_antenna(priv->hw_params.valid_tx_ant);
+       }
+
+       start_action = tbl->action;
        for (; ;) {
                lq_sta->action_counter++;
                switch (tbl->action) {
@@ -1291,7 +1392,10 @@ static int rs_move_legacy_other(struct iwl_priv *priv,
                                break;
 
                        /* Don't change antenna if success has been great */
-                       if (window->success_ratio >= IWL_RS_GOOD_RATIO)
+                       if (window->success_ratio >= IWL_RS_GOOD_RATIO &&
+                           !priv->bt_full_concurrent &&
+                           priv->bt_traffic_load ==
+                                       IWL_BT_COEX_TRAFFIC_LOAD_NONE)
                                break;
 
                        /* Set up search table to try other antenna */
@@ -1403,31 +1507,64 @@ static int rs_move_siso_to_other(struct iwl_priv *priv,
        struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
        u32 sz = (sizeof(struct iwl_scale_tbl_info) -
                  (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
-       u8 start_action = tbl->action;
+       u8 start_action;
        u8 valid_tx_ant = priv->hw_params.valid_tx_ant;
        u8 tx_chains_num = priv->hw_params.tx_chains_num;
        u8 update_search_tbl_counter = 0;
        int ret;
 
+       switch (priv->bt_traffic_load) {
+       case IWL_BT_COEX_TRAFFIC_LOAD_NONE:
+               /* nothing */
+               break;
+       case IWL_BT_COEX_TRAFFIC_LOAD_LOW:
+               /* avoid antenna B unless MIMO */
+               valid_tx_ant = first_antenna(priv->hw_params.valid_tx_ant);
+               if (tbl->action == IWL_SISO_SWITCH_ANTENNA2)
+                       tbl->action = IWL_SISO_SWITCH_ANTENNA1;
+               break;
+       case IWL_BT_COEX_TRAFFIC_LOAD_HIGH:
+       case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS:
+               /* avoid antenna B and MIMO */
+               valid_tx_ant = first_antenna(priv->hw_params.valid_tx_ant);
+               if (tbl->action != IWL_SISO_SWITCH_ANTENNA1)
+                       tbl->action = IWL_SISO_SWITCH_ANTENNA1;
+               break;
+       default:
+               IWL_ERR(priv, "Invalid BT load %d", priv->bt_traffic_load);
+               break;
+       }
+
        if (iwl_tx_ant_restriction(priv) == IWL_ANT_OK_SINGLE &&
            tbl->action > IWL_SISO_SWITCH_ANTENNA2) {
                /* stay in SISO */
                tbl->action = IWL_SISO_SWITCH_ANTENNA1;
        }
+
+       /* configure as 1x1 if bt full concurrency */
+       if (priv->bt_full_concurrent) {
+               valid_tx_ant = first_antenna(priv->hw_params.valid_tx_ant);
+               if (tbl->action >= IWL_LEGACY_SWITCH_ANTENNA2)
+                       tbl->action = IWL_SISO_SWITCH_ANTENNA1;
+       }
+
+       start_action = tbl->action;
        for (;;) {
                lq_sta->action_counter++;
                switch (tbl->action) {
                case IWL_SISO_SWITCH_ANTENNA1:
                case IWL_SISO_SWITCH_ANTENNA2:
                        IWL_DEBUG_RATE(priv, "LQ: SISO toggle Antenna\n");
-
                        if ((tbl->action == IWL_SISO_SWITCH_ANTENNA1 &&
-                                                       tx_chains_num <= 1) ||
+                                               tx_chains_num <= 1) ||
                            (tbl->action == IWL_SISO_SWITCH_ANTENNA2 &&
-                                                       tx_chains_num <= 2))
+                                               tx_chains_num <= 2))
                                break;
 
-                       if (window->success_ratio >= IWL_RS_GOOD_RATIO)
+                       if (window->success_ratio >= IWL_RS_GOOD_RATIO &&
+                           !priv->bt_full_concurrent &&
+                           priv->bt_traffic_load ==
+                                       IWL_BT_COEX_TRAFFIC_LOAD_NONE)
                                break;
 
                        memcpy(search_tbl, tbl, sz);
@@ -1541,18 +1678,47 @@ static int rs_move_mimo2_to_other(struct iwl_priv *priv,
        struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
        u32 sz = (sizeof(struct iwl_scale_tbl_info) -
                  (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
-       u8 start_action = tbl->action;
+       u8 start_action;
        u8 valid_tx_ant = priv->hw_params.valid_tx_ant;
        u8 tx_chains_num = priv->hw_params.tx_chains_num;
        u8 update_search_tbl_counter = 0;
        int ret;
 
+       switch (priv->bt_traffic_load) {
+       case IWL_BT_COEX_TRAFFIC_LOAD_NONE:
+               /* nothing */
+               break;
+       case IWL_BT_COEX_TRAFFIC_LOAD_HIGH:
+       case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS:
+               /* avoid antenna B and MIMO */
+               if (tbl->action != IWL_MIMO2_SWITCH_SISO_A)
+                       tbl->action = IWL_MIMO2_SWITCH_SISO_A;
+               break;
+       case IWL_BT_COEX_TRAFFIC_LOAD_LOW:
+               /* avoid antenna B unless MIMO */
+               if (tbl->action == IWL_MIMO2_SWITCH_SISO_B ||
+                   tbl->action == IWL_MIMO2_SWITCH_SISO_C)
+                       tbl->action = IWL_MIMO2_SWITCH_SISO_A;
+               break;
+       default:
+               IWL_ERR(priv, "Invalid BT load %d", priv->bt_traffic_load);
+               break;
+       }
+
        if ((iwl_tx_ant_restriction(priv) == IWL_ANT_OK_SINGLE) &&
            (tbl->action < IWL_MIMO2_SWITCH_SISO_A ||
             tbl->action > IWL_MIMO2_SWITCH_SISO_C)) {
                /* switch in SISO */
                tbl->action = IWL_MIMO2_SWITCH_SISO_A;
        }
+
+       /* configure as 1x1 if bt full concurrency */
+       if (priv->bt_full_concurrent &&
+           (tbl->action < IWL_MIMO2_SWITCH_SISO_A ||
+            tbl->action > IWL_MIMO2_SWITCH_SISO_C))
+               tbl->action = IWL_MIMO2_SWITCH_SISO_A;
+
+       start_action = tbl->action;
        for (;;) {
                lq_sta->action_counter++;
                switch (tbl->action) {
@@ -1682,18 +1848,47 @@ static int rs_move_mimo3_to_other(struct iwl_priv *priv,
        struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
        u32 sz = (sizeof(struct iwl_scale_tbl_info) -
                  (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
-       u8 start_action = tbl->action;
+       u8 start_action;
        u8 valid_tx_ant = priv->hw_params.valid_tx_ant;
        u8 tx_chains_num = priv->hw_params.tx_chains_num;
        int ret;
        u8 update_search_tbl_counter = 0;
 
+       switch (priv->bt_traffic_load) {
+       case IWL_BT_COEX_TRAFFIC_LOAD_NONE:
+               /* nothing */
+               break;
+       case IWL_BT_COEX_TRAFFIC_LOAD_HIGH:
+       case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS:
+               /* avoid antenna B and MIMO */
+               if (tbl->action != IWL_MIMO3_SWITCH_SISO_A)
+                       tbl->action = IWL_MIMO3_SWITCH_SISO_A;
+               break;
+       case IWL_BT_COEX_TRAFFIC_LOAD_LOW:
+               /* avoid antenna B unless MIMO */
+               if (tbl->action == IWL_MIMO3_SWITCH_SISO_B ||
+                   tbl->action == IWL_MIMO3_SWITCH_SISO_C)
+                       tbl->action = IWL_MIMO3_SWITCH_SISO_A;
+               break;
+       default:
+               IWL_ERR(priv, "Invalid BT load %d", priv->bt_traffic_load);
+               break;
+       }
+
        if ((iwl_tx_ant_restriction(priv) == IWL_ANT_OK_SINGLE) &&
            (tbl->action < IWL_MIMO3_SWITCH_SISO_A ||
             tbl->action > IWL_MIMO3_SWITCH_SISO_C)) {
                /* switch in SISO */
                tbl->action = IWL_MIMO3_SWITCH_SISO_A;
        }
+
+       /* configure as 1x1 if bt full concurrency */
+       if (priv->bt_full_concurrent &&
+           (tbl->action < IWL_MIMO3_SWITCH_SISO_A ||
+            tbl->action > IWL_MIMO3_SWITCH_SISO_C))
+               tbl->action = IWL_MIMO3_SWITCH_SISO_A;
+
+       start_action = tbl->action;
        for (;;) {
                lq_sta->action_counter++;
                switch (tbl->action) {
@@ -1820,7 +2015,7 @@ static int rs_move_mimo3_to_other(struct iwl_priv *priv,
  * 2) # times calling this function
  * 3) elapsed time in this mode (not used, for now)
  */
-static void rs_stay_in_table(struct iwl_lq_sta *lq_sta)
+static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search)
 {
        struct iwl_scale_tbl_info *tbl;
        int i;
@@ -1851,7 +2046,8 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta)
                 * allow a new search.  Also (below) reset all bitmaps and
                 * stats in active history.
                 */
-               if ((lq_sta->total_failed > lq_sta->max_failure_limit) ||
+               if (force_search ||
+                   (lq_sta->total_failed > lq_sta->max_failure_limit) ||
                    (lq_sta->total_success > lq_sta->max_success_limit) ||
                    ((!lq_sta->search_better_tbl) && (lq_sta->flush_timer)
                     && (flush_interval_passed))) {
@@ -1900,6 +2096,7 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta)
  * return rate_n_flags as used in the table
  */
 static u32 rs_update_rate_tbl(struct iwl_priv *priv,
+                             struct iwl_rxon_context *ctx,
                                struct iwl_lq_sta *lq_sta,
                                struct iwl_scale_tbl_info *tbl,
                                int index, u8 is_green)
@@ -1909,7 +2106,7 @@ static u32 rs_update_rate_tbl(struct iwl_priv *priv,
        /* Update uCode's rate table. */
        rate = rate_n_flags_from_tbl(priv, tbl, index, is_green);
        rs_fill_link_cmd(priv, lq_sta, rate);
-       iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC, false);
+       iwl_send_lq_cmd(priv, ctx, &lq_sta->lq, CMD_ASYNC, false);
 
        return rate;
 }
@@ -1948,6 +2145,8 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
        s32 sr;
        u8 tid = MAX_TID_COUNT;
        struct iwl_tid_data *tid_data;
+       struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
+       struct iwl_rxon_context *ctx = sta_priv->common.ctx;
 
        IWL_DEBUG_RATE(priv, "rate scale calculate new rate for skb\n");
 
@@ -1986,7 +2185,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
        if (is_legacy(tbl->lq_type))
                lq_sta->is_green = 0;
        else
-               lq_sta->is_green = rs_use_green(sta, &priv->current_ht_config);
+               lq_sta->is_green = rs_use_green(sta);
        is_green = lq_sta->is_green;
 
        /* current tx rate */
@@ -2025,7 +2224,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
                        tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
                        /* get "active" rate info */
                        index = iwl_hwrate_to_plcp_idx(tbl->current_rate);
-                       rate = rs_update_rate_tbl(priv, lq_sta,
+                       rate = rs_update_rate_tbl(priv, ctx, lq_sta,
                                                  tbl, index, is_green);
                }
                return;
@@ -2067,7 +2266,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
 
                /* Should we stay with this modulation mode,
                 * or search for a new one? */
-               rs_stay_in_table(lq_sta);
+               rs_stay_in_table(lq_sta, false);
 
                goto out;
        }
@@ -2215,6 +2414,28 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
        if (iwl_tx_ant_restriction(priv) != IWL_ANT_OK_MULTI &&
                (is_mimo2(tbl->lq_type) || is_mimo3(tbl->lq_type)))
                scale_action = -1;
+
+       if ((priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH) &&
+            (is_mimo2(tbl->lq_type) || is_mimo3(tbl->lq_type))) {
+               if (lq_sta->last_bt_traffic > priv->bt_traffic_load) {
+                       /*
+                        * don't set scale_action, don't want to scale up if
+                        * the rate scale doesn't otherwise think that is a
+                        * good idea.
+                        */
+               } else if (lq_sta->last_bt_traffic <= priv->bt_traffic_load) {
+                       scale_action = -1;
+               }
+       }
+       lq_sta->last_bt_traffic = priv->bt_traffic_load;
+
+       if ((priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH) &&
+            (is_mimo2(tbl->lq_type) || is_mimo3(tbl->lq_type))) {
+               /* search for a new modulation */
+               rs_stay_in_table(lq_sta, true);
+               goto lq_update;
+       }
+
        switch (scale_action) {
        case -1:
                /* Decrease starting rate, update uCode's rate table */
@@ -2245,13 +2466,13 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
 lq_update:
        /* Replace uCode's rate table for the destination station. */
        if (update_lq)
-               rate = rs_update_rate_tbl(priv, lq_sta,
+               rate = rs_update_rate_tbl(priv, ctx, lq_sta,
                                          tbl, index, is_green);
 
        if (iwl_tx_ant_restriction(priv) == IWL_ANT_OK_MULTI) {
                /* Should we stay with this modulation mode,
                 * or search for a new one? */
-               rs_stay_in_table(lq_sta);
+         rs_stay_in_table(lq_sta, false);
        }
        /*
         * Search for new modulation mode if we're:
@@ -2287,7 +2508,7 @@ lq_update:
                        IWL_DEBUG_RATE(priv, "Switch current  mcs: %X index: %d\n",
                                     tbl->current_rate, index);
                        rs_fill_link_cmd(priv, lq_sta, tbl->current_rate);
-                       iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC, false);
+                       iwl_send_lq_cmd(priv, ctx, &lq_sta->lq, CMD_ASYNC, false);
                } else
                        done_search = 1;
        }
@@ -2357,12 +2578,17 @@ static void rs_initialize_lq(struct iwl_priv *priv,
        int rate_idx;
        int i;
        u32 rate;
-       u8 use_green = rs_use_green(sta, &priv->current_ht_config);
+       u8 use_green = rs_use_green(sta);
        u8 active_tbl = 0;
        u8 valid_tx_ant;
+       struct iwl_station_priv *sta_priv;
+       struct iwl_rxon_context *ctx;
 
        if (!sta || !lq_sta)
-               goto out;
+               return;
+
+       sta_priv = (void *)sta->drv_priv;
+       ctx = sta_priv->common.ctx;
 
        i = lq_sta->last_txrate_idx;
 
@@ -2394,9 +2620,7 @@ static void rs_initialize_lq(struct iwl_priv *priv,
        rs_set_expected_tpt_table(lq_sta, tbl);
        rs_fill_link_cmd(NULL, lq_sta, rate);
        priv->stations[lq_sta->lq.sta_id].lq = &lq_sta->lq;
-       iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_SYNC, true);
- out:
-       return;
+       iwl_send_lq_cmd(priv, ctx, &lq_sta->lq, CMD_SYNC, true);
 }
 
 static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta,
@@ -2524,7 +2748,7 @@ void iwl_rs_rate_init(struct iwl_priv *priv, struct ieee80211_sta *sta, u8 sta_i
        lq_sta->is_dup = 0;
        lq_sta->max_rate_idx = -1;
        lq_sta->missed_rate_counter = IWL_MISSED_RATE_MAX;
-       lq_sta->is_green = rs_use_green(sta, &priv->current_ht_config);
+       lq_sta->is_green = rs_use_green(sta);
        lq_sta->active_legacy_rate = priv->active_rate & ~(0x1000);
        lq_sta->band = priv->band;
        /*
@@ -2594,10 +2818,15 @@ static void rs_fill_link_cmd(struct iwl_priv *priv,
        rs_dbgfs_set_mcs(lq_sta, &new_rate, index);
 
        /* Interpret new_rate (rate_n_flags) */
-       memset(&tbl_type, 0, sizeof(tbl_type));
        rs_get_tbl_info_from_mcs(new_rate, lq_sta->band,
                                  &tbl_type, &rate_idx);
 
+       if (priv && priv->bt_full_concurrent) {
+               /* 1x1 only */
+               tbl_type.ant_type =
+                       first_antenna(priv->hw_params.valid_tx_ant);
+       }
+
        /* How many times should we repeat the initial rate? */
        if (is_legacy(tbl_type.lq_type)) {
                ant_toggle_cnt = 1;
@@ -2622,9 +2851,12 @@ static void rs_fill_link_cmd(struct iwl_priv *priv,
 
        index++;
        repeat_rate--;
-
-       if (priv)
-               valid_tx_ant = priv->hw_params.valid_tx_ant;
+       if (priv) {
+               if (priv->bt_full_concurrent)
+                       valid_tx_ant = ANT_A;
+               else
+                       valid_tx_ant = priv->hw_params.valid_tx_ant;
+       }
 
        /* Fill rest of rate table */
        while (index < LINK_QUAL_MAX_RETRY_NUM) {
@@ -2639,7 +2871,7 @@ static void rs_fill_link_cmd(struct iwl_priv *priv,
                                         rs_toggle_antenna(valid_tx_ant,
                                                        &new_rate, &tbl_type))
                                        ant_toggle_cnt = 1;
-}
+                       }
 
                        /* Override next rate if needed for debug purposes */
                        rs_dbgfs_set_mcs(lq_sta, &new_rate, index);
@@ -2654,6 +2886,12 @@ static void rs_fill_link_cmd(struct iwl_priv *priv,
                rs_get_tbl_info_from_mcs(new_rate, lq_sta->band, &tbl_type,
                                                &rate_idx);
 
+               if (priv && priv->bt_full_concurrent) {
+                       /* 1x1 only */
+                       tbl_type.ant_type =
+                               first_antenna(priv->hw_params.valid_tx_ant);
+               }
+
                /* Indicate to uCode which entries might be MIMO.
                 * If initial rate was MIMO, this will finally end up
                 * as (IWL_HT_NUMBER_TRY * 2), after 2nd pass, otherwise 0. */
@@ -2694,8 +2932,18 @@ static void rs_fill_link_cmd(struct iwl_priv *priv,
 
        lq_cmd->agg_params.agg_frame_cnt_limit = LINK_QUAL_AGG_FRAME_LIMIT_DEF;
        lq_cmd->agg_params.agg_dis_start_th = LINK_QUAL_AGG_DISABLE_START_DEF;
+
        lq_cmd->agg_params.agg_time_limit =
                cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF);
+       /*
+        * overwrite if needed, pass aggregation time limit
+        * to uCode in uSec
+        */
+       if (priv && priv->cfg->agg_time_limit &&
+           priv->cfg->agg_time_limit >= LINK_QUAL_AGG_TIME_LIMIT_MIN &&
+           priv->cfg->agg_time_limit <= LINK_QUAL_AGG_TIME_LIMIT_MAX)
+               lq_cmd->agg_params.agg_time_limit =
+                       cpu_to_le16(priv->cfg->agg_time_limit);
 }
 
 static void *rs_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
@@ -2760,6 +3008,9 @@ static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file,
        char buf[64];
        int buf_size;
        u32 parsed_rate;
+       struct iwl_station_priv *sta_priv =
+               container_of(lq_sta, struct iwl_station_priv, lq_sta);
+       struct iwl_rxon_context *ctx = sta_priv->common.ctx;
 
        priv = lq_sta->drv;
        memset(buf, 0, sizeof(buf));
@@ -2782,7 +3033,8 @@ static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file,
 
        if (lq_sta->dbg_fixed_rate) {
                rs_fill_link_cmd(NULL, lq_sta, lq_sta->dbg_fixed_rate);
-               iwl_send_lq_cmd(lq_sta->drv, &lq_sta->lq, CMD_ASYNC, false);
+               iwl_send_lq_cmd(lq_sta->drv, ctx, &lq_sta->lq, CMD_ASYNC,
+                               false);
        }
 
        return count;
index 8292f6d48ec62067cb5dec7f4076038ad0b46430..3970ab1deaf99cbbe8c8437afd91315ac38705fe 100644 (file)
@@ -432,6 +432,8 @@ struct iwl_lq_sta {
        u32 last_rate_n_flags;
        /* packets destined for this STA are aggregated */
        u8 is_agg;
+       /* BT traffic this sta was last updated in */
+       u8 last_bt_traffic;
 };
 
 static inline u8 num_of_ant(u8 mask)
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tt.c b/drivers/net/wireless/iwlwifi/iwl-agn-tt.c
new file mode 100644 (file)
index 0000000..07b2c6c
--- /dev/null
@@ -0,0 +1,704 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ipw3945 project, as well
+ * as portions of the ieee80211 subsystem header files.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *****************************************************************************/
+
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+
+#include <net/mac80211.h>
+
+#include "iwl-eeprom.h"
+#include "iwl-dev.h"
+#include "iwl-core.h"
+#include "iwl-io.h"
+#include "iwl-commands.h"
+#include "iwl-debug.h"
+#include "iwl-agn-tt.h"
+
+/* default Thermal Throttling transaction table
+ * Current state   |         Throttling Down               |  Throttling Up
+ *=============================================================================
+ *                 Condition Nxt State  Condition Nxt State Condition Nxt State
+ *-----------------------------------------------------------------------------
+ *     IWL_TI_0     T >= 114   CT_KILL  114>T>=105   TI_1      N/A      N/A
+ *     IWL_TI_1     T >= 114   CT_KILL  114>T>=110   TI_2     T<=95     TI_0
+ *     IWL_TI_2     T >= 114   CT_KILL                        T<=100    TI_1
+ *    IWL_CT_KILL      N/A       N/A       N/A        N/A     T<=95     TI_0
+ *=============================================================================
+ */
+static const struct iwl_tt_trans tt_range_0[IWL_TI_STATE_MAX - 1] = {
+       {IWL_TI_0, IWL_ABSOLUTE_ZERO, 104},
+       {IWL_TI_1, 105, CT_KILL_THRESHOLD - 1},
+       {IWL_TI_CT_KILL, CT_KILL_THRESHOLD, IWL_ABSOLUTE_MAX}
+};
+static const struct iwl_tt_trans tt_range_1[IWL_TI_STATE_MAX - 1] = {
+       {IWL_TI_0, IWL_ABSOLUTE_ZERO, 95},
+       {IWL_TI_2, 110, CT_KILL_THRESHOLD - 1},
+       {IWL_TI_CT_KILL, CT_KILL_THRESHOLD, IWL_ABSOLUTE_MAX}
+};
+static const struct iwl_tt_trans tt_range_2[IWL_TI_STATE_MAX - 1] = {
+       {IWL_TI_1, IWL_ABSOLUTE_ZERO, 100},
+       {IWL_TI_CT_KILL, CT_KILL_THRESHOLD, IWL_ABSOLUTE_MAX},
+       {IWL_TI_CT_KILL, CT_KILL_THRESHOLD, IWL_ABSOLUTE_MAX}
+};
+static const struct iwl_tt_trans tt_range_3[IWL_TI_STATE_MAX - 1] = {
+       {IWL_TI_0, IWL_ABSOLUTE_ZERO, CT_KILL_EXIT_THRESHOLD},
+       {IWL_TI_CT_KILL, CT_KILL_EXIT_THRESHOLD + 1, IWL_ABSOLUTE_MAX},
+       {IWL_TI_CT_KILL, CT_KILL_EXIT_THRESHOLD + 1, IWL_ABSOLUTE_MAX}
+};
+
+/* Advance Thermal Throttling default restriction table */
+static const struct iwl_tt_restriction restriction_range[IWL_TI_STATE_MAX] = {
+       {IWL_ANT_OK_MULTI, IWL_ANT_OK_MULTI, true },
+       {IWL_ANT_OK_SINGLE, IWL_ANT_OK_MULTI, true },
+       {IWL_ANT_OK_SINGLE, IWL_ANT_OK_SINGLE, false },
+       {IWL_ANT_OK_NONE, IWL_ANT_OK_NONE, false }
+};
+
+bool iwl_tt_is_low_power_state(struct iwl_priv *priv)
+{
+       struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
+
+       if (tt->state >= IWL_TI_1)
+               return true;
+       return false;
+}
+
+u8 iwl_tt_current_power_mode(struct iwl_priv *priv)
+{
+       struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
+
+       return tt->tt_power_mode;
+}
+
+bool iwl_ht_enabled(struct iwl_priv *priv)
+{
+       struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
+       struct iwl_tt_restriction *restriction;
+
+       if (!priv->thermal_throttle.advanced_tt)
+               return true;
+       restriction = tt->restriction + tt->state;
+       return restriction->is_ht;
+}
+
+static bool iwl_within_ct_kill_margin(struct iwl_priv *priv)
+{
+       s32 temp = priv->temperature; /* degrees CELSIUS except specified */
+       bool within_margin = false;
+
+       if (priv->cfg->temperature_kelvin)
+               temp = KELVIN_TO_CELSIUS(priv->temperature);
+
+       if (!priv->thermal_throttle.advanced_tt)
+               within_margin = ((temp + IWL_TT_CT_KILL_MARGIN) >=
+                               CT_KILL_THRESHOLD_LEGACY) ? true : false;
+       else
+               within_margin = ((temp + IWL_TT_CT_KILL_MARGIN) >=
+                               CT_KILL_THRESHOLD) ? true : false;
+       return within_margin;
+}
+
+bool iwl_check_for_ct_kill(struct iwl_priv *priv)
+{
+       bool is_ct_kill = false;
+
+       if (iwl_within_ct_kill_margin(priv)) {
+               iwl_tt_enter_ct_kill(priv);
+               is_ct_kill = true;
+       }
+       return is_ct_kill;
+}
+
+enum iwl_antenna_ok iwl_tx_ant_restriction(struct iwl_priv *priv)
+{
+       struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
+       struct iwl_tt_restriction *restriction;
+
+       if (!priv->thermal_throttle.advanced_tt)
+               return IWL_ANT_OK_MULTI;
+       restriction = tt->restriction + tt->state;
+       return restriction->tx_stream;
+}
+
+enum iwl_antenna_ok iwl_rx_ant_restriction(struct iwl_priv *priv)
+{
+       struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
+       struct iwl_tt_restriction *restriction;
+
+       if (!priv->thermal_throttle.advanced_tt)
+               return IWL_ANT_OK_MULTI;
+       restriction = tt->restriction + tt->state;
+       return restriction->rx_stream;
+}
+
+#define CT_KILL_EXIT_DURATION (5)      /* 5 seconds duration */
+#define CT_KILL_WAITING_DURATION (300) /* 300ms duration */
+
+/*
+ * toggle the bit to wake up uCode and check the temperature
+ * if the temperature is below CT, uCode will stay awake and send card
+ * state notification with CT_KILL bit clear to inform Thermal Throttling
+ * Management to change state. Otherwise, uCode will go back to sleep
+ * without doing anything, driver should continue the 5 seconds timer
+ * to wake up uCode for temperature check until temperature drop below CT
+ */
+static void iwl_tt_check_exit_ct_kill(unsigned long data)
+{
+       struct iwl_priv *priv = (struct iwl_priv *)data;
+       struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
+       unsigned long flags;
+
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+               return;
+
+       if (tt->state == IWL_TI_CT_KILL) {
+               if (priv->thermal_throttle.ct_kill_toggle) {
+                       iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
+                                   CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
+                       priv->thermal_throttle.ct_kill_toggle = false;
+               } else {
+                       iwl_write32(priv, CSR_UCODE_DRV_GP1_SET,
+                                   CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
+                       priv->thermal_throttle.ct_kill_toggle = true;
+               }
+               iwl_read32(priv, CSR_UCODE_DRV_GP1);
+               spin_lock_irqsave(&priv->reg_lock, flags);
+               if (!iwl_grab_nic_access(priv))
+                       iwl_release_nic_access(priv);
+               spin_unlock_irqrestore(&priv->reg_lock, flags);
+
+               /* Reschedule the ct_kill timer to occur in
+                * CT_KILL_EXIT_DURATION seconds to ensure we get a
+                * thermal update */
+               IWL_DEBUG_POWER(priv, "schedule ct_kill exit timer\n");
+               mod_timer(&priv->thermal_throttle.ct_kill_exit_tm,
+                         jiffies + CT_KILL_EXIT_DURATION * HZ);
+       }
+}
+
+static void iwl_perform_ct_kill_task(struct iwl_priv *priv,
+                          bool stop)
+{
+       if (stop) {
+               IWL_DEBUG_POWER(priv, "Stop all queues\n");
+               if (priv->mac80211_registered)
+                       ieee80211_stop_queues(priv->hw);
+               IWL_DEBUG_POWER(priv,
+                               "Schedule 5 seconds CT_KILL Timer\n");
+               mod_timer(&priv->thermal_throttle.ct_kill_exit_tm,
+                         jiffies + CT_KILL_EXIT_DURATION * HZ);
+       } else {
+               IWL_DEBUG_POWER(priv, "Wake all queues\n");
+               if (priv->mac80211_registered)
+                       ieee80211_wake_queues(priv->hw);
+       }
+}
+
+static void iwl_tt_ready_for_ct_kill(unsigned long data)
+{
+       struct iwl_priv *priv = (struct iwl_priv *)data;
+       struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
+
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+               return;
+
+       /* temperature timer expired, ready to go into CT_KILL state */
+       if (tt->state != IWL_TI_CT_KILL) {
+               IWL_DEBUG_POWER(priv, "entering CT_KILL state when "
+                               "temperature timer expired\n");
+               tt->state = IWL_TI_CT_KILL;
+               set_bit(STATUS_CT_KILL, &priv->status);
+               iwl_perform_ct_kill_task(priv, true);
+       }
+}
+
+static void iwl_prepare_ct_kill_task(struct iwl_priv *priv)
+{
+       IWL_DEBUG_POWER(priv, "Prepare to enter IWL_TI_CT_KILL\n");
+       /* make request to retrieve statistics information */
+       iwl_send_statistics_request(priv, CMD_SYNC, false);
+       /* Reschedule the ct_kill wait timer */
+       mod_timer(&priv->thermal_throttle.ct_kill_waiting_tm,
+                jiffies + msecs_to_jiffies(CT_KILL_WAITING_DURATION));
+}
+
+#define IWL_MINIMAL_POWER_THRESHOLD            (CT_KILL_THRESHOLD_LEGACY)
+#define IWL_REDUCED_PERFORMANCE_THRESHOLD_2    (100)
+#define IWL_REDUCED_PERFORMANCE_THRESHOLD_1    (90)
+
+/*
+ * Legacy thermal throttling
+ * 1) Avoid NIC destruction due to high temperatures
+ *     Chip will identify dangerously high temperatures that can
+ *     harm the device and will power down
+ * 2) Avoid the NIC power down due to high temperature
+ *     Throttle early enough to lower the power consumption before
+ *     drastic steps are needed
+ */
+static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp, bool force)
+{
+       struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
+       enum iwl_tt_state old_state;
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+       if ((tt->tt_previous_temp) &&
+           (temp > tt->tt_previous_temp) &&
+           ((temp - tt->tt_previous_temp) >
+           IWL_TT_INCREASE_MARGIN)) {
+               IWL_DEBUG_POWER(priv,
+                       "Temperature increase %d degree Celsius\n",
+                       (temp - tt->tt_previous_temp));
+       }
+#endif
+       old_state = tt->state;
+       /* in Celsius */
+       if (temp >= IWL_MINIMAL_POWER_THRESHOLD)
+               tt->state = IWL_TI_CT_KILL;
+       else if (temp >= IWL_REDUCED_PERFORMANCE_THRESHOLD_2)
+               tt->state = IWL_TI_2;
+       else if (temp >= IWL_REDUCED_PERFORMANCE_THRESHOLD_1)
+               tt->state = IWL_TI_1;
+       else
+               tt->state = IWL_TI_0;
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+       tt->tt_previous_temp = temp;
+#endif
+       /* stop ct_kill_waiting_tm timer */
+       del_timer_sync(&priv->thermal_throttle.ct_kill_waiting_tm);
+       if (tt->state != old_state) {
+               switch (tt->state) {
+               case IWL_TI_0:
+                       /*
+                        * When the system is ready to go back to IWL_TI_0
+                        * we only have to call iwl_power_update_mode() to
+                        * do so.
+                        */
+                       break;
+               case IWL_TI_1:
+                       tt->tt_power_mode = IWL_POWER_INDEX_3;
+                       break;
+               case IWL_TI_2:
+                       tt->tt_power_mode = IWL_POWER_INDEX_4;
+                       break;
+               default:
+                       tt->tt_power_mode = IWL_POWER_INDEX_5;
+                       break;
+               }
+               mutex_lock(&priv->mutex);
+               if (old_state == IWL_TI_CT_KILL)
+                       clear_bit(STATUS_CT_KILL, &priv->status);
+               if (tt->state != IWL_TI_CT_KILL &&
+                   iwl_power_update_mode(priv, true)) {
+                       /* TT state not updated
+                        * try again during next temperature read
+                        */
+                       if (old_state == IWL_TI_CT_KILL)
+                               set_bit(STATUS_CT_KILL, &priv->status);
+                       tt->state = old_state;
+                       IWL_ERR(priv, "Cannot update power mode, "
+                                       "TT state not updated\n");
+               } else {
+                       if (tt->state == IWL_TI_CT_KILL) {
+                               if (force) {
+                                       set_bit(STATUS_CT_KILL, &priv->status);
+                                       iwl_perform_ct_kill_task(priv, true);
+                               } else {
+                                       iwl_prepare_ct_kill_task(priv);
+                                       tt->state = old_state;
+                               }
+                       } else if (old_state == IWL_TI_CT_KILL &&
+                                tt->state != IWL_TI_CT_KILL)
+                               iwl_perform_ct_kill_task(priv, false);
+                       IWL_DEBUG_POWER(priv, "Temperature state changed %u\n",
+                                       tt->state);
+                       IWL_DEBUG_POWER(priv, "Power Index change to %u\n",
+                                       tt->tt_power_mode);
+               }
+               mutex_unlock(&priv->mutex);
+       }
+}
+
+/*
+ * Advance thermal throttling
+ * 1) Avoid NIC destruction due to high temperatures
+ *     Chip will identify dangerously high temperatures that can
+ *     harm the device and will power down
+ * 2) Avoid the NIC power down due to high temperature
+ *     Throttle early enough to lower the power consumption before
+ *     drastic steps are needed
+ *     Actions include relaxing the power down sleep thresholds and
+ *     decreasing the number of TX streams
+ * 3) Avoid throughput performance impact as much as possible
+ *
+ *=============================================================================
+ *                 Condition Nxt State  Condition Nxt State Condition Nxt State
+ *-----------------------------------------------------------------------------
+ *     IWL_TI_0     T >= 114   CT_KILL  114>T>=105   TI_1      N/A      N/A
+ *     IWL_TI_1     T >= 114   CT_KILL  114>T>=110   TI_2     T<=95     TI_0
+ *     IWL_TI_2     T >= 114   CT_KILL                        T<=100    TI_1
+ *    IWL_CT_KILL      N/A       N/A       N/A        N/A     T<=95     TI_0
+ *=============================================================================
+ */
+static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp, bool force)
+{
+       struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
+       int i;
+       bool changed = false;
+       enum iwl_tt_state old_state;
+       struct iwl_tt_trans *transaction;
+
+       old_state = tt->state;
+       for (i = 0; i < IWL_TI_STATE_MAX - 1; i++) {
+               /* based on the current TT state,
+                * find the curresponding transaction table
+                * each table has (IWL_TI_STATE_MAX - 1) entries
+                * tt->transaction + ((old_state * (IWL_TI_STATE_MAX - 1))
+                * will advance to the correct table.
+                * then based on the current temperature
+                * find the next state need to transaction to
+                * go through all the possible (IWL_TI_STATE_MAX - 1) entries
+                * in the current table to see if transaction is needed
+                */
+               transaction = tt->transaction +
+                       ((old_state * (IWL_TI_STATE_MAX - 1)) + i);
+               if (temp >= transaction->tt_low &&
+                   temp <= transaction->tt_high) {
+#ifdef CONFIG_IWLWIFI_DEBUG
+                       if ((tt->tt_previous_temp) &&
+                           (temp > tt->tt_previous_temp) &&
+                           ((temp - tt->tt_previous_temp) >
+                           IWL_TT_INCREASE_MARGIN)) {
+                               IWL_DEBUG_POWER(priv,
+                                       "Temperature increase %d "
+                                       "degree Celsius\n",
+                                       (temp - tt->tt_previous_temp));
+                       }
+                       tt->tt_previous_temp = temp;
+#endif
+                       if (old_state !=
+                           transaction->next_state) {
+                               changed = true;
+                               tt->state =
+                                       transaction->next_state;
+                       }
+                       break;
+               }
+       }
+       /* stop ct_kill_waiting_tm timer */
+       del_timer_sync(&priv->thermal_throttle.ct_kill_waiting_tm);
+       if (changed) {
+               if (tt->state >= IWL_TI_1) {
+                       /* force PI = IWL_POWER_INDEX_5 in the case of TI > 0 */
+                       tt->tt_power_mode = IWL_POWER_INDEX_5;
+
+                       if (!iwl_ht_enabled(priv)) {
+                               struct iwl_rxon_context *ctx;
+
+                               for_each_context(priv, ctx) {
+                                       struct iwl_rxon_cmd *rxon;
+
+                                       rxon = &ctx->staging;
+
+                                       /* disable HT */
+                                       rxon->flags &= ~(
+                                               RXON_FLG_CHANNEL_MODE_MSK |
+                                               RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK |
+                                               RXON_FLG_HT40_PROT_MSK |
+                                               RXON_FLG_HT_PROT_MSK);
+                               }
+                       } else {
+                               /* check HT capability and set
+                                * according to the system HT capability
+                                * in case get disabled before */
+                               iwl_set_rxon_ht(priv, &priv->current_ht_config);
+                       }
+
+               } else {
+                       /*
+                        * restore system power setting -- it will be
+                        * recalculated automatically.
+                        */
+
+                       /* check HT capability and set
+                        * according to the system HT capability
+                        * in case get disabled before */
+                       iwl_set_rxon_ht(priv, &priv->current_ht_config);
+               }
+               mutex_lock(&priv->mutex);
+               if (old_state == IWL_TI_CT_KILL)
+                       clear_bit(STATUS_CT_KILL, &priv->status);
+               if (tt->state != IWL_TI_CT_KILL &&
+                   iwl_power_update_mode(priv, true)) {
+                       /* TT state not updated
+                        * try again during next temperature read
+                        */
+                       IWL_ERR(priv, "Cannot update power mode, "
+                                       "TT state not updated\n");
+                       if (old_state == IWL_TI_CT_KILL)
+                               set_bit(STATUS_CT_KILL, &priv->status);
+                       tt->state = old_state;
+               } else {
+                       IWL_DEBUG_POWER(priv,
+                                       "Thermal Throttling to new state: %u\n",
+                                       tt->state);
+                       if (old_state != IWL_TI_CT_KILL &&
+                           tt->state == IWL_TI_CT_KILL) {
+                               if (force) {
+                                       IWL_DEBUG_POWER(priv,
+                                               "Enter IWL_TI_CT_KILL\n");
+                                       set_bit(STATUS_CT_KILL, &priv->status);
+                                       iwl_perform_ct_kill_task(priv, true);
+                               } else {
+                                       iwl_prepare_ct_kill_task(priv);
+                                       tt->state = old_state;
+                               }
+                       } else if (old_state == IWL_TI_CT_KILL &&
+                                 tt->state != IWL_TI_CT_KILL) {
+                               IWL_DEBUG_POWER(priv, "Exit IWL_TI_CT_KILL\n");
+                               iwl_perform_ct_kill_task(priv, false);
+                       }
+               }
+               mutex_unlock(&priv->mutex);
+       }
+}
+
+/* Card State Notification indicated reach critical temperature
+ * if PSP not enable, no Thermal Throttling function will be performed
+ * just set the GP1 bit to acknowledge the event
+ * otherwise, go into IWL_TI_CT_KILL state
+ * since Card State Notification will not provide any temperature reading
+ * for Legacy mode
+ * so just pass the CT_KILL temperature to iwl_legacy_tt_handler()
+ * for advance mode
+ * pass CT_KILL_THRESHOLD+1 to make sure move into IWL_TI_CT_KILL state
+ */
+static void iwl_bg_ct_enter(struct work_struct *work)
+{
+       struct iwl_priv *priv = container_of(work, struct iwl_priv, ct_enter);
+       struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
+
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+               return;
+
+       if (!iwl_is_ready(priv))
+               return;
+
+       if (tt->state != IWL_TI_CT_KILL) {
+               IWL_ERR(priv, "Device reached critical temperature "
+                             "- ucode going to sleep!\n");
+               if (!priv->thermal_throttle.advanced_tt)
+                       iwl_legacy_tt_handler(priv,
+                                             IWL_MINIMAL_POWER_THRESHOLD,
+                                             true);
+               else
+                       iwl_advance_tt_handler(priv,
+                                              CT_KILL_THRESHOLD + 1, true);
+       }
+}
+
+/* Card State Notification indicated out of critical temperature
+ * since Card State Notification will not provide any temperature reading
+ * so pass the IWL_REDUCED_PERFORMANCE_THRESHOLD_2 temperature
+ * to iwl_legacy_tt_handler() to get out of IWL_CT_KILL state
+ */
+static void iwl_bg_ct_exit(struct work_struct *work)
+{
+       struct iwl_priv *priv = container_of(work, struct iwl_priv, ct_exit);
+       struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
+
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+               return;
+
+       if (!iwl_is_ready(priv))
+               return;
+
+       /* stop ct_kill_exit_tm timer */
+       del_timer_sync(&priv->thermal_throttle.ct_kill_exit_tm);
+
+       if (tt->state == IWL_TI_CT_KILL) {
+               IWL_ERR(priv,
+                       "Device temperature below critical"
+                       "- ucode awake!\n");
+               /*
+                * exit from CT_KILL state
+                * reset the current temperature reading
+                */
+               priv->temperature = 0;
+               if (!priv->thermal_throttle.advanced_tt)
+                       iwl_legacy_tt_handler(priv,
+                                     IWL_REDUCED_PERFORMANCE_THRESHOLD_2,
+                                     true);
+               else
+                       iwl_advance_tt_handler(priv, CT_KILL_EXIT_THRESHOLD,
+                                              true);
+       }
+}
+
+void iwl_tt_enter_ct_kill(struct iwl_priv *priv)
+{
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+               return;
+
+       IWL_DEBUG_POWER(priv, "Queueing critical temperature enter.\n");
+       queue_work(priv->workqueue, &priv->ct_enter);
+}
+EXPORT_SYMBOL(iwl_tt_enter_ct_kill);
+
+void iwl_tt_exit_ct_kill(struct iwl_priv *priv)
+{
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+               return;
+
+       IWL_DEBUG_POWER(priv, "Queueing critical temperature exit.\n");
+       queue_work(priv->workqueue, &priv->ct_exit);
+}
+EXPORT_SYMBOL(iwl_tt_exit_ct_kill);
+
+static void iwl_bg_tt_work(struct work_struct *work)
+{
+       struct iwl_priv *priv = container_of(work, struct iwl_priv, tt_work);
+       s32 temp = priv->temperature; /* degrees CELSIUS except specified */
+
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+               return;
+
+       if (priv->cfg->temperature_kelvin)
+               temp = KELVIN_TO_CELSIUS(priv->temperature);
+
+       if (!priv->thermal_throttle.advanced_tt)
+               iwl_legacy_tt_handler(priv, temp, false);
+       else
+               iwl_advance_tt_handler(priv, temp, false);
+}
+
+void iwl_tt_handler(struct iwl_priv *priv)
+{
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+               return;
+
+       IWL_DEBUG_POWER(priv, "Queueing thermal throttling work.\n");
+       queue_work(priv->workqueue, &priv->tt_work);
+}
+EXPORT_SYMBOL(iwl_tt_handler);
+
+/* Thermal throttling initialization
+ * For advance thermal throttling:
+ *     Initialize Thermal Index and temperature threshold table
+ *     Initialize thermal throttling restriction table
+ */
+void iwl_tt_initialize(struct iwl_priv *priv)
+{
+       struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
+       int size = sizeof(struct iwl_tt_trans) * (IWL_TI_STATE_MAX - 1);
+       struct iwl_tt_trans *transaction;
+
+       IWL_DEBUG_POWER(priv, "Initialize Thermal Throttling\n");
+
+       memset(tt, 0, sizeof(struct iwl_tt_mgmt));
+
+       tt->state = IWL_TI_0;
+       init_timer(&priv->thermal_throttle.ct_kill_exit_tm);
+       priv->thermal_throttle.ct_kill_exit_tm.data = (unsigned long)priv;
+       priv->thermal_throttle.ct_kill_exit_tm.function =
+               iwl_tt_check_exit_ct_kill;
+       init_timer(&priv->thermal_throttle.ct_kill_waiting_tm);
+       priv->thermal_throttle.ct_kill_waiting_tm.data =
+               (unsigned long)priv;
+       priv->thermal_throttle.ct_kill_waiting_tm.function =
+               iwl_tt_ready_for_ct_kill;
+       /* setup deferred ct kill work */
+       INIT_WORK(&priv->tt_work, iwl_bg_tt_work);
+       INIT_WORK(&priv->ct_enter, iwl_bg_ct_enter);
+       INIT_WORK(&priv->ct_exit, iwl_bg_ct_exit);
+
+       if (priv->cfg->adv_thermal_throttle) {
+               IWL_DEBUG_POWER(priv, "Advanced Thermal Throttling\n");
+               tt->restriction = kzalloc(sizeof(struct iwl_tt_restriction) *
+                                        IWL_TI_STATE_MAX, GFP_KERNEL);
+               tt->transaction = kzalloc(sizeof(struct iwl_tt_trans) *
+                       IWL_TI_STATE_MAX * (IWL_TI_STATE_MAX - 1),
+                       GFP_KERNEL);
+               if (!tt->restriction || !tt->transaction) {
+                       IWL_ERR(priv, "Fallback to Legacy Throttling\n");
+                       priv->thermal_throttle.advanced_tt = false;
+                       kfree(tt->restriction);
+                       tt->restriction = NULL;
+                       kfree(tt->transaction);
+                       tt->transaction = NULL;
+               } else {
+                       transaction = tt->transaction +
+                               (IWL_TI_0 * (IWL_TI_STATE_MAX - 1));
+                       memcpy(transaction, &tt_range_0[0], size);
+                       transaction = tt->transaction +
+                               (IWL_TI_1 * (IWL_TI_STATE_MAX - 1));
+                       memcpy(transaction, &tt_range_1[0], size);
+                       transaction = tt->transaction +
+                               (IWL_TI_2 * (IWL_TI_STATE_MAX - 1));
+                       memcpy(transaction, &tt_range_2[0], size);
+                       transaction = tt->transaction +
+                               (IWL_TI_CT_KILL * (IWL_TI_STATE_MAX - 1));
+                       memcpy(transaction, &tt_range_3[0], size);
+                       size = sizeof(struct iwl_tt_restriction) *
+                               IWL_TI_STATE_MAX;
+                       memcpy(tt->restriction,
+                               &restriction_range[0], size);
+                       priv->thermal_throttle.advanced_tt = true;
+               }
+       } else {
+               IWL_DEBUG_POWER(priv, "Legacy Thermal Throttling\n");
+               priv->thermal_throttle.advanced_tt = false;
+       }
+}
+EXPORT_SYMBOL(iwl_tt_initialize);
+
+/* cleanup thermal throttling management related memory and timer */
+void iwl_tt_exit(struct iwl_priv *priv)
+{
+       struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
+
+       /* stop ct_kill_exit_tm timer if activated */
+       del_timer_sync(&priv->thermal_throttle.ct_kill_exit_tm);
+       /* stop ct_kill_waiting_tm timer if activated */
+       del_timer_sync(&priv->thermal_throttle.ct_kill_waiting_tm);
+       cancel_work_sync(&priv->tt_work);
+       cancel_work_sync(&priv->ct_enter);
+       cancel_work_sync(&priv->ct_exit);
+
+       if (priv->thermal_throttle.advanced_tt) {
+               /* free advance thermal throttling memory */
+               kfree(tt->restriction);
+               tt->restriction = NULL;
+               kfree(tt->transaction);
+               tt->transaction = NULL;
+       }
+}
+EXPORT_SYMBOL(iwl_tt_exit);
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tt.h b/drivers/net/wireless/iwlwifi/iwl-agn-tt.h
new file mode 100644 (file)
index 0000000..d550604
--- /dev/null
@@ -0,0 +1,129 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ipw3945 project, as well
+ * as portions of the ieee80211 subsystem header files.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *****************************************************************************/
+#ifndef __iwl_tt_setting_h__
+#define __iwl_tt_setting_h__
+
+#include "iwl-commands.h"
+
+#define IWL_ABSOLUTE_ZERO              0
+#define IWL_ABSOLUTE_MAX               0xFFFFFFFF
+#define IWL_TT_INCREASE_MARGIN 5
+#define IWL_TT_CT_KILL_MARGIN  3
+
+enum iwl_antenna_ok {
+       IWL_ANT_OK_NONE,
+       IWL_ANT_OK_SINGLE,
+       IWL_ANT_OK_MULTI,
+};
+
+/* Thermal Throttling State Machine states */
+enum  iwl_tt_state {
+       IWL_TI_0,       /* normal temperature, system power state */
+       IWL_TI_1,       /* high temperature detect, low power state */
+       IWL_TI_2,       /* higher temperature detected, lower power state */
+       IWL_TI_CT_KILL, /* critical temperature detected, lowest power state */
+       IWL_TI_STATE_MAX
+};
+
+/**
+ * struct iwl_tt_restriction - Thermal Throttling restriction table
+ * @tx_stream: number of tx stream allowed
+ * @is_ht: ht enable/disable
+ * @rx_stream: number of rx stream allowed
+ *
+ * This table is used by advance thermal throttling management
+ * based on the current thermal throttling state, and determines
+ * the number of tx/rx streams and the status of HT operation.
+ */
+struct iwl_tt_restriction {
+       enum iwl_antenna_ok tx_stream;
+       enum iwl_antenna_ok rx_stream;
+       bool is_ht;
+};
+
+/**
+ * struct iwl_tt_trans - Thermal Throttling transaction table
+ * @next_state:  next thermal throttling mode
+ * @tt_low: low temperature threshold to change state
+ * @tt_high: high temperature threshold to change state
+ *
+ * This is used by the advanced thermal throttling algorithm
+ * to determine the next thermal state to go based on the
+ * current temperature.
+ */
+struct iwl_tt_trans {
+       enum iwl_tt_state next_state;
+       u32 tt_low;
+       u32 tt_high;
+};
+
+/**
+ * struct iwl_tt_mgnt - Thermal Throttling Management structure
+ * @advanced_tt:    advanced thermal throttle required
+ * @state:          current Thermal Throttling state
+ * @tt_power_mode:  Thermal Throttling power mode index
+ *                 being used to set power level when
+ *                 when thermal throttling state != IWL_TI_0
+ *                 the tt_power_mode should set to different
+ *                 power mode based on the current tt state
+ * @tt_previous_temperature: last measured temperature
+ * @iwl_tt_restriction: ptr to restriction tbl, used by advance
+ *                 thermal throttling to determine how many tx/rx streams
+ *                 should be used in tt state; and can HT be enabled or not
+ * @iwl_tt_trans: ptr to adv trans table, used by advance thermal throttling
+ *                 state transaction
+ * @ct_kill_toggle: used to toggle the CSR bit when checking uCode temperature
+ * @ct_kill_exit_tm: timer to exit thermal kill
+ */
+struct iwl_tt_mgmt {
+       enum iwl_tt_state state;
+       bool advanced_tt;
+       u8 tt_power_mode;
+       bool ct_kill_toggle;
+#ifdef CONFIG_IWLWIFI_DEBUG
+       s32 tt_previous_temp;
+#endif
+       struct iwl_tt_restriction *restriction;
+       struct iwl_tt_trans *transaction;
+       struct timer_list ct_kill_exit_tm;
+       struct timer_list ct_kill_waiting_tm;
+};
+
+u8 iwl_tt_current_power_mode(struct iwl_priv *priv);
+bool iwl_tt_is_low_power_state(struct iwl_priv *priv);
+bool iwl_ht_enabled(struct iwl_priv *priv);
+bool iwl_check_for_ct_kill(struct iwl_priv *priv);
+enum iwl_antenna_ok iwl_tx_ant_restriction(struct iwl_priv *priv);
+enum iwl_antenna_ok iwl_rx_ant_restriction(struct iwl_priv *priv);
+void iwl_tt_enter_ct_kill(struct iwl_priv *priv);
+void iwl_tt_exit_ct_kill(struct iwl_priv *priv);
+void iwl_tt_handler(struct iwl_priv *priv);
+void iwl_tt_initialize(struct iwl_priv *priv);
+void iwl_tt_exit(struct iwl_priv *priv);
+
+#endif  /* __iwl_tt_setting_h__ */
index 69155aa448fb80f8c042b212567679b905e20513..5950184d98606a4f997bc5b027b5ddd21b6db7f8 100644 (file)
@@ -71,18 +71,6 @@ static const u8 tid_to_ac[] = {
        2, 3, 3, 2, 1, 1, 0, 0
 };
 
-static const u8 ac_to_fifo[] = {
-       IWL_TX_FIFO_VO,
-       IWL_TX_FIFO_VI,
-       IWL_TX_FIFO_BE,
-       IWL_TX_FIFO_BK,
-};
-
-static inline int get_fifo_from_ac(u8 ac)
-{
-       return ac_to_fifo[ac];
-}
-
 static inline int get_ac_from_tid(u16 tid)
 {
        if (likely(tid < ARRAY_SIZE(tid_to_ac)))
@@ -92,10 +80,10 @@ static inline int get_ac_from_tid(u16 tid)
        return -EINVAL;
 }
 
-static inline int get_fifo_from_tid(u16 tid)
+static inline int get_fifo_from_tid(struct iwl_rxon_context *ctx, u16 tid)
 {
        if (likely(tid < ARRAY_SIZE(tid_to_ac)))
-               return get_fifo_from_ac(tid_to_ac[tid]);
+               return ctx->ac_to_fifo[tid_to_ac[tid]];
 
        /* no support for TIDs 8-15 yet */
        return -EINVAL;
@@ -118,7 +106,7 @@ void iwlagn_txq_update_byte_cnt_tbl(struct iwl_priv *priv,
 
        WARN_ON(len > 0xFFF || write_ptr >= TFD_QUEUE_SIZE_MAX);
 
-       if (txq_id != IWL_CMD_QUEUE_NUM) {
+       if (txq_id != priv->cmd_queue) {
                sta_id = txq->cmd[txq->q.write_ptr]->cmd.tx.sta_id;
                sec_ctl = txq->cmd[txq->q.write_ptr]->cmd.tx.sec_ctl;
 
@@ -155,7 +143,7 @@ void iwlagn_txq_inval_byte_cnt_tbl(struct iwl_priv *priv,
 
        WARN_ON(read_ptr >= TFD_QUEUE_SIZE_MAX);
 
-       if (txq_id != IWL_CMD_QUEUE_NUM)
+       if (txq_id != priv->cmd_queue)
                sta_id = txq->cmd[read_ptr]->cmd.tx.sta_id;
 
        bc_ent = cpu_to_le16(1 | (sta_id << 12));
@@ -333,19 +321,15 @@ void iwlagn_txq_set_sched(struct iwl_priv *priv, u32 mask)
        iwl_write_prph(priv, IWLAGN_SCD_TXFACT, mask);
 }
 
-static inline int get_queue_from_ac(u16 ac)
-{
-       return ac;
-}
-
 /*
  * handle build REPLY_TX command notification.
  */
 static void iwlagn_tx_cmd_build_basic(struct iwl_priv *priv,
-                                 struct iwl_tx_cmd *tx_cmd,
-                                 struct ieee80211_tx_info *info,
-                                 struct ieee80211_hdr *hdr,
-                                 u8 std_id)
+                                       struct sk_buff *skb,
+                                       struct iwl_tx_cmd *tx_cmd,
+                                       struct ieee80211_tx_info *info,
+                                       struct ieee80211_hdr *hdr,
+                                       u8 std_id)
 {
        __le16 fc = hdr->frame_control;
        __le32 tx_flags = tx_cmd->tx_flags;
@@ -365,6 +349,12 @@ static void iwlagn_tx_cmd_build_basic(struct iwl_priv *priv,
 
        if (ieee80211_is_back_req(fc))
                tx_flags |= TX_CMD_FLG_ACK_MSK | TX_CMD_FLG_IMM_BA_RSP_MASK;
+       else if (info->band == IEEE80211_BAND_2GHZ &&
+                priv->cfg->advanced_bt_coexist &&
+                (ieee80211_is_auth(fc) || ieee80211_is_assoc_req(fc) ||
+                ieee80211_is_reassoc_req(fc) ||
+                skb->protocol == cpu_to_be16(ETH_P_PAE)))
+               tx_flags |= TX_CMD_FLG_IGNORE_BT;
 
 
        tx_cmd->sta_id = std_id;
@@ -454,7 +444,12 @@ static void iwlagn_tx_cmd_build_rate(struct iwl_priv *priv,
                rate_flags |= RATE_MCS_CCK_MSK;
 
        /* Set up antennas */
-       priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant,
+        if (priv->cfg->advanced_bt_coexist && priv->bt_full_concurrent) {
+               /* operated as 1x1 in full concurrency mode */
+               priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant,
+                               first_antenna(priv->hw_params.valid_tx_ant));
+       } else
+               priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant,
                                              priv->hw_params.valid_tx_ant);
        rate_flags |= iwl_ant_idx_to_flags(priv->mgmt_tx_ant);
 
@@ -470,8 +465,8 @@ static void iwlagn_tx_cmd_build_hwcrypto(struct iwl_priv *priv,
 {
        struct ieee80211_key_conf *keyconf = info->control.hw_key;
 
-       switch (keyconf->alg) {
-       case ALG_CCMP:
+       switch (keyconf->cipher) {
+       case WLAN_CIPHER_SUITE_CCMP:
                tx_cmd->sec_ctl = TX_CMD_SEC_CCM;
                memcpy(tx_cmd->key, keyconf->key, keyconf->keylen);
                if (info->flags & IEEE80211_TX_CTL_AMPDU)
@@ -479,20 +474,20 @@ static void iwlagn_tx_cmd_build_hwcrypto(struct iwl_priv *priv,
                IWL_DEBUG_TX(priv, "tx_cmd with AES hwcrypto\n");
                break;
 
-       case ALG_TKIP:
+       case WLAN_CIPHER_SUITE_TKIP:
                tx_cmd->sec_ctl = TX_CMD_SEC_TKIP;
                ieee80211_get_tkip_key(keyconf, skb_frag,
                        IEEE80211_TKIP_P2_KEY, tx_cmd->key);
                IWL_DEBUG_TX(priv, "tx_cmd with tkip hwcrypto\n");
                break;
 
-       case ALG_WEP:
+       case WLAN_CIPHER_SUITE_WEP104:
+               tx_cmd->sec_ctl |= TX_CMD_SEC_KEY128;
+               /* fall through */
+       case WLAN_CIPHER_SUITE_WEP40:
                tx_cmd->sec_ctl |= (TX_CMD_SEC_WEP |
                        (keyconf->keyidx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT);
 
-               if (keyconf->keylen == WEP_KEY_LEN_128)
-                       tx_cmd->sec_ctl |= TX_CMD_SEC_KEY128;
-
                memcpy(&tx_cmd->key[3], keyconf->key, keyconf->keylen);
 
                IWL_DEBUG_TX(priv, "Configuring packet for WEP encryption "
@@ -500,7 +495,7 @@ static void iwlagn_tx_cmd_build_hwcrypto(struct iwl_priv *priv,
                break;
 
        default:
-               IWL_ERR(priv, "Unknown encode alg %d\n", keyconf->alg);
+               IWL_ERR(priv, "Unknown encode cipher %x\n", keyconf->cipher);
                break;
        }
 }
@@ -519,6 +514,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
        struct iwl_device_cmd *out_cmd;
        struct iwl_cmd_meta *out_meta;
        struct iwl_tx_cmd *tx_cmd;
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
        int swq_id, txq_id;
        dma_addr_t phys_addr;
        dma_addr_t txcmd_phys;
@@ -533,6 +529,9 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
        u8 *qc = NULL;
        unsigned long flags;
 
+       if (info->control.vif)
+               ctx = iwl_rxon_ctx_from_vif(info->control.vif);
+
        spin_lock_irqsave(&priv->lock, flags);
        if (iwl_is_rfkill(priv)) {
                IWL_DEBUG_DROP(priv, "Dropping - RF KILL\n");
@@ -553,7 +552,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
        hdr_len = ieee80211_hdrlen(fc);
 
        /* Find index into station table for destination station */
-       sta_id = iwl_sta_id_or_broadcast(priv, info->control.sta);
+       sta_id = iwl_sta_id_or_broadcast(priv, ctx, info->control.sta);
        if (sta_id == IWL_INVALID_STATION) {
                IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n",
                               hdr->addr1);
@@ -565,8 +564,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
        if (sta)
                sta_priv = (void *)sta->drv_priv;
 
-       if (sta_priv && sta_id != priv->hw_params.bcast_sta_id &&
-           sta_priv->asleep) {
+       if (sta_priv && sta_priv->asleep) {
                WARN_ON(!(info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE));
                /*
                 * This sends an asynchronous command to the device,
@@ -580,7 +578,20 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
                iwl_sta_modify_sleep_tx_count(priv, sta_id, 1);
        }
 
-       txq_id = get_queue_from_ac(skb_get_queue_mapping(skb));
+       /*
+        * Send this frame after DTIM -- there's a special queue
+        * reserved for this for contexts that support AP mode.
+        */
+       if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) {
+               txq_id = ctx->mcast_queue;
+               /*
+                * The microcode will clear the more data
+                * bit in the last frame it transmits.
+                */
+               hdr->frame_control |=
+                       cpu_to_le16(IEEE80211_FCTL_MOREDATA);
+       } else
+               txq_id = ctx->ac_to_queue[skb_get_queue_mapping(skb)];
 
        /* irqs already disabled/saved above when locking priv->lock */
        spin_lock(&priv->sta_lock);
@@ -625,6 +636,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
        /* Set up driver data for this TFD */
        memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl_tx_info));
        txq->txb[q->write_ptr].skb = skb;
+       txq->txb[q->write_ptr].ctx = ctx;
 
        /* Set up first empty entry in queue's array of Tx/cmd buffers */
        out_cmd = txq->cmd[q->write_ptr];
@@ -655,7 +667,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
                iwlagn_tx_cmd_build_hwcrypto(priv, info, tx_cmd, skb, sta_id);
 
        /* TODO need this for burst mode later on */
-       iwlagn_tx_cmd_build_basic(priv, tx_cmd, info, hdr, sta_id);
+       iwlagn_tx_cmd_build_basic(priv, skb, tx_cmd, info, hdr, sta_id);
        iwl_dbg_log_tx_data_frame(priv, len, hdr);
 
        iwlagn_tx_cmd_build_rate(priv, tx_cmd, info, fc);
@@ -813,7 +825,7 @@ void iwlagn_hw_txq_ctx_free(struct iwl_priv *priv)
        /* Tx queues */
        if (priv->txq) {
                for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++)
-                       if (txq_id == IWL_CMD_QUEUE_NUM)
+                       if (txq_id == priv->cmd_queue)
                                iwl_cmd_queue_free(priv);
                        else
                                iwl_tx_queue_free(priv, txq_id);
@@ -870,9 +882,9 @@ int iwlagn_txq_ctx_alloc(struct iwl_priv *priv)
 
        spin_unlock_irqrestore(&priv->lock, flags);
 
-       /* Alloc and init all Tx queues, including the command queue (#4) */
+       /* Alloc and init all Tx queues, including the command queue (#4/#9) */
        for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
-               slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ?
+               slots_num = (txq_id == priv->cmd_queue) ?
                                        TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
                ret = iwl_tx_queue_init(priv, &priv->txq[txq_id], slots_num,
                                       txq_id);
@@ -910,7 +922,7 @@ void iwlagn_txq_ctx_reset(struct iwl_priv *priv)
 
        /* Alloc and init all Tx queues, including the command queue (#4) */
        for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
-               slots_num = txq_id == IWL_CMD_QUEUE_NUM ?
+               slots_num = txq_id == priv->cmd_queue ?
                            TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
                iwl_tx_queue_reset(priv, &priv->txq[txq_id], slots_num, txq_id);
        }
@@ -968,7 +980,7 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif,
        unsigned long flags;
        struct iwl_tid_data *tid_data;
 
-       tx_fifo = get_fifo_from_tid(tid);
+       tx_fifo = get_fifo_from_tid(iwl_rxon_ctx_from_vif(vif), tid);
        if (unlikely(tx_fifo < 0))
                return tx_fifo;
 
@@ -1024,12 +1036,12 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif,
 int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
                       struct ieee80211_sta *sta, u16 tid)
 {
-       int tx_fifo_id, txq_id, sta_id, ssn = -1;
+       int tx_fifo_id, txq_id, sta_id, ssn;
        struct iwl_tid_data *tid_data;
        int write_ptr, read_ptr;
        unsigned long flags;
 
-       tx_fifo_id = get_fifo_from_tid(tid);
+       tx_fifo_id = get_fifo_from_tid(iwl_rxon_ctx_from_vif(vif), tid);
        if (unlikely(tx_fifo_id < 0))
                return tx_fifo_id;
 
@@ -1042,21 +1054,26 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
 
        spin_lock_irqsave(&priv->sta_lock, flags);
 
-       if (priv->stations[sta_id].tid[tid].agg.state ==
-                               IWL_EMPTYING_HW_QUEUE_ADDBA) {
-               IWL_DEBUG_HT(priv, "AGG stop before setup done\n");
-               ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
-               priv->stations[sta_id].tid[tid].agg.state = IWL_AGG_OFF;
-               spin_unlock_irqrestore(&priv->sta_lock, flags);
-               return 0;
-       }
-
-       if (priv->stations[sta_id].tid[tid].agg.state != IWL_AGG_ON)
-               IWL_WARN(priv, "Stopping AGG while state not ON or starting\n");
-
        tid_data = &priv->stations[sta_id].tid[tid];
        ssn = (tid_data->seq_number & IEEE80211_SCTL_SEQ) >> 4;
        txq_id = tid_data->agg.txq_id;
+
+       switch (priv->stations[sta_id].tid[tid].agg.state) {
+       case IWL_EMPTYING_HW_QUEUE_ADDBA:
+               /*
+                * This can happen if the peer stops aggregation
+                * again before we've had a chance to drain the
+                * queue we selected previously, i.e. before the
+                * session was really started completely.
+                */
+               IWL_DEBUG_HT(priv, "AGG stop before setup done\n");
+               goto turn_off;
+       case IWL_AGG_ON:
+               break;
+       default:
+               IWL_WARN(priv, "Stopping AGG while state not ON or starting\n");
+       }
+
        write_ptr = priv->txq[txq_id].q.write_ptr;
        read_ptr = priv->txq[txq_id].q.read_ptr;
 
@@ -1070,6 +1087,7 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
        }
 
        IWL_DEBUG_HT(priv, "HW queue is empty\n");
+ turn_off:
        priv->stations[sta_id].tid[tid].agg.state = IWL_AGG_OFF;
 
        /* do not restore/save irqs */
@@ -1098,6 +1116,9 @@ int iwlagn_txq_check_empty(struct iwl_priv *priv,
        struct iwl_queue *q = &priv->txq[txq_id].q;
        u8 *addr = priv->stations[sta_id].sta.sta.addr;
        struct iwl_tid_data *tid_data = &priv->stations[sta_id].tid[tid];
+       struct iwl_rxon_context *ctx;
+
+       ctx = &priv->contexts[priv->stations[sta_id].ctxid];
 
        lockdep_assert_held(&priv->sta_lock);
 
@@ -1108,12 +1129,12 @@ int iwlagn_txq_check_empty(struct iwl_priv *priv,
                if ((txq_id  == tid_data->agg.txq_id) &&
                    (q->read_ptr == q->write_ptr)) {
                        u16 ssn = SEQ_TO_SN(tid_data->seq_number);
-                       int tx_fifo = get_fifo_from_tid(tid);
+                       int tx_fifo = get_fifo_from_tid(ctx, tid);
                        IWL_DEBUG_HT(priv, "HW queue empty: continue DELBA flow\n");
                        priv->cfg->ops->lib->txq_agg_disable(priv, txq_id,
                                                             ssn, tx_fifo);
                        tid_data->agg.state = IWL_AGG_OFF;
-                       ieee80211_stop_tx_ba_cb_irqsafe(priv->vif, addr, tid);
+                       ieee80211_stop_tx_ba_cb_irqsafe(ctx->vif, addr, tid);
                }
                break;
        case IWL_EMPTYING_HW_QUEUE_ADDBA:
@@ -1121,7 +1142,7 @@ int iwlagn_txq_check_empty(struct iwl_priv *priv,
                if (tid_data->tfds_in_queue == 0) {
                        IWL_DEBUG_HT(priv, "HW queue empty: continue ADDBA flow\n");
                        tid_data->agg.state = IWL_AGG_ON;
-                       ieee80211_start_tx_ba_cb_irqsafe(priv->vif, addr, tid);
+                       ieee80211_start_tx_ba_cb_irqsafe(ctx->vif, addr, tid);
                }
                break;
        }
@@ -1129,14 +1150,14 @@ int iwlagn_txq_check_empty(struct iwl_priv *priv,
        return 0;
 }
 
-static void iwlagn_tx_status(struct iwl_priv *priv, struct sk_buff *skb)
+static void iwlagn_tx_status(struct iwl_priv *priv, struct iwl_tx_info *tx_info)
 {
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx_info->skb->data;
        struct ieee80211_sta *sta;
        struct iwl_station_priv *sta_priv;
 
        rcu_read_lock();
-       sta = ieee80211_find_sta(priv->vif, hdr->addr1);
+       sta = ieee80211_find_sta(tx_info->ctx->vif, hdr->addr1);
        if (sta) {
                sta_priv = (void *)sta->drv_priv;
                /* avoid atomic ops if this isn't a client */
@@ -1146,7 +1167,7 @@ static void iwlagn_tx_status(struct iwl_priv *priv, struct sk_buff *skb)
        }
        rcu_read_unlock();
 
-       ieee80211_tx_status_irqsafe(priv->hw, skb);
+       ieee80211_tx_status_irqsafe(priv->hw, tx_info->skb);
 }
 
 int iwlagn_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index)
@@ -1169,7 +1190,7 @@ int iwlagn_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index)
             q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
 
                tx_info = &txq->txb[txq->q.read_ptr];
-               iwlagn_tx_status(priv, tx_info->skb);
+               iwlagn_tx_status(priv, tx_info);
 
                hdr = (struct ieee80211_hdr *)tx_info->skb->data;
                if (hdr && ieee80211_is_data_qos(hdr->frame_control))
index 6f77441cb65a3f734260e23b1a38a08574d4a668..a7961bf395fcfddb1fd5bc9c4bd7a63260e16424 100644 (file)
@@ -52,6 +52,19 @@ static const s8 iwlagn_default_queue_to_tx_fifo[] = {
        IWL_TX_FIFO_UNUSED,
 };
 
+static const s8 iwlagn_ipan_queue_to_tx_fifo[] = {
+       IWL_TX_FIFO_VO,
+       IWL_TX_FIFO_VI,
+       IWL_TX_FIFO_BE,
+       IWL_TX_FIFO_BK,
+       IWL_TX_FIFO_BK_IPAN,
+       IWL_TX_FIFO_BE_IPAN,
+       IWL_TX_FIFO_VI_IPAN,
+       IWL_TX_FIFO_VO_IPAN,
+       IWL_TX_FIFO_BE_IPAN,
+       IWLAGN_CMD_FIFO_NUM,
+};
+
 static struct iwl_wimax_coex_event_entry cu_priorities[COEX_NUM_OF_EVENTS] = {
        {COEX_CU_UNASSOC_IDLE_RP, COEX_CU_UNASSOC_IDLE_WP,
         0, COEX_UNASSOC_IDLE_FLAGS},
@@ -329,8 +342,54 @@ static int iwlagn_send_wimax_coex(struct iwl_priv *priv)
                                sizeof(coex_cmd), &coex_cmd);
 }
 
+static const u8 iwlagn_bt_prio_tbl[BT_COEX_PRIO_TBL_EVT_MAX] = {
+       ((BT_COEX_PRIO_TBL_PRIO_BYPASS << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
+               (0 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
+       ((BT_COEX_PRIO_TBL_PRIO_BYPASS << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
+               (1 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
+       ((BT_COEX_PRIO_TBL_PRIO_LOW << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
+               (0 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
+       ((BT_COEX_PRIO_TBL_PRIO_LOW << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
+               (1 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
+       ((BT_COEX_PRIO_TBL_PRIO_HIGH << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
+               (0 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
+       ((BT_COEX_PRIO_TBL_PRIO_HIGH << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
+               (1 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
+       ((BT_COEX_PRIO_TBL_PRIO_BYPASS << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
+               (0 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
+       ((BT_COEX_PRIO_TBL_PRIO_COEX_OFF << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
+               (0 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
+       ((BT_COEX_PRIO_TBL_PRIO_COEX_ON << IWL_BT_COEX_PRIO_TBL_PRIO_POS) |
+               (0 << IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS)),
+       0, 0, 0, 0, 0, 0, 0
+};
+
+static void iwlagn_send_prio_tbl(struct iwl_priv *priv)
+{
+       struct iwl_bt_coex_prio_table_cmd prio_tbl_cmd;
+
+       memcpy(prio_tbl_cmd.prio_tbl, iwlagn_bt_prio_tbl,
+               sizeof(iwlagn_bt_prio_tbl));
+       if (iwl_send_cmd_pdu(priv, REPLY_BT_COEX_PRIO_TABLE,
+                               sizeof(prio_tbl_cmd), &prio_tbl_cmd))
+               IWL_ERR(priv, "failed to send BT prio tbl command\n");
+}
+
+static void iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type)
+{
+       struct iwl_bt_coex_prot_env_cmd env_cmd;
+
+       env_cmd.action = action;
+       env_cmd.type = type;
+       if (iwl_send_cmd_pdu(priv, REPLY_BT_COEX_PROT_ENV,
+                            sizeof(env_cmd), &env_cmd))
+               IWL_ERR(priv, "failed to send BT env command\n");
+}
+
+
 int iwlagn_alive_notify(struct iwl_priv *priv)
 {
+       const s8 *queues;
        u32 a;
        unsigned long flags;
        int i, chan;
@@ -365,7 +424,7 @@ int iwlagn_alive_notify(struct iwl_priv *priv)
                           reg_val | FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN);
 
        iwl_write_prph(priv, IWLAGN_SCD_QUEUECHAIN_SEL,
-               IWLAGN_SCD_QUEUECHAIN_SEL_ALL(priv->hw_params.max_txq_num));
+               IWLAGN_SCD_QUEUECHAIN_SEL_ALL(priv));
        iwl_write_prph(priv, IWLAGN_SCD_AGGR_SEL, 0);
 
        /* initiate the queues */
@@ -391,7 +450,13 @@ int iwlagn_alive_notify(struct iwl_priv *priv)
        /* Activate all Tx DMA/FIFO channels */
        priv->cfg->ops->lib->txq_set_sched(priv, IWL_MASK(0, 7));
 
-       iwlagn_set_wr_ptrs(priv, IWL_CMD_QUEUE_NUM, 0);
+       /* map queues to FIFOs */
+       if (priv->valid_contexts != BIT(IWL_RXON_CTX_BSS))
+               queues = iwlagn_ipan_queue_to_tx_fifo;
+       else
+               queues = iwlagn_default_queue_to_tx_fifo;
+
+       iwlagn_set_wr_ptrs(priv, priv->cmd_queue, 0);
 
        /* make sure all queue are not stopped */
        memset(&priv->queue_stopped[0], 0, sizeof(priv->queue_stopped));
@@ -400,11 +465,12 @@ int iwlagn_alive_notify(struct iwl_priv *priv)
 
        /* reset to 0 to enable all the queue first */
        priv->txq_ctx_active_msk = 0;
-       /* map qos queues to fifos one-to-one */
+
        BUILD_BUG_ON(ARRAY_SIZE(iwlagn_default_queue_to_tx_fifo) != 10);
+       BUILD_BUG_ON(ARRAY_SIZE(iwlagn_ipan_queue_to_tx_fifo) != 10);
 
-       for (i = 0; i < ARRAY_SIZE(iwlagn_default_queue_to_tx_fifo); i++) {
-               int ac = iwlagn_default_queue_to_tx_fifo[i];
+       for (i = 0; i < 10; i++) {
+               int ac = queues[i];
 
                iwl_txq_ctx_activate(priv, i);
 
@@ -416,6 +482,25 @@ int iwlagn_alive_notify(struct iwl_priv *priv)
 
        spin_unlock_irqrestore(&priv->lock, flags);
 
+       if (priv->cfg->advanced_bt_coexist) {
+               /* Configure Bluetooth device coexistence support */
+               /* need to perform this before any calibration */
+               priv->bt_valid = IWLAGN_BT_ALL_VALID_MSK;
+               priv->kill_ack_mask = IWLAGN_BT_KILL_ACK_MASK_DEFAULT;
+               priv->kill_cts_mask = IWLAGN_BT_KILL_CTS_MASK_DEFAULT;
+               priv->cfg->ops->hcmd->send_bt_config(priv);
+               priv->bt_valid = IWLAGN_BT_VALID_ENABLE_FLAGS;
+
+               if (bt_coex_active && priv->iw_mode != NL80211_IFTYPE_ADHOC) {
+                       iwlagn_send_prio_tbl(priv);
+                       iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_OPEN,
+                               BT_COEX_PRIO_TBL_EVT_INIT_CALIB2);
+                       iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_CLOSE,
+                               BT_COEX_PRIO_TBL_EVT_INIT_CALIB2);
+               }
+
+       }
+
        iwlagn_send_wimax_coex(priv);
 
        iwlagn_set_Xtal_calib(priv);
index 10d7b9b7f064f529af9d0cdc6aa2b0a144d9438d..ad0e67f5c0d41d7188ae86f37b78cb5f4263ccda 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/pci.h>
+#include <linux/pci-aspm.h>
 #include <linux/slab.h>
 #include <linux/dma-mapping.h>
 #include <linux/delay.h>
@@ -86,6 +87,9 @@ MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR);
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("iwl4965");
 
+static int iwlagn_ant_coupling;
+static bool iwlagn_bt_ch_announce = 1;
+
 /**
  * iwl_commit_rxon - commit staging_rxon to hardware
  *
@@ -94,21 +98,22 @@ MODULE_ALIAS("iwl4965");
  * function correctly transitions out of the RXON_ASSOC_MSK state if
  * a HW tune is required based on the RXON structure changes.
  */
-int iwl_commit_rxon(struct iwl_priv *priv)
+int iwl_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
 {
        /* cast away the const for active_rxon in this function */
-       struct iwl_rxon_cmd *active_rxon = (void *)&priv->active_rxon;
+       struct iwl_rxon_cmd *active_rxon = (void *)&ctx->active;
        int ret;
        bool new_assoc =
-               !!(priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK);
+               !!(ctx->staging.filter_flags & RXON_FILTER_ASSOC_MSK);
+       bool old_assoc = !!(ctx->active.filter_flags & RXON_FILTER_ASSOC_MSK);
 
        if (!iwl_is_alive(priv))
                return -EBUSY;
 
        /* always get timestamp with Rx frame */
-       priv->staging_rxon.flags |= RXON_FLG_TSF2HOST_MSK;
+       ctx->staging.flags |= RXON_FLG_TSF2HOST_MSK;
 
-       ret = iwl_check_rxon_cmd(priv);
+       ret = iwl_check_rxon_cmd(priv, ctx);
        if (ret) {
                IWL_ERR(priv, "Invalid RXON configuration.  Not committing.\n");
                return -EINVAL;
@@ -119,7 +124,7 @@ int iwl_commit_rxon(struct iwl_priv *priv)
         * abort any previous channel switch if still in process
         */
        if (priv->switch_rxon.switch_in_progress &&
-           (priv->switch_rxon.channel != priv->staging_rxon.channel)) {
+           (priv->switch_rxon.channel != ctx->staging.channel)) {
                IWL_DEBUG_11H(priv, "abort channel switch on %d\n",
                      le16_to_cpu(priv->switch_rxon.channel));
                iwl_chswitch_done(priv, false);
@@ -128,15 +133,15 @@ int iwl_commit_rxon(struct iwl_priv *priv)
        /* If we don't need to send a full RXON, we can use
         * iwl_rxon_assoc_cmd which is used to reconfigure filter
         * and other flags for the current radio configuration. */
-       if (!iwl_full_rxon_required(priv)) {
-               ret = iwl_send_rxon_assoc(priv);
+       if (!iwl_full_rxon_required(priv, ctx)) {
+               ret = iwl_send_rxon_assoc(priv, ctx);
                if (ret) {
                        IWL_ERR(priv, "Error setting RXON_ASSOC (%d)\n", ret);
                        return ret;
                }
 
-               memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon));
-               iwl_print_rx_config_cmd(priv);
+               memcpy(active_rxon, &ctx->staging, sizeof(*active_rxon));
+               iwl_print_rx_config_cmd(priv, ctx);
                return 0;
        }
 
@@ -144,13 +149,13 @@ int iwl_commit_rxon(struct iwl_priv *priv)
         * an RXON_ASSOC and the new config wants the associated mask enabled,
         * we must clear the associated from the active configuration
         * before we apply the new config */
-       if (iwl_is_associated(priv) && new_assoc) {
+       if (iwl_is_associated_ctx(ctx) && new_assoc) {
                IWL_DEBUG_INFO(priv, "Toggling associated bit on current RXON\n");
                active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
 
-               ret = iwl_send_cmd_pdu(priv, REPLY_RXON,
-                                     sizeof(struct iwl_rxon_cmd),
-                                     &priv->active_rxon);
+               ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd,
+                                      sizeof(struct iwl_rxon_cmd),
+                                      active_rxon);
 
                /* If the mask clearing failed then we set
                 * active_rxon back to what it was previously */
@@ -159,9 +164,9 @@ int iwl_commit_rxon(struct iwl_priv *priv)
                        IWL_ERR(priv, "Error clearing ASSOC_MSK (%d)\n", ret);
                        return ret;
                }
-               iwl_clear_ucode_stations(priv);
-               iwl_restore_stations(priv);
-               ret = iwl_restore_default_wep_keys(priv);
+               iwl_clear_ucode_stations(priv, ctx);
+               iwl_restore_stations(priv, ctx);
+               ret = iwl_restore_default_wep_keys(priv, ctx);
                if (ret) {
                        IWL_ERR(priv, "Failed to restore WEP keys (%d)\n", ret);
                        return ret;
@@ -173,27 +178,46 @@ int iwl_commit_rxon(struct iwl_priv *priv)
                       "* channel = %d\n"
                       "* bssid = %pM\n",
                       (new_assoc ? "" : "out"),
-                      le16_to_cpu(priv->staging_rxon.channel),
-                      priv->staging_rxon.bssid_addr);
+                      le16_to_cpu(ctx->staging.channel),
+                      ctx->staging.bssid_addr);
 
-       iwl_set_rxon_hwcrypto(priv, !priv->cfg->mod_params->sw_crypto);
+       iwl_set_rxon_hwcrypto(priv, ctx, !priv->cfg->mod_params->sw_crypto);
+
+       if (!old_assoc) {
+               /*
+                * First of all, before setting associated, we need to
+                * send RXON timing so the device knows about the DTIM
+                * period and other timing values
+                */
+               ret = iwl_send_rxon_timing(priv, ctx);
+               if (ret) {
+                       IWL_ERR(priv, "Error setting RXON timing!\n");
+                       return ret;
+               }
+       }
+
+       if (priv->cfg->ops->hcmd->set_pan_params) {
+               ret = priv->cfg->ops->hcmd->set_pan_params(priv);
+               if (ret)
+                       return ret;
+       }
 
        /* Apply the new configuration
         * RXON unassoc clears the station table in uCode so restoration of
         * stations is needed after it (the RXON command) completes
         */
        if (!new_assoc) {
-               ret = iwl_send_cmd_pdu(priv, REPLY_RXON,
-                             sizeof(struct iwl_rxon_cmd), &priv->staging_rxon);
+               ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd,
+                             sizeof(struct iwl_rxon_cmd), &ctx->staging);
                if (ret) {
                        IWL_ERR(priv, "Error setting new RXON (%d)\n", ret);
                        return ret;
                }
                IWL_DEBUG_INFO(priv, "Return from !new_assoc RXON.\n");
-               memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon));
-               iwl_clear_ucode_stations(priv);
-               iwl_restore_stations(priv);
-               ret = iwl_restore_default_wep_keys(priv);
+               memcpy(active_rxon, &ctx->staging, sizeof(*active_rxon));
+               iwl_clear_ucode_stations(priv, ctx);
+               iwl_restore_stations(priv, ctx);
+               ret = iwl_restore_default_wep_keys(priv, ctx);
                if (ret) {
                        IWL_ERR(priv, "Failed to restore WEP keys (%d)\n", ret);
                        return ret;
@@ -205,15 +229,15 @@ int iwl_commit_rxon(struct iwl_priv *priv)
                /* Apply the new configuration
                 * RXON assoc doesn't clear the station table in uCode,
                 */
-               ret = iwl_send_cmd_pdu(priv, REPLY_RXON,
-                             sizeof(struct iwl_rxon_cmd), &priv->staging_rxon);
+               ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd,
+                             sizeof(struct iwl_rxon_cmd), &ctx->staging);
                if (ret) {
                        IWL_ERR(priv, "Error setting new RXON (%d)\n", ret);
                        return ret;
                }
-               memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon));
+               memcpy(active_rxon, &ctx->staging, sizeof(*active_rxon));
        }
-       iwl_print_rx_config_cmd(priv);
+       iwl_print_rx_config_cmd(priv, ctx);
 
        iwl_init_sensitivity(priv);
 
@@ -230,10 +254,14 @@ int iwl_commit_rxon(struct iwl_priv *priv)
 
 void iwl_update_chain_flags(struct iwl_priv *priv)
 {
+       struct iwl_rxon_context *ctx;
 
-       if (priv->cfg->ops->hcmd->set_rxon_chain)
-               priv->cfg->ops->hcmd->set_rxon_chain(priv);
-       iwlcore_commit_rxon(priv);
+       if (priv->cfg->ops->hcmd->set_rxon_chain) {
+               for_each_context(priv, ctx) {
+                       priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
+                       iwlcore_commit_rxon(priv, ctx);
+               }
+       }
 }
 
 static void iwl_clear_free_frames(struct iwl_priv *priv)
@@ -337,6 +365,13 @@ static unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv,
         * beacon contents.
         */
 
+       lockdep_assert_held(&priv->mutex);
+
+       if (!priv->beacon_ctx) {
+               IWL_ERR(priv, "trying to build beacon w/o beacon context!\n");
+               return -EINVAL;
+       }
+
        /* Initialize memory */
        tx_beacon_cmd = &frame->u.beacon;
        memset(tx_beacon_cmd, 0, sizeof(*tx_beacon_cmd));
@@ -349,7 +384,7 @@ static unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv,
 
        /* Set up TX command fields */
        tx_beacon_cmd->tx.len = cpu_to_le16((u16)frame_size);
-       tx_beacon_cmd->tx.sta_id = priv->hw_params.bcast_sta_id;
+       tx_beacon_cmd->tx.sta_id = priv->beacon_ctx->bcast_sta_id;
        tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
        tx_beacon_cmd->tx.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK |
                TX_CMD_FLG_TSF_MSK | TX_CMD_FLG_STA_RATE_MSK;
@@ -359,7 +394,7 @@ static unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv,
                        frame_size);
 
        /* Set up packet rate and flags */
-       rate = iwl_rate_get_lowest_plcp(priv);
+       rate = iwl_rate_get_lowest_plcp(priv, priv->beacon_ctx);
        priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant,
                                              priv->hw_params.valid_tx_ant);
        rate_flags = iwl_ant_idx_to_flags(priv->mgmt_tx_ant);
@@ -592,23 +627,84 @@ static void iwl_bg_beacon_update(struct work_struct *work)
                container_of(work, struct iwl_priv, beacon_update);
        struct sk_buff *beacon;
 
-       /* Pull updated AP beacon from mac80211. will fail if not in AP mode */
-       beacon = ieee80211_beacon_get(priv->hw, priv->vif);
+       mutex_lock(&priv->mutex);
+       if (!priv->beacon_ctx) {
+               IWL_ERR(priv, "updating beacon w/o beacon context!\n");
+               goto out;
+       }
 
+       if (priv->beacon_ctx->vif->type != NL80211_IFTYPE_AP) {
+               /*
+                * The ucode will send beacon notifications even in
+                * IBSS mode, but we don't want to process them. But
+                * we need to defer the type check to here due to
+                * requiring locking around the beacon_ctx access.
+                */
+               goto out;
+       }
+
+       /* Pull updated AP beacon from mac80211. will fail if not in AP mode */
+       beacon = ieee80211_beacon_get(priv->hw, priv->beacon_ctx->vif);
        if (!beacon) {
                IWL_ERR(priv, "update beacon failed\n");
-               return;
+               goto out;
        }
 
-       mutex_lock(&priv->mutex);
        /* new beacon skb is allocated every time; dispose previous.*/
        if (priv->ibss_beacon)
                dev_kfree_skb(priv->ibss_beacon);
 
        priv->ibss_beacon = beacon;
-       mutex_unlock(&priv->mutex);
 
        iwl_send_beacon_cmd(priv);
+ out:
+       mutex_unlock(&priv->mutex);
+}
+
+static void iwl_bg_bt_runtime_config(struct work_struct *work)
+{
+       struct iwl_priv *priv =
+               container_of(work, struct iwl_priv, bt_runtime_config);
+
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+               return;
+
+       /* dont send host command if rf-kill is on */
+       if (!iwl_is_ready_rf(priv))
+               return;
+       priv->cfg->ops->hcmd->send_bt_config(priv);
+}
+
+static void iwl_bg_bt_full_concurrency(struct work_struct *work)
+{
+       struct iwl_priv *priv =
+               container_of(work, struct iwl_priv, bt_full_concurrency);
+       struct iwl_rxon_context *ctx;
+
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+               return;
+
+       /* dont send host command if rf-kill is on */
+       if (!iwl_is_ready_rf(priv))
+               return;
+
+       IWL_DEBUG_INFO(priv, "BT coex in %s mode\n",
+                      priv->bt_full_concurrent ?
+                      "full concurrency" : "3-wire");
+
+       /*
+        * LQ & RXON updated cmds must be sent before BT Config cmd
+        * to avoid 3-wire collisions
+        */
+       mutex_lock(&priv->mutex);
+       for_each_context(priv, ctx) {
+               if (priv->cfg->ops->hcmd->set_rxon_chain)
+                       priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
+               iwlcore_commit_rxon(priv, ctx);
+       }
+       mutex_unlock(&priv->mutex);
+
+       priv->cfg->ops->hcmd->send_bt_config(priv);
 }
 
 /**
@@ -763,10 +859,10 @@ static void iwl_bg_ucode_trace(unsigned long data)
 static void iwl_rx_beacon_notif(struct iwl_priv *priv,
                                struct iwl_rx_mem_buffer *rxb)
 {
-#ifdef CONFIG_IWLWIFI_DEBUG
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
        struct iwl4965_beacon_notif *beacon =
                (struct iwl4965_beacon_notif *)pkt->u.raw;
+#ifdef CONFIG_IWLWIFI_DEBUG
        u8 rate = iwl_hw_get_rate(beacon->beacon_notify_hdr.rate_n_flags);
 
        IWL_DEBUG_RX(priv, "beacon status %x retries %d iss %d "
@@ -778,8 +874,9 @@ static void iwl_rx_beacon_notif(struct iwl_priv *priv,
                le32_to_cpu(beacon->low_tsf), rate);
 #endif
 
-       if ((priv->iw_mode == NL80211_IFTYPE_AP) &&
-           (!test_bit(STATUS_EXIT_PENDING, &priv->status)))
+       priv->ibss_manager = le32_to_cpu(beacon->ibss_mgr_status);
+
+       if (!test_bit(STATUS_EXIT_PENDING, &priv->status))
                queue_work(priv->workqueue, &priv->beacon_update);
 }
 
@@ -1650,30 +1747,44 @@ static void iwl_nic_start(struct iwl_priv *priv)
 struct iwlagn_ucode_capabilities {
        u32 max_probe_length;
        u32 standard_phy_calibration_size;
+       bool pan;
 };
 
 static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context);
 static int iwl_mac_setup_register(struct iwl_priv *priv,
                                  struct iwlagn_ucode_capabilities *capa);
 
+#define UCODE_EXPERIMENTAL_INDEX       100
+#define UCODE_EXPERIMENTAL_TAG         "exp"
+
 static int __must_check iwl_request_firmware(struct iwl_priv *priv, bool first)
 {
        const char *name_pre = priv->cfg->fw_name_pre;
+       char tag[8];
 
-       if (first)
+       if (first) {
+#ifdef CONFIG_IWLWIFI_DEBUG_EXPERIMENTAL_UCODE
+               priv->fw_index = UCODE_EXPERIMENTAL_INDEX;
+               strcpy(tag, UCODE_EXPERIMENTAL_TAG);
+       } else if (priv->fw_index == UCODE_EXPERIMENTAL_INDEX) {
+#endif
                priv->fw_index = priv->cfg->ucode_api_max;
-       else
+               sprintf(tag, "%d", priv->fw_index);
+       } else {
                priv->fw_index--;
+               sprintf(tag, "%d", priv->fw_index);
+       }
 
        if (priv->fw_index < priv->cfg->ucode_api_min) {
                IWL_ERR(priv, "no suitable firmware found!\n");
                return -ENOENT;
        }
 
-       sprintf(priv->firmware_name, "%s%d%s",
-               name_pre, priv->fw_index, ".ucode");
+       sprintf(priv->firmware_name, "%s%s%s", name_pre, tag, ".ucode");
 
-       IWL_DEBUG_INFO(priv, "attempting to load firmware '%s'\n",
+       IWL_DEBUG_INFO(priv, "attempting to load firmware %s'%s'\n",
+                      (priv->fw_index == UCODE_EXPERIMENTAL_INDEX)
+                               ? "EXPERIMENTAL " : "",
                       priv->firmware_name);
 
        return request_firmware_nowait(THIS_MODULE, 1, priv->firmware_name,
@@ -1874,6 +1985,11 @@ static int iwlagn_load_firmware(struct iwl_priv *priv,
                        capa->max_probe_length =
                                        le32_to_cpup((__le32 *)tlv_data);
                        break;
+               case IWL_UCODE_TLV_PAN:
+                       if (tlv_len)
+                               goto invalid_tlv_len;
+                       capa->pan = true;
+                       break;
                case IWL_UCODE_TLV_INIT_EVTLOG_PTR:
                        if (tlv_len != sizeof(u32))
                                goto invalid_tlv_len;
@@ -1968,8 +2084,10 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
        memset(&pieces, 0, sizeof(pieces));
 
        if (!ucode_raw) {
-               IWL_ERR(priv, "request for firmware file '%s' failed.\n",
-                       priv->firmware_name);
+               if (priv->fw_index <= priv->cfg->ucode_api_max)
+                       IWL_ERR(priv,
+                               "request for firmware file '%s' failed.\n",
+                               priv->firmware_name);
                goto try_again;
        }
 
@@ -2016,7 +2134,9 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
                          api_max, api_ver);
 
        if (build)
-               sprintf(buildstr, " build %u", build);
+               sprintf(buildstr, " build %u%s", build,
+                      (priv->fw_index == UCODE_EXPERIMENTAL_INDEX)
+                               ? " (EXP)" : "");
        else
                buildstr[0] = '\0';
 
@@ -2145,6 +2265,12 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
                priv->_agn.inst_evtlog_size = priv->cfg->max_event_log_size;
        priv->_agn.inst_errlog_ptr = pieces.inst_errlog_ptr;
 
+       if (ucode_capa.pan) {
+               priv->valid_contexts |= BIT(IWL_RXON_CTX_PAN);
+               priv->sta_key_max_num = STA_KEY_MAX_NUM_PAN;
+       } else
+               priv->sta_key_max_num = STA_KEY_MAX_NUM;
+
        /* Copy images into buffers for card's bus-master reads ... */
 
        /* Runtime instructions (first block of data in file) */
@@ -2543,6 +2669,9 @@ int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
                return pos;
        }
 
+       /* enable/disable bt channel announcement */
+       priv->bt_ch_announce = iwlagn_bt_ch_announce;
+
 #ifdef CONFIG_IWLWIFI_DEBUG
        if (!(iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS) && !full_log)
                size = (size > DEFAULT_DUMP_EVENT_LOG_ENTRIES)
@@ -2589,6 +2718,52 @@ int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
        return pos;
 }
 
+static void iwl_rf_kill_ct_config(struct iwl_priv *priv)
+{
+       struct iwl_ct_kill_config cmd;
+       struct iwl_ct_kill_throttling_config adv_cmd;
+       unsigned long flags;
+       int ret = 0;
+
+       spin_lock_irqsave(&priv->lock, flags);
+       iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
+                   CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
+       spin_unlock_irqrestore(&priv->lock, flags);
+       priv->thermal_throttle.ct_kill_toggle = false;
+
+       if (priv->cfg->support_ct_kill_exit) {
+               adv_cmd.critical_temperature_enter =
+                       cpu_to_le32(priv->hw_params.ct_kill_threshold);
+               adv_cmd.critical_temperature_exit =
+                       cpu_to_le32(priv->hw_params.ct_kill_exit_threshold);
+
+               ret = iwl_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD,
+                                      sizeof(adv_cmd), &adv_cmd);
+               if (ret)
+                       IWL_ERR(priv, "REPLY_CT_KILL_CONFIG_CMD failed\n");
+               else
+                       IWL_DEBUG_INFO(priv, "REPLY_CT_KILL_CONFIG_CMD "
+                                       "succeeded, "
+                                       "critical temperature enter is %d,"
+                                       "exit is %d\n",
+                                      priv->hw_params.ct_kill_threshold,
+                                      priv->hw_params.ct_kill_exit_threshold);
+       } else {
+               cmd.critical_temperature_R =
+                       cpu_to_le32(priv->hw_params.ct_kill_threshold);
+
+               ret = iwl_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD,
+                                      sizeof(cmd), &cmd);
+               if (ret)
+                       IWL_ERR(priv, "REPLY_CT_KILL_CONFIG_CMD failed\n");
+               else
+                       IWL_DEBUG_INFO(priv, "REPLY_CT_KILL_CONFIG_CMD "
+                                       "succeeded, "
+                                       "critical temperature is %d\n",
+                                       priv->hw_params.ct_kill_threshold);
+       }
+}
+
 /**
  * iwl_alive_start - called after REPLY_ALIVE notification received
  *                   from protocol/runtime uCode (initialization uCode's
@@ -2597,6 +2772,7 @@ int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
 static void iwl_alive_start(struct iwl_priv *priv)
 {
        int ret = 0;
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
 
        IWL_DEBUG_INFO(priv, "Runtime Alive received.\n");
 
@@ -2645,27 +2821,31 @@ static void iwl_alive_start(struct iwl_priv *priv)
        if (priv->cfg->ops->hcmd->set_tx_ant)
                priv->cfg->ops->hcmd->set_tx_ant(priv, priv->cfg->valid_tx_ant);
 
-       if (iwl_is_associated(priv)) {
+       if (iwl_is_associated_ctx(ctx)) {
                struct iwl_rxon_cmd *active_rxon =
-                               (struct iwl_rxon_cmd *)&priv->active_rxon;
+                               (struct iwl_rxon_cmd *)&ctx->active;
                /* apply any changes in staging */
-               priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
+               ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK;
                active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
        } else {
+               struct iwl_rxon_context *tmp;
                /* Initialize our rx_config data */
-               iwl_connection_init_rx_config(priv, NULL);
+               for_each_context(priv, tmp)
+                       iwl_connection_init_rx_config(priv, tmp);
 
                if (priv->cfg->ops->hcmd->set_rxon_chain)
-                       priv->cfg->ops->hcmd->set_rxon_chain(priv);
+                       priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
        }
 
-       /* Configure Bluetooth device coexistence support */
-       priv->cfg->ops->hcmd->send_bt_config(priv);
+       if (!priv->cfg->advanced_bt_coexist) {
+               /* Configure Bluetooth device coexistence support */
+               priv->cfg->ops->hcmd->send_bt_config(priv);
+       }
 
        iwl_reset_run_time_calib(priv);
 
        /* Configure the adapter for unassociated operation */
-       iwlcore_commit_rxon(priv);
+       iwlcore_commit_rxon(priv, ctx);
 
        /* At this point, the NIC is initialized and operational */
        iwl_rf_kill_ct_config(priv);
@@ -2698,10 +2878,22 @@ static void __iwl_down(struct iwl_priv *priv)
        if (!exit_pending)
                set_bit(STATUS_EXIT_PENDING, &priv->status);
 
-       iwl_clear_ucode_stations(priv);
-       iwl_dealloc_bcast_station(priv);
+       /* Stop TX queues watchdog. We need to have STATUS_EXIT_PENDING bit set
+        * to prevent rearm timer */
+       if (priv->cfg->ops->lib->recover_from_tx_stall)
+               del_timer_sync(&priv->monitor_recover);
+
+       iwl_clear_ucode_stations(priv, NULL);
+       iwl_dealloc_bcast_stations(priv);
        iwl_clear_driver_stations(priv);
 
+       /* reset BT coex data */
+       priv->bt_status = 0;
+       priv->bt_traffic_load = priv->cfg->bt_init_traffic_load;
+       priv->bt_sco_active = false;
+       priv->bt_full_concurrent = false;
+       priv->bt_ci_compliance = 0;
+
        /* Unblock any waiting calls */
        wake_up_interruptible_all(&priv->wait_command_queue);
 
@@ -2834,6 +3026,7 @@ static int iwl_prepare_card_hw(struct iwl_priv *priv)
 
 static int __iwl_up(struct iwl_priv *priv)
 {
+       struct iwl_rxon_context *ctx;
        int i;
        int ret;
 
@@ -2847,9 +3040,13 @@ static int __iwl_up(struct iwl_priv *priv)
                return -EIO;
        }
 
-       ret = iwl_alloc_bcast_station(priv, true);
-       if (ret)
-               return ret;
+       for_each_context(priv, ctx) {
+               ret = iwl_alloc_bcast_station(priv, ctx, true);
+               if (ret) {
+                       iwl_dealloc_bcast_stations(priv);
+                       return ret;
+               }
+       }
 
        iwl_prepare_card_hw(priv);
 
@@ -2874,6 +3071,12 @@ static int __iwl_up(struct iwl_priv *priv)
 
        iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
 
+       /* must be initialised before iwl_hw_nic_init */
+       if (priv->valid_contexts != BIT(IWL_RXON_CTX_BSS))
+               priv->cmd_queue = IWL_IPAN_CMD_QUEUE_NUM;
+       else
+               priv->cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM;
+
        ret = iwlagn_hw_nic_init(priv);
        if (ret) {
                IWL_ERR(priv, "Unable to init nic\n");
@@ -3004,11 +3207,42 @@ static void iwl_bg_restart(struct work_struct *data)
                return;
 
        if (test_and_clear_bit(STATUS_FW_ERROR, &priv->status)) {
+               struct iwl_rxon_context *ctx;
+               bool bt_sco, bt_full_concurrent;
+               u8 bt_ci_compliance;
+               u8 bt_load;
+               u8 bt_status;
+
                mutex_lock(&priv->mutex);
-               priv->vif = NULL;
+               for_each_context(priv, ctx)
+                       ctx->vif = NULL;
                priv->is_open = 0;
+
+               /*
+                * __iwl_down() will clear the BT status variables,
+                * which is correct, but when we restart we really
+                * want to keep them so restore them afterwards.
+                *
+                * The restart process will later pick them up and
+                * re-configure the hw when we reconfigure the BT
+                * command.
+                */
+               bt_sco = priv->bt_sco_active;
+               bt_full_concurrent = priv->bt_full_concurrent;
+               bt_ci_compliance = priv->bt_ci_compliance;
+               bt_load = priv->bt_traffic_load;
+               bt_status = priv->bt_status;
+
+               __iwl_down(priv);
+
+               priv->bt_sco_active = bt_sco;
+               priv->bt_full_concurrent = bt_full_concurrent;
+               priv->bt_ci_compliance = bt_ci_compliance;
+               priv->bt_traffic_load = bt_load;
+               priv->bt_status = bt_status;
+
                mutex_unlock(&priv->mutex);
-               iwl_down(priv);
+               iwl_cancel_deferred_work(priv);
                ieee80211_restart_hw(priv->hw);
        } else {
                iwl_down(priv);
@@ -3039,12 +3273,15 @@ static void iwl_bg_rx_replenish(struct work_struct *data)
 
 void iwl_post_associate(struct iwl_priv *priv, struct ieee80211_vif *vif)
 {
+       struct iwl_rxon_context *ctx;
        struct ieee80211_conf *conf = NULL;
        int ret = 0;
 
        if (!vif || !priv->is_open)
                return;
 
+       ctx = iwl_rxon_ctx_from_vif(vif);
+
        if (vif->type == NL80211_IFTYPE_AP) {
                IWL_ERR(priv, "%s Should not be called in AP mode\n", __func__);
                return;
@@ -3057,44 +3294,42 @@ void iwl_post_associate(struct iwl_priv *priv, struct ieee80211_vif *vif)
 
        conf = ieee80211_get_hw_conf(priv->hw);
 
-       priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-       iwlcore_commit_rxon(priv);
+       ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+       iwlcore_commit_rxon(priv, ctx);
 
-       iwl_setup_rxon_timing(priv, vif);
-       ret = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING,
-                             sizeof(priv->rxon_timing), &priv->rxon_timing);
+       ret = iwl_send_rxon_timing(priv, ctx);
        if (ret)
-               IWL_WARN(priv, "REPLY_RXON_TIMING failed - "
+               IWL_WARN(priv, "RXON timing - "
                            "Attempting to continue.\n");
 
-       priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
+       ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK;
 
        iwl_set_rxon_ht(priv, &priv->current_ht_config);
 
        if (priv->cfg->ops->hcmd->set_rxon_chain)
-               priv->cfg->ops->hcmd->set_rxon_chain(priv);
+               priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
 
-       priv->staging_rxon.assoc_id = cpu_to_le16(vif->bss_conf.aid);
+       ctx->staging.assoc_id = cpu_to_le16(vif->bss_conf.aid);
 
        IWL_DEBUG_ASSOC(priv, "assoc id %d beacon interval %d\n",
                        vif->bss_conf.aid, vif->bss_conf.beacon_int);
 
        if (vif->bss_conf.use_short_preamble)
-               priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
+               ctx->staging.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
        else
-               priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
+               ctx->staging.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
 
-       if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) {
+       if (ctx->staging.flags & RXON_FLG_BAND_24G_MSK) {
                if (vif->bss_conf.use_short_slot)
-                       priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
+                       ctx->staging.flags |= RXON_FLG_SHORT_SLOT_MSK;
                else
-                       priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
+                       ctx->staging.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
        }
 
-       iwlcore_commit_rxon(priv);
+       iwlcore_commit_rxon(priv, ctx);
 
        IWL_DEBUG_ASSOC(priv, "Associated as %d to: %pM\n",
-                       vif->bss_conf.aid, priv->active_rxon.bssid_addr);
+                       vif->bss_conf.aid, ctx->active.bssid_addr);
 
        switch (vif->type) {
        case NL80211_IFTYPE_STATION:
@@ -3137,11 +3372,14 @@ static int iwl_mac_setup_register(struct iwl_priv *priv,
 {
        int ret;
        struct ieee80211_hw *hw = priv->hw;
+       struct iwl_rxon_context *ctx;
+
        hw->rate_control_algorithm = "iwl-agn-rs";
 
        /* Tell mac80211 our characteristics */
        hw->flags = IEEE80211_HW_SIGNAL_DBM |
                    IEEE80211_HW_AMPDU_AGGREGATION |
+                   IEEE80211_HW_NEED_DTIM_PERIOD |
                    IEEE80211_HW_SPECTRUM_MGMT;
 
        if (!priv->cfg->broken_powersave)
@@ -3155,9 +3393,10 @@ static int iwl_mac_setup_register(struct iwl_priv *priv,
        hw->sta_data_size = sizeof(struct iwl_station_priv);
        hw->vif_data_size = sizeof(struct iwl_vif_priv);
 
-       hw->wiphy->interface_modes =
-               BIT(NL80211_IFTYPE_STATION) |
-               BIT(NL80211_IFTYPE_ADHOC);
+       for_each_context(priv, ctx) {
+               hw->wiphy->interface_modes |= ctx->interface_modes;
+               hw->wiphy->interface_modes |= ctx->exclusive_interface_modes;
+       }
 
        hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY |
                            WIPHY_FLAG_DISABLE_BEACON_HINTS;
@@ -3285,24 +3524,25 @@ static int iwl_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 
 void iwl_config_ap(struct iwl_priv *priv, struct ieee80211_vif *vif)
 {
+       struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
        int ret = 0;
 
+       lockdep_assert_held(&priv->mutex);
+
        if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return;
 
        /* The following should be done only at AP bring up */
-       if (!iwl_is_associated(priv)) {
+       if (!iwl_is_associated_ctx(ctx)) {
 
                /* RXON - unassoc (to set timing command) */
-               priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-               iwlcore_commit_rxon(priv);
+               ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+               iwlcore_commit_rxon(priv, ctx);
 
                /* RXON Timing */
-               iwl_setup_rxon_timing(priv, vif);
-               ret = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING,
-                               sizeof(priv->rxon_timing), &priv->rxon_timing);
+               ret = iwl_send_rxon_timing(priv, ctx);
                if (ret)
-                       IWL_WARN(priv, "REPLY_RXON_TIMING failed - "
+                       IWL_WARN(priv, "RXON timing failed - "
                                        "Attempting to continue.\n");
 
                /* AP has all antennas */
@@ -3310,28 +3550,30 @@ void iwl_config_ap(struct iwl_priv *priv, struct ieee80211_vif *vif)
                        priv->hw_params.valid_rx_ant;
                iwl_set_rxon_ht(priv, &priv->current_ht_config);
                if (priv->cfg->ops->hcmd->set_rxon_chain)
-                       priv->cfg->ops->hcmd->set_rxon_chain(priv);
+                       priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
 
-               priv->staging_rxon.assoc_id = 0;
+               ctx->staging.assoc_id = 0;
 
                if (vif->bss_conf.use_short_preamble)
-                       priv->staging_rxon.flags |=
+                       ctx->staging.flags |=
                                RXON_FLG_SHORT_PREAMBLE_MSK;
                else
-                       priv->staging_rxon.flags &=
+                       ctx->staging.flags &=
                                ~RXON_FLG_SHORT_PREAMBLE_MSK;
 
-               if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) {
+               if (ctx->staging.flags & RXON_FLG_BAND_24G_MSK) {
                        if (vif->bss_conf.use_short_slot)
-                               priv->staging_rxon.flags |=
+                               ctx->staging.flags |=
                                        RXON_FLG_SHORT_SLOT_MSK;
                        else
-                               priv->staging_rxon.flags &=
+                               ctx->staging.flags &=
                                        ~RXON_FLG_SHORT_SLOT_MSK;
                }
+               /* need to send beacon cmd before committing assoc RXON! */
+               iwl_send_beacon_cmd(priv);
                /* restore RXON assoc */
-               priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
-               iwlcore_commit_rxon(priv);
+               ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK;
+               iwlcore_commit_rxon(priv, ctx);
        }
        iwl_send_beacon_cmd(priv);
 
@@ -3348,9 +3590,11 @@ static void iwl_mac_update_tkip_key(struct ieee80211_hw *hw,
 {
 
        struct iwl_priv *priv = hw->priv;
+       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
+
        IWL_DEBUG_MAC80211(priv, "enter\n");
 
-       iwl_update_tkip_key(priv, keyconf, sta,
+       iwl_update_tkip_key(priv, vif_priv->ctx, keyconf, sta,
                            iv32, phase1key);
 
        IWL_DEBUG_MAC80211(priv, "leave\n");
@@ -3362,6 +3606,8 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
                           struct ieee80211_key_conf *key)
 {
        struct iwl_priv *priv = hw->priv;
+       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
+       struct iwl_rxon_context *ctx = vif_priv->ctx;
        int ret;
        u8 sta_id;
        bool is_default_wep_key = false;
@@ -3373,7 +3619,7 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
                return -EOPNOTSUPP;
        }
 
-       sta_id = iwl_sta_id_or_broadcast(priv, sta);
+       sta_id = iwl_sta_id_or_broadcast(priv, vif_priv->ctx, sta);
        if (sta_id == IWL_INVALID_STATION)
                return -EINVAL;
 
@@ -3386,9 +3632,11 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
         * in 1X mode.
         * In legacy wep mode, we use another host command to the uCode.
         */
-       if (key->alg == ALG_WEP && !sta && vif->type != NL80211_IFTYPE_AP) {
+       if ((key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
+            key->cipher == WLAN_CIPHER_SUITE_WEP104) &&
+           !sta) {
                if (cmd == SET_KEY)
-                       is_default_wep_key = !priv->key_mapping_key;
+                       is_default_wep_key = !ctx->key_mapping_keys;
                else
                        is_default_wep_key =
                                        (key->hw_key_idx == HW_KEY_DEFAULT);
@@ -3397,17 +3645,18 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
        switch (cmd) {
        case SET_KEY:
                if (is_default_wep_key)
-                       ret = iwl_set_default_wep_key(priv, key);
+                       ret = iwl_set_default_wep_key(priv, vif_priv->ctx, key);
                else
-                       ret = iwl_set_dynamic_key(priv, key, sta_id);
+                       ret = iwl_set_dynamic_key(priv, vif_priv->ctx,
+                                                 key, sta_id);
 
                IWL_DEBUG_MAC80211(priv, "enable hwcrypto key\n");
                break;
        case DISABLE_KEY:
                if (is_default_wep_key)
-                       ret = iwl_remove_default_wep_key(priv, key);
+                       ret = iwl_remove_default_wep_key(priv, ctx, key);
                else
-                       ret = iwl_remove_dynamic_key(priv, key, sta_id);
+                       ret = iwl_remove_dynamic_key(priv, ctx, key, sta_id);
 
                IWL_DEBUG_MAC80211(priv, "disable hwcrypto key\n");
                break;
@@ -3476,8 +3725,8 @@ static int iwl_mac_ampdu_action(struct ieee80211_hw *hw,
 
                        sta_priv->lq_sta.lq.general_params.flags &=
                                ~LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK;
-                       iwl_send_lq_cmd(priv, &sta_priv->lq_sta.lq,
-                               CMD_ASYNC, false);
+                       iwl_send_lq_cmd(priv, iwl_rxon_ctx_from_vif(vif),
+                                       &sta_priv->lq_sta.lq, CMD_ASYNC, false);
                }
                break;
        case IEEE80211_AMPDU_TX_OPERATIONAL:
@@ -3492,8 +3741,8 @@ static int iwl_mac_ampdu_action(struct ieee80211_hw *hw,
 
                        sta_priv->lq_sta.lq.general_params.flags |=
                                LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK;
-                       iwl_send_lq_cmd(priv, &sta_priv->lq_sta.lq,
-                               CMD_ASYNC, false);
+                       iwl_send_lq_cmd(priv, iwl_rxon_ctx_from_vif(vif),
+                                       &sta_priv->lq_sta.lq, CMD_ASYNC, false);
                }
                ret = 0;
                break;
@@ -3539,6 +3788,7 @@ static int iwlagn_mac_sta_add(struct ieee80211_hw *hw,
 {
        struct iwl_priv *priv = hw->priv;
        struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
+       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
        bool is_ap = vif->type == NL80211_IFTYPE_STATION;
        int ret;
        u8 sta_id;
@@ -3554,8 +3804,8 @@ static int iwlagn_mac_sta_add(struct ieee80211_hw *hw,
        if (vif->type == NL80211_IFTYPE_AP)
                sta_priv->client = true;
 
-       ret = iwl_add_station_common(priv, sta->addr, is_ap, &sta->ht_cap,
-                                    &sta_id);
+       ret = iwl_add_station_common(priv, vif_priv->ctx, sta->addr,
+                                    is_ap, sta, &sta_id);
        if (ret) {
                IWL_ERR(priv, "Unable to add station %pM (%d)\n",
                        sta->addr, ret);
@@ -3581,7 +3831,17 @@ static void iwl_mac_channel_switch(struct ieee80211_hw *hw,
        struct iwl_priv *priv = hw->priv;
        const struct iwl_channel_info *ch_info;
        struct ieee80211_conf *conf = &hw->conf;
+       struct ieee80211_channel *channel = ch_switch->channel;
        struct iwl_ht_config *ht_conf = &priv->current_ht_config;
+       /*
+        * MULTI-FIXME
+        * When we add support for multiple interfaces, we need to
+        * revisit this. The channel switch command in the device
+        * only affects the BSS context, but what does that really
+        * mean? And what if we get a CSA on the second interface?
+        * This needs a lot of work.
+        */
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
        u16 ch;
        unsigned long flags = 0;
 
@@ -3594,7 +3854,7 @@ static void iwl_mac_channel_switch(struct ieee80211_hw *hw,
            test_bit(STATUS_SCANNING, &priv->status))
                goto out_exit;
 
-       if (!iwl_is_associated(priv))
+       if (!iwl_is_associated_ctx(ctx))
                goto out_exit;
 
        /* channel switch in progress */
@@ -3604,11 +3864,10 @@ static void iwl_mac_channel_switch(struct ieee80211_hw *hw,
        mutex_lock(&priv->mutex);
        if (priv->cfg->ops->lib->set_channel_switch) {
 
-               ch = ieee80211_frequency_to_channel(
-                       ch_switch->channel->center_freq);
-               if (le16_to_cpu(priv->active_rxon.channel) != ch) {
+               ch = channel->hw_value;
+               if (le16_to_cpu(ctx->active.channel) != ch) {
                        ch_info = iwl_get_channel_info(priv,
-                                                      conf->channel->band,
+                                                      channel->band,
                                                       ch);
                        if (!is_channel_valid(ch_info)) {
                                IWL_DEBUG_MAC80211(priv, "invalid channel\n");
@@ -3619,34 +3878,31 @@ static void iwl_mac_channel_switch(struct ieee80211_hw *hw,
                        priv->current_ht_config.smps = conf->smps_mode;
 
                        /* Configure HT40 channels */
-                       ht_conf->is_ht = conf_is_ht(conf);
-                       if (ht_conf->is_ht) {
+                       ctx->ht.enabled = conf_is_ht(conf);
+                       if (ctx->ht.enabled) {
                                if (conf_is_ht40_minus(conf)) {
-                                       ht_conf->extension_chan_offset =
+                                       ctx->ht.extension_chan_offset =
                                                IEEE80211_HT_PARAM_CHA_SEC_BELOW;
-                                       ht_conf->is_40mhz = true;
+                                       ctx->ht.is_40mhz = true;
                                } else if (conf_is_ht40_plus(conf)) {
-                                       ht_conf->extension_chan_offset =
+                                       ctx->ht.extension_chan_offset =
                                                IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
-                                       ht_conf->is_40mhz = true;
+                                       ctx->ht.is_40mhz = true;
                                } else {
-                                       ht_conf->extension_chan_offset =
+                                       ctx->ht.extension_chan_offset =
                                                IEEE80211_HT_PARAM_CHA_SEC_NONE;
-                                       ht_conf->is_40mhz = false;
+                                       ctx->ht.is_40mhz = false;
                                }
                        } else
-                               ht_conf->is_40mhz = false;
+                               ctx->ht.is_40mhz = false;
 
-                       /* if we are switching from ht to 2.4 clear flags
-                        * from any ht related info since 2.4 does not
-                        * support ht */
-                       if ((le16_to_cpu(priv->staging_rxon.channel) != ch))
-                               priv->staging_rxon.flags = 0;
+                       if ((le16_to_cpu(ctx->staging.channel) != ch))
+                               ctx->staging.flags = 0;
 
-                       iwl_set_rxon_channel(priv, conf->channel);
+                       iwl_set_rxon_channel(priv, channel, ctx);
                        iwl_set_rxon_ht(priv, ht_conf);
-                       iwl_set_flags_for_band(priv, conf->channel->band,
-                                              priv->vif);
+                       iwl_set_flags_for_band(priv, ctx, channel->band,
+                                              ctx->vif);
                        spin_unlock_irqrestore(&priv->lock, flags);
 
                        iwl_set_rate(priv);
@@ -3663,7 +3919,7 @@ out:
        mutex_unlock(&priv->mutex);
 out_exit:
        if (!priv->switch_rxon.switch_in_progress)
-               ieee80211_chswitch_done(priv->vif, false);
+               ieee80211_chswitch_done(ctx->vif, false);
        IWL_DEBUG_MAC80211(priv, "leave\n");
 }
 
@@ -3674,6 +3930,7 @@ static void iwlagn_configure_filter(struct ieee80211_hw *hw,
 {
        struct iwl_priv *priv = hw->priv;
        __le32 filter_or = 0, filter_nand = 0;
+       struct iwl_rxon_context *ctx;
 
 #define CHK(test, flag)        do { \
        if (*total_flags & (test))              \
@@ -3693,10 +3950,11 @@ static void iwlagn_configure_filter(struct ieee80211_hw *hw,
 
        mutex_lock(&priv->mutex);
 
-       priv->staging_rxon.filter_flags &= ~filter_nand;
-       priv->staging_rxon.filter_flags |= filter_or;
-
-       iwlcore_commit_rxon(priv);
+       for_each_context(priv, ctx) {
+               ctx->staging.filter_flags &= ~filter_nand;
+               ctx->staging.filter_flags |= filter_or;
+               iwlcore_commit_rxon(priv, ctx);
+       }
 
        mutex_unlock(&priv->mutex);
 
@@ -3765,6 +4023,8 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv)
        INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update);
        INIT_WORK(&priv->run_time_calib_work, iwl_bg_run_time_calib_work);
        INIT_WORK(&priv->tx_flush, iwl_bg_tx_flush);
+       INIT_WORK(&priv->bt_full_concurrency, iwl_bg_bt_full_concurrency);
+       INIT_WORK(&priv->bt_runtime_config, iwl_bg_bt_runtime_config);
        INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start);
        INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start);
 
@@ -3807,10 +4067,10 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv)
        cancel_delayed_work(&priv->alive_start);
        cancel_work_sync(&priv->run_time_calib_work);
        cancel_work_sync(&priv->beacon_update);
+       cancel_work_sync(&priv->bt_full_concurrency);
+       cancel_work_sync(&priv->bt_runtime_config);
        del_timer_sync(&priv->statistics_periodic);
        del_timer_sync(&priv->ucode_trace);
-       if (priv->cfg->ops->lib->recover_from_tx_stall)
-               del_timer_sync(&priv->monitor_recover);
 }
 
 static void iwl_init_hw_rates(struct iwl_priv *priv,
@@ -3865,10 +4125,22 @@ static int iwl_init_drv(struct iwl_priv *priv)
 
        /* Choose which receivers/antennas to use */
        if (priv->cfg->ops->hcmd->set_rxon_chain)
-               priv->cfg->ops->hcmd->set_rxon_chain(priv);
+               priv->cfg->ops->hcmd->set_rxon_chain(priv,
+                                       &priv->contexts[IWL_RXON_CTX_BSS]);
 
        iwl_init_scan_params(priv);
 
+       /* init bt coex */
+       if (priv->cfg->advanced_bt_coexist) {
+               priv->kill_ack_mask = IWLAGN_BT_KILL_ACK_MASK_DEFAULT;
+               priv->kill_cts_mask = IWLAGN_BT_KILL_CTS_MASK_DEFAULT;
+               priv->bt_valid = IWLAGN_BT_ALL_VALID_MSK;
+               priv->bt_on_thresh = BT_ON_THRESHOLD_DEF;
+               priv->bt_duration = BT_DURATION_LIMIT_DEF;
+               priv->dynamic_frag_thresh = BT_FRAG_THRESHOLD_DEF;
+               priv->dynamic_agg_thresh = BT_AGG_THRESHOLD_DEF;
+       }
+
        /* Set the tx_power_user_lmt to the lowest power level
         * this value will get overwritten by channel max power avg
         * from eeprom */
@@ -3923,11 +4195,60 @@ static struct ieee80211_ops iwl_hw_ops = {
        .sta_remove = iwl_mac_sta_remove,
        .channel_switch = iwl_mac_channel_switch,
        .flush = iwl_mac_flush,
+       .tx_last_beacon = iwl_mac_tx_last_beacon,
+};
+
+static void iwl_hw_detect(struct iwl_priv *priv)
+{
+       priv->hw_rev = _iwl_read32(priv, CSR_HW_REV);
+       priv->hw_wa_rev = _iwl_read32(priv, CSR_HW_REV_WA_REG);
+       pci_read_config_byte(priv->pci_dev, PCI_REVISION_ID, &priv->rev_id);
+       IWL_DEBUG_INFO(priv, "HW Revision ID = 0x%X\n", priv->rev_id);
+}
+
+static int iwl_set_hw_params(struct iwl_priv *priv)
+{
+       priv->hw_params.max_rxq_size = RX_QUEUE_SIZE;
+       priv->hw_params.max_rxq_log = RX_QUEUE_SIZE_LOG;
+       if (priv->cfg->mod_params->amsdu_size_8K)
+               priv->hw_params.rx_page_order = get_order(IWL_RX_BUF_SIZE_8K);
+       else
+               priv->hw_params.rx_page_order = get_order(IWL_RX_BUF_SIZE_4K);
+
+       priv->hw_params.max_beacon_itrvl = IWL_MAX_UCODE_BEACON_INTERVAL;
+
+       if (priv->cfg->mod_params->disable_11n)
+               priv->cfg->sku &= ~IWL_SKU_N;
+
+       /* Device-specific setup */
+       return priv->cfg->ops->lib->set_hw_params(priv);
+}
+
+static const u8 iwlagn_bss_ac_to_fifo[] = {
+       IWL_TX_FIFO_VO,
+       IWL_TX_FIFO_VI,
+       IWL_TX_FIFO_BE,
+       IWL_TX_FIFO_BK,
+};
+
+static const u8 iwlagn_bss_ac_to_queue[] = {
+       0, 1, 2, 3,
+};
+
+static const u8 iwlagn_pan_ac_to_fifo[] = {
+       IWL_TX_FIFO_VO_IPAN,
+       IWL_TX_FIFO_VI_IPAN,
+       IWL_TX_FIFO_BE_IPAN,
+       IWL_TX_FIFO_BK_IPAN,
+};
+
+static const u8 iwlagn_pan_ac_to_queue[] = {
+       7, 6, 5, 4,
 };
 
 static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
-       int err = 0;
+       int err = 0, i;
        struct iwl_priv *priv;
        struct ieee80211_hw *hw;
        struct iwl_cfg *cfg = (struct iwl_cfg *)(ent->driver_data);
@@ -3955,6 +4276,51 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        priv = hw->priv;
        /* At this point both hw and priv are allocated. */
 
+       /*
+        * The default context is always valid,
+        * more may be discovered when firmware
+        * is loaded.
+        */
+       priv->valid_contexts = BIT(IWL_RXON_CTX_BSS);
+
+       for (i = 0; i < NUM_IWL_RXON_CTX; i++)
+               priv->contexts[i].ctxid = i;
+
+       priv->contexts[IWL_RXON_CTX_BSS].rxon_cmd = REPLY_RXON;
+       priv->contexts[IWL_RXON_CTX_BSS].rxon_timing_cmd = REPLY_RXON_TIMING;
+       priv->contexts[IWL_RXON_CTX_BSS].rxon_assoc_cmd = REPLY_RXON_ASSOC;
+       priv->contexts[IWL_RXON_CTX_BSS].qos_cmd = REPLY_QOS_PARAM;
+       priv->contexts[IWL_RXON_CTX_BSS].ap_sta_id = IWL_AP_ID;
+       priv->contexts[IWL_RXON_CTX_BSS].wep_key_cmd = REPLY_WEPKEY;
+       priv->contexts[IWL_RXON_CTX_BSS].ac_to_fifo = iwlagn_bss_ac_to_fifo;
+       priv->contexts[IWL_RXON_CTX_BSS].ac_to_queue = iwlagn_bss_ac_to_queue;
+       priv->contexts[IWL_RXON_CTX_BSS].exclusive_interface_modes =
+               BIT(NL80211_IFTYPE_ADHOC);
+       priv->contexts[IWL_RXON_CTX_BSS].interface_modes =
+               BIT(NL80211_IFTYPE_STATION);
+       priv->contexts[IWL_RXON_CTX_BSS].ibss_devtype = RXON_DEV_TYPE_IBSS;
+       priv->contexts[IWL_RXON_CTX_BSS].station_devtype = RXON_DEV_TYPE_ESS;
+       priv->contexts[IWL_RXON_CTX_BSS].unused_devtype = RXON_DEV_TYPE_ESS;
+
+       priv->contexts[IWL_RXON_CTX_PAN].rxon_cmd = REPLY_WIPAN_RXON;
+       priv->contexts[IWL_RXON_CTX_PAN].rxon_timing_cmd = REPLY_WIPAN_RXON_TIMING;
+       priv->contexts[IWL_RXON_CTX_PAN].rxon_assoc_cmd = REPLY_WIPAN_RXON_ASSOC;
+       priv->contexts[IWL_RXON_CTX_PAN].qos_cmd = REPLY_WIPAN_QOS_PARAM;
+       priv->contexts[IWL_RXON_CTX_PAN].ap_sta_id = IWL_AP_ID_PAN;
+       priv->contexts[IWL_RXON_CTX_PAN].wep_key_cmd = REPLY_WIPAN_WEPKEY;
+       priv->contexts[IWL_RXON_CTX_PAN].bcast_sta_id = IWLAGN_PAN_BCAST_ID;
+       priv->contexts[IWL_RXON_CTX_PAN].station_flags = STA_FLG_PAN_STATION;
+       priv->contexts[IWL_RXON_CTX_PAN].ac_to_fifo = iwlagn_pan_ac_to_fifo;
+       priv->contexts[IWL_RXON_CTX_PAN].ac_to_queue = iwlagn_pan_ac_to_queue;
+       priv->contexts[IWL_RXON_CTX_PAN].mcast_queue = IWL_IPAN_MCAST_QUEUE;
+       priv->contexts[IWL_RXON_CTX_PAN].interface_modes =
+               BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP);
+       priv->contexts[IWL_RXON_CTX_PAN].ap_devtype = RXON_DEV_TYPE_CP;
+       priv->contexts[IWL_RXON_CTX_PAN].station_devtype = RXON_DEV_TYPE_2STA;
+       priv->contexts[IWL_RXON_CTX_PAN].unused_devtype = RXON_DEV_TYPE_P2P;
+
+       BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2);
+
        SET_IEEE80211_DEV(hw, &pdev->dev);
 
        IWL_DEBUG_INFO(priv, "*** LOAD DRIVER ***\n");
@@ -3962,12 +4328,23 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        priv->pci_dev = pdev;
        priv->inta_mask = CSR_INI_SET_MASK;
 
+       /* is antenna coupling more than 35dB ? */
+       priv->bt_ant_couple_ok =
+               (iwlagn_ant_coupling > IWL_BT_ANTENNA_COUPLING_THRESHOLD) ?
+               true : false;
+
+       /* enable/disable bt channel announcement */
+       priv->bt_ch_announce = iwlagn_bt_ch_announce;
+
        if (iwl_alloc_traffic_mem(priv))
                IWL_ERR(priv, "Not enough memory to generate traffic log\n");
 
        /**************************
         * 2. Initializing PCI bus
         **************************/
+       pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1 |
+                               PCIE_LINK_STATE_CLKPM);
+
        if (pci_enable_device(pdev)) {
                err = -ENODEV;
                goto out_ieee80211_free_hw;
@@ -4492,3 +4869,11 @@ module_param_named(ucode_alternative, iwlagn_wanted_ucode_alternative, int,
                   S_IRUGO);
 MODULE_PARM_DESC(ucode_alternative,
                 "specify ucode alternative to use from ucode file");
+
+module_param_named(antenna_coupling, iwlagn_ant_coupling, int, S_IRUGO);
+MODULE_PARM_DESC(antenna_coupling,
+                "specify antenna coupling in dB (defualt: 0 dB)");
+
+module_param_named(bt_ch_announce, iwlagn_bt_ch_announce, bool, S_IRUGO);
+MODULE_PARM_DESC(bt_ch_announce,
+                "Enable BT channel announcement mode (default: enable)");
index cc6464dc72e592bd57302423b84784f0b4b63d8d..7c542a8c8f8131e2ce717a513d04251e640c27a1 100644 (file)
@@ -95,6 +95,7 @@ extern struct iwl_cfg iwl1000_bg_cfg;
 
 extern struct iwl_mod_params iwlagn_mod_params;
 extern struct iwl_hcmd_ops iwlagn_hcmd;
+extern struct iwl_hcmd_ops iwlagn_bt_hcmd;
 extern struct iwl_hcmd_utils_ops iwlagn_hcmd_utils;
 
 int iwl_reset_ict(struct iwl_priv *priv);
@@ -223,7 +224,16 @@ int iwlagn_manage_ibss_station(struct iwl_priv *priv,
                               struct ieee80211_vif *vif, bool add);
 
 /* hcmd */
-int iwlagn_send_rxon_assoc(struct iwl_priv *priv);
+int iwlagn_send_rxon_assoc(struct iwl_priv *priv,
+                          struct iwl_rxon_context *ctx);
 int iwlagn_send_tx_ant_config(struct iwl_priv *priv, u8 valid_tx_ant);
 
+/* bt coex */
+void iwlagn_send_advance_bt_config(struct iwl_priv *priv);
+void iwlagn_bt_coex_profile_notif(struct iwl_priv *priv,
+                                 struct iwl_rx_mem_buffer *rxb);
+void iwlagn_bt_rx_handler_setup(struct iwl_priv *priv);
+void iwlagn_bt_setup_deferred_work(struct iwl_priv *priv);
+void iwlagn_bt_cancel_deferred_work(struct iwl_priv *priv);
+
 #endif /* __iwl_agn_h__ */
index 60725a5c1b694b689d42fe6e782c9c141a47ac74..3e4ba31b5d59ad0a666ad185d3e4c058e00383a8 100644 (file)
@@ -62,7 +62,7 @@
  *****************************************************************************/
 /*
  * Please use this file (iwl-commands.h) only for uCode API definitions.
- * Please use iwl-4965-hw.h for hardware-related definitions.
+ * Please use iwl-xxxx-hw.h for hardware-related definitions.
  * Please use iwl-dev.h for driver implementation definitions.
  */
 
@@ -173,6 +173,23 @@ enum {
        REPLY_RX_MPDU_CMD = 0xc1,
        REPLY_RX = 0xc3,
        REPLY_COMPRESSED_BA = 0xc5,
+
+       /* BT Coex */
+       REPLY_BT_COEX_PRIO_TABLE = 0xcc,
+       REPLY_BT_COEX_PROT_ENV = 0xcd,
+       REPLY_BT_COEX_PROFILE_NOTIF = 0xce,
+       REPLY_BT_COEX_SCO = 0xcf,
+
+       /* PAN commands */
+       REPLY_WIPAN_PARAMS = 0xb2,
+       REPLY_WIPAN_RXON = 0xb3,        /* use REPLY_RXON structure */
+       REPLY_WIPAN_RXON_TIMING = 0xb4, /* use REPLY_RXON_TIMING structure */
+       REPLY_WIPAN_RXON_ASSOC = 0xb6,  /* use REPLY_RXON_ASSOC structure */
+       REPLY_WIPAN_QOS_PARAM = 0xb7,   /* use REPLY_QOS_PARAM structure */
+       REPLY_WIPAN_WEPKEY = 0xb8,      /* use REPLY_WEPKEY structure */
+       REPLY_WIPAN_P2P_CHANNEL_SWITCH = 0xb9,
+       REPLY_WIPAN_NOA_NOTIFICATION = 0xbc,
+
        REPLY_MAX = 0xff
 };
 
@@ -600,6 +617,9 @@ enum {
        RXON_DEV_TYPE_ESS = 3,
        RXON_DEV_TYPE_IBSS = 4,
        RXON_DEV_TYPE_SNIFFER = 6,
+       RXON_DEV_TYPE_CP = 7,
+       RXON_DEV_TYPE_2STA = 8,
+       RXON_DEV_TYPE_P2P = 9,
 };
 
 
@@ -816,7 +836,8 @@ struct iwl_rxon_time_cmd {
        __le16 atim_window;
        __le32 beacon_init_val;
        __le16 listen_interval;
-       __le16 reserved;
+       u8 dtim_period;
+       u8 delta_cp_bss_tbtts;
 } __packed;
 
 /*
@@ -953,11 +974,13 @@ struct iwl_qosparam_cmd {
 
 /* Special, dedicated locations within device's station table */
 #define        IWL_AP_ID               0
+#define        IWL_AP_ID_PAN           1
 #define        IWL_STA_ID              2
 #define        IWL3945_BROADCAST_ID    24
 #define IWL3945_STATION_COUNT  25
 #define IWL4965_BROADCAST_ID   31
 #define        IWL4965_STATION_COUNT   32
+#define IWLAGN_PAN_BCAST_ID    14
 #define IWLAGN_BROADCAST_ID    15
 #define        IWLAGN_STATION_COUNT    16
 
@@ -966,6 +989,7 @@ struct iwl_qosparam_cmd {
 
 #define STA_FLG_TX_RATE_MSK            cpu_to_le32(1 << 2)
 #define STA_FLG_PWR_SAVE_MSK           cpu_to_le32(1 << 8)
+#define STA_FLG_PAN_STATION            cpu_to_le32(1 << 13)
 #define STA_FLG_RTS_MIMO_PROT_MSK      cpu_to_le32(1 << 17)
 #define STA_FLG_AGG_MPDU_8US_MSK       cpu_to_le32(1 << 18)
 #define STA_FLG_MAX_AGG_SIZE_POS       (19)
@@ -994,6 +1018,7 @@ struct iwl_qosparam_cmd {
 #define STA_KEY_FLG_KEY_SIZE_MSK     cpu_to_le16(0x1000)
 #define STA_KEY_MULTICAST_MSK        cpu_to_le16(0x4000)
 #define STA_KEY_MAX_NUM                8
+#define STA_KEY_MAX_NUM_PAN    16
 
 /* Flags indicate whether to modify vs. don't change various station params */
 #define        STA_MODIFY_KEY_MASK             0x01
@@ -1056,7 +1081,8 @@ struct sta_id_modify {
  *
  * The device contains an internal table of per-station information,
  * with info on security keys, aggregation parameters, and Tx rates for
- * initial Tx attempt and any retries (4965 uses REPLY_TX_LINK_QUALITY_CMD,
+ * initial Tx attempt and any retries (agn devices uses
+ * REPLY_TX_LINK_QUALITY_CMD,
  * 3945 uses REPLY_RATE_SCALE to set up rate tables).
  *
  * REPLY_ADD_STA sets up the table entry for one station, either creating
@@ -1367,21 +1393,24 @@ struct iwl4965_rx_non_cfg_phy {
 } __packed;
 
 
-#define IWL50_RX_RES_PHY_CNT 8
-#define IWL50_RX_RES_AGC_IDX     1
-#define IWL50_RX_RES_RSSI_AB_IDX 2
-#define IWL50_RX_RES_RSSI_C_IDX  3
-#define IWL50_OFDM_AGC_MSK 0xfe00
-#define IWL50_OFDM_AGC_BIT_POS 9
-#define IWL50_OFDM_RSSI_A_MSK 0x00ff
-#define IWL50_OFDM_RSSI_A_BIT_POS 0
-#define IWL50_OFDM_RSSI_B_MSK 0xff0000
-#define IWL50_OFDM_RSSI_B_BIT_POS 16
-#define IWL50_OFDM_RSSI_C_MSK 0x00ff
-#define IWL50_OFDM_RSSI_C_BIT_POS 0
+#define IWLAGN_RX_RES_PHY_CNT 8
+#define IWLAGN_RX_RES_AGC_IDX     1
+#define IWLAGN_RX_RES_RSSI_AB_IDX 2
+#define IWLAGN_RX_RES_RSSI_C_IDX  3
+#define IWLAGN_OFDM_AGC_MSK 0xfe00
+#define IWLAGN_OFDM_AGC_BIT_POS 9
+#define IWLAGN_OFDM_RSSI_INBAND_A_BITMSK 0x00ff
+#define IWLAGN_OFDM_RSSI_ALLBAND_A_BITMSK 0xff00
+#define IWLAGN_OFDM_RSSI_A_BIT_POS 0
+#define IWLAGN_OFDM_RSSI_INBAND_B_BITMSK 0xff0000
+#define IWLAGN_OFDM_RSSI_ALLBAND_B_BITMSK 0xff000000
+#define IWLAGN_OFDM_RSSI_B_BIT_POS 16
+#define IWLAGN_OFDM_RSSI_INBAND_C_BITMSK 0x00ff
+#define IWLAGN_OFDM_RSSI_ALLBAND_C_BITMSK 0xff00
+#define IWLAGN_OFDM_RSSI_C_BIT_POS 0
 
-struct iwl5000_non_cfg_phy {
-       __le32 non_cfg_phy[IWL50_RX_RES_PHY_CNT];  /* up to 8 phy entries */
+struct iwlagn_non_cfg_phy {
+       __le32 non_cfg_phy[IWLAGN_RX_RES_PHY_CNT];  /* up to 8 phy entries */
 } __packed;
 
 
@@ -1401,7 +1430,7 @@ struct iwl_rx_phy_res {
        u8 non_cfg_phy_buf[32]; /* for various implementations of non_cfg_phy */
        __le32 rate_n_flags;    /* RATE_MCS_* */
        __le16 byte_count;      /* frame's byte-count */
-       __le16 reserved3;
+       __le16 frame_time;      /* frame's time on the air */
 } __packed;
 
 struct iwl_rx_mpdu_res_start {
@@ -1424,12 +1453,12 @@ struct iwl_rx_mpdu_res_start {
  * uCode handles all timing and protocol related to control frames
  * (RTS/CTS/ACK), based on flags in the Tx command.  uCode and Tx scheduler
  * handle reception of block-acks; uCode updates the host driver via
- * REPLY_COMPRESSED_BA (4965).
+ * REPLY_COMPRESSED_BA.
  *
  * uCode handles retrying Tx when an ACK is expected but not received.
  * This includes trying lower data rates than the one requested in the Tx
  * command, as set up by the REPLY_RATE_SCALE (for 3945) or
- * REPLY_TX_LINK_QUALITY_CMD (4965).
+ * REPLY_TX_LINK_QUALITY_CMD (agn).
  *
  * Driver sets up transmit power for various rates via REPLY_TX_PWR_TABLE_CMD.
  * This command must be executed after every RXON command, before Tx can occur.
@@ -1465,7 +1494,7 @@ struct iwl_rx_mpdu_res_start {
  * Set this for unicast frames, but not broadcast/multicast. */
 #define TX_CMD_FLG_ACK_MSK cpu_to_le32(1 << 3)
 
-/* For 4965:
+/* For agn devices:
  * 1: Use rate scale table (see REPLY_TX_LINK_QUALITY_CMD).
  *    Tx command's initial_rate_index indicates first rate to try;
  *    uCode walks through table for additional Tx attempts.
@@ -1484,7 +1513,7 @@ struct iwl_rx_mpdu_res_start {
  */
 #define TX_CMD_FLG_FULL_TXOP_PROT_MSK cpu_to_le32(1 << 7)
 
-/* Tx antenna selection field; used only for 3945, reserved (0) for 4965.
+/* Tx antenna selection field; used only for 3945, reserved (0) for agn devices.
  * Set field to "0" to allow 3945 uCode to select antenna (normal usage). */
 #define TX_CMD_FLG_ANT_SEL_MSK cpu_to_le32(0xf00)
 #define TX_CMD_FLG_ANT_A_MSK cpu_to_le32(1 << 8)
@@ -1867,9 +1896,10 @@ enum {
  *     frame in this new agg block failed in previous agg block(s).
  *
  *     Note that, for aggregation, ACK (block-ack) status is not delivered here;
- *     block-ack has not been received by the time the 4965 records this status.
+ *     block-ack has not been received by the time the agn device records
+ *     this status.
  *     This status relates to reasons the tx might have been blocked or aborted
- *     within the sending station (this 4965), rather than whether it was
+ *     within the sending station (this agn device), rather than whether it was
  *     received successfully by the destination station.
  */
 struct agg_tx_status {
@@ -2092,8 +2122,8 @@ struct iwl_link_qual_general_params {
 } __packed;
 
 #define LINK_QUAL_AGG_TIME_LIMIT_DEF   (4000) /* 4 milliseconds */
-#define LINK_QUAL_AGG_TIME_LIMIT_MAX   (65535)
-#define LINK_QUAL_AGG_TIME_LIMIT_MIN   (0)
+#define LINK_QUAL_AGG_TIME_LIMIT_MAX   (8000)
+#define LINK_QUAL_AGG_TIME_LIMIT_MIN   (100)
 
 #define LINK_QUAL_AGG_DISABLE_START_DEF        (3)
 #define LINK_QUAL_AGG_DISABLE_START_MAX        (255)
@@ -2110,8 +2140,10 @@ struct iwl_link_qual_general_params {
  */
 struct iwl_link_qual_agg_params {
 
-       /* Maximum number of uSec in aggregation.
-        * Driver should set this to 4000 (4 milliseconds). */
+       /*
+        *Maximum number of uSec in aggregation.
+        * default set to 4000 (4 milliseconds) if not configured in .cfg
+        */
        __le16 agg_time_limit;
 
        /*
@@ -2135,14 +2167,16 @@ struct iwl_link_qual_agg_params {
 /*
  * REPLY_TX_LINK_QUALITY_CMD = 0x4e (command, has simple generic response)
  *
- * For 4965 only; 3945 uses REPLY_RATE_SCALE.
+ * For agn devices only; 3945 uses REPLY_RATE_SCALE.
  *
- * Each station in the 4965's internal station table has its own table of 16
+ * Each station in the agn device's internal station table has its own table
+ * of 16
  * Tx rates and modulation modes (e.g. legacy/SISO/MIMO) for retrying Tx when
  * an ACK is not received.  This command replaces the entire table for
  * one station.
  *
- * NOTE:  Station must already be in 4965's station table.  Use REPLY_ADD_STA.
+ * NOTE:  Station must already be in agn device's station table.
+ *       Use REPLY_ADD_STA.
  *
  * The rate scaling procedures described below work well.  Of course, other
  * procedures are possible, and may work better for particular environments.
@@ -2179,12 +2213,12 @@ struct iwl_link_qual_agg_params {
  *
  * ACCUMULATING HISTORY
  *
- * The rate scaling algorithm for 4965, as implemented in Linux driver, uses
- * two sets of frame Tx success history:  One for the current/active modulation
- * mode, and one for a speculative/search mode that is being attempted.  If the
- * speculative mode turns out to be more effective (i.e. actual transfer
- * rate is better), then the driver continues to use the speculative mode
- * as the new current active mode.
+ * The rate scaling algorithm for agn devices, as implemented in Linux driver,
+ * uses two sets of frame Tx success history:  One for the current/active
+ * modulation mode, and one for a speculative/search mode that is being
+ * attempted. If the speculative mode turns out to be more effective (i.e.
+ * actual transfer rate is better), then the driver continues to use the
+ * speculative mode as the new current active mode.
  *
  * Each history set contains, separately for each possible rate, data for a
  * sliding window of the 62 most recent tx attempts at that rate.  The data
@@ -2195,12 +2229,12 @@ struct iwl_link_qual_agg_params {
  * The driver uses the bit map to remove successes from the success sum, as
  * the oldest tx attempts fall out of the window.
  *
- * When the 4965 makes multiple tx attempts for a given frame, each attempt
- * might be at a different rate, and have different modulation characteristics
- * (e.g. antenna, fat channel, short guard interval), as set up in the rate
- * scaling table in the Link Quality command.  The driver must determine
- * which rate table entry was used for each tx attempt, to determine which
- * rate-specific history to update, and record only those attempts that
+ * When the agn device makes multiple tx attempts for a given frame, each
+ * attempt might be at a different rate, and have different modulation
+ * characteristics (e.g. antenna, fat channel, short guard interval), as set
+ * up in the rate scaling table in the Link Quality command.  The driver must
+ * determine which rate table entry was used for each tx attempt, to determine
+ * which rate-specific history to update, and record only those attempts that
  * match the modulation characteristics of the history set.
  *
  * When using block-ack (aggregation), all frames are transmitted at the same
@@ -2330,7 +2364,7 @@ struct iwl_link_quality_cmd {
        /*
         * Rate info; when using rate-scaling, Tx command's initial_rate_index
         * specifies 1st Tx rate attempted, via index into this table.
-        * 4965 works its way through table when retrying Tx.
+        * agn devices works its way through table when retrying Tx.
         */
        struct {
                __le32 rate_n_flags;    /* RATE_MCS_*, IWL_RATE_* */
@@ -2363,10 +2397,26 @@ struct iwl_link_quality_cmd {
 #define BT_MAX_KILL_DEF (0x5)
 #define BT_MAX_KILL_MAX (0xFF)
 
+#define BT_DURATION_LIMIT_DEF  625
+#define BT_DURATION_LIMIT_MAX  1250
+#define BT_DURATION_LIMIT_MIN  625
+
+#define BT_ON_THRESHOLD_DEF    4
+#define BT_ON_THRESHOLD_MAX    1000
+#define BT_ON_THRESHOLD_MIN    1
+
+#define BT_FRAG_THRESHOLD_DEF  0
+#define BT_FRAG_THRESHOLD_MAX  0
+#define BT_FRAG_THRESHOLD_MIN  0
+
+#define BT_AGG_THRESHOLD_DEF   0
+#define BT_AGG_THRESHOLD_MAX   0
+#define BT_AGG_THRESHOLD_MIN   0
+
 /*
  * REPLY_BT_CONFIG = 0x9b (command, has simple generic response)
  *
- * 3945 and 4965 support hardware handshake with Bluetooth device on
+ * 3945 and agn devices support hardware handshake with Bluetooth device on
  * same platform.  Bluetooth device alerts wireless device when it will Tx;
  * wireless device can delay or kill its own Tx to accommodate.
  */
@@ -2379,6 +2429,74 @@ struct iwl_bt_cmd {
        __le32 kill_cts_mask;
 } __packed;
 
+#define IWLAGN_BT_FLAG_CHANNEL_INHIBITION      BIT(0)
+
+#define IWLAGN_BT_FLAG_COEX_MODE_MASK          (BIT(3)|BIT(4)|BIT(5))
+#define IWLAGN_BT_FLAG_COEX_MODE_SHIFT         3
+#define IWLAGN_BT_FLAG_COEX_MODE_DISABLED      0
+#define IWLAGN_BT_FLAG_COEX_MODE_LEGACY_2W     1
+#define IWLAGN_BT_FLAG_COEX_MODE_3W            2
+#define IWLAGN_BT_FLAG_COEX_MODE_4W            3
+
+#define IWLAGN_BT_FLAG_UCODE_DEFAULT   BIT(6)
+#define IWLAGN_BT_FLAG_NOCOEX_NOTIF    BIT(7)
+
+#define IWLAGN_BT_PRIO_BOOST_MAX       0xFF
+#define IWLAGN_BT_PRIO_BOOST_MIN       0x00
+#define IWLAGN_BT_PRIO_BOOST_DEFAULT   0xF0
+
+#define IWLAGN_BT_MAX_KILL_DEFAULT     5
+
+#define IWLAGN_BT3_T7_DEFAULT          1
+
+#define IWLAGN_BT_KILL_ACK_MASK_DEFAULT        cpu_to_le32(0xffffffff)
+#define IWLAGN_BT_KILL_CTS_MASK_DEFAULT        cpu_to_le32(0xffffffff)
+
+#define IWLAGN_BT3_PRIO_SAMPLE_DEFAULT 2
+
+#define IWLAGN_BT3_T2_DEFAULT          0xc
+
+#define IWLAGN_BT_VALID_ENABLE_FLAGS   cpu_to_le16(BIT(0))
+#define IWLAGN_BT_VALID_BOOST          cpu_to_le16(BIT(1))
+#define IWLAGN_BT_VALID_MAX_KILL       cpu_to_le16(BIT(2))
+#define IWLAGN_BT_VALID_3W_TIMERS      cpu_to_le16(BIT(3))
+#define IWLAGN_BT_VALID_KILL_ACK_MASK  cpu_to_le16(BIT(4))
+#define IWLAGN_BT_VALID_KILL_CTS_MASK  cpu_to_le16(BIT(5))
+#define IWLAGN_BT_VALID_BT4_TIMES      cpu_to_le16(BIT(6))
+#define IWLAGN_BT_VALID_3W_LUT         cpu_to_le16(BIT(7))
+
+#define IWLAGN_BT_ALL_VALID_MSK                (IWLAGN_BT_VALID_ENABLE_FLAGS | \
+                                       IWLAGN_BT_VALID_BOOST | \
+                                       IWLAGN_BT_VALID_MAX_KILL | \
+                                       IWLAGN_BT_VALID_3W_TIMERS | \
+                                       IWLAGN_BT_VALID_KILL_ACK_MASK | \
+                                       IWLAGN_BT_VALID_KILL_CTS_MASK | \
+                                       IWLAGN_BT_VALID_BT4_TIMES | \
+                                       IWLAGN_BT_VALID_3W_LUT)
+
+struct iwlagn_bt_cmd {
+       u8 flags;
+       u8 ledtime; /* unused */
+       u8 max_kill;
+       u8 bt3_timer_t7_value;
+       __le32 kill_ack_mask;
+       __le32 kill_cts_mask;
+       u8 bt3_prio_sample_time;
+       u8 bt3_timer_t2_value;
+       __le16 bt4_reaction_time; /* unused */
+       __le32 bt3_lookup_table[12];
+       __le16 bt4_decision_time; /* unused */
+       __le16 valid;
+       u8 prio_boost;
+       u8 reserved[3];
+};
+
+#define IWLAGN_BT_SCO_ACTIVE   cpu_to_le32(BIT(0))
+
+struct iwlagn_bt_sco_cmd {
+       __le32 flags;
+};
+
 /******************************************************************************
  * (6)
  * Spectrum Management (802.11h) Commands, Responses, Notifications:
@@ -2567,7 +2685,7 @@ struct iwl_powertable_cmd {
 
 /*
  * PM_SLEEP_NOTIFICATION = 0x7A (notification only, not a command)
- * 3945 and 4965 identical.
+ * all devices identical.
  */
 struct iwl_sleep_notification {
        u8 pm_sleep_mode;
@@ -2578,7 +2696,7 @@ struct iwl_sleep_notification {
        __le32 bcon_timer;
 } __packed;
 
-/* Sleep states.  3945 and 4965 identical. */
+/* Sleep states.  all devices identical. */
 enum {
        IWL_PM_NO_SLEEP = 0,
        IWL_PM_SLP_MAC = 1,
@@ -2887,6 +3005,12 @@ struct iwl_scanstart_notification {
 #define  SCAN_OWNER_STATUS 0x1;
 #define  MEASURE_OWNER_STATUS 0x2;
 
+#define IWL_PROBE_STATUS_OK            0
+#define IWL_PROBE_STATUS_TX_FAILED     BIT(0)
+/* error statuses combined with TX_FAILED */
+#define IWL_PROBE_STATUS_FAIL_TTL      BIT(1)
+#define IWL_PROBE_STATUS_FAIL_BT       BIT(2)
+
 #define NUMBER_OF_STATISTICS 1 /* first __le32 is good CRC */
 /*
  * SCAN_RESULTS_NOTIFICATION = 0x83 (notification only, not a command)
@@ -2894,7 +3018,8 @@ struct iwl_scanstart_notification {
 struct iwl_scanresults_notification {
        u8 channel;
        u8 band;
-       u8 reserved[2];
+       u8 probe_status;
+       u8 num_probe_not_sent; /* not enough time to send */
        __le32 tsf_low;
        __le32 tsf_high;
        __le32 statistics[NUMBER_OF_STATISTICS];
@@ -2906,7 +3031,7 @@ struct iwl_scanresults_notification {
 struct iwl_scancomplete_notification {
        u8 scanned_channels;
        u8 status;
-       u8 reserved;
+       u8 bt_status;   /* BT On/Off status */
        u8 last_channel;
        __le32 tsf_low;
        __le32 tsf_high;
@@ -2919,6 +3044,11 @@ struct iwl_scancomplete_notification {
  *
  *****************************************************************************/
 
+enum iwl_ibss_manager {
+       IWL_NOT_IBSS_MANAGER = 0,
+       IWL_IBSS_MANAGER = 1,
+};
+
 /*
  * BEACON_NOTIFICATION = 0x90 (notification only, not a command)
  */
@@ -3260,7 +3390,7 @@ struct statistics_general_bt {
 
 /*
  * REPLY_STATISTICS_CMD = 0x9c,
- * 3945 and 4965 identical.
+ * all devices identical.
  *
  * This command triggers an immediate response containing uCode statistics.
  * The response is in the same format as STATISTICS_NOTIFICATION 0x9d, below.
@@ -3598,7 +3728,7 @@ struct iwl_enhance_sensitivity_cmd {
 /**
  * REPLY_PHY_CALIBRATION_CMD = 0xb0 (command, has simple generic response)
  *
- * This command sets the relative gains of 4965's 3 radio receiver chains.
+ * This command sets the relative gains of agn device's 3 radio receiver chains.
  *
  * After the first association, driver should accumulate signal and noise
  * statistics from the STATISTICS_NOTIFICATIONs that follow the first 20
@@ -3954,6 +4084,201 @@ struct iwl_coex_event_resp {
 } __packed;
 
 
+/******************************************************************************
+ * Bluetooth Coexistence commands
+ *
+ *****************************************************************************/
+
+/*
+ * BT Status notification
+ * REPLY_BT_COEX_PROFILE_NOTIF = 0xce
+ */
+enum iwl_bt_coex_profile_traffic_load {
+       IWL_BT_COEX_TRAFFIC_LOAD_NONE =         0,
+       IWL_BT_COEX_TRAFFIC_LOAD_LOW =          1,
+       IWL_BT_COEX_TRAFFIC_LOAD_HIGH =         2,
+       IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS =   3,
+/*
+ * There are no more even though below is a u8, the
+ * indication from the BT device only has two bits.
+ */
+};
+
+#define BT_UART_MSG_FRAME1MSGTYPE_POS          (0)
+#define BT_UART_MSG_FRAME1MSGTYPE_MSK          \
+               (0x7 << BT_UART_MSG_FRAME1MSGTYPE_POS)
+#define BT_UART_MSG_FRAME1SSN_POS              (3)
+#define BT_UART_MSG_FRAME1SSN_MSK              \
+               (0x3 << BT_UART_MSG_FRAME1SSN_POS)
+#define BT_UART_MSG_FRAME1UPDATEREQ_POS                (5)
+#define BT_UART_MSG_FRAME1UPDATEREQ_MSK                \
+               (0x1 << BT_UART_MSG_FRAME1UPDATEREQ_POS)
+#define BT_UART_MSG_FRAME1RESERVED_POS         (6)
+#define BT_UART_MSG_FRAME1RESERVED_MSK         \
+               (0x3 << BT_UART_MSG_FRAME1RESERVED_POS)
+
+#define BT_UART_MSG_FRAME2OPENCONNECTIONS_POS  (0)
+#define BT_UART_MSG_FRAME2OPENCONNECTIONS_MSK  \
+               (0x3 << BT_UART_MSG_FRAME2OPENCONNECTIONS_POS)
+#define BT_UART_MSG_FRAME2TRAFFICLOAD_POS      (2)
+#define BT_UART_MSG_FRAME2TRAFFICLOAD_MSK      \
+               (0x3 << BT_UART_MSG_FRAME2TRAFFICLOAD_POS)
+#define BT_UART_MSG_FRAME2CHLSEQN_POS          (4)
+#define BT_UART_MSG_FRAME2CHLSEQN_MSK          \
+               (0x1 << BT_UART_MSG_FRAME2CHLSEQN_POS)
+#define BT_UART_MSG_FRAME2INBAND_POS           (5)
+#define BT_UART_MSG_FRAME2INBAND_MSK           \
+               (0x1 << BT_UART_MSG_FRAME2INBAND_POS)
+#define BT_UART_MSG_FRAME2RESERVED_POS         (6)
+#define BT_UART_MSG_FRAME2RESERVED_MSK         \
+               (0x3 << BT_UART_MSG_FRAME2RESERVED_POS)
+
+#define BT_UART_MSG_FRAME3SCOESCO_POS          (0)
+#define BT_UART_MSG_FRAME3SCOESCO_MSK          \
+               (0x1 << BT_UART_MSG_FRAME3SCOESCO_POS)
+#define BT_UART_MSG_FRAME3SNIFF_POS            (1)
+#define BT_UART_MSG_FRAME3SNIFF_MSK            \
+               (0x1 << BT_UART_MSG_FRAME3SNIFF_POS)
+#define BT_UART_MSG_FRAME3A2DP_POS             (2)
+#define BT_UART_MSG_FRAME3A2DP_MSK             \
+               (0x1 << BT_UART_MSG_FRAME3A2DP_POS)
+#define BT_UART_MSG_FRAME3ACL_POS              (3)
+#define BT_UART_MSG_FRAME3ACL_MSK              \
+               (0x1 << BT_UART_MSG_FRAME3ACL_POS)
+#define BT_UART_MSG_FRAME3MASTER_POS           (4)
+#define BT_UART_MSG_FRAME3MASTER_MSK           \
+               (0x1 << BT_UART_MSG_FRAME3MASTER_POS)
+#define BT_UART_MSG_FRAME3OBEX_POS             (5)
+#define BT_UART_MSG_FRAME3OBEX_MSK             \
+               (0x1 << BT_UART_MSG_FRAME3OBEX_POS)
+#define BT_UART_MSG_FRAME3RESERVED_POS         (6)
+#define BT_UART_MSG_FRAME3RESERVED_MSK         \
+               (0x3 << BT_UART_MSG_FRAME3RESERVED_POS)
+
+#define BT_UART_MSG_FRAME4IDLEDURATION_POS     (0)
+#define BT_UART_MSG_FRAME4IDLEDURATION_MSK     \
+               (0x3F << BT_UART_MSG_FRAME4IDLEDURATION_POS)
+#define BT_UART_MSG_FRAME4RESERVED_POS         (6)
+#define BT_UART_MSG_FRAME4RESERVED_MSK         \
+               (0x3 << BT_UART_MSG_FRAME4RESERVED_POS)
+
+#define BT_UART_MSG_FRAME5TXACTIVITY_POS       (0)
+#define BT_UART_MSG_FRAME5TXACTIVITY_MSK       \
+               (0x3 << BT_UART_MSG_FRAME5TXACTIVITY_POS)
+#define BT_UART_MSG_FRAME5RXACTIVITY_POS       (2)
+#define BT_UART_MSG_FRAME5RXACTIVITY_MSK       \
+               (0x3 << BT_UART_MSG_FRAME5RXACTIVITY_POS)
+#define BT_UART_MSG_FRAME5ESCORETRANSMIT_POS   (4)
+#define BT_UART_MSG_FRAME5ESCORETRANSMIT_MSK   \
+               (0x3 << BT_UART_MSG_FRAME5ESCORETRANSMIT_POS)
+#define BT_UART_MSG_FRAME5RESERVED_POS         (6)
+#define BT_UART_MSG_FRAME5RESERVED_MSK         \
+               (0x3 << BT_UART_MSG_FRAME5RESERVED_POS)
+
+#define BT_UART_MSG_FRAME6SNIFFINTERVAL_POS    (0)
+#define BT_UART_MSG_FRAME6SNIFFINTERVAL_MSK    \
+               (0x1F << BT_UART_MSG_FRAME6SNIFFINTERVAL_POS)
+#define BT_UART_MSG_FRAME6DISCOVERABLE_POS     (5)
+#define BT_UART_MSG_FRAME6DISCOVERABLE_MSK     \
+               (0x1 << BT_UART_MSG_FRAME6DISCOVERABLE_POS)
+#define BT_UART_MSG_FRAME6RESERVED_POS         (6)
+#define BT_UART_MSG_FRAME6RESERVED_MSK         \
+               (0x3 << BT_UART_MSG_FRAME6RESERVED_POS)
+
+#define BT_UART_MSG_FRAME7SNIFFACTIVITY_POS    (0)
+#define BT_UART_MSG_FRAME7SNIFFACTIVITY_MSK    \
+               (0x7 << BT_UART_MSG_FRAME7SNIFFACTIVITY_POS)
+#define BT_UART_MSG_FRAME7INQUIRYPAGESRMODE_POS        (3)
+#define BT_UART_MSG_FRAME7INQUIRYPAGESRMODE_MSK        \
+               (0x3 << BT_UART_MSG_FRAME7INQUIRYPAGESRMODE_POS)
+#define BT_UART_MSG_FRAME7CONNECTABLE_POS      (5)
+#define BT_UART_MSG_FRAME7CONNECTABLE_MSK      \
+               (0x1 << BT_UART_MSG_FRAME7CONNECTABLE_POS)
+#define BT_UART_MSG_FRAME7RESERVED_POS         (6)
+#define BT_UART_MSG_FRAME7RESERVED_MSK         \
+               (0x3 << BT_UART_MSG_FRAME7RESERVED_POS)
+
+
+struct iwl_bt_uart_msg {
+       u8 header;
+       u8 frame1;
+       u8 frame2;
+       u8 frame3;
+       u8 frame4;
+       u8 frame5;
+       u8 frame6;
+       u8 frame7;
+} __attribute__((packed));
+
+struct iwl_bt_coex_profile_notif {
+       struct iwl_bt_uart_msg last_bt_uart_msg;
+       u8 bt_status; /* 0 - off, 1 - on */
+       u8 bt_traffic_load; /* 0 .. 3? */
+       u8 bt_ci_compliance; /* 0 - not complied, 1 - complied */
+       u8 reserved;
+} __attribute__((packed));
+
+#define IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_POS        0
+#define IWL_BT_COEX_PRIO_TBL_SHARED_ANTENNA_MSK        0x1
+#define IWL_BT_COEX_PRIO_TBL_PRIO_POS          1
+#define IWL_BT_COEX_PRIO_TBL_PRIO_MASK         0x0e
+#define IWL_BT_COEX_PRIO_TBL_RESERVED_POS      4
+#define IWL_BT_COEX_PRIO_TBL_RESERVED_MASK     0xf0
+#define IWL_BT_COEX_PRIO_TBL_PRIO_SHIFT                1
+
+/*
+ * BT Coexistence Priority table
+ * REPLY_BT_COEX_PRIO_TABLE = 0xcc
+ */
+enum bt_coex_prio_table_events {
+       BT_COEX_PRIO_TBL_EVT_INIT_CALIB1 = 0,
+       BT_COEX_PRIO_TBL_EVT_INIT_CALIB2 = 1,
+       BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_LOW1 = 2,
+       BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_LOW2 = 3, /* DC calib */
+       BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_HIGH1 = 4,
+       BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_HIGH2 = 5,
+       BT_COEX_PRIO_TBL_EVT_DTIM = 6,
+       BT_COEX_PRIO_TBL_EVT_SCAN52 = 7,
+       BT_COEX_PRIO_TBL_EVT_SCAN24 = 8,
+       BT_COEX_PRIO_TBL_EVT_RESERVED0 = 9,
+       BT_COEX_PRIO_TBL_EVT_RESERVED1 = 10,
+       BT_COEX_PRIO_TBL_EVT_RESERVED2 = 11,
+       BT_COEX_PRIO_TBL_EVT_RESERVED3 = 12,
+       BT_COEX_PRIO_TBL_EVT_RESERVED4 = 13,
+       BT_COEX_PRIO_TBL_EVT_RESERVED5 = 14,
+       BT_COEX_PRIO_TBL_EVT_RESERVED6 = 15,
+       /* BT_COEX_PRIO_TBL_EVT_MAX should always be last */
+       BT_COEX_PRIO_TBL_EVT_MAX,
+};
+
+enum bt_coex_prio_table_priorities {
+       BT_COEX_PRIO_TBL_DISABLED = 0,
+       BT_COEX_PRIO_TBL_PRIO_LOW = 1,
+       BT_COEX_PRIO_TBL_PRIO_HIGH = 2,
+       BT_COEX_PRIO_TBL_PRIO_BYPASS = 3,
+       BT_COEX_PRIO_TBL_PRIO_COEX_OFF = 4,
+       BT_COEX_PRIO_TBL_PRIO_COEX_ON = 5,
+       BT_COEX_PRIO_TBL_PRIO_RSRVD1 = 6,
+       BT_COEX_PRIO_TBL_PRIO_RSRVD2 = 7,
+       BT_COEX_PRIO_TBL_MAX,
+};
+
+struct iwl_bt_coex_prio_table_cmd {
+       u8 prio_tbl[BT_COEX_PRIO_TBL_EVT_MAX];
+} __attribute__((packed));
+
+#define IWL_BT_COEX_ENV_CLOSE  0
+#define IWL_BT_COEX_ENV_OPEN   1
+/*
+ * BT Protection Envelope
+ * REPLY_BT_COEX_PROT_ENV = 0xcd
+ */
+struct iwl_bt_coex_prot_env_cmd {
+       u8 action; /* 0 = closed, 1 = open */
+       u8 type; /* 0 .. 15 */
+       u8 reserved[2];
+} __attribute__((packed));
+
 /******************************************************************************
  * (13)
  * Union of all expected notifications/responses:
@@ -3993,6 +4318,7 @@ struct iwl_rx_packet {
                struct iwl_missed_beacon_notif missed_beacon;
                struct iwl_coex_medium_notification coex_medium_notif;
                struct iwl_coex_event_resp coex_event;
+               struct iwl_bt_coex_profile_notif bt_coex_profile_notif;
                __le32 status;
                u8 raw[0];
        } u;
@@ -4000,4 +4326,94 @@ struct iwl_rx_packet {
 
 int iwl_agn_check_rxon_cmd(struct iwl_priv *priv);
 
+/*
+ * REPLY_WIPAN_PARAMS = 0xb2 (Commands and Notification)
+ */
+
+/**
+ * struct iwl_wipan_slot
+ * @width: Time in TU
+ * @type:
+ *   0 - BSS
+ *   1 - PAN
+ */
+struct iwl_wipan_slot {
+       __le16 width;
+       u8 type;
+       u8 reserved;
+} __packed;
+
+#define IWL_WIPAN_PARAMS_FLG_LEAVE_CHANNEL_CTS         BIT(1)  /* reserved */
+#define IWL_WIPAN_PARAMS_FLG_LEAVE_CHANNEL_QUIET       BIT(2)  /* reserved */
+#define IWL_WIPAN_PARAMS_FLG_SLOTTED_MODE              BIT(3)  /* reserved */
+#define IWL_WIPAN_PARAMS_FLG_FILTER_BEACON_NOTIF       BIT(4)
+#define IWL_WIPAN_PARAMS_FLG_FULL_SLOTTED_MODE         BIT(5)
+
+/**
+ * struct iwl_wipan_params_cmd
+ * @flags:
+ *   bit0: reserved
+ *   bit1: CP leave channel with CTS
+ *   bit2: CP leave channel qith Quiet
+ *   bit3: slotted mode
+ *     1 - work in slotted mode
+ *     0 - work in non slotted mode
+ *   bit4: filter beacon notification
+ *   bit5: full tx slotted mode. if this flag is set,
+ *         uCode will perform leaving channel methods in context switch
+ *         also when working in same channel mode
+ * @num_slots: 1 - 10
+ */
+struct iwl_wipan_params_cmd {
+       __le16 flags;
+       u8 reserved;
+       u8 num_slots;
+       struct iwl_wipan_slot slots[10];
+} __packed;
+
+/*
+ * REPLY_WIPAN_P2P_CHANNEL_SWITCH = 0xb9
+ *
+ * TODO: Figure out what this is used for,
+ *      it can only switch between 2.4 GHz
+ *      channels!!
+ */
+
+struct iwl_wipan_p2p_channel_switch_cmd {
+       __le16 channel;
+       __le16 reserved;
+};
+
+/*
+ * REPLY_WIPAN_NOA_NOTIFICATION = 0xbc
+ *
+ * This is used by the device to notify us of the
+ * NoA schedule it determined so we can forward it
+ * to userspace for inclusion in probe responses.
+ *
+ * In beacons, the NoA schedule is simply appended
+ * to the frame we give the device.
+ */
+
+struct iwl_wipan_noa_descriptor {
+       u8 count;
+       __le32 duration;
+       __le32 interval;
+       __le32 starttime;
+} __packed;
+
+struct iwl_wipan_noa_attribute {
+       u8 id;
+       __le16 length;
+       u8 index;
+       u8 ct_window;
+       struct iwl_wipan_noa_descriptor descr0, descr1;
+       u8 reserved;
+} __packed;
+
+struct iwl_wipan_noa_notification {
+       u32 noa_active;
+       struct iwl_wipan_noa_attribute noa_attribute;
+} __packed;
+
 #endif                         /* __iwl_commands_h__ */
index 07dbc27964480eebedb67760029dcadab9584f84..87a2e40972ba85437a9fd26dd239244b2c1cf1fb 100644 (file)
@@ -64,7 +64,8 @@ MODULE_LICENSE("GPL");
  *
  * default: bt_coex_active = true (BT_COEX_ENABLE)
  */
-static bool bt_coex_active = true;
+bool bt_coex_active = true;
+EXPORT_SYMBOL_GPL(bt_coex_active);
 module_param(bt_coex_active, bool, S_IRUGO);
 MODULE_PARM_DESC(bt_coex_active, "enable wifi/bluetooth co-exist");
 
@@ -146,6 +147,10 @@ u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant, u8 valid)
        int i;
        u8 ind = ant;
 
+       if (priv->band == IEEE80211_BAND_2GHZ &&
+           priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH)
+               return 0;
+
        for (i = 0; i < RATE_ANT_NUM - 1; i++) {
                ind = (ind + 1) < RATE_ANT_NUM ?  ind + 1 : 0;
                if (valid & BIT(ind))
@@ -183,38 +188,30 @@ out:
 }
 EXPORT_SYMBOL(iwl_alloc_all);
 
-void iwl_hw_detect(struct iwl_priv *priv)
-{
-       priv->hw_rev = _iwl_read32(priv, CSR_HW_REV);
-       priv->hw_wa_rev = _iwl_read32(priv, CSR_HW_REV_WA_REG);
-       pci_read_config_byte(priv->pci_dev, PCI_REVISION_ID, &priv->rev_id);
-}
-EXPORT_SYMBOL(iwl_hw_detect);
-
 /*
  * QoS  support
 */
-static void iwl_update_qos(struct iwl_priv *priv)
+static void iwl_update_qos(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
 {
        if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return;
 
-       priv->qos_data.def_qos_parm.qos_flags = 0;
+       ctx->qos_data.def_qos_parm.qos_flags = 0;
 
-       if (priv->qos_data.qos_active)
-               priv->qos_data.def_qos_parm.qos_flags |=
+       if (ctx->qos_data.qos_active)
+               ctx->qos_data.def_qos_parm.qos_flags |=
                        QOS_PARAM_FLG_UPDATE_EDCA_MSK;
 
-       if (priv->current_ht_config.is_ht)
-               priv->qos_data.def_qos_parm.qos_flags |= QOS_PARAM_FLG_TGN_MSK;
+       if (ctx->ht.enabled)
+               ctx->qos_data.def_qos_parm.qos_flags |= QOS_PARAM_FLG_TGN_MSK;
 
        IWL_DEBUG_QOS(priv, "send QoS cmd with Qos active=%d FLAGS=0x%X\n",
-                     priv->qos_data.qos_active,
-                     priv->qos_data.def_qos_parm.qos_flags);
+                     ctx->qos_data.qos_active,
+                     ctx->qos_data.def_qos_parm.qos_flags);
 
-       iwl_send_cmd_pdu_async(priv, REPLY_QOS_PARAM,
+       iwl_send_cmd_pdu_async(priv, ctx->qos_cmd,
                               sizeof(struct iwl_qosparam_cmd),
-                              &priv->qos_data.def_qos_parm, NULL);
+                              &ctx->qos_data.def_qos_parm, NULL);
 }
 
 #define MAX_BIT_RATE_40_MHZ 150 /* Mbps */
@@ -247,7 +244,11 @@ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv,
                ht_info->cap |= IEEE80211_HT_CAP_MAX_AMSDU;
 
        ht_info->ampdu_factor = CFG_HT_RX_AMPDU_FACTOR_DEF;
+       if (priv->cfg->ampdu_factor)
+               ht_info->ampdu_factor = priv->cfg->ampdu_factor;
        ht_info->ampdu_density = CFG_HT_MPDU_DENSITY_DEF;
+       if (priv->cfg->ampdu_density)
+               ht_info->ampdu_density = priv->cfg->ampdu_density;
 
        ht_info->mcs.rx_mask[0] = 0xFF;
        if (rx_chains_num >= 2)
@@ -440,15 +441,15 @@ static bool is_single_rx_stream(struct iwl_priv *priv)
               priv->current_ht_config.single_chain_sufficient;
 }
 
-static u8 iwl_is_channel_extension(struct iwl_priv *priv,
-                                  enum ieee80211_band band,
-                                  u16 channel, u8 extension_chan_offset)
+static bool iwl_is_channel_extension(struct iwl_priv *priv,
+                                    enum ieee80211_band band,
+                                    u16 channel, u8 extension_chan_offset)
 {
        const struct iwl_channel_info *ch_info;
 
        ch_info = iwl_get_channel_info(priv, band, channel);
        if (!is_channel_valid(ch_info))
-               return 0;
+               return false;
 
        if (extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE)
                return !(ch_info->ht40_extension_channel &
@@ -457,31 +458,31 @@ static u8 iwl_is_channel_extension(struct iwl_priv *priv,
                return !(ch_info->ht40_extension_channel &
                                        IEEE80211_CHAN_NO_HT40MINUS);
 
-       return 0;
+       return false;
 }
 
-u8 iwl_is_ht40_tx_allowed(struct iwl_priv *priv,
-                        struct ieee80211_sta_ht_cap *sta_ht_inf)
+bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv,
+                           struct iwl_rxon_context *ctx,
+                           struct ieee80211_sta_ht_cap *ht_cap)
 {
-       struct iwl_ht_config *ht_conf = &priv->current_ht_config;
+       if (!ctx->ht.enabled || !ctx->ht.is_40mhz)
+               return false;
 
-       if (!ht_conf->is_ht || !ht_conf->is_40mhz)
-               return 0;
-
-       /* We do not check for IEEE80211_HT_CAP_SUP_WIDTH_20_40
+       /*
+        * We do not check for IEEE80211_HT_CAP_SUP_WIDTH_20_40
         * the bit will not set if it is pure 40MHz case
         */
-       if (sta_ht_inf) {
-               if (!sta_ht_inf->ht_supported)
-                       return 0;
-       }
+       if (ht_cap && !ht_cap->ht_supported)
+               return false;
+
 #ifdef CONFIG_IWLWIFI_DEBUGFS
        if (priv->disable_ht40)
-               return 0;
+               return false;
 #endif
+
        return iwl_is_channel_extension(priv, priv->band,
-                       le16_to_cpu(priv->staging_rxon.channel),
-                       ht_conf->extension_chan_offset);
+                       le16_to_cpu(ctx->staging.channel),
+                       ctx->ht.extension_chan_offset);
 }
 EXPORT_SYMBOL(iwl_is_ht40_tx_allowed);
 
@@ -499,51 +500,64 @@ static u16 iwl_adjust_beacon_interval(u16 beacon_val, u16 max_beacon_val)
        return new_val;
 }
 
-void iwl_setup_rxon_timing(struct iwl_priv *priv, struct ieee80211_vif *vif)
+int iwl_send_rxon_timing(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
 {
        u64 tsf;
        s32 interval_tm, rem;
-       unsigned long flags;
        struct ieee80211_conf *conf = NULL;
        u16 beacon_int;
+       struct ieee80211_vif *vif = ctx->vif;
 
        conf = ieee80211_get_hw_conf(priv->hw);
 
-       spin_lock_irqsave(&priv->lock, flags);
-       priv->rxon_timing.timestamp = cpu_to_le64(priv->timestamp);
-       priv->rxon_timing.listen_interval = cpu_to_le16(conf->listen_interval);
+       lockdep_assert_held(&priv->mutex);
 
-       beacon_int = vif->bss_conf.beacon_int;
+       memset(&ctx->timing, 0, sizeof(struct iwl_rxon_time_cmd));
 
-       if (vif->type == NL80211_IFTYPE_ADHOC) {
-               /* TODO: we need to get atim_window from upper stack
-                * for now we set to 0 */
-               priv->rxon_timing.atim_window = 0;
-       } else {
-               priv->rxon_timing.atim_window = 0;
-       }
+       ctx->timing.timestamp = cpu_to_le64(priv->timestamp);
+       ctx->timing.listen_interval = cpu_to_le16(conf->listen_interval);
 
-       beacon_int = iwl_adjust_beacon_interval(beacon_int,
+       beacon_int = vif ? vif->bss_conf.beacon_int : 0;
+
+       /*
+        * TODO: For IBSS we need to get atim_window from mac80211,
+        *       for now just always use 0
+        */
+       ctx->timing.atim_window = 0;
+
+       if (ctx->ctxid == IWL_RXON_CTX_PAN &&
+           (!ctx->vif || ctx->vif->type != NL80211_IFTYPE_STATION)) {
+               ctx->timing.beacon_interval =
+                       priv->contexts[IWL_RXON_CTX_BSS].timing.beacon_interval;
+               beacon_int = le16_to_cpu(ctx->timing.beacon_interval);
+       } else {
+               beacon_int = iwl_adjust_beacon_interval(beacon_int,
                                priv->hw_params.max_beacon_itrvl * TIME_UNIT);
-       priv->rxon_timing.beacon_interval = cpu_to_le16(beacon_int);
+               ctx->timing.beacon_interval = cpu_to_le16(beacon_int);
+       }
 
        tsf = priv->timestamp; /* tsf is modifed by do_div: copy it */
        interval_tm = beacon_int * TIME_UNIT;
        rem = do_div(tsf, interval_tm);
-       priv->rxon_timing.beacon_init_val = cpu_to_le32(interval_tm - rem);
+       ctx->timing.beacon_init_val = cpu_to_le32(interval_tm - rem);
+
+       ctx->timing.dtim_period = vif ? (vif->bss_conf.dtim_period ?: 1) : 1;
 
-       spin_unlock_irqrestore(&priv->lock, flags);
        IWL_DEBUG_ASSOC(priv,
                        "beacon interval %d beacon timer %d beacon tim %d\n",
-                       le16_to_cpu(priv->rxon_timing.beacon_interval),
-                       le32_to_cpu(priv->rxon_timing.beacon_init_val),
-                       le16_to_cpu(priv->rxon_timing.atim_window));
+                       le16_to_cpu(ctx->timing.beacon_interval),
+                       le32_to_cpu(ctx->timing.beacon_init_val),
+                       le16_to_cpu(ctx->timing.atim_window));
+
+       return iwl_send_cmd_pdu(priv, ctx->rxon_timing_cmd,
+                               sizeof(ctx->timing), &ctx->timing);
 }
-EXPORT_SYMBOL(iwl_setup_rxon_timing);
+EXPORT_SYMBOL(iwl_send_rxon_timing);
 
-void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt)
+void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
+                          int hw_decrypt)
 {
-       struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
+       struct iwl_rxon_cmd *rxon = &ctx->staging;
 
        if (hw_decrypt)
                rxon->filter_flags &= ~RXON_FILTER_DIS_DECRYPT_MSK;
@@ -560,11 +574,11 @@ EXPORT_SYMBOL(iwl_set_rxon_hwcrypto);
  * be #ifdef'd out once the driver is stable and folks aren't actively
  * making changes
  */
-int iwl_check_rxon_cmd(struct iwl_priv *priv)
+int iwl_check_rxon_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
 {
        int error = 0;
        int counter = 1;
-       struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
+       struct iwl_rxon_cmd *rxon = &ctx->staging;
 
        if (rxon->flags & RXON_FLG_BAND_24G_MSK) {
                error |= le32_to_cpu(rxon->flags &
@@ -636,66 +650,83 @@ EXPORT_SYMBOL(iwl_check_rxon_cmd);
  * or is clearing the RXON_FILTER_ASSOC_MSK, then return 1 to indicate that
  * a new tune (full RXON command, rather than RXON_ASSOC cmd) is required.
  */
-int iwl_full_rxon_required(struct iwl_priv *priv)
+int iwl_full_rxon_required(struct iwl_priv *priv,
+                          struct iwl_rxon_context *ctx)
 {
+       const struct iwl_rxon_cmd *staging = &ctx->staging;
+       const struct iwl_rxon_cmd *active = &ctx->active;
+
+#define CHK(cond)                                                      \
+       if ((cond)) {                                                   \
+               IWL_DEBUG_INFO(priv, "need full RXON - " #cond "\n");   \
+               return 1;                                               \
+       }
+
+#define CHK_NEQ(c1, c2)                                                \
+       if ((c1) != (c2)) {                                     \
+               IWL_DEBUG_INFO(priv, "need full RXON - "        \
+                              #c1 " != " #c2 " - %d != %d\n",  \
+                              (c1), (c2));                     \
+               return 1;                                       \
+       }
 
        /* These items are only settable from the full RXON command */
-       if (!(iwl_is_associated(priv)) ||
-           compare_ether_addr(priv->staging_rxon.bssid_addr,
-                              priv->active_rxon.bssid_addr) ||
-           compare_ether_addr(priv->staging_rxon.node_addr,
-                              priv->active_rxon.node_addr) ||
-           compare_ether_addr(priv->staging_rxon.wlap_bssid_addr,
-                              priv->active_rxon.wlap_bssid_addr) ||
-           (priv->staging_rxon.dev_type != priv->active_rxon.dev_type) ||
-           (priv->staging_rxon.channel != priv->active_rxon.channel) ||
-           (priv->staging_rxon.air_propagation !=
-            priv->active_rxon.air_propagation) ||
-           (priv->staging_rxon.ofdm_ht_single_stream_basic_rates !=
-            priv->active_rxon.ofdm_ht_single_stream_basic_rates) ||
-           (priv->staging_rxon.ofdm_ht_dual_stream_basic_rates !=
-            priv->active_rxon.ofdm_ht_dual_stream_basic_rates) ||
-           (priv->staging_rxon.ofdm_ht_triple_stream_basic_rates !=
-            priv->active_rxon.ofdm_ht_triple_stream_basic_rates) ||
-           (priv->staging_rxon.assoc_id != priv->active_rxon.assoc_id))
-               return 1;
+       CHK(!iwl_is_associated_ctx(ctx));
+       CHK(compare_ether_addr(staging->bssid_addr, active->bssid_addr));
+       CHK(compare_ether_addr(staging->node_addr, active->node_addr));
+       CHK(compare_ether_addr(staging->wlap_bssid_addr,
+                               active->wlap_bssid_addr));
+       CHK_NEQ(staging->dev_type, active->dev_type);
+       CHK_NEQ(staging->channel, active->channel);
+       CHK_NEQ(staging->air_propagation, active->air_propagation);
+       CHK_NEQ(staging->ofdm_ht_single_stream_basic_rates,
+               active->ofdm_ht_single_stream_basic_rates);
+       CHK_NEQ(staging->ofdm_ht_dual_stream_basic_rates,
+               active->ofdm_ht_dual_stream_basic_rates);
+       CHK_NEQ(staging->ofdm_ht_triple_stream_basic_rates,
+               active->ofdm_ht_triple_stream_basic_rates);
+       CHK_NEQ(staging->assoc_id, active->assoc_id);
 
        /* flags, filter_flags, ofdm_basic_rates, and cck_basic_rates can
         * be updated with the RXON_ASSOC command -- however only some
         * flag transitions are allowed using RXON_ASSOC */
 
        /* Check if we are not switching bands */
-       if ((priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) !=
-           (priv->active_rxon.flags & RXON_FLG_BAND_24G_MSK))
-               return 1;
+       CHK_NEQ(staging->flags & RXON_FLG_BAND_24G_MSK,
+               active->flags & RXON_FLG_BAND_24G_MSK);
 
        /* Check if we are switching association toggle */
-       if ((priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) !=
-               (priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK))
-               return 1;
+       CHK_NEQ(staging->filter_flags & RXON_FILTER_ASSOC_MSK,
+               active->filter_flags & RXON_FILTER_ASSOC_MSK);
+
+#undef CHK
+#undef CHK_NEQ
 
        return 0;
 }
 EXPORT_SYMBOL(iwl_full_rxon_required);
 
-u8 iwl_rate_get_lowest_plcp(struct iwl_priv *priv)
+u8 iwl_rate_get_lowest_plcp(struct iwl_priv *priv,
+                           struct iwl_rxon_context *ctx)
 {
        /*
         * Assign the lowest rate -- should really get this from
         * the beacon skb from mac80211.
         */
-       if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK)
+       if (ctx->staging.flags & RXON_FLG_BAND_24G_MSK)
                return IWL_RATE_1M_PLCP;
        else
                return IWL_RATE_6M_PLCP;
 }
 EXPORT_SYMBOL(iwl_rate_get_lowest_plcp);
 
-void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_config *ht_conf)
+static void _iwl_set_rxon_ht(struct iwl_priv *priv,
+                            struct iwl_ht_config *ht_conf,
+                            struct iwl_rxon_context *ctx)
 {
-       struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
+       struct iwl_rxon_cmd *rxon = &ctx->staging;
 
-       if (!ht_conf->is_ht) {
+       if (!ctx->ht.enabled) {
                rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK |
                        RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK |
                        RXON_FLG_HT40_PROT_MSK |
@@ -703,22 +734,22 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_config *ht_conf)
                return;
        }
 
-       /* FIXME: if the definition of ht_protection changed, the "translation"
+       /* FIXME: if the definition of ht.protection changed, the "translation"
         * will be needed for rxon->flags
         */
-       rxon->flags |= cpu_to_le32(ht_conf->ht_protection << RXON_FLG_HT_OPERATING_MODE_POS);
+       rxon->flags |= cpu_to_le32(ctx->ht.protection << RXON_FLG_HT_OPERATING_MODE_POS);
 
        /* Set up channel bandwidth:
         * 20 MHz only, 20/40 mixed or pure 40 if ht40 ok */
        /* clear the HT channel mode before set the mode */
        rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK |
                         RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK);
-       if (iwl_is_ht40_tx_allowed(priv, NULL)) {
+       if (iwl_is_ht40_tx_allowed(priv, ctx, NULL)) {
                /* pure ht40 */
-               if (ht_conf->ht_protection == IEEE80211_HT_OP_MODE_PROTECTION_20MHZ) {
+               if (ctx->ht.protection == IEEE80211_HT_OP_MODE_PROTECTION_20MHZ) {
                        rxon->flags |= RXON_FLG_CHANNEL_MODE_PURE_40;
                        /* Note: control channel is opposite of extension channel */
-                       switch (ht_conf->extension_chan_offset) {
+                       switch (ctx->ht.extension_chan_offset) {
                        case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
                                rxon->flags &= ~RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK;
                                break;
@@ -728,7 +759,7 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_config *ht_conf)
                        }
                } else {
                        /* Note: control channel is opposite of extension channel */
-                       switch (ht_conf->extension_chan_offset) {
+                       switch (ctx->ht.extension_chan_offset) {
                        case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
                                rxon->flags &= ~(RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK);
                                rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED;
@@ -749,12 +780,20 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_config *ht_conf)
        }
 
        if (priv->cfg->ops->hcmd->set_rxon_chain)
-               priv->cfg->ops->hcmd->set_rxon_chain(priv);
+               priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
 
        IWL_DEBUG_ASSOC(priv, "rxon flags 0x%X operation mode :0x%X "
                        "extension channel offset 0x%x\n",
-                       le32_to_cpu(rxon->flags), ht_conf->ht_protection,
-                       ht_conf->extension_chan_offset);
+                       le32_to_cpu(rxon->flags), ctx->ht.protection,
+                       ctx->ht.extension_chan_offset);
+}
+
+void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_config *ht_conf)
+{
+       struct iwl_rxon_context *ctx;
+
+       for_each_context(priv, ctx)
+               _iwl_set_rxon_ht(priv, ht_conf, ctx);
 }
 EXPORT_SYMBOL(iwl_set_rxon_ht);
 
@@ -775,6 +814,14 @@ EXPORT_SYMBOL(iwl_set_rxon_ht);
  */
 static int iwl_get_active_rx_chain_count(struct iwl_priv *priv)
 {
+       if (priv->cfg->advanced_bt_coexist && (priv->bt_full_concurrent ||
+           priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH)) {
+               /*
+                * only use chain 'A' in bt high traffic load or
+                * full concurrency mode
+                */
+               return IWL_NUM_RX_CHAINS_SINGLE;
+       }
        /* # of Rx chains to use when expecting MIMO. */
        if (is_single_rx_stream(priv))
                return IWL_NUM_RX_CHAINS_SINGLE;
@@ -819,7 +866,7 @@ static u8 iwl_count_chain_bitmap(u32 chain_bitmap)
  * Selects how many and which Rx receivers/antennas/chains to use.
  * This should not be used for scan command ... it puts data in wrong place.
  */
-void iwl_set_rxon_chain(struct iwl_priv *priv)
+void iwl_set_rxon_chain(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
 {
        bool is_single = is_single_rx_stream(priv);
        bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status);
@@ -831,11 +878,20 @@ void iwl_set_rxon_chain(struct iwl_priv *priv)
         * Before first association, we assume all antennas are connected.
         * Just after first association, iwl_chain_noise_calibration()
         *    checks which antennas actually *are* connected. */
-        if (priv->chain_noise_data.active_chains)
+       if (priv->chain_noise_data.active_chains)
                active_chains = priv->chain_noise_data.active_chains;
        else
                active_chains = priv->hw_params.valid_rx_ant;
 
+       if (priv->cfg->advanced_bt_coexist && (priv->bt_full_concurrent ||
+           priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH)) {
+               /*
+                * only use chain 'A' in bt high traffic load or
+                * full concurrency mode
+                */
+               active_chains = first_antenna(active_chains);
+       }
+
        rx_chain = active_chains << RXON_RX_CHAIN_VALID_POS;
 
        /* How many receivers should we use? */
@@ -856,15 +912,15 @@ void iwl_set_rxon_chain(struct iwl_priv *priv)
        rx_chain |= active_rx_cnt << RXON_RX_CHAIN_MIMO_CNT_POS;
        rx_chain |= idle_rx_cnt  << RXON_RX_CHAIN_CNT_POS;
 
-       priv->staging_rxon.rx_chain = cpu_to_le16(rx_chain);
+       ctx->staging.rx_chain = cpu_to_le16(rx_chain);
 
        if (!is_single && (active_rx_cnt >= IWL_NUM_RX_CHAINS_SINGLE) && is_cam)
-               priv->staging_rxon.rx_chain |= RXON_RX_CHAIN_MIMO_FORCE_MSK;
+               ctx->staging.rx_chain |= RXON_RX_CHAIN_MIMO_FORCE_MSK;
        else
-               priv->staging_rxon.rx_chain &= ~RXON_RX_CHAIN_MIMO_FORCE_MSK;
+               ctx->staging.rx_chain &= ~RXON_RX_CHAIN_MIMO_FORCE_MSK;
 
        IWL_DEBUG_ASSOC(priv, "rx_chain=0x%X active=%d idle=%d\n",
-                       priv->staging_rxon.rx_chain,
+                       ctx->staging.rx_chain,
                        active_rx_cnt, idle_rx_cnt);
 
        WARN_ON(active_rx_cnt == 0 || idle_rx_cnt == 0 ||
@@ -872,39 +928,41 @@ void iwl_set_rxon_chain(struct iwl_priv *priv)
 }
 EXPORT_SYMBOL(iwl_set_rxon_chain);
 
-/* Return valid channel */
+/* Return valid, unused, channel for a passive scan to reset the RF */
 u8 iwl_get_single_channel_number(struct iwl_priv *priv,
-                                 enum ieee80211_band band)
+                                enum ieee80211_band band)
 {
        const struct iwl_channel_info *ch_info;
        int i;
        u8 channel = 0;
+       u8 min, max;
+       struct iwl_rxon_context *ctx;
 
-       /* only scan single channel, good enough to reset the RF */
-       /* pick the first valid not in-use channel */
        if (band == IEEE80211_BAND_5GHZ) {
-               for (i = 14; i < priv->channel_count; i++) {
-                       if (priv->channel_info[i].channel !=
-                           le16_to_cpu(priv->staging_rxon.channel)) {
-                               channel = priv->channel_info[i].channel;
-                               ch_info = iwl_get_channel_info(priv,
-                                       band, channel);
-                               if (is_channel_valid(ch_info))
-                                       break;
-                       }
-               }
+               min = 14;
+               max = priv->channel_count;
        } else {
-               for (i = 0; i < 14; i++) {
-                       if (priv->channel_info[i].channel !=
-                           le16_to_cpu(priv->staging_rxon.channel)) {
-                                       channel =
-                                               priv->channel_info[i].channel;
-                                       ch_info = iwl_get_channel_info(priv,
-                                               band, channel);
-                                       if (is_channel_valid(ch_info))
-                                               break;
-                       }
+               min = 0;
+               max = 14;
+       }
+
+       for (i = min; i < max; i++) {
+               bool busy = false;
+
+               for_each_context(priv, ctx) {
+                       busy = priv->channel_info[i].channel ==
+                               le16_to_cpu(ctx->staging.channel);
+                       if (busy)
+                               break;
                }
+
+               if (busy)
+                       continue;
+
+               channel = priv->channel_info[i].channel;
+               ch_info = iwl_get_channel_info(priv, band, channel);
+               if (is_channel_valid(ch_info))
+                       break;
        }
 
        return channel;
@@ -912,35 +970,27 @@ u8 iwl_get_single_channel_number(struct iwl_priv *priv,
 EXPORT_SYMBOL(iwl_get_single_channel_number);
 
 /**
- * iwl_set_rxon_channel - Set the phymode and channel values in staging RXON
- * @phymode: MODE_IEEE80211A sets to 5.2GHz; all else set to 2.4GHz
- * @channel: Any channel valid for the requested phymode
+ * iwl_set_rxon_channel - Set the band and channel values in staging RXON
+ * @ch: requested channel as a pointer to struct ieee80211_channel
 
- * In addition to setting the staging RXON, priv->phymode is also set.
- *
  * NOTE:  Does not commit to the hardware; it sets appropriate bit fields
- * in the staging RXON flag structure based on the phymode
+ * in the staging RXON flag structure based on the ch->band
  */
-int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch)
+int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch,
+                        struct iwl_rxon_context *ctx)
 {
        enum ieee80211_band band = ch->band;
-       u16 channel = ieee80211_frequency_to_channel(ch->center_freq);
+       u16 channel = ch->hw_value;
 
-       if (!iwl_get_channel_info(priv, band, channel)) {
-               IWL_DEBUG_INFO(priv, "Could not set channel to %d [%d]\n",
-                              channel, band);
-               return -EINVAL;
-       }
-
-       if ((le16_to_cpu(priv->staging_rxon.channel) == channel) &&
+       if ((le16_to_cpu(ctx->staging.channel) == channel) &&
            (priv->band == band))
                return 0;
 
-       priv->staging_rxon.channel = cpu_to_le16(channel);
+       ctx->staging.channel = cpu_to_le16(channel);
        if (band == IEEE80211_BAND_5GHZ)
-               priv->staging_rxon.flags &= ~RXON_FLG_BAND_24G_MSK;
+               ctx->staging.flags &= ~RXON_FLG_BAND_24G_MSK;
        else
-               priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK;
+               ctx->staging.flags |= RXON_FLG_BAND_24G_MSK;
 
        priv->band = band;
 
@@ -951,24 +1001,25 @@ int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch)
 EXPORT_SYMBOL(iwl_set_rxon_channel);
 
 void iwl_set_flags_for_band(struct iwl_priv *priv,
+                           struct iwl_rxon_context *ctx,
                            enum ieee80211_band band,
                            struct ieee80211_vif *vif)
 {
        if (band == IEEE80211_BAND_5GHZ) {
-               priv->staging_rxon.flags &=
+               ctx->staging.flags &=
                    ~(RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK
                      | RXON_FLG_CCK_MSK);
-               priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
+               ctx->staging.flags |= RXON_FLG_SHORT_SLOT_MSK;
        } else {
                /* Copied from iwl_post_associate() */
                if (vif && vif->bss_conf.use_short_slot)
-                       priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
+                       ctx->staging.flags |= RXON_FLG_SHORT_SLOT_MSK;
                else
-                       priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
+                       ctx->staging.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
 
-               priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK;
-               priv->staging_rxon.flags |= RXON_FLG_AUTO_DETECT_MSK;
-               priv->staging_rxon.flags &= ~RXON_FLG_CCK_MSK;
+               ctx->staging.flags |= RXON_FLG_BAND_24G_MSK;
+               ctx->staging.flags |= RXON_FLG_AUTO_DETECT_MSK;
+               ctx->staging.flags &= ~RXON_FLG_CCK_MSK;
        }
 }
 EXPORT_SYMBOL(iwl_set_flags_for_band);
@@ -977,35 +1028,34 @@ EXPORT_SYMBOL(iwl_set_flags_for_band);
  * initialize rxon structure with default values from eeprom
  */
 void iwl_connection_init_rx_config(struct iwl_priv *priv,
-                                  struct ieee80211_vif *vif)
+                                  struct iwl_rxon_context *ctx)
 {
        const struct iwl_channel_info *ch_info;
-       enum nl80211_iftype type = NL80211_IFTYPE_STATION;
 
-       if (vif)
-               type = vif->type;
+       memset(&ctx->staging, 0, sizeof(ctx->staging));
 
-       memset(&priv->staging_rxon, 0, sizeof(priv->staging_rxon));
-
-       switch (type) {
+       if (!ctx->vif) {
+               ctx->staging.dev_type = ctx->unused_devtype;
+       } else switch (ctx->vif->type) {
        case NL80211_IFTYPE_AP:
-               priv->staging_rxon.dev_type = RXON_DEV_TYPE_AP;
+               ctx->staging.dev_type = ctx->ap_devtype;
                break;
 
        case NL80211_IFTYPE_STATION:
-               priv->staging_rxon.dev_type = RXON_DEV_TYPE_ESS;
-               priv->staging_rxon.filter_flags = RXON_FILTER_ACCEPT_GRP_MSK;
+               ctx->staging.dev_type = ctx->station_devtype;
+               ctx->staging.filter_flags = RXON_FILTER_ACCEPT_GRP_MSK;
                break;
 
        case NL80211_IFTYPE_ADHOC:
-               priv->staging_rxon.dev_type = RXON_DEV_TYPE_IBSS;
-               priv->staging_rxon.flags = RXON_FLG_SHORT_PREAMBLE_MSK;
-               priv->staging_rxon.filter_flags = RXON_FILTER_BCON_AWARE_MSK |
+               ctx->staging.dev_type = ctx->ibss_devtype;
+               ctx->staging.flags = RXON_FLG_SHORT_PREAMBLE_MSK;
+               ctx->staging.filter_flags = RXON_FILTER_BCON_AWARE_MSK |
                                                  RXON_FILTER_ACCEPT_GRP_MSK;
                break;
 
        default:
-               IWL_ERR(priv, "Unsupported interface type %d\n", type);
+               IWL_ERR(priv, "Unsupported interface type %d\n",
+                       ctx->vif->type);
                break;
        }
 
@@ -1013,37 +1063,36 @@ void iwl_connection_init_rx_config(struct iwl_priv *priv,
        /* TODO:  Figure out when short_preamble would be set and cache from
         * that */
        if (!hw_to_local(priv->hw)->short_preamble)
-               priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
+               ctx->staging.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
        else
-               priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
+               ctx->staging.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
 #endif
 
        ch_info = iwl_get_channel_info(priv, priv->band,
-                                      le16_to_cpu(priv->active_rxon.channel));
+                                      le16_to_cpu(ctx->active.channel));
 
        if (!ch_info)
                ch_info = &priv->channel_info[0];
 
-       priv->staging_rxon.channel = cpu_to_le16(ch_info->channel);
+       ctx->staging.channel = cpu_to_le16(ch_info->channel);
        priv->band = ch_info->band;
 
-       iwl_set_flags_for_band(priv, priv->band, vif);
+       iwl_set_flags_for_band(priv, ctx, priv->band, ctx->vif);
 
-       priv->staging_rxon.ofdm_basic_rates =
+       ctx->staging.ofdm_basic_rates =
            (IWL_OFDM_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
-       priv->staging_rxon.cck_basic_rates =
+       ctx->staging.cck_basic_rates =
            (IWL_CCK_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF;
 
        /* clear both MIX and PURE40 mode flag */
-       priv->staging_rxon.flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED |
+       ctx->staging.flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED |
                                        RXON_FLG_CHANNEL_MODE_PURE_40);
+       if (ctx->vif)
+               memcpy(ctx->staging.node_addr, ctx->vif->addr, ETH_ALEN);
 
-       if (vif)
-               memcpy(priv->staging_rxon.node_addr, vif->addr, ETH_ALEN);
-
-       priv->staging_rxon.ofdm_ht_single_stream_basic_rates = 0xff;
-       priv->staging_rxon.ofdm_ht_dual_stream_basic_rates = 0xff;
-       priv->staging_rxon.ofdm_ht_triple_stream_basic_rates = 0xff;
+       ctx->staging.ofdm_ht_single_stream_basic_rates = 0xff;
+       ctx->staging.ofdm_ht_dual_stream_basic_rates = 0xff;
+       ctx->staging.ofdm_ht_triple_stream_basic_rates = 0xff;
 }
 EXPORT_SYMBOL(iwl_connection_init_rx_config);
 
@@ -1051,6 +1100,7 @@ void iwl_set_rate(struct iwl_priv *priv)
 {
        const struct ieee80211_supported_band *hw = NULL;
        struct ieee80211_rate *rate;
+       struct iwl_rxon_context *ctx;
        int i;
 
        hw = iwl_get_hw_mode(priv, priv->band);
@@ -1069,21 +1119,29 @@ void iwl_set_rate(struct iwl_priv *priv)
 
        IWL_DEBUG_RATE(priv, "Set active_rate = %0x\n", priv->active_rate);
 
-       priv->staging_rxon.cck_basic_rates =
-           (IWL_CCK_BASIC_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF;
+       for_each_context(priv, ctx) {
+               ctx->staging.cck_basic_rates =
+                   (IWL_CCK_BASIC_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF;
 
-       priv->staging_rxon.ofdm_basic_rates =
-          (IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
+               ctx->staging.ofdm_basic_rates =
+                  (IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
+       }
 }
 EXPORT_SYMBOL(iwl_set_rate);
 
 void iwl_chswitch_done(struct iwl_priv *priv, bool is_success)
 {
+       /*
+        * MULTI-FIXME
+        * See iwl_mac_channel_switch.
+        */
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
+
        if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return;
 
        if (priv->switch_rxon.switch_in_progress) {
-               ieee80211_chswitch_done(priv->vif, is_success);
+               ieee80211_chswitch_done(ctx->vif, is_success);
                mutex_lock(&priv->mutex);
                priv->switch_rxon.switch_in_progress = false;
                mutex_unlock(&priv->mutex);
@@ -1094,14 +1152,19 @@ EXPORT_SYMBOL(iwl_chswitch_done);
 void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
 {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
-       struct iwl_rxon_cmd *rxon = (void *)&priv->active_rxon;
        struct iwl_csa_notification *csa = &(pkt->u.csa_notif);
+       /*
+        * MULTI-FIXME
+        * See iwl_mac_channel_switch.
+        */
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
+       struct iwl_rxon_cmd *rxon = (void *)&ctx->active;
 
        if (priv->switch_rxon.switch_in_progress) {
                if (!le32_to_cpu(csa->status) &&
                    (csa->channel == priv->switch_rxon.channel)) {
                        rxon->channel = csa->channel;
-                       priv->staging_rxon.channel = csa->channel;
+                       ctx->staging.channel = csa->channel;
                        IWL_DEBUG_11H(priv, "CSA notif: channel %d\n",
                              le16_to_cpu(csa->channel));
                        iwl_chswitch_done(priv, true);
@@ -1115,9 +1178,10 @@ void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
 EXPORT_SYMBOL(iwl_rx_csa);
 
 #ifdef CONFIG_IWLWIFI_DEBUG
-void iwl_print_rx_config_cmd(struct iwl_priv *priv)
+void iwl_print_rx_config_cmd(struct iwl_priv *priv,
+                            struct iwl_rxon_context *ctx)
 {
-       struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
+       struct iwl_rxon_cmd *rxon = &ctx->staging;
 
        IWL_DEBUG_RADIO(priv, "RX CONFIG:\n");
        iwl_print_hex_dump(priv, IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon));
@@ -1157,7 +1221,8 @@ void iwl_irq_handle_error(struct iwl_priv *priv)
        priv->cfg->ops->lib->dump_nic_event_log(priv, false, NULL, false);
 #ifdef CONFIG_IWLWIFI_DEBUG
        if (iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS)
-               iwl_print_rx_config_cmd(priv);
+               iwl_print_rx_config_cmd(priv,
+                                       &priv->contexts[IWL_RXON_CTX_BSS]);
 #endif
 
        wake_up_interruptible(&priv->wait_command_queue);
@@ -1328,25 +1393,6 @@ out:
 EXPORT_SYMBOL(iwl_apm_init);
 
 
-int iwl_set_hw_params(struct iwl_priv *priv)
-{
-       priv->hw_params.max_rxq_size = RX_QUEUE_SIZE;
-       priv->hw_params.max_rxq_log = RX_QUEUE_SIZE_LOG;
-       if (priv->cfg->mod_params->amsdu_size_8K)
-               priv->hw_params.rx_page_order = get_order(IWL_RX_BUF_SIZE_8K);
-       else
-               priv->hw_params.rx_page_order = get_order(IWL_RX_BUF_SIZE_4K);
-
-       priv->hw_params.max_beacon_itrvl = IWL_MAX_UCODE_BEACON_INTERVAL;
-
-       if (priv->cfg->mod_params->disable_11n)
-               priv->cfg->sku &= ~IWL_SKU_N;
-
-       /* Device-specific setup */
-       return priv->cfg->ops->lib->set_hw_params(priv);
-}
-EXPORT_SYMBOL(iwl_set_hw_params);
-
 int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force)
 {
        int ret = 0;
@@ -1496,76 +1542,6 @@ int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags, bool clear)
 }
 EXPORT_SYMBOL(iwl_send_statistics_request);
 
-void iwl_rf_kill_ct_config(struct iwl_priv *priv)
-{
-       struct iwl_ct_kill_config cmd;
-       struct iwl_ct_kill_throttling_config adv_cmd;
-       unsigned long flags;
-       int ret = 0;
-
-       spin_lock_irqsave(&priv->lock, flags);
-       iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
-                   CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
-       spin_unlock_irqrestore(&priv->lock, flags);
-       priv->thermal_throttle.ct_kill_toggle = false;
-
-       if (priv->cfg->support_ct_kill_exit) {
-               adv_cmd.critical_temperature_enter =
-                       cpu_to_le32(priv->hw_params.ct_kill_threshold);
-               adv_cmd.critical_temperature_exit =
-                       cpu_to_le32(priv->hw_params.ct_kill_exit_threshold);
-
-               ret = iwl_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD,
-                                      sizeof(adv_cmd), &adv_cmd);
-               if (ret)
-                       IWL_ERR(priv, "REPLY_CT_KILL_CONFIG_CMD failed\n");
-               else
-                       IWL_DEBUG_INFO(priv, "REPLY_CT_KILL_CONFIG_CMD "
-                                       "succeeded, "
-                                       "critical temperature enter is %d,"
-                                       "exit is %d\n",
-                                      priv->hw_params.ct_kill_threshold,
-                                      priv->hw_params.ct_kill_exit_threshold);
-       } else {
-               cmd.critical_temperature_R =
-                       cpu_to_le32(priv->hw_params.ct_kill_threshold);
-
-               ret = iwl_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD,
-                                      sizeof(cmd), &cmd);
-               if (ret)
-                       IWL_ERR(priv, "REPLY_CT_KILL_CONFIG_CMD failed\n");
-               else
-                       IWL_DEBUG_INFO(priv, "REPLY_CT_KILL_CONFIG_CMD "
-                                       "succeeded, "
-                                       "critical temperature is %d\n",
-                                       priv->hw_params.ct_kill_threshold);
-       }
-}
-EXPORT_SYMBOL(iwl_rf_kill_ct_config);
-
-
-/*
- * CARD_STATE_CMD
- *
- * Use: Sets the device's internal card state to enable, disable, or halt
- *
- * When in the 'enable' state the card operates as normal.
- * When in the 'disable' state, the card enters into a low power mode.
- * When in the 'halt' state, the card is shut down and must be fully
- * restarted to come back on.
- */
-int iwl_send_card_state(struct iwl_priv *priv, u32 flags, u8 meta_flag)
-{
-       struct iwl_host_cmd cmd = {
-               .id = REPLY_CARD_STATE_CMD,
-               .len = sizeof(u32),
-               .data = &flags,
-               .flags = meta_flag,
-       };
-
-       return iwl_send_cmd(priv, &cmd);
-}
-
 void iwl_rx_pm_sleep_notif(struct iwl_priv *priv,
                           struct iwl_rx_mem_buffer *rxb)
 {
@@ -1614,6 +1590,7 @@ int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
                           const struct ieee80211_tx_queue_params *params)
 {
        struct iwl_priv *priv = hw->priv;
+       struct iwl_rxon_context *ctx;
        unsigned long flags;
        int q;
 
@@ -1633,13 +1610,21 @@ int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
 
        spin_lock_irqsave(&priv->lock, flags);
 
-       priv->qos_data.def_qos_parm.ac[q].cw_min = cpu_to_le16(params->cw_min);
-       priv->qos_data.def_qos_parm.ac[q].cw_max = cpu_to_le16(params->cw_max);
-       priv->qos_data.def_qos_parm.ac[q].aifsn = params->aifs;
-       priv->qos_data.def_qos_parm.ac[q].edca_txop =
-                       cpu_to_le16((params->txop * 32));
+       /*
+        * MULTI-FIXME
+        * This may need to be done per interface in nl80211/cfg80211/mac80211.
+        */
+       for_each_context(priv, ctx) {
+               ctx->qos_data.def_qos_parm.ac[q].cw_min =
+                       cpu_to_le16(params->cw_min);
+               ctx->qos_data.def_qos_parm.ac[q].cw_max =
+                       cpu_to_le16(params->cw_max);
+               ctx->qos_data.def_qos_parm.ac[q].aifsn = params->aifs;
+               ctx->qos_data.def_qos_parm.ac[q].edca_txop =
+                               cpu_to_le16((params->txop * 32));
 
-       priv->qos_data.def_qos_parm.ac[q].reserved1 = 0;
+               ctx->qos_data.def_qos_parm.ac[q].reserved1 = 0;
+       }
 
        spin_unlock_irqrestore(&priv->lock, flags);
 
@@ -1648,21 +1633,30 @@ int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
 }
 EXPORT_SYMBOL(iwl_mac_conf_tx);
 
+int iwl_mac_tx_last_beacon(struct ieee80211_hw *hw)
+{
+       struct iwl_priv *priv = hw->priv;
+
+       return priv->ibss_manager == IWL_IBSS_MANAGER;
+}
+EXPORT_SYMBOL_GPL(iwl_mac_tx_last_beacon);
+
 static void iwl_ht_conf(struct iwl_priv *priv,
                        struct ieee80211_vif *vif)
 {
        struct iwl_ht_config *ht_conf = &priv->current_ht_config;
        struct ieee80211_sta *sta;
        struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
+       struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
 
        IWL_DEBUG_MAC80211(priv, "enter:\n");
 
-       if (!ht_conf->is_ht)
+       if (!ctx->ht.enabled)
                return;
 
-       ht_conf->ht_protection =
+       ctx->ht.protection =
                bss_conf->ht_operation_mode & IEEE80211_HT_OP_MODE_PROTECTION;
-       ht_conf->non_GF_STA_present =
+       ctx->ht.non_gf_sta_present =
                !!(bss_conf->ht_operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT);
 
        ht_conf->single_chain_sufficient = false;
@@ -1706,18 +1700,20 @@ static void iwl_ht_conf(struct iwl_priv *priv,
        IWL_DEBUG_MAC80211(priv, "leave\n");
 }
 
-static inline void iwl_set_no_assoc(struct iwl_priv *priv)
+static inline void iwl_set_no_assoc(struct iwl_priv *priv,
+                                   struct ieee80211_vif *vif)
 {
+       struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
+
        iwl_led_disassociate(priv);
        /*
         * inform the ucode that there is no longer an
         * association and that no more packets should be
         * sent
         */
-       priv->staging_rxon.filter_flags &=
-               ~RXON_FILTER_ASSOC_MSK;
-       priv->staging_rxon.assoc_id = 0;
-       iwlcore_commit_rxon(priv);
+       ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+       ctx->staging.assoc_id = 0;
+       iwlcore_commit_rxon(priv, ctx);
 }
 
 static int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
@@ -1728,6 +1724,14 @@ static int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
 
        IWL_DEBUG_MAC80211(priv, "enter\n");
 
+       lockdep_assert_held(&priv->mutex);
+
+       if (!priv->beacon_ctx) {
+               IWL_ERR(priv, "update beacon but no beacon context!\n");
+               dev_kfree_skb(skb);
+               return -EINVAL;
+       }
+
        if (!iwl_is_ready_rf(priv)) {
                IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n");
                return -EIO;
@@ -1746,7 +1750,7 @@ static int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
        IWL_DEBUG_MAC80211(priv, "leave\n");
        spin_unlock_irqrestore(&priv->lock, flags);
 
-       priv->cfg->ops->lib->post_associate(priv, priv->vif);
+       priv->cfg->ops->lib->post_associate(priv, priv->beacon_ctx->vif);
 
        return 0;
 }
@@ -1757,6 +1761,7 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw,
                          u32 changes)
 {
        struct iwl_priv *priv = hw->priv;
+       struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
        int ret;
 
        IWL_DEBUG_MAC80211(priv, "changes = 0x%X\n", changes);
@@ -1770,11 +1775,23 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw,
                unsigned long flags;
 
                spin_lock_irqsave(&priv->lock, flags);
-               priv->qos_data.qos_active = bss_conf->qos;
-               iwl_update_qos(priv);
+               ctx->qos_data.qos_active = bss_conf->qos;
+               iwl_update_qos(priv, ctx);
                spin_unlock_irqrestore(&priv->lock, flags);
        }
 
+       if (changes & BSS_CHANGED_BEACON_ENABLED) {
+               /*
+                * the add_interface code must make sure we only ever
+                * have a single interface that could be beaconing at
+                * any time.
+                */
+               if (vif->bss_conf.enable_beacon)
+                       priv->beacon_ctx = ctx;
+               else
+                       priv->beacon_ctx = NULL;
+       }
+
        if (changes & BSS_CHANGED_BEACON && vif->type == NL80211_IFTYPE_AP) {
                dev_kfree_skb(priv->ibss_beacon);
                priv->ibss_beacon = ieee80211_beacon_get(hw, vif);
@@ -1801,13 +1818,13 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw,
 
                /* mac80211 only sets assoc when in STATION mode */
                if (vif->type == NL80211_IFTYPE_ADHOC || bss_conf->assoc) {
-                       memcpy(priv->staging_rxon.bssid_addr,
+                       memcpy(ctx->staging.bssid_addr,
                               bss_conf->bssid, ETH_ALEN);
 
                        /* currently needed in a few places */
                        memcpy(priv->bssid, bss_conf->bssid, ETH_ALEN);
                } else {
-                       priv->staging_rxon.filter_flags &=
+                       ctx->staging.filter_flags &=
                                ~RXON_FILTER_ASSOC_MSK;
                }
 
@@ -1830,21 +1847,21 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw,
                IWL_DEBUG_MAC80211(priv, "ERP_PREAMBLE %d\n",
                                   bss_conf->use_short_preamble);
                if (bss_conf->use_short_preamble)
-                       priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
+                       ctx->staging.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
                else
-                       priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
+                       ctx->staging.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
        }
 
        if (changes & BSS_CHANGED_ERP_CTS_PROT) {
                IWL_DEBUG_MAC80211(priv, "ERP_CTS %d\n", bss_conf->use_cts_prot);
                if (bss_conf->use_cts_prot && (priv->band != IEEE80211_BAND_5GHZ))
-                       priv->staging_rxon.flags |= RXON_FLG_TGG_PROTECT_MSK;
+                       ctx->staging.flags |= RXON_FLG_TGG_PROTECT_MSK;
                else
-                       priv->staging_rxon.flags &= ~RXON_FLG_TGG_PROTECT_MSK;
+                       ctx->staging.flags &= ~RXON_FLG_TGG_PROTECT_MSK;
                if (bss_conf->use_cts_prot)
-                       priv->staging_rxon.flags |= RXON_FLG_SELF_CTS_EN;
+                       ctx->staging.flags |= RXON_FLG_SELF_CTS_EN;
                else
-                       priv->staging_rxon.flags &= ~RXON_FLG_SELF_CTS_EN;
+                       ctx->staging.flags &= ~RXON_FLG_SELF_CTS_EN;
        }
 
        if (changes & BSS_CHANGED_BASIC_RATES) {
@@ -1854,12 +1871,12 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw,
                 * like this here:
                 *
                if (A-band)
-                       priv->staging_rxon.ofdm_basic_rates =
+                       ctx->staging.ofdm_basic_rates =
                                bss_conf->basic_rates;
                else
-                       priv->staging_rxon.ofdm_basic_rates =
+                       ctx->staging.ofdm_basic_rates =
                                bss_conf->basic_rates >> 4;
-                       priv->staging_rxon.cck_basic_rates =
+                       ctx->staging.cck_basic_rates =
                                bss_conf->basic_rates & 0xF;
                 */
        }
@@ -1868,7 +1885,7 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw,
                iwl_ht_conf(priv, vif);
 
                if (priv->cfg->ops->hcmd->set_rxon_chain)
-                       priv->cfg->ops->hcmd->set_rxon_chain(priv);
+                       priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
        }
 
        if (changes & BSS_CHANGED_ASSOC) {
@@ -1881,29 +1898,29 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw,
                        if (!iwl_is_rfkill(priv))
                                priv->cfg->ops->lib->post_associate(priv, vif);
                } else
-                       iwl_set_no_assoc(priv);
+                       iwl_set_no_assoc(priv, vif);
        }
 
-       if (changes && iwl_is_associated(priv) && bss_conf->aid) {
+       if (changes && iwl_is_associated_ctx(ctx) && bss_conf->aid) {
                IWL_DEBUG_MAC80211(priv, "Changes (%#x) while associated\n",
                                   changes);
-               ret = iwl_send_rxon_assoc(priv);
+               ret = iwl_send_rxon_assoc(priv, ctx);
                if (!ret) {
                        /* Sync active_rxon with latest change. */
-                       memcpy((void *)&priv->active_rxon,
-                               &priv->staging_rxon,
+                       memcpy((void *)&ctx->active,
+                               &ctx->staging,
                                sizeof(struct iwl_rxon_cmd));
                }
        }
 
        if (changes & BSS_CHANGED_BEACON_ENABLED) {
                if (vif->bss_conf.enable_beacon) {
-                       memcpy(priv->staging_rxon.bssid_addr,
+                       memcpy(ctx->staging.bssid_addr,
                               bss_conf->bssid, ETH_ALEN);
                        memcpy(priv->bssid, bss_conf->bssid, ETH_ALEN);
                        iwlcore_config_ap(priv, vif);
                } else
-                       iwl_set_no_assoc(priv);
+                       iwl_set_no_assoc(priv, vif);
        }
 
        if (changes & BSS_CHANGED_IBSS) {
@@ -1915,6 +1932,12 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw,
                                bss_conf->bssid);
        }
 
+       if (changes & BSS_CHANGED_IDLE &&
+           priv->cfg->ops->hcmd->set_pan_params) {
+               if (priv->cfg->ops->hcmd->set_pan_params(priv))
+                       IWL_ERR(priv, "failed to update PAN params\n");
+       }
+
        mutex_unlock(&priv->mutex);
 
        IWL_DEBUG_MAC80211(priv, "leave\n");
@@ -1923,17 +1946,21 @@ EXPORT_SYMBOL(iwl_bss_info_changed);
 
 static int iwl_set_mode(struct iwl_priv *priv, struct ieee80211_vif *vif)
 {
-       iwl_connection_init_rx_config(priv, vif);
+       struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
+
+       iwl_connection_init_rx_config(priv, ctx);
 
        if (priv->cfg->ops->hcmd->set_rxon_chain)
-               priv->cfg->ops->hcmd->set_rxon_chain(priv);
+               priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
 
-       return iwlcore_commit_rxon(priv);
+       return iwlcore_commit_rxon(priv, ctx);
 }
 
 int iwl_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 {
        struct iwl_priv *priv = hw->priv;
+       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
+       struct iwl_rxon_context *tmp, *ctx = NULL;
        int err = 0;
 
        IWL_DEBUG_MAC80211(priv, "enter: type %d, addr %pM\n",
@@ -1946,23 +1973,60 @@ int iwl_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
                goto out;
        }
 
-       if (priv->vif) {
-               IWL_DEBUG_MAC80211(priv, "leave - vif != NULL\n");
+       for_each_context(priv, tmp) {
+               u32 possible_modes =
+                       tmp->interface_modes | tmp->exclusive_interface_modes;
+
+               if (tmp->vif) {
+                       /* check if this busy context is exclusive */
+                       if (tmp->exclusive_interface_modes &
+                                               BIT(tmp->vif->type)) {
+                               err = -EINVAL;
+                               goto out;
+                       }
+                       continue;
+               }
+
+               if (!(possible_modes & BIT(vif->type)))
+                       continue;
+
+               /* have maybe usable context w/o interface */
+               ctx = tmp;
+               break;
+       }
+
+       if (!ctx) {
                err = -EOPNOTSUPP;
                goto out;
        }
 
-       priv->vif = vif;
+       vif_priv->ctx = ctx;
+       ctx->vif = vif;
+       /*
+        * This variable will be correct only when there's just
+        * a single context, but all code using it is for hardware
+        * that supports only one context.
+        */
        priv->iw_mode = vif->type;
 
        err = iwl_set_mode(priv, vif);
        if (err)
                goto out_err;
 
+       if (priv->cfg->advanced_bt_coexist &&
+           vif->type == NL80211_IFTYPE_ADHOC) {
+               /*
+                * pretend to have high BT traffic as long as we
+                * are operating in IBSS mode, as this will cause
+                * the rate scaling etc. to behave as intended.
+                */
+               priv->bt_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_HIGH;
+       }
+
        goto out;
 
  out_err:
-       priv->vif = NULL;
+       ctx->vif = NULL;
        priv->iw_mode = NL80211_IFTYPE_STATION;
  out:
        mutex_unlock(&priv->mutex);
@@ -1976,26 +2040,36 @@ void iwl_mac_remove_interface(struct ieee80211_hw *hw,
                              struct ieee80211_vif *vif)
 {
        struct iwl_priv *priv = hw->priv;
+       struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
        bool scan_completed = false;
 
        IWL_DEBUG_MAC80211(priv, "enter\n");
 
        mutex_lock(&priv->mutex);
 
-       if (iwl_is_ready_rf(priv)) {
-               iwl_scan_cancel_timeout(priv, 100);
-               priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-               iwlcore_commit_rxon(priv);
-       }
-       if (priv->vif == vif) {
-               priv->vif = NULL;
-               if (priv->scan_vif == vif) {
-                       scan_completed = true;
-                       priv->scan_vif = NULL;
-                       priv->scan_request = NULL;
-               }
-               memset(priv->bssid, 0, ETH_ALEN);
+       WARN_ON(ctx->vif != vif);
+       ctx->vif = NULL;
+
+       iwl_scan_cancel_timeout(priv, 100);
+       iwl_set_mode(priv, vif);
+
+       if (priv->scan_vif == vif) {
+               scan_completed = true;
+               priv->scan_vif = NULL;
+               priv->scan_request = NULL;
        }
+
+       /*
+        * When removing the IBSS interface, overwrite the
+        * BT traffic load with the stored one from the last
+        * notification, if any. If this is a device that
+        * doesn't implement this, this has no effect since
+        * both values are the same and zero.
+        */
+       if (vif->type == NL80211_IFTYPE_ADHOC)
+               priv->bt_traffic_load = priv->notif_bt_traffic_load;
+
+       memset(priv->bssid, 0, ETH_ALEN);
        mutex_unlock(&priv->mutex);
 
        if (scan_completed)
@@ -2014,7 +2088,9 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
        struct iwl_priv *priv = hw->priv;
        const struct iwl_channel_info *ch_info;
        struct ieee80211_conf *conf = &hw->conf;
+       struct ieee80211_channel *channel = conf->channel;
        struct iwl_ht_config *ht_conf = &priv->current_ht_config;
+       struct iwl_rxon_context *ctx;
        unsigned long flags = 0;
        int ret = 0;
        u16 ch;
@@ -2023,7 +2099,7 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
        mutex_lock(&priv->mutex);
 
        IWL_DEBUG_MAC80211(priv, "enter to channel %d changed 0x%X\n",
-                                       conf->channel->hw_value, changed);
+                                       channel->hw_value, changed);
 
        if (unlikely(!priv->cfg->mod_params->disable_hw_scan &&
                        test_bit(STATUS_SCANNING, &priv->status))) {
@@ -2044,7 +2120,8 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
                 * configured.
                 */
                if (priv->cfg->ops->hcmd->set_rxon_chain)
-                       priv->cfg->ops->hcmd->set_rxon_chain(priv);
+                       for_each_context(priv, ctx)
+                               priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
        }
 
        /* during scanning mac80211 will delay channel setting until
@@ -2054,8 +2131,8 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
                if (scan_active)
                        goto set_ch_out;
 
-               ch = ieee80211_frequency_to_channel(conf->channel->center_freq);
-               ch_info = iwl_get_channel_info(priv, conf->channel->band, ch);
+               ch = channel->hw_value;
+               ch_info = iwl_get_channel_info(priv, channel->band, ch);
                if (!is_channel_valid(ch_info)) {
                        IWL_DEBUG_MAC80211(priv, "leave - invalid channel\n");
                        ret = -EINVAL;
@@ -2064,42 +2141,49 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
 
                spin_lock_irqsave(&priv->lock, flags);
 
-               /* Configure HT40 channels */
-               ht_conf->is_ht = conf_is_ht(conf);
-               if (ht_conf->is_ht) {
-                       if (conf_is_ht40_minus(conf)) {
-                               ht_conf->extension_chan_offset =
-                                       IEEE80211_HT_PARAM_CHA_SEC_BELOW;
-                               ht_conf->is_40mhz = true;
-                       } else if (conf_is_ht40_plus(conf)) {
-                               ht_conf->extension_chan_offset =
-                                       IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
-                               ht_conf->is_40mhz = true;
-                       } else {
-                               ht_conf->extension_chan_offset =
-                                       IEEE80211_HT_PARAM_CHA_SEC_NONE;
-                               ht_conf->is_40mhz = false;
-                       }
-               } else
-                       ht_conf->is_40mhz = false;
-               /* Default to no protection. Protection mode will later be set
-                * from BSS config in iwl_ht_conf */
-               ht_conf->ht_protection = IEEE80211_HT_OP_MODE_PROTECTION_NONE;
+               for_each_context(priv, ctx) {
+                       /* Configure HT40 channels */
+                       ctx->ht.enabled = conf_is_ht(conf);
+                       if (ctx->ht.enabled) {
+                               if (conf_is_ht40_minus(conf)) {
+                                       ctx->ht.extension_chan_offset =
+                                               IEEE80211_HT_PARAM_CHA_SEC_BELOW;
+                                       ctx->ht.is_40mhz = true;
+                               } else if (conf_is_ht40_plus(conf)) {
+                                       ctx->ht.extension_chan_offset =
+                                               IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
+                                       ctx->ht.is_40mhz = true;
+                               } else {
+                                       ctx->ht.extension_chan_offset =
+                                               IEEE80211_HT_PARAM_CHA_SEC_NONE;
+                                       ctx->ht.is_40mhz = false;
+                               }
+                       } else
+                               ctx->ht.is_40mhz = false;
 
-               /* if we are switching from ht to 2.4 clear flags
-                * from any ht related info since 2.4 does not
-                * support ht */
-               if ((le16_to_cpu(priv->staging_rxon.channel) != ch))
-                       priv->staging_rxon.flags = 0;
+                       /*
+                        * Default to no protection. Protection mode will
+                        * later be set from BSS config in iwl_ht_conf
+                        */
+                       ctx->ht.protection = IEEE80211_HT_OP_MODE_PROTECTION_NONE;
+
+                       /* if we are switching from ht to 2.4 clear flags
+                        * from any ht related info since 2.4 does not
+                        * support ht */
+                       if ((le16_to_cpu(ctx->staging.channel) != ch))
+                               ctx->staging.flags = 0;
 
-               iwl_set_rxon_channel(priv, conf->channel);
-               iwl_set_rxon_ht(priv, ht_conf);
+                       iwl_set_rxon_channel(priv, channel, ctx);
+                       iwl_set_rxon_ht(priv, ht_conf);
+
+                       iwl_set_flags_for_band(priv, ctx, channel->band,
+                                              ctx->vif);
+               }
 
-               iwl_set_flags_for_band(priv, conf->channel->band, priv->vif);
                spin_unlock_irqrestore(&priv->lock, flags);
 
-               if (priv->cfg->ops->lib->update_bcast_station)
-                       ret = priv->cfg->ops->lib->update_bcast_station(priv);
+               if (priv->cfg->ops->lib->update_bcast_stations)
+                       ret = priv->cfg->ops->lib->update_bcast_stations(priv);
 
  set_ch_out:
                /* The list of supported rates and rate mask can be different
@@ -2130,12 +2214,13 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
        if (scan_active)
                goto out;
 
-       if (memcmp(&priv->active_rxon,
-                  &priv->staging_rxon, sizeof(priv->staging_rxon)))
-               iwlcore_commit_rxon(priv);
-       else
-               IWL_DEBUG_INFO(priv, "Not re-sending same RXON configuration.\n");
-
+       for_each_context(priv, ctx) {
+               if (memcmp(&ctx->active, &ctx->staging, sizeof(ctx->staging)))
+                       iwlcore_commit_rxon(priv, ctx);
+               else
+                       IWL_DEBUG_INFO(priv,
+                               "Not re-sending same RXON configuration.\n");
+       }
 
 out:
        IWL_DEBUG_MAC80211(priv, "leave\n");
@@ -2148,6 +2233,8 @@ void iwl_mac_reset_tsf(struct ieee80211_hw *hw)
 {
        struct iwl_priv *priv = hw->priv;
        unsigned long flags;
+       /* IBSS can only be the IWL_RXON_CTX_BSS context */
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
 
        mutex_lock(&priv->mutex);
        IWL_DEBUG_MAC80211(priv, "enter\n");
@@ -2178,8 +2265,8 @@ void iwl_mac_reset_tsf(struct ieee80211_hw *hw)
         * clear RXON_FILTER_ASSOC_MSK bit
         */
        iwl_scan_cancel_timeout(priv, 100);
-       priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-       iwlcore_commit_rxon(priv);
+       ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+       iwlcore_commit_rxon(priv, ctx);
 
        iwl_set_rate(priv);
 
@@ -2588,7 +2675,7 @@ static void iwl_force_rf_reset(struct iwl_priv *priv)
        if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return;
 
-       if (!iwl_is_associated(priv)) {
+       if (!iwl_is_any_associated(priv)) {
                IWL_DEBUG_SCAN(priv, "force reset rejected: not associated\n");
                return;
        }
@@ -2714,10 +2801,14 @@ static int iwl_check_stuck_queue(struct iwl_priv *priv, int cnt)
                                                "queue %d, not read %d time\n",
                                                q->id,
                                                q->repeat_same_read_ptr);
-                               mod_timer(&priv->monitor_recover, jiffies +
-                                       msecs_to_jiffies(IWL_ONE_HUNDRED_MSECS));
+                               if (!priv->cfg->advanced_bt_coexist) {
+                                       mod_timer(&priv->monitor_recover,
+                                               jiffies + msecs_to_jiffies(
+                                               IWL_ONE_HUNDRED_MSECS));
+                                       return 1;
+                               }
                        }
-                       return 1;
+                       return 0;
                } else {
                        q->last_read_ptr = q->read_ptr;
                        q->repeat_same_read_ptr = 0;
@@ -2735,25 +2826,27 @@ void iwl_bg_monitor_recover(unsigned long data)
                return;
 
        /* monitor and check for stuck cmd queue */
-       if (iwl_check_stuck_queue(priv, IWL_CMD_QUEUE_NUM))
+       if (iwl_check_stuck_queue(priv, priv->cmd_queue))
                return;
 
        /* monitor and check for other stuck queues */
-       if (iwl_is_associated(priv)) {
+       if (iwl_is_any_associated(priv)) {
                for (cnt = 0; cnt < priv->hw_params.max_txq_num; cnt++) {
                        /* skip as we already checked the command queue */
-                       if (cnt == IWL_CMD_QUEUE_NUM)
+                       if (cnt == priv->cmd_queue)
                                continue;
                        if (iwl_check_stuck_queue(priv, cnt))
                                return;
                }
        }
-       /*
-        * Reschedule the timer to occur in
-        * priv->cfg->monitor_recover_period
-        */
-       mod_timer(&priv->monitor_recover,
-               jiffies + msecs_to_jiffies(priv->cfg->monitor_recover_period));
+       if (priv->cfg->monitor_recover_period) {
+               /*
+                * Reschedule the timer to occur in
+                * priv->cfg->monitor_recover_period
+                */
+               mod_timer(&priv->monitor_recover, jiffies + msecs_to_jiffies(
+                         priv->cfg->monitor_recover_period));
+       }
 }
 EXPORT_SYMBOL(iwl_bg_monitor_recover);
 
index 5e6ee3da6bbf740846033e4a57e44956e326a73c..f7b57ed84f66610d01e91b131cdae51970d09bed 100644 (file)
@@ -88,11 +88,13 @@ struct iwl_cmd;
 #define IWL_CMD(x) case x: return #x
 
 struct iwl_hcmd_ops {
-       int (*rxon_assoc)(struct iwl_priv *priv);
-       int (*commit_rxon)(struct iwl_priv *priv);
-       void (*set_rxon_chain)(struct iwl_priv *priv);
+       int (*rxon_assoc)(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
+       int (*commit_rxon)(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
+       void (*set_rxon_chain)(struct iwl_priv *priv,
+                              struct iwl_rxon_context *ctx);
        int (*set_tx_ant)(struct iwl_priv *priv, u8 valid_tx_ant);
        void (*send_bt_config)(struct iwl_priv *priv);
+       int (*set_pan_params)(struct iwl_priv *priv);
 };
 
 struct iwl_hcmd_utils_ops {
@@ -136,6 +138,12 @@ struct iwl_temp_ops {
        void (*set_calib_version)(struct iwl_priv *priv);
 };
 
+struct iwl_tt_ops {
+       bool (*lower_power_detection)(struct iwl_priv *priv);
+       u8 (*tt_power_mode)(struct iwl_priv *priv);
+       bool (*ct_kill_check)(struct iwl_priv *priv);
+};
+
 struct iwl_lib_ops {
        /* set hw dependent parameters */
        int (*set_hw_params)(struct iwl_priv *priv);
@@ -199,7 +207,7 @@ struct iwl_lib_ops {
        /* station management */
        int (*manage_ibss_station)(struct iwl_priv *priv,
                                   struct ieee80211_vif *vif, bool add);
-       int (*update_bcast_station)(struct iwl_priv *priv);
+       int (*update_bcast_stations)(struct iwl_priv *priv);
        /* recover from tx queue stall */
        void (*recover_from_tx_stall)(unsigned long data);
        /* check for plcp health */
@@ -212,6 +220,9 @@ struct iwl_lib_ops {
        void (*dev_txfifo_flush)(struct iwl_priv *priv, u16 flush_control);
 
        struct iwl_debugfs_ops debugfs_ops;
+
+       /* thermal throttling */
+       struct iwl_tt_ops tt_ops;
 };
 
 struct iwl_led_ops {
@@ -269,6 +280,14 @@ struct iwl_mod_params {
  * @chain_noise_calib_by_driver: driver has the capability to perform
  *     chain noise calibration operation
  * @scan_antennas: available antenna for scan operation
+ * @advanced_bt_coexist: support advanced bt coexist
+ * @bt_init_traffic_load: specify initial bt traffic load
+ * @bt_prio_boost: default bt priority boost value
+ * @need_dc_calib: need to perform init dc calibration
+ * @bt_statistics: use BT version of statistics notification
+ * @agg_time_limit: maximum number of uSec in aggregation
+ * @ampdu_factor: Maximum A-MPDU length factor
+ * @ampdu_density: Minimum A-MPDU spacing
  *
  * We enable the driver to be backward compatible wrt API version. The
  * driver specifies which APIs it supports (with @ucode_api_max being the
@@ -337,8 +356,14 @@ struct iwl_cfg {
        const bool chain_noise_calib_by_driver;
        u8 scan_rx_antennas[IEEE80211_NUM_BANDS];
        u8 scan_tx_antennas[IEEE80211_NUM_BANDS];
+       bool advanced_bt_coexist;
+       u8 bt_init_traffic_load;
+       u8 bt_prio_boost;
        const bool need_dc_calib;
        const bool bt_statistics;
+       u16 agg_time_limit;
+       u8 ampdu_factor;
+       u8 ampdu_density;
 };
 
 /***************************
@@ -347,38 +372,41 @@ struct iwl_cfg {
 
 struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg,
                struct ieee80211_ops *hw_ops);
-void iwl_hw_detect(struct iwl_priv *priv);
 void iwl_activate_qos(struct iwl_priv *priv);
 int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
                    const struct ieee80211_tx_queue_params *params);
-void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt);
-int iwl_check_rxon_cmd(struct iwl_priv *priv);
-int iwl_full_rxon_required(struct iwl_priv *priv);
-void iwl_set_rxon_chain(struct iwl_priv *priv);
-int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch);
+int iwl_mac_tx_last_beacon(struct ieee80211_hw *hw);
+void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
+                          int hw_decrypt);
+int iwl_check_rxon_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
+int iwl_full_rxon_required(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
+void iwl_set_rxon_chain(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
+int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch,
+                        struct iwl_rxon_context *ctx);
 void iwl_set_flags_for_band(struct iwl_priv *priv,
+                           struct iwl_rxon_context *ctx,
                            enum ieee80211_band band,
                            struct ieee80211_vif *vif);
 u8 iwl_get_single_channel_number(struct iwl_priv *priv,
                                  enum ieee80211_band band);
 void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_config *ht_conf);
-u8 iwl_is_ht40_tx_allowed(struct iwl_priv *priv,
-                        struct ieee80211_sta_ht_cap *sta_ht_inf);
+bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv,
+                           struct iwl_rxon_context *ctx,
+                           struct ieee80211_sta_ht_cap *ht_cap);
 void iwl_connection_init_rx_config(struct iwl_priv *priv,
-                                  struct ieee80211_vif *vif);
+                                  struct iwl_rxon_context *ctx);
 void iwl_set_rate(struct iwl_priv *priv);
 int iwl_set_decrypted_flag(struct iwl_priv *priv,
                           struct ieee80211_hdr *hdr,
                           u32 decrypt_res,
                           struct ieee80211_rx_status *stats);
 void iwl_irq_handle_error(struct iwl_priv *priv);
-int iwl_set_hw_params(struct iwl_priv *priv);
 void iwl_post_associate(struct iwl_priv *priv, struct ieee80211_vif *vif);
 void iwl_bss_info_changed(struct ieee80211_hw *hw,
                                     struct ieee80211_vif *vif,
                                     struct ieee80211_bss_conf *bss_conf,
                                     u32 changes);
-int iwl_commit_rxon(struct iwl_priv *priv);
+int iwl_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
 int iwl_mac_add_interface(struct ieee80211_hw *hw,
                          struct ieee80211_vif *vif);
 void iwl_mac_remove_interface(struct ieee80211_hw *hw,
@@ -496,7 +524,8 @@ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force);
 
 int iwl_hwrate_to_plcp_idx(u32 rate_n_flags);
 
-u8 iwl_rate_get_lowest_plcp(struct iwl_priv *priv);
+u8 iwl_rate_get_lowest_plcp(struct iwl_priv *priv,
+                           struct iwl_rxon_context *ctx);
 
 u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant_idx, u8 valid);
 
@@ -527,7 +556,6 @@ int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms);
 int iwl_mac_hw_scan(struct ieee80211_hw *hw,
                    struct ieee80211_vif *vif,
                    struct cfg80211_scan_request *req);
-void iwl_bg_start_internal_scan(struct work_struct *work);
 void iwl_internal_short_hw_scan(struct iwl_priv *priv);
 int iwl_force_reset(struct iwl_priv *priv, int mode, bool external);
 u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame,
@@ -539,9 +567,6 @@ u16 iwl_get_active_dwell_time(struct iwl_priv *priv,
 u16 iwl_get_passive_dwell_time(struct iwl_priv *priv,
                               enum ieee80211_band band,
                               struct ieee80211_vif *vif);
-void iwl_bg_scan_check(struct work_struct *data);
-void iwl_bg_abort_scan(struct work_struct *work);
-void iwl_bg_scan_completed(struct work_struct *work);
 void iwl_setup_scan_deferred_work(struct iwl_priv *priv);
 
 /* For faster active scanning, scan will move to the next channel if fewer than
@@ -580,8 +605,6 @@ int iwl_send_cmd_pdu_async(struct iwl_priv *priv, u8 id, u16 len,
 
 int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd);
 
-int iwl_send_card_state(struct iwl_priv *priv, u32 flags,
-                       u8 meta_flag);
 
 /*****************************************************
  * PCI                                              *
@@ -616,9 +639,11 @@ int iwl_dump_nic_event_log(struct iwl_priv *priv,
 void iwl_dump_csr(struct iwl_priv *priv);
 int iwl_dump_fh(struct iwl_priv *priv, char **buf, bool display);
 #ifdef CONFIG_IWLWIFI_DEBUG
-void iwl_print_rx_config_cmd(struct iwl_priv *priv);
+void iwl_print_rx_config_cmd(struct iwl_priv *priv,
+                            struct iwl_rxon_context *ctx);
 #else
-static inline void iwl_print_rx_config_cmd(struct iwl_priv *priv)
+static inline void iwl_print_rx_config_cmd(struct iwl_priv *priv,
+                                          struct iwl_rxon_context *ctx)
 {
 }
 #endif
@@ -695,23 +720,24 @@ static inline int iwl_is_ready_rf(struct iwl_priv *priv)
        return iwl_is_ready(priv);
 }
 
-extern void iwl_rf_kill_ct_config(struct iwl_priv *priv);
 extern void iwl_send_bt_config(struct iwl_priv *priv);
 extern int iwl_send_statistics_request(struct iwl_priv *priv,
                                       u8 flags, bool clear);
-extern int iwl_send_lq_cmd(struct iwl_priv *priv,
+extern int iwl_send_lq_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
                struct iwl_link_quality_cmd *lq, u8 flags, bool init);
 void iwl_apm_stop(struct iwl_priv *priv);
 int iwl_apm_init(struct iwl_priv *priv);
 
-void iwl_setup_rxon_timing(struct iwl_priv *priv, struct ieee80211_vif *vif);
-static inline int iwl_send_rxon_assoc(struct iwl_priv *priv)
+int iwl_send_rxon_timing(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
+static inline int iwl_send_rxon_assoc(struct iwl_priv *priv,
+                                     struct iwl_rxon_context *ctx)
 {
-       return priv->cfg->ops->hcmd->rxon_assoc(priv);
+       return priv->cfg->ops->hcmd->rxon_assoc(priv, ctx);
 }
-static inline int iwlcore_commit_rxon(struct iwl_priv *priv)
+static inline int iwlcore_commit_rxon(struct iwl_priv *priv,
+                                     struct iwl_rxon_context *ctx)
 {
-       return priv->cfg->ops->hcmd->commit_rxon(priv);
+       return priv->cfg->ops->hcmd->commit_rxon(priv, ctx);
 }
 static inline void iwlcore_config_ap(struct iwl_priv *priv,
                                     struct ieee80211_vif *vif)
@@ -723,4 +749,8 @@ static inline const struct ieee80211_supported_band *iwl_get_hw_mode(
 {
        return priv->hw->wiphy->bands[band];
 }
+
+extern bool bt_coex_active;
+extern bool bt_siso_mode;
+
 #endif /* __iwl_core_h__ */
index e96a1bb12783db78efc0d07a2794599525f9f830..0ee8f516c4ab0e4b1711f32792ec89d84c52a65f 100644 (file)
@@ -467,8 +467,7 @@ static ssize_t iwl_dbgfs_channels_read(struct file *file, char __user *user_buf,
                for (i = 0; i < supp_band->n_channels; i++)
                        pos += scnprintf(buf + pos, bufsz - pos,
                                        "%d: %ddBm: BSS%s%s, %s.\n",
-                                       ieee80211_frequency_to_channel(
-                                       channels[i].center_freq),
+                                       channels[i].hw_value,
                                        channels[i].max_power,
                                        channels[i].flags & IEEE80211_CHAN_RADAR ?
                                        " (IEEE 802.11h required)" : "",
@@ -491,8 +490,7 @@ static ssize_t iwl_dbgfs_channels_read(struct file *file, char __user *user_buf,
                for (i = 0; i < supp_band->n_channels; i++)
                        pos += scnprintf(buf + pos, bufsz - pos,
                                        "%d: %ddBm: BSS%s%s, %s.\n",
-                                       ieee80211_frequency_to_channel(
-                                       channels[i].center_freq),
+                                       channels[i].hw_value,
                                        channels[i].max_power,
                                        channels[i].flags & IEEE80211_CHAN_RADAR ?
                                        " (IEEE 802.11h required)" : "",
@@ -645,19 +643,25 @@ static ssize_t iwl_dbgfs_qos_read(struct file *file, char __user *user_buf,
                                       size_t count, loff_t *ppos)
 {
        struct iwl_priv *priv = file->private_data;
+       struct iwl_rxon_context *ctx;
        int pos = 0, i;
-       char buf[256];
+       char buf[256 * NUM_IWL_RXON_CTX];
        const size_t bufsz = sizeof(buf);
 
-       for (i = 0; i < AC_NUM; i++) {
-               pos += scnprintf(buf + pos, bufsz - pos,
-                       "\tcw_min\tcw_max\taifsn\ttxop\n");
-               pos += scnprintf(buf + pos, bufsz - pos,
+       for_each_context(priv, ctx) {
+               pos += scnprintf(buf + pos, bufsz - pos, "context %d:\n",
+                                ctx->ctxid);
+               for (i = 0; i < AC_NUM; i++) {
+                       pos += scnprintf(buf + pos, bufsz - pos,
+                               "\tcw_min\tcw_max\taifsn\ttxop\n");
+                       pos += scnprintf(buf + pos, bufsz - pos,
                                "AC[%d]\t%u\t%u\t%u\t%u\n", i,
-                               priv->qos_data.def_qos_parm.ac[i].cw_min,
-                               priv->qos_data.def_qos_parm.ac[i].cw_max,
-                               priv->qos_data.def_qos_parm.ac[i].aifsn,
-                               priv->qos_data.def_qos_parm.ac[i].edca_txop);
+                               ctx->qos_data.def_qos_parm.ac[i].cw_min,
+                               ctx->qos_data.def_qos_parm.ac[i].cw_max,
+                               ctx->qos_data.def_qos_parm.ac[i].aifsn,
+                               ctx->qos_data.def_qos_parm.ac[i].edca_txop);
+               }
+               pos += scnprintf(buf + pos, bufsz - pos, "\n");
        }
        return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 }
@@ -732,7 +736,7 @@ static ssize_t iwl_dbgfs_disable_ht40_write(struct file *file,
                return -EFAULT;
        if (sscanf(buf, "%d", &ht40) != 1)
                return -EFAULT;
-       if (!iwl_is_associated(priv))
+       if (!iwl_is_any_associated(priv))
                priv->disable_ht40 = ht40 ? true : false;
        else {
                IWL_ERR(priv, "Sta associated with AP - "
@@ -1321,7 +1325,8 @@ static ssize_t iwl_dbgfs_rxon_flags_read(struct file *file,
        int len = 0;
        char buf[20];
 
-       len = sprintf(buf, "0x%04X\n", le32_to_cpu(priv->active_rxon.flags));
+       len = sprintf(buf, "0x%04X\n",
+               le32_to_cpu(priv->contexts[IWL_RXON_CTX_BSS].active.flags));
        return simple_read_from_buffer(user_buf, count, ppos, buf, len);
 }
 
@@ -1334,7 +1339,7 @@ static ssize_t iwl_dbgfs_rxon_filter_flags_read(struct file *file,
        char buf[20];
 
        len = sprintf(buf, "0x%04X\n",
-                     le32_to_cpu(priv->active_rxon.filter_flags));
+               le32_to_cpu(priv->contexts[IWL_RXON_CTX_BSS].active.filter_flags));
        return simple_read_from_buffer(user_buf, count, ppos, buf, len);
 }
 
@@ -1529,6 +1534,76 @@ static ssize_t iwl_dbgfs_ucode_bt_stats_read(struct file *file,
                        user_buf, count, ppos);
 }
 
+static ssize_t iwl_dbgfs_monitor_period_write(struct file *file,
+                                       const char __user *user_buf,
+                                       size_t count, loff_t *ppos) {
+
+       struct iwl_priv *priv = file->private_data;
+       char buf[8];
+       int buf_size;
+       int period;
+
+       memset(buf, 0, sizeof(buf));
+       buf_size = min(count, sizeof(buf) -  1);
+       if (copy_from_user(buf, user_buf, buf_size))
+               return -EFAULT;
+       if (sscanf(buf, "%d", &period) != 1)
+               return -EINVAL;
+       if (period < 0 || period > IWL_MAX_MONITORING_PERIOD)
+               priv->cfg->monitor_recover_period = IWL_DEF_MONITORING_PERIOD;
+       else
+               priv->cfg->monitor_recover_period = period;
+
+       if (priv->cfg->monitor_recover_period)
+               mod_timer(&priv->monitor_recover, jiffies + msecs_to_jiffies(
+                         priv->cfg->monitor_recover_period));
+       else
+               del_timer_sync(&priv->monitor_recover);
+       return count;
+}
+
+static ssize_t iwl_dbgfs_bt_traffic_read(struct file *file,
+                                       char __user *user_buf,
+                                       size_t count, loff_t *ppos) {
+
+       struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+       int pos = 0;
+       char buf[200];
+       const size_t bufsz = sizeof(buf);
+       ssize_t ret;
+
+       pos += scnprintf(buf + pos, bufsz - pos, "BT in %s mode\n",
+               priv->bt_full_concurrent ? "full concurrency" : "3-wire");
+       pos += scnprintf(buf + pos, bufsz - pos, "BT status: %s, "
+                        "last traffic notif: %d\n",
+               priv->bt_status ? "On" : "Off", priv->notif_bt_traffic_load);
+       pos += scnprintf(buf + pos, bufsz - pos, "ch_announcement: %d, "
+                        "sco_active: %d, kill_ack_mask: %x, "
+                        "kill_cts_mask: %x\n",
+               priv->bt_ch_announce, priv->bt_sco_active,
+               priv->kill_ack_mask, priv->kill_cts_mask);
+
+       pos += scnprintf(buf + pos, bufsz - pos, "bluetooth traffic load: ");
+       switch (priv->bt_traffic_load) {
+       case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS:
+               pos += scnprintf(buf + pos, bufsz - pos, "Continuous\n");
+               break;
+       case IWL_BT_COEX_TRAFFIC_LOAD_HIGH:
+               pos += scnprintf(buf + pos, bufsz - pos, "High\n");
+               break;
+       case IWL_BT_COEX_TRAFFIC_LOAD_LOW:
+               pos += scnprintf(buf + pos, bufsz - pos, "Low\n");
+               break;
+       case IWL_BT_COEX_TRAFFIC_LOAD_NONE:
+       default:
+               pos += scnprintf(buf + pos, bufsz - pos, "None\n");
+               break;
+       }
+
+       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+       return ret;
+}
+
 DEBUGFS_READ_FILE_OPS(rx_statistics);
 DEBUGFS_READ_FILE_OPS(tx_statistics);
 DEBUGFS_READ_WRITE_FILE_OPS(traffic_log);
@@ -1552,6 +1627,8 @@ DEBUGFS_READ_FILE_OPS(rxon_flags);
 DEBUGFS_READ_FILE_OPS(rxon_filter_flags);
 DEBUGFS_WRITE_FILE_OPS(txfifo_flush);
 DEBUGFS_READ_FILE_OPS(ucode_bt_stats);
+DEBUGFS_WRITE_FILE_OPS(monitor_period);
+DEBUGFS_READ_FILE_OPS(bt_traffic);
 
 /*
  * Create the debugfs files and directories
@@ -1623,6 +1700,9 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
                DEBUGFS_ADD_FILE(ucode_bt_stats, dir_debug, S_IRUSR);
        DEBUGFS_ADD_FILE(rxon_flags, dir_debug, S_IWUSR);
        DEBUGFS_ADD_FILE(rxon_filter_flags, dir_debug, S_IWUSR);
+       DEBUGFS_ADD_FILE(monitor_period, dir_debug, S_IWUSR);
+       if (priv->cfg->advanced_bt_coexist)
+               DEBUGFS_ADD_FILE(bt_traffic, dir_debug, S_IRUSR);
        if (priv->cfg->sensitivity_calib_by_driver)
                DEBUGFS_ADD_BOOL(disable_sensitivity, dir_rf,
                                 &priv->disable_sens_cal);
index 2e97cd2fa98a6e0c7d9cdc6d98582ac54fe28459..4dd38b7b8b743a1614678bab5732788c779e46fc 100644 (file)
@@ -47,6 +47,7 @@
 #include "iwl-led.h"
 #include "iwl-power.h"
 #include "iwl-agn-rs.h"
+#include "iwl-agn-tt.h"
 
 struct iwl_tx_queue;
 
@@ -143,6 +144,7 @@ struct iwl_queue {
 /* One for each TFD */
 struct iwl_tx_info {
        struct sk_buff *skb;
+       struct iwl_rxon_context *ctx;
 };
 
 /**
@@ -252,10 +254,14 @@ struct iwl_channel_info {
        struct iwl3945_scan_power_info scan_pwr_info[IWL_NUM_SCAN_RATES];
 };
 
-#define IWL_TX_FIFO_BK         0
+#define IWL_TX_FIFO_BK         0       /* shared */
 #define IWL_TX_FIFO_BE         1
-#define IWL_TX_FIFO_VI         2
+#define IWL_TX_FIFO_VI         2       /* shared */
 #define IWL_TX_FIFO_VO         3
+#define IWL_TX_FIFO_BK_IPAN    IWL_TX_FIFO_BK
+#define IWL_TX_FIFO_BE_IPAN    4
+#define IWL_TX_FIFO_VI_IPAN    IWL_TX_FIFO_VI
+#define IWL_TX_FIFO_VO_IPAN    5
 #define IWL_TX_FIFO_UNUSED     -1
 
 /* Minimum number of queues. MAX_NUM is defined in hw specific files.
@@ -264,11 +270,17 @@ struct iwl_channel_info {
 #define IWL_MIN_NUM_QUEUES     10
 
 /*
- * Queue #4 is the command queue for 3945/4965/5x00/1000/6x00,
- * the driver maps it into the appropriate device FIFO for the
- * uCode.
+ * Command queue depends on iPAN support.
  */
-#define IWL_CMD_QUEUE_NUM      4
+#define IWL_DEFAULT_CMD_QUEUE_NUM      4
+#define IWL_IPAN_CMD_QUEUE_NUM         9
+
+/*
+ * This queue number is required for proper operation
+ * because the ucode will stop/start the scheduler as
+ * required.
+ */
+#define IWL_IPAN_MCAST_QUEUE           8
 
 /* Power management (not Tx power) structures */
 
@@ -420,7 +432,7 @@ struct iwl_tid_data {
 };
 
 struct iwl_hw_key {
-       enum ieee80211_key_alg alg;
+       u32 cipher;
        int keylen;
        u8 keyidx;
        u8 key[32];
@@ -434,7 +446,13 @@ union iwl_ht_rate_supp {
        };
 };
 
-#define CFG_HT_RX_AMPDU_FACTOR_DEF  (0x3)
+#define CFG_HT_RX_AMPDU_FACTOR_8K   (0x0)
+#define CFG_HT_RX_AMPDU_FACTOR_16K  (0x1)
+#define CFG_HT_RX_AMPDU_FACTOR_32K  (0x2)
+#define CFG_HT_RX_AMPDU_FACTOR_64K  (0x3)
+#define CFG_HT_RX_AMPDU_FACTOR_DEF  CFG_HT_RX_AMPDU_FACTOR_64K
+#define CFG_HT_RX_AMPDU_FACTOR_MAX  CFG_HT_RX_AMPDU_FACTOR_64K
+#define CFG_HT_RX_AMPDU_FACTOR_MIN  CFG_HT_RX_AMPDU_FACTOR_8K
 
 /*
  * Maximal MPDU density for TX aggregation
@@ -443,19 +461,17 @@ union iwl_ht_rate_supp {
  * 6 - 8us density
  * 7 - 16us density
  */
+#define CFG_HT_MPDU_DENSITY_2USEC   (0x4)
 #define CFG_HT_MPDU_DENSITY_4USEC   (0x5)
+#define CFG_HT_MPDU_DENSITY_8USEC   (0x6)
+#define CFG_HT_MPDU_DENSITY_16USEC  (0x7)
 #define CFG_HT_MPDU_DENSITY_DEF CFG_HT_MPDU_DENSITY_4USEC
+#define CFG_HT_MPDU_DENSITY_MAX CFG_HT_MPDU_DENSITY_16USEC
+#define CFG_HT_MPDU_DENSITY_MIN     (0x1)
 
 struct iwl_ht_config {
-       /* self configuration data */
-       bool is_ht;
-       bool is_40mhz;
        bool single_chain_sufficient;
        enum ieee80211_smps_mode smps; /* current smps mode */
-       /* BSS related data */
-       u8 extension_chan_offset;
-       u8 ht_protection;
-       u8 non_GF_STA_present;
 };
 
 /* QoS structures */
@@ -473,12 +489,13 @@ struct iwl_qos_info {
 struct iwl_station_entry {
        struct iwl_addsta_cmd sta;
        struct iwl_tid_data tid[MAX_TID_COUNT];
-       u8 used;
+       u8 used, ctxid;
        struct iwl_hw_key keyinfo;
        struct iwl_link_quality_cmd *lq;
 };
 
 struct iwl_station_priv_common {
+       struct iwl_rxon_context *ctx;
        u8 sta_id;
 };
 
@@ -507,6 +524,7 @@ struct iwl_station_priv {
  * space for us to put data into.
  */
 struct iwl_vif_priv {
+       struct iwl_rxon_context *ctx;
        u8 ibss_bssid_sta_id;
 };
 
@@ -564,6 +582,7 @@ enum iwl_ucode_tlv_type {
        IWL_UCODE_TLV_INIT_DATA         = 4,
        IWL_UCODE_TLV_BOOT              = 5,
        IWL_UCODE_TLV_PROBE_MAX_LEN     = 6, /* a u32 value */
+       IWL_UCODE_TLV_PAN               = 7,
        IWL_UCODE_TLV_RUNT_EVTLOG_PTR   = 8,
        IWL_UCODE_TLV_RUNT_EVTLOG_SIZE  = 9,
        IWL_UCODE_TLV_RUNT_ERRLOG_PTR   = 10,
@@ -658,7 +677,6 @@ struct iwl_sensitivity_ranges {
  * @rx_page_order: Rx buffer page order
  * @rx_wrt_ptr_reg: FH{39}_RSCSR_CHNL0_WPTR
  * @max_stations:
- * @bcast_sta_id:
  * @ht40_channel: is 40MHz width possible in band 2.4
  * BIT(IEEE80211_BAND_5GHZ) BIT(IEEE80211_BAND_5GHZ)
  * @sw_crypto: 0 for hw, 1 for sw
@@ -682,7 +700,6 @@ struct iwl_hw_params {
        u32 rx_page_order;
        u32 rx_wrt_ptr_reg;
        u8  max_stations;
-       u8  bcast_sta_id;
        u8  ht40_channel;
        u8  max_beacon_itrvl;   /* in 1024 ms */
        u32 max_inst_size;
@@ -1052,7 +1069,10 @@ struct iwl_event_log {
 #define IWL_DEF_MONITORING_PERIOD      (1000)
 #define IWL_LONG_MONITORING_PERIOD     (5000)
 #define IWL_ONE_HUNDRED_MSECS   (100)
-#define IWL_SIXTY_SECS          (60000)
+#define IWL_MAX_MONITORING_PERIOD      (60000)
+
+/* BT Antenna Coupling Threshold (dB) */
+#define IWL_BT_ANTENNA_COUPLING_THRESHOLD      (35)
 
 enum iwl_reset {
        IWL_RF_RESET = 0,
@@ -1082,6 +1102,57 @@ struct iwl_force_reset {
  */
 #define IWLAGN_EXT_BEACON_TIME_POS     22
 
+enum iwl_rxon_context_id {
+       IWL_RXON_CTX_BSS,
+       IWL_RXON_CTX_PAN,
+
+       NUM_IWL_RXON_CTX
+};
+
+struct iwl_rxon_context {
+       struct ieee80211_vif *vif;
+
+       const u8 *ac_to_fifo;
+       const u8 *ac_to_queue;
+       u8 mcast_queue;
+
+       enum iwl_rxon_context_id ctxid;
+
+       u32 interface_modes, exclusive_interface_modes;
+       u8 unused_devtype, ap_devtype, ibss_devtype, station_devtype;
+
+       /*
+        * We declare this const so it can only be
+        * changed via explicit cast within the
+        * routines that actually update the physical
+        * hardware.
+        */
+       const struct iwl_rxon_cmd active;
+       struct iwl_rxon_cmd staging;
+
+       struct iwl_rxon_time_cmd timing;
+
+       struct iwl_qos_info qos_data;
+
+       u8 bcast_sta_id, ap_sta_id;
+
+       u8 rxon_cmd, rxon_assoc_cmd, rxon_timing_cmd;
+       u8 qos_cmd;
+       u8 wep_key_cmd;
+
+       struct iwl_wep_key wep_keys[WEP_KEYS_MAX];
+       u8 key_mapping_keys;
+
+       __le32 station_flags;
+
+       struct {
+               bool non_gf_sta_present;
+               u8 protection;
+               bool enabled, is_40mhz;
+               u8 extension_chan_offset;
+       } ht;
+};
+
 struct iwl_priv {
 
        /* ieee device used by generic ieee processing code */
@@ -1110,6 +1181,9 @@ struct iwl_priv {
        u32 ucode_beacon_time;
        int missed_beacon_threshold;
 
+       /* track IBSS manager (last beacon) status */
+       u32 ibss_manager;
+
        /* storing the jiffies when the plcp error rate is received */
        unsigned long plcp_jiffies;
 
@@ -1155,6 +1229,15 @@ struct iwl_priv {
        u32  hw_wa_rev;
        u8   rev_id;
 
+       /* microcode/device supports multiple contexts */
+       u8 valid_contexts;
+
+       /* command queue number */
+       u8 cmd_queue;
+
+       /* max number of station keys */
+       u8 sta_key_max_num;
+
        /* EEPROM MAC addresses */
        struct mac_address addresses[2];
 
@@ -1172,15 +1255,7 @@ struct iwl_priv {
        u8 ucode_write_complete;        /* the image write is complete */
        char firmware_name[25];
 
-
-       struct iwl_rxon_time_cmd rxon_timing;
-
-       /* We declare this const so it can only be
-        * changed via explicit cast within the
-        * routines that actually update the physical
-        * hardware */
-       const struct iwl_rxon_cmd active_rxon;
-       struct iwl_rxon_cmd staging_rxon;
+       struct iwl_rxon_context contexts[NUM_IWL_RXON_CTX];
 
        struct iwl_switch_rxon switch_rxon;
 
@@ -1242,8 +1317,6 @@ struct iwl_priv {
        spinlock_t sta_lock;
        int num_stations;
        struct iwl_station_entry stations[IWL_STATION_COUNT];
-       struct iwl_wep_key wep_keys[WEP_KEYS_MAX]; /* protected by mutex */
-       u8 key_mapping_key;
        unsigned long ucode_key_table;
 
        /* queue refcounts */
@@ -1268,7 +1341,6 @@ struct iwl_priv {
 
        /* Last Rx'd beacon timestamp */
        u64 timestamp;
-       struct ieee80211_vif *vif;
 
        union {
 #if defined(CONFIG_IWL3945) || defined(CONFIG_IWL3945_MODULE)
@@ -1348,12 +1420,27 @@ struct iwl_priv {
 #endif
        };
 
+       /* bt coex */
+       u8 bt_status;
+       u8 bt_traffic_load, notif_bt_traffic_load;
+       bool bt_ch_announce;
+       bool bt_sco_active;
+       bool bt_full_concurrent;
+       bool bt_ant_couple_ok;
+       __le32 kill_ack_mask;
+       __le32 kill_cts_mask;
+       __le16 bt_valid;
+       u16 bt_on_thresh;
+       u16 bt_duration;
+       u16 dynamic_frag_thresh;
+       u16 dynamic_agg_thresh;
+       u8 bt_ci_compliance;
+       struct work_struct bt_traffic_change_work;
+
        struct iwl_hw_params hw_params;
 
        u32 inta_mask;
 
-       struct iwl_qos_info qos_data;
-
        struct workqueue_struct *workqueue;
 
        struct work_struct restart;
@@ -1361,11 +1448,15 @@ struct iwl_priv {
        struct work_struct rx_replenish;
        struct work_struct abort_scan;
        struct work_struct beacon_update;
+       struct iwl_rxon_context *beacon_ctx;
+
        struct work_struct tt_work;
        struct work_struct ct_enter;
        struct work_struct ct_exit;
        struct work_struct start_internal_scan;
        struct work_struct tx_flush;
+       struct work_struct bt_full_concurrency;
+       struct work_struct bt_runtime_config;
 
        struct tasklet_struct irq_tasklet;
 
@@ -1453,10 +1544,34 @@ static inline struct ieee80211_hdr *iwl_tx_queue_get_hdr(struct iwl_priv *priv,
        return NULL;
 }
 
+static inline struct iwl_rxon_context *
+iwl_rxon_ctx_from_vif(struct ieee80211_vif *vif)
+{
+       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
+
+       return vif_priv->ctx;
+}
+
+#define for_each_context(priv, ctx)                            \
+       for (ctx = &priv->contexts[IWL_RXON_CTX_BSS];           \
+            ctx < &priv->contexts[NUM_IWL_RXON_CTX]; ctx++)    \
+               if (priv->valid_contexts & BIT(ctx->ctxid))
+
+static inline int iwl_is_associated(struct iwl_priv *priv,
+                                   enum iwl_rxon_context_id ctxid)
+{
+       return (priv->contexts[ctxid].active.filter_flags &
+                       RXON_FILTER_ASSOC_MSK) ? 1 : 0;
+}
+
+static inline int iwl_is_any_associated(struct iwl_priv *priv)
+{
+       return iwl_is_associated(priv, IWL_RXON_CTX_BSS);
+}
 
-static inline int iwl_is_associated(struct iwl_priv *priv)
+static inline int iwl_is_associated_ctx(struct iwl_rxon_context *ctx)
 {
-       return (priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) ? 1 : 0;
+       return (ctx->active.filter_flags & RXON_FILTER_ASSOC_MSK) ? 1 : 0;
 }
 
 static inline int is_channel_valid(const struct iwl_channel_info *ch_info)
index 258d059ef41f44ae01e4199327133655b5e6df1e..c373b53babeaee1cd1c4e7781151e683e305f2ba 100644 (file)
@@ -97,6 +97,17 @@ const char *get_cmd_string(u8 cmd)
                IWL_CMD(REPLY_TX_POWER_DBM_CMD);
                IWL_CMD(TEMPERATURE_NOTIFICATION);
                IWL_CMD(TX_ANT_CONFIGURATION_CMD);
+               IWL_CMD(REPLY_BT_COEX_PROFILE_NOTIF);
+               IWL_CMD(REPLY_BT_COEX_PRIO_TABLE);
+               IWL_CMD(REPLY_BT_COEX_PROT_ENV);
+               IWL_CMD(REPLY_WIPAN_PARAMS);
+               IWL_CMD(REPLY_WIPAN_RXON);
+               IWL_CMD(REPLY_WIPAN_RXON_TIMING);
+               IWL_CMD(REPLY_WIPAN_RXON_ASSOC);
+               IWL_CMD(REPLY_WIPAN_QOS_PARAM);
+               IWL_CMD(REPLY_WIPAN_WEPKEY);
+               IWL_CMD(REPLY_WIPAN_P2P_CHANNEL_SWITCH);
+               IWL_CMD(REPLY_WIPAN_NOA_NOTIFICATION);
        default:
                return "UNKNOWN";
 
@@ -229,7 +240,7 @@ cancel:
                 * in later, it will possibly set an invalid
                 * address (cmd->meta.source).
                 */
-               priv->txq[IWL_CMD_QUEUE_NUM].meta[cmd_idx].flags &=
+               priv->txq[priv->cmd_queue].meta[cmd_idx].flags &=
                                                        ~CMD_WANT_SKB;
        }
 fail:
index cda6a94d6cc92234f901470fb3c8fe93650c61e6..63c0ab46261faa105a7a20419b1d7cab899d2dc8 100644 (file)
@@ -192,47 +192,6 @@ static void iwl_static_sleep_cmd(struct iwl_priv *priv,
        IWL_DEBUG_POWER(priv, "Sleep command for index %d\n", lvl + 1);
 }
 
-/* default Thermal Throttling transaction table
- * Current state   |         Throttling Down               |  Throttling Up
- *=============================================================================
- *                 Condition Nxt State  Condition Nxt State Condition Nxt State
- *-----------------------------------------------------------------------------
- *     IWL_TI_0     T >= 114   CT_KILL  114>T>=105   TI_1      N/A      N/A
- *     IWL_TI_1     T >= 114   CT_KILL  114>T>=110   TI_2     T<=95     TI_0
- *     IWL_TI_2     T >= 114   CT_KILL                        T<=100    TI_1
- *    IWL_CT_KILL      N/A       N/A       N/A        N/A     T<=95     TI_0
- *=============================================================================
- */
-static const struct iwl_tt_trans tt_range_0[IWL_TI_STATE_MAX - 1] = {
-       {IWL_TI_0, IWL_ABSOLUTE_ZERO, 104},
-       {IWL_TI_1, 105, CT_KILL_THRESHOLD - 1},
-       {IWL_TI_CT_KILL, CT_KILL_THRESHOLD, IWL_ABSOLUTE_MAX}
-};
-static const struct iwl_tt_trans tt_range_1[IWL_TI_STATE_MAX - 1] = {
-       {IWL_TI_0, IWL_ABSOLUTE_ZERO, 95},
-       {IWL_TI_2, 110, CT_KILL_THRESHOLD - 1},
-       {IWL_TI_CT_KILL, CT_KILL_THRESHOLD, IWL_ABSOLUTE_MAX}
-};
-static const struct iwl_tt_trans tt_range_2[IWL_TI_STATE_MAX - 1] = {
-       {IWL_TI_1, IWL_ABSOLUTE_ZERO, 100},
-       {IWL_TI_CT_KILL, CT_KILL_THRESHOLD, IWL_ABSOLUTE_MAX},
-       {IWL_TI_CT_KILL, CT_KILL_THRESHOLD, IWL_ABSOLUTE_MAX}
-};
-static const struct iwl_tt_trans tt_range_3[IWL_TI_STATE_MAX - 1] = {
-       {IWL_TI_0, IWL_ABSOLUTE_ZERO, CT_KILL_EXIT_THRESHOLD},
-       {IWL_TI_CT_KILL, CT_KILL_EXIT_THRESHOLD + 1, IWL_ABSOLUTE_MAX},
-       {IWL_TI_CT_KILL, CT_KILL_EXIT_THRESHOLD + 1, IWL_ABSOLUTE_MAX}
-};
-
-/* Advance Thermal Throttling default restriction table */
-static const struct iwl_tt_restriction restriction_range[IWL_TI_STATE_MAX] = {
-       {IWL_ANT_OK_MULTI, IWL_ANT_OK_MULTI, true },
-       {IWL_ANT_OK_SINGLE, IWL_ANT_OK_MULTI, true },
-       {IWL_ANT_OK_SINGLE, IWL_ANT_OK_SINGLE, false },
-       {IWL_ANT_OK_NONE, IWL_ANT_OK_NONE, false }
-};
-
-
 static void iwl_power_sleep_cam_cmd(struct iwl_priv *priv,
                                    struct iwl_powertable_cmd *cmd)
 {
@@ -308,7 +267,6 @@ static int iwl_set_power(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd)
 int iwl_power_update_mode(struct iwl_priv *priv, bool force)
 {
        int ret = 0;
-       struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
        bool enabled = priv->hw->conf.flags & IEEE80211_CONF_PS;
        bool update_chains;
        struct iwl_powertable_cmd cmd;
@@ -325,9 +283,13 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force)
        else if (priv->cfg->supports_idle &&
                 priv->hw->conf.flags & IEEE80211_CONF_IDLE)
                iwl_static_sleep_cmd(priv, &cmd, IWL_POWER_INDEX_5, 20);
-       else if (tt->state >= IWL_TI_1)
-               iwl_static_sleep_cmd(priv, &cmd, tt->tt_power_mode, dtimper);
-       else if (!enabled)
+       else if (priv->cfg->ops->lib->tt_ops.lower_power_detection &&
+                priv->cfg->ops->lib->tt_ops.tt_power_mode &&
+                priv->cfg->ops->lib->tt_ops.lower_power_detection(priv)) {
+               /* in thermal throttling low power state */
+               iwl_static_sleep_cmd(priv, &cmd,
+                   priv->cfg->ops->lib->tt_ops.tt_power_mode(priv), dtimper);
+       } else if (!enabled)
                iwl_power_sleep_cam_cmd(priv, &cmd);
        else if (priv->power_data.debug_sleep_level_override >= 0)
                iwl_static_sleep_cmd(priv, &cmd,
@@ -367,592 +329,6 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force)
 }
 EXPORT_SYMBOL(iwl_power_update_mode);
 
-bool iwl_ht_enabled(struct iwl_priv *priv)
-{
-       struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
-       struct iwl_tt_restriction *restriction;
-
-       if (!priv->thermal_throttle.advanced_tt)
-               return true;
-       restriction = tt->restriction + tt->state;
-       return restriction->is_ht;
-}
-EXPORT_SYMBOL(iwl_ht_enabled);
-
-bool iwl_within_ct_kill_margin(struct iwl_priv *priv)
-{
-       s32 temp = priv->temperature; /* degrees CELSIUS except specified */
-       bool within_margin = false;
-
-       if (priv->cfg->temperature_kelvin)
-               temp = KELVIN_TO_CELSIUS(priv->temperature);
-
-       if (!priv->thermal_throttle.advanced_tt)
-               within_margin = ((temp + IWL_TT_CT_KILL_MARGIN) >=
-                               CT_KILL_THRESHOLD_LEGACY) ? true : false;
-       else
-               within_margin = ((temp + IWL_TT_CT_KILL_MARGIN) >=
-                               CT_KILL_THRESHOLD) ? true : false;
-       return within_margin;
-}
-
-enum iwl_antenna_ok iwl_tx_ant_restriction(struct iwl_priv *priv)
-{
-       struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
-       struct iwl_tt_restriction *restriction;
-
-       if (!priv->thermal_throttle.advanced_tt)
-               return IWL_ANT_OK_MULTI;
-       restriction = tt->restriction + tt->state;
-       return restriction->tx_stream;
-}
-EXPORT_SYMBOL(iwl_tx_ant_restriction);
-
-enum iwl_antenna_ok iwl_rx_ant_restriction(struct iwl_priv *priv)
-{
-       struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
-       struct iwl_tt_restriction *restriction;
-
-       if (!priv->thermal_throttle.advanced_tt)
-               return IWL_ANT_OK_MULTI;
-       restriction = tt->restriction + tt->state;
-       return restriction->rx_stream;
-}
-
-#define CT_KILL_EXIT_DURATION (5)      /* 5 seconds duration */
-#define CT_KILL_WAITING_DURATION (300) /* 300ms duration */
-
-/*
- * toggle the bit to wake up uCode and check the temperature
- * if the temperature is below CT, uCode will stay awake and send card
- * state notification with CT_KILL bit clear to inform Thermal Throttling
- * Management to change state. Otherwise, uCode will go back to sleep
- * without doing anything, driver should continue the 5 seconds timer
- * to wake up uCode for temperature check until temperature drop below CT
- */
-static void iwl_tt_check_exit_ct_kill(unsigned long data)
-{
-       struct iwl_priv *priv = (struct iwl_priv *)data;
-       struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
-       unsigned long flags;
-
-       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-               return;
-
-       if (tt->state == IWL_TI_CT_KILL) {
-               if (priv->thermal_throttle.ct_kill_toggle) {
-                       iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
-                                   CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
-                       priv->thermal_throttle.ct_kill_toggle = false;
-               } else {
-                       iwl_write32(priv, CSR_UCODE_DRV_GP1_SET,
-                                   CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
-                       priv->thermal_throttle.ct_kill_toggle = true;
-               }
-               iwl_read32(priv, CSR_UCODE_DRV_GP1);
-               spin_lock_irqsave(&priv->reg_lock, flags);
-               if (!iwl_grab_nic_access(priv))
-                       iwl_release_nic_access(priv);
-               spin_unlock_irqrestore(&priv->reg_lock, flags);
-
-               /* Reschedule the ct_kill timer to occur in
-                * CT_KILL_EXIT_DURATION seconds to ensure we get a
-                * thermal update */
-               IWL_DEBUG_POWER(priv, "schedule ct_kill exit timer\n");
-               mod_timer(&priv->thermal_throttle.ct_kill_exit_tm, jiffies +
-                         CT_KILL_EXIT_DURATION * HZ);
-       }
-}
-
-static void iwl_perform_ct_kill_task(struct iwl_priv *priv,
-                          bool stop)
-{
-       if (stop) {
-               IWL_DEBUG_POWER(priv, "Stop all queues\n");
-               if (priv->mac80211_registered)
-                       ieee80211_stop_queues(priv->hw);
-               IWL_DEBUG_POWER(priv,
-                               "Schedule 5 seconds CT_KILL Timer\n");
-               mod_timer(&priv->thermal_throttle.ct_kill_exit_tm, jiffies +
-                         CT_KILL_EXIT_DURATION * HZ);
-       } else {
-               IWL_DEBUG_POWER(priv, "Wake all queues\n");
-               if (priv->mac80211_registered)
-                       ieee80211_wake_queues(priv->hw);
-       }
-}
-
-static void iwl_tt_ready_for_ct_kill(unsigned long data)
-{
-       struct iwl_priv *priv = (struct iwl_priv *)data;
-       struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
-
-       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-               return;
-
-       /* temperature timer expired, ready to go into CT_KILL state */
-       if (tt->state != IWL_TI_CT_KILL) {
-               IWL_DEBUG_POWER(priv, "entering CT_KILL state when temperature timer expired\n");
-               tt->state = IWL_TI_CT_KILL;
-               set_bit(STATUS_CT_KILL, &priv->status);
-               iwl_perform_ct_kill_task(priv, true);
-       }
-}
-
-static void iwl_prepare_ct_kill_task(struct iwl_priv *priv)
-{
-       IWL_DEBUG_POWER(priv, "Prepare to enter IWL_TI_CT_KILL\n");
-       /* make request to retrieve statistics information */
-       iwl_send_statistics_request(priv, CMD_SYNC, false);
-       /* Reschedule the ct_kill wait timer */
-       mod_timer(&priv->thermal_throttle.ct_kill_waiting_tm,
-                jiffies + msecs_to_jiffies(CT_KILL_WAITING_DURATION));
-}
-
-#define IWL_MINIMAL_POWER_THRESHOLD            (CT_KILL_THRESHOLD_LEGACY)
-#define IWL_REDUCED_PERFORMANCE_THRESHOLD_2    (100)
-#define IWL_REDUCED_PERFORMANCE_THRESHOLD_1    (90)
-
-/*
- * Legacy thermal throttling
- * 1) Avoid NIC destruction due to high temperatures
- *     Chip will identify dangerously high temperatures that can
- *     harm the device and will power down
- * 2) Avoid the NIC power down due to high temperature
- *     Throttle early enough to lower the power consumption before
- *     drastic steps are needed
- */
-static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp, bool force)
-{
-       struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
-       enum iwl_tt_state old_state;
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-       if ((tt->tt_previous_temp) &&
-           (temp > tt->tt_previous_temp) &&
-           ((temp - tt->tt_previous_temp) >
-           IWL_TT_INCREASE_MARGIN)) {
-               IWL_DEBUG_POWER(priv,
-                       "Temperature increase %d degree Celsius\n",
-                       (temp - tt->tt_previous_temp));
-       }
-#endif
-       old_state = tt->state;
-       /* in Celsius */
-       if (temp >= IWL_MINIMAL_POWER_THRESHOLD)
-               tt->state = IWL_TI_CT_KILL;
-       else if (temp >= IWL_REDUCED_PERFORMANCE_THRESHOLD_2)
-               tt->state = IWL_TI_2;
-       else if (temp >= IWL_REDUCED_PERFORMANCE_THRESHOLD_1)
-               tt->state = IWL_TI_1;
-       else
-               tt->state = IWL_TI_0;
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-       tt->tt_previous_temp = temp;
-#endif
-       /* stop ct_kill_waiting_tm timer */
-       del_timer_sync(&priv->thermal_throttle.ct_kill_waiting_tm);
-       if (tt->state != old_state) {
-               switch (tt->state) {
-               case IWL_TI_0:
-                       /*
-                        * When the system is ready to go back to IWL_TI_0
-                        * we only have to call iwl_power_update_mode() to
-                        * do so.
-                        */
-                       break;
-               case IWL_TI_1:
-                       tt->tt_power_mode = IWL_POWER_INDEX_3;
-                       break;
-               case IWL_TI_2:
-                       tt->tt_power_mode = IWL_POWER_INDEX_4;
-                       break;
-               default:
-                       tt->tt_power_mode = IWL_POWER_INDEX_5;
-                       break;
-               }
-               mutex_lock(&priv->mutex);
-               if (old_state == IWL_TI_CT_KILL)
-                       clear_bit(STATUS_CT_KILL, &priv->status);
-               if (tt->state != IWL_TI_CT_KILL &&
-                   iwl_power_update_mode(priv, true)) {
-                       /* TT state not updated
-                        * try again during next temperature read
-                        */
-                       if (old_state == IWL_TI_CT_KILL)
-                               set_bit(STATUS_CT_KILL, &priv->status);
-                       tt->state = old_state;
-                       IWL_ERR(priv, "Cannot update power mode, "
-                                       "TT state not updated\n");
-               } else {
-                       if (tt->state == IWL_TI_CT_KILL) {
-                               if (force) {
-                                       set_bit(STATUS_CT_KILL, &priv->status);
-                                       iwl_perform_ct_kill_task(priv, true);
-                               } else {
-                                       iwl_prepare_ct_kill_task(priv);
-                                       tt->state = old_state;
-                               }
-                       } else if (old_state == IWL_TI_CT_KILL &&
-                                tt->state != IWL_TI_CT_KILL)
-                               iwl_perform_ct_kill_task(priv, false);
-                       IWL_DEBUG_POWER(priv, "Temperature state changed %u\n",
-                                       tt->state);
-                       IWL_DEBUG_POWER(priv, "Power Index change to %u\n",
-                                       tt->tt_power_mode);
-               }
-               mutex_unlock(&priv->mutex);
-       }
-}
-
-/*
- * Advance thermal throttling
- * 1) Avoid NIC destruction due to high temperatures
- *     Chip will identify dangerously high temperatures that can
- *     harm the device and will power down
- * 2) Avoid the NIC power down due to high temperature
- *     Throttle early enough to lower the power consumption before
- *     drastic steps are needed
- *     Actions include relaxing the power down sleep thresholds and
- *     decreasing the number of TX streams
- * 3) Avoid throughput performance impact as much as possible
- *
- *=============================================================================
- *                 Condition Nxt State  Condition Nxt State Condition Nxt State
- *-----------------------------------------------------------------------------
- *     IWL_TI_0     T >= 114   CT_KILL  114>T>=105   TI_1      N/A      N/A
- *     IWL_TI_1     T >= 114   CT_KILL  114>T>=110   TI_2     T<=95     TI_0
- *     IWL_TI_2     T >= 114   CT_KILL                        T<=100    TI_1
- *    IWL_CT_KILL      N/A       N/A       N/A        N/A     T<=95     TI_0
- *=============================================================================
- */
-static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp, bool force)
-{
-       struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
-       int i;
-       bool changed = false;
-       enum iwl_tt_state old_state;
-       struct iwl_tt_trans *transaction;
-
-       old_state = tt->state;
-       for (i = 0; i < IWL_TI_STATE_MAX - 1; i++) {
-               /* based on the current TT state,
-                * find the curresponding transaction table
-                * each table has (IWL_TI_STATE_MAX - 1) entries
-                * tt->transaction + ((old_state * (IWL_TI_STATE_MAX - 1))
-                * will advance to the correct table.
-                * then based on the current temperature
-                * find the next state need to transaction to
-                * go through all the possible (IWL_TI_STATE_MAX - 1) entries
-                * in the current table to see if transaction is needed
-                */
-               transaction = tt->transaction +
-                       ((old_state * (IWL_TI_STATE_MAX - 1)) + i);
-               if (temp >= transaction->tt_low &&
-                   temp <= transaction->tt_high) {
-#ifdef CONFIG_IWLWIFI_DEBUG
-                       if ((tt->tt_previous_temp) &&
-                           (temp > tt->tt_previous_temp) &&
-                           ((temp - tt->tt_previous_temp) >
-                           IWL_TT_INCREASE_MARGIN)) {
-                               IWL_DEBUG_POWER(priv,
-                                       "Temperature increase %d "
-                                       "degree Celsius\n",
-                                       (temp - tt->tt_previous_temp));
-                       }
-                       tt->tt_previous_temp = temp;
-#endif
-                       if (old_state !=
-                           transaction->next_state) {
-                               changed = true;
-                               tt->state =
-                                       transaction->next_state;
-                       }
-                       break;
-               }
-       }
-       /* stop ct_kill_waiting_tm timer */
-       del_timer_sync(&priv->thermal_throttle.ct_kill_waiting_tm);
-       if (changed) {
-               struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
-
-               if (tt->state >= IWL_TI_1) {
-                       /* force PI = IWL_POWER_INDEX_5 in the case of TI > 0 */
-                       tt->tt_power_mode = IWL_POWER_INDEX_5;
-                       if (!iwl_ht_enabled(priv))
-                               /* disable HT */
-                               rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK |
-                                       RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK |
-                                       RXON_FLG_HT40_PROT_MSK |
-                                       RXON_FLG_HT_PROT_MSK);
-                       else {
-                               /* check HT capability and set
-                                * according to the system HT capability
-                                * in case get disabled before */
-                               iwl_set_rxon_ht(priv, &priv->current_ht_config);
-                       }
-
-               } else {
-                       /*
-                        * restore system power setting -- it will be
-                        * recalculated automatically.
-                        */
-
-                       /* check HT capability and set
-                        * according to the system HT capability
-                        * in case get disabled before */
-                       iwl_set_rxon_ht(priv, &priv->current_ht_config);
-               }
-               mutex_lock(&priv->mutex);
-               if (old_state == IWL_TI_CT_KILL)
-                       clear_bit(STATUS_CT_KILL, &priv->status);
-               if (tt->state != IWL_TI_CT_KILL &&
-                   iwl_power_update_mode(priv, true)) {
-                       /* TT state not updated
-                        * try again during next temperature read
-                        */
-                       IWL_ERR(priv, "Cannot update power mode, "
-                                       "TT state not updated\n");
-                       if (old_state == IWL_TI_CT_KILL)
-                               set_bit(STATUS_CT_KILL, &priv->status);
-                       tt->state = old_state;
-               } else {
-                       IWL_DEBUG_POWER(priv,
-                                       "Thermal Throttling to new state: %u\n",
-                                       tt->state);
-                       if (old_state != IWL_TI_CT_KILL &&
-                           tt->state == IWL_TI_CT_KILL) {
-                               if (force) {
-                                       IWL_DEBUG_POWER(priv,
-                                               "Enter IWL_TI_CT_KILL\n");
-                                       set_bit(STATUS_CT_KILL, &priv->status);
-                                       iwl_perform_ct_kill_task(priv, true);
-                               } else {
-                                       iwl_prepare_ct_kill_task(priv);
-                                       tt->state = old_state;
-                               }
-                       } else if (old_state == IWL_TI_CT_KILL &&
-                                 tt->state != IWL_TI_CT_KILL) {
-                               IWL_DEBUG_POWER(priv, "Exit IWL_TI_CT_KILL\n");
-                               iwl_perform_ct_kill_task(priv, false);
-                       }
-               }
-               mutex_unlock(&priv->mutex);
-       }
-}
-
-/* Card State Notification indicated reach critical temperature
- * if PSP not enable, no Thermal Throttling function will be performed
- * just set the GP1 bit to acknowledge the event
- * otherwise, go into IWL_TI_CT_KILL state
- * since Card State Notification will not provide any temperature reading
- * for Legacy mode
- * so just pass the CT_KILL temperature to iwl_legacy_tt_handler()
- * for advance mode
- * pass CT_KILL_THRESHOLD+1 to make sure move into IWL_TI_CT_KILL state
- */
-static void iwl_bg_ct_enter(struct work_struct *work)
-{
-       struct iwl_priv *priv = container_of(work, struct iwl_priv, ct_enter);
-       struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
-
-       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-               return;
-
-       if (!iwl_is_ready(priv))
-               return;
-
-       if (tt->state != IWL_TI_CT_KILL) {
-               IWL_ERR(priv, "Device reached critical temperature "
-                             "- ucode going to sleep!\n");
-               if (!priv->thermal_throttle.advanced_tt)
-                       iwl_legacy_tt_handler(priv,
-                                             IWL_MINIMAL_POWER_THRESHOLD,
-                                             true);
-               else
-                       iwl_advance_tt_handler(priv,
-                                              CT_KILL_THRESHOLD + 1, true);
-       }
-}
-
-/* Card State Notification indicated out of critical temperature
- * since Card State Notification will not provide any temperature reading
- * so pass the IWL_REDUCED_PERFORMANCE_THRESHOLD_2 temperature
- * to iwl_legacy_tt_handler() to get out of IWL_CT_KILL state
- */
-static void iwl_bg_ct_exit(struct work_struct *work)
-{
-       struct iwl_priv *priv = container_of(work, struct iwl_priv, ct_exit);
-       struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
-
-       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-               return;
-
-       if (!iwl_is_ready(priv))
-               return;
-
-       /* stop ct_kill_exit_tm timer */
-       del_timer_sync(&priv->thermal_throttle.ct_kill_exit_tm);
-
-       if (tt->state == IWL_TI_CT_KILL) {
-               IWL_ERR(priv,
-                       "Device temperature below critical"
-                       "- ucode awake!\n");
-               /*
-                * exit from CT_KILL state
-                * reset the current temperature reading
-                */
-               priv->temperature = 0;
-               if (!priv->thermal_throttle.advanced_tt)
-                       iwl_legacy_tt_handler(priv,
-                                             IWL_REDUCED_PERFORMANCE_THRESHOLD_2,
-                                             true);
-               else
-                       iwl_advance_tt_handler(priv, CT_KILL_EXIT_THRESHOLD,
-                                              true);
-       }
-}
-
-void iwl_tt_enter_ct_kill(struct iwl_priv *priv)
-{
-       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-               return;
-
-       IWL_DEBUG_POWER(priv, "Queueing critical temperature enter.\n");
-       queue_work(priv->workqueue, &priv->ct_enter);
-}
-EXPORT_SYMBOL(iwl_tt_enter_ct_kill);
-
-void iwl_tt_exit_ct_kill(struct iwl_priv *priv)
-{
-       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-               return;
-
-       IWL_DEBUG_POWER(priv, "Queueing critical temperature exit.\n");
-       queue_work(priv->workqueue, &priv->ct_exit);
-}
-EXPORT_SYMBOL(iwl_tt_exit_ct_kill);
-
-static void iwl_bg_tt_work(struct work_struct *work)
-{
-       struct iwl_priv *priv = container_of(work, struct iwl_priv, tt_work);
-       s32 temp = priv->temperature; /* degrees CELSIUS except specified */
-
-       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-               return;
-
-       if (priv->cfg->temperature_kelvin)
-               temp = KELVIN_TO_CELSIUS(priv->temperature);
-
-       if (!priv->thermal_throttle.advanced_tt)
-               iwl_legacy_tt_handler(priv, temp, false);
-       else
-               iwl_advance_tt_handler(priv, temp, false);
-}
-
-void iwl_tt_handler(struct iwl_priv *priv)
-{
-       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-               return;
-
-       IWL_DEBUG_POWER(priv, "Queueing thermal throttling work.\n");
-       queue_work(priv->workqueue, &priv->tt_work);
-}
-EXPORT_SYMBOL(iwl_tt_handler);
-
-/* Thermal throttling initialization
- * For advance thermal throttling:
- *     Initialize Thermal Index and temperature threshold table
- *     Initialize thermal throttling restriction table
- */
-void iwl_tt_initialize(struct iwl_priv *priv)
-{
-       struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
-       int size = sizeof(struct iwl_tt_trans) * (IWL_TI_STATE_MAX - 1);
-       struct iwl_tt_trans *transaction;
-
-       IWL_DEBUG_POWER(priv, "Initialize Thermal Throttling\n");
-
-       memset(tt, 0, sizeof(struct iwl_tt_mgmt));
-
-       tt->state = IWL_TI_0;
-       init_timer(&priv->thermal_throttle.ct_kill_exit_tm);
-       priv->thermal_throttle.ct_kill_exit_tm.data = (unsigned long)priv;
-       priv->thermal_throttle.ct_kill_exit_tm.function =
-               iwl_tt_check_exit_ct_kill;
-       init_timer(&priv->thermal_throttle.ct_kill_waiting_tm);
-       priv->thermal_throttle.ct_kill_waiting_tm.data = (unsigned long)priv;
-       priv->thermal_throttle.ct_kill_waiting_tm.function =
-               iwl_tt_ready_for_ct_kill;
-       /* setup deferred ct kill work */
-       INIT_WORK(&priv->tt_work, iwl_bg_tt_work);
-       INIT_WORK(&priv->ct_enter, iwl_bg_ct_enter);
-       INIT_WORK(&priv->ct_exit, iwl_bg_ct_exit);
-
-       if (priv->cfg->adv_thermal_throttle) {
-               IWL_DEBUG_POWER(priv, "Advanced Thermal Throttling\n");
-               tt->restriction = kzalloc(sizeof(struct iwl_tt_restriction) *
-                                        IWL_TI_STATE_MAX, GFP_KERNEL);
-               tt->transaction = kzalloc(sizeof(struct iwl_tt_trans) *
-                       IWL_TI_STATE_MAX * (IWL_TI_STATE_MAX - 1),
-                       GFP_KERNEL);
-               if (!tt->restriction || !tt->transaction) {
-                       IWL_ERR(priv, "Fallback to Legacy Throttling\n");
-                       priv->thermal_throttle.advanced_tt = false;
-                       kfree(tt->restriction);
-                       tt->restriction = NULL;
-                       kfree(tt->transaction);
-                       tt->transaction = NULL;
-               } else {
-                       transaction = tt->transaction +
-                               (IWL_TI_0 * (IWL_TI_STATE_MAX - 1));
-                       memcpy(transaction, &tt_range_0[0], size);
-                       transaction = tt->transaction +
-                               (IWL_TI_1 * (IWL_TI_STATE_MAX - 1));
-                       memcpy(transaction, &tt_range_1[0], size);
-                       transaction = tt->transaction +
-                               (IWL_TI_2 * (IWL_TI_STATE_MAX - 1));
-                       memcpy(transaction, &tt_range_2[0], size);
-                       transaction = tt->transaction +
-                               (IWL_TI_CT_KILL * (IWL_TI_STATE_MAX - 1));
-                       memcpy(transaction, &tt_range_3[0], size);
-                       size = sizeof(struct iwl_tt_restriction) *
-                               IWL_TI_STATE_MAX;
-                       memcpy(tt->restriction,
-                               &restriction_range[0], size);
-                       priv->thermal_throttle.advanced_tt = true;
-               }
-       } else {
-               IWL_DEBUG_POWER(priv, "Legacy Thermal Throttling\n");
-               priv->thermal_throttle.advanced_tt = false;
-       }
-}
-EXPORT_SYMBOL(iwl_tt_initialize);
-
-/* cleanup thermal throttling management related memory and timer */
-void iwl_tt_exit(struct iwl_priv *priv)
-{
-       struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
-
-       /* stop ct_kill_exit_tm timer if activated */
-       del_timer_sync(&priv->thermal_throttle.ct_kill_exit_tm);
-       /* stop ct_kill_waiting_tm timer if activated */
-       del_timer_sync(&priv->thermal_throttle.ct_kill_waiting_tm);
-       cancel_work_sync(&priv->tt_work);
-       cancel_work_sync(&priv->ct_enter);
-       cancel_work_sync(&priv->ct_exit);
-
-       if (priv->thermal_throttle.advanced_tt) {
-               /* free advance thermal throttling memory */
-               kfree(tt->restriction);
-               tt->restriction = NULL;
-               kfree(tt->transaction);
-               tt->transaction = NULL;
-       }
-}
-EXPORT_SYMBOL(iwl_tt_exit);
-
 /* initialize to default */
 void iwl_power_initialize(struct iwl_priv *priv)
 {
index 5db91c10dcc8ca602a4f1760ac4dbd395105bdae..df81565a7cc49c7414a6acd2421a2f3bd0f85930 100644 (file)
 
 #include "iwl-commands.h"
 
-#define IWL_ABSOLUTE_ZERO              0
-#define IWL_ABSOLUTE_MAX               0xFFFFFFFF
-#define IWL_TT_INCREASE_MARGIN 5
-#define IWL_TT_CT_KILL_MARGIN  3
-
-enum iwl_antenna_ok {
-       IWL_ANT_OK_NONE,
-       IWL_ANT_OK_SINGLE,
-       IWL_ANT_OK_MULTI,
-};
-
-/* Thermal Throttling State Machine states */
-enum  iwl_tt_state {
-       IWL_TI_0,       /* normal temperature, system power state */
-       IWL_TI_1,       /* high temperature detect, low power state */
-       IWL_TI_2,       /* higher temperature detected, lower power state */
-       IWL_TI_CT_KILL, /* critical temperature detected, lowest power state */
-       IWL_TI_STATE_MAX
-};
-
-/**
- * struct iwl_tt_restriction - Thermal Throttling restriction table
- * @tx_stream: number of tx stream allowed
- * @is_ht: ht enable/disable
- * @rx_stream: number of rx stream allowed
- *
- * This table is used by advance thermal throttling management
- * based on the current thermal throttling state, and determines
- * the number of tx/rx streams and the status of HT operation.
- */
-struct iwl_tt_restriction {
-       enum iwl_antenna_ok tx_stream;
-       enum iwl_antenna_ok rx_stream;
-       bool is_ht;
-};
-
-/**
- * struct iwl_tt_trans - Thermal Throttling transaction table
- * @next_state:  next thermal throttling mode
- * @tt_low: low temperature threshold to change state
- * @tt_high: high temperature threshold to change state
- *
- * This is used by the advanced thermal throttling algorithm
- * to determine the next thermal state to go based on the
- * current temperature.
- */
-struct iwl_tt_trans {
-       enum iwl_tt_state next_state;
-       u32 tt_low;
-       u32 tt_high;
-};
-
-/**
- * struct iwl_tt_mgnt - Thermal Throttling Management structure
- * @advanced_tt:    advanced thermal throttle required
- * @state:          current Thermal Throttling state
- * @tt_power_mode:  Thermal Throttling power mode index
- *                 being used to set power level when
- *                 when thermal throttling state != IWL_TI_0
- *                 the tt_power_mode should set to different
- *                 power mode based on the current tt state
- * @tt_previous_temperature: last measured temperature
- * @iwl_tt_restriction: ptr to restriction tbl, used by advance
- *                 thermal throttling to determine how many tx/rx streams
- *                 should be used in tt state; and can HT be enabled or not
- * @iwl_tt_trans: ptr to adv trans table, used by advance thermal throttling
- *                 state transaction
- * @ct_kill_toggle: used to toggle the CSR bit when checking uCode temperature
- * @ct_kill_exit_tm: timer to exit thermal kill
- */
-struct iwl_tt_mgmt {
-       enum iwl_tt_state state;
-       bool advanced_tt;
-       u8 tt_power_mode;
-       bool ct_kill_toggle;
-#ifdef CONFIG_IWLWIFI_DEBUG
-       s32 tt_previous_temp;
-#endif
-       struct iwl_tt_restriction *restriction;
-       struct iwl_tt_trans *transaction;
-       struct timer_list ct_kill_exit_tm;
-       struct timer_list ct_kill_waiting_tm;
-};
-
 enum iwl_power_level {
        IWL_POWER_INDEX_1,
        IWL_POWER_INDEX_2,
@@ -130,15 +46,6 @@ struct iwl_power_mgr {
 };
 
 int iwl_power_update_mode(struct iwl_priv *priv, bool force);
-bool iwl_ht_enabled(struct iwl_priv *priv);
-bool iwl_within_ct_kill_margin(struct iwl_priv *priv);
-enum iwl_antenna_ok iwl_tx_ant_restriction(struct iwl_priv *priv);
-enum iwl_antenna_ok iwl_rx_ant_restriction(struct iwl_priv *priv);
-void iwl_tt_enter_ct_kill(struct iwl_priv *priv);
-void iwl_tt_exit_ct_kill(struct iwl_priv *priv);
-void iwl_tt_handler(struct iwl_priv *priv);
-void iwl_tt_initialize(struct iwl_priv *priv);
-void iwl_tt_exit(struct iwl_priv *priv);
 void iwl_power_initialize(struct iwl_priv *priv);
 
 extern bool no_sleep_autoadjust;
index b1f101caf19d2f063386453c7cd1f8e045e7b10d..5469655646aebaa72cf673a942e4f127bd3fa5e5 100644 (file)
  *     at a time, until receiving ACK from receiving station, or reaching
  *     retry limit and giving up.
  *
- *     The command queue (#4) must use this mode!
+ *     The command queue (#4/#9) must use this mode!
  *     This mode does not require use of the Byte Count table in host DRAM.
  *
  * Driver controls scheduler operation via 3 means:
  *     (1024 bytes for each queue).
  *
  * After receiving "Alive" response from uCode, driver must initialize
- * the scheduler (especially for queue #4, the command queue, otherwise
+ * the scheduler (especially for queue #4/#9, the command queue, otherwise
  * the driver can't issue commands!):
  */
 
 #define IWLAGN_SCD_TRANSLATE_TBL_OFFSET_QUEUE(x) \
        ((IWLAGN_SCD_TRANSLATE_TBL_OFFSET + ((x) * 2)) & 0xfffc)
 
-#define IWLAGN_SCD_QUEUECHAIN_SEL_ALL(x)               (((1<<(x)) - 1) &\
-       (~(1<<IWL_CMD_QUEUE_NUM)))
+#define IWLAGN_SCD_QUEUECHAIN_SEL_ALL(priv)    \
+       (((1<<(priv)->hw_params.max_txq_num) - 1) &\
+       (~(1<<(priv)->cmd_queue)))
 
 #define IWLAGN_SCD_BASE                        (PRPH_BASE + 0xa02c00)
 
index 79773e353baaa56478a6d173fdc5f0f70cf837fa..10be197b0f2294b92643baf5a96d4ebd141552c7 100644 (file)
@@ -228,7 +228,7 @@ void iwl_recover_from_statistics(struct iwl_priv *priv,
 {
        if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return;
-       if (iwl_is_associated(priv)) {
+       if (iwl_is_any_associated(priv)) {
                if (priv->cfg->ops->lib->check_ack_health) {
                        if (!priv->cfg->ops->lib->check_ack_health(
                            priv, pkt)) {
@@ -266,7 +266,12 @@ int iwl_set_decrypted_flag(struct iwl_priv *priv,
 {
        u16 fc = le16_to_cpu(hdr->frame_control);
 
-       if (priv->active_rxon.filter_flags & RXON_FILTER_DIS_DECRYPT_MSK)
+       /*
+        * All contexts have the same setting here due to it being
+        * a module parameter, so OK to check any context.
+        */
+       if (priv->contexts[IWL_RXON_CTX_BSS].active.filter_flags &
+                                               RXON_FILTER_DIS_DECRYPT_MSK)
                return 0;
 
        if (!(fc & IEEE80211_FCTL_PROTECTED))
index a4b3663a262fb40857c521126d8d1df73f8f72be..7727f0966d3168e971dad3c6ffd03d3e45c54369 100644 (file)
@@ -206,7 +206,6 @@ static void iwl_rx_scan_results_notif(struct iwl_priv *priv,
 static void iwl_rx_scan_complete_notif(struct iwl_priv *priv,
                                       struct iwl_rx_mem_buffer *rxb)
 {
-#ifdef CONFIG_IWLWIFI_DEBUG
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
        struct iwl_scancomplete_notification *scan_notif = (void *)pkt->u.raw;
 
@@ -214,7 +213,6 @@ static void iwl_rx_scan_complete_notif(struct iwl_priv *priv,
                       scan_notif->scanned_channels,
                       scan_notif->tsf_low,
                       scan_notif->tsf_high, scan_notif->status);
-#endif
 
        /* The HW is no longer scanning */
        clear_bit(STATUS_SCAN_HW, &priv->status);
@@ -236,6 +234,26 @@ static void iwl_rx_scan_complete_notif(struct iwl_priv *priv,
 
        clear_bit(STATUS_SCANNING, &priv->status);
 
+       if (priv->iw_mode != NL80211_IFTYPE_ADHOC &&
+           priv->cfg->advanced_bt_coexist && priv->bt_status !=
+           scan_notif->bt_status) {
+               if (scan_notif->bt_status) {
+                       /* BT on */
+                       if (!priv->bt_ch_announce)
+                               priv->bt_traffic_load =
+                                       IWL_BT_COEX_TRAFFIC_LOAD_HIGH;
+                       /*
+                        * otherwise, no traffic load information provided
+                        * no changes made
+                        */
+               } else {
+                       /* BT off */
+                       priv->bt_traffic_load =
+                               IWL_BT_COEX_TRAFFIC_LOAD_NONE;
+               }
+               priv->bt_status = scan_notif->bt_status;
+               queue_work(priv->workqueue, &priv->bt_traffic_change_work);
+       }
        queue_work(priv->workqueue, &priv->scan_completed);
 }
 
@@ -268,18 +286,28 @@ u16 iwl_get_passive_dwell_time(struct iwl_priv *priv,
                               enum ieee80211_band band,
                               struct ieee80211_vif *vif)
 {
+       struct iwl_rxon_context *ctx;
        u16 passive = (band == IEEE80211_BAND_2GHZ) ?
            IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_24 :
            IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_52;
 
-       if (iwl_is_associated(priv)) {
-               /* If we're associated, we clamp the maximum passive
-                * dwell time to be 98% of the beacon interval (minus
-                * 2 * channel tune time) */
-               passive = vif ? vif->bss_conf.beacon_int : 0;
-               if ((passive > IWL_PASSIVE_DWELL_BASE) || !passive)
-                       passive = IWL_PASSIVE_DWELL_BASE;
-               passive = (passive * 98) / 100 - IWL_CHANNEL_TUNE_TIME * 2;
+       if (iwl_is_any_associated(priv)) {
+               /*
+                * If we're associated, we clamp the maximum passive
+                * dwell time to be 98% of the smallest beacon interval
+                * (minus 2 * channel tune time)
+                */
+               for_each_context(priv, ctx) {
+                       u16 value;
+
+                       if (!iwl_is_associated_ctx(ctx))
+                               continue;
+                       value = ctx->vif ? ctx->vif->bss_conf.beacon_int : 0;
+                       if ((value > IWL_PASSIVE_DWELL_BASE) || !value)
+                               value = IWL_PASSIVE_DWELL_BASE;
+                       value = (value * 98) / 100 - IWL_CHANNEL_TUNE_TIME * 2;
+                       passive = min(value, passive);
+               }
        }
 
        return passive;
@@ -378,7 +406,7 @@ void iwl_internal_short_hw_scan(struct iwl_priv *priv)
        queue_work(priv->workqueue, &priv->start_internal_scan);
 }
 
-void iwl_bg_start_internal_scan(struct work_struct *work)
+static void iwl_bg_start_internal_scan(struct work_struct *work)
 {
        struct iwl_priv *priv =
                container_of(work, struct iwl_priv, start_internal_scan);
@@ -418,9 +446,8 @@ void iwl_bg_start_internal_scan(struct work_struct *work)
  unlock:
        mutex_unlock(&priv->mutex);
 }
-EXPORT_SYMBOL(iwl_bg_start_internal_scan);
 
-void iwl_bg_scan_check(struct work_struct *data)
+static void iwl_bg_scan_check(struct work_struct *data)
 {
        struct iwl_priv *priv =
            container_of(data, struct iwl_priv, scan_check.work);
@@ -439,7 +466,6 @@ void iwl_bg_scan_check(struct work_struct *data)
        }
        mutex_unlock(&priv->mutex);
 }
-EXPORT_SYMBOL(iwl_bg_scan_check);
 
 /**
  * iwl_fill_probe_req - fill in all required fields and IE for probe request
@@ -489,7 +515,7 @@ u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame,
 }
 EXPORT_SYMBOL(iwl_fill_probe_req);
 
-void iwl_bg_abort_scan(struct work_struct *work)
+static void iwl_bg_abort_scan(struct work_struct *work)
 {
        struct iwl_priv *priv = container_of(work, struct iwl_priv, abort_scan);
 
@@ -504,13 +530,14 @@ void iwl_bg_abort_scan(struct work_struct *work)
                iwl_send_scan_abort(priv);
        mutex_unlock(&priv->mutex);
 }
-EXPORT_SYMBOL(iwl_bg_abort_scan);
 
-void iwl_bg_scan_completed(struct work_struct *work)
+static void iwl_bg_scan_completed(struct work_struct *work)
 {
        struct iwl_priv *priv =
            container_of(work, struct iwl_priv, scan_completed);
        bool internal = false;
+       bool scan_completed = false;
+       struct iwl_rxon_context *ctx;
 
        IWL_DEBUG_SCAN(priv, "SCAN complete scan\n");
 
@@ -521,7 +548,8 @@ void iwl_bg_scan_completed(struct work_struct *work)
                priv->is_internal_short_scan = false;
                IWL_DEBUG_SCAN(priv, "internal short scan completed\n");
                internal = true;
-       } else {
+       } else if (priv->scan_request) {
+               scan_completed = true;
                priv->scan_request = NULL;
                priv->scan_vif = NULL;
        }
@@ -540,11 +568,13 @@ void iwl_bg_scan_completed(struct work_struct *work)
         * Since setting the RXON may have been deferred while
         * performing the scan, fire one off if needed
         */
-       if (memcmp(&priv->active_rxon,
-                  &priv->staging_rxon, sizeof(priv->staging_rxon)))
-               iwlcore_commit_rxon(priv);
+       for_each_context(priv, ctx)
+               iwlcore_commit_rxon(priv, ctx);
 
  out:
+       if (priv->cfg->ops->hcmd->set_pan_params)
+               priv->cfg->ops->hcmd->set_pan_params(priv);
+
        mutex_unlock(&priv->mutex);
 
        /*
@@ -552,10 +582,9 @@ void iwl_bg_scan_completed(struct work_struct *work)
         * into driver again into functions that will attempt to take
         * mutex.
         */
-       if (!internal)
+       if (scan_completed)
                ieee80211_scan_completed(priv->hw, false);
 }
-EXPORT_SYMBOL(iwl_bg_scan_completed);
 
 void iwl_setup_scan_deferred_work(struct iwl_priv *priv)
 {
index 7e0829be5e783a0e49957a89414d61a413a79407..ccd09027c7cdd8f3a1b479e6fda1215c960bd102 100644 (file)
@@ -172,12 +172,14 @@ int iwl_send_add_sta(struct iwl_priv *priv,
 EXPORT_SYMBOL(iwl_send_add_sta);
 
 static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index,
-                                  struct ieee80211_sta_ht_cap *sta_ht_inf)
+                                  struct ieee80211_sta *sta,
+                                  struct iwl_rxon_context *ctx)
 {
+       struct ieee80211_sta_ht_cap *sta_ht_inf = &sta->ht_cap;
        __le32 sta_flags;
        u8 mimo_ps_mode;
 
-       if (!sta_ht_inf || !sta_ht_inf->ht_supported)
+       if (!sta || !sta_ht_inf->ht_supported)
                goto done;
 
        mimo_ps_mode = (sta_ht_inf->cap & IEEE80211_HT_CAP_SM_PS) >> 2;
@@ -211,7 +213,7 @@ static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index,
        sta_flags |= cpu_to_le32(
              (u32)sta_ht_inf->ampdu_density << STA_FLG_AGG_MPDU_DENSITY_POS);
 
-       if (iwl_is_ht40_tx_allowed(priv, sta_ht_inf))
+       if (iwl_is_ht40_tx_allowed(priv, ctx, &sta->ht_cap))
                sta_flags |= STA_FLG_HT40_EN_MSK;
        else
                sta_flags &= ~STA_FLG_HT40_EN_MSK;
@@ -226,9 +228,9 @@ static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index,
  *
  * should be called with sta_lock held
  */
-static u8 iwl_prep_station(struct iwl_priv *priv, const u8 *addr,
-                          bool is_ap,
-                          struct ieee80211_sta_ht_cap *ht_info)
+static u8 iwl_prep_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
+                          const u8 *addr, bool is_ap,
+                          struct ieee80211_sta *sta)
 {
        struct iwl_station_entry *station;
        int i;
@@ -236,9 +238,9 @@ static u8 iwl_prep_station(struct iwl_priv *priv, const u8 *addr,
        u16 rate;
 
        if (is_ap)
-               sta_id = IWL_AP_ID;
+               sta_id = ctx->ap_sta_id;
        else if (is_broadcast_ether_addr(addr))
-               sta_id = priv->hw_params.bcast_sta_id;
+               sta_id = ctx->bcast_sta_id;
        else
                for (i = IWL_STA_ID; i < priv->hw_params.max_stations; i++) {
                        if (!compare_ether_addr(priv->stations[i].sta.sta.addr,
@@ -289,14 +291,22 @@ static u8 iwl_prep_station(struct iwl_priv *priv, const u8 *addr,
        memcpy(station->sta.sta.addr, addr, ETH_ALEN);
        station->sta.mode = 0;
        station->sta.sta.sta_id = sta_id;
-       station->sta.station_flags = 0;
+       station->sta.station_flags = ctx->station_flags;
+       station->ctxid = ctx->ctxid;
+
+       if (sta) {
+               struct iwl_station_priv_common *sta_priv;
+
+               sta_priv = (void *)sta->drv_priv;
+               sta_priv->ctx = ctx;
+       }
 
        /*
         * OK to call unconditionally, since local stations (IBSS BSSID
-        * STA and broadcast STA) pass in a NULL ht_info, and mac80211
+        * STA and broadcast STA) pass in a NULL sta, and mac80211
         * doesn't allow HT IBSS.
         */
-       iwl_set_ht_add_station(priv, sta_id, ht_info);
+       iwl_set_ht_add_station(priv, sta_id, sta, ctx);
 
        /* 3945 only */
        rate = (priv->band == IEEE80211_BAND_5GHZ) ?
@@ -313,10 +323,9 @@ static u8 iwl_prep_station(struct iwl_priv *priv, const u8 *addr,
 /**
  * iwl_add_station_common -
  */
-int iwl_add_station_common(struct iwl_priv *priv, const u8 *addr,
-                                 bool is_ap,
-                                 struct ieee80211_sta_ht_cap *ht_info,
-                                 u8 *sta_id_r)
+int iwl_add_station_common(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
+                          const u8 *addr, bool is_ap,
+                          struct ieee80211_sta *sta, u8 *sta_id_r)
 {
        unsigned long flags_spin;
        int ret = 0;
@@ -325,7 +334,7 @@ int iwl_add_station_common(struct iwl_priv *priv, const u8 *addr,
 
        *sta_id_r = 0;
        spin_lock_irqsave(&priv->sta_lock, flags_spin);
-       sta_id = iwl_prep_station(priv, addr, is_ap, ht_info);
+       sta_id = iwl_prep_station(priv, ctx, addr, is_ap, sta);
        if (sta_id == IWL_INVALID_STATION) {
                IWL_ERR(priv, "Unable to prepare station %pM for addition\n",
                        addr);
@@ -431,8 +440,8 @@ static struct iwl_link_quality_cmd *iwl_sta_alloc_lq(struct iwl_priv *priv,
  *
  * Function sleeps.
  */
-int iwl_add_bssid_station(struct iwl_priv *priv, const u8 *addr, bool init_rs,
-                         u8 *sta_id_r)
+int iwl_add_bssid_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
+                         const u8 *addr, bool init_rs, u8 *sta_id_r)
 {
        int ret;
        u8 sta_id;
@@ -442,7 +451,7 @@ int iwl_add_bssid_station(struct iwl_priv *priv, const u8 *addr, bool init_rs,
        if (sta_id_r)
                *sta_id_r = IWL_INVALID_STATION;
 
-       ret = iwl_add_station_common(priv, addr, 0, NULL, &sta_id);
+       ret = iwl_add_station_common(priv, ctx, addr, 0, NULL, &sta_id);
        if (ret) {
                IWL_ERR(priv, "Unable to add station %pM\n", addr);
                return ret;
@@ -464,7 +473,7 @@ int iwl_add_bssid_station(struct iwl_priv *priv, const u8 *addr, bool init_rs,
                        return -ENOMEM;
                }
 
-               ret = iwl_send_lq_cmd(priv, link_cmd, CMD_SYNC, true);
+               ret = iwl_send_lq_cmd(priv, ctx, link_cmd, CMD_SYNC, true);
                if (ret)
                        IWL_ERR(priv, "Link quality command failed (%d)\n", ret);
 
@@ -616,7 +625,8 @@ EXPORT_SYMBOL_GPL(iwl_remove_station);
  * other than explicit station management would cause this in
  * the ucode, e.g. unassociated RXON.
  */
-void iwl_clear_ucode_stations(struct iwl_priv *priv)
+void iwl_clear_ucode_stations(struct iwl_priv *priv,
+                             struct iwl_rxon_context *ctx)
 {
        int i;
        unsigned long flags_spin;
@@ -626,6 +636,9 @@ void iwl_clear_ucode_stations(struct iwl_priv *priv)
 
        spin_lock_irqsave(&priv->sta_lock, flags_spin);
        for (i = 0; i < priv->hw_params.max_stations; i++) {
+               if (ctx && ctx->ctxid != priv->stations[i].ctxid)
+                       continue;
+
                if (priv->stations[i].used & IWL_STA_UCODE_ACTIVE) {
                        IWL_DEBUG_INFO(priv, "Clearing ucode active for station %d\n", i);
                        priv->stations[i].used &= ~IWL_STA_UCODE_ACTIVE;
@@ -647,7 +660,7 @@ EXPORT_SYMBOL(iwl_clear_ucode_stations);
  *
  * Function sleeps.
  */
-void iwl_restore_stations(struct iwl_priv *priv)
+void iwl_restore_stations(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
 {
        struct iwl_addsta_cmd sta_cmd;
        struct iwl_link_quality_cmd lq;
@@ -665,6 +678,8 @@ void iwl_restore_stations(struct iwl_priv *priv)
        IWL_DEBUG_ASSOC(priv, "Restoring all known stations ... start.\n");
        spin_lock_irqsave(&priv->sta_lock, flags_spin);
        for (i = 0; i < priv->hw_params.max_stations; i++) {
+               if (ctx->ctxid != priv->stations[i].ctxid)
+                       continue;
                if ((priv->stations[i].used & IWL_STA_DRIVER_ACTIVE) &&
                            !(priv->stations[i].used & IWL_STA_UCODE_ACTIVE)) {
                        IWL_DEBUG_ASSOC(priv, "Restoring sta %pM\n",
@@ -700,7 +715,7 @@ void iwl_restore_stations(struct iwl_priv *priv)
                         * current LQ command
                         */
                        if (send_lq)
-                               iwl_send_lq_cmd(priv, &lq, CMD_SYNC, true);
+                               iwl_send_lq_cmd(priv, ctx, &lq, CMD_SYNC, true);
                        spin_lock_irqsave(&priv->sta_lock, flags_spin);
                        priv->stations[i].used &= ~IWL_STA_UCODE_INPROGRESS;
                }
@@ -718,7 +733,7 @@ int iwl_get_free_ucode_key_index(struct iwl_priv *priv)
 {
        int i;
 
-       for (i = 0; i < STA_KEY_MAX_NUM; i++)
+       for (i = 0; i < priv->sta_key_max_num; i++)
                if (!test_and_set_bit(i, &priv->ucode_key_table))
                        return i;
 
@@ -726,7 +741,9 @@ int iwl_get_free_ucode_key_index(struct iwl_priv *priv)
 }
 EXPORT_SYMBOL(iwl_get_free_ucode_key_index);
 
-static int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, u8 send_if_empty)
+static int iwl_send_static_wepkey_cmd(struct iwl_priv *priv,
+                                     struct iwl_rxon_context *ctx,
+                                     bool send_if_empty)
 {
        int i, not_empty = 0;
        u8 buff[sizeof(struct iwl_wep_cmd) +
@@ -734,7 +751,7 @@ static int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, u8 send_if_empty)
        struct iwl_wep_cmd *wep_cmd = (struct iwl_wep_cmd *)buff;
        size_t cmd_size  = sizeof(struct iwl_wep_cmd);
        struct iwl_host_cmd cmd = {
-               .id = REPLY_WEPKEY,
+               .id = ctx->wep_key_cmd,
                .data = wep_cmd,
                .flags = CMD_SYNC,
        };
@@ -746,16 +763,16 @@ static int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, u8 send_if_empty)
 
        for (i = 0; i < WEP_KEYS_MAX ; i++) {
                wep_cmd->key[i].key_index = i;
-               if (priv->wep_keys[i].key_size) {
+               if (ctx->wep_keys[i].key_size) {
                        wep_cmd->key[i].key_offset = i;
                        not_empty = 1;
                } else {
                        wep_cmd->key[i].key_offset = WEP_INVALID_OFFSET;
                }
 
-               wep_cmd->key[i].key_size = priv->wep_keys[i].key_size;
-               memcpy(&wep_cmd->key[i].key[3], priv->wep_keys[i].key,
-                               priv->wep_keys[i].key_size);
+               wep_cmd->key[i].key_size = ctx->wep_keys[i].key_size;
+               memcpy(&wep_cmd->key[i].key[3], ctx->wep_keys[i].key,
+                               ctx->wep_keys[i].key_size);
        }
 
        wep_cmd->global_key_type = WEP_KEY_WEP_TYPE;
@@ -771,15 +788,17 @@ static int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, u8 send_if_empty)
                return 0;
 }
 
-int iwl_restore_default_wep_keys(struct iwl_priv *priv)
+int iwl_restore_default_wep_keys(struct iwl_priv *priv,
+                                struct iwl_rxon_context *ctx)
 {
        lockdep_assert_held(&priv->mutex);
 
-       return iwl_send_static_wepkey_cmd(priv, 0);
+       return iwl_send_static_wepkey_cmd(priv, ctx, false);
 }
 EXPORT_SYMBOL(iwl_restore_default_wep_keys);
 
 int iwl_remove_default_wep_key(struct iwl_priv *priv,
+                              struct iwl_rxon_context *ctx,
                               struct ieee80211_key_conf *keyconf)
 {
        int ret;
@@ -789,13 +808,13 @@ int iwl_remove_default_wep_key(struct iwl_priv *priv,
        IWL_DEBUG_WEP(priv, "Removing default WEP key: idx=%d\n",
                      keyconf->keyidx);
 
-       memset(&priv->wep_keys[keyconf->keyidx], 0, sizeof(priv->wep_keys[0]));
+       memset(&ctx->wep_keys[keyconf->keyidx], 0, sizeof(ctx->wep_keys[0]));
        if (iwl_is_rfkill(priv)) {
                IWL_DEBUG_WEP(priv, "Not sending REPLY_WEPKEY command due to RFKILL.\n");
                /* but keys in device are clear anyway so return success */
                return 0;
        }
-       ret = iwl_send_static_wepkey_cmd(priv, 1);
+       ret = iwl_send_static_wepkey_cmd(priv, ctx, 1);
        IWL_DEBUG_WEP(priv, "Remove default WEP key: idx=%d ret=%d\n",
                      keyconf->keyidx, ret);
 
@@ -804,6 +823,7 @@ int iwl_remove_default_wep_key(struct iwl_priv *priv,
 EXPORT_SYMBOL(iwl_remove_default_wep_key);
 
 int iwl_set_default_wep_key(struct iwl_priv *priv,
+                           struct iwl_rxon_context *ctx,
                            struct ieee80211_key_conf *keyconf)
 {
        int ret;
@@ -818,13 +838,13 @@ int iwl_set_default_wep_key(struct iwl_priv *priv,
 
        keyconf->flags &= ~IEEE80211_KEY_FLAG_GENERATE_IV;
        keyconf->hw_key_idx = HW_KEY_DEFAULT;
-       priv->stations[IWL_AP_ID].keyinfo.alg = ALG_WEP;
+       priv->stations[ctx->ap_sta_id].keyinfo.cipher = keyconf->cipher;
 
-       priv->wep_keys[keyconf->keyidx].key_size = keyconf->keylen;
-       memcpy(&priv->wep_keys[keyconf->keyidx].key, &keyconf->key,
+       ctx->wep_keys[keyconf->keyidx].key_size = keyconf->keylen;
+       memcpy(&ctx->wep_keys[keyconf->keyidx].key, &keyconf->key,
                                                        keyconf->keylen);
 
-       ret = iwl_send_static_wepkey_cmd(priv, 0);
+       ret = iwl_send_static_wepkey_cmd(priv, ctx, false);
        IWL_DEBUG_WEP(priv, "Set default WEP key: len=%d idx=%d ret=%d\n",
                keyconf->keylen, keyconf->keyidx, ret);
 
@@ -833,8 +853,9 @@ int iwl_set_default_wep_key(struct iwl_priv *priv,
 EXPORT_SYMBOL(iwl_set_default_wep_key);
 
 static int iwl_set_wep_dynamic_key_info(struct iwl_priv *priv,
-                               struct ieee80211_key_conf *keyconf,
-                               u8 sta_id)
+                                       struct iwl_rxon_context *ctx,
+                                       struct ieee80211_key_conf *keyconf,
+                                       u8 sta_id)
 {
        unsigned long flags;
        __le16 key_flags = 0;
@@ -851,12 +872,12 @@ static int iwl_set_wep_dynamic_key_info(struct iwl_priv *priv,
        if (keyconf->keylen == WEP_KEY_LEN_128)
                key_flags |= STA_KEY_FLG_KEY_SIZE_MSK;
 
-       if (sta_id == priv->hw_params.bcast_sta_id)
+       if (sta_id == ctx->bcast_sta_id)
                key_flags |= STA_KEY_MULTICAST_MSK;
 
        spin_lock_irqsave(&priv->sta_lock, flags);
 
-       priv->stations[sta_id].keyinfo.alg = keyconf->alg;
+       priv->stations[sta_id].keyinfo.cipher = keyconf->cipher;
        priv->stations[sta_id].keyinfo.keylen = keyconf->keylen;
        priv->stations[sta_id].keyinfo.keyidx = keyconf->keyidx;
 
@@ -887,8 +908,9 @@ static int iwl_set_wep_dynamic_key_info(struct iwl_priv *priv,
 }
 
 static int iwl_set_ccmp_dynamic_key_info(struct iwl_priv *priv,
-                                  struct ieee80211_key_conf *keyconf,
-                                  u8 sta_id)
+                                        struct iwl_rxon_context *ctx,
+                                        struct ieee80211_key_conf *keyconf,
+                                        u8 sta_id)
 {
        unsigned long flags;
        __le16 key_flags = 0;
@@ -900,13 +922,13 @@ static int iwl_set_ccmp_dynamic_key_info(struct iwl_priv *priv,
        key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
        key_flags &= ~STA_KEY_FLG_INVALID;
 
-       if (sta_id == priv->hw_params.bcast_sta_id)
+       if (sta_id == ctx->bcast_sta_id)
                key_flags |= STA_KEY_MULTICAST_MSK;
 
        keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
 
        spin_lock_irqsave(&priv->sta_lock, flags);
-       priv->stations[sta_id].keyinfo.alg = keyconf->alg;
+       priv->stations[sta_id].keyinfo.cipher = keyconf->cipher;
        priv->stations[sta_id].keyinfo.keylen = keyconf->keylen;
 
        memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key,
@@ -936,8 +958,9 @@ static int iwl_set_ccmp_dynamic_key_info(struct iwl_priv *priv,
 }
 
 static int iwl_set_tkip_dynamic_key_info(struct iwl_priv *priv,
-                                  struct ieee80211_key_conf *keyconf,
-                                  u8 sta_id)
+                                        struct iwl_rxon_context *ctx,
+                                        struct ieee80211_key_conf *keyconf,
+                                        u8 sta_id)
 {
        unsigned long flags;
        int ret = 0;
@@ -947,7 +970,7 @@ static int iwl_set_tkip_dynamic_key_info(struct iwl_priv *priv,
        key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
        key_flags &= ~STA_KEY_FLG_INVALID;
 
-       if (sta_id == priv->hw_params.bcast_sta_id)
+       if (sta_id == ctx->bcast_sta_id)
                key_flags |= STA_KEY_MULTICAST_MSK;
 
        keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
@@ -955,7 +978,7 @@ static int iwl_set_tkip_dynamic_key_info(struct iwl_priv *priv,
 
        spin_lock_irqsave(&priv->sta_lock, flags);
 
-       priv->stations[sta_id].keyinfo.alg = keyconf->alg;
+       priv->stations[sta_id].keyinfo.cipher = keyconf->cipher;
        priv->stations[sta_id].keyinfo.keylen = 16;
 
        if ((priv->stations[sta_id].sta.key.key_flags & STA_KEY_FLG_ENCRYPT_MSK)
@@ -982,8 +1005,9 @@ static int iwl_set_tkip_dynamic_key_info(struct iwl_priv *priv,
 }
 
 void iwl_update_tkip_key(struct iwl_priv *priv,
-                       struct ieee80211_key_conf *keyconf,
-                       struct ieee80211_sta *sta, u32 iv32, u16 *phase1key)
+                        struct iwl_rxon_context *ctx,
+                        struct ieee80211_key_conf *keyconf,
+                        struct ieee80211_sta *sta, u32 iv32, u16 *phase1key)
 {
        u8 sta_id;
        unsigned long flags;
@@ -995,7 +1019,7 @@ void iwl_update_tkip_key(struct iwl_priv *priv,
                return;
        }
 
-       sta_id = iwl_sta_id_or_broadcast(priv, sta);
+       sta_id = iwl_sta_id_or_broadcast(priv, ctx, sta);
        if (sta_id == IWL_INVALID_STATION)
                return;
 
@@ -1018,8 +1042,9 @@ void iwl_update_tkip_key(struct iwl_priv *priv,
 EXPORT_SYMBOL(iwl_update_tkip_key);
 
 int iwl_remove_dynamic_key(struct iwl_priv *priv,
-                               struct ieee80211_key_conf *keyconf,
-                               u8 sta_id)
+                          struct iwl_rxon_context *ctx,
+                          struct ieee80211_key_conf *keyconf,
+                          u8 sta_id)
 {
        unsigned long flags;
        u16 key_flags;
@@ -1028,7 +1053,7 @@ int iwl_remove_dynamic_key(struct iwl_priv *priv,
 
        lockdep_assert_held(&priv->mutex);
 
-       priv->key_mapping_key--;
+       ctx->key_mapping_keys--;
 
        spin_lock_irqsave(&priv->sta_lock, flags);
        key_flags = le16_to_cpu(priv->stations[sta_id].sta.key.key_flags);
@@ -1080,34 +1105,36 @@ int iwl_remove_dynamic_key(struct iwl_priv *priv,
 }
 EXPORT_SYMBOL(iwl_remove_dynamic_key);
 
-int iwl_set_dynamic_key(struct iwl_priv *priv,
-                               struct ieee80211_key_conf *keyconf, u8 sta_id)
+int iwl_set_dynamic_key(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
+                       struct ieee80211_key_conf *keyconf, u8 sta_id)
 {
        int ret;
 
        lockdep_assert_held(&priv->mutex);
 
-       priv->key_mapping_key++;
+       ctx->key_mapping_keys++;
        keyconf->hw_key_idx = HW_KEY_DYNAMIC;
 
-       switch (keyconf->alg) {
-       case ALG_CCMP:
-               ret = iwl_set_ccmp_dynamic_key_info(priv, keyconf, sta_id);
+       switch (keyconf->cipher) {
+       case WLAN_CIPHER_SUITE_CCMP:
+               ret = iwl_set_ccmp_dynamic_key_info(priv, ctx, keyconf, sta_id);
                break;
-       case ALG_TKIP:
-               ret = iwl_set_tkip_dynamic_key_info(priv, keyconf, sta_id);
+       case WLAN_CIPHER_SUITE_TKIP:
+               ret = iwl_set_tkip_dynamic_key_info(priv, ctx, keyconf, sta_id);
                break;
-       case ALG_WEP:
-               ret = iwl_set_wep_dynamic_key_info(priv, keyconf, sta_id);
+       case WLAN_CIPHER_SUITE_WEP40:
+       case WLAN_CIPHER_SUITE_WEP104:
+               ret = iwl_set_wep_dynamic_key_info(priv, ctx, keyconf, sta_id);
                break;
        default:
                IWL_ERR(priv,
-                       "Unknown alg: %s alg = %d\n", __func__, keyconf->alg);
+                       "Unknown alg: %s cipher = %x\n", __func__,
+                       keyconf->cipher);
                ret = -EINVAL;
        }
 
-       IWL_DEBUG_WEP(priv, "Set dynamic key: alg= %d len=%d idx=%d sta=%d ret=%d\n",
-                     keyconf->alg, keyconf->keylen, keyconf->keyidx,
+       IWL_DEBUG_WEP(priv, "Set dynamic key: cipher=%x len=%d idx=%d sta=%d ret=%d\n",
+                     keyconf->cipher, keyconf->keylen, keyconf->keyidx,
                      sta_id, ret);
 
        return ret;
@@ -1147,16 +1174,16 @@ static inline void iwl_dump_lq_cmd(struct iwl_priv *priv,
  * RXON flags are updated and when LQ command is updated.
  */
 static bool is_lq_table_valid(struct iwl_priv *priv,
+                             struct iwl_rxon_context *ctx,
                              struct iwl_link_quality_cmd *lq)
 {
        int i;
-       struct iwl_ht_config *ht_conf = &priv->current_ht_config;
 
-       if (ht_conf->is_ht)
+       if (ctx->ht.enabled)
                return true;
 
        IWL_DEBUG_INFO(priv, "Channel %u is not an HT channel\n",
-                      priv->active_rxon.channel);
+                      ctx->active.channel);
        for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) {
                if (le32_to_cpu(lq->rs_table[i].rate_n_flags) & RATE_MCS_HT_MSK) {
                        IWL_DEBUG_INFO(priv,
@@ -1178,7 +1205,7 @@ static bool is_lq_table_valid(struct iwl_priv *priv,
  * this case to clear the state indicating that station creation is in
  * progress.
  */
-int iwl_send_lq_cmd(struct iwl_priv *priv,
+int iwl_send_lq_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
                    struct iwl_link_quality_cmd *lq, u8 flags, bool init)
 {
        int ret = 0;
@@ -1197,7 +1224,7 @@ int iwl_send_lq_cmd(struct iwl_priv *priv,
        iwl_dump_lq_cmd(priv, lq);
        BUG_ON(init && (cmd.flags & CMD_ASYNC));
 
-       if (is_lq_table_valid(priv, lq))
+       if (is_lq_table_valid(priv, ctx, lq))
                ret = iwl_send_cmd(priv, &cmd);
        else
                ret = -EINVAL;
@@ -1223,14 +1250,15 @@ EXPORT_SYMBOL(iwl_send_lq_cmd);
  * and marks it driver active, so that it will be restored to the
  * device at the next best time.
  */
-int iwl_alloc_bcast_station(struct iwl_priv *priv, bool init_lq)
+int iwl_alloc_bcast_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
+                           bool init_lq)
 {
        struct iwl_link_quality_cmd *link_cmd;
        unsigned long flags;
        u8 sta_id;
 
        spin_lock_irqsave(&priv->sta_lock, flags);
-       sta_id = iwl_prep_station(priv, iwl_bcast_addr, false, NULL);
+       sta_id = iwl_prep_station(priv, ctx, iwl_bcast_addr, false, NULL);
        if (sta_id == IWL_INVALID_STATION) {
                IWL_ERR(priv, "Unable to prepare broadcast station\n");
                spin_unlock_irqrestore(&priv->sta_lock, flags);
@@ -1265,11 +1293,12 @@ EXPORT_SYMBOL_GPL(iwl_alloc_bcast_station);
  * Only used by iwlagn. Placed here to have all bcast station management
  * code together.
  */
-int iwl_update_bcast_station(struct iwl_priv *priv)
+static int iwl_update_bcast_station(struct iwl_priv *priv,
+                                   struct iwl_rxon_context *ctx)
 {
        unsigned long flags;
        struct iwl_link_quality_cmd *link_cmd;
-       u8 sta_id = priv->hw_params.bcast_sta_id;
+       u8 sta_id = ctx->bcast_sta_id;
 
        link_cmd = iwl_sta_alloc_lq(priv, sta_id);
        if (!link_cmd) {
@@ -1287,9 +1316,23 @@ int iwl_update_bcast_station(struct iwl_priv *priv)
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(iwl_update_bcast_station);
 
-void iwl_dealloc_bcast_station(struct iwl_priv *priv)
+int iwl_update_bcast_stations(struct iwl_priv *priv)
+{
+       struct iwl_rxon_context *ctx;
+       int ret = 0;
+
+       for_each_context(priv, ctx) {
+               ret = iwl_update_bcast_station(priv, ctx);
+               if (ret)
+                       break;
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(iwl_update_bcast_stations);
+
+void iwl_dealloc_bcast_stations(struct iwl_priv *priv)
 {
        unsigned long flags;
        int i;
@@ -1307,7 +1350,7 @@ void iwl_dealloc_bcast_station(struct iwl_priv *priv)
        }
        spin_unlock_irqrestore(&priv->sta_lock, flags);
 }
-EXPORT_SYMBOL_GPL(iwl_dealloc_bcast_station);
+EXPORT_SYMBOL_GPL(iwl_dealloc_bcast_stations);
 
 /**
  * iwl_sta_tx_modify_enable_tid - Enable Tx for this TID in station table
index d38a350ba0bd46a7d98e09810346243dea2be528..56bad3f60d8131c74d3874472370e1ca0d241bdb 100644 (file)
 
 
 int iwl_remove_default_wep_key(struct iwl_priv *priv,
+                              struct iwl_rxon_context *ctx,
                               struct ieee80211_key_conf *key);
 int iwl_set_default_wep_key(struct iwl_priv *priv,
+                           struct iwl_rxon_context *ctx,
                            struct ieee80211_key_conf *key);
-int iwl_restore_default_wep_keys(struct iwl_priv *priv);
-int iwl_set_dynamic_key(struct iwl_priv *priv,
+int iwl_restore_default_wep_keys(struct iwl_priv *priv,
+                                struct iwl_rxon_context *ctx);
+int iwl_set_dynamic_key(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
                        struct ieee80211_key_conf *key, u8 sta_id);
-int iwl_remove_dynamic_key(struct iwl_priv *priv,
+int iwl_remove_dynamic_key(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
                           struct ieee80211_key_conf *key, u8 sta_id);
 void iwl_update_tkip_key(struct iwl_priv *priv,
-                       struct ieee80211_key_conf *keyconf,
-                       struct ieee80211_sta *sta, u32 iv32, u16 *phase1key);
-
-void iwl_restore_stations(struct iwl_priv *priv);
-void iwl_clear_ucode_stations(struct iwl_priv *priv);
-int iwl_alloc_bcast_station(struct iwl_priv *priv, bool init_lq);
-void iwl_dealloc_bcast_station(struct iwl_priv *priv);
-int iwl_update_bcast_station(struct iwl_priv *priv);
+                        struct iwl_rxon_context *ctx,
+                        struct ieee80211_key_conf *keyconf,
+                        struct ieee80211_sta *sta, u32 iv32, u16 *phase1key);
+
+void iwl_restore_stations(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
+void iwl_clear_ucode_stations(struct iwl_priv *priv,
+                             struct iwl_rxon_context *ctx);
+int iwl_alloc_bcast_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
+                           bool init_lq);
+void iwl_dealloc_bcast_stations(struct iwl_priv *priv);
+int iwl_update_bcast_stations(struct iwl_priv *priv);
 int iwl_get_free_ucode_key_index(struct iwl_priv *priv);
 int iwl_send_add_sta(struct iwl_priv *priv,
                     struct iwl_addsta_cmd *sta, u8 flags);
-int iwl_add_bssid_station(struct iwl_priv *priv, const u8 *addr, bool init_rs,
-                         u8 *sta_id_r);
-int iwl_add_station_common(struct iwl_priv *priv, const u8 *addr,
-                                 bool is_ap,
-                                 struct ieee80211_sta_ht_cap *ht_info,
-                                 u8 *sta_id_r);
+int iwl_add_bssid_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
+                         const u8 *addr, bool init_rs, u8 *sta_id_r);
+int iwl_add_station_common(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
+                          const u8 *addr, bool is_ap,
+                          struct ieee80211_sta *sta, u8 *sta_id_r);
 int iwl_remove_station(struct iwl_priv *priv, const u8 sta_id,
                       const u8 *addr);
 int iwl_mac_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
@@ -94,20 +99,25 @@ void iwl_sta_modify_sleep_tx_count(struct iwl_priv *priv, int sta_id, int cnt);
 static inline void iwl_clear_driver_stations(struct iwl_priv *priv)
 {
        unsigned long flags;
+       struct iwl_rxon_context *ctx;
 
        spin_lock_irqsave(&priv->sta_lock, flags);
        memset(priv->stations, 0, sizeof(priv->stations));
        priv->num_stations = 0;
 
-       /*
-        * Remove all key information that is not stored as part of station
-        * information since mac80211 may not have had a
-        * chance to remove all the keys. When device is reconfigured by
-        * mac80211 after an error all keys will be reconfigured.
-        */
        priv->ucode_key_table = 0;
-       priv->key_mapping_key = 0;
-       memset(priv->wep_keys, 0, sizeof(priv->wep_keys));
+
+       for_each_context(priv, ctx) {
+               /*
+                * Remove all key information that is not stored as part
+                * of station information since mac80211 may not have had
+                * a chance to remove all the keys. When device is
+                * reconfigured by mac80211 after an error all keys will
+                * be reconfigured.
+                */
+               memset(ctx->wep_keys, 0, sizeof(ctx->wep_keys));
+               ctx->key_mapping_keys = 0;
+       }
 
        spin_unlock_irqrestore(&priv->sta_lock, flags);
 }
@@ -123,6 +133,7 @@ static inline int iwl_sta_id(struct ieee80211_sta *sta)
 /**
  * iwl_sta_id_or_broadcast - return sta_id or broadcast sta
  * @priv: iwl priv
+ * @context: the current context
  * @sta: mac80211 station
  *
  * In certain circumstances mac80211 passes a station pointer
@@ -131,12 +142,13 @@ static inline int iwl_sta_id(struct ieee80211_sta *sta)
  * inline wraps that pattern.
  */
 static inline int iwl_sta_id_or_broadcast(struct iwl_priv *priv,
+                                         struct iwl_rxon_context *context,
                                          struct ieee80211_sta *sta)
 {
        int sta_id;
 
        if (!sta)
-               return priv->hw_params.bcast_sta_id;
+               return context->bcast_sta_id;
 
        sta_id = iwl_sta_id(sta);
 
index a81989c0698336dab5ebd0127ed01b93de698e57..347d3dc6a01549632227ae8f1acd5ae84a1c50e0 100644 (file)
@@ -134,7 +134,7 @@ EXPORT_SYMBOL(iwl_tx_queue_free);
  */
 void iwl_cmd_queue_free(struct iwl_priv *priv)
 {
-       struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM];
+       struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue];
        struct iwl_queue *q = &txq->q;
        struct device *dev = &priv->pci_dev->dev;
        int i;
@@ -271,7 +271,7 @@ static int iwl_tx_queue_alloc(struct iwl_priv *priv,
 
        /* Driver private data, only for Tx (not command) queues,
         * not shared with device. */
-       if (id != IWL_CMD_QUEUE_NUM) {
+       if (id != priv->cmd_queue) {
                txq->txb = kzalloc(sizeof(txq->txb[0]) *
                                   TFD_QUEUE_SIZE_MAX, GFP_KERNEL);
                if (!txq->txb) {
@@ -314,13 +314,13 @@ int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
 
        /*
         * Alloc buffer array for commands (Tx or other types of commands).
-        * For the command queue (#4), allocate command space + one big
+        * For the command queue (#4/#9), allocate command space + one big
         * command for scan, since scan command is very huge; the system will
         * not have two scans at the same time, so only one is needed.
         * For normal Tx queues (all other queues), no super-size command
         * space is needed.
         */
-       if (txq_id == IWL_CMD_QUEUE_NUM)
+       if (txq_id == priv->cmd_queue)
                actual_slots++;
 
        txq->meta = kzalloc(sizeof(struct iwl_cmd_meta) * actual_slots,
@@ -355,7 +355,7 @@ int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
         * need an swq_id so don't set one to catch errors, all others can
         * be set up to the identity mapping.
         */
-       if (txq_id != IWL_CMD_QUEUE_NUM)
+       if (txq_id != priv->cmd_queue)
                txq->swq_id = txq_id;
 
        /* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise
@@ -385,7 +385,7 @@ void iwl_tx_queue_reset(struct iwl_priv *priv, struct iwl_tx_queue *txq,
 {
        int actual_slots = slots_num;
 
-       if (txq_id == IWL_CMD_QUEUE_NUM)
+       if (txq_id == priv->cmd_queue)
                actual_slots++;
 
        memset(txq->meta, 0, sizeof(struct iwl_cmd_meta) * actual_slots);
@@ -413,7 +413,7 @@ EXPORT_SYMBOL(iwl_tx_queue_reset);
  */
 int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
 {
-       struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM];
+       struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue];
        struct iwl_queue *q = &txq->q;
        struct iwl_device_cmd *out_cmd;
        struct iwl_cmd_meta *out_meta;
@@ -422,6 +422,7 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
        int len;
        u32 idx;
        u16 fix_size;
+       bool is_ct_kill = false;
 
        cmd->len = priv->cfg->ops->utils->get_hcmd_size(cmd->id, cmd->len);
        fix_size = (u16)(cmd->len + sizeof(out_cmd->hdr));
@@ -443,9 +444,11 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
 
        if (iwl_queue_space(q) < ((cmd->flags & CMD_ASYNC) ? 2 : 1)) {
                IWL_ERR(priv, "No space in command queue\n");
-               if (iwl_within_ct_kill_margin(priv))
-                       iwl_tt_enter_ct_kill(priv);
-               else {
+               if (priv->cfg->ops->lib->tt_ops.ct_kill_check) {
+                       is_ct_kill =
+                               priv->cfg->ops->lib->tt_ops.ct_kill_check(priv);
+               }
+               if (!is_ct_kill) {
                        IWL_ERR(priv, "Restarting adapter due to queue full\n");
                        queue_work(priv->workqueue, &priv->restart);
                }
@@ -480,7 +483,7 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
         * information */
 
        out_cmd->hdr.flags = 0;
-       out_cmd->hdr.sequence = cpu_to_le16(QUEUE_TO_SEQ(IWL_CMD_QUEUE_NUM) |
+       out_cmd->hdr.sequence = cpu_to_le16(QUEUE_TO_SEQ(priv->cmd_queue) |
                        INDEX_TO_SEQ(q->write_ptr));
        if (cmd->flags & CMD_SIZE_HUGE)
                out_cmd->hdr.sequence |= SEQ_HUGE_FRAME;
@@ -497,15 +500,15 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
                                get_cmd_string(out_cmd->hdr.cmd),
                                out_cmd->hdr.cmd,
                                le16_to_cpu(out_cmd->hdr.sequence), fix_size,
-                               q->write_ptr, idx, IWL_CMD_QUEUE_NUM);
-                               break;
+                               q->write_ptr, idx, priv->cmd_queue);
+               break;
        default:
                IWL_DEBUG_HC(priv, "Sending command %s (#%x), seq: 0x%04X, "
                                "%d bytes at %d[%d]:%d\n",
                                get_cmd_string(out_cmd->hdr.cmd),
                                out_cmd->hdr.cmd,
                                le16_to_cpu(out_cmd->hdr.sequence), fix_size,
-                               q->write_ptr, idx, IWL_CMD_QUEUE_NUM);
+                               q->write_ptr, idx, priv->cmd_queue);
        }
 #endif
        txq->need_update = 1;
@@ -584,16 +587,16 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
        bool huge = !!(pkt->hdr.sequence & SEQ_HUGE_FRAME);
        struct iwl_device_cmd *cmd;
        struct iwl_cmd_meta *meta;
-       struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM];
+       struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue];
 
        /* If a Tx command is being handled and it isn't in the actual
         * command queue then there a command routing bug has been introduced
         * in the queue management code. */
-       if (WARN(txq_id != IWL_CMD_QUEUE_NUM,
-                "wrong command queue %d, sequence 0x%X readp=%d writep=%d\n",
-                 txq_id, sequence,
-                 priv->txq[IWL_CMD_QUEUE_NUM].q.read_ptr,
-                 priv->txq[IWL_CMD_QUEUE_NUM].q.write_ptr)) {
+       if (WARN(txq_id != priv->cmd_queue,
+                "wrong command queue %d (should be %d), sequence 0x%X readp=%d writep=%d\n",
+                 txq_id, priv->cmd_queue, sequence,
+                 priv->txq[priv->cmd_queue].q.read_ptr,
+                 priv->txq[priv->cmd_queue].q.write_ptr)) {
                iwl_print_hex_error(priv, pkt, 32);
                return;
        }
index 59a308b02f95fdc077a84a7d12d71db7451b1816..68e624afb9879d28554e522e8857137aea5ff212 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/pci.h>
+#include <linux/pci-aspm.h>
 #include <linux/slab.h>
 #include <linux/dma-mapping.h>
 #include <linux/delay.h>
@@ -143,7 +144,7 @@ static int iwl3945_set_ccmp_dynamic_key_info(struct iwl_priv *priv,
        key_flags |= (STA_KEY_FLG_CCMP | STA_KEY_FLG_MAP_KEY_MSK);
        key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
 
-       if (sta_id == priv->hw_params.bcast_sta_id)
+       if (sta_id == priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id)
                key_flags |= STA_KEY_MULTICAST_MSK;
 
        keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
@@ -151,7 +152,7 @@ static int iwl3945_set_ccmp_dynamic_key_info(struct iwl_priv *priv,
        key_flags &= ~STA_KEY_FLG_INVALID;
 
        spin_lock_irqsave(&priv->sta_lock, flags);
-       priv->stations[sta_id].keyinfo.alg = keyconf->alg;
+       priv->stations[sta_id].keyinfo.cipher = keyconf->cipher;
        priv->stations[sta_id].keyinfo.keylen = keyconf->keylen;
        memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key,
               keyconf->keylen);
@@ -222,23 +223,25 @@ static int iwl3945_set_dynamic_key(struct iwl_priv *priv,
 
        keyconf->hw_key_idx = HW_KEY_DYNAMIC;
 
-       switch (keyconf->alg) {
-       case ALG_CCMP:
+       switch (keyconf->cipher) {
+       case WLAN_CIPHER_SUITE_CCMP:
                ret = iwl3945_set_ccmp_dynamic_key_info(priv, keyconf, sta_id);
                break;
-       case ALG_TKIP:
+       case WLAN_CIPHER_SUITE_TKIP:
                ret = iwl3945_set_tkip_dynamic_key_info(priv, keyconf, sta_id);
                break;
-       case ALG_WEP:
+       case WLAN_CIPHER_SUITE_WEP40:
+       case WLAN_CIPHER_SUITE_WEP104:
                ret = iwl3945_set_wep_dynamic_key_info(priv, keyconf, sta_id);
                break;
        default:
-               IWL_ERR(priv, "Unknown alg: %s alg = %d\n", __func__, keyconf->alg);
+               IWL_ERR(priv, "Unknown alg: %s alg=%x\n", __func__,
+                       keyconf->cipher);
                ret = -EINVAL;
        }
 
-       IWL_DEBUG_WEP(priv, "Set dynamic key: alg= %d len=%d idx=%d sta=%d ret=%d\n",
-                     keyconf->alg, keyconf->keylen, keyconf->keyidx,
+       IWL_DEBUG_WEP(priv, "Set dynamic key: alg=%x len=%d idx=%d sta=%d ret=%d\n",
+                     keyconf->cipher, keyconf->keylen, keyconf->keyidx,
                      sta_id, ret);
 
        return ret;
@@ -254,10 +257,11 @@ static int iwl3945_remove_static_key(struct iwl_priv *priv)
 static int iwl3945_set_static_key(struct iwl_priv *priv,
                                struct ieee80211_key_conf *key)
 {
-       if (key->alg == ALG_WEP)
+       if (key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
+           key->cipher == WLAN_CIPHER_SUITE_WEP104)
                return -EOPNOTSUPP;
 
-       IWL_ERR(priv, "Static key invalid: alg %d\n", key->alg);
+       IWL_ERR(priv, "Static key invalid: cipher %x\n", key->cipher);
        return -EINVAL;
 }
 
@@ -313,7 +317,7 @@ unsigned int iwl3945_fill_beacon_frame(struct iwl_priv *priv,
                                int left)
 {
 
-       if (!iwl_is_associated(priv) || !priv->ibss_beacon)
+       if (!iwl_is_associated(priv, IWL_RXON_CTX_BSS) || !priv->ibss_beacon)
                return 0;
 
        if (priv->ibss_beacon->len > left)
@@ -339,7 +343,8 @@ static int iwl3945_send_beacon_cmd(struct iwl_priv *priv)
                return -ENOMEM;
        }
 
-       rate = iwl_rate_get_lowest_plcp(priv);
+       rate = iwl_rate_get_lowest_plcp(priv,
+                               &priv->contexts[IWL_RXON_CTX_BSS]);
 
        frame_size = iwl3945_hw_get_beacon_cmd(priv, frame, rate);
 
@@ -369,23 +374,25 @@ static void iwl3945_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
        struct iwl3945_tx_cmd *tx_cmd = (struct iwl3945_tx_cmd *)cmd->cmd.payload;
        struct iwl_hw_key *keyinfo = &priv->stations[sta_id].keyinfo;
 
-       switch (keyinfo->alg) {
-       case ALG_CCMP:
+       tx_cmd->sec_ctl = 0;
+
+       switch (keyinfo->cipher) {
+       case WLAN_CIPHER_SUITE_CCMP:
                tx_cmd->sec_ctl = TX_CMD_SEC_CCM;
                memcpy(tx_cmd->key, keyinfo->key, keyinfo->keylen);
                IWL_DEBUG_TX(priv, "tx_cmd with AES hwcrypto\n");
                break;
 
-       case ALG_TKIP:
+       case WLAN_CIPHER_SUITE_TKIP:
                break;
 
-       case ALG_WEP:
-               tx_cmd->sec_ctl = TX_CMD_SEC_WEP |
+       case WLAN_CIPHER_SUITE_WEP104:
+               tx_cmd->sec_ctl |= TX_CMD_SEC_KEY128;
+               /* fall through */
+       case WLAN_CIPHER_SUITE_WEP40:
+               tx_cmd->sec_ctl |= TX_CMD_SEC_WEP |
                    (info->control.hw_key->hw_key_idx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT;
 
-               if (keyinfo->keylen == 13)
-                       tx_cmd->sec_ctl |= TX_CMD_SEC_KEY128;
-
                memcpy(&tx_cmd->key[3], keyinfo->key, keyinfo->keylen);
 
                IWL_DEBUG_TX(priv, "Configuring packet for WEP encryption "
@@ -393,7 +400,7 @@ static void iwl3945_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
                break;
 
        default:
-               IWL_ERR(priv, "Unknown encode alg %d\n", keyinfo->alg);
+               IWL_ERR(priv, "Unknown encode cipher %x\n", keyinfo->cipher);
                break;
        }
 }
@@ -506,7 +513,9 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
        hdr_len = ieee80211_hdrlen(fc);
 
        /* Find index into station table for destination station */
-       sta_id = iwl_sta_id_or_broadcast(priv, info->control.sta);
+       sta_id = iwl_sta_id_or_broadcast(
+                       priv, &priv->contexts[IWL_RXON_CTX_BSS],
+                       info->control.sta);
        if (sta_id == IWL_INVALID_STATION) {
                IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n",
                               hdr->addr1);
@@ -536,6 +545,7 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
        /* Set up driver data for this TFD */
        memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl_tx_info));
        txq->txb[q->write_ptr].skb = skb;
+       txq->txb[q->write_ptr].ctx = &priv->contexts[IWL_RXON_CTX_BSS];
 
        /* Init first empty entry in queue's array of Tx/cmd buffers */
        out_cmd = txq->cmd[idx];
@@ -677,11 +687,12 @@ static int iwl3945_get_measurement(struct iwl_priv *priv,
        int rc;
        int spectrum_resp_status;
        int duration = le16_to_cpu(params->duration);
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
 
-       if (iwl_is_associated(priv))
+       if (iwl_is_associated(priv, IWL_RXON_CTX_BSS))
                add_time = iwl_usecs_to_beacons(priv,
                        le64_to_cpu(params->start_time) - priv->_3945.last_tsf,
-                       le16_to_cpu(priv->rxon_timing.beacon_interval));
+                       le16_to_cpu(ctx->timing.beacon_interval));
 
        memset(&spectrum, 0, sizeof(spectrum));
 
@@ -692,18 +703,18 @@ static int iwl3945_get_measurement(struct iwl_priv *priv,
        cmd.len = sizeof(spectrum);
        spectrum.len = cpu_to_le16(cmd.len - sizeof(spectrum.len));
 
-       if (iwl_is_associated(priv))
+       if (iwl_is_associated(priv, IWL_RXON_CTX_BSS))
                spectrum.start_time =
                        iwl_add_beacon_time(priv,
                                priv->_3945.last_beacon_time, add_time,
-                               le16_to_cpu(priv->rxon_timing.beacon_interval));
+                               le16_to_cpu(ctx->timing.beacon_interval));
        else
                spectrum.start_time = 0;
 
        spectrum.channels[0].duration = cpu_to_le32(duration * TIME_UNIT);
        spectrum.channels[0].channel = params->channel;
        spectrum.channels[0].type = type;
-       if (priv->active_rxon.flags & RXON_FLG_BAND_24G_MSK)
+       if (ctx->active.flags & RXON_FLG_BAND_24G_MSK)
                spectrum.flags |= RXON_FLG_BAND_24G_MSK |
                    RXON_FLG_AUTO_DETECT_MSK | RXON_FLG_TGG_PROTECT_MSK;
 
@@ -792,7 +803,8 @@ static void iwl3945_bg_beacon_update(struct work_struct *work)
        struct sk_buff *beacon;
 
        /* Pull updated AP beacon from mac80211. will fail if not in AP mode */
-       beacon = ieee80211_beacon_get(priv->hw, priv->vif);
+       beacon = ieee80211_beacon_get(priv->hw,
+                       priv->contexts[IWL_RXON_CTX_BSS].vif);
 
        if (!beacon) {
                IWL_ERR(priv, "update beacon failed\n");
@@ -813,9 +825,9 @@ static void iwl3945_bg_beacon_update(struct work_struct *work)
 static void iwl3945_rx_beacon_notif(struct iwl_priv *priv,
                                struct iwl_rx_mem_buffer *rxb)
 {
-#ifdef CONFIG_IWLWIFI_DEBUG
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
        struct iwl3945_beacon_notif *beacon = &(pkt->u.beacon_status);
+#ifdef CONFIG_IWLWIFI_DEBUG
        u8 rate = beacon->beacon_notify_hdr.rate;
 
        IWL_DEBUG_RX(priv, "beacon status %x retries %d iss %d "
@@ -827,6 +839,8 @@ static void iwl3945_rx_beacon_notif(struct iwl_priv *priv,
                le32_to_cpu(beacon->low_tsf), rate);
 #endif
 
+       priv->ibss_manager = le32_to_cpu(beacon->ibss_mgr_status);
+
        if ((priv->iw_mode == NL80211_IFTYPE_AP) &&
            (!test_bit(STATUS_EXIT_PENDING, &priv->status)))
                queue_work(priv->workqueue, &priv->beacon_update);
@@ -2460,6 +2474,7 @@ static void iwl3945_alive_start(struct iwl_priv *priv)
 {
        int thermal_spin = 0;
        u32 rfkill;
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
 
        IWL_DEBUG_INFO(priv, "Runtime Alive received.\n");
 
@@ -2517,22 +2532,22 @@ static void iwl3945_alive_start(struct iwl_priv *priv)
 
        iwl_power_update_mode(priv, true);
 
-       if (iwl_is_associated(priv)) {
+       if (iwl_is_associated(priv, IWL_RXON_CTX_BSS)) {
                struct iwl3945_rxon_cmd *active_rxon =
-                               (struct iwl3945_rxon_cmd *)(&priv->active_rxon);
+                               (struct iwl3945_rxon_cmd *)(&ctx->active);
 
-               priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
+               ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK;
                active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
        } else {
                /* Initialize our rx_config data */
-               iwl_connection_init_rx_config(priv, NULL);
+               iwl_connection_init_rx_config(priv, ctx);
        }
 
        /* Configure Bluetooth device coexistence support */
        priv->cfg->ops->hcmd->send_bt_config(priv);
 
        /* Configure the adapter for unassociated operation */
-       iwlcore_commit_rxon(priv);
+       iwlcore_commit_rxon(priv, ctx);
 
        iwl3945_reg_txpower_periodic(priv);
 
@@ -2563,9 +2578,14 @@ static void __iwl3945_down(struct iwl_priv *priv)
        if (!exit_pending)
                set_bit(STATUS_EXIT_PENDING, &priv->status);
 
+       /* Stop TX queues watchdog. We need to have STATUS_EXIT_PENDING bit set
+        * to prevent rearm timer */
+       if (priv->cfg->ops->lib->recover_from_tx_stall)
+               del_timer_sync(&priv->monitor_recover);
+
        /* Station information will now be cleared in device */
-       iwl_clear_ucode_stations(priv);
-       iwl_dealloc_bcast_station(priv);
+       iwl_clear_ucode_stations(priv, NULL);
+       iwl_dealloc_bcast_stations(priv);
        iwl_clear_driver_stations(priv);
 
        /* Unblock any waiting calls */
@@ -2647,7 +2667,8 @@ static int __iwl3945_up(struct iwl_priv *priv)
 {
        int rc, i;
 
-       rc = iwl_alloc_bcast_station(priv, false);
+       rc = iwl_alloc_bcast_station(priv, &priv->contexts[IWL_RXON_CTX_BSS],
+                                    false);
        if (rc)
                return rc;
 
@@ -2870,7 +2891,7 @@ void iwl3945_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
        scan->quiet_plcp_th = IWL_PLCP_QUIET_THRESH;
        scan->quiet_time = IWL_ACTIVE_QUIET_TIME;
 
-       if (iwl_is_associated(priv)) {
+       if (iwl_is_associated(priv, IWL_RXON_CTX_BSS)) {
                u16 interval = 0;
                u32 extra;
                u32 suspend_time = 100;
@@ -2931,7 +2952,7 @@ void iwl3945_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
        /* We don't build a direct scan probe request; the uCode will do
         * that based on the direct_mask added to each channel entry */
        scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK;
-       scan->tx_cmd.sta_id = priv->hw_params.bcast_sta_id;
+       scan->tx_cmd.sta_id = priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id;
        scan->tx_cmd.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
 
        /* flags + rate selection */
@@ -3029,8 +3050,10 @@ static void iwl3945_bg_restart(struct work_struct *data)
                return;
 
        if (test_and_clear_bit(STATUS_FW_ERROR, &priv->status)) {
+               struct iwl_rxon_context *ctx;
                mutex_lock(&priv->mutex);
-               priv->vif = NULL;
+               for_each_context(priv, ctx)
+                       ctx->vif = NULL;
                priv->is_open = 0;
                mutex_unlock(&priv->mutex);
                iwl3945_down(priv);
@@ -3064,6 +3087,7 @@ void iwl3945_post_associate(struct iwl_priv *priv, struct ieee80211_vif *vif)
 {
        int rc = 0;
        struct ieee80211_conf *conf = NULL;
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
 
        if (!vif || !priv->is_open)
                return;
@@ -3074,7 +3098,7 @@ void iwl3945_post_associate(struct iwl_priv *priv, struct ieee80211_vif *vif)
        }
 
        IWL_DEBUG_ASSOC(priv, "Associated as %d to: %pM\n",
-                       vif->bss_conf.aid, priv->active_rxon.bssid_addr);
+                       vif->bss_conf.aid, ctx->active.bssid_addr);
 
        if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return;
@@ -3083,37 +3107,34 @@ void iwl3945_post_associate(struct iwl_priv *priv, struct ieee80211_vif *vif)
 
        conf = ieee80211_get_hw_conf(priv->hw);
 
-       priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-       iwlcore_commit_rxon(priv);
+       ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+       iwlcore_commit_rxon(priv, ctx);
 
-       memset(&priv->rxon_timing, 0, sizeof(struct iwl_rxon_time_cmd));
-       iwl_setup_rxon_timing(priv, vif);
-       rc = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING,
-                             sizeof(priv->rxon_timing), &priv->rxon_timing);
+       rc = iwl_send_rxon_timing(priv, ctx);
        if (rc)
                IWL_WARN(priv, "REPLY_RXON_TIMING failed - "
                            "Attempting to continue.\n");
 
-       priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
+       ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK;
 
-       priv->staging_rxon.assoc_id = cpu_to_le16(vif->bss_conf.aid);
+       ctx->staging.assoc_id = cpu_to_le16(vif->bss_conf.aid);
 
        IWL_DEBUG_ASSOC(priv, "assoc id %d beacon interval %d\n",
                        vif->bss_conf.aid, vif->bss_conf.beacon_int);
 
        if (vif->bss_conf.use_short_preamble)
-               priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
+               ctx->staging.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
        else
-               priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
+               ctx->staging.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
 
-       if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) {
+       if (ctx->staging.flags & RXON_FLG_BAND_24G_MSK) {
                if (vif->bss_conf.use_short_slot)
-                       priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
+                       ctx->staging.flags |= RXON_FLG_SHORT_SLOT_MSK;
                else
-                       priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
+                       ctx->staging.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
        }
 
-       iwlcore_commit_rxon(priv);
+       iwlcore_commit_rxon(priv, ctx);
 
        switch (vif->type) {
        case NL80211_IFTYPE_STATION:
@@ -3250,48 +3271,45 @@ static int iwl3945_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 
 void iwl3945_config_ap(struct iwl_priv *priv, struct ieee80211_vif *vif)
 {
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
        int rc = 0;
 
        if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return;
 
        /* The following should be done only at AP bring up */
-       if (!(iwl_is_associated(priv))) {
+       if (!(iwl_is_associated(priv, IWL_RXON_CTX_BSS))) {
 
                /* RXON - unassoc (to set timing command) */
-               priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-               iwlcore_commit_rxon(priv);
+               ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+               iwlcore_commit_rxon(priv, ctx);
 
                /* RXON Timing */
-               memset(&priv->rxon_timing, 0, sizeof(struct iwl_rxon_time_cmd));
-               iwl_setup_rxon_timing(priv, vif);
-               rc = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING,
-                                     sizeof(priv->rxon_timing),
-                                     &priv->rxon_timing);
+               rc = iwl_send_rxon_timing(priv, ctx);
                if (rc)
                        IWL_WARN(priv, "REPLY_RXON_TIMING failed - "
                                        "Attempting to continue.\n");
 
-               priv->staging_rxon.assoc_id = 0;
+               ctx->staging.assoc_id = 0;
 
                if (vif->bss_conf.use_short_preamble)
-                       priv->staging_rxon.flags |=
+                       ctx->staging.flags |=
                                RXON_FLG_SHORT_PREAMBLE_MSK;
                else
-                       priv->staging_rxon.flags &=
+                       ctx->staging.flags &=
                                ~RXON_FLG_SHORT_PREAMBLE_MSK;
 
-               if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) {
+               if (ctx->staging.flags & RXON_FLG_BAND_24G_MSK) {
                        if (vif->bss_conf.use_short_slot)
-                               priv->staging_rxon.flags |=
+                               ctx->staging.flags |=
                                        RXON_FLG_SHORT_SLOT_MSK;
                        else
-                               priv->staging_rxon.flags &=
+                               ctx->staging.flags &=
                                        ~RXON_FLG_SHORT_SLOT_MSK;
                }
                /* restore RXON assoc */
-               priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
-               iwlcore_commit_rxon(priv);
+               ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK;
+               iwlcore_commit_rxon(priv, ctx);
        }
        iwl3945_send_beacon_cmd(priv);
 
@@ -3317,10 +3335,11 @@ static int iwl3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
                return -EOPNOTSUPP;
        }
 
-       static_key = !iwl_is_associated(priv);
+       static_key = !iwl_is_associated(priv, IWL_RXON_CTX_BSS);
 
        if (!static_key) {
-               sta_id = iwl_sta_id_or_broadcast(priv, sta);
+               sta_id = iwl_sta_id_or_broadcast(
+                               priv, &priv->contexts[IWL_RXON_CTX_BSS], sta);
                if (sta_id == IWL_INVALID_STATION)
                        return -EINVAL;
        }
@@ -3371,8 +3390,8 @@ static int iwl3945_mac_sta_add(struct ieee80211_hw *hw,
        sta_priv->common.sta_id = IWL_INVALID_STATION;
 
 
-       ret = iwl_add_station_common(priv, sta->addr, is_ap, &sta->ht_cap,
-                                    &sta_id);
+       ret = iwl_add_station_common(priv, &priv->contexts[IWL_RXON_CTX_BSS],
+                                    sta->addr, is_ap, sta, &sta_id);
        if (ret) {
                IWL_ERR(priv, "Unable to add station %pM (%d)\n",
                        sta->addr, ret);
@@ -3399,6 +3418,7 @@ static void iwl3945_configure_filter(struct ieee80211_hw *hw,
 {
        struct iwl_priv *priv = hw->priv;
        __le32 filter_or = 0, filter_nand = 0;
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
 
 #define CHK(test, flag)        do { \
        if (*total_flags & (test))              \
@@ -3418,8 +3438,8 @@ static void iwl3945_configure_filter(struct ieee80211_hw *hw,
 
        mutex_lock(&priv->mutex);
 
-       priv->staging_rxon.filter_flags &= ~filter_nand;
-       priv->staging_rxon.filter_flags |= filter_or;
+       ctx->staging.filter_flags &= ~filter_nand;
+       ctx->staging.filter_flags |= filter_or;
 
        /*
         * Committing directly here breaks for some reason,
@@ -3533,8 +3553,9 @@ static ssize_t show_flags(struct device *d,
                          struct device_attribute *attr, char *buf)
 {
        struct iwl_priv *priv = dev_get_drvdata(d);
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
 
-       return sprintf(buf, "0x%04X\n", priv->active_rxon.flags);
+       return sprintf(buf, "0x%04X\n", ctx->active.flags);
 }
 
 static ssize_t store_flags(struct device *d,
@@ -3543,17 +3564,18 @@ static ssize_t store_flags(struct device *d,
 {
        struct iwl_priv *priv = dev_get_drvdata(d);
        u32 flags = simple_strtoul(buf, NULL, 0);
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
 
        mutex_lock(&priv->mutex);
-       if (le32_to_cpu(priv->staging_rxon.flags) != flags) {
+       if (le32_to_cpu(ctx->staging.flags) != flags) {
                /* Cancel any currently running scans... */
                if (iwl_scan_cancel_timeout(priv, 100))
                        IWL_WARN(priv, "Could not cancel scan.\n");
                else {
                        IWL_DEBUG_INFO(priv, "Committing rxon.flags = 0x%04X\n",
                                       flags);
-                       priv->staging_rxon.flags = cpu_to_le32(flags);
-                       iwlcore_commit_rxon(priv);
+                       ctx->staging.flags = cpu_to_le32(flags);
+                       iwlcore_commit_rxon(priv, ctx);
                }
        }
        mutex_unlock(&priv->mutex);
@@ -3567,9 +3589,10 @@ static ssize_t show_filter_flags(struct device *d,
                                 struct device_attribute *attr, char *buf)
 {
        struct iwl_priv *priv = dev_get_drvdata(d);
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
 
        return sprintf(buf, "0x%04X\n",
-               le32_to_cpu(priv->active_rxon.filter_flags));
+               le32_to_cpu(ctx->active.filter_flags));
 }
 
 static ssize_t store_filter_flags(struct device *d,
@@ -3577,19 +3600,20 @@ static ssize_t store_filter_flags(struct device *d,
                                  const char *buf, size_t count)
 {
        struct iwl_priv *priv = dev_get_drvdata(d);
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
        u32 filter_flags = simple_strtoul(buf, NULL, 0);
 
        mutex_lock(&priv->mutex);
-       if (le32_to_cpu(priv->staging_rxon.filter_flags) != filter_flags) {
+       if (le32_to_cpu(ctx->staging.filter_flags) != filter_flags) {
                /* Cancel any currently running scans... */
                if (iwl_scan_cancel_timeout(priv, 100))
                        IWL_WARN(priv, "Could not cancel scan.\n");
                else {
                        IWL_DEBUG_INFO(priv, "Committing rxon.filter_flags = "
                                       "0x%04X\n", filter_flags);
-                       priv->staging_rxon.filter_flags =
+                       ctx->staging.filter_flags =
                                cpu_to_le32(filter_flags);
-                       iwlcore_commit_rxon(priv);
+                       iwlcore_commit_rxon(priv, ctx);
                }
        }
        mutex_unlock(&priv->mutex);
@@ -3637,8 +3661,9 @@ static ssize_t store_measurement(struct device *d,
                                 const char *buf, size_t count)
 {
        struct iwl_priv *priv = dev_get_drvdata(d);
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
        struct ieee80211_measurement_params params = {
-               .channel = le16_to_cpu(priv->active_rxon.channel),
+               .channel = le16_to_cpu(ctx->active.channel),
                .start_time = cpu_to_le64(priv->_3945.last_tsf),
                .duration = cpu_to_le16(1),
        };
@@ -3785,10 +3810,8 @@ static void iwl3945_setup_deferred_work(struct iwl_priv *priv)
        INIT_DELAYED_WORK(&priv->init_alive_start, iwl3945_bg_init_alive_start);
        INIT_DELAYED_WORK(&priv->alive_start, iwl3945_bg_alive_start);
        INIT_DELAYED_WORK(&priv->_3945.rfkill_poll, iwl3945_rfkill_poll);
-       INIT_WORK(&priv->scan_completed, iwl_bg_scan_completed);
-       INIT_WORK(&priv->abort_scan, iwl_bg_abort_scan);
-       INIT_WORK(&priv->start_internal_scan, iwl_bg_start_internal_scan);
-       INIT_DELAYED_WORK(&priv->scan_check, iwl_bg_scan_check);
+
+       iwl_setup_scan_deferred_work(priv);
 
        iwl3945_hw_setup_deferred_work(priv);
 
@@ -3812,8 +3835,6 @@ static void iwl3945_cancel_deferred_work(struct iwl_priv *priv)
        cancel_delayed_work(&priv->alive_start);
        cancel_work_sync(&priv->start_internal_scan);
        cancel_work_sync(&priv->beacon_update);
-       if (priv->cfg->ops->lib->recover_from_tx_stall)
-               del_timer_sync(&priv->monitor_recover);
 }
 
 static struct attribute *iwl3945_sysfs_entries[] = {
@@ -3853,6 +3874,7 @@ static struct ieee80211_ops iwl3945_hw_ops = {
        .hw_scan = iwl_mac_hw_scan,
        .sta_add = iwl3945_mac_sta_add,
        .sta_remove = iwl_mac_sta_remove,
+       .tx_last_beacon = iwl_mac_tx_last_beacon,
 };
 
 static int iwl3945_init_drv(struct iwl_priv *priv)
@@ -3933,8 +3955,7 @@ static int iwl3945_setup_mac(struct iwl_priv *priv)
                             IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
 
        hw->wiphy->interface_modes =
-               BIT(NL80211_IFTYPE_STATION) |
-               BIT(NL80211_IFTYPE_ADHOC);
+               priv->contexts[IWL_RXON_CTX_BSS].interface_modes;
 
        hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY |
                            WIPHY_FLAG_DISABLE_BEACON_HINTS;
@@ -3966,7 +3987,7 @@ static int iwl3945_setup_mac(struct iwl_priv *priv)
 
 static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
-       int err = 0;
+       int err = 0, i;
        struct iwl_priv *priv;
        struct ieee80211_hw *hw;
        struct iwl_cfg *cfg = (struct iwl_cfg *)(ent->driver_data);
@@ -3988,6 +4009,27 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
        priv = hw->priv;
        SET_IEEE80211_DEV(hw, &pdev->dev);
 
+       priv->cmd_queue = IWL39_CMD_QUEUE_NUM;
+
+       /* 3945 has only one valid context */
+       priv->valid_contexts = BIT(IWL_RXON_CTX_BSS);
+
+       for (i = 0; i < NUM_IWL_RXON_CTX; i++)
+               priv->contexts[i].ctxid = i;
+
+       priv->contexts[IWL_RXON_CTX_BSS].rxon_cmd = REPLY_RXON;
+       priv->contexts[IWL_RXON_CTX_BSS].rxon_timing_cmd = REPLY_RXON_TIMING;
+       priv->contexts[IWL_RXON_CTX_BSS].rxon_assoc_cmd = REPLY_RXON_ASSOC;
+       priv->contexts[IWL_RXON_CTX_BSS].qos_cmd = REPLY_QOS_PARAM;
+       priv->contexts[IWL_RXON_CTX_BSS].ap_sta_id = IWL_AP_ID;
+       priv->contexts[IWL_RXON_CTX_BSS].wep_key_cmd = REPLY_WEPKEY;
+       priv->contexts[IWL_RXON_CTX_BSS].interface_modes =
+               BIT(NL80211_IFTYPE_STATION) |
+               BIT(NL80211_IFTYPE_ADHOC);
+       priv->contexts[IWL_RXON_CTX_BSS].ibss_devtype = RXON_DEV_TYPE_IBSS;
+       priv->contexts[IWL_RXON_CTX_BSS].station_devtype = RXON_DEV_TYPE_ESS;
+       priv->contexts[IWL_RXON_CTX_BSS].unused_devtype = RXON_DEV_TYPE_ESS;
+
        /*
         * Disabling hardware scan means that mac80211 will perform scans
         * "the hard way", rather than using device's scan.
@@ -4009,6 +4051,9 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
        /***************************
         * 2. Initializing PCI bus
         * *************************/
+       pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1 |
+                               PCIE_LINK_STATE_CLKPM);
+
        if (pci_enable_device(pdev)) {
                err = -ENODEV;
                goto out_ieee80211_free_hw;
@@ -4120,7 +4165,8 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
        }
 
        iwl_set_rxon_channel(priv,
-                            &priv->bands[IEEE80211_BAND_2GHZ].channels[5]);
+                            &priv->bands[IEEE80211_BAND_2GHZ].channels[5],
+                            &priv->contexts[IWL_RXON_CTX_BSS]);
        iwl3945_setup_deferred_work(priv);
        iwl3945_setup_rx_handlers(priv);
        iwl_power_initialize(priv);
index c02fcedea9fafc5e80375832d9e8bc7c70867317..a944893ae3ca78d9b3371102ffc85ad9b5cea65e 100644 (file)
@@ -1195,11 +1195,8 @@ static int iwm_ntf_wifi_if_wrapper(struct iwm_priv *iwm, u8 *buf,
        IWM_DBG_NTF(iwm, DBG, "WIFI_IF_WRAPPER cmd is delivered to UMAC: "
                    "oid is 0x%x\n", hdr->oid);
 
-       if (hdr->oid <= WIFI_IF_NTFY_MAX) {
-               set_bit(hdr->oid, &iwm->wifi_ntfy[0]);
-               wake_up_interruptible(&iwm->wifi_ntfy_queue);
-       } else
-               return -EINVAL;
+       set_bit(hdr->oid, &iwm->wifi_ntfy[0]);
+       wake_up_interruptible(&iwm->wifi_ntfy_queue);
 
        switch (hdr->oid) {
        case UMAC_WIFI_IF_CMD_SET_PROFILE:
index 3e82f162720972d8c6bd732fa437c7fc7046bde6..317f086ced0a50cdcf8ac2695e112d9f6886585c 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/wait.h>
 #include <linux/slab.h>
 #include <linux/sched.h>
+#include <linux/wait.h>
 #include <linux/ieee80211.h>
 #include <net/cfg80211.h>
 #include <asm/unaligned.h>
@@ -526,20 +527,31 @@ static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy,
 
        pos = scanresp->bssdesc_and_tlvbuffer;
 
+       lbs_deb_hex(LBS_DEB_SCAN, "SCAN_RSP", scanresp->bssdesc_and_tlvbuffer,
+                       scanresp->bssdescriptsize);
+
        tsfdesc = pos + bsssize;
        tsfsize = 4 + 8 * scanresp->nr_sets;
+       lbs_deb_hex(LBS_DEB_SCAN, "SCAN_TSF", (u8 *) tsfdesc, tsfsize);
 
        /* Validity check: we expect a Marvell-Local TLV */
        i = get_unaligned_le16(tsfdesc);
        tsfdesc += 2;
-       if (i != TLV_TYPE_TSFTIMESTAMP)
+       if (i != TLV_TYPE_TSFTIMESTAMP) {
+               lbs_deb_scan("scan response: invalid TSF Timestamp %d\n", i);
                goto done;
+       }
+
        /* Validity check: the TLV holds TSF values with 8 bytes each, so
         * the size in the TLV must match the nr_sets value */
        i = get_unaligned_le16(tsfdesc);
        tsfdesc += 2;
-       if (i / 8 != scanresp->nr_sets)
+       if (i / 8 != scanresp->nr_sets) {
+               lbs_deb_scan("scan response: invalid number of TSF timestamp "
+                            "sets (expected %d got %d)\n", scanresp->nr_sets,
+                            i / 8);
                goto done;
+       }
 
        for (i = 0; i < scanresp->nr_sets; i++) {
                const u8 *bssid;
@@ -581,8 +593,11 @@ static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy,
                        id = *pos++;
                        elen = *pos++;
                        left -= 2;
-                       if (elen > left || elen == 0)
+                       if (elen > left || elen == 0) {
+                               lbs_deb_scan("scan response: invalid IE fmt\n");
                                goto done;
+                       }
+
                        if (id == WLAN_EID_DS_PARAMS)
                                chan_no = *pos;
                        if (id == WLAN_EID_SSID) {
@@ -613,7 +628,9 @@ static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy,
                                        capa, intvl, ie, ielen,
                                        LBS_SCAN_RSSI_TO_MBM(rssi),
                                        GFP_KERNEL);
-               }
+               } else
+                       lbs_deb_scan("scan response: missing BSS channel IE\n");
+
                tsfdesc += 8;
        }
        ret = 0;
@@ -1103,7 +1120,7 @@ static int lbs_associate(struct lbs_private *priv,
        lbs_deb_hex(LBS_DEB_ASSOC, "Common Rates", tmp, pos - tmp);
 
        /* add auth type TLV */
-       if (priv->fwrelease >= 0x09000000)
+       if (MRVL_FW_MAJOR_REV(priv->fwrelease) >= 9)
                pos += lbs_add_auth_type_tlv(pos, sme->auth_type);
 
        /* add WPA/WPA2 TLV */
@@ -1114,6 +1131,9 @@ static int lbs_associate(struct lbs_private *priv,
                (u16)(pos - (u8 *) &cmd->iebuf);
        cmd->hdr.size = cpu_to_le16(len);
 
+       lbs_deb_hex(LBS_DEB_ASSOC, "ASSOC_CMD", (u8 *) cmd,
+                       le16_to_cpu(cmd->hdr.size));
+
        /* store for later use */
        memcpy(priv->assoc_bss, bss->bssid, ETH_ALEN);
 
@@ -1121,14 +1141,28 @@ static int lbs_associate(struct lbs_private *priv,
        if (ret)
                goto done;
 
-
        /* generate connect message to cfg80211 */
 
        resp = (void *) cmd; /* recast for easier field access */
        status = le16_to_cpu(resp->statuscode);
 
-       /* Convert statis code of old firmware */
-       if (priv->fwrelease < 0x09000000)
+       /* Older FW versions map the IEEE 802.11 Status Code in the association
+        * response to the following values returned in resp->statuscode:
+        *
+        *    IEEE Status Code                Marvell Status Code
+        *    0                       ->      0x0000 ASSOC_RESULT_SUCCESS
+        *    13                      ->      0x0004 ASSOC_RESULT_AUTH_REFUSED
+        *    14                      ->      0x0004 ASSOC_RESULT_AUTH_REFUSED
+        *    15                      ->      0x0004 ASSOC_RESULT_AUTH_REFUSED
+        *    16                      ->      0x0004 ASSOC_RESULT_AUTH_REFUSED
+        *    others                  ->      0x0003 ASSOC_RESULT_REFUSED
+        *
+        * Other response codes:
+        *    0x0001 -> ASSOC_RESULT_INVALID_PARAMETERS (unused)
+        *    0x0002 -> ASSOC_RESULT_TIMEOUT (internal timer expired waiting for
+        *                                    association response from the AP)
+        */
+       if (MRVL_FW_MAJOR_REV(priv->fwrelease) <= 8) {
                switch (status) {
                case 0:
                        break;
@@ -1150,11 +1184,16 @@ static int lbs_associate(struct lbs_private *priv,
                        break;
                default:
                        lbs_deb_assoc("association failure %d\n", status);
-                       status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+                       /* v5 OLPC firmware does return the AP status code if
+                        * it's not one of the values above.  Let that through.
+                        */
+                       break;
+               }
        }
 
-       lbs_deb_assoc("status %d, capability 0x%04x\n", status,
-                     le16_to_cpu(resp->capability));
+       lbs_deb_assoc("status %d, statuscode 0x%04x, capability 0x%04x, "
+                     "aid 0x%04x\n", status, le16_to_cpu(resp->statuscode),
+                     le16_to_cpu(resp->capability), le16_to_cpu(resp->aid));
 
        resp_ie_len = le16_to_cpu(resp->hdr.size)
                - sizeof(resp->hdr)
@@ -1174,7 +1213,6 @@ static int lbs_associate(struct lbs_private *priv,
                        netif_tx_wake_all_queues(priv->dev);
        }
 
-
 done:
        lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
        return ret;
index 1d141fefd7673bf89c9a5554aa6f6bcbb49aac9e..2ae752d1006555318bb421b39fea2a9b6d37d735 100644 (file)
@@ -8,7 +8,14 @@
 #define _LBS_DECL_H_
 
 #include <linux/netdevice.h>
+#include <linux/firmware.h>
 
+/* Should be terminated by a NULL entry */
+struct lbs_fw_table {
+       int model;
+       const char *helper;
+       const char *fwname;
+};
 
 struct lbs_private;
 struct sk_buff;
@@ -53,4 +60,10 @@ int lbs_exit_auto_deep_sleep(struct lbs_private *priv);
 u32 lbs_fw_index_to_data_rate(u8 index);
 u8 lbs_data_rate_to_fw_index(u32 rate);
 
+int lbs_get_firmware(struct device *dev, const char *user_helper,
+                       const char *user_mainfw, u32 card_model,
+                       const struct lbs_fw_table *fw_table,
+                       const struct firmware **helper,
+                       const struct firmware **mainfw);
+
 #endif
index 9c298396be50b7fe5d0d6f8c6b102ecef441b3f7..e213a5dc049dc634b0daf4198f03ca027fd42be4 100644 (file)
@@ -48,7 +48,6 @@
 MODULE_AUTHOR("Holger Schurig <hs4233@mail.mn-solutions.de>");
 MODULE_DESCRIPTION("Driver for Marvell 83xx compact flash WLAN cards");
 MODULE_LICENSE("GPL");
-MODULE_FIRMWARE("libertas_cs_helper.fw");
 
 
 
@@ -61,9 +60,34 @@ struct if_cs_card {
        struct lbs_private *priv;
        void __iomem *iobase;
        bool align_regs;
+       u32 model;
 };
 
 
+enum {
+       MODEL_UNKNOWN = 0x00,
+       MODEL_8305 = 0x01,
+       MODEL_8381 = 0x02,
+       MODEL_8385 = 0x03
+};
+
+static const struct lbs_fw_table fw_table[] = {
+       { MODEL_8305, "libertas/cf8305.bin", NULL },
+       { MODEL_8305, "libertas_cs_helper.fw", NULL },
+       { MODEL_8381, "libertas/cf8381_helper.bin", "libertas/cf8381.bin" },
+       { MODEL_8381, "libertas_cs_helper.fw", "libertas_cs.fw" },
+       { MODEL_8385, "libertas/cf8385_helper.bin", "libertas/cf8385.bin" },
+       { MODEL_8385, "libertas_cs_helper.fw", "libertas_cs.fw" },
+       { 0, NULL, NULL }
+};
+MODULE_FIRMWARE("libertas/cf8305.bin");
+MODULE_FIRMWARE("libertas/cf8381_helper.bin");
+MODULE_FIRMWARE("libertas/cf8381.bin");
+MODULE_FIRMWARE("libertas/cf8385_helper.bin");
+MODULE_FIRMWARE("libertas/cf8385.bin");
+MODULE_FIRMWARE("libertas_cs_helper.fw");
+MODULE_FIRMWARE("libertas_cs.fw");
+
 
 /********************************************************************/
 /* Hardware access                                                  */
@@ -289,22 +313,19 @@ static int if_cs_poll_while_fw_download(struct if_cs_card *card, uint addr, u8 r
 #define CF8385_MANFID          0x02df
 #define CF8385_CARDID          0x8103
 
-static inline int if_cs_hw_is_cf8305(struct pcmcia_device *p_dev)
-{
-       return (p_dev->manf_id == CF8305_MANFID &&
-               p_dev->card_id == CF8305_CARDID);
-}
-
-static inline int if_cs_hw_is_cf8381(struct pcmcia_device *p_dev)
-{
-       return (p_dev->manf_id == CF8381_MANFID &&
-               p_dev->card_id == CF8381_CARDID);
-}
-
-static inline int if_cs_hw_is_cf8385(struct pcmcia_device *p_dev)
+/* FIXME: just use the 'driver_info' field of 'struct pcmcia_device_id' when
+ * that gets fixed.  Currently there's no way to access it from the probe hook.
+ */
+static inline u32 get_model(u16 manf_id, u16 card_id)
 {
-       return (p_dev->manf_id == CF8385_MANFID &&
-               p_dev->card_id == CF8385_CARDID);
+       /* NOTE: keep in sync with if_cs_ids */
+       if (manf_id == CF8305_MANFID && card_id == CF8305_CARDID)
+               return MODEL_8305;
+       else if (manf_id == CF8381_MANFID && card_id == CF8381_CARDID)
+               return MODEL_8381;
+       else if (manf_id == CF8385_MANFID && card_id == CF8385_CARDID)
+               return MODEL_8385;
+       return MODEL_UNKNOWN;
 }
 
 /********************************************************************/
@@ -558,12 +579,11 @@ static irqreturn_t if_cs_interrupt(int irq, void *data)
  *
  * Return 0 on success
  */
-static int if_cs_prog_helper(struct if_cs_card *card)
+static int if_cs_prog_helper(struct if_cs_card *card, const struct firmware *fw)
 {
        int ret = 0;
        int sent = 0;
        u8  scratch;
-       const struct firmware *fw;
 
        lbs_deb_enter(LBS_DEB_CS);
 
@@ -589,14 +609,6 @@ static int if_cs_prog_helper(struct if_cs_card *card)
                goto done;
        }
 
-       /* TODO: make firmware file configurable */
-       ret = request_firmware(&fw, "libertas_cs_helper.fw",
-               &card->p_dev->dev);
-       if (ret) {
-               lbs_pr_err("can't load helper firmware\n");
-               ret = -ENODEV;
-               goto done;
-       }
        lbs_deb_cs("helper size %td\n", fw->size);
 
        /* "Set the 5 bytes of the helper image to 0" */
@@ -635,7 +647,7 @@ static int if_cs_prog_helper(struct if_cs_card *card)
                if (ret < 0) {
                        lbs_pr_err("can't download helper at 0x%x, ret %d\n",
                                sent, ret);
-                       goto err_release;
+                       goto done;
                }
 
                if (count == 0)
@@ -644,17 +656,14 @@ static int if_cs_prog_helper(struct if_cs_card *card)
                sent += count;
        }
 
-err_release:
-       release_firmware(fw);
 done:
        lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
        return ret;
 }
 
 
-static int if_cs_prog_real(struct if_cs_card *card)
+static int if_cs_prog_real(struct if_cs_card *card, const struct firmware *fw)
 {
-       const struct firmware *fw;
        int ret = 0;
        int retry = 0;
        int len = 0;
@@ -662,21 +671,13 @@ static int if_cs_prog_real(struct if_cs_card *card)
 
        lbs_deb_enter(LBS_DEB_CS);
 
-       /* TODO: make firmware file configurable */
-       ret = request_firmware(&fw, "libertas_cs.fw",
-               &card->p_dev->dev);
-       if (ret) {
-               lbs_pr_err("can't load firmware\n");
-               ret = -ENODEV;
-               goto done;
-       }
        lbs_deb_cs("fw size %td\n", fw->size);
 
        ret = if_cs_poll_while_fw_download(card, IF_CS_SQ_READ_LOW,
                IF_CS_SQ_HELPER_OK);
        if (ret < 0) {
                lbs_pr_err("helper firmware doesn't answer\n");
-               goto err_release;
+               goto done;
        }
 
        for (sent = 0; sent < fw->size; sent += len) {
@@ -691,7 +692,7 @@ static int if_cs_prog_real(struct if_cs_card *card)
                if (retry > 20) {
                        lbs_pr_err("could not download firmware\n");
                        ret = -ENODEV;
-                       goto err_release;
+                       goto done;
                }
                if (retry) {
                        sent -= len;
@@ -710,7 +711,7 @@ static int if_cs_prog_real(struct if_cs_card *card)
                        IF_CS_BIT_COMMAND);
                if (ret < 0) {
                        lbs_pr_err("can't download firmware at 0x%x\n", sent);
-                       goto err_release;
+                       goto done;
                }
        }
 
@@ -718,9 +719,6 @@ static int if_cs_prog_real(struct if_cs_card *card)
        if (ret < 0)
                lbs_pr_err("firmware download failed\n");
 
-err_release:
-       release_firmware(fw);
-
 done:
        lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
        return ret;
@@ -824,6 +822,8 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
        unsigned int prod_id;
        struct lbs_private *priv;
        struct if_cs_card *card;
+       const struct firmware *helper = NULL;
+       const struct firmware *mainfw = NULL;
 
        lbs_deb_enter(LBS_DEB_CS);
 
@@ -843,7 +843,6 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
                goto out1;
        }
 
-
        /*
         * Allocate an interrupt line.  Note that this does not assign
         * a handler to the interrupt, unless the 'Handler' member of
@@ -881,34 +880,47 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
         */
        card->align_regs = 0;
 
+       card->model = get_model(p_dev->manf_id, p_dev->card_id);
+       if (card->model == MODEL_UNKNOWN) {
+               lbs_pr_err("unsupported manf_id 0x%04x / card_id 0x%04x\n",
+                          p_dev->manf_id, p_dev->card_id);
+               goto out2;
+       }
+
        /* Check if we have a current silicon */
        prod_id = if_cs_read8(card, IF_CS_PRODUCT_ID);
-       if (if_cs_hw_is_cf8305(p_dev)) {
+       if (card->model == MODEL_8305) {
                card->align_regs = 1;
                if (prod_id < IF_CS_CF8305_B1_REV) {
-                       lbs_pr_err("old chips like 8305 rev B3 "
-                               "aren't supported\n");
+                       lbs_pr_err("8305 rev B0 and older are not supported\n");
                        ret = -ENODEV;
                        goto out2;
                }
        }
 
-       if (if_cs_hw_is_cf8381(p_dev) && prod_id < IF_CS_CF8381_B3_REV) {
-               lbs_pr_err("old chips like 8381 rev B3 aren't supported\n");
+       if ((card->model == MODEL_8381) && prod_id < IF_CS_CF8381_B3_REV) {
+               lbs_pr_err("8381 rev B2 and older are not supported\n");
                ret = -ENODEV;
                goto out2;
        }
 
-       if (if_cs_hw_is_cf8385(p_dev) && prod_id < IF_CS_CF8385_B1_REV) {
-               lbs_pr_err("old chips like 8385 rev B1 aren't supported\n");
+       if ((card->model == MODEL_8385) && prod_id < IF_CS_CF8385_B1_REV) {
+               lbs_pr_err("8385 rev B0 and older are not supported\n");
                ret = -ENODEV;
                goto out2;
        }
 
+       ret = lbs_get_firmware(&p_dev->dev, NULL, NULL, card->model,
+                               &fw_table[0], &helper, &mainfw);
+       if (ret) {
+               lbs_pr_err("failed to find firmware (%d)\n", ret);
+               goto out2;
+       }
+
        /* Load the firmware early, before calling into libertas.ko */
-       ret = if_cs_prog_helper(card);
-       if (ret == 0 && !if_cs_hw_is_cf8305(p_dev))
-               ret = if_cs_prog_real(card);
+       ret = if_cs_prog_helper(card, helper);
+       if (ret == 0 && (card->model != MODEL_8305))
+               ret = if_cs_prog_real(card, mainfw);
        if (ret)
                goto out2;
 
@@ -957,6 +969,11 @@ out2:
 out1:
        pcmcia_disable_device(p_dev);
 out:
+       if (helper)
+               release_firmware(helper);
+       if (mainfw)
+               release_firmware(mainfw);
+
        lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
        return ret;
 }
@@ -993,6 +1010,7 @@ static struct pcmcia_device_id if_cs_ids[] = {
        PCMCIA_DEVICE_MANF_CARD(CF8305_MANFID, CF8305_CARDID),
        PCMCIA_DEVICE_MANF_CARD(CF8381_MANFID, CF8381_CARDID),
        PCMCIA_DEVICE_MANF_CARD(CF8385_MANFID, CF8385_CARDID),
+       /* NOTE: keep in sync with get_model() */
        PCMCIA_DEVICE_NULL,
 };
 MODULE_DEVICE_TABLE(pcmcia, if_cs_ids);
index 87b634978b357797ed6ceb22f7dec9643f6c7054..296fd00a5129f2bb9f47e3475bf25d35c67e7f20 100644 (file)
@@ -76,36 +76,32 @@ static const struct sdio_device_id if_sdio_ids[] = {
 
 MODULE_DEVICE_TABLE(sdio, if_sdio_ids);
 
-struct if_sdio_model {
-       int model;
-       const char *helper;
-       const char *firmware;
-};
-
-static struct if_sdio_model if_sdio_models[] = {
-       {
-               /* 8385 */
-               .model = IF_SDIO_MODEL_8385,
-               .helper = "sd8385_helper.bin",
-               .firmware = "sd8385.bin",
-       },
-       {
-               /* 8686 */
-               .model = IF_SDIO_MODEL_8686,
-               .helper = "sd8686_helper.bin",
-               .firmware = "sd8686.bin",
-       },
-       {
-               /* 8688 */
-               .model = IF_SDIO_MODEL_8688,
-               .helper = "sd8688_helper.bin",
-               .firmware = "sd8688.bin",
-       },
+#define MODEL_8385     0x04
+#define MODEL_8686     0x0b
+#define MODEL_8688     0x10
+
+static const struct lbs_fw_table fw_table[] = {
+       { MODEL_8385, "libertas/sd8385_helper.bin", "libertas/sd8385.bin" },
+       { MODEL_8385, "sd8385_helper.bin", "sd8385.bin" },
+       { MODEL_8686, "libertas/sd8686_v9_helper.bin", "libertas/sd8686_v9.bin" },
+       { MODEL_8686, "libertas/sd8686_v8_helper.bin", "libertas/sd8686_v8.bin" },
+       { MODEL_8686, "sd8686_helper.bin", "sd8686.bin" },
+       { MODEL_8688, "libertas/sd8688_helper.bin", "libertas/sd8688.bin" },
+       { MODEL_8688, "sd8688_helper.bin", "sd8688.bin" },
+       { 0, NULL, NULL }
 };
+MODULE_FIRMWARE("libertas/sd8385_helper.bin");
+MODULE_FIRMWARE("libertas/sd8385.bin");
 MODULE_FIRMWARE("sd8385_helper.bin");
 MODULE_FIRMWARE("sd8385.bin");
+MODULE_FIRMWARE("libertas/sd8686_v9_helper.bin");
+MODULE_FIRMWARE("libertas/sd8686_v9.bin");
+MODULE_FIRMWARE("libertas/sd8686_v8_helper.bin");
+MODULE_FIRMWARE("libertas/sd8686_v8.bin");
 MODULE_FIRMWARE("sd8686_helper.bin");
 MODULE_FIRMWARE("sd8686.bin");
+MODULE_FIRMWARE("libertas/sd8688_helper.bin");
+MODULE_FIRMWARE("libertas/sd8688.bin");
 MODULE_FIRMWARE("sd8688_helper.bin");
 MODULE_FIRMWARE("sd8688.bin");
 
@@ -187,11 +183,11 @@ static u16 if_sdio_read_rx_len(struct if_sdio_card *card, int *err)
        u16 rx_len;
 
        switch (card->model) {
-       case IF_SDIO_MODEL_8385:
-       case IF_SDIO_MODEL_8686:
+       case MODEL_8385:
+       case MODEL_8686:
                rx_len = if_sdio_read_scratch(card, &ret);
                break;
-       case IF_SDIO_MODEL_8688:
+       case MODEL_8688:
        default: /* for newer chipsets */
                rx_len = sdio_readb(card->func, IF_SDIO_RX_LEN, &ret);
                if (!ret)
@@ -288,7 +284,7 @@ static int if_sdio_handle_event(struct if_sdio_card *card,
 
        lbs_deb_enter(LBS_DEB_SDIO);
 
-       if (card->model == IF_SDIO_MODEL_8385) {
+       if (card->model == MODEL_8385) {
                event = sdio_readb(card->func, IF_SDIO_EVENT, &ret);
                if (ret)
                        goto out;
@@ -466,10 +462,10 @@ static void if_sdio_host_to_card_worker(struct work_struct *work)
 
 #define FW_DL_READY_STATUS (IF_SDIO_IO_RDY | IF_SDIO_DL_RDY)
 
-static int if_sdio_prog_helper(struct if_sdio_card *card)
+static int if_sdio_prog_helper(struct if_sdio_card *card,
+                               const struct firmware *fw)
 {
        int ret;
-       const struct firmware *fw;
        unsigned long timeout;
        u8 *chunk_buffer;
        u32 chunk_size;
@@ -478,16 +474,10 @@ static int if_sdio_prog_helper(struct if_sdio_card *card)
 
        lbs_deb_enter(LBS_DEB_SDIO);
 
-       ret = request_firmware(&fw, card->helper, &card->func->dev);
-       if (ret) {
-               lbs_pr_err("can't load helper firmware\n");
-               goto out;
-       }
-
        chunk_buffer = kzalloc(64, GFP_KERNEL);
        if (!chunk_buffer) {
                ret = -ENOMEM;
-               goto release_fw;
+               goto out;
        }
 
        sdio_claim_host(card->func);
@@ -562,22 +552,19 @@ static int if_sdio_prog_helper(struct if_sdio_card *card)
 release:
        sdio_release_host(card->func);
        kfree(chunk_buffer);
-release_fw:
-       release_firmware(fw);
 
 out:
        if (ret)
                lbs_pr_err("failed to load helper firmware\n");
 
        lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
-
        return ret;
 }
 
-static int if_sdio_prog_real(struct if_sdio_card *card)
+static int if_sdio_prog_real(struct if_sdio_card *card,
+                               const struct firmware *fw)
 {
        int ret;
-       const struct firmware *fw;
        unsigned long timeout;
        u8 *chunk_buffer;
        u32 chunk_size;
@@ -586,16 +573,10 @@ static int if_sdio_prog_real(struct if_sdio_card *card)
 
        lbs_deb_enter(LBS_DEB_SDIO);
 
-       ret = request_firmware(&fw, card->firmware, &card->func->dev);
-       if (ret) {
-               lbs_pr_err("can't load firmware\n");
-               goto out;
-       }
-
        chunk_buffer = kzalloc(512, GFP_KERNEL);
        if (!chunk_buffer) {
                ret = -ENOMEM;
-               goto release_fw;
+               goto out;
        }
 
        sdio_claim_host(card->func);
@@ -685,15 +666,12 @@ static int if_sdio_prog_real(struct if_sdio_card *card)
 release:
        sdio_release_host(card->func);
        kfree(chunk_buffer);
-release_fw:
-       release_firmware(fw);
 
 out:
        if (ret)
                lbs_pr_err("failed to load firmware\n");
 
        lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
-
        return ret;
 }
 
@@ -701,6 +679,8 @@ static int if_sdio_prog_firmware(struct if_sdio_card *card)
 {
        int ret;
        u16 scratch;
+       const struct firmware *helper = NULL;
+       const struct firmware *mainfw = NULL;
 
        lbs_deb_enter(LBS_DEB_SDIO);
 
@@ -718,11 +698,18 @@ static int if_sdio_prog_firmware(struct if_sdio_card *card)
                goto success;
        }
 
-       ret = if_sdio_prog_helper(card);
+       ret = lbs_get_firmware(&card->func->dev, lbs_helper_name, lbs_fw_name,
+                               card->model, &fw_table[0], &helper, &mainfw);
+       if (ret) {
+               lbs_pr_err("failed to find firmware (%d)\n", ret);
+               goto out;
+       }
+
+       ret = if_sdio_prog_helper(card, helper);
        if (ret)
                goto out;
 
-       ret = if_sdio_prog_real(card);
+       ret = if_sdio_prog_real(card, mainfw);
        if (ret)
                goto out;
 
@@ -733,8 +720,12 @@ success:
        ret = 0;
 
 out:
-       lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
+       if (helper)
+               release_firmware(helper);
+       if (mainfw)
+               release_firmware(mainfw);
 
+       lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
        return ret;
 }
 
@@ -938,7 +929,7 @@ static int if_sdio_probe(struct sdio_func *func,
                                "ID: %x", &model) == 1)
                        break;
                if (!strcmp(func->card->info[i], "IBIS Wireless SDIO Card")) {
-                       model = IF_SDIO_MODEL_8385;
+                       model = MODEL_8385;
                        break;
                }
        }
@@ -956,13 +947,13 @@ static int if_sdio_probe(struct sdio_func *func,
        card->model = model;
 
        switch (card->model) {
-       case IF_SDIO_MODEL_8385:
+       case MODEL_8385:
                card->scratch_reg = IF_SDIO_SCRATCH_OLD;
                break;
-       case IF_SDIO_MODEL_8686:
+       case MODEL_8686:
                card->scratch_reg = IF_SDIO_SCRATCH;
                break;
-       case IF_SDIO_MODEL_8688:
+       case MODEL_8688:
        default: /* for newer chipsets */
                card->scratch_reg = IF_SDIO_FW_STATUS;
                break;
@@ -972,49 +963,17 @@ static int if_sdio_probe(struct sdio_func *func,
        card->workqueue = create_workqueue("libertas_sdio");
        INIT_WORK(&card->packet_worker, if_sdio_host_to_card_worker);
 
-       for (i = 0;i < ARRAY_SIZE(if_sdio_models);i++) {
-               if (card->model == if_sdio_models[i].model)
+       /* Check if we support this card */
+       for (i = 0; i < ARRAY_SIZE(fw_table); i++) {
+               if (card->model == fw_table[i].model)
                        break;
        }
-
-       if (i == ARRAY_SIZE(if_sdio_models)) {
+       if (i == ARRAY_SIZE(fw_table)) {
                lbs_pr_err("unknown card model 0x%x\n", card->model);
                ret = -ENODEV;
                goto free;
        }
 
-       card->helper = if_sdio_models[i].helper;
-       card->firmware = if_sdio_models[i].firmware;
-
-       kparam_block_sysfs_write(helper_name);
-       if (lbs_helper_name) {
-               char *helper = kstrdup(lbs_helper_name, GFP_KERNEL);
-               if (!helper) {
-                       kparam_unblock_sysfs_write(helper_name);
-                       ret = -ENOMEM;
-                       goto free;
-               }
-               lbs_deb_sdio("overriding helper firmware: %s\n",
-                       lbs_helper_name);
-               card->helper = helper;
-               card->helper_allocated = true;
-       }
-       kparam_unblock_sysfs_write(helper_name);
-
-       kparam_block_sysfs_write(fw_name);
-       if (lbs_fw_name) {
-               char *fw_name = kstrdup(lbs_fw_name, GFP_KERNEL);
-               if (!fw_name) {
-                       kparam_unblock_sysfs_write(fw_name);
-                       ret = -ENOMEM;
-                       goto free;
-               }
-               lbs_deb_sdio("overriding firmware: %s\n", lbs_fw_name);
-               card->firmware = fw_name;
-               card->firmware_allocated = true;
-       }
-       kparam_unblock_sysfs_write(fw_name);
-
        sdio_claim_host(func);
 
        ret = sdio_enable_func(func);
@@ -1028,7 +987,7 @@ static int if_sdio_probe(struct sdio_func *func,
        /* For 1-bit transfers to the 8686 model, we need to enable the
         * interrupt flag in the CCCR register. Set the MMC_QUIRK_LENIENT_FN0
         * bit to allow access to non-vendor registers. */
-       if ((card->model == IF_SDIO_MODEL_8686) &&
+       if ((card->model == MODEL_8686) &&
            (host->caps & MMC_CAP_SDIO_IRQ) &&
            (host->ios.bus_width == MMC_BUS_WIDTH_1)) {
                u8 reg;
@@ -1091,8 +1050,8 @@ static int if_sdio_probe(struct sdio_func *func,
         * Get rx_unit if the chip is SD8688 or newer.
         * SD8385 & SD8686 do not have rx_unit.
         */
-       if ((card->model != IF_SDIO_MODEL_8385)
-                       && (card->model != IF_SDIO_MODEL_8686))
+       if ((card->model != MODEL_8385)
+                       && (card->model != MODEL_8686))
                card->rx_unit = if_sdio_read_rx_unit(card);
        else
                card->rx_unit = 0;
@@ -1108,7 +1067,7 @@ static int if_sdio_probe(struct sdio_func *func,
        /*
         * FUNC_INIT is required for SD8688 WLAN/BT multiple functions
         */
-       if (card->model == IF_SDIO_MODEL_8688) {
+       if (card->model == MODEL_8688) {
                struct cmd_header cmd;
 
                memset(&cmd, 0, sizeof(cmd));
@@ -1165,7 +1124,7 @@ static void if_sdio_remove(struct sdio_func *func)
 
        card = sdio_get_drvdata(func);
 
-       if (user_rmmod && (card->model == IF_SDIO_MODEL_8688)) {
+       if (user_rmmod && (card->model == MODEL_8688)) {
                /*
                 * FUNC_SHUTDOWN is required for SD8688 WLAN/BT
                 * multiple functions
index 12179c1dc9c9b27583bafb90f73c7b22af9c516a..62fda3592f6784f191e484a8f0c1b515b002a035 100644 (file)
 #ifndef _LBS_IF_SDIO_H
 #define _LBS_IF_SDIO_H
 
-#define IF_SDIO_MODEL_8385     0x04
-#define IF_SDIO_MODEL_8686     0x0b
-#define IF_SDIO_MODEL_8688     0x10
-
 #define IF_SDIO_IOPORT         0x00
 
 #define IF_SDIO_H_INT_MASK     0x04
index fe3f08028eb3a07881ea62bc33cc34b931d34883..79bcb4e5d2ca03c7ccb82621576296a6ea68b5d0 100644 (file)
@@ -39,9 +39,6 @@ struct if_spi_card {
        struct lbs_private              *priv;
        struct libertas_spi_platform_data *pdata;
 
-       char                            helper_fw_name[IF_SPI_FW_NAME_MAX];
-       char                            main_fw_name[IF_SPI_FW_NAME_MAX];
-
        /* The card ID and card revision, as reported by the hardware. */
        u16                             card_id;
        u8                              card_rev;
@@ -70,10 +67,28 @@ static void free_if_spi_card(struct if_spi_card *card)
        kfree(card);
 }
 
-static struct chip_ident chip_id_to_device_name[] = {
-       { .chip_id = 0x04, .name = 8385 },
-       { .chip_id = 0x0b, .name = 8686 },
+#define MODEL_8385     0x04
+#define MODEL_8686     0x0b
+#define MODEL_8688     0x10
+
+static const struct lbs_fw_table fw_table[] = {
+       { MODEL_8385, "libertas/gspi8385_helper.bin", "libertas/gspi8385.bin" },
+       { MODEL_8385, "libertas/gspi8385_hlp.bin", "libertas/gspi8385.bin" },
+       { MODEL_8686, "libertas/gspi8686_v9_helper.bin", "libertas/gspi8686_v9.bin" },
+       { MODEL_8686, "libertas/gspi8686_hlp.bin", "libertas/gspi8686.bin" },
+       { MODEL_8688, "libertas/gspi8688_helper.bin", "libertas/gspi8688.bin" },
+       { 0, NULL, NULL }
 };
+MODULE_FIRMWARE("libertas/gspi8385_helper.bin");
+MODULE_FIRMWARE("libertas/gspi8385_hlp.bin");
+MODULE_FIRMWARE("libertas/gspi8385.bin");
+MODULE_FIRMWARE("libertas/gspi8686_v9_helper.bin");
+MODULE_FIRMWARE("libertas/gspi8686_v9.bin");
+MODULE_FIRMWARE("libertas/gspi8686_hlp.bin");
+MODULE_FIRMWARE("libertas/gspi8686.bin");
+MODULE_FIRMWARE("libertas/gspi8688_helper.bin");
+MODULE_FIRMWARE("libertas/gspi8688.bin");
+
 
 /*
  * SPI Interface Unit Routines
@@ -399,26 +414,20 @@ static int spu_init(struct if_spi_card *card, int use_dummy_writes)
  * Firmware Loading
  */
 
-static int if_spi_prog_helper_firmware(struct if_spi_card *card)
+static int if_spi_prog_helper_firmware(struct if_spi_card *card,
+                                       const struct firmware *firmware)
 {
        int err = 0;
-       const struct firmware *firmware = NULL;
        int bytes_remaining;
        const u8 *fw;
        u8 temp[HELPER_FW_LOAD_CHUNK_SZ];
-       struct spi_device *spi = card->spi;
 
        lbs_deb_enter(LBS_DEB_SPI);
 
        err = spu_set_interrupt_mode(card, 1, 0);
        if (err)
                goto out;
-       /* Get helper firmware image */
-       err = request_firmware(&firmware, card->helper_fw_name, &spi->dev);
-       if (err) {
-               lbs_pr_err("request_firmware failed with err = %d\n", err);
-               goto out;
-       }
+
        bytes_remaining = firmware->size;
        fw = firmware->data;
 
@@ -429,13 +438,13 @@ static int if_spi_prog_helper_firmware(struct if_spi_card *card)
                err = spu_write_u16(card, IF_SPI_SCRATCH_1_REG,
                                        HELPER_FW_LOAD_CHUNK_SZ);
                if (err)
-                       goto release_firmware;
+                       goto out;
 
                err = spu_wait_for_u16(card, IF_SPI_HOST_INT_STATUS_REG,
                                        IF_SPI_HIST_CMD_DOWNLOAD_RDY,
                                        IF_SPI_HIST_CMD_DOWNLOAD_RDY);
                if (err)
-                       goto release_firmware;
+                       goto out;
 
                /* Feed the data into the command read/write port reg
                 * in chunks of 64 bytes */
@@ -446,16 +455,16 @@ static int if_spi_prog_helper_firmware(struct if_spi_card *card)
                err = spu_write(card, IF_SPI_CMD_RDWRPORT_REG,
                                        temp, HELPER_FW_LOAD_CHUNK_SZ);
                if (err)
-                       goto release_firmware;
+                       goto out;
 
                /* Interrupt the boot code */
                err = spu_write_u16(card, IF_SPI_HOST_INT_STATUS_REG, 0);
                if (err)
-                       goto release_firmware;
+                       goto out;
                err = spu_write_u16(card, IF_SPI_CARD_INT_CAUSE_REG,
                                       IF_SPI_CIC_CMD_DOWNLOAD_OVER);
                if (err)
-                       goto release_firmware;
+                       goto out;
                bytes_remaining -= HELPER_FW_LOAD_CHUNK_SZ;
                fw += HELPER_FW_LOAD_CHUNK_SZ;
        }
@@ -465,18 +474,16 @@ static int if_spi_prog_helper_firmware(struct if_spi_card *card)
         * bootloader. This completes the helper download. */
        err = spu_write_u16(card, IF_SPI_SCRATCH_1_REG, FIRMWARE_DNLD_OK);
        if (err)
-               goto release_firmware;
+               goto out;
        err = spu_write_u16(card, IF_SPI_HOST_INT_STATUS_REG, 0);
        if (err)
-               goto release_firmware;
+               goto out;
        err = spu_write_u16(card, IF_SPI_CARD_INT_CAUSE_REG,
                                IF_SPI_CIC_CMD_DOWNLOAD_OVER);
-               goto release_firmware;
+               goto out;
 
        lbs_deb_spi("waiting for helper to boot...\n");
 
-release_firmware:
-       release_firmware(firmware);
 out:
        if (err)
                lbs_pr_err("failed to load helper firmware (err=%d)\n", err);
@@ -523,13 +530,12 @@ static int if_spi_prog_main_firmware_check_len(struct if_spi_card *card,
        return len;
 }
 
-static int if_spi_prog_main_firmware(struct if_spi_card *card)
+static int if_spi_prog_main_firmware(struct if_spi_card *card,
+                                       const struct firmware *firmware)
 {
        int len, prev_len;
        int bytes, crc_err = 0, err = 0;
-       const struct firmware *firmware = NULL;
        const u8 *fw;
-       struct spi_device *spi = card->spi;
        u16 num_crc_errs;
 
        lbs_deb_enter(LBS_DEB_SPI);
@@ -538,19 +544,11 @@ static int if_spi_prog_main_firmware(struct if_spi_card *card)
        if (err)
                goto out;
 
-       /* Get firmware image */
-       err = request_firmware(&firmware, card->main_fw_name, &spi->dev);
-       if (err) {
-               lbs_pr_err("%s: can't get firmware '%s' from kernel. "
-                       "err = %d\n", __func__, card->main_fw_name, err);
-               goto out;
-       }
-
        err = spu_wait_for_u16(card, IF_SPI_SCRATCH_1_REG, 0, 0);
        if (err) {
                lbs_pr_err("%s: timed out waiting for initial "
                           "scratch reg = 0\n", __func__);
-               goto release_firmware;
+               goto out;
        }
 
        num_crc_errs = 0;
@@ -560,7 +558,7 @@ static int if_spi_prog_main_firmware(struct if_spi_card *card)
        while ((len = if_spi_prog_main_firmware_check_len(card, &crc_err))) {
                if (len < 0) {
                        err = len;
-                       goto release_firmware;
+                       goto out;
                }
                if (bytes < 0) {
                        /* If there are no more bytes left, we would normally
@@ -575,7 +573,7 @@ static int if_spi_prog_main_firmware(struct if_spi_card *card)
                                lbs_pr_err("Too many CRC errors encountered "
                                           "in firmware load.\n");
                                err = -EIO;
-                               goto release_firmware;
+                               goto out;
                        }
                } else {
                        /* Previous transfer succeeded. Advance counters. */
@@ -590,15 +588,15 @@ static int if_spi_prog_main_firmware(struct if_spi_card *card)
 
                err = spu_write_u16(card, IF_SPI_HOST_INT_STATUS_REG, 0);
                if (err)
-                       goto release_firmware;
+                       goto out;
                err = spu_write(card, IF_SPI_CMD_RDWRPORT_REG,
                                card->cmd_buffer, len);
                if (err)
-                       goto release_firmware;
+                       goto out;
                err = spu_write_u16(card, IF_SPI_CARD_INT_CAUSE_REG ,
                                        IF_SPI_CIC_CMD_DOWNLOAD_OVER);
                if (err)
-                       goto release_firmware;
+                       goto out;
                prev_len = len;
        }
        if (bytes > prev_len) {
@@ -611,12 +609,9 @@ static int if_spi_prog_main_firmware(struct if_spi_card *card)
                                        SUCCESSFUL_FW_DOWNLOAD_MAGIC);
        if (err) {
                lbs_pr_err("failed to confirm the firmware download\n");
-               goto release_firmware;
+               goto out;
        }
 
-release_firmware:
-       release_firmware(firmware);
-
 out:
        if (err)
                lbs_pr_err("failed to load firmware (err=%d)\n", err);
@@ -800,14 +795,16 @@ static int lbs_spi_thread(void *data)
                        goto err;
                }
 
-               if (hiStatus & IF_SPI_HIST_CMD_UPLOAD_RDY)
+               if (hiStatus & IF_SPI_HIST_CMD_UPLOAD_RDY) {
                        err = if_spi_c2h_cmd(card);
                        if (err)
                                goto err;
-               if (hiStatus & IF_SPI_HIST_RX_UPLOAD_RDY)
+               }
+               if (hiStatus & IF_SPI_HIST_RX_UPLOAD_RDY) {
                        err = if_spi_c2h_data(card);
                        if (err)
                                goto err;
+               }
 
                /* workaround: in PS mode, the card does not set the Command
                 * Download Ready bit, but it sets TX Download Ready. */
@@ -886,37 +883,16 @@ static irqreturn_t if_spi_host_interrupt(int irq, void *dev_id)
  * SPI callbacks
  */
 
-static int if_spi_calculate_fw_names(u16 card_id,
-                             char *helper_fw, char *main_fw)
-{
-       int i;
-       for (i = 0; i < ARRAY_SIZE(chip_id_to_device_name); ++i) {
-               if (card_id == chip_id_to_device_name[i].chip_id)
-                       break;
-       }
-       if (i == ARRAY_SIZE(chip_id_to_device_name)) {
-               lbs_pr_err("Unsupported chip_id: 0x%02x\n", card_id);
-               return -EAFNOSUPPORT;
-       }
-       snprintf(helper_fw, IF_SPI_FW_NAME_MAX, "libertas/gspi%d_hlp.bin",
-                chip_id_to_device_name[i].name);
-       snprintf(main_fw, IF_SPI_FW_NAME_MAX, "libertas/gspi%d.bin",
-                chip_id_to_device_name[i].name);
-       return 0;
-}
-MODULE_FIRMWARE("libertas/gspi8385_hlp.bin");
-MODULE_FIRMWARE("libertas/gspi8385.bin");
-MODULE_FIRMWARE("libertas/gspi8686_hlp.bin");
-MODULE_FIRMWARE("libertas/gspi8686.bin");
-
 static int __devinit if_spi_probe(struct spi_device *spi)
 {
        struct if_spi_card *card;
        struct lbs_private *priv = NULL;
        struct libertas_spi_platform_data *pdata = spi->dev.platform_data;
-       int err = 0;
+       int err = 0, i;
        u32 scratch;
        struct sched_param param = { .sched_priority = 1 };
+       const struct firmware *helper = NULL;
+       const struct firmware *mainfw = NULL;
 
        lbs_deb_enter(LBS_DEB_SPI);
 
@@ -961,10 +937,25 @@ static int __devinit if_spi_probe(struct spi_device *spi)
                lbs_deb_spi("Firmware is already loaded for "
                            "Marvell WLAN 802.11 adapter\n");
        else {
-               err = if_spi_calculate_fw_names(card->card_id,
-                               card->helper_fw_name, card->main_fw_name);
-               if (err)
+               /* Check if we support this card */
+               for (i = 0; i < ARRAY_SIZE(fw_table); i++) {
+                       if (card->card_id == fw_table[i].model)
+                               break;
+               }
+               if (i == ARRAY_SIZE(fw_table)) {
+                       lbs_pr_err("Unsupported chip_id: 0x%02x\n",
+                                       card->card_id);
+                       err = -ENODEV;
                        goto free_card;
+               }
+
+               err = lbs_get_firmware(&card->spi->dev, NULL, NULL,
+                                       card->card_id, &fw_table[0], &helper,
+                                       &mainfw);
+               if (err) {
+                       lbs_pr_err("failed to find firmware (%d)\n", err);
+                       goto free_card;
+               }
 
                lbs_deb_spi("Initializing FW for Marvell WLAN 802.11 adapter "
                                "(chip_id = 0x%04x, chip_rev = 0x%02x) "
@@ -973,10 +964,10 @@ static int __devinit if_spi_probe(struct spi_device *spi)
                                card->card_id, card->card_rev,
                                spi->master->bus_num, spi->chip_select,
                                spi->max_speed_hz);
-               err = if_spi_prog_helper_firmware(card);
+               err = if_spi_prog_helper_firmware(card, helper);
                if (err)
                        goto free_card;
-               err = if_spi_prog_main_firmware(card);
+               err = if_spi_prog_main_firmware(card, mainfw);
                if (err)
                        goto free_card;
                lbs_deb_spi("loaded FW for Marvell WLAN 802.11 adapter\n");
@@ -1044,6 +1035,11 @@ remove_card:
 free_card:
        free_if_spi_card(card);
 out:
+       if (helper)
+               release_firmware(helper);
+       if (mainfw)
+               release_firmware(mainfw);
+
        lbs_deb_leave_args(LBS_DEB_SPI, "err %d\n", err);
        return err;
 }
index f87eec410848fb023416170c0241a84938949f55..8b1417d3b71b6a1533ff100bde95a7752e391893 100644 (file)
 
 #define IF_SPI_FW_NAME_MAX 30
 
-struct chip_ident {
-       u16 chip_id;
-       u16 name;
-};
-
 #define MAX_MAIN_FW_LOAD_CRC_ERR 10
 
 /* Chunk size when loading the helper firmware */
index 3ff61063671a099a944fd4fd840e62c582d9a7c6..e906616232a2f4bea102426dea77285637148046 100644 (file)
 
 #define MESSAGE_HEADER_LEN     4
 
-static char *lbs_fw_name = "usb8388.bin";
+static char *lbs_fw_name = NULL;
 module_param_named(fw_name, lbs_fw_name, charp, 0644);
 
+MODULE_FIRMWARE("libertas/usb8388_v9.bin");
+MODULE_FIRMWARE("libertas/usb8388_v5.bin");
+MODULE_FIRMWARE("libertas/usb8388.bin");
+MODULE_FIRMWARE("libertas/usb8682.bin");
 MODULE_FIRMWARE("usb8388.bin");
 
+enum {
+       MODEL_UNKNOWN = 0x0,
+       MODEL_8388 = 0x1,
+       MODEL_8682 = 0x2
+};
+
 static struct usb_device_id if_usb_table[] = {
        /* Enter the device signature inside */
-       { USB_DEVICE(0x1286, 0x2001) },
-       { USB_DEVICE(0x05a3, 0x8388) },
+       { USB_DEVICE(0x1286, 0x2001), .driver_info = MODEL_8388 },
+       { USB_DEVICE(0x05a3, 0x8388), .driver_info = MODEL_8388 },
        {}      /* Terminating entry */
 };
 
@@ -66,6 +76,8 @@ static ssize_t if_usb_firmware_set(struct device *dev,
        struct if_usb_card *cardp = priv->card;
        int ret;
 
+       BUG_ON(buf == NULL);
+
        ret = if_usb_prog_firmware(cardp, buf, BOOT_CMD_UPDATE_FW);
        if (ret == 0)
                return count;
@@ -91,6 +103,8 @@ static ssize_t if_usb_boot2_set(struct device *dev,
        struct if_usb_card *cardp = priv->card;
        int ret;
 
+       BUG_ON(buf == NULL);
+
        ret = if_usb_prog_firmware(cardp, buf, BOOT_CMD_UPDATE_BOOT2);
        if (ret == 0)
                return count;
@@ -244,6 +258,7 @@ static int if_usb_probe(struct usb_interface *intf,
        init_waitqueue_head(&cardp->fw_wq);
 
        cardp->udev = udev;
+       cardp->model = (uint32_t) id->driver_info;
        iface_desc = intf->cur_altsetting;
 
        lbs_deb_usbd(&udev->dev, "bcdUSB = 0x%X bDeviceClass = 0x%X"
@@ -924,6 +939,38 @@ static int if_usb_prog_firmware(struct if_usb_card *cardp,
        return ret;
 }
 
+/* table of firmware file names */
+static const struct {
+       u32 model;
+       const char *fwname;
+} fw_table[] = {
+       { MODEL_8388, "libertas/usb8388_v9.bin" },
+       { MODEL_8388, "libertas/usb8388_v5.bin" },
+       { MODEL_8388, "libertas/usb8388.bin" },
+       { MODEL_8388, "usb8388.bin" },
+       { MODEL_8682, "libertas/usb8682.bin" }
+};
+
+static int get_fw(struct if_usb_card *cardp, const char *fwname)
+{
+       int i;
+
+       /* Try user-specified firmware first */
+       if (fwname)
+               return request_firmware(&cardp->fw, fwname, &cardp->udev->dev);
+
+       /* Otherwise search for firmware to use */
+       for (i = 0; i < ARRAY_SIZE(fw_table); i++) {
+               if (fw_table[i].model != cardp->model)
+                       continue;
+               if (request_firmware(&cardp->fw, fw_table[i].fwname,
+                                       &cardp->udev->dev) == 0)
+                       return 0;
+       }
+
+       return -ENOENT;
+}
+
 static int __if_usb_prog_firmware(struct if_usb_card *cardp,
                                        const char *fwname, int cmd)
 {
@@ -933,10 +980,9 @@ static int __if_usb_prog_firmware(struct if_usb_card *cardp,
 
        lbs_deb_enter(LBS_DEB_USB);
 
-       ret = request_firmware(&cardp->fw, fwname, &cardp->udev->dev);
-       if (ret < 0) {
-               lbs_pr_err("request_firmware() failed with %#x\n", ret);
-               lbs_pr_err("firmware %s not found\n", fwname);
+       ret = get_fw(cardp, fwname);
+       if (ret) {
+               lbs_pr_err("failed to find firmware (%d)\n", ret);
                goto done;
        }
 
index 5ba0aee0eb2f7e6eac289583a990f51fc1daf2f6..d819e7e3c9aaff43c53d866d73547e6fdc0373fc 100644 (file)
@@ -43,6 +43,7 @@ struct bootcmdresp
 /** USB card description structure*/
 struct if_usb_card {
        struct usb_device *udev;
+       uint32_t model;  /* MODEL_* */
        struct urb *rx_urb, *tx_urb;
        struct lbs_private *priv;
 
index 24958a86747b3261d76c13d235b7f63211740ed8..47ce5a6ba120e9b9d707c56e93a79d35c1b5a3ea 100644 (file)
@@ -1047,6 +1047,111 @@ void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx)
 }
 EXPORT_SYMBOL_GPL(lbs_notify_command_response);
 
+/**
+ *  @brief Retrieves two-stage firmware
+ *
+ *  @param dev         A pointer to device structure
+ *  @param user_helper User-defined helper firmware file
+ *  @param user_mainfw User-defined main firmware file
+ *  @param card_model  Bus-specific card model ID used to filter firmware table
+ *                         elements
+ *  @param fw_table    Table of firmware file names and device model numbers
+ *                         terminated by an entry with a NULL helper name
+ *  @param helper      On success, the helper firmware; caller must free
+ *  @param mainfw      On success, the main firmware; caller must free
+ *
+ *  @return            0 on success, non-zero on failure
+ */
+int lbs_get_firmware(struct device *dev, const char *user_helper,
+                       const char *user_mainfw, u32 card_model,
+                       const struct lbs_fw_table *fw_table,
+                       const struct firmware **helper,
+                       const struct firmware **mainfw)
+{
+       const struct lbs_fw_table *iter;
+       int ret;
+
+       BUG_ON(helper == NULL);
+       BUG_ON(mainfw == NULL);
+
+       /* Try user-specified firmware first */
+       if (user_helper) {
+               ret = request_firmware(helper, user_helper, dev);
+               if (ret) {
+                       lbs_pr_err("couldn't find helper firmware %s",
+                                       user_helper);
+                       goto fail;
+               }
+       }
+       if (user_mainfw) {
+               ret = request_firmware(mainfw, user_mainfw, dev);
+               if (ret) {
+                       lbs_pr_err("couldn't find main firmware %s",
+                                       user_mainfw);
+                       goto fail;
+               }
+       }
+
+       if (*helper && *mainfw)
+               return 0;
+
+       /* Otherwise search for firmware to use.  If neither the helper or
+        * the main firmware were specified by the user, then we need to
+        * make sure that found helper & main are from the same entry in
+        * fw_table.
+        */
+       iter = fw_table;
+       while (iter && iter->helper) {
+               if (iter->model != card_model)
+                       goto next;
+
+               if (*helper == NULL) {
+                       ret = request_firmware(helper, iter->helper, dev);
+                       if (ret)
+                               goto next;
+
+                       /* If the device has one-stage firmware (ie cf8305) and
+                        * we've got it then we don't need to bother with the
+                        * main firmware.
+                        */
+                       if (iter->fwname == NULL)
+                               return 0;
+               }
+
+               if (*mainfw == NULL) {
+                       ret = request_firmware(mainfw, iter->fwname, dev);
+                       if (ret && !user_helper) {
+                               /* Clear the helper if it wasn't user-specified
+                                * and the main firmware load failed, to ensure
+                                * we don't have mismatched firmware pairs.
+                                */
+                               release_firmware(*helper);
+                               *helper = NULL;
+                       }
+               }
+
+               if (*helper && *mainfw)
+                       return 0;
+
+  next:
+               iter++;
+       }
+
+  fail:
+       /* Failed */
+       if (*helper) {
+               release_firmware(*helper);
+               *helper = NULL;
+       }
+       if (*mainfw) {
+               release_firmware(*mainfw);
+               *mainfw = NULL;
+       }
+
+       return -ENOENT;
+}
+EXPORT_SYMBOL_GPL(lbs_get_firmware);
+
 static int __init lbs_init_module(void)
 {
        lbs_deb_enter(LBS_DEB_MAIN);
index 41a4f214ade1271e66b526cc4c936daf2059736a..ba7d96584cb6695120e548763dc4be8a976066ec 100644 (file)
@@ -54,7 +54,7 @@ static int if_usb_reset_device(struct if_usb_card *cardp);
 /**
  *  if_usb_wrike_bulk_callback -  call back to handle URB status
  *
- *  @param urb                 pointer to urb structure
+ *  @param urb         pointer to urb structure
  */
 static void if_usb_write_bulk_callback(struct urb *urb)
 {
@@ -178,16 +178,19 @@ static int if_usb_probe(struct usb_interface *intf,
                                le16_to_cpu(endpoint->wMaxPacketSize);
                        cardp->ep_in = usb_endpoint_num(endpoint);
 
-                       lbtf_deb_usbd(&udev->dev, "in_endpoint = %d\n", cardp->ep_in);
-                       lbtf_deb_usbd(&udev->dev, "Bulk in size is %d\n", cardp->ep_in_size);
+                       lbtf_deb_usbd(&udev->dev, "in_endpoint = %d\n",
+                               cardp->ep_in);
+                       lbtf_deb_usbd(&udev->dev, "Bulk in size is %d\n",
+                               cardp->ep_in_size);
                } else if (usb_endpoint_is_bulk_out(endpoint)) {
                        cardp->ep_out_size =
                                le16_to_cpu(endpoint->wMaxPacketSize);
                        cardp->ep_out = usb_endpoint_num(endpoint);
 
-                       lbtf_deb_usbd(&udev->dev, "out_endpoint = %d\n", cardp->ep_out);
+                       lbtf_deb_usbd(&udev->dev, "out_endpoint = %d\n",
+                               cardp->ep_out);
                        lbtf_deb_usbd(&udev->dev, "Bulk out size is %d\n",
-                                     cardp->ep_out_size);
+                               cardp->ep_out_size);
                }
        }
        if (!cardp->ep_out_size || !cardp->ep_in_size) {
@@ -318,10 +321,12 @@ static int if_usb_send_fw_pkt(struct if_usb_card *cardp)
 
        if (fwdata->hdr.dnldcmd == cpu_to_le32(FW_HAS_DATA_TO_RECV)) {
                lbtf_deb_usb2(&cardp->udev->dev, "There are data to follow\n");
-               lbtf_deb_usb2(&cardp->udev->dev, "seqnum = %d totalbytes = %d\n",
-                            cardp->fwseqnum, cardp->totalbytes);
+               lbtf_deb_usb2(&cardp->udev->dev,
+                       "seqnum = %d totalbytes = %d\n",
+                       cardp->fwseqnum, cardp->totalbytes);
        } else if (fwdata->hdr.dnldcmd == cpu_to_le32(FW_HAS_LAST_BLOCK)) {
-               lbtf_deb_usb2(&cardp->udev->dev, "Host has finished FW downloading\n");
+               lbtf_deb_usb2(&cardp->udev->dev,
+                       "Host has finished FW downloading\n");
                lbtf_deb_usb2(&cardp->udev->dev, "Donwloading FW JUMP BLOCK\n");
 
                /* Host has finished FW downloading
@@ -367,7 +372,7 @@ EXPORT_SYMBOL_GPL(if_usb_reset_device);
 /**
  *  usb_tx_block - transfer data to the device
  *
- *  @priv      pointer to struct lbtf_private
+ *  @priv      pointer to struct lbtf_private
  *  @payload   pointer to payload data
  *  @nb                data length
  *  @data      non-zero for data, zero for commands
@@ -400,7 +405,8 @@ static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload,
        urb->transfer_flags |= URB_ZERO_PACKET;
 
        if (usb_submit_urb(urb, GFP_ATOMIC)) {
-               lbtf_deb_usbd(&cardp->udev->dev, "usb_submit_urb failed: %d\n", ret);
+               lbtf_deb_usbd(&cardp->udev->dev,
+                       "usb_submit_urb failed: %d\n", ret);
                goto tx_ret;
        }
 
@@ -438,10 +444,12 @@ static int __if_usb_submit_rx_urb(struct if_usb_card *cardp,
 
        cardp->rx_urb->transfer_flags |= URB_ZERO_PACKET;
 
-       lbtf_deb_usb2(&cardp->udev->dev, "Pointer for rx_urb %p\n", cardp->rx_urb);
+       lbtf_deb_usb2(&cardp->udev->dev, "Pointer for rx_urb %p\n",
+               cardp->rx_urb);
        ret = usb_submit_urb(cardp->rx_urb, GFP_ATOMIC);
        if (ret) {
-               lbtf_deb_usbd(&cardp->udev->dev, "Submit Rx URB failed: %d\n", ret);
+               lbtf_deb_usbd(&cardp->udev->dev,
+                       "Submit Rx URB failed: %d\n", ret);
                kfree_skb(skb);
                cardp->rx_skb = NULL;
                lbtf_deb_leave(LBTF_DEB_USB);
@@ -522,14 +530,14 @@ static void if_usb_receive_fwload(struct urb *urb)
                        }
                } else if (bcmdresp.cmd != BOOT_CMD_FW_BY_USB) {
                        pr_info("boot cmd response cmd_tag error (%d)\n",
-                                   bcmdresp.cmd);
+                               bcmdresp.cmd);
                } else if (bcmdresp.result != BOOT_CMD_RESP_OK) {
                        pr_info("boot cmd response result error (%d)\n",
-                                   bcmdresp.result);
+                               bcmdresp.result);
                } else {
                        cardp->bootcmdresp = 1;
                        lbtf_deb_usbd(&cardp->udev->dev,
-                                    "Received valid boot command response\n");
+                               "Received valid boot command response\n");
                }
 
                kfree_skb(skb);
@@ -541,19 +549,23 @@ static void if_usb_receive_fwload(struct urb *urb)
        syncfwheader = kmemdup(skb->data, sizeof(struct fwsyncheader),
                               GFP_ATOMIC);
        if (!syncfwheader) {
-               lbtf_deb_usbd(&cardp->udev->dev, "Failure to allocate syncfwheader\n");
+               lbtf_deb_usbd(&cardp->udev->dev,
+                       "Failure to allocate syncfwheader\n");
                kfree_skb(skb);
                lbtf_deb_leave(LBTF_DEB_USB);
                return;
        }
 
        if (!syncfwheader->cmd) {
-               lbtf_deb_usb2(&cardp->udev->dev, "FW received Blk with correct CRC\n");
-               lbtf_deb_usb2(&cardp->udev->dev, "FW received Blk seqnum = %d\n",
-                            le32_to_cpu(syncfwheader->seqnum));
+               lbtf_deb_usb2(&cardp->udev->dev,
+                       "FW received Blk with correct CRC\n");
+               lbtf_deb_usb2(&cardp->udev->dev,
+                       "FW received Blk seqnum = %d\n",
+                       le32_to_cpu(syncfwheader->seqnum));
                cardp->CRC_OK = 1;
        } else {
-               lbtf_deb_usbd(&cardp->udev->dev, "FW received Blk with CRC error\n");
+               lbtf_deb_usbd(&cardp->udev->dev,
+                       "FW received Blk with CRC error\n");
                cardp->CRC_OK = 0;
        }
 
@@ -666,7 +678,8 @@ static void if_usb_receive(struct urb *urb)
        {
                /* Event cause handling */
                u32 event_cause = le32_to_cpu(pkt[1]);
-               lbtf_deb_usbd(&cardp->udev->dev, "**EVENT** 0x%X\n", event_cause);
+               lbtf_deb_usbd(&cardp->udev->dev, "**EVENT** 0x%X\n",
+                       event_cause);
 
                /* Icky undocumented magic special case */
                if (event_cause & 0xffff0000) {
@@ -689,7 +702,7 @@ static void if_usb_receive(struct urb *urb)
        }
        default:
                lbtf_deb_usbd(&cardp->udev->dev,
-                        "libertastf: unknown command type 0x%X\n", recvtype);
+                       "libertastf: unknown command type 0x%X\n", recvtype);
                kfree_skb(skb);
                break;
        }
index 86fa8abdd66fda1cba26ef0e2bfe90a249d14128..92b486d46eb9fca3d7e53fa39102574156e4d24c 100644 (file)
@@ -9,7 +9,8 @@
 
 /*
  * TODO:
- * - IBSS mode simulation (Beacon transmission with competition for "air time")
+ * - Add TSF sync and fix IBSS beacon transmission by adding
+ *   competition for "air time" at TBTT
  * - RX filtering based on filter configuration (data->rx_filter)
  */
 
@@ -600,6 +601,18 @@ static int mac80211_hwsim_add_interface(struct ieee80211_hw *hw,
 }
 
 
+static int mac80211_hwsim_change_interface(struct ieee80211_hw *hw,
+                                          struct ieee80211_vif *vif,
+                                          enum nl80211_iftype newtype)
+{
+       wiphy_debug(hw->wiphy,
+                   "%s (old type=%d, new type=%d, mac_addr=%pM)\n",
+                   __func__, vif->type, newtype, vif->addr);
+       hwsim_check_magic(vif);
+
+       return 0;
+}
+
 static void mac80211_hwsim_remove_interface(
        struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 {
@@ -620,7 +633,8 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac,
        hwsim_check_magic(vif);
 
        if (vif->type != NL80211_IFTYPE_AP &&
-           vif->type != NL80211_IFTYPE_MESH_POINT)
+           vif->type != NL80211_IFTYPE_MESH_POINT &&
+           vif->type != NL80211_IFTYPE_ADHOC)
                return;
 
        skb = ieee80211_beacon_get(hw, vif);
@@ -1025,6 +1039,7 @@ static struct ieee80211_ops mac80211_hwsim_ops =
        .start = mac80211_hwsim_start,
        .stop = mac80211_hwsim_stop,
        .add_interface = mac80211_hwsim_add_interface,
+       .change_interface = mac80211_hwsim_change_interface,
        .remove_interface = mac80211_hwsim_remove_interface,
        .config = mac80211_hwsim_config,
        .configure_filter = mac80211_hwsim_configure_filter,
@@ -1295,6 +1310,7 @@ static int __init init_mac80211_hwsim(void)
                hw->wiphy->interface_modes =
                        BIT(NL80211_IFTYPE_STATION) |
                        BIT(NL80211_IFTYPE_AP) |
+                       BIT(NL80211_IFTYPE_ADHOC) |
                        BIT(NL80211_IFTYPE_MESH_POINT);
 
                hw->flags = IEEE80211_HW_MFP_CAPABLE |
index 077baa86756b07db035799d319fa366abdd01490..b4772c1c6135c40fcad9859b6510eff0e1224182 100644 (file)
@@ -762,14 +762,17 @@ int orinoco_hw_get_act_bitrate(struct orinoco_private *priv, int *bitrate)
        case FIRMWARE_TYPE_INTERSIL: /* Intersil style rate */
        case FIRMWARE_TYPE_SYMBOL: /* Symbol style rate */
                for (i = 0; i < BITRATE_TABLE_SIZE; i++)
-                       if (bitrate_table[i].intersil_txratectrl == val)
+                       if (bitrate_table[i].intersil_txratectrl == val) {
+                               *bitrate = bitrate_table[i].bitrate * 100000;
                                break;
+                       }
 
-               if (i >= BITRATE_TABLE_SIZE)
+               if (i >= BITRATE_TABLE_SIZE) {
                        printk(KERN_INFO "%s: Unable to determine current bitrate (0x%04hx)\n",
                               priv->ndev->name, val);
+                       err = -EIO;
+               }
 
-               *bitrate = bitrate_table[i].bitrate * 100000;
                break;
        default:
                BUG();
index cf7be1eb612495b699dc2e0cdc8fe17650c26736..93505f93bf97711019e86bbe27f39f4f727bce01 100644 (file)
@@ -589,8 +589,15 @@ static int orinoco_ioctl_getrate(struct net_device *dev,
 
        /* If the interface is running we try to find more about the
           current mode */
-       if (netif_running(dev))
-               err = orinoco_hw_get_act_bitrate(priv, &bitrate);
+       if (netif_running(dev)) {
+               int act_bitrate;
+               int lerr;
+
+               /* Ignore errors if we can't get the actual bitrate */
+               lerr = orinoco_hw_get_act_bitrate(priv, &act_bitrate);
+               if (!lerr)
+                       bitrate = act_bitrate;
+       }
 
        orinoco_unlock(priv, &flags);
 
index b0342a520bf160ca9daf2bd0df1a21406bad6f18..e5f45cb2a7a2334d839560d7c6366227f83c0030 100644 (file)
@@ -2,6 +2,7 @@ config P54_COMMON
        tristate "Softmac Prism54 support"
        depends on MAC80211 && EXPERIMENTAL
        select FW_LOADER
+       select CRC_CCITT
        ---help---
          This is common code for isl38xx/stlc45xx based modules.
          This module does nothing by itself - the USB/PCI/SPI front-ends
@@ -48,6 +49,23 @@ config P54_SPI
 
          If you choose to build a module, it'll be called p54spi.
 
+config P54_SPI_DEFAULT_EEPROM
+       bool "Include fallback EEPROM blob"
+       depends on P54_SPI
+       default n
+       ---help---
+        Unlike the PCI or USB devices, the SPI variants don't have
+        a dedicated EEPROM chip to store all device specific values
+        for calibration, country and interface settings.
+
+        The driver will try to load the image "3826.eeprom", if the
+        file is put at the right place. (usually /lib/firmware.)
+
+        Only if this request fails, this option will provide a
+        backup set of generic values to get the device working.
+
+        Enabling this option adds about 4k to p54spi.
+
 config P54_LEDS
        bool
        depends on P54_COMMON && MAC80211_LEDS && (LEDS_CLASS = y || LEDS_CLASS = P54_COMMON)
index 78347041ec40a3c51d094328495c8d86cb5c5a3b..8c05266d37f46f071760b7107c96357fa89c9ef2 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/slab.h>
 
 #include <net/mac80211.h>
+#include <linux/crc-ccitt.h>
 
 #include "p54.h"
 #include "eeprom.h"
@@ -540,6 +541,7 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
        int err;
        u8 *end = (u8 *)eeprom + len;
        u16 synth = 0;
+       u16 crc16 = ~0;
 
        wrap = (struct eeprom_pda_wrap *) eeprom;
        entry = (void *)wrap->data + le16_to_cpu(wrap->len);
@@ -655,16 +657,29 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
                        }
                        break;
                case PDR_END:
-                       /* make it overrun */
-                       entry_len = len;
+                       crc16 = ~crc_ccitt(crc16, (u8 *) entry, sizeof(*entry));
+                       if (crc16 != le16_to_cpup((__le16 *)entry->data)) {
+                               wiphy_err(dev->wiphy, "eeprom failed checksum "
+                                        "test!\n");
+                               err = -ENOMSG;
+                               goto err;
+                       } else {
+                               goto good_eeprom;
+                       }
                        break;
                default:
                        break;
                }
 
-               entry = (void *)entry + (entry_len + 1)*2;
+               crc16 = crc_ccitt(crc16, (u8 *)entry, (entry_len + 1) * 2);
+               entry = (void *)entry + (entry_len + 1) * 2;
        }
 
+       wiphy_err(dev->wiphy, "unexpected end of eeprom data.\n");
+       err = -ENODATA;
+       goto err;
+
+good_eeprom:
        if (!synth || !priv->iq_autocal || !priv->output_limit ||
            !priv->curve_data) {
                wiphy_err(dev->wiphy,
index 15b20c29a6042ae6e3dc5c99dae07e8c317127ca..92b9b1f05fd536d4ed529a73b92d1ea198189923 100644 (file)
@@ -123,10 +123,14 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
                bootrec = (struct bootrec *)&bootrec->data[len];
        }
 
-       if (fw_version)
+       if (fw_version) {
                wiphy_info(priv->hw->wiphy,
                           "FW rev %s - Softmac protocol %x.%x\n",
                           fw_version, priv->fw_var >> 8, priv->fw_var & 0xff);
+               snprintf(dev->wiphy->fw_version, sizeof(dev->wiphy->fw_version),
+                               "%s - %x.%x", fw_version,
+                               priv->fw_var >> 8, priv->fw_var & 0xff);
+       }
 
        if (priv->fw_var < 0x500)
                wiphy_info(priv->hw->wiphy,
index 47db439b63bfd9d3f2b9330095b4c4b606160479..622d27b6d8f214a1e69b92b93c4c570a7b22b8df 100644 (file)
@@ -429,8 +429,8 @@ static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd,
 
        mutex_lock(&priv->conf_mutex);
        if (cmd == SET_KEY) {
-               switch (key->alg) {
-               case ALG_TKIP:
+               switch (key->cipher) {
+               case WLAN_CIPHER_SUITE_TKIP:
                        if (!(priv->privacy_caps & (BR_DESC_PRIV_CAP_MICHAEL |
                              BR_DESC_PRIV_CAP_TKIP))) {
                                ret = -EOPNOTSUPP;
@@ -439,7 +439,8 @@ static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd,
                        key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
                        algo = P54_CRYPTO_TKIPMICHAEL;
                        break;
-               case ALG_WEP:
+               case WLAN_CIPHER_SUITE_WEP40:
+               case WLAN_CIPHER_SUITE_WEP104:
                        if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_WEP)) {
                                ret = -EOPNOTSUPP;
                                goto out_unlock;
@@ -447,7 +448,7 @@ static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd,
                        key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
                        algo = P54_CRYPTO_WEP;
                        break;
-               case ALG_CCMP:
+               case WLAN_CIPHER_SUITE_CCMP:
                        if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP)) {
                                ret = -EOPNOTSUPP;
                                goto out_unlock;
index 087bf0698a5af7aee75a8c47fac852fe4cd35fa1..156e57dbd2cfa858df969ab3e98c8476f173ee89 100644 (file)
 #include <linux/slab.h>
 
 #include "p54spi.h"
-#include "p54spi_eeprom.h"
 #include "p54.h"
 
 #include "lmac.h"
 
+#ifdef CONFIG_P54_SPI_DEFAULT_EEPROM
+#include "p54spi_eeprom.h"
+#endif /* CONFIG_P54_SPI_DEFAULT_EEPROM */
+
 MODULE_FIRMWARE("3826.arm");
 MODULE_ALIAS("stlc45xx");
 
@@ -195,9 +198,11 @@ static int p54spi_request_eeprom(struct ieee80211_hw *dev)
 
        ret = request_firmware(&eeprom, "3826.eeprom", &priv->spi->dev);
        if (ret < 0) {
+#ifdef CONFIG_P54_SPI_DEFAULT_EEPROM
                dev_info(&priv->spi->dev, "loading default eeprom...\n");
                ret = p54_parse_eeprom(dev, (void *) p54spi_eeprom,
                                       sizeof(p54spi_eeprom));
+#endif /* CONFIG_P54_SPI_DEFAULT_EEPROM */
        } else {
                dev_info(&priv->spi->dev, "loading user eeprom...\n");
                ret = p54_parse_eeprom(dev, (void *) eeprom->data,
index 1ea1050911d97a54c456e566c6b539e249af8f29..d592cbd34d78069911d0fc9c12dca390b09e970a 100644 (file)
@@ -671,7 +671,7 @@ static unsigned char p54spi_eeprom[] = {
        0xa8, 0x09, 0x25, 0x00, 0xf5, 0xff, 0xf9, 0xff, 0x00, 0x01,
 
 0x02, 0x00, 0x00, 0x00,                /* PDR_END */
-       0xa8, 0xf5                      /* bogus data */
+       0x67, 0x99,
 };
 
 #endif /* P54SPI_EEPROM_H */
index ad595958b7df19f144a38671cc0424551aaba709..063248b350692f13b6948e63722e28b4b634434d 100644 (file)
@@ -930,8 +930,8 @@ static int __devinit p54u_probe(struct usb_interface *intf,
 #ifdef CONFIG_PM
                /* ISL3887 needs a full reset on resume */
                udev->reset_resume = 1;
+#endif /* CONFIG_PM */
                err = p54u_device_reset(dev);
-#endif
 
                priv->hw_type = P54U_3887;
                dev->extra_tx_headroom += sizeof(struct lm87_tx_hdr);
index 0e937dc0c9c41df6cff985c6b538f6cb17cf1091..76b2318a7dc776a460c335133289953cff8806fc 100644 (file)
@@ -275,15 +275,15 @@ static int p54_rssi_to_dbm(struct p54_common *priv, int rssi)
 {
        int band = priv->hw->conf.channel->band;
 
-       if (priv->rxhw != 5)
+       if (priv->rxhw != 5) {
                return ((rssi * priv->rssical_db[band].mul) / 64 +
                         priv->rssical_db[band].add) / 4;
-       else
+       } else {
                /*
                 * TODO: find the correct formula
                 */
-               return ((rssi * priv->rssical_db[band].mul) / 64 +
-                        priv->rssical_db[band].add) / 4;
+               return rssi / 2 - 110;
+       }
 }
 
 /*
@@ -683,14 +683,15 @@ static void p54_tx_80211_header(struct p54_common *priv, struct sk_buff *skb,
        }
 }
 
-static u8 p54_convert_algo(enum ieee80211_key_alg alg)
+static u8 p54_convert_algo(u32 cipher)
 {
-       switch (alg) {
-       case ALG_WEP:
+       switch (cipher) {
+       case WLAN_CIPHER_SUITE_WEP40:
+       case WLAN_CIPHER_SUITE_WEP104:
                return P54_CRYPTO_WEP;
-       case ALG_TKIP:
+       case WLAN_CIPHER_SUITE_TKIP:
                return P54_CRYPTO_TKIPMICHAEL;
-       case ALG_CCMP:
+       case WLAN_CIPHER_SUITE_CCMP:
                return P54_CRYPTO_AESCCMP;
        default:
                return 0;
@@ -731,7 +732,7 @@ int p54_tx_80211(struct ieee80211_hw *dev, struct sk_buff *skb)
 
        if (info->control.hw_key) {
                crypt_offset = ieee80211_get_hdrlen_from_skb(skb);
-               if (info->control.hw_key->alg == ALG_TKIP) {
+               if (info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) {
                        u8 *iv = (u8 *)(skb->data + crypt_offset);
                        /*
                         * The firmware excepts that the IV has to have
@@ -827,10 +828,10 @@ int p54_tx_80211(struct ieee80211_hw *dev, struct sk_buff *skb)
        hdr->tries = ridx;
        txhdr->rts_rate_idx = 0;
        if (info->control.hw_key) {
-               txhdr->key_type = p54_convert_algo(info->control.hw_key->alg);
+               txhdr->key_type = p54_convert_algo(info->control.hw_key->cipher);
                txhdr->key_len = min((u8)16, info->control.hw_key->keylen);
                memcpy(txhdr->key, info->control.hw_key->key, txhdr->key_len);
-               if (info->control.hw_key->alg == ALG_TKIP) {
+               if (info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) {
                        /* reserve space for the MIC key */
                        len += 8;
                        memcpy(skb_put(skb, 8), &(info->control.hw_key->key
index 77cd65db8500b2363496721702777cd280e3bb15..d97a2caf582b3997f2378434117758a928cefbd3 100644 (file)
@@ -3234,7 +3234,7 @@ prism54_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
        switch (cmd) {
                case PRISM54_HOSTAPD:
                if (!capable(CAP_NET_ADMIN))
-               return -EPERM;
+                       return -EPERM;
                ret = prism54_hostapd(ndev, &wrq->u.data);
                return ret;
        }
index 88560d0ae50a2457d1373103db85b98ebb61211e..d91a831a7700b0509f40e4ff1b445a7b9923abac 100644 (file)
@@ -43,7 +43,6 @@
 #include <linux/if_arp.h>
 #include <linux/ioport.h>
 #include <linux/skbuff.h>
-#include <linux/ethtool.h>
 #include <linux/ieee80211.h>
 
 #include <pcmcia/cs.h>
@@ -80,8 +79,6 @@ static int ray_dev_config(struct net_device *dev, struct ifmap *map);
 static struct net_device_stats *ray_get_stats(struct net_device *dev);
 static int ray_dev_init(struct net_device *dev);
 
-static const struct ethtool_ops netdev_ethtool_ops;
-
 static int ray_open(struct net_device *dev);
 static netdev_tx_t ray_dev_start_xmit(struct sk_buff *skb,
                                            struct net_device *dev);
@@ -333,7 +330,6 @@ static int ray_probe(struct pcmcia_device *p_dev)
 
        /* Raylink entries in the device structure */
        dev->netdev_ops = &ray_netdev_ops;
-       SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
        dev->wireless_handlers = &ray_handler_def;
 #ifdef WIRELESS_SPY
        local->wireless_data.spy_data = &local->spy_data;
@@ -608,7 +604,7 @@ static int dl_startup_params(struct net_device *dev)
        /* Start kernel timer to wait for dl startup to complete. */
        local->timer.expires = jiffies + HZ / 2;
        local->timer.data = (long)local;
-       local->timer.function = &verify_dl_startup;
+       local->timer.function = verify_dl_startup;
        add_timer(&local->timer);
        dev_dbg(&link->dev,
              "ray_cs dl_startup_params started timer for verify_dl_startup\n");
@@ -1062,18 +1058,6 @@ AP to AP 1       1       dest AP         src AP          dest    source
        }
 } /* end encapsulate_frame */
 
-/*===========================================================================*/
-
-static void netdev_get_drvinfo(struct net_device *dev,
-                              struct ethtool_drvinfo *info)
-{
-       strcpy(info->driver, "ray_cs");
-}
-
-static const struct ethtool_ops netdev_ethtool_ops = {
-       .get_drvinfo = netdev_get_drvinfo,
-};
-
 /*====================================================================*/
 
 /*------------------------------------------------------------------*/
@@ -1997,12 +1981,12 @@ static irqreturn_t ray_interrupt(int irq, void *dev_id)
                                        dev_dbg(&link->dev,
                                              "ray_cs interrupt network \"%s\" start failed\n",
                                              local->sparm.b4.a_current_ess_id);
-                                       local->timer.function = &start_net;
+                                       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);
-                                       local->timer.function = &join_net;
+                                       local->timer.function = join_net;
                                }
                                add_timer(&local->timer);
                        }
@@ -2470,9 +2454,9 @@ static void authenticate(ray_dev_t *local)
 
        del_timer(&local->timer);
        if (build_auth_frame(local, local->bss_id, OPEN_AUTH_REQUEST)) {
-               local->timer.function = &join_net;
+               local->timer.function = join_net;
        } else {
-               local->timer.function = &authenticate_timeout;
+               local->timer.function = authenticate_timeout;
        }
        local->timer.expires = jiffies + HZ * 2;
        local->timer.data = (long)local;
@@ -2557,7 +2541,7 @@ static void associate(ray_dev_t *local)
                del_timer(&local->timer);
                local->timer.expires = jiffies + HZ * 2;
                local->timer.data = (long)local;
-               local->timer.function = &join_net;
+               local->timer.function = join_net;
                add_timer(&local->timer);
                local->card_status = CARD_ASSOC_FAILED;
                return;
index 5063e01410e5b76640946aea9d1722d0543c2aa5..103c71164f109d05f7b87fc77b479ae856f7502d 100644 (file)
@@ -1007,12 +1007,11 @@ static int rt2400pci_set_device_state(struct rt2x00_dev *rt2x00dev,
 /*
  * TX descriptor initialization
  */
-static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
-                                   struct sk_buff *skb,
+static void rt2400pci_write_tx_desc(struct queue_entry *entry,
                                    struct txentry_desc *txdesc)
 {
-       struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
-       struct queue_entry_priv_pci *entry_priv = skbdesc->entry->priv_data;
+       struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
+       struct queue_entry_priv_pci *entry_priv = entry->priv_data;
        __le32 *txd = entry_priv->desc;
        u32 word;
 
@@ -1096,7 +1095,7 @@ static void rt2400pci_write_beacon(struct queue_entry *entry,
        /*
         * Write the TX descriptor for the beacon.
         */
-       rt2400pci_write_tx_desc(rt2x00dev, entry->skb, txdesc);
+       rt2400pci_write_tx_desc(entry, txdesc);
 
        /*
         * Dump beacon to userspace through debugfs.
@@ -1112,24 +1111,24 @@ static void rt2400pci_write_beacon(struct queue_entry *entry,
        rt2x00pci_register_write(rt2x00dev, CSR14, reg);
 }
 
-static void rt2400pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
-                                   const enum data_queue_qid queue)
+static void rt2400pci_kick_tx_queue(struct data_queue *queue)
 {
+       struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
        u32 reg;
 
        rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
-       rt2x00_set_field32(&reg, TXCSR0_KICK_PRIO, (queue == QID_AC_BE));
-       rt2x00_set_field32(&reg, TXCSR0_KICK_TX, (queue == QID_AC_BK));
-       rt2x00_set_field32(&reg, TXCSR0_KICK_ATIM, (queue == QID_ATIM));
+       rt2x00_set_field32(&reg, TXCSR0_KICK_PRIO, (queue->qid == QID_AC_BE));
+       rt2x00_set_field32(&reg, TXCSR0_KICK_TX, (queue->qid == QID_AC_BK));
+       rt2x00_set_field32(&reg, TXCSR0_KICK_ATIM, (queue->qid == QID_ATIM));
        rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
 }
 
-static void rt2400pci_kill_tx_queue(struct rt2x00_dev *rt2x00dev,
-                                   const enum data_queue_qid qid)
+static void rt2400pci_kill_tx_queue(struct data_queue *queue)
 {
+       struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
        u32 reg;
 
-       if (qid == QID_BEACON) {
+       if (queue->qid == QID_BEACON) {
                rt2x00pci_register_write(rt2x00dev, CSR14, 0);
        } else {
                rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
@@ -1481,15 +1480,17 @@ static int rt2400pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
        /*
         * Create channel information array
         */
-       info = kzalloc(spec->num_channels * sizeof(*info), GFP_KERNEL);
+       info = kcalloc(spec->num_channels, sizeof(*info), GFP_KERNEL);
        if (!info)
                return -ENOMEM;
 
        spec->channels_info = info;
 
        tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_START);
-       for (i = 0; i < 14; i++)
-               info[i].tx_power1 = TXPOWER_FROM_DEV(tx_power[i]);
+       for (i = 0; i < 14; i++) {
+               info[i].max_power = TXPOWER_FROM_DEV(MAX_TXPOWER);
+               info[i].default_power1 = TXPOWER_FROM_DEV(tx_power[i]);
+       }
 
        return 0;
 }
index c2a555d5376b3bbe4738813225a695d8fd81eac0..ab0507110e423b2cd2afbd79b50c1277f29a9661 100644 (file)
@@ -1161,12 +1161,11 @@ static int rt2500pci_set_device_state(struct rt2x00_dev *rt2x00dev,
 /*
  * TX descriptor initialization
  */
-static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
-                                   struct sk_buff *skb,
+static void rt2500pci_write_tx_desc(struct queue_entry *entry,
                                    struct txentry_desc *txdesc)
 {
-       struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
-       struct queue_entry_priv_pci *entry_priv = skbdesc->entry->priv_data;
+       struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
+       struct queue_entry_priv_pci *entry_priv = entry->priv_data;
        __le32 *txd = entry_priv->desc;
        u32 word;
 
@@ -1249,7 +1248,7 @@ static void rt2500pci_write_beacon(struct queue_entry *entry,
        /*
         * Write the TX descriptor for the beacon.
         */
-       rt2500pci_write_tx_desc(rt2x00dev, entry->skb, txdesc);
+       rt2500pci_write_tx_desc(entry, txdesc);
 
        /*
         * Dump beacon to userspace through debugfs.
@@ -1265,24 +1264,24 @@ static void rt2500pci_write_beacon(struct queue_entry *entry,
        rt2x00pci_register_write(rt2x00dev, CSR14, reg);
 }
 
-static void rt2500pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
-                                   const enum data_queue_qid queue)
+static void rt2500pci_kick_tx_queue(struct data_queue *queue)
 {
+       struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
        u32 reg;
 
        rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
-       rt2x00_set_field32(&reg, TXCSR0_KICK_PRIO, (queue == QID_AC_BE));
-       rt2x00_set_field32(&reg, TXCSR0_KICK_TX, (queue == QID_AC_BK));
-       rt2x00_set_field32(&reg, TXCSR0_KICK_ATIM, (queue == QID_ATIM));
+       rt2x00_set_field32(&reg, TXCSR0_KICK_PRIO, (queue->qid == QID_AC_BE));
+       rt2x00_set_field32(&reg, TXCSR0_KICK_TX, (queue->qid == QID_AC_BK));
+       rt2x00_set_field32(&reg, TXCSR0_KICK_ATIM, (queue->qid == QID_ATIM));
        rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
 }
 
-static void rt2500pci_kill_tx_queue(struct rt2x00_dev *rt2x00dev,
-                                   const enum data_queue_qid qid)
+static void rt2500pci_kill_tx_queue(struct data_queue *queue)
 {
+       struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
        u32 reg;
 
-       if (qid == QID_BEACON) {
+       if (queue->qid == QID_BEACON) {
                rt2x00pci_register_write(rt2x00dev, CSR14, 0);
        } else {
                rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
@@ -1795,19 +1794,23 @@ static int rt2500pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
        /*
         * Create channel information array
         */
-       info = kzalloc(spec->num_channels * sizeof(*info), GFP_KERNEL);
+       info = kcalloc(spec->num_channels, sizeof(*info), GFP_KERNEL);
        if (!info)
                return -ENOMEM;
 
        spec->channels_info = info;
 
        tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_START);
-       for (i = 0; i < 14; i++)
-               info[i].tx_power1 = TXPOWER_FROM_DEV(tx_power[i]);
+       for (i = 0; i < 14; i++) {
+               info[i].max_power = MAX_TXPOWER;
+               info[i].default_power1 = TXPOWER_FROM_DEV(tx_power[i]);
+       }
 
        if (spec->num_channels > 14) {
-               for (i = 14; i < spec->num_channels; i++)
-                       info[i].tx_power1 = DEFAULT_TXPOWER;
+               for (i = 14; i < spec->num_channels; i++) {
+                       info[i].max_power = MAX_TXPOWER;
+                       info[i].default_power1 = DEFAULT_TXPOWER;
+               }
        }
 
        return 0;
index cdaf93f48263c012649b30d6b72604ac0b853f64..db64df4267d8b77a7619374a341c40178f6f72fc 100644 (file)
@@ -355,7 +355,9 @@ static int rt2500usb_config_key(struct rt2x00_dev *rt2x00dev,
                 * it is known that not work at least on some hardware.
                 * SW crypto will be used in that case.
                 */
-               if (key->alg == ALG_WEP && key->keyidx != 0)
+               if ((key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
+                    key->cipher == WLAN_CIPHER_SUITE_WEP104) &&
+                   key->keyidx != 0)
                        return -EOPNOTSUPP;
 
                /*
@@ -1039,12 +1041,11 @@ static int rt2500usb_set_device_state(struct rt2x00_dev *rt2x00dev,
 /*
  * TX descriptor initialization
  */
-static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
-                                   struct sk_buff *skb,
+static void rt2500usb_write_tx_desc(struct queue_entry *entry,
                                    struct txentry_desc *txdesc)
 {
-       struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
-       __le32 *txd = (__le32 *) skb->data;
+       struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
+       __le32 *txd = (__le32 *) entry->skb->data;
        u32 word;
 
        /*
@@ -1127,7 +1128,7 @@ static void rt2500usb_write_beacon(struct queue_entry *entry,
        /*
         * Write the TX descriptor for the beacon.
         */
-       rt2500usb_write_tx_desc(rt2x00dev, entry->skb, txdesc);
+       rt2500usb_write_tx_desc(entry, txdesc);
 
        /*
         * Dump beacon to userspace through debugfs.
@@ -1195,6 +1196,14 @@ static int rt2500usb_get_tx_data_len(struct queue_entry *entry)
        return length;
 }
 
+static void rt2500usb_kill_tx_queue(struct data_queue *queue)
+{
+       if (queue->qid == QID_BEACON)
+               rt2500usb_register_write(queue->rt2x00dev, TXRX_CSR19, 0);
+
+       rt2x00usb_kill_tx_queue(queue);
+}
+
 /*
  * RX control handlers
  */
@@ -1698,19 +1707,23 @@ static int rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
        /*
         * Create channel information array
         */
-       info = kzalloc(spec->num_channels * sizeof(*info), GFP_KERNEL);
+       info = kcalloc(spec->num_channels, sizeof(*info), GFP_KERNEL);
        if (!info)
                return -ENOMEM;
 
        spec->channels_info = info;
 
        tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_START);
-       for (i = 0; i < 14; i++)
-               info[i].tx_power1 = TXPOWER_FROM_DEV(tx_power[i]);
+       for (i = 0; i < 14; i++) {
+               info[i].max_power = MAX_TXPOWER;
+               info[i].default_power1 = TXPOWER_FROM_DEV(tx_power[i]);
+       }
 
        if (spec->num_channels > 14) {
-               for (i = 14; i < spec->num_channels; i++)
-                       info[i].tx_power1 = DEFAULT_TXPOWER;
+               for (i = 14; i < spec->num_channels; i++) {
+                       info[i].max_power = MAX_TXPOWER;
+                       info[i].default_power1 = DEFAULT_TXPOWER;
+               }
        }
 
        return 0;
@@ -1789,7 +1802,7 @@ static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = {
        .write_beacon           = rt2500usb_write_beacon,
        .get_tx_data_len        = rt2500usb_get_tx_data_len,
        .kick_tx_queue          = rt2x00usb_kick_tx_queue,
-       .kill_tx_queue          = rt2x00usb_kill_tx_queue,
+       .kill_tx_queue          = rt2500usb_kill_tx_queue,
        .fill_rxdone            = rt2500usb_fill_rxdone,
        .config_shared_key      = rt2500usb_config_key,
        .config_pairwise_key    = rt2500usb_config_key,
index ed4ebcdde7c9c4155c58807cd5aae839a39ea63e..70a5cb86405b14b0589199700f137e43df771953 100644 (file)
 #define TX_STA_CNT2_TX_UNDER_FLOW_COUNT        FIELD32(0xffff0000)
 
 /*
- * TX_STA_FIFO: TX Result for specific PID status fifo register
+ * TX_STA_FIFO: TX Result for specific PID status fifo register.
+ *
+ * This register is implemented as FIFO with 16 entries in the HW. Each
+ * register read fetches the next tx result. If the FIFO is full because
+ * it wasn't read fast enough after the according interrupt (TX_FIFO_STATUS)
+ * triggered, the hw seems to simply drop further tx results.
+ *
+ * VALID: 1: this tx result is valid
+ *        0: no valid tx result -> driver should stop reading
+ * PID_TYPE: The PID latched from the PID field in the TXWI, can be used
+ *           to match a frame with its tx result (even though the PID is
+ *           only 4 bits wide).
+ * TX_SUCCESS: Indicates tx success (1) or failure (0)
+ * TX_AGGRE: Indicates if the frame was part of an aggregate (1) or not (0)
+ * TX_ACK_REQUIRED: Indicates if the frame needed to get ack'ed (1) or not (0)
+ * WCID: The wireless client ID.
+ * MCS: The tx rate used during the last transmission of this frame, be it
+ *      successful or not.
+ * PHYMODE: The phymode used for the transmission.
  */
 #define TX_STA_FIFO                    0x1718
 #define TX_STA_FIFO_VALID              FIELD32(0x00000001)
@@ -1840,6 +1858,13 @@ struct mac_iveiv_entry {
 #define EEPROM_RSSI_A2_OFFSET2         FIELD16(0x00ff)
 #define EEPROM_RSSI_A2_LNA_A2          FIELD16(0xff00)
 
+/*
+ * EEPROM Maximum TX power values
+ */
+#define EEPROM_MAX_TX_POWER            0x0027
+#define EEPROM_MAX_TX_POWER_24GHZ      FIELD16(0x00ff)
+#define EEPROM_MAX_TX_POWER_5GHZ       FIELD16(0xff00)
+
 /*
  * EEPROM TXpower delta: 20MHZ AND 40 MHZ use different power.
  *     This is delta in 40MHZ.
@@ -1928,6 +1953,8 @@ struct mac_iveiv_entry {
  * TX_OP: 0:HT TXOP rule , 1:PIFS TX ,2:Backoff, 3:sifs
  * BW: Channel bandwidth 20MHz or 40 MHz
  * STBC: 1: STBC support MCS =0-7, 2,3 : RESERVED
+ * AMPDU: 1: this frame is eligible for AMPDU aggregation, the hw will
+ *        aggregate consecutive frames with the same RA and QoS TID.
  */
 #define TXWI_W0_FRAG                   FIELD32(0x00000001)
 #define TXWI_W0_MIMO_PS                        FIELD32(0x00000002)
@@ -1945,6 +1972,15 @@ struct mac_iveiv_entry {
 
 /*
  * Word1
+ * ACK: 0: No Ack needed, 1: Ack needed
+ * NSEQ: 0: Don't assign hw sequence number, 1: Assign hw sequence number
+ * BW_WIN_SIZE: BA windows size of the recipient
+ * WIRELESS_CLI_ID: Client ID for WCID table access
+ * MPDU_TOTAL_BYTE_COUNT: Length of 802.11 frame
+ * PACKETID: Will be latched into the TX_STA_FIFO register once the according
+ *           frame was processed. If multiple frames are aggregated together
+ *           (AMPDU==1) the reported tx status will always contain the packet
+ *           id of the first frame. 0: Don't report tx status for this frame.
  */
 #define TXWI_W1_ACK                    FIELD32(0x00000001)
 #define TXWI_W1_NSEQ                   FIELD32(0x00000002)
index b66e0fd8f0fa178f2d18544a2dc3e192c7c00b93..27a6e225083c94211f3a7109e595df74cfac9d4a 100644 (file)
@@ -1,4 +1,5 @@
 /*
+       Copyright (C) 2010 Willow Garage <http://www.willowgarage.com>
        Copyright (C) 2010 Ivo van Doorn <IvDoorn@gmail.com>
        Copyright (C) 2009 Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
        Copyright (C) 2009 Gertjan van Wingerde <gwingerde@gmail.com>
@@ -254,6 +255,23 @@ void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev,
 }
 EXPORT_SYMBOL_GPL(rt2800_mcu_request);
 
+int rt2800_wait_csr_ready(struct rt2x00_dev *rt2x00dev)
+{
+       unsigned int i = 0;
+       u32 reg;
+
+       for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+               rt2800_register_read(rt2x00dev, MAC_CSR0, &reg);
+               if (reg && reg != ~0)
+                       return 0;
+               msleep(1);
+       }
+
+       ERROR(rt2x00dev, "Unstable hardware.\n");
+       return -EBUSY;
+}
+EXPORT_SYMBOL_GPL(rt2800_wait_csr_ready);
+
 int rt2800_wait_wpdma_ready(struct rt2x00_dev *rt2x00dev)
 {
        unsigned int i;
@@ -367,19 +385,16 @@ int rt2800_load_firmware(struct rt2x00_dev *rt2x00dev,
        u32 reg;
 
        /*
-        * Wait for stable hardware.
+        * If driver doesn't wake up firmware here,
+        * rt2800_load_firmware will hang forever when interface is up again.
         */
-       for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
-               rt2800_register_read(rt2x00dev, MAC_CSR0, &reg);
-               if (reg && reg != ~0)
-                       break;
-               msleep(1);
-       }
+       rt2800_register_write(rt2x00dev, AUTOWAKEUP_CFG, 0x00000000);
 
-       if (i == REGISTER_BUSY_COUNT) {
-               ERROR(rt2x00dev, "Unstable hardware.\n");
+       /*
+        * Wait for stable hardware.
+        */
+       if (rt2800_wait_csr_ready(rt2x00dev))
                return -EBUSY;
-       }
 
        if (rt2x00_is_pci(rt2x00dev))
                rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000002);
@@ -427,8 +442,10 @@ int rt2800_load_firmware(struct rt2x00_dev *rt2x00dev,
 }
 EXPORT_SYMBOL_GPL(rt2800_load_firmware);
 
-void rt2800_write_txwi(__le32 *txwi, struct txentry_desc *txdesc)
+void rt2800_write_tx_data(struct queue_entry *entry,
+                         struct txentry_desc *txdesc)
 {
+       __le32 *txwi = rt2800_drv_get_txwi(entry);
        u32 word;
 
        /*
@@ -437,7 +454,8 @@ void rt2800_write_txwi(__le32 *txwi, struct txentry_desc *txdesc)
        rt2x00_desc_read(txwi, 0, &word);
        rt2x00_set_field32(&word, TXWI_W0_FRAG,
                           test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags));
-       rt2x00_set_field32(&word, TXWI_W0_MIMO_PS, 0);
+       rt2x00_set_field32(&word, TXWI_W0_MIMO_PS,
+                          test_bit(ENTRY_TXD_HT_MIMO_PS, &txdesc->flags));
        rt2x00_set_field32(&word, TXWI_W0_CF_ACK, 0);
        rt2x00_set_field32(&word, TXWI_W0_TS,
                           test_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags));
@@ -465,7 +483,7 @@ void rt2800_write_txwi(__le32 *txwi, struct txentry_desc *txdesc)
                           txdesc->key_idx : 0xff);
        rt2x00_set_field32(&word, TXWI_W1_MPDU_TOTAL_BYTE_COUNT,
                           txdesc->length);
-       rt2x00_set_field32(&word, TXWI_W1_PACKETID, txdesc->queue + 1);
+       rt2x00_set_field32(&word, TXWI_W1_PACKETID, txdesc->qid + 1);
        rt2x00_desc_write(txwi, 1, word);
 
        /*
@@ -478,7 +496,7 @@ void rt2800_write_txwi(__le32 *txwi, struct txentry_desc *txdesc)
        _rt2x00_desc_write(txwi, 2, 0 /* skbdesc->iv[0] */);
        _rt2x00_desc_write(txwi, 3, 0 /* skbdesc->iv[1] */);
 }
-EXPORT_SYMBOL_GPL(rt2800_write_txwi);
+EXPORT_SYMBOL_GPL(rt2800_write_tx_data);
 
 static int rt2800_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxwi_w2)
 {
@@ -490,7 +508,7 @@ static int rt2800_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxwi_w2)
        u8 offset1;
        u8 offset2;
 
-       if (rt2x00dev->rx_status.band == IEEE80211_BAND_2GHZ) {
+       if (rt2x00dev->curr_band == IEEE80211_BAND_2GHZ) {
                rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_BG, &eeprom);
                offset0 = rt2x00_get_field16(eeprom, EEPROM_RSSI_BG_OFFSET0);
                offset1 = rt2x00_get_field16(eeprom, EEPROM_RSSI_BG_OFFSET1);
@@ -569,6 +587,148 @@ void rt2800_process_rxwi(struct queue_entry *entry,
 }
 EXPORT_SYMBOL_GPL(rt2800_process_rxwi);
 
+static bool rt2800_txdone_entry_check(struct queue_entry *entry, u32 reg)
+{
+       __le32 *txwi;
+       u32 word;
+       int wcid, ack, pid;
+       int tx_wcid, tx_ack, tx_pid;
+
+       wcid    = rt2x00_get_field32(reg, TX_STA_FIFO_WCID);
+       ack     = rt2x00_get_field32(reg, TX_STA_FIFO_TX_ACK_REQUIRED);
+       pid     = rt2x00_get_field32(reg, TX_STA_FIFO_PID_TYPE);
+
+       /*
+        * This frames has returned with an IO error,
+        * so the status report is not intended for this
+        * frame.
+        */
+       if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags)) {
+               rt2x00lib_txdone_noinfo(entry, TXDONE_FAILURE);
+               return false;
+       }
+
+       /*
+        * Validate if this TX status report is intended for
+        * this entry by comparing the WCID/ACK/PID fields.
+        */
+       txwi = rt2800_drv_get_txwi(entry);
+
+       rt2x00_desc_read(txwi, 1, &word);
+       tx_wcid = rt2x00_get_field32(word, TXWI_W1_WIRELESS_CLI_ID);
+       tx_ack  = rt2x00_get_field32(word, TXWI_W1_ACK);
+       tx_pid  = rt2x00_get_field32(word, TXWI_W1_PACKETID);
+
+       if ((wcid != tx_wcid) || (ack != tx_ack) || (pid != tx_pid)) {
+               WARNING(entry->queue->rt2x00dev,
+                       "TX status report missed for queue %d entry %d\n",
+               entry->queue->qid, entry->entry_idx);
+               rt2x00lib_txdone_noinfo(entry, TXDONE_UNKNOWN);
+               return false;
+       }
+
+       return true;
+}
+
+void rt2800_txdone(struct rt2x00_dev *rt2x00dev)
+{
+       struct data_queue *queue;
+       struct queue_entry *entry;
+       __le32 *txwi;
+       struct txdone_entry_desc txdesc;
+       u32 word;
+       u32 reg;
+       u16 mcs, real_mcs;
+       u8 pid;
+       int i;
+
+       /*
+        * TX_STA_FIFO is a stack of X entries, hence read TX_STA_FIFO
+        * at most X times and also stop processing once the TX_STA_FIFO_VALID
+        * flag is not set anymore.
+        *
+        * The legacy drivers use X=TX_RING_SIZE but state in a comment
+        * that the TX_STA_FIFO stack has a size of 16. We stick to our
+        * tx ring size for now.
+        */
+       for (i = 0; i < TX_ENTRIES; i++) {
+               rt2800_register_read(rt2x00dev, TX_STA_FIFO, &reg);
+               if (!rt2x00_get_field32(reg, TX_STA_FIFO_VALID))
+                       break;
+
+               /*
+                * Skip this entry when it contains an invalid
+                * queue identication number.
+                */
+               pid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_TYPE) - 1;
+               if (pid >= QID_RX)
+                       continue;
+
+               queue = rt2x00queue_get_queue(rt2x00dev, pid);
+               if (unlikely(!queue))
+                       continue;
+
+               /*
+                * Inside each queue, we process each entry in a chronological
+                * order. We first check that the queue is not empty.
+                */
+               entry = NULL;
+               txwi = NULL;
+               while (!rt2x00queue_empty(queue)) {
+                       entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
+                       if (rt2800_txdone_entry_check(entry, reg))
+                               break;
+               }
+
+               if (!entry || rt2x00queue_empty(queue))
+                       break;
+
+
+               /*
+                * Obtain the status about this packet.
+                */
+               txdesc.flags = 0;
+               txwi = rt2800_drv_get_txwi(entry);
+               rt2x00_desc_read(txwi, 0, &word);
+               mcs = rt2x00_get_field32(word, TXWI_W0_MCS);
+               real_mcs = rt2x00_get_field32(reg, TX_STA_FIFO_MCS);
+
+               /*
+                * Ralink has a retry mechanism using a global fallback
+                * table. We setup this fallback table to try the immediate
+                * lower rate for all rates. In the TX_STA_FIFO, the MCS field
+                * always contains the MCS used for the last transmission, be
+                * it successful or not.
+                */
+               if (rt2x00_get_field32(reg, TX_STA_FIFO_TX_SUCCESS)) {
+                       /*
+                        * Transmission succeeded. The number of retries is
+                        * mcs - real_mcs
+                        */
+                       __set_bit(TXDONE_SUCCESS, &txdesc.flags);
+                       txdesc.retry = ((mcs > real_mcs) ? mcs - real_mcs : 0);
+               } else {
+                       /*
+                        * Transmission failed. The number of retries is
+                        * always 7 in this case (for a total number of 8
+                        * frames sent).
+                        */
+                       __set_bit(TXDONE_FAILURE, &txdesc.flags);
+                       txdesc.retry = rt2x00dev->long_retry;
+               }
+
+               /*
+                * the frame was retried at least once
+                * -> hw used fallback rates
+                */
+               if (txdesc.retry)
+                       __set_bit(TXDONE_FALLBACK, &txdesc.flags);
+
+               rt2x00lib_txdone(entry, &txdesc);
+       }
+}
+EXPORT_SYMBOL_GPL(rt2800_txdone);
+
 void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc)
 {
        struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
@@ -600,7 +760,7 @@ void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc)
        /*
         * Add the TXWI for the beacon to the skb.
         */
-       rt2800_write_txwi((__le32 *)entry->skb->data, txdesc);
+       rt2800_write_tx_data(entry, txdesc);
 
        /*
         * Dump beacon to userspace through debugfs.
@@ -975,19 +1135,23 @@ void rt2800_config_intf(struct rt2x00_dev *rt2x00dev, struct rt2x00_intf *intf,
        }
 
        if (flags & CONFIG_UPDATE_MAC) {
-               reg = le32_to_cpu(conf->mac[1]);
-               rt2x00_set_field32(&reg, MAC_ADDR_DW1_UNICAST_TO_ME_MASK, 0xff);
-               conf->mac[1] = cpu_to_le32(reg);
+               if (!is_zero_ether_addr((const u8 *)conf->mac)) {
+                       reg = le32_to_cpu(conf->mac[1]);
+                       rt2x00_set_field32(&reg, MAC_ADDR_DW1_UNICAST_TO_ME_MASK, 0xff);
+                       conf->mac[1] = cpu_to_le32(reg);
+               }
 
                rt2800_register_multiwrite(rt2x00dev, MAC_ADDR_DW0,
                                              conf->mac, sizeof(conf->mac));
        }
 
        if (flags & CONFIG_UPDATE_BSSID) {
-               reg = le32_to_cpu(conf->bssid[1]);
-               rt2x00_set_field32(&reg, MAC_BSSID_DW1_BSS_ID_MASK, 3);
-               rt2x00_set_field32(&reg, MAC_BSSID_DW1_BSS_BCN_NUM, 7);
-               conf->bssid[1] = cpu_to_le32(reg);
+               if (!is_zero_ether_addr((const u8 *)conf->bssid)) {
+                       reg = le32_to_cpu(conf->bssid[1]);
+                       rt2x00_set_field32(&reg, MAC_BSSID_DW1_BSS_ID_MASK, 3);
+                       rt2x00_set_field32(&reg, MAC_BSSID_DW1_BSS_BCN_NUM, 7);
+                       conf->bssid[1] = cpu_to_le32(reg);
+               }
 
                rt2800_register_multiwrite(rt2x00dev, MAC_BSSID_DW0,
                                              conf->bssid, sizeof(conf->bssid));
@@ -1120,27 +1284,23 @@ static void rt2800_config_channel_rf2xxx(struct rt2x00_dev *rt2x00dev,
                 * double meaning, and we should set a 7DBm boost flag.
                 */
                rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_A_7DBM_BOOST,
-                                  (info->tx_power1 >= 0));
+                                  (info->default_power1 >= 0));
 
-               if (info->tx_power1 < 0)
-                       info->tx_power1 += 7;
+               if (info->default_power1 < 0)
+                       info->default_power1 += 7;
 
-               rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_A,
-                                  TXPOWER_A_TO_DEV(info->tx_power1));
+               rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_A, info->default_power1);
 
                rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_A_7DBM_BOOST,
-                                  (info->tx_power2 >= 0));
+                                  (info->default_power2 >= 0));
 
-               if (info->tx_power2 < 0)
-                       info->tx_power2 += 7;
+               if (info->default_power2 < 0)
+                       info->default_power2 += 7;
 
-               rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_A,
-                                  TXPOWER_A_TO_DEV(info->tx_power2));
+               rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_A, info->default_power2);
        } else {
-               rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_G,
-                                  TXPOWER_G_TO_DEV(info->tx_power1));
-               rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_G,
-                                  TXPOWER_G_TO_DEV(info->tx_power2));
+               rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_G, info->default_power1);
+               rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_G, info->default_power2);
        }
 
        rt2x00_set_field32(&rf->rf4, RF4_HT40, conf_is_ht40(conf));
@@ -1180,13 +1340,11 @@ static void rt2800_config_channel_rf3xxx(struct rt2x00_dev *rt2x00dev,
        rt2800_rfcsr_write(rt2x00dev, 6, rfcsr);
 
        rt2800_rfcsr_read(rt2x00dev, 12, &rfcsr);
-       rt2x00_set_field8(&rfcsr, RFCSR12_TX_POWER,
-                         TXPOWER_G_TO_DEV(info->tx_power1));
+       rt2x00_set_field8(&rfcsr, RFCSR12_TX_POWER, info->default_power1);
        rt2800_rfcsr_write(rt2x00dev, 12, rfcsr);
 
        rt2800_rfcsr_read(rt2x00dev, 13, &rfcsr);
-       rt2x00_set_field8(&rfcsr, RFCSR13_TX_POWER,
-                         TXPOWER_G_TO_DEV(info->tx_power2));
+       rt2x00_set_field8(&rfcsr, RFCSR13_TX_POWER, info->default_power2);
        rt2800_rfcsr_write(rt2x00dev, 13, rfcsr);
 
        rt2800_rfcsr_read(rt2x00dev, 23, &rfcsr);
@@ -1210,10 +1368,19 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
        unsigned int tx_pin;
        u8 bbp;
 
+       if (rf->channel <= 14) {
+               info->default_power1 = TXPOWER_G_TO_DEV(info->default_power1);
+               info->default_power2 = TXPOWER_G_TO_DEV(info->default_power2);
+       } else {
+               info->default_power1 = TXPOWER_A_TO_DEV(info->default_power1);
+               info->default_power2 = TXPOWER_A_TO_DEV(info->default_power2);
+       }
+
        if (rt2x00_rf(rt2x00dev, RF2020) ||
            rt2x00_rf(rt2x00dev, RF3020) ||
            rt2x00_rf(rt2x00dev, RF3021) ||
-           rt2x00_rf(rt2x00dev, RF3022))
+           rt2x00_rf(rt2x00dev, RF3022) ||
+           rt2x00_rf(rt2x00dev, RF3052))
                rt2800_config_channel_rf3xxx(rt2x00dev, conf, rf, info);
        else
                rt2800_config_channel_rf2xxx(rt2x00dev, conf, rf, info);
@@ -1536,7 +1703,7 @@ EXPORT_SYMBOL_GPL(rt2800_link_tuner);
 /*
  * Initialization functions.
  */
-int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
+static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
 {
        u32 reg;
        u16 eeprom;
@@ -1906,7 +2073,6 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(rt2800_init_registers);
 
 static int rt2800_wait_bbp_rf_ready(struct rt2x00_dev *rt2x00dev)
 {
@@ -1949,7 +2115,7 @@ static int rt2800_wait_bbp_ready(struct rt2x00_dev *rt2x00dev)
        return -EACCES;
 }
 
-int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
+static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
 {
        unsigned int i;
        u16 eeprom;
@@ -2044,7 +2210,6 @@ int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(rt2800_init_bbp);
 
 static u8 rt2800_init_rx_filter(struct rt2x00_dev *rt2x00dev,
                                bool bw40, u8 rfcsr24, u8 filter_target)
@@ -2106,7 +2271,7 @@ static u8 rt2800_init_rx_filter(struct rt2x00_dev *rt2x00dev,
        return rfcsr24;
 }
 
-int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
+static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
 {
        u8 rfcsr;
        u8 bbp;
@@ -2360,7 +2525,100 @@ int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(rt2800_init_rfcsr);
+
+int rt2800_enable_radio(struct rt2x00_dev *rt2x00dev)
+{
+       u32 reg;
+       u16 word;
+
+       /*
+        * Initialize all registers.
+        */
+       if (unlikely(rt2800_wait_wpdma_ready(rt2x00dev) ||
+                    rt2800_init_registers(rt2x00dev) ||
+                    rt2800_init_bbp(rt2x00dev) ||
+                    rt2800_init_rfcsr(rt2x00dev)))
+               return -EIO;
+
+       /*
+        * Send signal to firmware during boot time.
+        */
+       rt2800_mcu_request(rt2x00dev, MCU_BOOT_SIGNAL, 0, 0, 0);
+
+       if (rt2x00_is_usb(rt2x00dev) &&
+           (rt2x00_rt(rt2x00dev, RT3070) ||
+            rt2x00_rt(rt2x00dev, RT3071) ||
+            rt2x00_rt(rt2x00dev, RT3572))) {
+               udelay(200);
+               rt2800_mcu_request(rt2x00dev, MCU_CURRENT, 0, 0, 0);
+               udelay(10);
+       }
+
+       /*
+        * Enable RX.
+        */
+       rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
+       rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_TX, 1);
+       rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_RX, 0);
+       rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
+
+       udelay(50);
+
+       rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, &reg);
+       rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_TX_DMA, 1);
+       rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_RX_DMA, 1);
+       rt2x00_set_field32(&reg, WPDMA_GLO_CFG_WP_DMA_BURST_SIZE, 2);
+       rt2x00_set_field32(&reg, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1);
+       rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg);
+
+       rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
+       rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_TX, 1);
+       rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_RX, 1);
+       rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
+
+       /*
+        * Initialize LED control
+        */
+       rt2x00_eeprom_read(rt2x00dev, EEPROM_LED1, &word);
+       rt2800_mcu_request(rt2x00dev, MCU_LED_1, 0xff,
+                          word & 0xff, (word >> 8) & 0xff);
+
+       rt2x00_eeprom_read(rt2x00dev, EEPROM_LED2, &word);
+       rt2800_mcu_request(rt2x00dev, MCU_LED_2, 0xff,
+                          word & 0xff, (word >> 8) & 0xff);
+
+       rt2x00_eeprom_read(rt2x00dev, EEPROM_LED3, &word);
+       rt2800_mcu_request(rt2x00dev, MCU_LED_3, 0xff,
+                          word & 0xff, (word >> 8) & 0xff);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(rt2800_enable_radio);
+
+void rt2800_disable_radio(struct rt2x00_dev *rt2x00dev)
+{
+       u32 reg;
+
+       rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, &reg);
+       rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_TX_DMA, 0);
+       rt2x00_set_field32(&reg, WPDMA_GLO_CFG_TX_DMA_BUSY, 0);
+       rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_RX_DMA, 0);
+       rt2x00_set_field32(&reg, WPDMA_GLO_CFG_RX_DMA_BUSY, 0);
+       rt2x00_set_field32(&reg, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1);
+       rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg);
+
+       /* Wait for DMA, ignore error */
+       rt2800_wait_wpdma_ready(rt2x00dev);
+
+       rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
+       rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_TX, 0);
+       rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_RX, 0);
+       rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
+
+       rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0);
+       rt2800_register_write(rt2x00dev, TX_PIN_CFG, 0);
+}
+EXPORT_SYMBOL_GPL(rt2800_disable_radio);
 
 int rt2800_efuse_detect(struct rt2x00_dev *rt2x00dev)
 {
@@ -2516,6 +2774,13 @@ int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev)
                                   default_lna_gain);
        rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_A2, word);
 
+       rt2x00_eeprom_read(rt2x00dev, EEPROM_MAX_TX_POWER, &word);
+       if (rt2x00_get_field16(word, EEPROM_MAX_TX_POWER_24GHZ) == 0xff)
+               rt2x00_set_field16(&word, EEPROM_MAX_TX_POWER_24GHZ, MAX_G_TXPOWER);
+       if (rt2x00_get_field16(word, EEPROM_MAX_TX_POWER_5GHZ) == 0xff)
+               rt2x00_set_field16(&word, EEPROM_MAX_TX_POWER_5GHZ, MAX_A_TXPOWER);
+       rt2x00_eeprom_write(rt2x00dev, EEPROM_MAX_TX_POWER, word);
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(rt2800_validate_eeprom);
@@ -2755,9 +3020,10 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
 {
        struct hw_mode_spec *spec = &rt2x00dev->spec;
        struct channel_info *info;
-       char *tx_power1;
-       char *tx_power2;
+       char *default_power1;
+       char *default_power2;
        unsigned int i;
+       unsigned short max_power;
        u16 eeprom;
 
        /*
@@ -2865,27 +3131,32 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
        /*
         * Create channel information array
         */
-       info = kzalloc(spec->num_channels * sizeof(*info), GFP_KERNEL);
+       info = kcalloc(spec->num_channels, sizeof(*info), GFP_KERNEL);
        if (!info)
                return -ENOMEM;
 
        spec->channels_info = info;
 
-       tx_power1 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG1);
-       tx_power2 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG2);
+       rt2x00_eeprom_read(rt2x00dev, EEPROM_MAX_TX_POWER, &eeprom);
+       max_power = rt2x00_get_field16(eeprom, EEPROM_MAX_TX_POWER_24GHZ);
+       default_power1 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG1);
+       default_power2 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG2);
 
        for (i = 0; i < 14; i++) {
-               info[i].tx_power1 = TXPOWER_G_FROM_DEV(tx_power1[i]);
-               info[i].tx_power2 = TXPOWER_G_FROM_DEV(tx_power2[i]);
+               info[i].max_power = max_power;
+               info[i].default_power1 = TXPOWER_G_FROM_DEV(default_power1[i]);
+               info[i].default_power2 = TXPOWER_G_FROM_DEV(default_power2[i]);
        }
 
        if (spec->num_channels > 14) {
-               tx_power1 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A1);
-               tx_power2 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A2);
+               max_power = rt2x00_get_field16(eeprom, EEPROM_MAX_TX_POWER_5GHZ);
+               default_power1 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A1);
+               default_power2 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A2);
 
                for (i = 14; i < spec->num_channels; i++) {
-                       info[i].tx_power1 = TXPOWER_A_FROM_DEV(tx_power1[i]);
-                       info[i].tx_power2 = TXPOWER_A_FROM_DEV(tx_power2[i]);
+                       info[i].max_power = max_power;
+                       info[i].default_power1 = TXPOWER_A_FROM_DEV(default_power1[i]);
+                       info[i].default_power2 = TXPOWER_A_FROM_DEV(default_power2[i]);
                }
        }
 
index 091641e3c5e2ec95eb4d89449490f7b45c41d18d..986229c06c19ba02e0c6d9dc7633a7fa8f148113 100644 (file)
@@ -1,4 +1,6 @@
 /*
+       Copyright (C) 2010 Willow Garage <http://www.willowgarage.com>
+       Copyright (C) 2010 Ivo van Doorn <IvDoorn@gmail.com>
        Copyright (C) 2009 Bartlomiej Zolnierkiewicz
 
        This program is free software; you can redistribute it and/or modify
@@ -44,6 +46,7 @@ struct rt2800_ops {
        int (*drv_write_firmware)(struct rt2x00_dev *rt2x00dev,
                                  const u8 *data, const size_t len);
        int (*drv_init_registers)(struct rt2x00_dev *rt2x00dev);
+       __le32 *(*drv_get_txwi)(struct queue_entry *entry);
 };
 
 static inline void rt2800_register_read(struct rt2x00_dev *rt2x00dev,
@@ -126,18 +129,31 @@ static inline int rt2800_drv_init_registers(struct rt2x00_dev *rt2x00dev)
        return rt2800ops->drv_init_registers(rt2x00dev);
 }
 
+static inline __le32 *rt2800_drv_get_txwi(struct queue_entry *entry)
+{
+       const struct rt2800_ops *rt2800ops = entry->queue->rt2x00dev->ops->drv;
+
+       return rt2800ops->drv_get_txwi(entry);
+}
+
 void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev,
                        const u8 command, const u8 token,
                        const u8 arg0, const u8 arg1);
 
+int rt2800_wait_csr_ready(struct rt2x00_dev *rt2x00dev);
+int rt2800_wait_wpdma_ready(struct rt2x00_dev *rt2x00dev);
+
 int rt2800_check_firmware(struct rt2x00_dev *rt2x00dev,
                          const u8 *data, const size_t len);
 int rt2800_load_firmware(struct rt2x00_dev *rt2x00dev,
                         const u8 *data, const size_t len);
 
-void rt2800_write_txwi(__le32 *txwi, struct txentry_desc *txdesc);
+void rt2800_write_tx_data(struct queue_entry *entry,
+                         struct txentry_desc *txdesc);
 void rt2800_process_rxwi(struct queue_entry *entry, struct rxdone_entry_desc *txdesc);
 
+void rt2800_txdone(struct rt2x00_dev *rt2x00dev);
+
 void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc);
 
 extern const struct rt2x00debug rt2800_rt2x00debug;
@@ -163,10 +179,8 @@ void rt2800_reset_tuner(struct rt2x00_dev *rt2x00dev, struct link_qual *qual);
 void rt2800_link_tuner(struct rt2x00_dev *rt2x00dev, struct link_qual *qual,
                       const u32 count);
 
-int rt2800_init_registers(struct rt2x00_dev *rt2x00dev);
-int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev);
-int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev);
-int rt2800_wait_wpdma_ready(struct rt2x00_dev *rt2x00dev);
+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);
index 39b3846fa340a83704a69d8a252bb7a6d6fa87b5..2bcb1507e3ac57289e536a8646f34b24b7818eec 100644 (file)
@@ -1,5 +1,5 @@
 /*
-       Copyright (C) 2009 Ivo van Doorn <IvDoorn@gmail.com>
+       Copyright (C) 2009 - 2010 Ivo van Doorn <IvDoorn@gmail.com>
        Copyright (C) 2009 Alban Browaeys <prahal@yahoo.com>
        Copyright (C) 2009 Felix Fietkau <nbd@openwrt.org>
        Copyright (C) 2009 Luis Correia <luis.f.correia@gmail.com>
@@ -196,8 +196,6 @@ static int rt2800pci_write_firmware(struct rt2x00_dev *rt2x00dev,
 {
        u32 reg;
 
-       rt2800_register_write(rt2x00dev, AUTOWAKEUP_CFG, 0x00000000);
-
        /*
         * enable Host program ram write selection
         */
@@ -399,78 +397,18 @@ static int rt2800pci_init_registers(struct rt2x00_dev *rt2x00dev)
 
 static int rt2800pci_enable_radio(struct rt2x00_dev *rt2x00dev)
 {
-       u32 reg;
-       u16 word;
-
-       /*
-        * Initialize all registers.
-        */
        if (unlikely(rt2800_wait_wpdma_ready(rt2x00dev) ||
-                    rt2800pci_init_queues(rt2x00dev) ||
-                    rt2800_init_registers(rt2x00dev) ||
-                    rt2800_wait_wpdma_ready(rt2x00dev) ||
-                    rt2800_init_bbp(rt2x00dev) ||
-                    rt2800_init_rfcsr(rt2x00dev)))
+                    rt2800pci_init_queues(rt2x00dev)))
                return -EIO;
 
-       /*
-        * Send signal to firmware during boot time.
-        */
-       rt2800_mcu_request(rt2x00dev, MCU_BOOT_SIGNAL, 0, 0, 0);
-
-       /*
-        * Enable RX.
-        */
-       rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
-       rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_TX, 1);
-       rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_RX, 0);
-       rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
-
-       rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, &reg);
-       rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_TX_DMA, 1);
-       rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_RX_DMA, 1);
-       rt2x00_set_field32(&reg, WPDMA_GLO_CFG_WP_DMA_BURST_SIZE, 2);
-       rt2x00_set_field32(&reg, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1);
-       rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg);
-
-       rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
-       rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_TX, 1);
-       rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_RX, 1);
-       rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
-
-       /*
-        * Initialize LED control
-        */
-       rt2x00_eeprom_read(rt2x00dev, EEPROM_LED1, &word);
-       rt2800_mcu_request(rt2x00dev, MCU_LED_1, 0xff,
-                             word & 0xff, (word >> 8) & 0xff);
-
-       rt2x00_eeprom_read(rt2x00dev, EEPROM_LED2, &word);
-       rt2800_mcu_request(rt2x00dev, MCU_LED_2, 0xff,
-                             word & 0xff, (word >> 8) & 0xff);
-
-       rt2x00_eeprom_read(rt2x00dev, EEPROM_LED3, &word);
-       rt2800_mcu_request(rt2x00dev, MCU_LED_3, 0xff,
-                             word & 0xff, (word >> 8) & 0xff);
-
-       return 0;
+       return rt2800_enable_radio(rt2x00dev);
 }
 
 static void rt2800pci_disable_radio(struct rt2x00_dev *rt2x00dev)
 {
        u32 reg;
 
-       rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, &reg);
-       rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_TX_DMA, 0);
-       rt2x00_set_field32(&reg, WPDMA_GLO_CFG_TX_DMA_BUSY, 0);
-       rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_RX_DMA, 0);
-       rt2x00_set_field32(&reg, WPDMA_GLO_CFG_RX_DMA_BUSY, 0);
-       rt2x00_set_field32(&reg, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1);
-       rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg);
-
-       rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, 0);
-       rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0);
-       rt2800_register_write(rt2x00dev, TX_PIN_CFG, 0);
+       rt2800_disable_radio(rt2x00dev);
 
        rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00001280);
 
@@ -486,9 +424,6 @@ static void rt2800pci_disable_radio(struct rt2x00_dev *rt2x00dev)
 
        rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e1f);
        rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e00);
-
-       /* Wait for DMA, ignore error */
-       rt2800_wait_wpdma_ready(rt2x00dev);
 }
 
 static int rt2800pci_set_state(struct rt2x00_dev *rt2x00dev,
@@ -566,21 +501,16 @@ static int rt2800pci_set_device_state(struct rt2x00_dev *rt2x00dev,
 /*
  * TX descriptor initialization
  */
-static void rt2800pci_write_tx_data(struct queue_entry* entry,
-                                   struct txentry_desc *txdesc)
+static __le32 *rt2800pci_get_txwi(struct queue_entry *entry)
 {
-       __le32 *txwi = (__le32 *) entry->skb->data;
-
-       rt2800_write_txwi(txwi, txdesc);
+       return (__le32 *) entry->skb->data;
 }
 
-
-static void rt2800pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
-                                   struct sk_buff *skb,
+static void rt2800pci_write_tx_desc(struct queue_entry *entry,
                                    struct txentry_desc *txdesc)
 {
-       struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
-       struct queue_entry_priv_pci *entry_priv = skbdesc->entry->priv_data;
+       struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
+       struct queue_entry_priv_pci *entry_priv = entry->priv_data;
        __le32 *txd = entry_priv->desc;
        u32 word;
 
@@ -600,7 +530,7 @@ static void rt2800pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
        rt2x00_desc_write(txd, 0, word);
 
        rt2x00_desc_read(txd, 1, &word);
-       rt2x00_set_field32(&word, TXD_W1_SD_LEN1, skb->len);
+       rt2x00_set_field32(&word, TXD_W1_SD_LEN1, entry->skb->len);
        rt2x00_set_field32(&word, TXD_W1_LAST_SEC1,
                           !test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags));
        rt2x00_set_field32(&word, TXD_W1_BURST,
@@ -631,41 +561,35 @@ static void rt2800pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
 /*
  * TX data initialization
  */
-static void rt2800pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
-                                   const enum data_queue_qid queue_idx)
+static void rt2800pci_kick_tx_queue(struct data_queue *queue)
 {
-       struct data_queue *queue;
-       unsigned int idx, qidx = 0;
-
-       if (queue_idx > QID_HCCA && queue_idx != QID_MGMT)
-               return;
-
-       queue = rt2x00queue_get_queue(rt2x00dev, queue_idx);
-       idx = queue->index[Q_INDEX];
+       struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+       struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX);
+       unsigned int qidx = 0;
 
-       if (queue_idx == QID_MGMT)
+       if (queue->qid == QID_MGMT)
                qidx = 5;
        else
-               qidx = queue_idx;
+               qidx = queue->qid;
 
-       rt2800_register_write(rt2x00dev, TX_CTX_IDX(qidx), idx);
+       rt2800_register_write(rt2x00dev, TX_CTX_IDX(qidx), entry->entry_idx);
 }
 
-static void rt2800pci_kill_tx_queue(struct rt2x00_dev *rt2x00dev,
-                                   const enum data_queue_qid qid)
+static void rt2800pci_kill_tx_queue(struct data_queue *queue)
 {
+       struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
        u32 reg;
 
-       if (qid == QID_BEACON) {
+       if (queue->qid == QID_BEACON) {
                rt2800_register_write(rt2x00dev, BCN_TIME_CFG, 0);
                return;
        }
 
        rt2800_register_read(rt2x00dev, WPDMA_RST_IDX, &reg);
-       rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX0, (qid == QID_AC_BE));
-       rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX1, (qid == QID_AC_BK));
-       rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX2, (qid == QID_AC_VI));
-       rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX3, (qid == QID_AC_VO));
+       rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX0, (queue->qid == QID_AC_BE));
+       rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX1, (queue->qid == QID_AC_BK));
+       rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX2, (queue->qid == QID_AC_VI));
+       rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX3, (queue->qid == QID_AC_VO));
        rt2800_register_write(rt2x00dev, WPDMA_RST_IDX, reg);
 }
 
@@ -728,110 +652,6 @@ static void rt2800pci_fill_rxdone(struct queue_entry *entry,
 /*
  * Interrupt functions.
  */
-static void rt2800pci_txdone(struct rt2x00_dev *rt2x00dev)
-{
-       struct data_queue *queue;
-       struct queue_entry *entry;
-       __le32 *txwi;
-       struct txdone_entry_desc txdesc;
-       u32 word;
-       u32 reg;
-       int wcid, ack, pid, tx_wcid, tx_ack, tx_pid;
-       u16 mcs, real_mcs;
-       int i;
-
-       /*
-        * TX_STA_FIFO is a stack of X entries, hence read TX_STA_FIFO
-        * at most X times and also stop processing once the TX_STA_FIFO_VALID
-        * flag is not set anymore.
-        *
-        * The legacy drivers use X=TX_RING_SIZE but state in a comment
-        * that the TX_STA_FIFO stack has a size of 16. We stick to our
-        * tx ring size for now.
-        */
-       for (i = 0; i < TX_ENTRIES; i++) {
-               rt2800_register_read(rt2x00dev, TX_STA_FIFO, &reg);
-               if (!rt2x00_get_field32(reg, TX_STA_FIFO_VALID))
-                       break;
-
-               wcid    = rt2x00_get_field32(reg, TX_STA_FIFO_WCID);
-               ack     = rt2x00_get_field32(reg, TX_STA_FIFO_TX_ACK_REQUIRED);
-               pid     = rt2x00_get_field32(reg, TX_STA_FIFO_PID_TYPE);
-
-               /*
-                * Skip this entry when it contains an invalid
-                * queue identication number.
-                */
-               if (pid <= 0 || pid > QID_RX)
-                       continue;
-
-               queue = rt2x00queue_get_queue(rt2x00dev, pid - 1);
-               if (unlikely(!queue))
-                       continue;
-
-               /*
-                * Inside each queue, we process each entry in a chronological
-                * order. We first check that the queue is not empty.
-                */
-               if (rt2x00queue_empty(queue))
-                       continue;
-               entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
-
-               /* Check if we got a match by looking at WCID/ACK/PID
-                * fields */
-               txwi = (__le32 *) entry->skb->data;
-
-               rt2x00_desc_read(txwi, 1, &word);
-               tx_wcid = rt2x00_get_field32(word, TXWI_W1_WIRELESS_CLI_ID);
-               tx_ack  = rt2x00_get_field32(word, TXWI_W1_ACK);
-               tx_pid  = rt2x00_get_field32(word, TXWI_W1_PACKETID);
-
-               if ((wcid != tx_wcid) || (ack != tx_ack) || (pid != tx_pid))
-                       WARNING(rt2x00dev, "invalid TX_STA_FIFO content\n");
-
-               /*
-                * Obtain the status about this packet.
-                */
-               txdesc.flags = 0;
-               rt2x00_desc_read(txwi, 0, &word);
-               mcs = rt2x00_get_field32(word, TXWI_W0_MCS);
-               real_mcs = rt2x00_get_field32(reg, TX_STA_FIFO_MCS);
-
-               /*
-                * Ralink has a retry mechanism using a global fallback
-                * table. We setup this fallback table to try the immediate
-                * lower rate for all rates. In the TX_STA_FIFO, the MCS field
-                * always contains the MCS used for the last transmission, be
-                * it successful or not.
-                */
-               if (rt2x00_get_field32(reg, TX_STA_FIFO_TX_SUCCESS)) {
-                       /*
-                        * Transmission succeeded. The number of retries is
-                        * mcs - real_mcs
-                        */
-                       __set_bit(TXDONE_SUCCESS, &txdesc.flags);
-                       txdesc.retry = ((mcs > real_mcs) ? mcs - real_mcs : 0);
-               } else {
-                       /*
-                        * Transmission failed. The number of retries is
-                        * always 7 in this case (for a total number of 8
-                        * frames sent).
-                        */
-                       __set_bit(TXDONE_FAILURE, &txdesc.flags);
-                       txdesc.retry = 7;
-               }
-
-               /*
-                * the frame was retried at least once
-                * -> hw used fallback rates
-                */
-               if (txdesc.retry)
-                       __set_bit(TXDONE_FALLBACK, &txdesc.flags);
-
-               rt2x00lib_txdone(entry, &txdesc);
-       }
-}
-
 static void rt2800pci_wakeup(struct rt2x00_dev *rt2x00dev)
 {
        struct ieee80211_conf conf = { .flags = 0 };
@@ -867,7 +687,7 @@ static irqreturn_t rt2800pci_interrupt_thread(int irq, void *dev_instance)
         * 4 - Tx done interrupt.
         */
        if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TX_FIFO_STATUS))
-               rt2800pci_txdone(rt2x00dev);
+               rt2800_txdone(rt2x00dev);
 
        /*
         * 5 - Auto wakeup interrupt.
@@ -1011,6 +831,7 @@ static const struct rt2800_ops rt2800pci_rt2800_ops = {
        .regbusy_read           = rt2x00pci_regbusy_read,
        .drv_write_firmware     = rt2800pci_write_firmware,
        .drv_init_registers     = rt2800pci_init_registers,
+       .drv_get_txwi           = rt2800pci_get_txwi,
 };
 
 static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = {
@@ -1030,7 +851,7 @@ static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = {
        .reset_tuner            = rt2800_reset_tuner,
        .link_tuner             = rt2800_link_tuner,
        .write_tx_desc          = rt2800pci_write_tx_desc,
-       .write_tx_data          = rt2800pci_write_tx_data,
+       .write_tx_data          = rt2800_write_tx_data,
        .write_beacon           = rt2800_write_beacon,
        .kick_tx_queue          = rt2800pci_kick_tx_queue,
        .kill_tx_queue          = rt2800pci_kill_tx_queue,
index 5a2dfe87c6b61b5f48ec9d55ad95fea5208ab4ca..3dff56ec195abaa60e9500611a6a020da2dc199f 100644 (file)
@@ -1,5 +1,6 @@
 /*
-       Copyright (C) 2009 Ivo van Doorn <IvDoorn@gmail.com>
+       Copyright (C) 2010 Willow Garage <http://www.willowgarage.com>
+       Copyright (C) 2009 - 2010 Ivo van Doorn <IvDoorn@gmail.com>
        Copyright (C) 2009 Mattias Nissler <mattias.nissler@gmx.de>
        Copyright (C) 2009 Felix Fietkau <nbd@openwrt.org>
        Copyright (C) 2009 Xose Vazquez Perez <xose.vazquez@gmail.com>
@@ -100,19 +101,6 @@ static int rt2800usb_write_firmware(struct rt2x00_dev *rt2x00dev,
        msleep(10);
        rt2800_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0);
 
-       /*
-        * Send signal to firmware during boot time.
-        */
-       rt2800_mcu_request(rt2x00dev, MCU_BOOT_SIGNAL, 0, 0, 0);
-
-       if (rt2x00_rt(rt2x00dev, RT3070) ||
-           rt2x00_rt(rt2x00dev, RT3071) ||
-           rt2x00_rt(rt2x00dev, RT3572)) {
-               udelay(200);
-               rt2800_mcu_request(rt2x00dev, MCU_CURRENT, 0, 0, 0);
-               udelay(10);
-       }
-
        return 0;
 }
 
@@ -134,26 +122,18 @@ static void rt2800usb_toggle_rx(struct rt2x00_dev *rt2x00dev,
 static int rt2800usb_init_registers(struct rt2x00_dev *rt2x00dev)
 {
        u32 reg;
-       int i;
 
        /*
         * Wait until BBP and RF are ready.
         */
-       for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
-               rt2800_register_read(rt2x00dev, MAC_CSR0, &reg);
-               if (reg && reg != ~0)
-                       break;
-               msleep(1);
-       }
-
-       if (i == REGISTER_BUSY_COUNT) {
-               ERROR(rt2x00dev, "Unstable hardware.\n");
+       if (rt2800_wait_csr_ready(rt2x00dev))
                return -EBUSY;
-       }
 
        rt2800_register_read(rt2x00dev, PBF_SYS_CTRL, &reg);
        rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, reg & ~0x00002000);
 
+       rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003);
+
        rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
        rt2x00_set_field32(&reg, MAC_SYS_CTRL_RESET_CSR, 1);
        rt2x00_set_field32(&reg, MAC_SYS_CTRL_RESET_BBP, 1);
@@ -172,30 +152,10 @@ static int rt2800usb_init_registers(struct rt2x00_dev *rt2x00dev)
 static int rt2800usb_enable_radio(struct rt2x00_dev *rt2x00dev)
 {
        u32 reg;
-       u16 word;
 
-       /*
-        * Initialize all registers.
-        */
-       if (unlikely(rt2800_wait_wpdma_ready(rt2x00dev) ||
-                    rt2800_init_registers(rt2x00dev) ||
-                    rt2800_init_bbp(rt2x00dev) ||
-                    rt2800_init_rfcsr(rt2x00dev)))
+       if (unlikely(rt2800_wait_wpdma_ready(rt2x00dev)))
                return -EIO;
 
-       rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
-       rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_TX, 1);
-       rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
-
-       udelay(50);
-
-       rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, &reg);
-       rt2x00_set_field32(&reg, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1);
-       rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_RX_DMA, 1);
-       rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_TX_DMA, 1);
-       rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg);
-
-
        rt2800_register_read(rt2x00dev, USB_DMA_CFG, &reg);
        rt2x00_set_field32(&reg, USB_DMA_CFG_PHY_CLEAR, 0);
        rt2x00_set_field32(&reg, USB_DMA_CFG_RX_BULK_AGG_EN, 0);
@@ -210,45 +170,12 @@ static int rt2800usb_enable_radio(struct rt2x00_dev *rt2x00dev)
        rt2x00_set_field32(&reg, USB_DMA_CFG_TX_BULK_EN, 1);
        rt2800_register_write(rt2x00dev, USB_DMA_CFG, reg);
 
-       rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
-       rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_TX, 1);
-       rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_RX, 1);
-       rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
-
-       /*
-        * Initialize LED control
-        */
-       rt2x00_eeprom_read(rt2x00dev, EEPROM_LED1, &word);
-       rt2800_mcu_request(rt2x00dev, MCU_LED_1, 0xff,
-                             word & 0xff, (word >> 8) & 0xff);
-
-       rt2x00_eeprom_read(rt2x00dev, EEPROM_LED2, &word);
-       rt2800_mcu_request(rt2x00dev, MCU_LED_2, 0xff,
-                             word & 0xff, (word >> 8) & 0xff);
-
-       rt2x00_eeprom_read(rt2x00dev, EEPROM_LED3, &word);
-       rt2800_mcu_request(rt2x00dev, MCU_LED_3, 0xff,
-                             word & 0xff, (word >> 8) & 0xff);
-
-       return 0;
+       return rt2800_enable_radio(rt2x00dev);
 }
 
 static void rt2800usb_disable_radio(struct rt2x00_dev *rt2x00dev)
 {
-       u32 reg;
-
-       rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, &reg);
-       rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_TX_DMA, 0);
-       rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_RX_DMA, 0);
-       rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg);
-
-       rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, 0);
-       rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0);
-       rt2800_register_write(rt2x00dev, TX_PIN_CFG, 0);
-
-       /* Wait for DMA, ignore error */
-       rt2800_wait_wpdma_ready(rt2x00dev);
-
+       rt2800_disable_radio(rt2x00dev);
        rt2x00usb_disable_radio(rt2x00dev);
 }
 
@@ -320,21 +247,19 @@ static int rt2800usb_set_device_state(struct rt2x00_dev *rt2x00dev,
 /*
  * TX descriptor initialization
  */
-static void rt2800usb_write_tx_data(struct queue_entry* entry,
-                                   struct txentry_desc *txdesc)
+static __le32 *rt2800usb_get_txwi(struct queue_entry *entry)
 {
-       __le32 *txwi = (__le32 *) (entry->skb->data + TXINFO_DESC_SIZE);
-
-       rt2800_write_txwi(txwi, txdesc);
+       if (entry->queue->qid == QID_BEACON)
+               return (__le32 *) (entry->skb->data);
+       else
+               return (__le32 *) (entry->skb->data + TXINFO_DESC_SIZE);
 }
 
-
-static void rt2800usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
-                                   struct sk_buff *skb,
+static void rt2800usb_write_tx_desc(struct queue_entry *entry,
                                    struct txentry_desc *txdesc)
 {
-       struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
-       __le32 *txi = (__le32 *) skb->data;
+       struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
+       __le32 *txi = (__le32 *) entry->skb->data;
        u32 word;
 
        /*
@@ -342,7 +267,7 @@ static void rt2800usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
         */
        rt2x00_desc_read(txi, 0, &word);
        rt2x00_set_field32(&word, TXINFO_W0_USB_DMA_TX_PKT_LEN,
-                          skb->len - TXINFO_DESC_SIZE);
+                          entry->skb->len - TXINFO_DESC_SIZE);
        rt2x00_set_field32(&word, TXINFO_W0_WIV,
                           !test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc->flags));
        rt2x00_set_field32(&word, TXINFO_W0_QSEL, 2);
@@ -378,6 +303,46 @@ static int rt2800usb_get_tx_data_len(struct queue_entry *entry)
        return length;
 }
 
+/*
+ * TX control handlers
+ */
+static void rt2800usb_work_txdone(struct work_struct *work)
+{
+       struct rt2x00_dev *rt2x00dev =
+           container_of(work, struct rt2x00_dev, txdone_work);
+       struct data_queue *queue;
+       struct queue_entry *entry;
+
+       rt2800_txdone(rt2x00dev);
+
+       /*
+        * Process any trailing TX status reports for IO failures,
+        * we loop until we find the first non-IO error entry. This
+        * can either be a frame which is free, is being uploaded,
+        * or has completed the upload but didn't have an entry
+        * in the TX_STAT_FIFO register yet.
+        */
+       tx_queue_for_each(rt2x00dev, queue) {
+               while (!rt2x00queue_empty(queue)) {
+                       entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
+
+                       if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags) ||
+                           !test_bit(ENTRY_DATA_IO_FAILED, &entry->flags))
+                               break;
+
+                       rt2x00lib_txdone_noinfo(entry, TXDONE_FAILURE);
+               }
+       }
+}
+
+static void rt2800usb_kill_tx_queue(struct data_queue *queue)
+{
+       if (queue->qid == QID_BEACON)
+               rt2x00usb_register_write(queue->rt2x00dev, BCN_TIME_CFG, 0);
+
+       rt2x00usb_kill_tx_queue(queue);
+}
+
 /*
  * RX control handlers
  */
@@ -514,6 +479,11 @@ static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev)
         */
        rt2x00dev->rssi_offset = DEFAULT_RSSI_OFFSET;
 
+       /*
+        * Overwrite TX done handler
+        */
+       PREPARE_WORK(&rt2x00dev->txdone_work, rt2800usb_work_txdone);
+
        return 0;
 }
 
@@ -549,6 +519,7 @@ static const struct rt2800_ops rt2800usb_rt2800_ops = {
        .regbusy_read           = rt2x00usb_regbusy_read,
        .drv_write_firmware     = rt2800usb_write_firmware,
        .drv_init_registers     = rt2800usb_init_registers,
+       .drv_get_txwi           = rt2800usb_get_txwi,
 };
 
 static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = {
@@ -566,11 +537,11 @@ static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = {
        .link_tuner             = rt2800_link_tuner,
        .watchdog               = rt2x00usb_watchdog,
        .write_tx_desc          = rt2800usb_write_tx_desc,
-       .write_tx_data          = rt2800usb_write_tx_data,
+       .write_tx_data          = rt2800_write_tx_data,
        .write_beacon           = rt2800_write_beacon,
        .get_tx_data_len        = rt2800usb_get_tx_data_len,
        .kick_tx_queue          = rt2x00usb_kick_tx_queue,
-       .kill_tx_queue          = rt2x00usb_kill_tx_queue,
+       .kill_tx_queue          = rt2800usb_kill_tx_queue,
        .fill_rxdone            = rt2800usb_fill_rxdone,
        .config_shared_key      = rt2800_config_shared_key,
        .config_pairwise_key    = rt2800_config_pairwise_key,
index c21af38cc5af57364694c8bc46e19867e2c8150d..0ae942cb66df4d55c5ab3d056f975749a670bd70 100644 (file)
@@ -1,5 +1,6 @@
 /*
-       Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
+       Copyright (C) 2010 Willow Garage <http://www.willowgarage.com>
+       Copyright (C) 2004 - 2010 Ivo van Doorn <IvDoorn@gmail.com>
        Copyright (C) 2004 - 2009 Gertjan van Wingerde <gwingerde@gmail.com>
        <http://rt2x00.serialmonkey.com>
 
@@ -212,8 +213,9 @@ struct channel_info {
        unsigned int flags;
 #define GEOGRAPHY_ALLOWED      0x00000001
 
-       short tx_power1;
-       short tx_power2;
+       short max_power;
+       short default_power1;
+       short default_power2;
 };
 
 /*
@@ -558,18 +560,15 @@ struct rt2x00lib_ops {
        /*
         * TX control handlers
         */
-       void (*write_tx_desc) (struct rt2x00_dev *rt2x00dev,
-                              struct sk_buff *skb,
+       void (*write_tx_desc) (struct queue_entry *entry,
                               struct txentry_desc *txdesc);
        void (*write_tx_data) (struct queue_entry *entry,
                               struct txentry_desc *txdesc);
        void (*write_beacon) (struct queue_entry *entry,
                              struct txentry_desc *txdesc);
        int (*get_tx_data_len) (struct queue_entry *entry);
-       void (*kick_tx_queue) (struct rt2x00_dev *rt2x00dev,
-                              const enum data_queue_qid queue);
-       void (*kill_tx_queue) (struct rt2x00_dev *rt2x00dev,
-                              const enum data_queue_qid queue);
+       void (*kick_tx_queue) (struct data_queue *queue);
+       void (*kill_tx_queue) (struct data_queue *queue);
 
        /*
         * RX control handlers
@@ -698,6 +697,7 @@ struct rt2x00_dev {
        struct ieee80211_hw *hw;
        struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS];
        enum ieee80211_band curr_band;
+       int curr_freq;
 
        /*
         * If enabled, the debugfs interface structures
@@ -849,11 +849,6 @@ struct rt2x00_dev {
         */
        struct ieee80211_low_level_stats low_level_stats;
 
-       /*
-        * RX configuration information.
-        */
-       struct ieee80211_rx_status rx_status;
-
        /*
         * Scheduled work.
         * NOTE: intf_work will use ieee80211_iterate_active_interfaces()
@@ -862,6 +857,12 @@ struct rt2x00_dev {
         */
        struct work_struct intf_work;
 
+       /**
+        * Scheduled work for TX/RX done handling (USB devices)
+        */
+       struct work_struct rxdone_work;
+       struct work_struct txdone_work;
+
        /*
         * Data queue arrays for RX, TX and Beacon.
         * The Beacon array also contains the Atim queue
@@ -1069,8 +1070,10 @@ static inline void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
  */
 void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev);
 void rt2x00lib_pretbtt(struct rt2x00_dev *rt2x00dev);
+void rt2x00lib_dmadone(struct queue_entry *entry);
 void rt2x00lib_txdone(struct queue_entry *entry,
                      struct txdone_entry_desc *txdesc);
+void rt2x00lib_txdone_noinfo(struct queue_entry *entry, u32 status);
 void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
                      struct queue_entry *entry);
 
index 953dc4f2c6affa5f808928718089aa1e12bde312..34f34fa7f53a60ec04db9b9bed0a22e23d28ed4c 100644 (file)
@@ -126,11 +126,6 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
         * ANTENNA_SW_DIVERSITY state to the driver.
         * If that happens, fallback to hardware defaults,
         * or our own default.
-        * If diversity handling is active for a particular antenna,
-        * we shouldn't overwrite that antenna.
-        * The calls to rt2x00lib_config_antenna_check()
-        * might have caused that we restore back to the already
-        * active setting. If that has happened we can quit.
         */
        if (!(ant->flags & ANTENNA_RX_DIVERSITY))
                config.rx = rt2x00lib_config_antenna_check(config.rx, def->rx);
@@ -142,9 +137,6 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
        else
                config.tx = active->tx;
 
-       if (config.rx == active->rx && config.tx == active->tx)
-               return;
-
        /*
         * Antenna setup changes require the RX to be disabled,
         * else the changes will be ignored by the device.
@@ -209,10 +201,8 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
                rt2x00link_reset_tuner(rt2x00dev, false);
 
        rt2x00dev->curr_band = conf->channel->band;
+       rt2x00dev->curr_freq = conf->channel->center_freq;
        rt2x00dev->tx_power = conf->power_level;
        rt2x00dev->short_retry = conf->short_frame_max_tx_count;
        rt2x00dev->long_retry = conf->long_frame_max_tx_count;
-
-       rt2x00dev->rx_status.band = conf->channel->band;
-       rt2x00dev->rx_status.freq = conf->channel->center_freq;
 }
index 583dacd8d2419dadc08af51dbaa8d7f9e30b7760..5e9074bf2b8efbb7eac0ad72db70474604557a72 100644 (file)
 
 enum cipher rt2x00crypto_key_to_cipher(struct ieee80211_key_conf *key)
 {
-       switch (key->alg) {
-       case ALG_WEP:
-               if (key->keylen == WLAN_KEY_LEN_WEP40)
-                       return CIPHER_WEP64;
-               else
-                       return CIPHER_WEP128;
-       case ALG_TKIP:
+       switch (key->cipher) {
+       case WLAN_CIPHER_SUITE_WEP40:
+               return CIPHER_WEP64;
+       case WLAN_CIPHER_SUITE_WEP104:
+               return CIPHER_WEP128;
+       case WLAN_CIPHER_SUITE_TKIP:
                return CIPHER_TKIP;
-       case ALG_CCMP:
+       case WLAN_CIPHER_SUITE_CCMP:
                return CIPHER_AES;
        default:
                return CIPHER_NONE;
@@ -95,7 +94,7 @@ unsigned int rt2x00crypto_tx_overhead(struct rt2x00_dev *rt2x00dev,
                overhead += key->iv_len;
 
        if (!(key->flags & IEEE80211_KEY_FLAG_GENERATE_MMIC)) {
-               if (key->alg == ALG_TKIP)
+               if (key->cipher == WLAN_CIPHER_SUITE_TKIP)
                        overhead += 8;
        }
 
index b0498e7e7aae95a733eef24bbb139ee0486c690b..b8cf45c4e9f53ccf3ec250700b25eed71901a991 100644 (file)
@@ -333,12 +333,12 @@ static ssize_t rt2x00debug_read_queue_stats(struct file *file,
        if (*offset)
                return 0;
 
-       data = kzalloc(lines * MAX_LINE_LENGTH, GFP_KERNEL);
+       data = kcalloc(lines, MAX_LINE_LENGTH, GFP_KERNEL);
        if (!data)
                return -ENOMEM;
 
        temp = data +
-           sprintf(data, "qid\tcount\tlimit\tlength\tindex\tdone\tcrypto\n");
+           sprintf(data, "qid\tcount\tlimit\tlength\tindex\tdma done\tdone\n");
 
        queue_for_each(intf->rt2x00dev, queue) {
                spin_lock_irqsave(&queue->lock, irqflags);
@@ -346,8 +346,8 @@ static ssize_t rt2x00debug_read_queue_stats(struct file *file,
                temp += sprintf(temp, "%d\t%d\t%d\t%d\t%d\t%d\t%d\n", queue->qid,
                                queue->count, queue->limit, queue->length,
                                queue->index[Q_INDEX],
-                               queue->index[Q_INDEX_DONE],
-                               queue->index[Q_INDEX_CRYPTO]);
+                               queue->index[Q_INDEX_DMA_DONE],
+                               queue->index[Q_INDEX_DONE]);
 
                spin_unlock_irqrestore(&queue->lock, irqflags);
        }
@@ -481,6 +481,9 @@ static ssize_t rt2x00debug_write_##__name(struct file *file,        \
        if (index >= debug->__name.word_count)                  \
                return -EINVAL;                                 \
                                                                \
+       if (length > sizeof(line))                              \
+               return -EINVAL;                                 \
+                                                               \
        if (copy_from_user(line, buf, length))                  \
                return -EFAULT;                                 \
                                                                \
index 585e8166f22a635f628a5524d040d0f1807b3805..053fdd3bd7206c56836a7aa73aed12e155edd026 100644 (file)
@@ -1,5 +1,6 @@
 /*
-       Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
+       Copyright (C) 2010 Willow Garage <http://www.willowgarage.com>
+       Copyright (C) 2004 - 2010 Ivo van Doorn <IvDoorn@gmail.com>
        <http://rt2x00.serialmonkey.com>
 
        This program is free software; you can redistribute it and/or modify
@@ -250,6 +251,12 @@ void rt2x00lib_pretbtt(struct rt2x00_dev *rt2x00dev)
 }
 EXPORT_SYMBOL_GPL(rt2x00lib_pretbtt);
 
+void rt2x00lib_dmadone(struct queue_entry *entry)
+{
+       rt2x00queue_index_inc(entry->queue, Q_INDEX_DMA_DONE);
+}
+EXPORT_SYMBOL_GPL(rt2x00lib_dmadone);
+
 void rt2x00lib_txdone(struct queue_entry *entry,
                      struct txdone_entry_desc *txdesc)
 {
@@ -383,15 +390,7 @@ void rt2x00lib_txdone(struct queue_entry *entry,
         * send the status report back.
         */
        if (!(skbdesc_flags & SKBDESC_NOT_MAC80211))
-               /*
-                * Only PCI and SOC devices process the tx status in process
-                * context. Hence use ieee80211_tx_status for PCI and SOC
-                * devices and stick to ieee80211_tx_status_irqsafe for USB.
-                */
-               if (rt2x00_is_usb(rt2x00dev))
-                       ieee80211_tx_status_irqsafe(rt2x00dev->hw, entry->skb);
-               else
-                       ieee80211_tx_status(rt2x00dev->hw, entry->skb);
+               ieee80211_tx_status(rt2x00dev->hw, entry->skb);
        else
                dev_kfree_skb_any(entry->skb);
 
@@ -403,7 +402,6 @@ void rt2x00lib_txdone(struct queue_entry *entry,
 
        rt2x00dev->ops->lib->clear_entry(entry);
 
-       clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
        rt2x00queue_index_inc(entry->queue, Q_INDEX_DONE);
 
        /*
@@ -416,6 +414,18 @@ void rt2x00lib_txdone(struct queue_entry *entry,
 }
 EXPORT_SYMBOL_GPL(rt2x00lib_txdone);
 
+void rt2x00lib_txdone_noinfo(struct queue_entry *entry, u32 status)
+{
+       struct txdone_entry_desc txdesc;
+
+       txdesc.flags = 0;
+       __set_bit(status, &txdesc.flags);
+       txdesc.retry = 0;
+
+       rt2x00lib_txdone(entry, &txdesc);
+}
+EXPORT_SYMBOL_GPL(rt2x00lib_txdone_noinfo);
+
 static int rt2x00lib_rxdone_read_signal(struct rt2x00_dev *rt2x00dev,
                                        struct rxdone_entry_desc *rxdesc)
 {
@@ -460,9 +470,13 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
 {
        struct rxdone_entry_desc rxdesc;
        struct sk_buff *skb;
-       struct ieee80211_rx_status *rx_status = &rt2x00dev->rx_status;
+       struct ieee80211_rx_status *rx_status;
        unsigned int header_length;
        int rate_idx;
+
+       if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags))
+               goto submit_entry;
+
        /*
         * Allocate a new sk_buffer. If no new buffer available, drop the
         * received frame and reuse the existing buffer.
@@ -527,39 +541,32 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
         */
        rt2x00link_update_stats(rt2x00dev, entry->skb, &rxdesc);
        rt2x00debug_update_crypto(rt2x00dev, &rxdesc);
+       rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_RXDONE, entry->skb);
 
+       /*
+        * Initialize RX status information, and send frame
+        * to mac80211.
+        */
+       rx_status = IEEE80211_SKB_RXCB(entry->skb);
        rx_status->mactime = rxdesc.timestamp;
+       rx_status->band = rt2x00dev->curr_band;
+       rx_status->freq = rt2x00dev->curr_freq;
        rx_status->rate_idx = rate_idx;
        rx_status->signal = rxdesc.rssi;
        rx_status->flag = rxdesc.flags;
        rx_status->antenna = rt2x00dev->link.ant.active.rx;
 
-       /*
-        * Send frame to mac80211 & debugfs.
-        * mac80211 will clean up the skb structure.
-        */
-       rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_RXDONE, entry->skb);
-       memcpy(IEEE80211_SKB_RXCB(entry->skb), rx_status, sizeof(*rx_status));
-
-       /*
-        * Currently only PCI and SOC devices handle rx interrupts in process
-        * context. Hence, use ieee80211_rx_irqsafe for USB and ieee80211_rx_ni
-        * for PCI and SOC devices.
-        */
-       if (rt2x00_is_usb(rt2x00dev))
-               ieee80211_rx_irqsafe(rt2x00dev->hw, entry->skb);
-       else
-               ieee80211_rx_ni(rt2x00dev->hw, entry->skb);
+       ieee80211_rx_ni(rt2x00dev->hw, entry->skb);
 
        /*
         * Replace the skb with the freshly allocated one.
         */
        entry->skb = skb;
-       entry->flags = 0;
 
+submit_entry:
        rt2x00dev->ops->lib->clear_entry(entry);
-
        rt2x00queue_index_inc(entry->queue, Q_INDEX);
+       rt2x00queue_index_inc(entry->queue, Q_INDEX_DONE);
 }
 EXPORT_SYMBOL_GPL(rt2x00lib_rxdone);
 
@@ -710,7 +717,7 @@ static int rt2x00lib_probe_hw_modes(struct rt2x00_dev *rt2x00dev,
        for (i = 0; i < spec->num_channels; i++) {
                rt2x00lib_channel(&channels[i],
                                  spec->channels[i].channel,
-                                 spec->channels_info[i].tx_power1, i);
+                                 spec->channels_info[i].max_power, i);
        }
 
        /*
@@ -1017,6 +1024,8 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev)
         * Stop all work.
         */
        cancel_work_sync(&rt2x00dev->intf_work);
+       cancel_work_sync(&rt2x00dev->rxdone_work);
+       cancel_work_sync(&rt2x00dev->txdone_work);
 
        /*
         * Uninitialize device.
index b818a43c4672733792295f2dec5163137e860ce4..f0e1eb72befc0abff02c5f7e2f33d8d610c70cdd 100644 (file)
@@ -63,6 +63,9 @@ static int rt2x00lib_request_firmware(struct rt2x00_dev *rt2x00dev)
 
        INFO(rt2x00dev, "Firmware detected - version: %d.%d.\n",
             fw->data[fw->size - 4], fw->data[fw->size - 3]);
+       snprintf(rt2x00dev->hw->wiphy->fw_version,
+                       sizeof(rt2x00dev->hw->wiphy->fw_version), "%d.%d",
+                       fw->data[fw->size - 4], fw->data[fw->size - 3]);
 
        retval = rt2x00dev->ops->lib->check_firmware(rt2x00dev, fw->data, fw->size);
        switch (retval) {
index c004cd3a8847c852c5b007ec5cdf2faf220c16f5..ad3c7ff4837b5bc96fb4efc6e74d69aa84fefe0c 100644 (file)
@@ -54,6 +54,16 @@ void rt2x00ht_create_tx_descriptor(struct queue_entry *entry,
         */
        if (txrate->flags & IEEE80211_TX_RC_MCS) {
                txdesc->mcs = txrate->idx;
+
+               /*
+                * MIMO PS should be set to 1 for STA's using dynamic SM PS
+                * when using more then one tx stream (>MCS7).
+                */
+               if (tx_info->control.sta && txdesc->mcs > 7 &&
+                   (tx_info->control.sta->ht_cap.cap &
+                    (WLAN_HT_CAP_SM_PS_DYNAMIC <<
+                     IEEE80211_HT_CAP_SM_PS_SHIFT)))
+                       __set_bit(ENTRY_TXD_HT_MIMO_PS, &txdesc->flags);
        } else {
                txdesc->mcs = rt2x00_get_rate_mcs(hwrate->mcs);
                if (txrate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
index a3401d301058870745879c6ec0b19fa2d29ebfda..eede99939db917936462a3e7372b5bb010413541 100644 (file)
@@ -1,5 +1,6 @@
 /*
-       Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
+       Copyright (C) 2010 Willow Garage <http://www.willowgarage.com>
+       Copyright (C) 2004 - 2010 Ivo van Doorn <IvDoorn@gmail.com>
        Copyright (C) 2004 - 2009 Gertjan van Wingerde <gwingerde@gmail.com>
        <http://rt2x00.serialmonkey.com>
 
@@ -311,7 +312,7 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
        /*
         * Initialize information from queue
         */
-       txdesc->queue = entry->queue->qid;
+       txdesc->qid = entry->queue->qid;
        txdesc->cw_min = entry->queue->cw_min;
        txdesc->cw_max = entry->queue->cw_max;
        txdesc->aifs = entry->queue->aifs;
@@ -448,15 +449,14 @@ static void rt2x00queue_write_tx_descriptor(struct queue_entry *entry,
                                            struct txentry_desc *txdesc)
 {
        struct data_queue *queue = entry->queue;
-       struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
 
-       rt2x00dev->ops->lib->write_tx_desc(rt2x00dev, entry->skb, txdesc);
+       queue->rt2x00dev->ops->lib->write_tx_desc(entry, txdesc);
 
        /*
         * All processing on the frame has been completed, this means
         * it is now ready to be dumped to userspace through debugfs.
         */
-       rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_TX, entry->skb);
+       rt2x00debug_dump_frame(queue->rt2x00dev, DUMP_FRAME_TX, entry->skb);
 }
 
 static void rt2x00queue_kick_tx_queue(struct queue_entry *entry,
@@ -476,7 +476,7 @@ static void rt2x00queue_kick_tx_queue(struct queue_entry *entry,
         */
        if (rt2x00queue_threshold(queue) ||
            !test_bit(ENTRY_TXD_BURST, &txdesc->flags))
-               rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, queue->qid);
+               rt2x00dev->ops->lib->kick_tx_queue(queue);
 }
 
 int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb,
@@ -590,7 +590,7 @@ int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev,
        intf->beacon->skb = NULL;
 
        if (!enable_beacon) {
-               rt2x00dev->ops->lib->kill_tx_queue(rt2x00dev, QID_BEACON);
+               rt2x00dev->ops->lib->kill_tx_queue(intf->beacon->queue);
                mutex_unlock(&intf->beacon_skb_mutex);
                return 0;
        }
@@ -625,6 +625,51 @@ int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev,
        return 0;
 }
 
+void rt2x00queue_for_each_entry(struct data_queue *queue,
+                               enum queue_index start,
+                               enum queue_index end,
+                               void (*fn)(struct queue_entry *entry))
+{
+       unsigned long irqflags;
+       unsigned int index_start;
+       unsigned int index_end;
+       unsigned int i;
+
+       if (unlikely(start >= Q_INDEX_MAX || end >= Q_INDEX_MAX)) {
+               ERROR(queue->rt2x00dev,
+                     "Entry requested from invalid index range (%d - %d)\n",
+                     start, end);
+               return;
+       }
+
+       /*
+        * Only protect the range we are going to loop over,
+        * if during our loop a extra entry is set to pending
+        * it should not be kicked during this run, since it
+        * is part of another TX operation.
+        */
+       spin_lock_irqsave(&queue->lock, irqflags);
+       index_start = queue->index[start];
+       index_end = queue->index[end];
+       spin_unlock_irqrestore(&queue->lock, irqflags);
+
+       /*
+        * Start from the TX done pointer, this guarentees that we will
+        * send out all frames in the correct order.
+        */
+       if (index_start < index_end) {
+               for (i = index_start; i < index_end; i++)
+                       fn(&queue->entries[i]);
+       } else {
+               for (i = index_start; i < queue->limit; i++)
+                       fn(&queue->entries[i]);
+
+               for (i = 0; i < index_end; i++)
+                       fn(&queue->entries[i]);
+       }
+}
+EXPORT_SYMBOL_GPL(rt2x00queue_for_each_entry);
+
 struct data_queue *rt2x00queue_get_queue(struct rt2x00_dev *rt2x00dev,
                                         const enum data_queue_qid queue)
 {
@@ -686,13 +731,13 @@ void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index)
        if (queue->index[index] >= queue->limit)
                queue->index[index] = 0;
 
+       queue->last_action[index] = jiffies;
+
        if (index == Q_INDEX) {
                queue->length++;
-               queue->last_index = jiffies;
        } else if (index == Q_INDEX_DONE) {
                queue->length--;
                queue->count++;
-               queue->last_index_done = jiffies;
        }
 
        spin_unlock_irqrestore(&queue->lock, irqflags);
@@ -701,14 +746,17 @@ void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index)
 static void rt2x00queue_reset(struct data_queue *queue)
 {
        unsigned long irqflags;
+       unsigned int i;
 
        spin_lock_irqsave(&queue->lock, irqflags);
 
        queue->count = 0;
        queue->length = 0;
-       queue->last_index = jiffies;
-       queue->last_index_done = jiffies;
-       memset(queue->index, 0, sizeof(queue->index));
+
+       for (i = 0; i < Q_INDEX_MAX; i++) {
+               queue->index[i] = 0;
+               queue->last_action[i] = jiffies;
+       }
 
        spin_unlock_irqrestore(&queue->lock, irqflags);
 }
@@ -718,7 +766,7 @@ void rt2x00queue_stop_queues(struct rt2x00_dev *rt2x00dev)
        struct data_queue *queue;
 
        txall_queue_for_each(rt2x00dev, queue)
-               rt2x00dev->ops->lib->kill_tx_queue(rt2x00dev, queue->qid);
+               rt2x00dev->ops->lib->kill_tx_queue(queue);
 }
 
 void rt2x00queue_init_queues(struct rt2x00_dev *rt2x00dev)
@@ -730,9 +778,9 @@ void rt2x00queue_init_queues(struct rt2x00_dev *rt2x00dev)
                rt2x00queue_reset(queue);
 
                for (i = 0; i < queue->limit; i++) {
-                       queue->entries[i].flags = 0;
-
                        rt2x00dev->ops->lib->clear_entry(&queue->entries[i]);
+                       if (queue->qid == QID_RX)
+                               rt2x00queue_index_inc(queue, Q_INDEX);
                }
        }
 }
@@ -755,7 +803,7 @@ static int rt2x00queue_alloc_entries(struct data_queue *queue,
         * Allocate all queue entries.
         */
        entry_size = sizeof(*entries) + qdesc->priv_size;
-       entries = kzalloc(queue->limit * entry_size, GFP_KERNEL);
+       entries = kcalloc(queue->limit, entry_size, GFP_KERNEL);
        if (!entries)
                return -ENOMEM;
 
@@ -891,7 +939,7 @@ int rt2x00queue_allocate(struct rt2x00_dev *rt2x00dev)
         */
        rt2x00dev->data_queues = 2 + rt2x00dev->ops->tx_queues + req_atim;
 
-       queue = kzalloc(rt2x00dev->data_queues * sizeof(*queue), GFP_KERNEL);
+       queue = kcalloc(rt2x00dev->data_queues, sizeof(*queue), GFP_KERNEL);
        if (!queue) {
                ERROR(rt2x00dev, "Queue allocation failed.\n");
                return -ENOMEM;
index 191e7775a9c0b418f791a134ca13217b6f91b25d..d81d85f3486611cb79b18571694727c9616d7885 100644 (file)
@@ -1,5 +1,5 @@
 /*
-       Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
+       Copyright (C) 2004 - 2010 Ivo van Doorn <IvDoorn@gmail.com>
        <http://rt2x00.serialmonkey.com>
 
        This program is free software; you can redistribute it and/or modify
@@ -268,6 +268,7 @@ struct txdone_entry_desc {
  * @ENTRY_TXD_HT_AMPDU: This frame is part of an AMPDU.
  * @ENTRY_TXD_HT_BW_40: Use 40MHz Bandwidth.
  * @ENTRY_TXD_HT_SHORT_GI: Use short GI.
+ * @ENTRY_TXD_HT_MIMO_PS: The receiving STA is in dynamic SM PS mode.
  */
 enum txentry_desc_flags {
        ENTRY_TXD_RTS_FRAME,
@@ -286,6 +287,7 @@ enum txentry_desc_flags {
        ENTRY_TXD_HT_AMPDU,
        ENTRY_TXD_HT_BW_40,
        ENTRY_TXD_HT_SHORT_GI,
+       ENTRY_TXD_HT_MIMO_PS,
 };
 
 /**
@@ -294,7 +296,7 @@ enum txentry_desc_flags {
  * Summary of information for the frame descriptor before sending a TX frame.
  *
  * @flags: Descriptor flags (See &enum queue_entry_flags).
- * @queue: Queue identification (See &enum data_queue_qid).
+ * @qid: Queue identification (See &enum data_queue_qid).
  * @length: Length of the entire frame.
  * @header_length: Length of 802.11 header.
  * @length_high: PLCP length high word.
@@ -320,7 +322,7 @@ enum txentry_desc_flags {
 struct txentry_desc {
        unsigned long flags;
 
-       enum data_queue_qid queue;
+       enum data_queue_qid qid;
 
        u16 length;
        u16 header_length;
@@ -358,17 +360,17 @@ struct txentry_desc {
  * @ENTRY_OWNER_DEVICE_DATA: This entry is owned by the device for data
  *     transfer (either TX or RX depending on the queue). The entry should
  *     only be touched after the device has signaled it is done with it.
- * @ENTRY_OWNER_DEVICE_CRYPTO: This entry is owned by the device for data
- *     encryption or decryption. The entry should only be touched after
- *     the device has signaled it is done with it.
  * @ENTRY_DATA_PENDING: This entry contains a valid frame and is waiting
  *     for the signal to start sending.
+ * @ENTRY_DATA_IO_FAILED: Hardware indicated that an IO error occured
+ *     while transfering the data to the hardware. No TX status report will
+ *     be expected from the hardware.
  */
 enum queue_entry_flags {
        ENTRY_BCN_ASSIGNED,
        ENTRY_OWNER_DEVICE_DATA,
-       ENTRY_OWNER_DEVICE_CRYPTO,
        ENTRY_DATA_PENDING,
+       ENTRY_DATA_IO_FAILED
 };
 
 /**
@@ -399,18 +401,18 @@ struct queue_entry {
  *
  * @Q_INDEX: Index pointer to the current entry in the queue, if this entry is
  *     owned by the hardware then the queue is considered to be full.
+ * @Q_INDEX_DMA_DONE: Index pointer for the next entry which will have been
+ *     transfered to the hardware.
  * @Q_INDEX_DONE: Index pointer to the next entry which will be completed by
  *     the hardware and for which we need to run the txdone handler. If this
  *     entry is not owned by the hardware the queue is considered to be empty.
- * @Q_INDEX_CRYPTO: Index pointer to the next entry which encryption/decription
- *     will be completed by the hardware next.
  * @Q_INDEX_MAX: Keep last, used in &struct data_queue to determine the size
  *     of the index array.
  */
 enum queue_index {
        Q_INDEX,
+       Q_INDEX_DMA_DONE,
        Q_INDEX_DONE,
-       Q_INDEX_CRYPTO,
        Q_INDEX_MAX,
 };
 
@@ -446,13 +448,12 @@ struct data_queue {
        enum data_queue_qid qid;
 
        spinlock_t lock;
-       unsigned long last_index;
-       unsigned long last_index_done;
        unsigned int count;
        unsigned short limit;
        unsigned short threshold;
        unsigned short length;
        unsigned short index[Q_INDEX_MAX];
+       unsigned long last_action[Q_INDEX_MAX];
 
        unsigned short txop;
        unsigned short aifs;
@@ -564,6 +565,22 @@ struct data_queue_desc {
 #define txall_queue_for_each(__dev, __entry) \
        queue_loop(__entry, (__dev)->tx, queue_end(__dev))
 
+/**
+ * rt2x00queue_for_each_entry - Loop through all entries in the queue
+ * @queue: Pointer to @data_queue
+ * @start: &enum queue_index Pointer to start index
+ * @end: &enum queue_index Pointer to end index
+ * @fn: The function to call for each &struct queue_entry
+ *
+ * This will walk through all entries in the queue, in chronological
+ * order. This means it will start at the current @start pointer
+ * and will walk through the queue until it reaches the @end pointer.
+ */
+void rt2x00queue_for_each_entry(struct data_queue *queue,
+                               enum queue_index start,
+                               enum queue_index end,
+                               void (*fn)(struct queue_entry *entry));
+
 /**
  * rt2x00queue_empty - Check if the queue is empty.
  * @queue: Queue to check if empty.
@@ -601,12 +618,23 @@ static inline int rt2x00queue_threshold(struct data_queue *queue)
 }
 
 /**
- * rt2x00queue_timeout - Check if a timeout occured for this queue
+ * rt2x00queue_timeout - Check if a timeout occured for STATUS reorts
  * @queue: Queue to check.
  */
 static inline int rt2x00queue_timeout(struct data_queue *queue)
 {
-       return time_after(queue->last_index, queue->last_index_done + (HZ / 10));
+       return time_after(queue->last_action[Q_INDEX_DMA_DONE],
+                         queue->last_action[Q_INDEX_DONE] + (HZ / 10));
+}
+
+/**
+ * rt2x00queue_timeout - Check if a timeout occured for DMA transfers
+ * @queue: Queue to check.
+ */
+static inline int rt2x00queue_dma_timeout(struct data_queue *queue)
+{
+       return time_after(queue->last_action[Q_INDEX],
+                         queue->last_action[Q_INDEX_DMA_DONE] + (HZ / 10));
 }
 
 /**
index ff3a36622d1b88de75353a72f8abc35ee5d26c44..4c5ae3d456253ac0a1525fbe592ff9869c06bbc1 100644 (file)
@@ -1,5 +1,6 @@
 /*
-       Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
+       Copyright (C) 2010 Willow Garage <http://www.willowgarage.com>
+       Copyright (C) 2004 - 2010 Ivo van Doorn <IvDoorn@gmail.com>
        <http://rt2x00.serialmonkey.com>
 
        This program is free software; you can redistribute it and/or modify
@@ -167,137 +168,142 @@ EXPORT_SYMBOL_GPL(rt2x00usb_regbusy_read);
 /*
  * TX data handlers.
  */
-static void rt2x00usb_interrupt_txdone(struct urb *urb)
+static void rt2x00usb_work_txdone_entry(struct queue_entry *entry)
 {
-       struct queue_entry *entry = (struct queue_entry *)urb->context;
-       struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
-       struct txdone_entry_desc txdesc;
-
-       if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags) ||
-           !test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
-               return;
-
        /*
-        * Obtain the status about this packet.
-        * Note that when the status is 0 it does not mean the
+        * If the transfer to hardware succeeded, it does not mean the
         * frame was send out correctly. It only means the frame
         * was succesfully pushed to the hardware, we have no
         * way to determine the transmission status right now.
         * (Only indirectly by looking at the failed TX counters
         * in the register).
         */
-       txdesc.flags = 0;
-       if (!urb->status)
-               __set_bit(TXDONE_UNKNOWN, &txdesc.flags);
+       if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags))
+               rt2x00lib_txdone_noinfo(entry, TXDONE_FAILURE);
        else
-               __set_bit(TXDONE_FAILURE, &txdesc.flags);
-       txdesc.retry = 0;
-
-       rt2x00lib_txdone(entry, &txdesc);
+               rt2x00lib_txdone_noinfo(entry, TXDONE_UNKNOWN);
 }
 
-static inline void rt2x00usb_kick_tx_entry(struct queue_entry *entry)
+static void rt2x00usb_work_txdone(struct work_struct *work)
 {
-       struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
-       struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);
-       struct queue_entry_priv_usb *entry_priv = entry->priv_data;
-       u32 length;
+       struct rt2x00_dev *rt2x00dev =
+           container_of(work, struct rt2x00_dev, txdone_work);
+       struct data_queue *queue;
+       struct queue_entry *entry;
 
-       if (test_and_clear_bit(ENTRY_DATA_PENDING, &entry->flags)) {
-               /*
-                * USB devices cannot blindly pass the skb->len as the
-                * length of the data to usb_fill_bulk_urb. Pass the skb
-                * to the driver to determine what the length should be.
-                */
-               length = rt2x00dev->ops->lib->get_tx_data_len(entry);
+       tx_queue_for_each(rt2x00dev, queue) {
+               while (!rt2x00queue_empty(queue)) {
+                       entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
 
-               usb_fill_bulk_urb(entry_priv->urb, usb_dev,
-                                 usb_sndbulkpipe(usb_dev, entry->queue->usb_endpoint),
-                                 entry->skb->data, length,
-                                 rt2x00usb_interrupt_txdone, entry);
+                       if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
+                               break;
 
-               usb_submit_urb(entry_priv->urb, GFP_ATOMIC);
+                       rt2x00usb_work_txdone_entry(entry);
+               }
        }
 }
 
-void rt2x00usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
-                            const enum data_queue_qid qid)
+static void rt2x00usb_interrupt_txdone(struct urb *urb)
 {
-       struct data_queue *queue = rt2x00queue_get_queue(rt2x00dev, qid);
-       unsigned long irqflags;
-       unsigned int index;
-       unsigned int index_done;
-       unsigned int i;
+       struct queue_entry *entry = (struct queue_entry *)urb->context;
+       struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
+
+       if (!__test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
+               return;
 
        /*
-        * Only protect the range we are going to loop over,
-        * if during our loop a extra entry is set to pending
-        * it should not be kicked during this run, since it
-        * is part of another TX operation.
+        * Report the frame as DMA done
         */
-       spin_lock_irqsave(&queue->lock, irqflags);
-       index = queue->index[Q_INDEX];
-       index_done = queue->index[Q_INDEX_DONE];
-       spin_unlock_irqrestore(&queue->lock, irqflags);
+       rt2x00lib_dmadone(entry);
 
        /*
-        * Start from the TX done pointer, this guarentees that we will
-        * send out all frames in the correct order.
+        * Check if the frame was correctly uploaded
         */
-       if (index_done < index) {
-               for (i = index_done; i < index; i++)
-                       rt2x00usb_kick_tx_entry(&queue->entries[i]);
-       } else {
-               for (i = index_done; i < queue->limit; i++)
-                       rt2x00usb_kick_tx_entry(&queue->entries[i]);
+       if (urb->status)
+               __set_bit(ENTRY_DATA_IO_FAILED, &entry->flags);
 
-               for (i = 0; i < index; i++)
-                       rt2x00usb_kick_tx_entry(&queue->entries[i]);
-       }
+       /*
+        * Schedule the delayed work for reading the TX status
+        * from the device.
+        */
+       if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) &&
+           test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
+               ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->txdone_work);
+}
+
+static void rt2x00usb_kick_tx_entry(struct queue_entry *entry)
+{
+       struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
+       struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);
+       struct queue_entry_priv_usb *entry_priv = entry->priv_data;
+       u32 length;
+
+       if (!test_and_clear_bit(ENTRY_DATA_PENDING, &entry->flags))
+               return;
+
+       /*
+        * USB devices cannot blindly pass the skb->len as the
+        * length of the data to usb_fill_bulk_urb. Pass the skb
+        * to the driver to determine what the length should be.
+        */
+       length = rt2x00dev->ops->lib->get_tx_data_len(entry);
+
+       usb_fill_bulk_urb(entry_priv->urb, usb_dev,
+                         usb_sndbulkpipe(usb_dev, entry->queue->usb_endpoint),
+                         entry->skb->data, length,
+                         rt2x00usb_interrupt_txdone, entry);
+
+       usb_submit_urb(entry_priv->urb, GFP_ATOMIC);
+}
+
+void rt2x00usb_kick_tx_queue(struct data_queue *queue)
+{
+       rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX,
+                                  rt2x00usb_kick_tx_entry);
 }
 EXPORT_SYMBOL_GPL(rt2x00usb_kick_tx_queue);
 
-void rt2x00usb_kill_tx_queue(struct rt2x00_dev *rt2x00dev,
-                            const enum data_queue_qid qid)
+static void rt2x00usb_kill_tx_entry(struct queue_entry *entry)
 {
-       struct data_queue *queue = rt2x00queue_get_queue(rt2x00dev, qid);
-       struct queue_entry_priv_usb *entry_priv;
-       struct queue_entry_priv_usb_bcn *bcn_priv;
-       unsigned int i;
-       bool kill_guard;
+       struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
+       struct queue_entry_priv_usb *entry_priv = entry->priv_data;
+       struct queue_entry_priv_usb_bcn *bcn_priv = entry->priv_data;
+
+       if (!test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
+               return;
+
+       usb_kill_urb(entry_priv->urb);
 
        /*
-        * When killing the beacon queue, we must also kill
-        * the beacon guard byte.
+        * Kill guardian urb (if required by driver).
         */
-       kill_guard =
-           (qid == QID_BEACON) &&
-           (test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags));
+       if ((entry->queue->qid == QID_BEACON) &&
+           (test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags)))
+               usb_kill_urb(bcn_priv->guardian_urb);
 
        /*
-        * Cancel all entries.
+        * We need a short delay here to wait for
+        * the URB to be canceled
         */
-       for (i = 0; i < queue->limit; i++) {
-               entry_priv = queue->entries[i].priv_data;
-               usb_kill_urb(entry_priv->urb);
+       do {
+               udelay(100);
+       } while (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags));
+}
 
-               /*
-                * Kill guardian urb (if required by driver).
-                */
-               if (kill_guard) {
-                       bcn_priv = queue->entries[i].priv_data;
-                       usb_kill_urb(bcn_priv->guardian_urb);
-               }
-       }
+void rt2x00usb_kill_tx_queue(struct data_queue *queue)
+{
+       rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX,
+                                  rt2x00usb_kill_tx_entry);
 }
 EXPORT_SYMBOL_GPL(rt2x00usb_kill_tx_queue);
 
-static void rt2x00usb_watchdog_reset_tx(struct data_queue *queue)
+static void rt2x00usb_watchdog_tx_dma(struct data_queue *queue)
 {
-       struct queue_entry_priv_usb *entry_priv;
+       struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
        unsigned short threshold = queue->threshold;
 
-       WARNING(queue->rt2x00dev, "TX queue %d timed out, invoke reset", queue->qid);
+       WARNING(queue->rt2x00dev, "TX queue %d DMA timed out,"
+               " invoke forced forced reset", queue->qid);
 
        /*
         * Temporarily disable the TX queue, this will force mac80211
@@ -307,20 +313,33 @@ static void rt2x00usb_watchdog_reset_tx(struct data_queue *queue)
         * queue from being enabled during the txdone handler.
         */
        queue->threshold = queue->limit;
-       ieee80211_stop_queue(queue->rt2x00dev->hw, queue->qid);
+       ieee80211_stop_queue(rt2x00dev->hw, queue->qid);
 
        /*
-        * Reset all currently uploaded TX frames.
+        * Kill all entries in the queue, afterwards we need to
+        * wait a bit for all URBs to be cancelled.
         */
-       while (!rt2x00queue_empty(queue)) {
-               entry_priv = rt2x00queue_get_entry(queue, Q_INDEX_DONE)->priv_data;
-               usb_kill_urb(entry_priv->urb);
+       rt2x00usb_kill_tx_queue(queue);
 
-               /*
-                * We need a short delay here to wait for
-                * the URB to be canceled and invoked the tx_done handler.
-                */
-               udelay(200);
+       /*
+        * In case that a driver has overriden the txdone_work
+        * function, we invoke the TX done through there.
+        */
+       rt2x00dev->txdone_work.func(&rt2x00dev->txdone_work);
+
+       /*
+        * Security measure: if the driver did override the
+        * txdone_work function, and the hardware did arrive
+        * in a state which causes it to malfunction, it is
+        * possible that the driver couldn't handle the txdone
+        * event correctly. So after giving the driver the
+        * chance to cleanup, we now force a cleanup of any
+        * leftovers.
+        */
+       if (!rt2x00queue_empty(queue)) {
+               WARNING(queue->rt2x00dev, "TX queue %d DMA timed out,"
+                       " status handling failed, invoke hard reset", queue->qid);
+               rt2x00usb_work_txdone(&rt2x00dev->txdone_work);
        }
 
        /*
@@ -328,7 +347,15 @@ static void rt2x00usb_watchdog_reset_tx(struct data_queue *queue)
         * queue again.
         */
        queue->threshold = threshold;
-       ieee80211_wake_queue(queue->rt2x00dev->hw, queue->qid);
+       ieee80211_wake_queue(rt2x00dev->hw, queue->qid);
+}
+
+static void rt2x00usb_watchdog_tx_status(struct data_queue *queue)
+{
+       WARNING(queue->rt2x00dev, "TX queue %d status timed out,"
+               " invoke forced tx handler", queue->qid);
+
+       ieee80211_queue_work(queue->rt2x00dev->hw, &queue->rt2x00dev->txdone_work);
 }
 
 void rt2x00usb_watchdog(struct rt2x00_dev *rt2x00dev)
@@ -336,8 +363,10 @@ void rt2x00usb_watchdog(struct rt2x00_dev *rt2x00dev)
        struct data_queue *queue;
 
        tx_queue_for_each(rt2x00dev, queue) {
+               if (rt2x00queue_dma_timeout(queue))
+                       rt2x00usb_watchdog_tx_dma(queue);
                if (rt2x00queue_timeout(queue))
-                       rt2x00usb_watchdog_reset_tx(queue);
+                       rt2x00usb_watchdog_tx_status(queue);
        }
 }
 EXPORT_SYMBOL_GPL(rt2x00usb_watchdog);
@@ -345,38 +374,62 @@ EXPORT_SYMBOL_GPL(rt2x00usb_watchdog);
 /*
  * RX data handlers.
  */
+static void rt2x00usb_work_rxdone(struct work_struct *work)
+{
+       struct rt2x00_dev *rt2x00dev =
+           container_of(work, struct rt2x00_dev, rxdone_work);
+       struct queue_entry *entry;
+       struct skb_frame_desc *skbdesc;
+       u8 rxd[32];
+
+       while (!rt2x00queue_empty(rt2x00dev->rx)) {
+               entry = rt2x00queue_get_entry(rt2x00dev->rx, Q_INDEX_DONE);
+
+               if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
+                       break;
+
+               /*
+                * Fill in desc fields of the skb descriptor
+                */
+               skbdesc = get_skb_frame_desc(entry->skb);
+               skbdesc->desc = rxd;
+               skbdesc->desc_len = entry->queue->desc_size;
+
+               /*
+                * Send the frame to rt2x00lib for further processing.
+                */
+               rt2x00lib_rxdone(rt2x00dev, entry);
+       }
+}
+
 static void rt2x00usb_interrupt_rxdone(struct urb *urb)
 {
        struct queue_entry *entry = (struct queue_entry *)urb->context;
        struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
-       struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
-       u8 rxd[32];
 
-       if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags) ||
-           !test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
+       if (!__test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
                return;
 
        /*
-        * Check if the received data is simply too small
-        * to be actually valid, or if the urb is signaling
-        * a problem.
+        * Report the frame as DMA done
         */
-       if (urb->actual_length < entry->queue->desc_size || urb->status) {
-               set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
-               usb_submit_urb(urb, GFP_ATOMIC);
-               return;
-       }
+       rt2x00lib_dmadone(entry);
 
        /*
-        * Fill in desc fields of the skb descriptor
+        * Check if the received data is simply too small
+        * to be actually valid, or if the urb is signaling
+        * a problem.
         */
-       skbdesc->desc = rxd;
-       skbdesc->desc_len = entry->queue->desc_size;
+       if (urb->actual_length < entry->queue->desc_size || urb->status)
+               __set_bit(ENTRY_DATA_IO_FAILED, &entry->flags);
 
        /*
-        * Send the frame to rt2x00lib for further processing.
+        * Schedule the delayed work for reading the RX status
+        * from the device.
         */
-       rt2x00lib_rxdone(rt2x00dev, entry);
+       if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) &&
+           test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
+               ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->rxdone_work);
 }
 
 /*
@@ -391,7 +444,7 @@ void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev)
         * The USB version of kill_tx_queue also works
         * on the RX queue.
         */
-       rt2x00dev->ops->lib->kill_tx_queue(rt2x00dev, QID_RX);
+       rt2x00dev->ops->lib->kill_tx_queue(rt2x00dev->rx);
 }
 EXPORT_SYMBOL_GPL(rt2x00usb_disable_radio);
 
@@ -405,6 +458,8 @@ void rt2x00usb_clear_entry(struct queue_entry *entry)
        struct queue_entry_priv_usb *entry_priv = entry->priv_data;
        int pipe;
 
+       entry->flags = 0;
+
        if (entry->queue->qid == QID_RX) {
                pipe = usb_rcvbulkpipe(usb_dev, entry->queue->usb_endpoint);
                usb_fill_bulk_urb(entry_priv->urb, usb_dev, pipe,
@@ -413,8 +468,6 @@ void rt2x00usb_clear_entry(struct queue_entry *entry)
 
                set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
                usb_submit_urb(entry_priv->urb, GFP_ATOMIC);
-       } else {
-               entry->flags = 0;
        }
 }
 EXPORT_SYMBOL_GPL(rt2x00usb_clear_entry);
@@ -659,6 +712,9 @@ int rt2x00usb_probe(struct usb_interface *usb_intf,
 
        rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_USB);
 
+       INIT_WORK(&rt2x00dev->rxdone_work, rt2x00usb_work_rxdone);
+       INIT_WORK(&rt2x00dev->txdone_work, rt2x00usb_work_txdone);
+
        retval = rt2x00usb_alloc_reg(rt2x00dev);
        if (retval)
                goto exit_free_device;
index d3d3ddc408759d755a8e55df993ee0c4853084c8..c2d997f67b3e718a9bc2fe063e5245acff3a852e 100644 (file)
@@ -379,25 +379,21 @@ struct queue_entry_priv_usb_bcn {
 
 /**
  * rt2x00usb_kick_tx_queue - Kick data queue
- * @rt2x00dev: Pointer to &struct rt2x00_dev
- * @qid: Data queue to kick
+ * @queue: Data queue to kick
  *
  * This will walk through all entries of the queue and push all pending
  * frames to the hardware as a single burst.
  */
-void rt2x00usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
-                            const enum data_queue_qid qid);
+void rt2x00usb_kick_tx_queue(struct data_queue *queue);
 
 /**
  * rt2x00usb_kill_tx_queue - Kill data queue
- * @rt2x00dev: Pointer to &struct rt2x00_dev
- * @qid: Data queue to kill
+ * @queue: Data queue to kill
  *
  * This will walk through all entries of the queue and kill all
  * previously kicked frames before they can be send.
  */
-void rt2x00usb_kill_tx_queue(struct rt2x00_dev *rt2x00dev,
-                             const enum data_queue_qid qid);
+void rt2x00usb_kill_tx_queue(struct data_queue *queue);
 
 /**
  * rt2x00usb_watchdog - Watchdog for USB communication
index e539c6cb636fd5d429f30c50fba98e1a6512b70c..3a7759929190b78674aed60783fb5b6793124f4c 100644 (file)
@@ -1050,7 +1050,7 @@ static void rt61pci_link_tuner(struct rt2x00_dev *rt2x00dev,
        /*
         * Determine r17 bounds.
         */
-       if (rt2x00dev->rx_status.band == IEEE80211_BAND_5GHZ) {
+       if (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ) {
                low_bound = 0x28;
                up_bound = 0x48;
                if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) {
@@ -1766,12 +1766,11 @@ static int rt61pci_set_device_state(struct rt2x00_dev *rt2x00dev,
 /*
  * TX descriptor initialization
  */
-static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
-                                 struct sk_buff *skb,
+static void rt61pci_write_tx_desc(struct queue_entry *entry,
                                  struct txentry_desc *txdesc)
 {
-       struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
-       struct queue_entry_priv_pci *entry_priv = skbdesc->entry->priv_data;
+       struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
+       struct queue_entry_priv_pci *entry_priv = entry->priv_data;
        __le32 *txd = entry_priv->desc;
        u32 word;
 
@@ -1779,7 +1778,7 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
         * Start writing the descriptor words.
         */
        rt2x00_desc_read(txd, 1, &word);
-       rt2x00_set_field32(&word, TXD_W1_HOST_Q_ID, txdesc->queue);
+       rt2x00_set_field32(&word, TXD_W1_HOST_Q_ID, txdesc->qid);
        rt2x00_set_field32(&word, TXD_W1_AIFSN, txdesc->aifs);
        rt2x00_set_field32(&word, TXD_W1_CWMIN, txdesc->cw_min);
        rt2x00_set_field32(&word, TXD_W1_CWMAX, txdesc->cw_max);
@@ -1802,15 +1801,15 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
        }
 
        rt2x00_desc_read(txd, 5, &word);
-       rt2x00_set_field32(&word, TXD_W5_PID_TYPE, skbdesc->entry->queue->qid);
+       rt2x00_set_field32(&word, TXD_W5_PID_TYPE, entry->queue->qid);
        rt2x00_set_field32(&word, TXD_W5_PID_SUBTYPE,
                           skbdesc->entry->entry_idx);
        rt2x00_set_field32(&word, TXD_W5_TX_POWER,
-                          TXPOWER_TO_DEV(rt2x00dev->tx_power));
+                          TXPOWER_TO_DEV(entry->queue->rt2x00dev->tx_power));
        rt2x00_set_field32(&word, TXD_W5_WAITING_DMA_DONE_INT, 1);
        rt2x00_desc_write(txd, 5, word);
 
-       if (txdesc->queue != QID_BEACON) {
+       if (txdesc->qid != QID_BEACON) {
                rt2x00_desc_read(txd, 6, &word);
                rt2x00_set_field32(&word, TXD_W6_BUFFER_PHYSICAL_ADDRESS,
                                   skbdesc->skb_dma);
@@ -1857,7 +1856,7 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
         */
        skbdesc->desc = txd;
        skbdesc->desc_len =
-               (txdesc->queue == QID_BEACON) ?  TXINFO_SIZE : TXD_DESC_SIZE;
+               (txdesc->qid == QID_BEACON) ?  TXINFO_SIZE : TXD_DESC_SIZE;
 }
 
 /*
@@ -1882,7 +1881,7 @@ static void rt61pci_write_beacon(struct queue_entry *entry,
        /*
         * Write the TX descriptor for the beacon.
         */
-       rt61pci_write_tx_desc(rt2x00dev, entry->skb, txdesc);
+       rt61pci_write_tx_desc(entry, txdesc);
 
        /*
         * Dump beacon to userspace through debugfs.
@@ -1918,34 +1917,34 @@ static void rt61pci_write_beacon(struct queue_entry *entry,
        entry->skb = NULL;
 }
 
-static void rt61pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
-                                 const enum data_queue_qid queue)
+static void rt61pci_kick_tx_queue(struct data_queue *queue)
 {
+       struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
        u32 reg;
 
        rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
-       rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC0, (queue == QID_AC_BE));
-       rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC1, (queue == QID_AC_BK));
-       rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC2, (queue == QID_AC_VI));
-       rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC3, (queue == QID_AC_VO));
+       rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC0, (queue->qid == QID_AC_BE));
+       rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC1, (queue->qid == QID_AC_BK));
+       rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC2, (queue->qid == QID_AC_VI));
+       rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC3, (queue->qid == QID_AC_VO));
        rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
 }
 
-static void rt61pci_kill_tx_queue(struct rt2x00_dev *rt2x00dev,
-                                 const enum data_queue_qid qid)
+static void rt61pci_kill_tx_queue(struct data_queue *queue)
 {
+       struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
        u32 reg;
 
-       if (qid == QID_BEACON) {
+       if (queue->qid == QID_BEACON) {
                rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, 0);
                return;
        }
 
        rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
-       rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC0, (qid == QID_AC_BE));
-       rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC1, (qid == QID_AC_BK));
-       rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC2, (qid == QID_AC_VI));
-       rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC3, (qid == QID_AC_VO));
+       rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC0, (queue->qid == QID_AC_BE));
+       rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC1, (queue->qid == QID_AC_BK));
+       rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC2, (queue->qid == QID_AC_VI));
+       rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC3, (queue->qid == QID_AC_VO));
        rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
 }
 
@@ -1972,7 +1971,7 @@ static int rt61pci_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1)
                return 0;
        }
 
-       if (rt2x00dev->rx_status.band == IEEE80211_BAND_5GHZ) {
+       if (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ) {
                if (lna == 3 || lna == 2)
                        offset += 10;
        }
@@ -2107,11 +2106,7 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev)
                                "TX status report missed for entry %d\n",
                                entry_done->entry_idx);
 
-                       txdesc.flags = 0;
-                       __set_bit(TXDONE_UNKNOWN, &txdesc.flags);
-                       txdesc.retry = 0;
-
-                       rt2x00lib_txdone(entry_done, &txdesc);
+                       rt2x00lib_txdone_noinfo(entry, TXDONE_UNKNOWN);
                        entry_done = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
                }
 
@@ -2654,20 +2649,24 @@ static int rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
        /*
         * Create channel information array
         */
-       info = kzalloc(spec->num_channels * sizeof(*info), GFP_KERNEL);
+       info = kcalloc(spec->num_channels, sizeof(*info), GFP_KERNEL);
        if (!info)
                return -ENOMEM;
 
        spec->channels_info = info;
 
        tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_G_START);
-       for (i = 0; i < 14; i++)
-               info[i].tx_power1 = TXPOWER_FROM_DEV(tx_power[i]);
+       for (i = 0; i < 14; i++) {
+               info[i].max_power = MAX_TXPOWER;
+               info[i].default_power1 = TXPOWER_FROM_DEV(tx_power[i]);
+       }
 
        if (spec->num_channels > 14) {
                tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A_START);
-               for (i = 14; i < spec->num_channels; i++)
-                       info[i].tx_power1 = TXPOWER_FROM_DEV(tx_power[i]);
+               for (i = 14; i < spec->num_channels; i++) {
+                       info[i].max_power = MAX_TXPOWER;
+                       info[i].default_power1 = TXPOWER_FROM_DEV(tx_power[i]);
+               }
        }
 
        return 0;
index aa9de18fd410f016c452008e7852abcf5adc937c..87fb2201537b68d96fd2882dfc230129e98ed074 100644 (file)
@@ -929,7 +929,7 @@ static void rt73usb_link_tuner(struct rt2x00_dev *rt2x00dev,
        /*
         * Determine r17 bounds.
         */
-       if (rt2x00dev->rx_status.band == IEEE80211_BAND_5GHZ) {
+       if (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ) {
                low_bound = 0x28;
                up_bound = 0x48;
 
@@ -1426,12 +1426,11 @@ static int rt73usb_set_device_state(struct rt2x00_dev *rt2x00dev,
 /*
  * TX descriptor initialization
  */
-static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
-                                 struct sk_buff *skb,
+static void rt73usb_write_tx_desc(struct queue_entry *entry,
                                  struct txentry_desc *txdesc)
 {
-       struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
-       __le32 *txd = (__le32 *) skb->data;
+       struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
+       __le32 *txd = (__le32 *) entry->skb->data;
        u32 word;
 
        /*
@@ -1464,7 +1463,7 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
        rt2x00_desc_write(txd, 0, word);
 
        rt2x00_desc_read(txd, 1, &word);
-       rt2x00_set_field32(&word, TXD_W1_HOST_Q_ID, txdesc->queue);
+       rt2x00_set_field32(&word, TXD_W1_HOST_Q_ID, txdesc->qid);
        rt2x00_set_field32(&word, TXD_W1_AIFSN, txdesc->aifs);
        rt2x00_set_field32(&word, TXD_W1_CWMIN, txdesc->cw_min);
        rt2x00_set_field32(&word, TXD_W1_CWMAX, txdesc->cw_max);
@@ -1487,7 +1486,7 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
 
        rt2x00_desc_read(txd, 5, &word);
        rt2x00_set_field32(&word, TXD_W5_TX_POWER,
-                          TXPOWER_TO_DEV(rt2x00dev->tx_power));
+                          TXPOWER_TO_DEV(entry->queue->rt2x00dev->tx_power));
        rt2x00_set_field32(&word, TXD_W5_WAITING_DMA_DONE_INT, 1);
        rt2x00_desc_write(txd, 5, word);
 
@@ -1526,7 +1525,7 @@ static void rt73usb_write_beacon(struct queue_entry *entry,
        /*
         * Write the TX descriptor for the beacon.
         */
-       rt73usb_write_tx_desc(rt2x00dev, entry->skb, txdesc);
+       rt73usb_write_tx_desc(entry, txdesc);
 
        /*
         * Dump beacon to userspace through debugfs.
@@ -1574,6 +1573,14 @@ static int rt73usb_get_tx_data_len(struct queue_entry *entry)
        return length;
 }
 
+static void rt73usb_kill_tx_queue(struct data_queue *queue)
+{
+       if (queue->qid == QID_BEACON)
+               rt2x00usb_register_write(queue->rt2x00dev, TXRX_CSR9, 0);
+
+       rt2x00usb_kill_tx_queue(queue);
+}
+
 /*
  * RX control handlers
  */
@@ -1597,7 +1604,7 @@ static int rt73usb_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1)
                return 0;
        }
 
-       if (rt2x00dev->rx_status.band == IEEE80211_BAND_5GHZ) {
+       if (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ) {
                if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) {
                        if (lna == 3 || lna == 2)
                                offset += 10;
@@ -2084,20 +2091,24 @@ static int rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
        /*
         * Create channel information array
         */
-       info = kzalloc(spec->num_channels * sizeof(*info), GFP_KERNEL);
+       info = kcalloc(spec->num_channels, sizeof(*info), GFP_KERNEL);
        if (!info)
                return -ENOMEM;
 
        spec->channels_info = info;
 
        tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_G_START);
-       for (i = 0; i < 14; i++)
-               info[i].tx_power1 = TXPOWER_FROM_DEV(tx_power[i]);
+       for (i = 0; i < 14; i++) {
+               info[i].max_power = MAX_TXPOWER;
+               info[i].default_power1 = TXPOWER_FROM_DEV(tx_power[i]);
+       }
 
        if (spec->num_channels > 14) {
                tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A_START);
-               for (i = 14; i < spec->num_channels; i++)
-                       info[i].tx_power1 = TXPOWER_FROM_DEV(tx_power[i]);
+               for (i = 14; i < spec->num_channels; i++) {
+                       info[i].max_power = MAX_TXPOWER;
+                       info[i].default_power1 = TXPOWER_FROM_DEV(tx_power[i]);
+               }
        }
 
        return 0;
@@ -2259,7 +2270,7 @@ static const struct rt2x00lib_ops rt73usb_rt2x00_ops = {
        .write_beacon           = rt73usb_write_beacon,
        .get_tx_data_len        = rt73usb_get_tx_data_len,
        .kick_tx_queue          = rt2x00usb_kick_tx_queue,
-       .kill_tx_queue          = rt2x00usb_kill_tx_queue,
+       .kill_tx_queue          = rt73usb_kill_tx_queue,
        .fill_rxdone            = rt73usb_fill_rxdone,
        .config_shared_key      = rt73usb_config_shared_key,
        .config_pairwise_key    = rt73usb_config_pairwise_key,
index 30107ce78dfb6cc8613c83c5ca525a5e8bf42314..05c6badbe201a892eb57a431ebdffd5d1630efcf 100644 (file)
@@ -99,19 +99,66 @@ void rtl8180_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data)
        }
 }
 
-static void rtl8180_handle_rx(struct ieee80211_hw *dev)
+static void rtl8180_handle_tx(struct ieee80211_hw *dev)
 {
        struct rtl8180_priv *priv = dev->priv;
-       unsigned int count = 32;
+       struct rtl8180_tx_ring *ring;
+       int prio;
+
+       spin_lock(&priv->lock);
+
+       for (prio = 3; prio >= 0; prio--) {
+               ring = &priv->tx_ring[prio];
+
+               while (skb_queue_len(&ring->queue)) {
+                       struct rtl8180_tx_desc *entry = &ring->desc[ring->idx];
+                       struct sk_buff *skb;
+                       struct ieee80211_tx_info *info;
+                       u32 flags = le32_to_cpu(entry->flags);
+
+                       if (flags & RTL818X_TX_DESC_FLAG_OWN)
+                               break;
+
+                       ring->idx = (ring->idx + 1) % ring->entries;
+                       skb = __skb_dequeue(&ring->queue);
+                       pci_unmap_single(priv->pdev, le32_to_cpu(entry->tx_buf),
+                                        skb->len, PCI_DMA_TODEVICE);
+
+                       info = IEEE80211_SKB_CB(skb);
+                       ieee80211_tx_info_clear_status(info);
+
+                       if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) &&
+                           (flags & RTL818X_TX_DESC_FLAG_TX_OK))
+                               info->flags |= IEEE80211_TX_STAT_ACK;
+
+                       info->status.rates[0].count = (flags & 0xFF) + 1;
+                       info->status.rates[1].idx = -1;
+
+                       ieee80211_tx_status(dev, skb);
+                       if (ring->entries - skb_queue_len(&ring->queue) == 2)
+                               ieee80211_wake_queue(dev, prio);
+               }
+       }
+
+       spin_unlock(&priv->lock);
+}
+
+static int rtl8180_poll(struct ieee80211_hw *dev, int budget)
+{
+       struct rtl8180_priv *priv = dev->priv;
+       unsigned int count = 0;
        u8 signal, agc, sq;
 
-       while (count--) {
+       /* handle pending Tx queue cleanup */
+       rtl8180_handle_tx(dev);
+
+       while (count++ < budget) {
                struct rtl8180_rx_desc *entry = &priv->rx_ring[priv->rx_idx];
                struct sk_buff *skb = priv->rx_buf[priv->rx_idx];
                u32 flags = le32_to_cpu(entry->flags);
 
                if (flags & RTL818X_RX_DESC_FLAG_OWN)
-                       return;
+                       break;
 
                if (unlikely(flags & (RTL818X_RX_DESC_FLAG_DMA_FAIL |
                                      RTL818X_RX_DESC_FLAG_FOF |
@@ -151,7 +198,7 @@ static void rtl8180_handle_rx(struct ieee80211_hw *dev)
                                rx_status.flag |= RX_FLAG_FAILED_FCS_CRC;
 
                        memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status));
-                       ieee80211_rx_irqsafe(dev, skb);
+                       ieee80211_rx(dev, skb);
 
                        skb = new_skb;
                        priv->rx_buf[priv->rx_idx] = skb;
@@ -168,41 +215,16 @@ static void rtl8180_handle_rx(struct ieee80211_hw *dev)
                        entry->flags |= cpu_to_le32(RTL818X_RX_DESC_FLAG_EOR);
                priv->rx_idx = (priv->rx_idx + 1) % 32;
        }
-}
 
-static void rtl8180_handle_tx(struct ieee80211_hw *dev, unsigned int prio)
-{
-       struct rtl8180_priv *priv = dev->priv;
-       struct rtl8180_tx_ring *ring = &priv->tx_ring[prio];
+       if (count < budget) {
+               /* disable polling */
+               ieee80211_napi_complete(dev);
 
-       while (skb_queue_len(&ring->queue)) {
-               struct rtl8180_tx_desc *entry = &ring->desc[ring->idx];
-               struct sk_buff *skb;
-               struct ieee80211_tx_info *info;
-               u32 flags = le32_to_cpu(entry->flags);
-
-               if (flags & RTL818X_TX_DESC_FLAG_OWN)
-                       return;
-
-               ring->idx = (ring->idx + 1) % ring->entries;
-               skb = __skb_dequeue(&ring->queue);
-               pci_unmap_single(priv->pdev, le32_to_cpu(entry->tx_buf),
-                                skb->len, PCI_DMA_TODEVICE);
-
-               info = IEEE80211_SKB_CB(skb);
-               ieee80211_tx_info_clear_status(info);
-
-               if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) &&
-                   (flags & RTL818X_TX_DESC_FLAG_TX_OK))
-                       info->flags |= IEEE80211_TX_STAT_ACK;
-
-               info->status.rates[0].count = (flags & 0xFF) + 1;
-               info->status.rates[1].idx = -1;
-
-               ieee80211_tx_status_irqsafe(dev, skb);
-               if (ring->entries - skb_queue_len(&ring->queue) == 2)
-                       ieee80211_wake_queue(dev, prio);
+               /* enable interrupts */
+               rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0xFFFF);
        }
+
+       return count;
 }
 
 static irqreturn_t rtl8180_interrupt(int irq, void *dev_id)
@@ -211,31 +233,17 @@ static irqreturn_t rtl8180_interrupt(int irq, void *dev_id)
        struct rtl8180_priv *priv = dev->priv;
        u16 reg;
 
-       spin_lock(&priv->lock);
        reg = rtl818x_ioread16(priv, &priv->map->INT_STATUS);
-       if (unlikely(reg == 0xFFFF)) {
-               spin_unlock(&priv->lock);
+       if (unlikely(reg == 0xFFFF))
                return IRQ_HANDLED;
-       }
 
        rtl818x_iowrite16(priv, &priv->map->INT_STATUS, reg);
 
-       if (reg & (RTL818X_INT_TXB_OK | RTL818X_INT_TXB_ERR))
-               rtl8180_handle_tx(dev, 3);
-
-       if (reg & (RTL818X_INT_TXH_OK | RTL818X_INT_TXH_ERR))
-               rtl8180_handle_tx(dev, 2);
-
-       if (reg & (RTL818X_INT_TXN_OK | RTL818X_INT_TXN_ERR))
-               rtl8180_handle_tx(dev, 1);
-
-       if (reg & (RTL818X_INT_TXL_OK | RTL818X_INT_TXL_ERR))
-               rtl8180_handle_tx(dev, 0);
-
-       if (reg & (RTL818X_INT_RX_OK | RTL818X_INT_RX_ERR))
-               rtl8180_handle_rx(dev);
+       /* disable interrupts */
+       rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0);
 
-       spin_unlock(&priv->lock);
+       /* enable polling */
+       ieee80211_napi_schedule(dev);
 
        return IRQ_HANDLED;
 }
@@ -247,7 +255,6 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
        struct rtl8180_priv *priv = dev->priv;
        struct rtl8180_tx_ring *ring;
        struct rtl8180_tx_desc *entry;
-       unsigned long flags;
        unsigned int idx, prio;
        dma_addr_t mapping;
        u32 tx_flags;
@@ -294,7 +301,7 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
                        plcp_len |= 1 << 15;
        }
 
-       spin_lock_irqsave(&priv->lock, flags);
+       spin_lock(&priv->lock);
 
        if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
                if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
@@ -318,7 +325,7 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
        if (ring->entries - skb_queue_len(&ring->queue) < 2)
                ieee80211_stop_queue(dev, prio);
 
-       spin_unlock_irqrestore(&priv->lock, flags);
+       spin_unlock(&priv->lock);
 
        rtl818x_iowrite8(priv, &priv->map->TX_DMA_POLLING, (1 << (prio + 4)));
 
@@ -783,6 +790,7 @@ static void rtl8180_bss_info_changed(struct ieee80211_hw *dev,
        struct rtl8180_priv *priv = dev->priv;
        struct rtl8180_vif *vif_priv;
        int i;
+       u8 reg;
 
        vif_priv = (struct rtl8180_vif *)&vif->drv_priv;
 
@@ -791,12 +799,14 @@ static void rtl8180_bss_info_changed(struct ieee80211_hw *dev,
                        rtl818x_iowrite8(priv, &priv->map->BSSID[i],
                                         info->bssid[i]);
 
-               if (is_valid_ether_addr(info->bssid))
-                       rtl818x_iowrite8(priv, &priv->map->MSR,
-                                        RTL818X_MSR_INFRA);
-               else
-                       rtl818x_iowrite8(priv, &priv->map->MSR,
-                                        RTL818X_MSR_NO_LINK);
+               if (is_valid_ether_addr(info->bssid)) {
+                       if (vif->type == NL80211_IFTYPE_ADHOC)
+                               reg = RTL818X_MSR_ADHOC;
+                       else
+                               reg = RTL818X_MSR_INFRA;
+               } else
+                       reg = RTL818X_MSR_NO_LINK;
+               rtl818x_iowrite8(priv, &priv->map->MSR, reg);
        }
 
        if (changed & BSS_CHANGED_ERP_SLOT && priv->rf->conf_erp)
@@ -861,6 +871,7 @@ static const struct ieee80211_ops rtl8180_ops = {
        .prepare_multicast      = rtl8180_prepare_multicast,
        .configure_filter       = rtl8180_configure_filter,
        .get_tsf                = rtl8180_get_tsf,
+       .napi_poll              = rtl8180_poll,
 };
 
 static void rtl8180_eeprom_register_read(struct eeprom_93cx6 *eeprom)
@@ -992,6 +1003,8 @@ static int __devinit rtl8180_probe(struct pci_dev *pdev,
        dev->queues = 1;
        dev->max_signal = 65;
 
+       dev->napi_weight = 64;
+
        reg = rtl818x_ioread32(priv, &priv->map->TX_CONF);
        reg &= RTL818X_TX_CONF_HWVER_MASK;
        switch (reg) {
index 98e0351c1dd6923214b17919161793c873d89967..38fa8244cc96d93d26f7d7201d4d2d1a85c129c9 100644 (file)
@@ -1176,13 +1176,12 @@ static void rtl8187_bss_info_changed(struct ieee80211_hw *dev,
                else
                        reg = 0;
 
-               if (is_valid_ether_addr(info->bssid)) {
+               if (is_valid_ether_addr(info->bssid))
                        reg |= RTL818X_MSR_INFRA;
-                       rtl818x_iowrite8(priv, &priv->map->MSR, reg);
-               } else {
+               else
                        reg |= RTL818X_MSR_NO_LINK;
-                       rtl818x_iowrite8(priv, &priv->map->MSR, reg);
-               }
+
+               rtl818x_iowrite8(priv, &priv->map->MSR, reg);
 
                mutex_unlock(&priv->conf_mutex);
        }
index 6b942a28e6a5dd02e87cebd8f20273e234cdea10..e113d4c1fb357924d20a342d4ec214b6fde33c85 100644 (file)
@@ -4,8 +4,6 @@
  * Copyright (c) 1998-2007 Texas Instruments Incorporated
  * Copyright (C) 2008-2009 Nokia Corporation
  *
- * Contact: Kalle Valo <kalle.valo@nokia.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.
@@ -274,6 +272,8 @@ struct wl1251 {
        int irq;
        bool use_eeprom;
 
+       spinlock_t wl_lock;
+
        enum wl1251_state state;
        struct mutex mutex;
 
@@ -401,7 +401,8 @@ void wl1251_disable_interrupts(struct wl1251 *wl);
 
 #define WL1251_DEFAULT_POWER_LEVEL 20
 
-#define WL1251_TX_QUEUE_MAX_LENGTH 20
+#define WL1251_TX_QUEUE_LOW_WATERMARK  10
+#define WL1251_TX_QUEUE_HIGH_WATERMARK 25
 
 #define WL1251_DEFAULT_BEACON_INT 100
 #define WL1251_DEFAULT_DTIM_PERIOD 1
index 91891f9280706266b2ab8e6f8d283e587d833c70..2f8a2ba744dce84c6afdb6336272abe0fdfb8d90 100644 (file)
@@ -380,7 +380,7 @@ int wl1251_acx_pd_threshold(struct wl1251 *wl)
 
 out:
        kfree(pd);
-       return 0;
+       return ret;
 }
 
 int wl1251_acx_slot(struct wl1251 *wl, enum acx_slot_type slot_time)
index 842df310d92a61554f44184273b3470608b9a165..c7cc5c1e8a7571a5f3098a87ad71c83238a1a7e0 100644 (file)
@@ -4,8 +4,6 @@
  * Copyright (c) 1998-2007 Texas Instruments Incorporated
  * Copyright (C) 2008 Nokia Corporation
  *
- * Contact: Kalle Valo <kalle.valo@nokia.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.
@@ -37,7 +35,7 @@ struct acx_header {
 
        /* payload length (not including headers */
        u16 len;
-};
+} __packed;
 
 struct acx_error_counter {
        struct acx_header header;
@@ -459,8 +457,8 @@ struct acx_beacon_filter_ie_table {
        struct acx_header header;
 
        u8 num_ie;
-       u8 table[BEACON_FILTER_TABLE_MAX_SIZE];
        u8 pad[3];
+       u8 table[BEACON_FILTER_TABLE_MAX_SIZE];
 } __packed;
 
 #define SYNCH_FAIL_DEFAULT_THRESHOLD    10     /* number of beacons */
@@ -471,7 +469,7 @@ struct acx_conn_monit_params {
 
        u32 synch_fail_thold; /* number of beacons missed */
        u32 bss_lose_timeout; /* number of TU's from synch fail */
-};
+} __packed;
 
 enum {
        SG_ENABLE = 0,
@@ -1056,7 +1054,7 @@ struct acx_rate_class {
        u8 long_retry_limit;
        u8 aflags;
        u8 reserved;
-};
+} __packed;
 
 struct acx_rate_policy {
        struct acx_header header;
index 65e0416be5b6975642ea589a105b39bda95b5e32..468b47b0328a01c65b63318e78b49bfc0fd0b8b8 100644 (file)
@@ -3,8 +3,6 @@
  *
  * Copyright (C) 2008 Nokia Corporation
  *
- * Contact: Kalle Valo <kalle.valo@nokia.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.
@@ -302,7 +300,7 @@ int wl1251_boot_run_firmware(struct wl1251 *wl)
                ROAMING_TRIGGER_LOW_RSSI_EVENT_ID |
                ROAMING_TRIGGER_REGAINED_RSSI_EVENT_ID |
                REGAINED_BSS_EVENT_ID | BT_PTA_SENSE_EVENT_ID |
-               BT_PTA_PREDICTION_EVENT_ID;
+               BT_PTA_PREDICTION_EVENT_ID | JOIN_EVENT_COMPLETE_ID;
 
        ret = wl1251_event_unmask(wl);
        if (ret < 0) {
index 90063697e8f279f9590af39aff1e735ce408ffc7..7661bc5e46627182fe040af0e73b6265e17d9aee 100644 (file)
@@ -3,8 +3,6 @@
  *
  * Copyright (C) 2008 Nokia Corporation
  *
- * Contact: Kalle Valo <kalle.valo@nokia.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.
index ce3722f4c3e38e532c587051bce253257bcd89eb..15fb68c6b542629bd2d2c389380c489751cd2e41 100644 (file)
@@ -200,7 +200,7 @@ int wl1251_cmd_vbm(struct wl1251 *wl, u8 identity,
 
 out:
        kfree(vbm);
-       return 0;
+       return ret;
 }
 
 int wl1251_cmd_data_path(struct wl1251 *wl, u8 channel, bool enable)
index a9e4991369be5d47d3a1de2f9029649476b324f0..e5c74c631374cd0c051574dff620b0a200f3d83a 100644 (file)
@@ -4,8 +4,6 @@
  * Copyright (c) 1998-2007 Texas Instruments Incorporated
  * Copyright (C) 2008 Nokia Corporation
  *
- * Contact: Kalle Valo <kalle.valo@nokia.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.
@@ -111,7 +109,7 @@ struct wl1251_cmd_header {
 struct  wl1251_command {
        struct wl1251_cmd_header header;
        u8  parameters[MAX_CMD_PARAMS];
-};
+} __packed;
 
 enum {
        CMD_MAILBOX_IDLE                        =  0,
@@ -164,7 +162,7 @@ struct cmd_read_write_memory {
           of this field is the Host in WRITE command or the Wilink in READ
           command. */
        u8 value[MAX_READ_SIZE];
-};
+} __packed;
 
 #define CMDMBOX_HEADER_LEN 4
 #define CMDMBOX_INFO_ELEM_HEADER_LEN 4
@@ -339,7 +337,7 @@ struct wl1251_cmd_trigger_scan_to {
        struct wl1251_cmd_header header;
 
        u32 timeout;
-};
+} __packed;
 
 /* HW encryption keys */
 #define NUM_ACCESS_CATEGORIES_COPY 4
index 5e4465ac08fadbbb435db0ad890edc4d610e2ae6..6ffe4cd5856140caf384ecbd4d638c86e54a2538 100644 (file)
@@ -3,8 +3,6 @@
  *
  * Copyright (C) 2009 Nokia Corporation
  *
- * Contact: Kalle Valo <kalle.valo@nokia.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.
index 6dc3d080853c47950cb9dad1fe069f3a226f247b..b3417c02a218e597e3136fb65c8f02667b02d30a 100644 (file)
@@ -3,8 +3,6 @@
  *
  * Copyright (C) 2009 Nokia Corporation
  *
- * Contact: Kalle Valo <kalle.valo@nokia.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.
index 020d764f9c135d38838297a241b3709ba02b62a1..54223556b3088d1b9078d6b8131ba6b2f08e185a 100644 (file)
@@ -4,8 +4,6 @@
  * Copyright (c) 1998-2007 Texas Instruments Incorporated
  * Copyright (C) 2008 Nokia Corporation
  *
- * Contact: Kalle Valo <kalle.valo@nokia.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.
@@ -36,9 +34,7 @@ static int wl1251_event_scan_complete(struct wl1251 *wl,
                     mbox->scheduled_scan_channels);
 
        if (wl->scanning) {
-               mutex_unlock(&wl->mutex);
                ieee80211_scan_completed(wl->hw, false);
-               mutex_lock(&wl->mutex);
                wl1251_debug(DEBUG_MAC80211, "mac80211 hw scan completed");
                wl->scanning = false;
        }
@@ -97,6 +93,35 @@ static int wl1251_event_process(struct wl1251 *wl, struct event_mailbox *mbox)
        return 0;
 }
 
+/*
+ * Poll the mailbox event field until any of the bits in the mask is set or a
+ * timeout occurs (WL1251_EVENT_TIMEOUT in msecs)
+ */
+int wl1251_event_wait(struct wl1251 *wl, u32 mask, int timeout_ms)
+{
+       u32 events_vector, event;
+       unsigned long timeout;
+
+       timeout = jiffies + msecs_to_jiffies(timeout_ms);
+
+       do {
+               if (time_after(jiffies, timeout))
+                       return -ETIMEDOUT;
+
+               msleep(1);
+
+               /* read from both event fields */
+               wl1251_mem_read(wl, wl->mbox_ptr[0], &events_vector,
+                               sizeof(events_vector));
+               event = events_vector & mask;
+               wl1251_mem_read(wl, wl->mbox_ptr[1], &events_vector,
+                               sizeof(events_vector));
+               event |= events_vector & mask;
+       } while (!event);
+
+       return 0;
+}
+
 int wl1251_event_unmask(struct wl1251 *wl)
 {
        int ret;
index f48a2b66bc5a670b673b45d19a35c5b77b14de9b..30eb5d150bf75d8ca8a653a4adc27f59f186d0a7 100644 (file)
@@ -4,8 +4,6 @@
  * Copyright (c) 1998-2007 Texas Instruments Incorporated
  * Copyright (C) 2008 Nokia Corporation
  *
- * Contact: Kalle Valo <kalle.valo@nokia.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.
@@ -117,5 +115,6 @@ struct event_mailbox {
 int wl1251_event_unmask(struct wl1251 *wl);
 void wl1251_event_mbox_config(struct wl1251 *wl);
 int wl1251_event_handle(struct wl1251 *wl, u8 mbox);
+int wl1251_event_wait(struct wl1251 *wl, u32 mask, int timeout_ms);
 
 #endif
index b538bdd7b320f41e8abdf2516d755179d780f94e..c5daec05d9eedf058804484a0544c32f5f1fea05 100644 (file)
@@ -3,8 +3,6 @@
  *
  * Copyright (C) 2009 Nokia Corporation
  *
- * Contact: Kalle Valo <kalle.valo@nokia.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.
index 269cefb3e7d43f20d96e3ca1902b1388fd5049e3..543f17582eadfda1375239011b5eb2efc03c050f 100644 (file)
@@ -3,8 +3,6 @@
  *
  * Copyright (C) 2009 Nokia Corporation
  *
- * Contact: Kalle Valo <kalle.valo@nokia.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.
index f1c232e0887fb65b2e1c51af82e3e9c9a89eac78..ad6ca68b303ffce05ee9855176e060ac8c5e4345 100644 (file)
@@ -3,8 +3,6 @@
  *
  * Copyright (C) 2008 Nokia Corporation
  *
- * Contact: Kalle Valo <kalle.valo@nokia.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.
index 861a5f33761e9ea94d15d355a360835a0766ade0..faf221ca3f41b6aa4646c633d18c9620bfb55e1e 100644 (file)
@@ -3,8 +3,6 @@
  *
  * Copyright (C) 2008-2009 Nokia Corporation
  *
- * Contact: Kalle Valo <kalle.valo@nokia.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.
@@ -293,14 +291,14 @@ static void wl1251_irq_work(struct work_struct *work)
                        wl1251_tx_complete(wl);
                }
 
-               if (intr & (WL1251_ACX_INTR_EVENT_A |
-                           WL1251_ACX_INTR_EVENT_B)) {
-                       wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_EVENT (0x%x)",
-                                    intr);
-                       if (intr & WL1251_ACX_INTR_EVENT_A)
-                               wl1251_event_handle(wl, 0);
-                       else
-                               wl1251_event_handle(wl, 1);
+               if (intr & WL1251_ACX_INTR_EVENT_A) {
+                       wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_EVENT_A");
+                       wl1251_event_handle(wl, 0);
+               }
+
+               if (intr & WL1251_ACX_INTR_EVENT_B) {
+                       wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_EVENT_B");
+                       wl1251_event_handle(wl, 1);
                }
 
                if (intr & WL1251_ACX_INTR_INIT_COMPLETE)
@@ -339,11 +337,9 @@ static int wl1251_join(struct wl1251 *wl, u8 bss_type, u8 channel,
        if (ret < 0)
                goto out;
 
-       /*
-        * FIXME: we should wait for JOIN_EVENT_COMPLETE_ID but to simplify
-        * locking we just sleep instead, for now
-        */
-       msleep(10);
+       ret = wl1251_event_wait(wl, JOIN_EVENT_COMPLETE_ID, 100);
+       if (ret < 0)
+               wl1251_warning("join timeout");
 
 out:
        return ret;
@@ -379,6 +375,7 @@ out:
 static int wl1251_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 {
        struct wl1251 *wl = hw->priv;
+       unsigned long flags;
 
        skb_queue_tail(&wl->tx_queue, skb);
 
@@ -393,16 +390,13 @@ static int wl1251_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
         * The workqueue is slow to process the tx_queue and we need stop
         * the queue here, otherwise the queue will get too long.
         */
-       if (skb_queue_len(&wl->tx_queue) >= WL1251_TX_QUEUE_MAX_LENGTH) {
+       if (skb_queue_len(&wl->tx_queue) >= WL1251_TX_QUEUE_HIGH_WATERMARK) {
                wl1251_debug(DEBUG_TX, "op_tx: tx_queue full, stop queues");
-               ieee80211_stop_queues(wl->hw);
 
-               /*
-                * FIXME: this is racy, the variable is not properly
-                * protected. Maybe fix this by removing the stupid
-                * variable altogether and checking the real queue state?
-                */
+               spin_lock_irqsave(&wl->wl_lock, flags);
+               ieee80211_stop_queues(wl->hw);
                wl->tx_queue_stopped = true;
+               spin_unlock_irqrestore(&wl->wl_lock, flags);
        }
 
        return NETDEV_TX_OK;
@@ -471,9 +465,7 @@ static void wl1251_op_stop(struct ieee80211_hw *hw)
        WARN_ON(wl->state != WL1251_STATE_ON);
 
        if (wl->scanning) {
-               mutex_unlock(&wl->mutex);
                ieee80211_scan_completed(wl->hw, true);
-               mutex_lock(&wl->mutex);
                wl->scanning = false;
        }
 
@@ -725,8 +717,9 @@ static int wl1251_set_key_type(struct wl1251 *wl,
                               struct ieee80211_key_conf *mac80211_key,
                               const u8 *addr)
 {
-       switch (mac80211_key->alg) {
-       case ALG_WEP:
+       switch (mac80211_key->cipher) {
+       case WLAN_CIPHER_SUITE_WEP40:
+       case WLAN_CIPHER_SUITE_WEP104:
                if (is_broadcast_ether_addr(addr))
                        key->key_type = KEY_WEP_DEFAULT;
                else
@@ -734,7 +727,7 @@ static int wl1251_set_key_type(struct wl1251 *wl,
 
                mac80211_key->hw_key_idx = mac80211_key->keyidx;
                break;
-       case ALG_TKIP:
+       case WLAN_CIPHER_SUITE_TKIP:
                if (is_broadcast_ether_addr(addr))
                        key->key_type = KEY_TKIP_MIC_GROUP;
                else
@@ -742,7 +735,7 @@ static int wl1251_set_key_type(struct wl1251 *wl,
 
                mac80211_key->hw_key_idx = mac80211_key->keyidx;
                break;
-       case ALG_CCMP:
+       case WLAN_CIPHER_SUITE_CCMP:
                if (is_broadcast_ether_addr(addr))
                        key->key_type = KEY_AES_GROUP;
                else
@@ -750,7 +743,7 @@ static int wl1251_set_key_type(struct wl1251 *wl,
                mac80211_key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
                break;
        default:
-               wl1251_error("Unknown key algo 0x%x", mac80211_key->alg);
+               wl1251_error("Unknown key cipher 0x%x", mac80211_key->cipher);
                return -EOPNOTSUPP;
        }
 
@@ -783,7 +776,7 @@ static int wl1251_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
        wl1251_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
        wl1251_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
        wl1251_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
-                    key->alg, key->keyidx, key->keylen, key->flags);
+                    key->cipher, key->keyidx, key->keylen, key->flags);
        wl1251_dump(DEBUG_CRYPT, "KEY: ", key->key, key->keylen);
 
        if (is_zero_ether_addr(addr)) {
@@ -1438,5 +1431,5 @@ EXPORT_SYMBOL_GPL(wl1251_free_hw);
 
 MODULE_DESCRIPTION("TI wl1251 Wireles LAN Driver Core");
 MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Kalle Valo <kalle.valo@nokia.com>");
+MODULE_AUTHOR("Kalle Valo <kvalo@adurom.com>");
 MODULE_FIRMWARE(WL1251_FW_NAME);
index b55cb2bd459aa0d278556f3b81d5ca7701fe209d..0b997bdfec09498f9ca5c562eac2becc202cdec0 100644 (file)
@@ -3,8 +3,6 @@
  *
  * Copyright (C) 2008 Nokia Corporation
  *
- * Contact: Kalle Valo <kalle.valo@nokia.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.
index c688ac57aee480cc2378c93c50f14f0f32272113..e5db81fc1dfcc8d710c6761593f6f2dcd0a3d300 100644 (file)
@@ -1,14 +1,9 @@
-#ifndef __WL1251_PS_H__
-#define __WL1251_PS_H__
-
 /*
  * This file is part of wl1251
  *
  * Copyright (c) 1998-2007 Texas Instruments Incorporated
  * Copyright (C) 2008 Nokia Corporation
  *
- * Contact: Kalle Valo <kalle.valo@nokia.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.
@@ -25,6 +20,9 @@
  *
  */
 
+#ifndef __WL1251_PS_H__
+#define __WL1251_PS_H__
+
 #include "wl1251.h"
 #include "wl1251_acx.h"
 
index d16edd9bf06c1bf9e61cb397068ba381f1da22ca..a5809019c5c19a5ced3d1f4d0b674b1e3bee6779 100644 (file)
@@ -4,8 +4,6 @@
  * Copyright (c) 1998-2007 Texas Instruments Incorporated
  * Copyright (C) 2008 Nokia Corporation
  *
- * Contact: Kalle Valo <kalle.valo@nokia.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.
index 1b6294b3b996fd9f660d17c02bc1543b9bd428dd..25764592a596c26e412d300bc36d6028cfb34ce8 100644 (file)
@@ -4,8 +4,6 @@
  * Copyright (c) 1998-2007 Texas Instruments Incorporated
  * Copyright (C) 2008 Nokia Corporation
  *
- * Contact: Kalle Valo <kalle.valo@nokia.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.
index da4e53406a0ead9810568785a1f8d5fd3a3c3b1f..4448f635a4d8e8462643ac820226b95b34ee623e 100644 (file)
@@ -4,8 +4,6 @@
  * Copyright (c) 1998-2007 Texas Instruments Incorporated
  * Copyright (C) 2008 Nokia Corporation
  *
- * Contact: Kalle Valo <kalle.valo@nokia.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.
index b901b6135654f0ce00974411ad4f69628963f596..c0b68b0a9aa894e0f7e4364151313aa175973919 100644 (file)
@@ -339,4 +339,4 @@ module_init(wl1251_sdio_init);
 module_exit(wl1251_sdio_exit);
 
 MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Kalle Valo <kalle.valo@nokia.com>");
+MODULE_AUTHOR("Kalle Valo <kvalo@adurom.com>");
index 27fdfaaeb0742c780d82ccaaf2138ed485675cec..334ded9881c02ebdb680e4a5d0b2d6d5f2a29ffa 100644 (file)
@@ -3,8 +3,6 @@
  *
  * Copyright (C) 2008 Nokia Corporation
  *
- * Contact: Kalle Valo <kalle.valo@nokia.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.
@@ -344,5 +342,5 @@ module_init(wl1251_spi_init);
 module_exit(wl1251_spi_exit);
 
 MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Kalle Valo <kalle.valo@nokia.com>");
+MODULE_AUTHOR("Kalle Valo <kvalo@adurom.com>");
 MODULE_ALIAS("spi:wl1251");
index 2e273a97e7f3ac25853485e2037aa486e88896fb..7dcf3cf7ae406f148dd94231cccaa51bc91a18ae 100644 (file)
@@ -4,8 +4,6 @@
  * Copyright (c) 1998-2007 Texas Instruments Incorporated
  * Copyright (C) 2008 Nokia Corporation
  *
- * Contact: Kalle Valo <kalle.valo@nokia.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.
index a38ec199187a99ee7ebb475d547b218b43b8f9fc..388492a7f41f0202028c49e8badbe009bcb46da8 100644 (file)
@@ -4,8 +4,6 @@
  * Copyright (c) 1998-2007 Texas Instruments Incorporated
  * Copyright (C) 2008 Nokia Corporation
  *
- * Contact: Kalle Valo <kalle.valo@nokia.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.
@@ -189,7 +187,7 @@ static int wl1251_tx_send_packet(struct wl1251 *wl, struct sk_buff *skb,
        tx_hdr = (struct tx_double_buffer_desc *) skb->data;
 
        if (control->control.hw_key &&
-           control->control.hw_key->alg == ALG_TKIP) {
+           control->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) {
                int hdrlen;
                __le16 fc;
                u16 length;
@@ -322,11 +320,6 @@ void wl1251_tx_work(struct work_struct *work)
 
                ret = wl1251_tx_frame(wl, skb);
                if (ret == -EBUSY) {
-                       /* firmware buffer is full, stop queues */
-                       wl1251_debug(DEBUG_TX, "tx_work: fw buffer full, "
-                                    "stop queues");
-                       ieee80211_stop_queues(wl->hw);
-                       wl->tx_queue_stopped = true;
                        skb_queue_head(&wl->tx_queue, skb);
                        goto out;
                } else if (ret < 0) {
@@ -399,7 +392,7 @@ static void wl1251_tx_packet_cb(struct wl1251 *wl,
         */
        frame = skb_pull(skb, sizeof(struct tx_double_buffer_desc));
        if (info->control.hw_key &&
-           info->control.hw_key->alg == ALG_TKIP) {
+           info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) {
                hdrlen = ieee80211_get_hdrlen_from_skb(skb);
                memmove(frame + WL1251_TKIP_IV_SPACE, frame, hdrlen);
                skb_pull(skb, WL1251_TKIP_IV_SPACE);
@@ -449,6 +442,7 @@ void wl1251_tx_complete(struct wl1251 *wl)
 {
        int i, result_index, num_complete = 0;
        struct tx_result result[FW_TX_CMPLT_BLOCK_SIZE], *result_ptr;
+       unsigned long flags;
 
        if (unlikely(wl->state != WL1251_STATE_ON))
                return;
@@ -477,6 +471,20 @@ void wl1251_tx_complete(struct wl1251 *wl)
                }
        }
 
+       if (wl->tx_queue_stopped
+           &&
+           skb_queue_len(&wl->tx_queue) <= WL1251_TX_QUEUE_LOW_WATERMARK){
+
+               /* firmware buffer has space, restart queues */
+               wl1251_debug(DEBUG_TX, "tx_complete: waking queues");
+               spin_lock_irqsave(&wl->wl_lock, flags);
+               ieee80211_wake_queues(wl->hw);
+               wl->tx_queue_stopped = false;
+               spin_unlock_irqrestore(&wl->wl_lock, flags);
+               ieee80211_queue_work(wl->hw, &wl->tx_work);
+
+       }
+
        /* Every completed frame needs to be acknowledged */
        if (num_complete) {
                /*
index f40eeb37f5aaf590a84a989a3bfdd93636fe5205..96011e78cd5a6751059dffb9ee3661e68d82c557 100644 (file)
@@ -4,8 +4,6 @@
  * Copyright (c) 1998-2007 Texas Instruments Incorporated
  * Copyright (C) 2008 Nokia Corporation
  *
- * Contact: Kalle Valo <kalle.valo@nokia.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.
index bb245f05af496a2535ea5324b4113f4d499a4628..f03ad088db8b3eb7535e9e29de8b19dd08a0928d 100644 (file)
@@ -269,7 +269,7 @@ int wl1271_acx_pd_threshold(struct wl1271 *wl)
 
 out:
        kfree(pd);
-       return 0;
+       return ret;
 }
 
 int wl1271_acx_slot(struct wl1271 *wl, enum acx_slot_type slot_time)
index 9d68f0012f05af67317ff6cfc9668b833e1c9d00..8e55cf8d509d8e4faa0802e3dc2d018aab97bbdf 100644 (file)
@@ -948,9 +948,7 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
                ieee80211_enable_dyn_ps(wl->vif);
 
        if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
-               mutex_unlock(&wl->mutex);
                ieee80211_scan_completed(wl->hw, true);
-               mutex_lock(&wl->mutex);
                wl->scan.state = WL1271_SCAN_STATE_IDLE;
                kfree(wl->scan.scanned_ch);
                wl->scan.scanned_ch = NULL;
@@ -1439,7 +1437,7 @@ static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
        wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
        wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
        wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
-                    key_conf->alg, key_conf->keyidx,
+                    key_conf->cipher, key_conf->keyidx,
                     key_conf->keylen, key_conf->flags);
        wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
 
@@ -1455,20 +1453,21 @@ static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
        if (ret < 0)
                goto out_unlock;
 
-       switch (key_conf->alg) {
-       case ALG_WEP:
+       switch (key_conf->cipher) {
+       case WLAN_CIPHER_SUITE_WEP40:
+       case WLAN_CIPHER_SUITE_WEP104:
                key_type = KEY_WEP;
 
                key_conf->hw_key_idx = key_conf->keyidx;
                break;
-       case ALG_TKIP:
+       case WLAN_CIPHER_SUITE_TKIP:
                key_type = KEY_TKIP;
 
                key_conf->hw_key_idx = key_conf->keyidx;
                tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
                tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
                break;
-       case ALG_CCMP:
+       case WLAN_CIPHER_SUITE_CCMP:
                key_type = KEY_AES;
 
                key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
@@ -1476,7 +1475,7 @@ static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
                tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
                break;
        default:
-               wl1271_error("Unknown key algo 0x%x", key_conf->alg);
+               wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
 
                ret = -EOPNOTSUPP;
                goto out_sleep;
index fec43eed8c553424231c6b990132b35bf8b7167b..e4950c8e396e38a57c553c81875ab51b2aa04d43 100644 (file)
@@ -215,9 +215,7 @@ void wl1271_scan_stm(struct wl1271 *wl)
                break;
 
        case WL1271_SCAN_STATE_DONE:
-               mutex_unlock(&wl->mutex);
                ieee80211_scan_completed(wl->hw, false);
-               mutex_lock(&wl->mutex);
 
                kfree(wl->scan.scanned_ch);
                wl->scan.scanned_ch = NULL;
@@ -248,7 +246,7 @@ int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len,
 
        wl->scan.req = req;
 
-       wl->scan.scanned_ch = kzalloc(req->n_channels *
+       wl->scan.scanned_ch = kcalloc(req->n_channels,
                                      sizeof(*wl->scan.scanned_ch),
                                      GFP_KERNEL);
        wl1271_scan_stm(wl);
index c592cc2e9fe88690bcfb97014a423489fbbedb6d..dc0b46c93c4b52aec49441dc518613cf6f762343 100644 (file)
@@ -193,7 +193,7 @@ static int wl1271_tx_frame(struct wl1271 *wl, struct sk_buff *skb)
        info = IEEE80211_SKB_CB(skb);
 
        if (info->control.hw_key &&
-           info->control.hw_key->alg == ALG_TKIP)
+           info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP)
                extra = WL1271_TKIP_IV_SPACE;
 
        if (info->control.hw_key) {
@@ -347,7 +347,7 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
 
        /* remove TKIP header space if present */
        if (info->control.hw_key &&
-           info->control.hw_key->alg == ALG_TKIP) {
+           info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) {
                int hdrlen = ieee80211_get_hdrlen_from_skb(skb);
                memmove(skb->data + WL1271_TKIP_IV_SPACE, skb->data, hdrlen);
                skb_pull(skb, WL1271_TKIP_IV_SPACE);
index a1cc2d498a1c01bd19b0174d1497d8bd0c0c8a8b..420e9e986a1893c8a9b2c69d3253f69a2872976d 100644 (file)
@@ -29,7 +29,6 @@
 
 #include <linux/delay.h>
 #include <linux/types.h>
-#include <linux/ethtool.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/in.h>
@@ -1411,15 +1410,6 @@ static struct iw_statistics *wl3501_get_wireless_stats(struct net_device *dev)
        return wstats;
 }
 
-static void wl3501_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
-{
-       strlcpy(info->driver, "wl3501_cs", sizeof(info->driver));
-}
-
-static const struct ethtool_ops ops = {
-       .get_drvinfo = wl3501_get_drvinfo
-};
-
 /**
  * wl3501_detach - deletes a driver "instance"
  * @link - FILL_IN
@@ -1905,7 +1895,6 @@ static int wl3501_probe(struct pcmcia_device *p_dev)
        this->p_dev = p_dev;
        dev->wireless_data      = &this->wireless_data;
        dev->wireless_handlers  = &wl3501_handler_def;
-       SET_ETHTOOL_OPS(dev, &ops);
        netif_stop_queue(dev);
        p_dev->priv = dev;
 
index b2af3c549bb39e21010051f55a3eaa21df00a30a..87a95bcfee5735f593489cf52011068f4d92e0e1 100644 (file)
@@ -973,6 +973,7 @@ static void dump_fw_registers(struct zd_chip *chip)
 
 static int print_fw_version(struct zd_chip *chip)
 {
+       struct wiphy *wiphy = zd_chip_to_mac(chip)->hw->wiphy;
        int r;
        u16 version;
 
@@ -982,6 +983,10 @@ static int print_fw_version(struct zd_chip *chip)
                return r;
 
        dev_info(zd_chip_dev(chip),"firmware version %04hx\n", version);
+
+       snprintf(wiphy->fw_version, sizeof(wiphy->fw_version),
+                       "%04hx", version);
+
        return 0;
 }
 
index b50fedcef8ac9dd9872a51ed63cb0b6c3135c778..788a9bc1dbac486f52ac048addbacf7857fe80d6 100644 (file)
@@ -1395,7 +1395,7 @@ static int setup_netfront(struct xenbus_device *dev, struct netfront_info *info)
 }
 
 /* Common code used when first setting up, and when resuming. */
-static int talk_to_backend(struct xenbus_device *dev,
+static int talk_to_netback(struct xenbus_device *dev,
                           struct netfront_info *info)
 {
        const char *message;
@@ -1545,7 +1545,7 @@ static int xennet_connect(struct net_device *dev)
                return -ENODEV;
        }
 
-       err = talk_to_backend(np->xbdev, np);
+       err = talk_to_netback(np->xbdev, np);
        if (err)
                return err;
 
@@ -1599,7 +1599,7 @@ static int xennet_connect(struct net_device *dev)
 /**
  * Callback received when the backend's state changes.
  */
-static void backend_changed(struct xenbus_device *dev,
+static void netback_changed(struct xenbus_device *dev,
                            enum xenbus_state backend_state)
 {
        struct netfront_info *np = dev_get_drvdata(&dev->dev);
@@ -1801,7 +1801,7 @@ static struct xenbus_driver netfront_driver = {
        .probe = netfront_probe,
        .remove = __devexit_p(xennet_remove),
        .resume = netfront_resume,
-       .otherend_changed = backend_changed,
+       .otherend_changed = netback_changed,
 };
 
 static int __init netif_init(void)
index ecbbb688eba08a1b337447a406284c5fd42d7fe2..f3f8be5a35fac0a47a40a40f14ee6d40bb055549 100644 (file)
@@ -641,7 +641,7 @@ static void xemaclite_rx_handler(struct net_device *dev)
        skb_put(skb, len);      /* Tell the skb how much data we got */
 
        skb->protocol = eth_type_trans(skb, dev);
-       skb->ip_summed = CHECKSUM_NONE;
+       skb_checksum_none_assert(skb);
 
        dev->stats.rx_packets++;
        dev->stats.rx_bytes += len;
@@ -1269,6 +1269,16 @@ static int __devexit xemaclite_of_remove(struct platform_device *of_dev)
        return 0;
 }
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void
+xemaclite_poll_controller(struct net_device *ndev)
+{
+       disable_irq(ndev->irq);
+       xemaclite_interrupt(ndev->irq, ndev);
+       enable_irq(ndev->irq);
+}
+#endif
+
 static struct net_device_ops xemaclite_netdev_ops = {
        .ndo_open               = xemaclite_open,
        .ndo_stop               = xemaclite_close,
@@ -1276,6 +1286,9 @@ static struct net_device_ops xemaclite_netdev_ops = {
        .ndo_set_mac_address    = xemaclite_set_mac_address,
        .ndo_tx_timeout         = xemaclite_tx_timeout,
        .ndo_get_stats          = xemaclite_get_stats,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       .ndo_poll_controller = xemaclite_poll_controller,
+#endif
 };
 
 /* Match table for OF platform binding */
index 4eb67aed68ddaf020d8e0f61020bb3bab7f55a67..cd1b3dcd61db67671e28df47cae7a19293fa881f 100644 (file)
@@ -646,7 +646,7 @@ static int yellowfin_open(struct net_device *dev)
        init_timer(&yp->timer);
        yp->timer.expires = jiffies + 3*HZ;
        yp->timer.data = (unsigned long)dev;
-       yp->timer.function = &yellowfin_timer;                          /* timer handler */
+       yp->timer.function = yellowfin_timer;                           /* timer handler */
        add_timer(&yp->timer);
 
        return 0;
index f0037eefd44e62532c5b5c23be9cd30100bd7999..0f4ef8769a3dfb9b74670a7eb4270ade36192215 100644 (file)
@@ -208,6 +208,7 @@ struct qdio_dev_perf_stat {
        unsigned int eqbs_partial;
        unsigned int sqbs;
        unsigned int sqbs_partial;
+       unsigned int int_discarded;
 } ____cacheline_aligned;
 
 struct qdio_queue_perf_stat {
@@ -222,6 +223,10 @@ struct qdio_queue_perf_stat {
        unsigned int nr_sbal_total;
 };
 
+enum qdio_queue_irq_states {
+       QDIO_QUEUE_IRQS_DISABLED,
+};
+
 struct qdio_input_q {
        /* input buffer acknowledgement flag */
        int polling;
@@ -231,6 +236,10 @@ struct qdio_input_q {
        int ack_count;
        /* last time of noticing incoming data */
        u64 timestamp;
+       /* upper-layer polling flag */
+       unsigned long queue_irq_state;
+       /* callback to start upper-layer polling */
+       void (*queue_start_poll) (struct ccw_device *, int, unsigned long);
 };
 
 struct qdio_output_q {
@@ -399,6 +408,26 @@ static inline int multicast_outbound(struct qdio_q *q)
 #define sub_buf(bufnr, dec) \
        ((bufnr - dec) & QDIO_MAX_BUFFERS_MASK)
 
+#define queue_irqs_enabled(q)                  \
+       (test_bit(QDIO_QUEUE_IRQS_DISABLED, &q->u.in.queue_irq_state) == 0)
+#define queue_irqs_disabled(q)                 \
+       (test_bit(QDIO_QUEUE_IRQS_DISABLED, &q->u.in.queue_irq_state) != 0)
+
+#define TIQDIO_SHARED_IND              63
+
+/* device state change indicators */
+struct indicator_t {
+       u32 ind;        /* u32 because of compare-and-swap performance */
+       atomic_t count; /* use count, 0 or 1 for non-shared indicators */
+};
+
+extern struct indicator_t *q_indicators;
+
+static inline int shared_ind(struct qdio_irq *irq_ptr)
+{
+       return irq_ptr->dsci == &q_indicators[TIQDIO_SHARED_IND].ind;
+}
+
 /* prototypes for thin interrupt */
 void qdio_setup_thinint(struct qdio_irq *irq_ptr);
 int qdio_establish_thinint(struct qdio_irq *irq_ptr);
index 6ce83f56d5371c5acdd0a216b9992019188a6e69..28868e7471a50122260c4c2bf7aa36784d7b460e 100644 (file)
@@ -56,9 +56,16 @@ static int qstat_show(struct seq_file *m, void *v)
 
        seq_printf(m, "DSCI: %d   nr_used: %d\n",
                   *(u32 *)q->irq_ptr->dsci, atomic_read(&q->nr_buf_used));
-       seq_printf(m, "ftc: %d  last_move: %d\n", q->first_to_check, q->last_move);
-       seq_printf(m, "polling: %d  ack start: %d  ack count: %d\n",
-                  q->u.in.polling, q->u.in.ack_start, q->u.in.ack_count);
+       seq_printf(m, "ftc: %d  last_move: %d\n",
+                  q->first_to_check, q->last_move);
+       if (q->is_input_q) {
+               seq_printf(m, "polling: %d  ack start: %d  ack count: %d\n",
+                          q->u.in.polling, q->u.in.ack_start,
+                          q->u.in.ack_count);
+               seq_printf(m, "IRQs disabled: %u\n",
+                          test_bit(QDIO_QUEUE_IRQS_DISABLED,
+                          &q->u.in.queue_irq_state));
+       }
        seq_printf(m, "SBAL states:\n");
        seq_printf(m, "|0      |8      |16     |24     |32     |40     |48     |56  63|\n");
 
@@ -113,22 +120,6 @@ static int qstat_show(struct seq_file *m, void *v)
        return 0;
 }
 
-static ssize_t qstat_seq_write(struct file *file, const char __user *buf,
-                              size_t count, loff_t *off)
-{
-       struct seq_file *seq = file->private_data;
-       struct qdio_q *q = seq->private;
-
-       if (!q)
-               return 0;
-       if (q->is_input_q)
-               xchg(q->irq_ptr->dsci, 1);
-       local_bh_disable();
-       tasklet_schedule(&q->tasklet);
-       local_bh_enable();
-       return count;
-}
-
 static int qstat_seq_open(struct inode *inode, struct file *filp)
 {
        return single_open(filp, qstat_show,
@@ -139,7 +130,6 @@ static const struct file_operations debugfs_fops = {
        .owner   = THIS_MODULE,
        .open    = qstat_seq_open,
        .read    = seq_read,
-       .write   = qstat_seq_write,
        .llseek  = seq_lseek,
        .release = single_release,
 };
@@ -166,7 +156,8 @@ static char *qperf_names[] = {
        "QEBSM eqbs",
        "QEBSM eqbs partial",
        "QEBSM sqbs",
-       "QEBSM sqbs partial"
+       "QEBSM sqbs partial",
+       "Discarded interrupts"
 };
 
 static int qperf_show(struct seq_file *m, void *v)
index 00520f9a7a8e0ae2240d10855835ef13531a8284..5fcfa7f9e9ef7d4530e94ec79d2328d6349e95d9 100644 (file)
@@ -884,8 +884,19 @@ static void qdio_int_handler_pci(struct qdio_irq *irq_ptr)
        if (unlikely(irq_ptr->state == QDIO_IRQ_STATE_STOPPED))
                return;
 
-       for_each_input_queue(irq_ptr, q, i)
-               tasklet_schedule(&q->tasklet);
+       for_each_input_queue(irq_ptr, q, i) {
+               if (q->u.in.queue_start_poll) {
+                       /* skip if polling is enabled or already in work */
+                       if (test_and_set_bit(QDIO_QUEUE_IRQS_DISABLED,
+                                    &q->u.in.queue_irq_state)) {
+                               qperf_inc(q, int_discarded);
+                               continue;
+                       }
+                       q->u.in.queue_start_poll(q->irq_ptr->cdev, q->nr,
+                                                q->irq_ptr->int_parm);
+               } else
+                       tasklet_schedule(&q->tasklet);
+       }
 
        if (!(irq_ptr->qib.ac & QIB_AC_OUTBOUND_PCI_SUPPORTED))
                return;
@@ -1519,6 +1530,129 @@ int do_QDIO(struct ccw_device *cdev, unsigned int callflags,
 }
 EXPORT_SYMBOL_GPL(do_QDIO);
 
+/**
+ * qdio_start_irq - process input buffers
+ * @cdev: associated ccw_device for the qdio subchannel
+ * @nr: input queue number
+ *
+ * Return codes
+ *   0 - success
+ *   1 - irqs not started since new data is available
+ */
+int qdio_start_irq(struct ccw_device *cdev, int nr)
+{
+       struct qdio_q *q;
+       struct qdio_irq *irq_ptr = cdev->private->qdio_data;
+
+       if (!irq_ptr)
+               return -ENODEV;
+       q = irq_ptr->input_qs[nr];
+
+       WARN_ON(queue_irqs_enabled(q));
+
+       if (!shared_ind(q->irq_ptr))
+               xchg(q->irq_ptr->dsci, 0);
+
+       qdio_stop_polling(q);
+       clear_bit(QDIO_QUEUE_IRQS_DISABLED, &q->u.in.queue_irq_state);
+
+       /*
+        * We need to check again to not lose initiative after
+        * resetting the ACK state.
+        */
+       if (!shared_ind(q->irq_ptr) && *q->irq_ptr->dsci)
+               goto rescan;
+       if (!qdio_inbound_q_done(q))
+               goto rescan;
+       return 0;
+
+rescan:
+       if (test_and_set_bit(QDIO_QUEUE_IRQS_DISABLED,
+                            &q->u.in.queue_irq_state))
+               return 0;
+       else
+               return 1;
+
+}
+EXPORT_SYMBOL(qdio_start_irq);
+
+/**
+ * qdio_get_next_buffers - process input buffers
+ * @cdev: associated ccw_device for the qdio subchannel
+ * @nr: input queue number
+ * @bufnr: first filled buffer number
+ * @error: buffers are in error state
+ *
+ * Return codes
+ *   < 0 - error
+ *   = 0 - no new buffers found
+ *   > 0 - number of processed buffers
+ */
+int qdio_get_next_buffers(struct ccw_device *cdev, int nr, int *bufnr,
+                         int *error)
+{
+       struct qdio_q *q;
+       int start, end;
+       struct qdio_irq *irq_ptr = cdev->private->qdio_data;
+
+       if (!irq_ptr)
+               return -ENODEV;
+       q = irq_ptr->input_qs[nr];
+       WARN_ON(queue_irqs_enabled(q));
+
+       qdio_sync_after_thinint(q);
+
+       /*
+        * The interrupt could be caused by a PCI request. Check the
+        * PCI capable outbound queues.
+        */
+       qdio_check_outbound_after_thinint(q);
+
+       if (!qdio_inbound_q_moved(q))
+               return 0;
+
+       /* Note: upper-layer MUST stop processing immediately here ... */
+       if (unlikely(q->irq_ptr->state != QDIO_IRQ_STATE_ACTIVE))
+               return -EIO;
+
+       start = q->first_to_kick;
+       end = q->first_to_check;
+       *bufnr = start;
+       *error = q->qdio_error;
+
+       /* for the next time */
+       q->first_to_kick = end;
+       q->qdio_error = 0;
+       return sub_buf(end, start);
+}
+EXPORT_SYMBOL(qdio_get_next_buffers);
+
+/**
+ * qdio_stop_irq - disable interrupt processing for the device
+ * @cdev: associated ccw_device for the qdio subchannel
+ * @nr: input queue number
+ *
+ * Return codes
+ *   0 - interrupts were already disabled
+ *   1 - interrupts successfully disabled
+ */
+int qdio_stop_irq(struct ccw_device *cdev, int nr)
+{
+       struct qdio_q *q;
+       struct qdio_irq *irq_ptr = cdev->private->qdio_data;
+
+       if (!irq_ptr)
+               return -ENODEV;
+       q = irq_ptr->input_qs[nr];
+
+       if (test_and_set_bit(QDIO_QUEUE_IRQS_DISABLED,
+                            &q->u.in.queue_irq_state))
+               return 0;
+       else
+               return 1;
+}
+EXPORT_SYMBOL(qdio_stop_irq);
+
 static int __init init_QDIO(void)
 {
        int rc;
index 34c7e4046df456897f4ebbfaa6ad8e970a2869ca..a13cf7ec64b2b0e0ab558694e4d77e8487a9ab36 100644 (file)
@@ -161,6 +161,7 @@ static void setup_queues(struct qdio_irq *irq_ptr,
                setup_queues_misc(q, irq_ptr, qdio_init->input_handler, i);
 
                q->is_input_q = 1;
+               q->u.in.queue_start_poll = qdio_init->queue_start_poll;
                setup_storage_lists(q, irq_ptr, input_sbal_array, i);
                input_sbal_array += QDIO_MAX_BUFFERS_PER_Q;
 
index 8daf1b99f15391a27f41e48e0407b1eefa01647c..752dbee06af582a4c2ac8481cb079658579bfcaa 100644 (file)
  */
 #define TIQDIO_NR_NONSHARED_IND                63
 #define TIQDIO_NR_INDICATORS           (TIQDIO_NR_NONSHARED_IND + 1)
-#define TIQDIO_SHARED_IND              63
 
 /* list of thin interrupt input queues */
 static LIST_HEAD(tiq_list);
 DEFINE_MUTEX(tiq_list_lock);
 
 /* adapter local summary indicator */
-static unsigned char *tiqdio_alsi;
+static u8 *tiqdio_alsi;
 
-/* device state change indicators */
-struct indicator_t {
-       u32 ind;        /* u32 because of compare-and-swap performance */
-       atomic_t count; /* use count, 0 or 1 for non-shared indicators */
-};
-static struct indicator_t *q_indicators;
+struct indicator_t *q_indicators;
 
 static int css_qdio_omit_svs;
 
+static u64 last_ai_time;
+
 static inline unsigned long do_clear_global_summary(void)
 {
        register unsigned long __fn asm("1") = 3;
@@ -116,59 +112,73 @@ void tiqdio_remove_input_queues(struct qdio_irq *irq_ptr)
        }
 }
 
-static inline int shared_ind(struct qdio_irq *irq_ptr)
+static inline int shared_ind_used(void)
 {
-       return irq_ptr->dsci == &q_indicators[TIQDIO_SHARED_IND].ind;
+       return atomic_read(&q_indicators[TIQDIO_SHARED_IND].count);
 }
 
 /**
  * tiqdio_thinint_handler - thin interrupt handler for qdio
- * @ind: pointer to adapter local summary indicator
- * @drv_data: NULL
+ * @alsi: pointer to adapter local summary indicator
+ * @data: NULL
  */
-static void tiqdio_thinint_handler(void *ind, void *drv_data)
+static void tiqdio_thinint_handler(void *alsi, void *data)
 {
        struct qdio_q *q;
 
+       last_ai_time = S390_lowcore.int_clock;
+
        /*
         * SVS only when needed: issue SVS to benefit from iqdio interrupt
-        * avoidance (SVS clears adapter interrupt suppression overwrite)
+        * avoidance (SVS clears adapter interrupt suppression overwrite).
         */
        if (!css_qdio_omit_svs)
                do_clear_global_summary();
 
-       /*
-        * reset local summary indicator (tiqdio_alsi) to stop adapter
-        * interrupts for now
-        */
-       xchg((u8 *)ind, 0);
+       /* reset local summary indicator */
+       if (shared_ind_used())
+               xchg(tiqdio_alsi, 0);
 
        /* protect tiq_list entries, only changed in activate or shutdown */
        rcu_read_lock();
 
        /* check for work on all inbound thinint queues */
-       list_for_each_entry_rcu(q, &tiq_list, entry)
+       list_for_each_entry_rcu(q, &tiq_list, entry) {
+
                /* only process queues from changed sets */
-               if (*q->irq_ptr->dsci) {
-                       qperf_inc(q, adapter_int);
+               if (!*q->irq_ptr->dsci)
+                       continue;
 
+               if (q->u.in.queue_start_poll) {
+                       /* skip if polling is enabled or already in work */
+                       if (test_and_set_bit(QDIO_QUEUE_IRQS_DISABLED,
+                                            &q->u.in.queue_irq_state)) {
+                               qperf_inc(q, int_discarded);
+                               continue;
+                       }
+
+                       /* avoid dsci clear here, done after processing */
+                       q->u.in.queue_start_poll(q->irq_ptr->cdev, q->nr,
+                                                q->irq_ptr->int_parm);
+               } else {
                        /* only clear it if the indicator is non-shared */
                        if (!shared_ind(q->irq_ptr))
                                xchg(q->irq_ptr->dsci, 0);
                        /*
-                        * don't call inbound processing directly since
-                        * that could starve other thinint queues
+                        * Call inbound processing but not directly
+                        * since that could starve other thinint queues.
                         */
                        tasklet_schedule(&q->tasklet);
                }
-
+               qperf_inc(q, adapter_int);
+       }
        rcu_read_unlock();
 
        /*
-        * if we used the shared indicator clear it now after all queues
-        * were processed
+        * If the shared indicator was used clear it now after all queues
+        * were processed.
         */
-       if (atomic_read(&q_indicators[TIQDIO_SHARED_IND].count)) {
+       if (shared_ind_used()) {
                xchg(&q_indicators[TIQDIO_SHARED_IND].ind, 0);
 
                /* prevent racing */
index 977bb4d4ed15425b6b780649c5c15d98e977c964..456b1874339765b1104fab2726a2d47358549559 100644 (file)
@@ -100,6 +100,6 @@ config QETH_IPV6
 
 config CCWGROUP
        tristate
-       default (LCS || CTCM || QETH)
+       default (LCS || CTCM || QETH || CLAW)
 
 endmenu
index d1257768be90053f1a6d93c4c048b2de0bb89bd4..6be43eb126b40077ab4bc0298ef7179bea0c9496 100644 (file)
@@ -676,6 +676,7 @@ enum qeth_discipline_id {
 };
 
 struct qeth_discipline {
+       void (*start_poll)(struct ccw_device *, int, unsigned long);
        qdio_handler_t *input_handler;
        qdio_handler_t *output_handler;
        int (*recover)(void *ptr);
@@ -702,6 +703,16 @@ struct qeth_skb_data {
 #define QETH_SKB_MAGIC 0x71657468
 #define QETH_SIGA_CC2_RETRIES 3
 
+struct qeth_rx {
+       int b_count;
+       int b_index;
+       struct qdio_buffer_element *b_element;
+       int e_offset;
+       int qdio_err;
+};
+
+#define QETH_NAPI_WEIGHT 128
+
 struct qeth_card {
        struct list_head list;
        enum qeth_card_states state;
@@ -749,6 +760,8 @@ struct qeth_card {
        debug_info_t *debug;
        struct mutex conf_mutex;
        struct mutex discipline_mutex;
+       struct napi_struct napi;
+       struct qeth_rx rx;
 };
 
 struct qeth_card_list_struct {
@@ -831,6 +844,10 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *,
                struct qdio_buffer *, struct qdio_buffer_element **, int *,
                struct qeth_hdr **);
 void qeth_schedule_recovery(struct qeth_card *);
+void qeth_qdio_start_poll(struct ccw_device *, int, unsigned long);
+void qeth_qdio_input_handler(struct ccw_device *,
+               unsigned int, unsigned int, int,
+               int, unsigned long);
 void qeth_qdio_output_handler(struct ccw_device *, unsigned int,
                        int, int, int, unsigned long);
 void qeth_clear_ipacmd_list(struct qeth_card *);
index 3a5a18a0fc283de5a987365e80dead90a9b6a9ea..764267062601b8812017f9552350b0ad6480ba23 100644 (file)
@@ -2911,6 +2911,27 @@ static void qeth_check_outbound_queue(struct qeth_qdio_out_q *queue)
        }
 }
 
+void qeth_qdio_start_poll(struct ccw_device *ccwdev, int queue,
+               unsigned long card_ptr)
+{
+       struct qeth_card *card = (struct qeth_card *)card_ptr;
+
+       if (card->dev)
+               napi_schedule(&card->napi);
+}
+EXPORT_SYMBOL_GPL(qeth_qdio_start_poll);
+
+void qeth_qdio_input_handler(struct ccw_device *ccwdev, unsigned int qdio_err,
+               unsigned int queue, int first_element, int count,
+               unsigned long card_ptr)
+{
+       struct qeth_card *card = (struct qeth_card *)card_ptr;
+
+       if (qdio_err)
+               qeth_schedule_recovery(card);
+}
+EXPORT_SYMBOL_GPL(qeth_qdio_input_handler);
+
 void qeth_qdio_output_handler(struct ccw_device *ccwdev,
                unsigned int qdio_error, int __queue, int first_element,
                int count, unsigned long card_ptr)
@@ -3843,6 +3864,7 @@ static int qeth_qdio_establish(struct qeth_card *card)
        init_data.no_output_qs           = card->qdio.no_out_queues;
        init_data.input_handler          = card->discipline.input_handler;
        init_data.output_handler         = card->discipline.output_handler;
+       init_data.queue_start_poll       = card->discipline.start_poll;
        init_data.int_parm               = (unsigned long) card;
        init_data.input_sbal_addr_array  = (void **) in_sbal_ptrs;
        init_data.output_sbal_addr_array = (void **) out_sbal_ptrs;
@@ -4513,8 +4535,8 @@ static struct {
 /* 20 */{"queue 1 buffer usage"},
        {"queue 2 buffer usage"},
        {"queue 3 buffer usage"},
-       {"rx handler time"},
-       {"rx handler count"},
+       {"rx poll time"},
+       {"rx poll count"},
        {"rx do_QDIO time"},
        {"rx do_QDIO count"},
        {"tx handler time"},
index 830d63524d612ff8bc665f918d6b01400e5c0c88..01c3c1f7787941c415d2c5e2367d72b756ec3591 100644 (file)
@@ -407,29 +407,25 @@ static int qeth_l2_stop_card(struct qeth_card *card, int recovery_mode)
        return rc;
 }
 
-static void qeth_l2_process_inbound_buffer(struct qeth_card *card,
-                           struct qeth_qdio_buffer *buf, int index)
+static int qeth_l2_process_inbound_buffer(struct qeth_card *card,
+                               int budget, int *done)
 {
-       struct qdio_buffer_element *element;
+       int work_done = 0;
        struct sk_buff *skb;
        struct qeth_hdr *hdr;
-       int offset;
        unsigned int len;
 
-       /* get first element of current buffer */
-       element = (struct qdio_buffer_element *)&buf->buffer->element[0];
-       offset = 0;
-       if (card->options.performance_stats)
-               card->perf_stats.bufs_rec++;
-       while ((skb = qeth_core_get_next_skb(card, buf->buffer, &element,
-                                      &offset, &hdr))) {
-               skb->dev = card->dev;
-               /* is device UP ? */
-               if (!(card->dev->flags & IFF_UP)) {
-                       dev_kfree_skb_any(skb);
-                       continue;
+       *done = 0;
+       BUG_ON(!budget);
+       while (budget) {
+               skb = qeth_core_get_next_skb(card,
+                       card->qdio.in_q->bufs[card->rx.b_index].buffer,
+                       &card->rx.b_element, &card->rx.e_offset, &hdr);
+               if (!skb) {
+                       *done = 1;
+                       break;
                }
-
+               skb->dev = card->dev;
                switch (hdr->hdr.l2.id) {
                case QETH_HEADER_TYPE_LAYER2:
                        skb->pkt_type = PACKET_HOST;
@@ -441,7 +437,7 @@ static void qeth_l2_process_inbound_buffer(struct qeth_card *card,
                        if (skb->protocol == htons(ETH_P_802_2))
                                *((__u32 *)skb->cb) = ++card->seqno.pkt_seqno;
                        len = skb->len;
-                       netif_rx(skb);
+                       netif_receive_skb(skb);
                        break;
                case QETH_HEADER_TYPE_OSN:
                        if (card->info.type == QETH_CARD_TYPE_OSN) {
@@ -459,9 +455,87 @@ static void qeth_l2_process_inbound_buffer(struct qeth_card *card,
                        QETH_DBF_HEX(CTRL, 3, hdr, QETH_DBF_CTRL_LEN);
                        continue;
                }
+               work_done++;
+               budget--;
                card->stats.rx_packets++;
                card->stats.rx_bytes += len;
        }
+       return work_done;
+}
+
+static int qeth_l2_poll(struct napi_struct *napi, int budget)
+{
+       struct qeth_card *card = container_of(napi, struct qeth_card, napi);
+       int work_done = 0;
+       struct qeth_qdio_buffer *buffer;
+       int done;
+       int new_budget = budget;
+
+       if (card->options.performance_stats) {
+               card->perf_stats.inbound_cnt++;
+               card->perf_stats.inbound_start_time = qeth_get_micros();
+       }
+
+       while (1) {
+               if (!card->rx.b_count) {
+                       card->rx.qdio_err = 0;
+                       card->rx.b_count = qdio_get_next_buffers(
+                               card->data.ccwdev, 0, &card->rx.b_index,
+                               &card->rx.qdio_err);
+                       if (card->rx.b_count <= 0) {
+                               card->rx.b_count = 0;
+                               break;
+                       }
+                       card->rx.b_element =
+                               &card->qdio.in_q->bufs[card->rx.b_index]
+                               .buffer->element[0];
+                       card->rx.e_offset = 0;
+               }
+
+               while (card->rx.b_count) {
+                       buffer = &card->qdio.in_q->bufs[card->rx.b_index];
+                       if (!(card->rx.qdio_err &&
+                           qeth_check_qdio_errors(card, buffer->buffer,
+                           card->rx.qdio_err, "qinerr")))
+                               work_done += qeth_l2_process_inbound_buffer(
+                                       card, new_budget, &done);
+                       else
+                               done = 1;
+
+                       if (done) {
+                               if (card->options.performance_stats)
+                                       card->perf_stats.bufs_rec++;
+                               qeth_put_buffer_pool_entry(card,
+                                       buffer->pool_entry);
+                               qeth_queue_input_buffer(card, card->rx.b_index);
+                               card->rx.b_count--;
+                               if (card->rx.b_count) {
+                                       card->rx.b_index =
+                                               (card->rx.b_index + 1) %
+                                               QDIO_MAX_BUFFERS_PER_Q;
+                                       card->rx.b_element =
+                                               &card->qdio.in_q
+                                               ->bufs[card->rx.b_index]
+                                               .buffer->element[0];
+                                       card->rx.e_offset = 0;
+                               }
+                       }
+
+                       if (work_done >= budget)
+                               goto out;
+                       else
+                               new_budget = budget - work_done;
+               }
+       }
+
+       napi_complete(napi);
+       if (qdio_start_irq(card->data.ccwdev, 0))
+               napi_schedule(&card->napi);
+out:
+       if (card->options.performance_stats)
+               card->perf_stats.inbound_time += qeth_get_micros() -
+                       card->perf_stats.inbound_start_time;
+       return work_done;
 }
 
 static int qeth_l2_send_setdelmac(struct qeth_card *card, __u8 *mac,
@@ -755,49 +829,10 @@ tx_drop:
        return NETDEV_TX_OK;
 }
 
-static void qeth_l2_qdio_input_handler(struct ccw_device *ccwdev,
-                       unsigned int qdio_err, unsigned int queue,
-                       int first_element, int count, unsigned long card_ptr)
-{
-       struct net_device *net_dev;
-       struct qeth_card *card;
-       struct qeth_qdio_buffer *buffer;
-       int index;
-       int i;
-
-       card = (struct qeth_card *) card_ptr;
-       net_dev = card->dev;
-       if (card->options.performance_stats) {
-               card->perf_stats.inbound_cnt++;
-               card->perf_stats.inbound_start_time = qeth_get_micros();
-       }
-       if (qdio_err & QDIO_ERROR_ACTIVATE_CHECK_CONDITION) {
-               QETH_CARD_TEXT(card, 1, "qdinchk");
-               QETH_CARD_TEXT_(card, 1, "%04X%04X", first_element,
-                               count);
-               QETH_CARD_TEXT_(card, 1, "%04X", queue);
-               qeth_schedule_recovery(card);
-               return;
-       }
-       for (i = first_element; i < (first_element + count); ++i) {
-               index = i % QDIO_MAX_BUFFERS_PER_Q;
-               buffer = &card->qdio.in_q->bufs[index];
-               if (!(qdio_err &&
-                     qeth_check_qdio_errors(card, buffer->buffer, qdio_err,
-                                            "qinerr")))
-                       qeth_l2_process_inbound_buffer(card, buffer, index);
-               /* clear buffer and give back to hardware */
-               qeth_put_buffer_pool_entry(card, buffer->pool_entry);
-               qeth_queue_input_buffer(card, index);
-       }
-       if (card->options.performance_stats)
-               card->perf_stats.inbound_time += qeth_get_micros() -
-                       card->perf_stats.inbound_start_time;
-}
-
 static int qeth_l2_open(struct net_device *dev)
 {
        struct qeth_card *card = dev->ml_priv;
+       int rc = 0;
 
        QETH_CARD_TEXT(card, 4, "qethopen");
        if (card->state != CARD_STATE_SOFTSETUP)
@@ -814,18 +849,24 @@ static int qeth_l2_open(struct net_device *dev)
 
        if (!card->lan_online && netif_carrier_ok(dev))
                netif_carrier_off(dev);
-       return 0;
+       if (qdio_stop_irq(card->data.ccwdev, 0) >= 0) {
+               napi_enable(&card->napi);
+               napi_schedule(&card->napi);
+       } else
+               rc = -EIO;
+       return rc;
 }
 
-
 static int qeth_l2_stop(struct net_device *dev)
 {
        struct qeth_card *card = dev->ml_priv;
 
        QETH_CARD_TEXT(card, 4, "qethstop");
        netif_tx_disable(dev);
-       if (card->state == CARD_STATE_UP)
+       if (card->state == CARD_STATE_UP) {
                card->state = CARD_STATE_SOFTSETUP;
+               napi_disable(&card->napi);
+       }
        return 0;
 }
 
@@ -836,8 +877,9 @@ static int qeth_l2_probe_device(struct ccwgroup_device *gdev)
        INIT_LIST_HEAD(&card->vid_list);
        INIT_LIST_HEAD(&card->mc_list);
        card->options.layer2 = 1;
+       card->discipline.start_poll = qeth_qdio_start_poll;
        card->discipline.input_handler = (qdio_handler_t *)
-               qeth_l2_qdio_input_handler;
+               qeth_qdio_input_handler;
        card->discipline.output_handler = (qdio_handler_t *)
                qeth_qdio_output_handler;
        card->discipline.recover = qeth_l2_recover;
@@ -923,6 +965,7 @@ static int qeth_l2_setup_netdev(struct qeth_card *card)
        card->info.broadcast_capable = 1;
        qeth_l2_request_initial_mac(card);
        SET_NETDEV_DEV(card->dev, &card->gdev->dev);
+       netif_napi_add(card->dev, &card->napi, qeth_l2_poll, QETH_NAPI_WEIGHT);
        return register_netdev(card->dev);
 }
 
@@ -955,6 +998,7 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode)
                qeth_l2_send_setmac(card, &card->dev->dev_addr[0]);
 
        card->state = CARD_STATE_HARDSETUP;
+       memset(&card->rx, 0, sizeof(struct qeth_rx));
        qeth_print_status_message(card);
 
        /* softsetup */
@@ -1086,9 +1130,6 @@ static int qeth_l2_recover(void *ptr)
        card->use_hard_stop = 1;
        __qeth_l2_set_offline(card->gdev, 1);
        rc = __qeth_l2_set_online(card->gdev, 1);
-       /* don't run another scheduled recovery */
-       qeth_clear_thread_start_bit(card, QETH_RECOVER_THREAD);
-       qeth_clear_thread_running_bit(card, QETH_RECOVER_THREAD);
        if (!rc)
                dev_info(&card->gdev->dev,
                        "Device successfully recovered!\n");
@@ -1099,6 +1140,8 @@ static int qeth_l2_recover(void *ptr)
                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);
        return 0;
 }
 
index e22ae248f613eea825eaf8fe48f02bbd078f9818..5b79f573bd93ee377bd90786e69c162daccb3c66 100644 (file)
@@ -103,12 +103,7 @@ int qeth_l3_string_to_ipaddr4(const char *buf, __u8 *addr)
 
 void qeth_l3_ipaddr6_to_string(const __u8 *addr, char *buf)
 {
-       sprintf(buf, "%02x%02x:%02x%02x:%02x%02x:%02x%02x"
-                    ":%02x%02x:%02x%02x:%02x%02x:%02x%02x",
-                    addr[0], addr[1], addr[2], addr[3],
-                    addr[4], addr[5], addr[6], addr[7],
-                    addr[8], addr[9], addr[10], addr[11],
-                    addr[12], addr[13], addr[14], addr[15]);
+       sprintf(buf, "%pI6", addr);
 }
 
 int qeth_l3_string_to_ipaddr6(const char *buf, __u8 *addr)
@@ -2112,51 +2107,44 @@ static inline __u16 qeth_l3_rebuild_skb(struct qeth_card *card,
        return vlan_id;
 }
 
-static void qeth_l3_process_inbound_buffer(struct qeth_card *card,
-                           struct qeth_qdio_buffer *buf, int index)
+static int qeth_l3_process_inbound_buffer(struct qeth_card *card,
+                               int budget, int *done)
 {
-       struct qdio_buffer_element *element;
+       int work_done = 0;
        struct sk_buff *skb;
        struct qeth_hdr *hdr;
-       int offset;
        __u16 vlan_tag = 0;
        unsigned int len;
-       /* get first element of current buffer */
-       element = (struct qdio_buffer_element *)&buf->buffer->element[0];
-       offset = 0;
-       if (card->options.performance_stats)
-               card->perf_stats.bufs_rec++;
-       while ((skb = qeth_core_get_next_skb(card, buf->buffer, &element,
-                                      &offset, &hdr))) {
-               skb->dev = card->dev;
-               /* is device UP ? */
-               if (!(card->dev->flags & IFF_UP)) {
-                       dev_kfree_skb_any(skb);
-                       continue;
-               }
 
+       *done = 0;
+       BUG_ON(!budget);
+       while (budget) {
+               skb = qeth_core_get_next_skb(card,
+                       card->qdio.in_q->bufs[card->rx.b_index].buffer,
+                       &card->rx.b_element, &card->rx.e_offset, &hdr);
+               if (!skb) {
+                       *done = 1;
+                       break;
+               }
+               skb->dev = card->dev;
                switch (hdr->hdr.l3.id) {
                case QETH_HEADER_TYPE_LAYER3:
                        vlan_tag = qeth_l3_rebuild_skb(card, skb, hdr);
                        len = skb->len;
                        if (vlan_tag && !card->options.sniffer)
                                if (card->vlangrp)
-                                       vlan_hwaccel_rx(skb, card->vlangrp,
-                                               vlan_tag);
+                                       vlan_gro_receive(&card->napi,
+                                               card->vlangrp, vlan_tag, skb);
                                else {
                                        dev_kfree_skb_any(skb);
                                        continue;
                                }
                        else
-                               netif_rx(skb);
+                               napi_gro_receive(&card->napi, skb);
                        break;
                case QETH_HEADER_TYPE_LAYER2: /* for HiperSockets sniffer */
                        skb->pkt_type = PACKET_HOST;
                        skb->protocol = eth_type_trans(skb, skb->dev);
-                       if (card->options.checksum_type == NO_CHECKSUMMING)
-                               skb->ip_summed = CHECKSUM_UNNECESSARY;
-                       else
-                               skb->ip_summed = CHECKSUM_NONE;
                        len = skb->len;
                        netif_receive_skb(skb);
                        break;
@@ -2166,10 +2154,87 @@ static void qeth_l3_process_inbound_buffer(struct qeth_card *card,
                        QETH_DBF_HEX(CTRL, 3, hdr, QETH_DBF_CTRL_LEN);
                        continue;
                }
-
+               work_done++;
+               budget--;
                card->stats.rx_packets++;
                card->stats.rx_bytes += len;
        }
+       return work_done;
+}
+
+static int qeth_l3_poll(struct napi_struct *napi, int budget)
+{
+       struct qeth_card *card = container_of(napi, struct qeth_card, napi);
+       int work_done = 0;
+       struct qeth_qdio_buffer *buffer;
+       int done;
+       int new_budget = budget;
+
+       if (card->options.performance_stats) {
+               card->perf_stats.inbound_cnt++;
+               card->perf_stats.inbound_start_time = qeth_get_micros();
+       }
+
+       while (1) {
+               if (!card->rx.b_count) {
+                       card->rx.qdio_err = 0;
+                       card->rx.b_count = qdio_get_next_buffers(
+                               card->data.ccwdev, 0, &card->rx.b_index,
+                               &card->rx.qdio_err);
+                       if (card->rx.b_count <= 0) {
+                               card->rx.b_count = 0;
+                               break;
+                       }
+                       card->rx.b_element =
+                               &card->qdio.in_q->bufs[card->rx.b_index]
+                               .buffer->element[0];
+                       card->rx.e_offset = 0;
+               }
+
+               while (card->rx.b_count) {
+                       buffer = &card->qdio.in_q->bufs[card->rx.b_index];
+                       if (!(card->rx.qdio_err &&
+                           qeth_check_qdio_errors(card, buffer->buffer,
+                           card->rx.qdio_err, "qinerr")))
+                               work_done += qeth_l3_process_inbound_buffer(
+                                       card, new_budget, &done);
+                       else
+                               done = 1;
+
+                       if (done) {
+                               if (card->options.performance_stats)
+                                       card->perf_stats.bufs_rec++;
+                               qeth_put_buffer_pool_entry(card,
+                                       buffer->pool_entry);
+                               qeth_queue_input_buffer(card, card->rx.b_index);
+                               card->rx.b_count--;
+                               if (card->rx.b_count) {
+                                       card->rx.b_index =
+                                               (card->rx.b_index + 1) %
+                                               QDIO_MAX_BUFFERS_PER_Q;
+                                       card->rx.b_element =
+                                               &card->qdio.in_q
+                                               ->bufs[card->rx.b_index]
+                                               .buffer->element[0];
+                                       card->rx.e_offset = 0;
+                               }
+                       }
+
+                       if (work_done >= budget)
+                               goto out;
+                       else
+                               new_budget = budget - work_done;
+               }
+       }
+
+       napi_complete(napi);
+       if (qdio_start_irq(card->data.ccwdev, 0))
+               napi_schedule(&card->napi);
+out:
+       if (card->options.performance_stats)
+               card->perf_stats.inbound_time += qeth_get_micros() -
+                       card->perf_stats.inbound_start_time;
+       return work_done;
 }
 
 static int qeth_l3_verify_vlan_dev(struct net_device *dev,
@@ -3103,6 +3168,7 @@ tx_drop:
 static int qeth_l3_open(struct net_device *dev)
 {
        struct qeth_card *card = dev->ml_priv;
+       int rc = 0;
 
        QETH_CARD_TEXT(card, 4, "qethopen");
        if (card->state != CARD_STATE_SOFTSETUP)
@@ -3113,7 +3179,12 @@ static int qeth_l3_open(struct net_device *dev)
 
        if (!card->lan_online && netif_carrier_ok(dev))
                netif_carrier_off(dev);
-       return 0;
+       if (qdio_stop_irq(card->data.ccwdev, 0) >= 0) {
+               napi_enable(&card->napi);
+               napi_schedule(&card->napi);
+       } else
+               rc = -EIO;
+       return rc;
 }
 
 static int qeth_l3_stop(struct net_device *dev)
@@ -3122,8 +3193,10 @@ static int qeth_l3_stop(struct net_device *dev)
 
        QETH_CARD_TEXT(card, 4, "qethstop");
        netif_tx_disable(dev);
-       if (card->state == CARD_STATE_UP)
+       if (card->state == CARD_STATE_UP) {
                card->state = CARD_STATE_SOFTSETUP;
+               napi_disable(&card->napi);
+       }
        return 0;
 }
 
@@ -3293,57 +3366,19 @@ static int qeth_l3_setup_netdev(struct qeth_card *card)
        card->dev->gso_max_size = 15 * PAGE_SIZE;
 
        SET_NETDEV_DEV(card->dev, &card->gdev->dev);
+       netif_napi_add(card->dev, &card->napi, qeth_l3_poll, QETH_NAPI_WEIGHT);
        return register_netdev(card->dev);
 }
 
-static void qeth_l3_qdio_input_handler(struct ccw_device *ccwdev,
-               unsigned int qdio_err, unsigned int queue, int first_element,
-               int count, unsigned long card_ptr)
-{
-       struct net_device *net_dev;
-       struct qeth_card *card;
-       struct qeth_qdio_buffer *buffer;
-       int index;
-       int i;
-
-       card = (struct qeth_card *) card_ptr;
-       net_dev = card->dev;
-       if (card->options.performance_stats) {
-               card->perf_stats.inbound_cnt++;
-               card->perf_stats.inbound_start_time = qeth_get_micros();
-       }
-       if (qdio_err & QDIO_ERROR_ACTIVATE_CHECK_CONDITION) {
-               QETH_CARD_TEXT(card, 1, "qdinchk");
-               QETH_CARD_TEXT_(card, 1, "%04X%04X",
-                               first_element, count);
-               QETH_CARD_TEXT_(card, 1, "%04X", queue);
-               qeth_schedule_recovery(card);
-               return;
-       }
-       for (i = first_element; i < (first_element + count); ++i) {
-               index = i % QDIO_MAX_BUFFERS_PER_Q;
-               buffer = &card->qdio.in_q->bufs[index];
-               if (!(qdio_err &&
-                     qeth_check_qdio_errors(card, buffer->buffer,
-                                            qdio_err, "qinerr")))
-                       qeth_l3_process_inbound_buffer(card, buffer, index);
-               /* clear buffer and give back to hardware */
-               qeth_put_buffer_pool_entry(card, buffer->pool_entry);
-               qeth_queue_input_buffer(card, index);
-       }
-       if (card->options.performance_stats)
-               card->perf_stats.inbound_time += qeth_get_micros() -
-                       card->perf_stats.inbound_start_time;
-}
-
 static int qeth_l3_probe_device(struct ccwgroup_device *gdev)
 {
        struct qeth_card *card = dev_get_drvdata(&gdev->dev);
 
        qeth_l3_create_device_attributes(&gdev->dev);
        card->options.layer2 = 0;
+       card->discipline.start_poll = qeth_qdio_start_poll;
        card->discipline.input_handler = (qdio_handler_t *)
-               qeth_l3_qdio_input_handler;
+               qeth_qdio_input_handler;
        card->discipline.output_handler = (qdio_handler_t *)
                qeth_qdio_output_handler;
        card->discipline.recover = qeth_l3_recover;
@@ -3402,6 +3437,7 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode)
        }
 
        card->state = CARD_STATE_HARDSETUP;
+       memset(&card->rx, 0, sizeof(struct qeth_rx));
        qeth_print_status_message(card);
 
        /* softsetup */
@@ -3538,9 +3574,6 @@ static int qeth_l3_recover(void *ptr)
        card->use_hard_stop = 1;
        __qeth_l3_set_offline(card->gdev, 1);
        rc = __qeth_l3_set_online(card->gdev, 1);
-       /* don't run another scheduled recovery */
-       qeth_clear_thread_start_bit(card, QETH_RECOVER_THREAD);
-       qeth_clear_thread_running_bit(card, QETH_RECOVER_THREAD);
        if (!rc)
                dev_info(&card->gdev->dev,
                        "Device successfully recovered!\n");
@@ -3551,6 +3584,8 @@ static int qeth_l3_recover(void *ptr)
                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);
        return 0;
 }
 
index b2635759721cd81db28c4de2dfe6097568836d6f..da54a28a1b8724ac0de6a17b6cf2ddeb9b3714f2 100644 (file)
@@ -277,16 +277,12 @@ int zfcp_qdio_send(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req)
 static void zfcp_qdio_setup_init_data(struct qdio_initialize *id,
                                      struct zfcp_qdio *qdio)
 {
-
+       memset(id, 0, sizeof(*id));
        id->cdev = qdio->adapter->ccw_device;
        id->q_format = QDIO_ZFCP_QFMT;
        memcpy(id->adapter_name, dev_name(&id->cdev->dev), 8);
        ASCEBC(id->adapter_name, 8);
        id->qib_rflags = QIB_RFLAGS_ENABLE_DATA_DIV;
-       id->qib_param_field_format = 0;
-       id->qib_param_field = NULL;
-       id->input_slib_elements = NULL;
-       id->output_slib_elements = NULL;
        id->no_input_qs = 1;
        id->no_output_qs = 1;
        id->input_handler = zfcp_qdio_int_resp;
index 5af23cc5ea9fe6cf8c9ded25ccea29f172dc5a8e..f383cb42b1d76c779f5fa91f5cac8d3599f16bba 100644 (file)
@@ -1344,8 +1344,24 @@ static struct usbatm_driver cxacru_driver = {
        .tx_padding     = 11,
 };
 
-static int cxacru_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
+static int cxacru_usb_probe(struct usb_interface *intf,
+               const struct usb_device_id *id)
 {
+       struct usb_device *usb_dev = interface_to_usbdev(intf);
+       char buf[15];
+
+       /* Avoid ADSL routers (cx82310_eth).
+        * Abort if bDeviceClass is 0xff and iProduct is "USB NET CARD".
+        */
+       if (usb_dev->descriptor.bDeviceClass == USB_CLASS_VENDOR_SPEC
+                       && usb_string(usb_dev, usb_dev->descriptor.iProduct,
+                               buf, sizeof(buf)) > 0) {
+               if (!strcmp(buf, "USB NET CARD")) {
+                       dev_info(&intf->dev, "ignoring cx82310_eth device\n");
+                       return -ENODEV;
+               }
+       }
+
        return usbatm_usb_probe(intf, id, &cxacru_driver);
 }
 
index 626b629429ff2fc3f30fcf63b25fb52211f184c0..c7fbf298ad6899a6884db700cc47c43cb194619d 100644 (file)
@@ -302,6 +302,7 @@ header-y += quota.h
 header-y += radeonfb.h
 header-y += random.h
 header-y += raw.h
+header-y += rds.h
 header-y += reboot.h
 header-y += reiserfs_fs.h
 header-y += reiserfs_xattr.h
index 2308fbb4523a399abce0809860f6f398c8844ed5..fb6aa607092154247ab59358a6fdc14f6808c618 100644 (file)
@@ -237,13 +237,29 @@ static inline bool is_etherdev_addr(const struct net_device *dev,
  * entry points.
  */
 
-static inline int compare_ether_header(const void *a, const void *b)
+static inline unsigned long compare_ether_header(const void *a, const void *b)
 {
+#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64
+       unsigned long fold;
+
+       /*
+        * We want to compare 14 bytes:
+        *  [a0 ... a13] ^ [b0 ... b13]
+        * Use two long XOR, ORed together, with an overlap of two bytes.
+        *  [a0  a1  a2  a3  a4  a5  a6  a7 ] ^ [b0  b1  b2  b3  b4  b5  b6  b7 ] |
+        *  [a6  a7  a8  a9  a10 a11 a12 a13] ^ [b6  b7  b8  b9  b10 b11 b12 b13]
+        * This means the [a6 a7] ^ [b6 b7] part is done two times.
+       */
+       fold = *(unsigned long *)a ^ *(unsigned long *)b;
+       fold |= *(unsigned long *)(a + 6) ^ *(unsigned long *)(b + 6);
+       return fold;
+#else
        u32 *a32 = (u32 *)((u8 *)a + 2);
        u32 *b32 = (u32 *)((u8 *)b + 2);
 
        return (*(u16 *)a ^ *(u16 *)b) | (a32[0] ^ b32[0]) |
               (a32[1] ^ b32[1]) | (a32[2] ^ b32[2]);
+#endif
 }
 
 #endif /* _LINUX_ETHERDEVICE_H */
index 53558ec59e1b16d4272f9cdd51e1a0ba4957facc..123959927745b7934cacea3e1aacf5c6303bcb1c 100644 (file)
@@ -75,6 +75,8 @@
 #define IFF_DISABLE_NETPOLL    0x2000  /* disable netpoll at run-time */
 #define IFF_MACVLAN_PORT       0x4000  /* device used as macvlan port */
 #define IFF_BRIDGE_PORT        0x8000          /* device used as bridge port */
+#define IFF_OVS_DATAPATH       0x10000 /* device used as Open vSwitch
+                                        * datapath port */
 
 #define IF_GET_IFACE   0x0001          /* for querying only */
 #define IF_GET_PROTO   0x0002
index bed7a4682b90734935e3dd6680d5e646b0b895c0..f9c3df03db0f0babecddf685250798807c9a7b97 100644 (file)
@@ -137,8 +137,6 @@ extern struct ctl_table ether_table[];
 
 extern ssize_t sysfs_format_mac(char *buf, const unsigned char *addr, int len);
 
-#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
-
 #endif
 
 #endif /* _LINUX_IF_ETHER_H */
index 35280b302290459ff20293b2e4bcafd5aa6b9b2a..8a2fd66a8b5f8b51bd5f9475dc04580c0ccd6757 100644 (file)
@@ -40,6 +40,12 @@ struct macvlan_rx_stats {
        unsigned long           rx_errors;
 };
 
+/*
+ * Maximum times a macvtap device can be opened. This can be used to
+ * configure the number of receive queue, e.g. for multiqueue virtio.
+ */
+#define MAX_MACVTAP_QUEUES     (NR_CPUS < 16 ? NR_CPUS : 16)
+
 struct macvlan_dev {
        struct net_device       *dev;
        struct list_head        list;
@@ -50,7 +56,8 @@ struct macvlan_dev {
        enum macvlan_mode       mode;
        int (*receive)(struct sk_buff *skb);
        int (*forward)(struct net_device *dev, struct sk_buff *skb);
-       struct macvtap_queue    *tap;
+       struct macvtap_queue    *taps[MAX_MACVTAP_QUEUES];
+       int                     numvtaps;
 };
 
 static inline void macvlan_count_rx(const struct macvlan_dev *vlan,
index 27741e05446f97dfad3e5f35e83f328d02520588..29bcd55851ebed4dd2113965c2277f1e4c6bb9e6 100644 (file)
  * PPPoE addressing definition 
  */ 
 typedef __be16 sid_t;
-struct pppoe_addr
-       sid_t           sid;                    /* Session identifier */ 
-       unsigned char   remote[ETH_ALEN];       /* Remote address */ 
-       char            dev[IFNAMSIZ];          /* Local device to use */ 
+struct pppoe_addr {
+       sid_t         sid;                    /* Session identifier */
+       unsigned char remote[ETH_ALEN];       /* Remote address */
+       char          dev[IFNAMSIZ];          /* Local device to use */
 }; 
  
 /************************************************************************ 
- * Protocols supported by AF_PPPOX 
- */ 
+ * PPTP addressing definition
+ */
+struct pptp_addr {
+       __be16          call_id;
+       struct in_addr  sin_addr;
+};
+
+/************************************************************************
+ * Protocols supported by AF_PPPOX
+ */
 #define PX_PROTO_OE    0 /* Currently just PPPoE */
 #define PX_PROTO_OL2TP 1 /* Now L2TP also */
-#define PX_MAX_PROTO   2
-
-struct sockaddr_pppox { 
-       sa_family_t     sa_family;            /* address family, AF_PPPOX */ 
-       unsigned int    sa_protocol;          /* protocol identifier */ 
-       union{ 
-               struct pppoe_addr       pppoe; 
-       }sa_addr; 
+#define PX_PROTO_PPTP  2
+#define PX_MAX_PROTO   3
+
+struct sockaddr_pppox {
+       sa_family_t     sa_family;            /* address family, AF_PPPOX */
+       unsigned int    sa_protocol;          /* protocol identifier */
+       union {
+               struct pppoe_addr  pppoe;
+               struct pptp_addr   pptp;
+       } sa_addr;
 } __attribute__((packed));
 
 /* The use of the above union isn't viable because the size of this
@@ -150,15 +160,23 @@ struct pppoe_opt {
                                             relayed to (PPPoE relaying) */
 };
 
+struct pptp_opt {
+       struct pptp_addr src_addr;
+       struct pptp_addr dst_addr;
+       u32 ack_sent, ack_recv;
+       u32 seq_sent, seq_recv;
+       int ppp_flags;
+};
 #include <net/sock.h>
 
 struct pppox_sock {
        /* struct sock must be the first member of pppox_sock */
-       struct sock             sk;
-       struct ppp_channel      chan;
+       struct sock sk;
+       struct ppp_channel chan;
        struct pppox_sock       *next;    /* for hash table */
        union {
                struct pppoe_opt pppoe;
+               struct pptp_opt  pptp;
        } proto;
        __be16                  num;
 };
index 3d870fda8c4ff3ca3477796a9c454e01e4598996..a52320751bfc29621dfd5d5f1cb8d41951e2c59b 100644 (file)
@@ -119,7 +119,7 @@ extern u16 vlan_dev_vlan_id(const struct net_device *dev);
 
 extern int __vlan_hwaccel_rx(struct sk_buff *skb, struct vlan_group *grp,
                             u16 vlan_tci, int polling);
-extern int vlan_hwaccel_do_receive(struct sk_buff *skb);
+extern void vlan_hwaccel_do_receive(struct sk_buff *skb);
 extern gro_result_t
 vlan_gro_receive(struct napi_struct *napi, struct vlan_group *grp,
                 unsigned int vlan_tci, struct sk_buff *skb);
@@ -147,9 +147,8 @@ static inline int __vlan_hwaccel_rx(struct sk_buff *skb, struct vlan_group *grp,
        return NET_XMIT_SUCCESS;
 }
 
-static inline int vlan_hwaccel_do_receive(struct sk_buff *skb)
+static inline void vlan_hwaccel_do_receive(struct sk_buff *skb)
 {
-       return 0;
 }
 
 static inline gro_result_t
index 41d88a4689af0a77a000cfc88437a70d8abdc1fb..beeb6dee2b49d416cc3f74537e920ca2ae93dd17 100644 (file)
@@ -250,6 +250,25 @@ struct sockaddr_in {
 
 #ifdef __KERNEL__
 
+#include <linux/errno.h>
+
+static inline int proto_ports_offset(int proto)
+{
+       switch (proto) {
+       case IPPROTO_TCP:
+       case IPPROTO_UDP:
+       case IPPROTO_DCCP:
+       case IPPROTO_ESP:       /* SPI */
+       case IPPROTO_SCTP:
+       case IPPROTO_UDPLITE:
+               return 0;
+       case IPPROTO_AH:        /* SPI */
+               return 4;
+       default:
+               return -EINVAL;
+       }
+}
+
 static inline bool ipv4_is_loopback(__be32 addr)
 {
        return (addr & htonl(0xff000000)) == htonl(0x7f000000);
index 0f82293a82edf23da15a2ae51447d7db8c1b674f..78a1b96717523ba47b84867fc875aacef4f51e20 100644 (file)
@@ -56,6 +56,7 @@ enum {
        MLX4_CMD_QUERY_HCA       = 0xb,
        MLX4_CMD_QUERY_PORT      = 0x43,
        MLX4_CMD_SENSE_PORT      = 0x4d,
+       MLX4_CMD_HW_HEALTH_CHECK = 0x50,
        MLX4_CMD_SET_PORT        = 0xc,
        MLX4_CMD_ACCESS_DDR      = 0x2e,
        MLX4_CMD_MAP_ICM         = 0xffa,
index 7a7f9c1e679a30e5b2f8366926cf7b7991360723..7338654c02b4de5402cbba6c80a3f96106e3b717 100644 (file)
@@ -186,6 +186,10 @@ struct mlx4_caps {
        int                     eth_mtu_cap[MLX4_MAX_PORTS + 1];
        int                     gid_table_len[MLX4_MAX_PORTS + 1];
        int                     pkey_table_len[MLX4_MAX_PORTS + 1];
+       int                     trans_type[MLX4_MAX_PORTS + 1];
+       int                     vendor_oui[MLX4_MAX_PORTS + 1];
+       int                     wavelength[MLX4_MAX_PORTS + 1];
+       u64                     trans_code[MLX4_MAX_PORTS + 1];
        int                     local_ca_ack_delay;
        int                     num_uars;
        int                     bf_reg_size;
@@ -229,6 +233,8 @@ struct mlx4_caps {
        u32                     bmme_flags;
        u32                     reserved_lkey;
        u16                     stat_rate_support;
+       int                     udp_rss;
+       int                     loopback_support;
        u8                      port_width_cap[MLX4_MAX_PORTS + 1];
        int                     max_gso_sz;
        int                     reserved_qps_cnt[MLX4_NUM_QP_REGION];
@@ -480,5 +486,6 @@ void mlx4_fmr_unmap(struct mlx4_dev *dev, struct mlx4_fmr *fmr,
                    u32 *lkey, u32 *rkey);
 int mlx4_fmr_free(struct mlx4_dev *dev, struct mlx4_fmr *fmr);
 int mlx4_SYNC_TPT(struct mlx4_dev *dev);
+int mlx4_test_interrupts(struct mlx4_dev *dev);
 
 #endif /* MLX4_DEVICE_H */
index 46c36ffe20eed83f4be29dfd4b75bc694c110c68..af05186d5b366c61cbf50cbb85de9ccb3b2ed2fc 100644 (file)
@@ -901,7 +901,7 @@ struct net_device {
 
        unsigned int            flags;  /* interface flags (a la BSD)   */
        unsigned short          gflags;
-        unsigned short          priv_flags; /* Like 'flags' but invisible to userspace. */
+        unsigned int            priv_flags; /* Like 'flags' but invisible to userspace. */
        unsigned short          padded; /* How much padding added by alloc_netdev() */
 
        unsigned char           operstate; /* RFC2863 operstate */
@@ -953,7 +953,14 @@ struct net_device {
 /*
  * Cache line mostly used on receive path (including eth_type_trans())
  */
-       unsigned long           last_rx;        /* Time of last Rx      */
+       unsigned long           last_rx;        /* Time of last Rx
+                                                * This should not be set in
+                                                * drivers, unless really needed,
+                                                * because network stack (bonding)
+                                                * use it if/when necessary, to
+                                                * avoid dirtying this cache line.
+                                                */
+
        /* Interface address info used in eth_type_trans() */
        unsigned char           *dev_addr;      /* hw address, (before bcast
                                                   because most packets are
@@ -1695,6 +1702,7 @@ extern gro_result_t       dev_gro_receive(struct napi_struct *napi,
 extern gro_result_t    napi_skb_finish(gro_result_t ret, struct sk_buff *skb);
 extern gro_result_t    napi_gro_receive(struct napi_struct *napi,
                                         struct sk_buff *skb);
+extern void            napi_gro_flush(struct napi_struct *napi);
 extern void            napi_reuse_skb(struct napi_struct *napi,
                                       struct sk_buff *skb);
 extern struct sk_buff *        napi_get_frags(struct napi_struct *napi);
@@ -2171,6 +2179,8 @@ extern void dev_seq_stop(struct seq_file *seq, void *v);
 extern int netdev_class_create_file(struct class_attribute *class_attr);
 extern void netdev_class_remove_file(struct class_attribute *class_attr);
 
+extern struct kobj_ns_type_operations net_ns_type_operations;
+
 extern char *netdev_drivername(const struct net_device *dev, char *buffer, int len);
 
 extern void linkwatch_run_queue(void);
@@ -2191,7 +2201,7 @@ static inline int net_gso_ok(int features, int gso_type)
 static inline int skb_gso_ok(struct sk_buff *skb, int features)
 {
        return net_gso_ok(features, skb_shinfo(skb)->gso_type) &&
-              (!skb_has_frags(skb) || (features & NETIF_F_FRAGLIST));
+              (!skb_has_frag_list(skb) || (features & NETIF_F_FRAGLIST));
 }
 
 static inline int netif_needs_gso(struct net_device *dev, struct sk_buff *skb)
index 2c8701687336c94327297274e6bf0502c5b3633c..31603e8b558132818f37936ae0a99113bf43a54f 100644 (file)
  * TODO: need more info?
  */
 
+/**
+ * DOC: Frame transmission/registration support
+ *
+ * Frame transmission and registration support exists to allow userspace
+ * management entities such as wpa_supplicant react to management frames
+ * that are not being handled by the kernel. This includes, for example,
+ * certain classes of action frames that cannot be handled in the kernel
+ * for various reasons.
+ *
+ * Frame registration is done on a per-interface basis and registrations
+ * cannot be removed other than by closing the socket. It is possible to
+ * specify a registration filter to register, for example, only for a
+ * certain type of action frame. In particular with action frames, those
+ * that userspace registers for will not be returned as unhandled by the
+ * driver, so that the registered application has to take responsibility
+ * for doing that.
+ *
+ * The type of frame that can be registered for is also dependent on the
+ * driver and interface type. The frame types are advertised in wiphy
+ * attributes so applications know what to expect.
+ *
+ * NOTE: When an interface changes type while registrations are active,
+ *       these registrations are ignored until the interface type is
+ *       changed again. This means that changing the interface type can
+ *       lead to a situation that couldn't otherwise be produced, but
+ *       any such registrations will be dormant in the sense that they
+ *       will not be serviced, i.e. they will not receive any frames.
+ *
+ * Frame transmission allows userspace to send for example the required
+ * responses to action frames. It is subject to some sanity checking,
+ * but many frames can be transmitted. When a frame was transmitted, its
+ * status is indicated to the sending socket.
+ *
+ * For more technical details, see the corresponding command descriptions
+ * below.
+ */
+
 /**
  * enum nl80211_commands - supported nl80211 commands
  *
  *     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 and %NL80211_ATTR_CONTROL_PORT.
+ *     %NL80211_ATTR_WIPHY_FREQ, %NL80211_ATTR_CONTROL_PORT,
+ *     %NL80211_ATTR_CONTROL_PORT_ETHERTYPE and
+ *     %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT.
  *     It is also sent as an event, with the BSSID and response IEs when the
  *     connection is established or failed to be established. This can be
  *     determined by the STATUS_CODE attribute.
  *     rate selection. %NL80211_ATTR_IFINDEX is used to specify the interface
  *     and @NL80211_ATTR_TX_RATES the set of allowed rates.
  *
- * @NL80211_CMD_REGISTER_ACTION: Register for receiving certain action frames
- *     (via @NL80211_CMD_ACTION) for processing in userspace. This command
- *     requires an interface index and a match attribute containing the first
- *     few bytes of the frame that should match, e.g. a single byte for only
- *     a category match or four bytes for vendor frames including the OUI.
- *     The registration cannot be dropped, but is removed automatically
- *     when the netlink socket is closed. Multiple registrations can be made.
- * @NL80211_CMD_ACTION: Action frame TX request and RX notification. This
- *     command is used both as a request to transmit an Action frame and as an
- *     event indicating reception of an Action frame that was not processed in
+ * @NL80211_CMD_REGISTER_FRAME: Register for receiving certain mgmt frames
+ *     (via @NL80211_CMD_FRAME) for processing in userspace. This command
+ *     requires an interface index, a frame type attribute (optional for
+ *     backward compatibility reasons, if not given assumes action frames)
+ *     and a match attribute containing the first few bytes of the frame
+ *     that should match, e.g. a single byte for only a category match or
+ *     four bytes for vendor frames including the OUI. The registration
+ *     cannot be dropped, but is removed automatically when the netlink
+ *     socket is closed. Multiple registrations can be made.
+ * @NL80211_CMD_REGISTER_ACTION: Alias for @NL80211_CMD_REGISTER_FRAME for
+ *     backward compatibility
+ * @NL80211_CMD_FRAME: Management frame TX request and RX notification. This
+ *     command is used both as a request to transmit a management frame and
+ *     as an event indicating reception of a frame that was not processed in
  *     kernel code, but is for us (i.e., which may need to be processed in a
  *     user space application). %NL80211_ATTR_FRAME is used to specify the
  *     frame contents (including header). %NL80211_ATTR_WIPHY_FREQ (and
  *     operational channel). When called, this operation returns a cookie
  *     (%NL80211_ATTR_COOKIE) that will be included with the TX status event
  *     pertaining to the TX request.
- * @NL80211_CMD_ACTION_TX_STATUS: Report TX status of an Action frame
- *     transmitted with %NL80211_CMD_ACTION. %NL80211_ATTR_COOKIE identifies
+ * @NL80211_CMD_ACTION: Alias for @NL80211_CMD_FRAME for backward compatibility.
+ * @NL80211_CMD_FRAME_TX_STATUS: Report TX status of a management frame
+ *     transmitted with %NL80211_CMD_FRAME. %NL80211_ATTR_COOKIE identifies
  *     the TX command and %NL80211_ATTR_FRAME includes the contents of the
  *     frame. %NL80211_ATTR_ACK flag is included if the recipient acknowledged
  *     the frame.
+ * @NL80211_CMD_ACTION_TX_STATUS: Alias for @NL80211_CMD_FRAME_TX_STATUS for
+ *     backward compatibility.
  * @NL80211_CMD_SET_CQM: Connection quality monitor configuration. This command
  *     is used to configure connection quality monitoring notification trigger
  *     levels.
@@ -429,9 +475,12 @@ enum nl80211_commands {
 
        NL80211_CMD_SET_TX_BITRATE_MASK,
 
-       NL80211_CMD_REGISTER_ACTION,
-       NL80211_CMD_ACTION,
-       NL80211_CMD_ACTION_TX_STATUS,
+       NL80211_CMD_REGISTER_FRAME,
+       NL80211_CMD_REGISTER_ACTION = NL80211_CMD_REGISTER_FRAME,
+       NL80211_CMD_FRAME,
+       NL80211_CMD_ACTION = NL80211_CMD_FRAME,
+       NL80211_CMD_FRAME_TX_STATUS,
+       NL80211_CMD_ACTION_TX_STATUS = NL80211_CMD_FRAME_TX_STATUS,
 
        NL80211_CMD_SET_POWER_SAVE,
        NL80211_CMD_GET_POWER_SAVE,
@@ -639,6 +688,15 @@ enum nl80211_commands {
  *     request, the driver will assume that the port is unauthorized until
  *     authorized by user space. Otherwise, port is marked authorized by
  *     default in station mode.
+ * @NL80211_ATTR_CONTROL_PORT_ETHERTYPE: A 16-bit value indicating the
+ *     ethertype that will be used for key negotiation. It can be
+ *     specified with the associate and connect commands. If it is not
+ *     specified, the value defaults to 0x888E (PAE, 802.1X). This
+ *     attribute is also used as a flag in the wiphy information to
+ *     indicate that protocols other than PAE are supported.
+ * @NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT: When included along with
+ *     %NL80211_ATTR_CONTROL_PORT_ETHERTYPE, indicates that the custom
+ *     ethertype frames used for key negotiation must not be encrypted.
  *
  * @NL80211_ATTR_TESTDATA: Testmode data blob, passed through to the driver.
  *     We recommend using nested, driver-specific attributes within this.
@@ -708,7 +766,16 @@ enum nl80211_commands {
  *     is used with %NL80211_CMD_SET_TX_BITRATE_MASK.
  *
  * @NL80211_ATTR_FRAME_MATCH: A binary attribute which typically must contain
- *     at least one byte, currently used with @NL80211_CMD_REGISTER_ACTION.
+ *     at least one byte, currently used with @NL80211_CMD_REGISTER_FRAME.
+ * @NL80211_ATTR_FRAME_TYPE: A u16 indicating the frame type/subtype for the
+ *     @NL80211_CMD_REGISTER_FRAME command.
+ * @NL80211_ATTR_TX_FRAME_TYPES: wiphy capability attribute, which is a
+ *     nested attribute of %NL80211_ATTR_FRAME_TYPE attributes, containing
+ *     information about which frame types can be transmitted with
+ *     %NL80211_CMD_FRAME.
+ * @NL80211_ATTR_RX_FRAME_TYPES: wiphy capability attribute, which is a
+ *     nested attribute of %NL80211_ATTR_FRAME_TYPE attributes, containing
+ *     information about which frame types can be registered for RX.
  *
  * @NL80211_ATTR_ACK: Flag attribute indicating that the frame was
  *     acknowledged by the recipient.
@@ -891,6 +958,13 @@ enum nl80211_attrs {
        NL80211_ATTR_WIPHY_TX_POWER_SETTING,
        NL80211_ATTR_WIPHY_TX_POWER_LEVEL,
 
+       NL80211_ATTR_TX_FRAME_TYPES,
+       NL80211_ATTR_RX_FRAME_TYPES,
+       NL80211_ATTR_FRAME_TYPE,
+
+       NL80211_ATTR_CONTROL_PORT_ETHERTYPE,
+       NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT,
+
        /* add attributes here, update the policy in nl80211.c */
 
        __NL80211_ATTR_AFTER_LAST,
@@ -947,7 +1021,7 @@ enum nl80211_attrs {
  * @NL80211_IFTYPE_MONITOR: monitor interface receiving all frames
  * @NL80211_IFTYPE_MESH_POINT: mesh point
  * @NL80211_IFTYPE_MAX: highest interface type number currently defined
- * @__NL80211_IFTYPE_AFTER_LAST: internal use
+ * @NUM_NL80211_IFTYPES: number of defined interface types
  *
  * These values are used with the %NL80211_ATTR_IFTYPE
  * to set the type of an interface.
@@ -964,8 +1038,8 @@ enum nl80211_iftype {
        NL80211_IFTYPE_MESH_POINT,
 
        /* keep last */
-       __NL80211_IFTYPE_AFTER_LAST,
-       NL80211_IFTYPE_MAX = __NL80211_IFTYPE_AFTER_LAST - 1
+       NUM_NL80211_IFTYPES,
+       NL80211_IFTYPE_MAX = NUM_NL80211_IFTYPES - 1
 };
 
 /**
@@ -974,11 +1048,14 @@ enum nl80211_iftype {
  * Station flags. When a station is added to an AP interface, it is
  * assumed to be already associated (and hence authenticated.)
  *
+ * @__NL80211_STA_FLAG_INVALID: attribute number 0 is reserved
  * @NL80211_STA_FLAG_AUTHORIZED: station is authorized (802.1X)
  * @NL80211_STA_FLAG_SHORT_PREAMBLE: station is capable of receiving frames
  *     with short barker preamble
  * @NL80211_STA_FLAG_WME: station is WME/QoS capable
  * @NL80211_STA_FLAG_MFP: station uses management frame protection
+ * @NL80211_STA_FLAG_MAX: highest station flag number currently defined
+ * @__NL80211_STA_FLAG_AFTER_LAST: internal use
  */
 enum nl80211_sta_flags {
        __NL80211_STA_FLAG_INVALID,
@@ -1091,14 +1168,17 @@ enum nl80211_mpath_flags {
  * information about a mesh path.
  *
  * @__NL80211_MPATH_INFO_INVALID: attribute number 0 is reserved
- * @NL80211_ATTR_MPATH_FRAME_QLEN: number of queued frames for this destination
- * @NL80211_ATTR_MPATH_SN: destination sequence number
- * @NL80211_ATTR_MPATH_METRIC: metric (cost) of this mesh path
- * @NL80211_ATTR_MPATH_EXPTIME: expiration time for the path, in msec from now
- * @NL80211_ATTR_MPATH_FLAGS: mesh path flags, enumerated in
+ * @NL80211_MPATH_INFO_FRAME_QLEN: number of queued frames for this destination
+ * @NL80211_MPATH_INFO_SN: destination sequence number
+ * @NL80211_MPATH_INFO_METRIC: metric (cost) of this mesh path
+ * @NL80211_MPATH_INFO_EXPTIME: expiration time for the path, in msec from now
+ * @NL80211_MPATH_INFO_FLAGS: mesh path flags, enumerated in
  *     &enum nl80211_mpath_flags;
- * @NL80211_ATTR_MPATH_DISCOVERY_TIMEOUT: total path discovery timeout, in msec
- * @NL80211_ATTR_MPATH_DISCOVERY_RETRIES: mesh path discovery retries
+ * @NL80211_MPATH_INFO_DISCOVERY_TIMEOUT: total path discovery timeout, in msec
+ * @NL80211_MPATH_INFO_DISCOVERY_RETRIES: mesh path discovery retries
+ * @NL80211_MPATH_INFO_MAX: highest mesh path information attribute number
+ *     currently defind
+ * @__NL80211_MPATH_INFO_AFTER_LAST: internal use
  */
 enum nl80211_mpath_info {
        __NL80211_MPATH_INFO_INVALID,
@@ -1127,6 +1207,8 @@ enum nl80211_mpath_info {
  * @NL80211_BAND_ATTR_HT_CAPA: HT capabilities, as in the HT information IE
  * @NL80211_BAND_ATTR_HT_AMPDU_FACTOR: A-MPDU factor, as in 11n
  * @NL80211_BAND_ATTR_HT_AMPDU_DENSITY: A-MPDU density, as in 11n
+ * @NL80211_BAND_ATTR_MAX: highest band attribute currently defined
+ * @__NL80211_BAND_ATTR_AFTER_LAST: internal use
  */
 enum nl80211_band_attr {
        __NL80211_BAND_ATTR_INVALID,
@@ -1147,6 +1229,7 @@ enum nl80211_band_attr {
 
 /**
  * enum nl80211_frequency_attr - frequency attributes
+ * @__NL80211_FREQUENCY_ATTR_INVALID: attribute number 0 is reserved
  * @NL80211_FREQUENCY_ATTR_FREQ: Frequency in MHz
  * @NL80211_FREQUENCY_ATTR_DISABLED: Channel is disabled in current
  *     regulatory domain.
@@ -1158,6 +1241,9 @@ enum nl80211_band_attr {
  *     on this channel in current regulatory domain.
  * @NL80211_FREQUENCY_ATTR_MAX_TX_POWER: Maximum transmission power in mBm
  *     (100 * dBm).
+ * @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number
+ *     currently defined
+ * @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use
  */
 enum nl80211_frequency_attr {
        __NL80211_FREQUENCY_ATTR_INVALID,
@@ -1177,9 +1263,13 @@ enum nl80211_frequency_attr {
 
 /**
  * enum nl80211_bitrate_attr - bitrate attributes
+ * @__NL80211_BITRATE_ATTR_INVALID: attribute number 0 is reserved
  * @NL80211_BITRATE_ATTR_RATE: Bitrate in units of 100 kbps
  * @NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE: Short preamble supported
  *     in 2.4 GHz band.
+ * @NL80211_BITRATE_ATTR_MAX: highest bitrate attribute number
+ *     currently defined
+ * @__NL80211_BITRATE_ATTR_AFTER_LAST: internal use
  */
 enum nl80211_bitrate_attr {
        __NL80211_BITRATE_ATTR_INVALID,
@@ -1235,6 +1325,7 @@ enum nl80211_reg_type {
 
 /**
  * enum nl80211_reg_rule_attr - regulatory rule attributes
+ * @__NL80211_REG_RULE_ATTR_INVALID: attribute number 0 is reserved
  * @NL80211_ATTR_REG_RULE_FLAGS: a set of flags which specify additional
  *     considerations for a given frequency range. These are the
  *     &enum nl80211_reg_rule_flags.
@@ -1251,6 +1342,9 @@ enum nl80211_reg_type {
  *     If you don't have one then don't send this.
  * @NL80211_ATTR_POWER_RULE_MAX_EIRP: the maximum allowed EIRP for
  *     a given frequency range. The value is in mBm (100 * dBm).
+ * @NL80211_REG_RULE_ATTR_MAX: highest regulatory rule attribute number
+ *     currently defined
+ * @__NL80211_REG_RULE_ATTR_AFTER_LAST: internal use
  */
 enum nl80211_reg_rule_attr {
        __NL80211_REG_RULE_ATTR_INVALID,
@@ -1302,6 +1396,9 @@ enum nl80211_reg_rule_flags {
  * @__NL80211_SURVEY_INFO_INVALID: attribute number 0 is reserved
  * @NL80211_SURVEY_INFO_FREQUENCY: center frequency of channel
  * @NL80211_SURVEY_INFO_NOISE: noise level of channel (u8, dBm)
+ * @NL80211_SURVEY_INFO_MAX: highest survey info attribute number
+ *     currently defined
+ * @__NL80211_SURVEY_INFO_AFTER_LAST: internal use
  */
 enum nl80211_survey_info {
        __NL80211_SURVEY_INFO_INVALID,
@@ -1466,6 +1563,7 @@ enum nl80211_channel_type {
  * enum nl80211_bss - netlink attributes for a BSS
  *
  * @__NL80211_BSS_INVALID: invalid
+ * @NL80211_BSS_BSSID: BSSID of the BSS (6 octets)
  * @NL80211_BSS_FREQUENCY: frequency in MHz (u32)
  * @NL80211_BSS_TSF: TSF of the received probe response/beacon (u64)
  * @NL80211_BSS_BEACON_INTERVAL: beacon interval of the (I)BSS (u16)
@@ -1509,6 +1607,12 @@ enum nl80211_bss {
 
 /**
  * enum nl80211_bss_status - BSS "status"
+ * @NL80211_BSS_STATUS_AUTHENTICATED: Authenticated with this BSS.
+ * @NL80211_BSS_STATUS_ASSOCIATED: Associated with this BSS.
+ * @NL80211_BSS_STATUS_IBSS_JOINED: Joined to this IBSS.
+ *
+ * The BSS status is a BSS attribute in scan dumps, which
+ * indicates the status the interface has wrt. this BSS.
  */
 enum nl80211_bss_status {
        NL80211_BSS_STATUS_AUTHENTICATED,
@@ -1619,8 +1723,8 @@ enum nl80211_tx_rate_attributes {
 
 /**
  * enum nl80211_band - Frequency band
- * @NL80211_BAND_2GHZ - 2.4 GHz ISM band
- * @NL80211_BAND_5GHZ - around 5 GHz band (4.9 - 5.7 GHz)
+ * @NL80211_BAND_2GHZ: 2.4 GHz ISM band
+ * @NL80211_BAND_5GHZ: around 5 GHz band (4.9 - 5.7 GHz)
  */
 enum nl80211_band {
        NL80211_BAND_2GHZ,
@@ -1658,9 +1762,9 @@ enum nl80211_attr_cqm {
 
 /**
  * enum nl80211_cqm_rssi_threshold_event - RSSI threshold event
- * @NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW - The RSSI level is lower than the
+ * @NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW: The RSSI level is lower than the
  *      configured threshold
- * @NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH - The RSSI is higher than the
+ * @NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH: The RSSI is higher than the
  *      configured threshold
  */
 enum nl80211_cqm_rssi_threshold_event {
index 10d33309e9a61351aa4d3597540f201c97dc9294..9438660b46eab77c727bf022d0b1fcd8577a49c7 100644 (file)
 #define PCI_VENDOR_ID_ARIMA            0x161f
 
 #define PCI_VENDOR_ID_BROCADE          0x1657
+#define PCI_DEVICE_ID_BROCADE_CT       0x0014
+#define PCI_DEVICE_ID_BROCADE_FC_8G1P  0x0017
+#define PCI_DEVICE_ID_BROCADE_CT_FC    0x0021
 
 #define PCI_VENDOR_ID_SIBYTE           0x166d
 #define PCI_DEVICE_ID_BCM1250_PCI      0x0001
index 6b0a782c6224f60d4530139a90ebc479ac6b3513..a6e047a04f798ed1ae0f75583ad7a2430b2c3958 100644 (file)
@@ -116,7 +116,7 @@ struct mii_bus {
        /* list of all PHYs on bus */
        struct phy_device *phy_map[PHY_MAX_ADDR];
 
-       /* Phy addresses to be ignored when probing */
+       /* PHY addresses to be ignored when probing */
        u32 phy_mask;
 
        /*
@@ -283,7 +283,7 @@ struct phy_device {
 
        phy_interface_t interface;
 
-       /* Bus address of the PHY (0-32) */
+       /* Bus address of the PHY (0-31) */
        int addr;
 
        /*
index 7f6ba8658abe4909d27c3699fba92332b059a1dd..defbde203d0782034d23173063a9f7313d0b2e81 100644 (file)
@@ -332,6 +332,7 @@ enum {
        FLOW_KEY_SKUID,
        FLOW_KEY_SKGID,
        FLOW_KEY_VLAN_TAG,
+       FLOW_KEY_RXHASH,
        __FLOW_KEY_MAX,
 };
 
index 24bce3ded9eade070774b40a517446b62df7fce9..91950950aa598060a8e0e370f82654cd9a75e7d6 100644 (file)
 
 #include <linux/types.h>
 
-/* These sparse annotated types shouldn't be in any user
- * visible header file. We should clean this up rather
- * than kludging around them. */
-#ifndef __KERNEL__
-#define __be16 u_int16_t
-#define __be32 u_int32_t
-#define __be64 u_int64_t
-#endif
-
 #define RDS_IB_ABI_VERSION             0x301
 
 /*
 #define RDS_CMSG_RDMA_MAP              3
 #define RDS_CMSG_RDMA_STATUS           4
 #define RDS_CMSG_CONG_UPDATE           5
+#define RDS_CMSG_ATOMIC_FADD           6
+#define RDS_CMSG_ATOMIC_CSWP           7
+#define RDS_CMSG_MASKED_ATOMIC_FADD    8
+#define RDS_CMSG_MASKED_ATOMIC_CSWP    9
 
 #define RDS_INFO_FIRST                 10000
 #define RDS_INFO_COUNTERS              10000
@@ -98,9 +93,9 @@
 #define RDS_INFO_LAST                  10010
 
 struct rds_info_counter {
-       u_int8_t        name[32];
-       u_int64_t       value;
-} __packed;
+       uint8_t name[32];
+       uint64_t        value;
+} __attribute__((packed));
 
 #define RDS_INFO_CONNECTION_FLAG_SENDING       0x01
 #define RDS_INFO_CONNECTION_FLAG_CONNECTING    0x02
@@ -109,56 +104,48 @@ struct rds_info_counter {
 #define TRANSNAMSIZ    16
 
 struct rds_info_connection {
-       u_int64_t       next_tx_seq;
-       u_int64_t       next_rx_seq;
-       __be32          laddr;
-       __be32          faddr;
-       u_int8_t        transport[TRANSNAMSIZ];         /* null term ascii */
-       u_int8_t        flags;
-} __packed;
-
-struct rds_info_flow {
+       uint64_t        next_tx_seq;
+       uint64_t        next_rx_seq;
        __be32          laddr;
        __be32          faddr;
-       u_int32_t       bytes;
-       __be16          lport;
-       __be16          fport;
-} __packed;
+       uint8_t transport[TRANSNAMSIZ];         /* null term ascii */
+       uint8_t flags;
+} __attribute__((packed));
 
 #define RDS_INFO_MESSAGE_FLAG_ACK               0x01
 #define RDS_INFO_MESSAGE_FLAG_FAST_ACK          0x02
 
 struct rds_info_message {
-       u_int64_t       seq;
-       u_int32_t       len;
+       uint64_t        seq;
+       uint32_t        len;
        __be32          laddr;
        __be32          faddr;
        __be16          lport;
        __be16          fport;
-       u_int8_t        flags;
-} __packed;
+       uint8_t flags;
+} __attribute__((packed));
 
 struct rds_info_socket {
-       u_int32_t       sndbuf;
+       uint32_t        sndbuf;
        __be32          bound_addr;
        __be32          connected_addr;
        __be16          bound_port;
        __be16          connected_port;
-       u_int32_t       rcvbuf;
-       u_int64_t       inum;
-} __packed;
+       uint32_t        rcvbuf;
+       uint64_t        inum;
+} __attribute__((packed));
 
 struct rds_info_tcp_socket {
        __be32          local_addr;
        __be16          local_port;
        __be32          peer_addr;
        __be16          peer_port;
-       u_int64_t       hdr_rem;
-       u_int64_t       data_rem;
-       u_int32_t       last_sent_nxt;
-       u_int32_t       last_expected_una;
-       u_int32_t       last_seen_una;
-} __packed;
+       uint64_t       hdr_rem;
+       uint64_t       data_rem;
+       uint32_t       last_sent_nxt;
+       uint32_t       last_expected_una;
+       uint32_t       last_seen_una;
+} __attribute__((packed));
 
 #define RDS_IB_GID_LEN 16
 struct rds_info_rdma_connection {
@@ -212,42 +199,69 @@ struct rds_info_rdma_connection {
  * (so that the application does not have to worry about
  * alignment).
  */
-typedef u_int64_t      rds_rdma_cookie_t;
+typedef uint64_t       rds_rdma_cookie_t;
 
 struct rds_iovec {
-       u_int64_t       addr;
-       u_int64_t       bytes;
+       uint64_t        addr;
+       uint64_t        bytes;
 };
 
 struct rds_get_mr_args {
        struct rds_iovec vec;
-       u_int64_t       cookie_addr;
+       uint64_t        cookie_addr;
        uint64_t        flags;
 };
 
 struct rds_get_mr_for_dest_args {
        struct sockaddr_storage dest_addr;
        struct rds_iovec        vec;
-       u_int64_t               cookie_addr;
+       uint64_t                cookie_addr;
        uint64_t                flags;
 };
 
 struct rds_free_mr_args {
        rds_rdma_cookie_t cookie;
-       u_int64_t       flags;
+       uint64_t        flags;
 };
 
 struct rds_rdma_args {
        rds_rdma_cookie_t cookie;
        struct rds_iovec remote_vec;
-       u_int64_t       local_vec_addr;
-       u_int64_t       nr_local;
-       u_int64_t       flags;
-       u_int64_t       user_token;
+       uint64_t        local_vec_addr;
+       uint64_t        nr_local;
+       uint64_t        flags;
+       uint64_t        user_token;
+};
+
+struct rds_atomic_args {
+       rds_rdma_cookie_t cookie;
+       uint64_t        local_addr;
+       uint64_t        remote_addr;
+       union {
+               struct {
+                       uint64_t        compare;
+                       uint64_t        swap;
+               } cswp;
+               struct {
+                       uint64_t        add;
+               } fadd;
+               struct {
+                       uint64_t        compare;
+                       uint64_t        swap;
+                       uint64_t        compare_mask;
+                       uint64_t        swap_mask;
+               } m_cswp;
+               struct {
+                       uint64_t        add;
+                       uint64_t        nocarry_mask;
+               } m_fadd;
+       };
+       uint64_t        flags;
+       uint64_t        user_token;
 };
 
 struct rds_rdma_notify {
-       u_int64_t       user_token;
+       uint64_t        user_token;
        int32_t         status;
 };
 
@@ -266,5 +280,6 @@ struct rds_rdma_notify {
 #define RDS_RDMA_USE_ONCE      0x0008  /* free MR after use */
 #define RDS_RDMA_DONTWAIT      0x0010  /* Don't wait in SET_BARRIER */
 #define RDS_RDMA_NOTIFY_ME     0x0020  /* Notify when operation completes */
+#define RDS_RDMA_SILENT                0x0040  /* Do not interrupt remote */
 
 #endif /* IB_RDS_H */
index 58d44491880fa79ec30d7c863f609547c4ed7439..263690d991a833ce6636c35eaf311efc830af896 100644 (file)
@@ -749,6 +749,17 @@ extern int rtnl_is_locked(void);
 extern int lockdep_rtnl_is_held(void);
 #endif /* #ifdef CONFIG_PROVE_LOCKING */
 
+/**
+ * rcu_dereference_rtnl - rcu_dereference with debug checking
+ * @p: The pointer to read, prior to dereferencing
+ *
+ * Do an rcu_dereference(p), but check caller either holds rcu_read_lock()
+ * or RTNL
+ */
+#define rcu_dereference_rtnl(p)                                        \
+       rcu_dereference_check(p, rcu_read_lock_held() ||        \
+                                lockdep_rtnl_is_held())
+
 extern void rtnetlink_init(void);
 extern void __rtnl_unlock(void);
 
index 77eb60d2b496e0139a182d047077ea0b0949178e..9e8085a89589b5637f272af8f637e21d889990ee 100644 (file)
@@ -163,26 +163,19 @@ struct skb_shared_hwtstamps {
        ktime_t syststamp;
 };
 
-/**
- * struct skb_shared_tx - instructions for time stamping of outgoing packets
- * @hardware:          generate hardware time stamp
- * @software:          generate software time stamp
- * @in_progress:       device driver is going to provide
- *                     hardware time stamp
- * @prevent_sk_orphan: make sk reference available on driver level
- * @flags:             all shared_tx flags
- *
- * These flags are attached to packets as part of the
- * &skb_shared_info. Use skb_tx() to get a pointer.
- */
-union skb_shared_tx {
-       struct {
-               __u8    hardware:1,
-                       software:1,
-                       in_progress:1,
-                       prevent_sk_orphan:1;
-       };
-       __u8 flags;
+/* Definitions for tx_flags in struct skb_shared_info */
+enum {
+       /* generate hardware time stamp */
+       SKBTX_HW_TSTAMP = 1 << 0,
+
+       /* generate software time stamp */
+       SKBTX_SW_TSTAMP = 1 << 1,
+
+       /* device driver is going to provide hardware time stamp */
+       SKBTX_IN_PROGRESS = 1 << 2,
+
+       /* ensure the originating sk reference is available on driver level */
+       SKBTX_DRV_NEEDS_SK_REF = 1 << 3,
 };
 
 /* This data is invariant across clones and lives at
@@ -195,7 +188,7 @@ struct skb_shared_info {
        unsigned short  gso_segs;
        unsigned short  gso_type;
        __be32          ip6_frag_id;
-       union skb_shared_tx tx_flags;
+       __u8            tx_flags;
        struct sk_buff  *frag_list;
        struct skb_shared_hwtstamps hwtstamps;
 
@@ -558,6 +551,15 @@ extern unsigned int   skb_find_text(struct sk_buff *skb, unsigned int from,
                                    unsigned int to, struct ts_config *config,
                                    struct ts_state *state);
 
+extern __u32 __skb_get_rxhash(struct sk_buff *skb);
+static inline __u32 skb_get_rxhash(struct sk_buff *skb)
+{
+       if (!skb->rxhash)
+               skb->rxhash = __skb_get_rxhash(skb);
+
+       return skb->rxhash;
+}
+
 #ifdef NET_SKBUFF_DATA_USES_OFFSET
 static inline unsigned char *skb_end_pointer(const struct sk_buff *skb)
 {
@@ -578,11 +580,6 @@ static inline struct skb_shared_hwtstamps *skb_hwtstamps(struct sk_buff *skb)
        return &skb_shinfo(skb)->hwtstamps;
 }
 
-static inline union skb_shared_tx *skb_tx(struct sk_buff *skb)
-{
-       return &skb_shinfo(skb)->tx_flags;
-}
-
 /**
  *     skb_queue_empty - check if a queue is empty
  *     @list: queue head
@@ -1123,7 +1120,7 @@ extern void skb_add_rx_frag(struct sk_buff *skb, int i, struct page *page,
                            int off, int size);
 
 #define SKB_PAGE_ASSERT(skb)   BUG_ON(skb_shinfo(skb)->nr_frags)
-#define SKB_FRAG_ASSERT(skb)   BUG_ON(skb_has_frags(skb))
+#define SKB_FRAG_ASSERT(skb)   BUG_ON(skb_has_frag_list(skb))
 #define SKB_LINEAR_ASSERT(skb)  BUG_ON(skb_is_nonlinear(skb))
 
 #ifdef NET_SKBUFF_DATA_USES_OFFSET
@@ -1787,7 +1784,7 @@ static inline int pskb_trim_rcsum(struct sk_buff *skb, unsigned int len)
                     skb = skb->prev)
 
 
-static inline bool skb_has_frags(const struct sk_buff *skb)
+static inline bool skb_has_frag_list(const struct sk_buff *skb)
 {
        return skb_shinfo(skb)->frag_list != NULL;
 }
@@ -1987,8 +1984,8 @@ extern void skb_tstamp_tx(struct sk_buff *orig_skb,
 
 static inline void sw_tx_timestamp(struct sk_buff *skb)
 {
-       union skb_shared_tx *shtx = skb_tx(skb);
-       if (shtx->software && !shtx->in_progress)
+       if (skb_shinfo(skb)->tx_flags & SKBTX_SW_TSTAMP &&
+           !(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS))
                skb_tstamp_tx(skb, NULL);
 }
 
@@ -2209,6 +2206,21 @@ static inline void skb_forward_csum(struct sk_buff *skb)
                skb->ip_summed = CHECKSUM_NONE;
 }
 
+/**
+ * skb_checksum_none_assert - make sure skb ip_summed is CHECKSUM_NONE
+ * @skb: skb to check
+ *
+ * fresh skbs have their ip_summed set to CHECKSUM_NONE.
+ * Instead of forcing ip_summed to CHECKSUM_NONE, we can
+ * use this helper, to document places where we make this assertion.
+ */
+static inline void skb_checksum_none_assert(struct sk_buff *skb)
+{
+#ifdef DEBUG
+       BUG_ON(skb->ip_summed != CHECKSUM_NONE);
+#endif
+}
+
 bool skb_partial_csum_set(struct sk_buff *skb, u16 start, u16 off);
 #endif /* __KERNEL__ */
 #endif /* _LINUX_SKBUFF_H */
index a223ecbc71eff8160c0c0b96921cd4e81e0e9d4f..a20bccf0b5c2679c7e28b0ac859380823b324931 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 2009 Nokia Corporation
  *
- * Contact: Kalle Valo <kalle.valo@nokia.com>
+ * Contact: Luciano Coelho <luciano.coelho@nokia.com>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
index a6d5225b9275e73b2d4beaf2c0017df325bb054b..11daf9c140e78f7e82a62aafff0419992abdd09a 100644 (file)
@@ -97,6 +97,7 @@
 #define  SSB_TMSLOW_RESET      0x00000001 /* Reset */
 #define  SSB_TMSLOW_REJECT_22  0x00000002 /* Reject (Backplane rev 2.2) */
 #define  SSB_TMSLOW_REJECT_23  0x00000004 /* Reject (Backplane rev 2.3) */
+#define  SSB_TMSLOW_PHYCLK     0x00000010 /* MAC PHY Clock Control Enable */
 #define  SSB_TMSLOW_CLOCK      0x00010000 /* Clock Enable */
 #define  SSB_TMSLOW_FGC                0x00020000 /* Force Gated Clocks On */
 #define  SSB_TMSLOW_PE         0x40000000 /* Power Management Enable */
index 632ff7c0328040f4f3ceb5dd8f06655bf05e84b5..a4adf0de6ed60b880765549c200b97a639d14e3c 100644 (file)
@@ -35,7 +35,7 @@ struct plat_stmmacenet_data {
        int has_gmac;
        int enh_desc;
        void (*fix_mac_speed)(void *priv, unsigned int speed);
-       void (*bus_setup)(unsigned long ioaddr);
+       void (*bus_setup)(void __iomem *ioaddr);
 #ifdef CONFIG_STM_DRIVERS
        struct stm_pad_config *pad_config;
 #endif
index 76990937f4c9517f0aa46b86a905de58ccd95119..67b501c302b20fa3cddfd605c1e45172f02c5500 100644 (file)
@@ -4,3 +4,4 @@ header-y += tc_mirred.h
 header-y += tc_pedit.h
 header-y += tc_nat.h
 header-y += tc_skbedit.h
+header-y += tc_csum.h
diff --git a/include/linux/tc_act/tc_csum.h b/include/linux/tc_act/tc_csum.h
new file mode 100644 (file)
index 0000000..a047c49
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef __LINUX_TC_CSUM_H
+#define __LINUX_TC_CSUM_H
+
+#include <linux/types.h>
+#include <linux/pkt_cls.h>
+
+#define TCA_ACT_CSUM 16
+
+enum {
+       TCA_CSUM_UNSPEC,
+       TCA_CSUM_PARMS,
+       TCA_CSUM_TM,
+       __TCA_CSUM_MAX
+};
+#define TCA_CSUM_MAX (__TCA_CSUM_MAX - 1)
+
+enum {
+       TCA_CSUM_UPDATE_FLAG_IPV4HDR = 1,
+       TCA_CSUM_UPDATE_FLAG_ICMP    = 2,
+       TCA_CSUM_UPDATE_FLAG_IGMP    = 4,
+       TCA_CSUM_UPDATE_FLAG_TCP     = 8,
+       TCA_CSUM_UPDATE_FLAG_UDP     = 16,
+       TCA_CSUM_UPDATE_FLAG_UDPLITE = 32
+};
+
+struct tc_csum {
+       tc_gen;
+
+       __u32 update_flags;
+};
+
+#endif /* __LINUX_TC_CSUM_H */
index 0864206ec1a331b2aadacef8fa4a7fae4f3aa47e..7138962664f81912b974c29c12900606ae07306a 100644 (file)
@@ -79,6 +79,7 @@ enum {
        TCF_META_ID_SK_SENDMSG_OFF,
        TCF_META_ID_SK_WRITE_PENDING,
        TCF_META_ID_VLAN_TAG,
+       TCF_META_ID_RXHASH,
        __TCF_META_ID_MAX
 };
 #define TCF_META_ID_MAX (__TCF_META_ID_MAX - 1)
index a778ee024590dafb3357caed05da1cb1f6133821..e64f4c67d0ef7d4dcf65232bd58f9de2b5cb86d4 100644 (file)
@@ -105,6 +105,7 @@ enum {
 #define TCP_COOKIE_TRANSACTIONS        15      /* TCP Cookie Transactions */
 #define TCP_THIN_LINEAR_TIMEOUTS 16      /* Use linear timeouts for thin streams*/
 #define TCP_THIN_DUPACK         17      /* Fast retrans. after 1 dupack */
+#define TCP_USER_TIMEOUT       18      /* How long for loss retry before timeout */
 
 /* for TCP_INFO socket option */
 #define TCPI_OPT_TIMESTAMPS    1
index 2fd06c60ffbba1b81af86303d46e5187f98e946d..4c8c727d0cca04abe49fd01594378d38ddf12f3e 100644 (file)
 #include <linux/wireless.h>
 
 
+/**
+ * DOC: Introduction
+ *
+ * cfg80211 is the configuration API for 802.11 devices in Linux. It bridges
+ * userspace and drivers, and offers some utility functionality associated
+ * with 802.11. cfg80211 must, directly or indirectly via mac80211, be used
+ * by all modern wireless drivers in Linux, so that they offer a consistent
+ * API through nl80211. For backward compatibility, cfg80211 also offers
+ * wireless extensions to userspace, but hides them from drivers completely.
+ *
+ * Additionally, cfg80211 contains code to help enforce regulatory spectrum
+ * use restrictions.
+ */
+
+
+/**
+ * DOC: Device registration
+ *
+ * In order for a driver to use cfg80211, it must register the hardware device
+ * with cfg80211. This happens through a number of hardware capability structs
+ * described below.
+ *
+ * The fundamental structure for each device is the 'wiphy', of which each
+ * instance describes a physical wireless device connected to the system. Each
+ * such wiphy can have zero, one, or many virtual interfaces associated with
+ * it, which need to be identified as such by pointing the network interface's
+ * @ieee80211_ptr pointer to a &struct wireless_dev which further describes
+ * the wireless part of the interface, normally this struct is embedded in the
+ * network interface's private data area. Drivers can optionally allow creating
+ * or destroying virtual interfaces on the fly, but without at least one or the
+ * ability to create some the wireless device isn't useful.
+ *
+ * Each wiphy structure contains device capability information, and also has
+ * a pointer to the various operations the driver offers. The definitions and
+ * structures here describe these capabilities in detail.
+ */
+
 /*
  * wireless hardware capability structures
  */
@@ -204,6 +241,21 @@ struct ieee80211_supported_band {
  * Wireless hardware/device configuration structures and methods
  */
 
+/**
+ * DOC: Actions and configuration
+ *
+ * Each wireless device and each virtual interface offer a set of configuration
+ * operations and other actions that are invoked by userspace. Each of these
+ * actions is described in the operations structure, and the parameters these
+ * operations use are described separately.
+ *
+ * Additionally, some operations are asynchronous and expect to get status
+ * information via some functions that drivers need to call.
+ *
+ * Scanning and BSS list handling with its associated functionality is described
+ * in a separate chapter.
+ */
+
 /**
  * struct vif_params - describes virtual interface parameters
  * @mesh_id: mesh ID to use
@@ -570,8 +622,28 @@ struct ieee80211_txq_params {
 /* from net/wireless.h */
 struct wiphy;
 
-/* from net/ieee80211.h */
-struct ieee80211_channel;
+/**
+ * DOC: Scanning and BSS list handling
+ *
+ * The scanning process itself is fairly simple, but cfg80211 offers quite
+ * a bit of helper functionality. To start a scan, the scan operation will
+ * be invoked with a scan definition. This scan definition contains the
+ * channels to scan, and the SSIDs to send probe requests for (including the
+ * wildcard, if desired). A passive scan is indicated by having no SSIDs to
+ * probe. Additionally, a scan request may contain extra information elements
+ * that should be added to the probe request. The IEs are guaranteed to be
+ * well-formed, and will not exceed the maximum length the driver advertised
+ * in the wiphy structure.
+ *
+ * When scanning finds a BSS, cfg80211 needs to be notified of that, because
+ * it is responsible for maintaining the BSS list; the driver should not
+ * maintain a list itself. For this notification, various functions exist.
+ *
+ * Since drivers do not maintain a BSS list, there are also a number of
+ * functions to search for a BSS and obtain information about it from the
+ * BSS structure cfg80211 maintains. The BSS list is also made available
+ * to userspace.
+ */
 
 /**
  * struct cfg80211_ssid - SSID description
@@ -691,6 +763,10 @@ const u8 *ieee80211_bss_get_ie(struct cfg80211_bss *bss, u8 ie);
  *     sets/clears %NL80211_STA_FLAG_AUTHORIZED. If true, the driver is
  *     required to assume that the port is unauthorized until authorized by
  *     user space. Otherwise, port is marked authorized by default.
+ * @control_port_ethertype: the control port protocol that should be
+ *     allowed through even on unauthorized ports
+ * @control_port_no_encrypt: TRUE to prevent encryption of control port
+ *     protocol frames.
  */
 struct cfg80211_crypto_settings {
        u32 wpa_versions;
@@ -700,6 +776,8 @@ struct cfg80211_crypto_settings {
        int n_akm_suites;
        u32 akm_suites[NL80211_MAX_NR_AKM_SUITES];
        bool control_port;
+       __be16 control_port_ethertype;
+       bool control_port_no_encrypt;
 };
 
 /**
@@ -1020,7 +1098,7 @@ struct cfg80211_pmksa {
  * @cancel_remain_on_channel: Cancel an on-going remain-on-channel operation.
  *     This allows the operation to be terminated prior to timeout based on
  *     the duration value.
- * @action: Transmit an action frame
+ * @mgmt_tx: Transmit a management frame
  *
  * @testmode_cmd: run a test mode command
  *
@@ -1172,7 +1250,7 @@ struct cfg80211_ops {
                                            struct net_device *dev,
                                            u64 cookie);
 
-       int     (*action)(struct wiphy *wiphy, struct net_device *dev,
+       int     (*mgmt_tx)(struct wiphy *wiphy, struct net_device *dev,
                          struct ieee80211_channel *chan,
                          enum nl80211_channel_type channel_type,
                          bool channel_type_valid,
@@ -1221,21 +1299,29 @@ struct cfg80211_ops {
  * @WIPHY_FLAG_4ADDR_AP: supports 4addr mode even on AP (with a single station
  *     on a VLAN interface)
  * @WIPHY_FLAG_4ADDR_STATION: supports 4addr mode even as a station
+ * @WIPHY_FLAG_CONTROL_PORT_PROTOCOL: This device supports setting the
+ *     control port protocol ethertype. The device also honours the
+ *     control_port_no_encrypt flag.
  */
 enum wiphy_flags {
-       WIPHY_FLAG_CUSTOM_REGULATORY    = BIT(0),
-       WIPHY_FLAG_STRICT_REGULATORY    = BIT(1),
-       WIPHY_FLAG_DISABLE_BEACON_HINTS = BIT(2),
-       WIPHY_FLAG_NETNS_OK             = BIT(3),
-       WIPHY_FLAG_PS_ON_BY_DEFAULT     = BIT(4),
-       WIPHY_FLAG_4ADDR_AP             = BIT(5),
-       WIPHY_FLAG_4ADDR_STATION        = BIT(6),
+       WIPHY_FLAG_CUSTOM_REGULATORY            = BIT(0),
+       WIPHY_FLAG_STRICT_REGULATORY            = BIT(1),
+       WIPHY_FLAG_DISABLE_BEACON_HINTS         = BIT(2),
+       WIPHY_FLAG_NETNS_OK                     = BIT(3),
+       WIPHY_FLAG_PS_ON_BY_DEFAULT             = BIT(4),
+       WIPHY_FLAG_4ADDR_AP                     = BIT(5),
+       WIPHY_FLAG_4ADDR_STATION                = BIT(6),
+       WIPHY_FLAG_CONTROL_PORT_PROTOCOL        = BIT(7),
 };
 
 struct mac_address {
        u8 addr[ETH_ALEN];
 };
 
+struct ieee80211_txrx_stypes {
+       u16 tx, rx;
+};
+
 /**
  * struct wiphy - wireless hardware description
  * @reg_notifier: the driver's regulatory notification callback
@@ -1286,6 +1372,10 @@ struct mac_address {
  * @privid: a pointer that drivers can use to identify if an arbitrary
  *     wiphy is theirs, e.g. in global notifiers
  * @bands: information about bands/channels supported by this device
+ *
+ * @mgmt_stypes: bitmasks of frame subtypes that can be subscribed to or
+ *     transmitted through nl80211, points to an array indexed by interface
+ *     type
  */
 struct wiphy {
        /* assign these fields before you register the wiphy */
@@ -1294,9 +1384,12 @@ struct wiphy {
        u8 perm_addr[ETH_ALEN];
        u8 addr_mask[ETH_ALEN];
 
-       u16 n_addresses;
        struct mac_address *addresses;
 
+       const struct ieee80211_txrx_stypes *mgmt_stypes;
+
+       u16 n_addresses;
+
        /* Supported interface modes, OR together BIT(NL80211_IFTYPE_...) */
        u16 interface_modes;
 
@@ -1492,8 +1585,8 @@ struct cfg80211_cached_keys;
  *     set by driver (if supported) on add_interface BEFORE registering the
  *     netdev and may otherwise be used by driver read-only, will be update
  *     by cfg80211 on change_interface
- * @action_registrations: list of registrations for action frames
- * @action_registrations_lock: lock for the list
+ * @mgmt_registrations: list of registrations for management frames
+ * @mgmt_registrations_lock: lock for the list
  * @mtx: mutex used to lock data in this struct
  * @cleanup_work: work struct used for cleanup that can't be done directly
  */
@@ -1505,8 +1598,8 @@ struct wireless_dev {
        struct list_head list;
        struct net_device *netdev;
 
-       struct list_head action_registrations;
-       spinlock_t action_registrations_lock;
+       struct list_head mgmt_registrations;
+       spinlock_t mgmt_registrations_lock;
 
        struct mutex mtx;
 
@@ -1563,8 +1656,10 @@ static inline void *wdev_priv(struct wireless_dev *wdev)
        return wiphy_priv(wdev->wiphy);
 }
 
-/*
- * Utility functions
+/**
+ * DOC: Utility functions
+ *
+ * cfg80211 offers a number of utility functions that can be useful.
  */
 
 /**
@@ -1715,7 +1810,15 @@ 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
  */
-unsigned int ieee80211_hdrlen(__le16 fc);
+unsigned int __attribute_const__ ieee80211_hdrlen(__le16 fc);
+
+/**
+ * DOC: Data path helpers
+ *
+ * In addition to generic utilities, cfg80211 also offers
+ * functions that help implement the data path for devices
+ * that do not do the 802.11/802.3 conversion on the device.
+ */
 
 /**
  * ieee80211_data_to_8023 - convert an 802.11 data frame to 802.3
@@ -1777,8 +1880,10 @@ unsigned int cfg80211_classify8021d(struct sk_buff *skb);
  */
 const u8 *cfg80211_find_ie(u8 eid, const u8 *ies, int len);
 
-/*
- * Regulatory helper functions for wiphys
+/**
+ * DOC: Regulatory enforcement infrastructure
+ *
+ * TODO
  */
 
 /**
@@ -2180,6 +2285,20 @@ void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr,
  */
 void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp);
 
+/**
+ * DOC: RFkill integration
+ *
+ * RFkill integration in cfg80211 is almost invisible to drivers,
+ * as cfg80211 automatically registers an rfkill instance for each
+ * wireless device it knows about. Soft kill is also translated
+ * into disconnecting and turning all interfaces off, drivers are
+ * expected to turn off the device when all interfaces are down.
+ *
+ * However, devices may have a hard RFkill line, in which case they
+ * also need to interact with the rfkill subsystem, via cfg80211.
+ * They can do this with a few helper functions documented here.
+ */
+
 /**
  * wiphy_rfkill_set_hw_state - notify cfg80211 about hw block state
  * @wiphy: the wiphy
@@ -2200,6 +2319,17 @@ void wiphy_rfkill_start_polling(struct wiphy *wiphy);
 void wiphy_rfkill_stop_polling(struct wiphy *wiphy);
 
 #ifdef CONFIG_NL80211_TESTMODE
+/**
+ * DOC: Test mode
+ *
+ * Test mode is a set of utility functions to allow drivers to
+ * interact with driver-specific tools to aid, for instance,
+ * factory programming.
+ *
+ * This chapter describes how drivers interact with it, for more
+ * information see the nl80211 book's chapter on it.
+ */
+
 /**
  * cfg80211_testmode_alloc_reply_skb - allocate testmode reply
  * @wiphy: the wiphy
@@ -2373,38 +2503,39 @@ void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr,
                      struct station_info *sinfo, gfp_t gfp);
 
 /**
- * cfg80211_rx_action - notification of received, unprocessed Action frame
+ * cfg80211_rx_mgmt - notification of received, unprocessed management frame
  * @dev: network device
  * @freq: Frequency on which the frame was received in MHz
- * @buf: Action frame (header + body)
+ * @buf: Management frame (header + body)
  * @len: length of the frame data
  * @gfp: context flags
- * Returns %true if a user space application is responsible for rejecting the
- *     unrecognized Action frame; %false if no such application is registered
- *     (i.e., the driver is responsible for rejecting the unrecognized Action
- *     frame)
+ *
+ * Returns %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_action(struct net_device *dev, int freq, const u8 *buf,
-                       size_t len, gfp_t gfp);
+bool cfg80211_rx_mgmt(struct net_device *dev, int freq, const u8 *buf,
+                     size_t len, gfp_t gfp);
 
 /**
- * cfg80211_action_tx_status - notification of TX status for Action frame
+ * cfg80211_mgmt_tx_status - notification of TX status for management frame
  * @dev: network device
- * @cookie: Cookie returned by cfg80211_ops::action()
- * @buf: Action frame (header + body)
+ * @cookie: Cookie returned by cfg80211_ops::mgmt_tx()
+ * @buf: Management frame (header + body)
  * @len: length of the frame data
  * @ack: Whether frame was acknowledged
  * @gfp: context flags
  *
- * This function is called whenever an Action frame was requested to be
- * transmitted with cfg80211_ops::action() to report the TX status of the
+ * This function is called whenever a management frame was requested to be
+ * transmitted with cfg80211_ops::mgmt_tx() to report the TX status of the
  * transmission attempt.
  */
-void cfg80211_action_tx_status(struct net_device *dev, u64 cookie,
-                              const u8 *buf, size_t len, bool ack, gfp_t gfp);
+void cfg80211_mgmt_tx_status(struct net_device *dev, u64 cookie,
+                            const u8 *buf, size_t len, bool ack, gfp_t gfp);
 
 
 /**
diff --git a/include/net/gre.h b/include/net/gre.h
new file mode 100644 (file)
index 0000000..8266547
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef __LINUX_GRE_H
+#define __LINUX_GRE_H
+
+#include <linux/skbuff.h>
+
+#define GREPROTO_CISCO         0
+#define GREPROTO_PPTP          1
+#define GREPROTO_MAX           2
+
+struct gre_protocol {
+       int  (*handler)(struct sk_buff *skb);
+       void (*err_handler)(struct sk_buff *skb, u32 info);
+};
+
+int gre_add_protocol(const struct gre_protocol *proto, u8 version);
+int gre_del_protocol(const struct gre_protocol *proto, u8 version);
+
+#endif
index b6d3b55da19b49e71d5cc7e0206090240cca0346..e4f494b42e060e1d4309acce8532aaa7f4b036eb 100644 (file)
@@ -125,6 +125,7 @@ struct inet_connection_sock {
                int               probe_size;
        } icsk_mtup;
        u32                       icsk_ca_priv[16];
+       u32                       icsk_user_timeout;
 #define ICSK_CA_PRIV_SIZE      (16 * sizeof(u32))
 };
 
index 890f9725d68156b8d4df25adea50880ae3bf46a0..7691aca133db438051adfcbdb0d37347c8a66b0d 100644 (file)
@@ -53,7 +53,7 @@ struct ipcm_cookie {
        __be32                  addr;
        int                     oif;
        struct ip_options       *opt;
-       union skb_shared_tx     shtx;
+       __u8                    tx_flags;
 };
 
 #define IPCB(skb) ((struct inet_skb_parm*)((skb)->cb))
index 73cacb3ac16cae48a2e494ec10874bb8258b44db..0af8b8dfbc227898badec117e2abe759889f8a20 100644 (file)
@@ -171,7 +171,6 @@ struct irlan_cb {
        int    magic;
        struct list_head  dev_list;
        struct net_device *dev;        /* Ethernet device structure*/
-       struct net_device_stats stats;
 
        __u32 saddr;               /* Source device address */
        __u32 daddr;               /* Destination device address */
index b0787a1dea904c69c3ca5f29c0674b54053c41bb..f91fc331369bb22f0ec6463e0511e180cf1fa902 100644 (file)
@@ -149,6 +149,7 @@ struct ieee80211_low_level_stats {
  * @BSS_CHANGED_ARP_FILTER: Hardware ARP filter address list or state changed.
  * @BSS_CHANGED_QOS: QoS for this association was enabled/disabled. Note
  *     that it is only ever disabled for station mode.
+ * @BSS_CHANGED_IDLE: Idle changed for this BSS/interface.
  */
 enum ieee80211_bss_change {
        BSS_CHANGED_ASSOC               = 1<<0,
@@ -165,6 +166,7 @@ enum ieee80211_bss_change {
        BSS_CHANGED_IBSS                = 1<<11,
        BSS_CHANGED_ARP_FILTER          = 1<<12,
        BSS_CHANGED_QOS                 = 1<<13,
+       BSS_CHANGED_IDLE                = 1<<14,
 
        /* when adding here, make sure to change ieee80211_reconfig */
 };
@@ -223,6 +225,9 @@ enum ieee80211_bss_change {
  *     hardware must not perform any ARP filtering. Note, that the filter will
  *     be enabled also in promiscuous mode.
  * @qos: This is a QoS-enabled BSS.
+ * @idle: This interface is idle. There's also a global idle flag in the
+ *     hardware config which may be more appropriate depending on what
+ *     your driver/device needs to do.
  */
 struct ieee80211_bss_conf {
        const u8 *bssid;
@@ -247,6 +252,7 @@ struct ieee80211_bss_conf {
        u8 arp_addr_cnt;
        bool arp_filter_enabled;
        bool qos;
+       bool idle;
 };
 
 /**
@@ -782,20 +788,6 @@ static inline bool ieee80211_vif_is_mesh(struct ieee80211_vif *vif)
        return false;
 }
 
-/**
- * enum ieee80211_key_alg - key algorithm
- * @ALG_WEP: WEP40 or WEP104
- * @ALG_TKIP: TKIP
- * @ALG_CCMP: CCMP (AES)
- * @ALG_AES_CMAC: AES-128-CMAC
- */
-enum ieee80211_key_alg {
-       ALG_WEP,
-       ALG_TKIP,
-       ALG_CCMP,
-       ALG_AES_CMAC,
-};
-
 /**
  * enum ieee80211_key_flags - key flags
  *
@@ -833,7 +825,7 @@ enum ieee80211_key_flags {
  * @hw_key_idx: To be set by the driver, this is the key index the driver
  *     wants to be given when a frame is transmitted and needs to be
  *     encrypted in hardware.
- * @alg: The key algorithm.
+ * @cipher: The key's cipher suite selector.
  * @flags: key flags, see &enum ieee80211_key_flags.
  * @keyidx: the key index (0-3)
  * @keylen: key material length
@@ -846,7 +838,7 @@ enum ieee80211_key_flags {
  * @iv_len: The IV length for this key type
  */
 struct ieee80211_key_conf {
-       enum ieee80211_key_alg alg;
+       u32 cipher;
        u8 icv_len;
        u8 iv_len;
        u8 hw_key_idx;
@@ -1102,6 +1094,10 @@ enum ieee80211_hw_flags {
  *
  * @max_rates: maximum number of alternate rate retry stages
  * @max_rate_tries: maximum number of tries for each stage
+ *
+ * @napi_weight: weight used for NAPI polling.  You must specify an
+ *     appropriate value here if a napi_poll operation is provided
+ *     by your driver.
  */
 struct ieee80211_hw {
        struct ieee80211_conf conf;
@@ -1113,6 +1109,7 @@ struct ieee80211_hw {
        int channel_change_time;
        int vif_data_size;
        int sta_data_size;
+       int napi_weight;
        u16 queues;
        u16 max_listen_interval;
        s8 max_signal;
@@ -1245,8 +1242,8 @@ ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw,
  * %IEEE80211_CONF_PS flag enabled means that the powersave mode defined in
  * IEEE 802.11-2007 section 11.2 is enabled. This is not to be confused
  * with hardware wakeup and sleep states. Driver is responsible for waking
- * up the hardware before issueing commands to the hardware and putting it
- * back to sleep at approriate times.
+ * up the hardware before issuing commands to the hardware and putting it
+ * back to sleep at appropriate times.
  *
  * When PS is enabled, hardware needs to wakeup for beacons and receive the
  * buffered multicast/broadcast frames after the beacon. Also it must be
@@ -1267,7 +1264,7 @@ ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw,
  * there's data traffic and still saving significantly power in idle
  * periods.
  *
- * Dynamic powersave is supported by simply mac80211 enabling and disabling
+ * Dynamic powersave is simply supported by mac80211 enabling and disabling
  * PS based on traffic. Driver needs to only set %IEEE80211_HW_SUPPORTS_PS
  * flag and mac80211 will handle everything automatically. Additionally,
  * hardware having support for the dynamic PS feature may set the
@@ -1540,6 +1537,12 @@ enum ieee80211_ampdu_mlme_action {
  *     negative error code (which will be seen in userspace.)
  *     Must be implemented and can sleep.
  *
+ * @change_interface: Called when a netdevice changes type. This callback
+ *     is optional, but only if it is supported can interface types be
+ *     switched while the interface is UP. The callback may sleep.
+ *     Note that while an interface is being switched, it will not be
+ *     found by the interface iteration callbacks.
+ *
  * @remove_interface: Notifies a driver that an interface is going down.
  *     The @stop callback is called after this if it is the last interface
  *     and no monitor interfaces are present.
@@ -1687,6 +1690,8 @@ enum ieee80211_ampdu_mlme_action {
  *     switch operation for CSAs received from the AP may implement this
  *     callback. They must then call ieee80211_chswitch_done() to indicate
  *     completion of the channel switch.
+ *
+ * @napi_poll: Poll Rx queue for incoming data frames.
  */
 struct ieee80211_ops {
        int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb);
@@ -1694,6 +1699,9 @@ struct ieee80211_ops {
        void (*stop)(struct ieee80211_hw *hw);
        int (*add_interface)(struct ieee80211_hw *hw,
                             struct ieee80211_vif *vif);
+       int (*change_interface)(struct ieee80211_hw *hw,
+                               struct ieee80211_vif *vif,
+                               enum nl80211_iftype new_type);
        void (*remove_interface)(struct ieee80211_hw *hw,
                                 struct ieee80211_vif *vif);
        int (*config)(struct ieee80211_hw *hw, u32 changed);
@@ -1752,6 +1760,7 @@ struct ieee80211_ops {
        void (*flush)(struct ieee80211_hw *hw, bool drop);
        void (*channel_switch)(struct ieee80211_hw *hw,
                               struct ieee80211_channel_switch *ch_switch);
+       int (*napi_poll)(struct ieee80211_hw *hw, int budget);
 };
 
 /**
@@ -1897,6 +1906,22 @@ void ieee80211_free_hw(struct ieee80211_hw *hw);
  */
 void ieee80211_restart_hw(struct ieee80211_hw *hw);
 
+/** ieee80211_napi_schedule - schedule NAPI poll
+ *
+ * Use this function to schedule NAPI polling on a device.
+ *
+ * @hw: the hardware to start polling
+ */
+void ieee80211_napi_schedule(struct ieee80211_hw *hw);
+
+/** ieee80211_napi_complete - complete NAPI polling
+ *
+ * Use this function to finish NAPI polling on a device.
+ *
+ * @hw: the hardware to stop polling
+ */
+void ieee80211_napi_complete(struct ieee80211_hw *hw);
+
 /**
  * ieee80211_rx - receive frame
  *
@@ -2252,7 +2277,8 @@ void ieee80211_wake_queues(struct ieee80211_hw *hw);
  *
  * When hardware scan offload is used (i.e. the hw_scan() callback is
  * assigned) this function needs to be called by the driver to notify
- * mac80211 that the scan finished.
+ * mac80211 that the scan finished. This function can be called from
+ * any context, including hardirq context.
  *
  * @hw: the hardware that finished the scan
  * @aborted: set to true if scan was aborted
@@ -2442,7 +2468,7 @@ void ieee80211_sta_block_awake(struct ieee80211_hw *hw,
  *
  * @vif: &struct ieee80211_vif pointer from the add_interface callback.
  *
- * When beacon filtering is enabled with %IEEE80211_HW_BEACON_FILTERING and
+ * When beacon filtering is enabled with %IEEE80211_HW_BEACON_FILTER and
  * %IEEE80211_CONF_PS is set, the driver needs to inform whenever the
  * hardware is not receiving beacons with this function.
  */
@@ -2453,7 +2479,7 @@ void ieee80211_beacon_loss(struct ieee80211_vif *vif);
  *
  * @vif: &struct ieee80211_vif pointer from the add_interface callback.
  *
- * When beacon filtering is enabled with %IEEE80211_HW_BEACON_FILTERING, and
+ * When beacon filtering is enabled with %IEEE80211_HW_BEACON_FILTER, and
  * %IEEE80211_CONF_PS and %IEEE80211_HW_CONNECTION_MONITOR are set, the driver
  * needs to inform if the connection to the AP has been lost.
  *
@@ -2518,6 +2544,18 @@ void ieee80211_cqm_rssi_notify(struct ieee80211_vif *vif,
  */
 void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success);
 
+/**
+ * ieee80211_request_smps - request SM PS transition
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback.
+ * @smps_mode: new SM PS mode
+ *
+ * This allows the driver to request an SM PS transition in managed
+ * mode. This is useful when the driver has more information than
+ * the stack about possible interference, for example by bluetooth.
+ */
+void ieee80211_request_smps(struct ieee80211_vif *vif,
+                           enum ieee80211_smps_mode smps_mode);
+
 /* Rate control API */
 
 /**
index 43c57502659b230c637d9c8d1e21aa986bde3de9..42ce6fe7a2d519c84c0f171cebaad87f537b23b9 100644 (file)
@@ -45,7 +45,10 @@ struct raw_iter_state {
        struct raw_hashinfo *h;
 };
 
-#define raw_seq_private(seq) ((struct raw_iter_state *)(seq)->private)
+static inline struct raw_iter_state *raw_seq_private(struct seq_file *seq)
+{
+       return seq->private;
+}
 void *raw_seq_start(struct seq_file *seq, loff_t *pos);
 void *raw_seq_next(struct seq_file *seq, void *v, loff_t *pos);
 void raw_seq_stop(struct seq_file *seq, void *v);
index 65946bc43d00876e4c90165627cb46ee68f4d8e0..2cb3980b1616fce18c10c6762747539521edf24b 100644 (file)
@@ -275,24 +275,35 @@ struct sctp_mib {
 /* Print debugging messages.  */
 #if SCTP_DEBUG
 extern int sctp_debug_flag;
-#define SCTP_DEBUG_PRINTK(whatever...) \
-       ((void) (sctp_debug_flag && printk(KERN_DEBUG whatever)))
-#define SCTP_DEBUG_PRINTK_IPADDR(lead, trail, leadparm, saddr, otherparms...) \
-       if (sctp_debug_flag) { \
-               if (saddr->sa.sa_family == AF_INET6) { \
-                       printk(KERN_DEBUG \
-                              lead "%pI6" trail, \
-                              leadparm, \
-                              &saddr->v6.sin6_addr, \
-                              otherparms); \
-               } else { \
-                       printk(KERN_DEBUG \
-                              lead "%pI4" trail, \
-                              leadparm, \
-                              &saddr->v4.sin_addr.s_addr, \
-                              otherparms); \
-               } \
-       }
+#define SCTP_DEBUG_PRINTK(fmt, args...)                        \
+do {                                                   \
+       if (sctp_debug_flag)                            \
+               printk(KERN_DEBUG pr_fmt(fmt), ##args); \
+} while (0)
+#define SCTP_DEBUG_PRINTK_CONT(fmt, args...)           \
+do {                                                   \
+       if (sctp_debug_flag)                            \
+               pr_cont(fmt, ##args);                   \
+} while (0)
+#define SCTP_DEBUG_PRINTK_IPADDR(fmt_lead, fmt_trail,                  \
+                                args_lead, saddr, args_trail...)       \
+do {                                                                   \
+       if (sctp_debug_flag) {                                          \
+               if (saddr->sa.sa_family == AF_INET6) {                  \
+                       printk(KERN_DEBUG                               \
+                              pr_fmt(fmt_lead "%pI6" fmt_trail),       \
+                              args_lead,                               \
+                              &saddr->v6.sin6_addr,                    \
+                              args_trail);                             \
+               } else {                                                \
+                       printk(KERN_DEBUG                               \
+                              pr_fmt(fmt_lead "%pI4" fmt_trail),       \
+                              args_lead,                               \
+                              &saddr->v4.sin_addr.s_addr,              \
+                              args_trail);                             \
+               }                                                       \
+       }                                                               \
+} while (0)
 #define SCTP_ENABLE_DEBUG { sctp_debug_flag = 1; }
 #define SCTP_DISABLE_DEBUG { sctp_debug_flag = 0; }
 
@@ -306,6 +317,7 @@ extern int sctp_debug_flag;
 #else  /* SCTP_DEBUG */
 
 #define SCTP_DEBUG_PRINTK(whatever...)
+#define SCTP_DEBUG_PRINTK_CONT(fmt, args...)
 #define SCTP_DEBUG_PRINTK_IPADDR(whatever...)
 #define SCTP_ENABLE_DEBUG
 #define SCTP_DISABLE_DEBUG
index adab9dc5818355c603a699101c4787c99434eb12..8ae97c4970df142cc17b9653b9ee4fb18a573e75 100644 (file)
@@ -1670,17 +1670,13 @@ static inline void sock_recv_ts_and_drops(struct msghdr *msg, struct sock *sk,
 
 /**
  * sock_tx_timestamp - checks whether the outgoing packet is to be time stamped
- * @msg:       outgoing packet
  * @sk:                socket sending this packet
- * @shtx:      filled with instructions for time stamping
+ * @tx_flags:  filled with instructions for time stamping
  *
  * Currently only depends on SOCK_TIMESTAMPING* flags. Returns error code if
  * parameters are invalid.
  */
-extern int sock_tx_timestamp(struct msghdr *msg,
-                            struct sock *sk,
-                            union skb_shared_tx *shtx);
-
+extern int sock_tx_timestamp(struct sock *sk, __u8 *tx_flags);
 
 /**
  * sk_eat_skb - Release a skb if it is no longer needed
diff --git a/include/net/tc_act/tc_csum.h b/include/net/tc_act/tc_csum.h
new file mode 100644 (file)
index 0000000..9e8710b
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef __NET_TC_CSUM_H
+#define __NET_TC_CSUM_H
+
+#include <linux/types.h>
+#include <net/act_api.h>
+
+struct tcf_csum {
+       struct tcf_common common;
+
+       u32 update_flags;
+};
+#define to_tcf_csum(pc) \
+       container_of(pc,struct tcf_csum,common)
+
+#endif /* __NET_TC_CSUM_H */
index eaa9582779d029a9362c32b3816fed8c157e4d3e..bfc1da43295c578d908b26ed852938bd522c8f04 100644 (file)
@@ -789,6 +789,15 @@ static inline __u32 tcp_current_ssthresh(const struct sock *sk)
 /* Use define here intentionally to get WARN_ON location shown at the caller */
 #define tcp_verify_left_out(tp)        WARN_ON(tcp_left_out(tp) > tp->packets_out)
 
+/*
+ * Convert RFC 3390 larger initial window into an equivalent number of packets.
+ * This is based on the numbers specified in RFC 5681, 3.1.
+ */
+static inline u32 rfc3390_bytes_to_packets(const u32 smss)
+{
+       return smss <= 1095 ? 4 : (smss > 2190 ? 2 : 3);
+}
+
 extern void tcp_enter_cwr(struct sock *sk, const int set_ssthresh);
 extern __u32 tcp_init_cwnd(struct tcp_sock *tp, struct dst_entry *dst);
 
index 01ddb0472f86c511f49ff8a602a726dd60550ff0..889f4ac4459abcf477210297b6572dc71cf25ca5 100644 (file)
@@ -35,12 +35,12 @@ drop:
 }
 EXPORT_SYMBOL(__vlan_hwaccel_rx);
 
-int vlan_hwaccel_do_receive(struct sk_buff *skb)
+void vlan_hwaccel_do_receive(struct sk_buff *skb)
 {
        struct net_device *dev = skb->dev;
        struct vlan_rx_stats     *rx_stats;
 
-       skb->dev = vlan_dev_info(dev)->real_dev;
+       skb->dev = vlan_dev_real_dev(dev);
        netif_nit_deliver(skb);
 
        skb->dev = dev;
@@ -69,7 +69,6 @@ int vlan_hwaccel_do_receive(struct sk_buff *skb)
                break;
        }
        u64_stats_update_end(&rx_stats->syncp);
-       return 0;
 }
 
 struct net_device *vlan_dev_real_dev(const struct net_device *dev)
@@ -106,9 +105,12 @@ vlan_gro_common(struct napi_struct *napi, struct vlan_group *grp,
                goto drop;
 
        for (p = napi->gro_list; p; p = p->next) {
-               NAPI_GRO_CB(p)->same_flow =
-                       p->dev == skb->dev && !compare_ether_header(
-                               skb_mac_header(p), skb_gro_mac_header(skb));
+               unsigned long diffs;
+
+               diffs = (unsigned long)p->dev ^ (unsigned long)skb->dev;
+               diffs |= compare_ether_header(skb_mac_header(p),
+                                             skb_gro_mac_header(skb));
+               NAPI_GRO_CB(p)->same_flow = !diffs;
                NAPI_GRO_CB(p)->flush = 0;
        }
 
index c85109d809caa4767ef2576c1947fcd877e432b7..078eb162d9bfc4e7d6c05cd5b59c6b8920fec31e 100644 (file)
@@ -222,7 +222,7 @@ static void p9_conn_cancel(struct p9_conn *m, int err)
        }
 }
 
-static unsigned int
+static int
 p9_fd_poll(struct p9_client *client, struct poll_table_struct *pt)
 {
        int ret, n;
index 940404a73b3dddf05e262a7c5c727784c1a65bf3..1b9c52a02cd31995c63040377d4e24443bad85a3 100644 (file)
@@ -792,7 +792,7 @@ int vcc_getsockopt(struct socket *sock, int level, int optname,
        default:
                if (level == SOL_SOCKET)
                        return -EINVAL;
-                       break;
+               break;
        }
        if (!vcc->dev || !vcc->dev->ops->getsockopt)
                return -EINVAL;
index d98bde1a0ac8ffafb95ef961382a51e2d2c179cb..181d70c73d708bd730f49e4b61f88ac72e373a20 100644 (file)
@@ -220,7 +220,6 @@ static unsigned char *get_tr_dst(unsigned char *packet, unsigned char *rdesc)
 static int lec_open(struct net_device *dev)
 {
        netif_start_queue(dev);
-       memset(&dev->stats, 0, sizeof(struct net_device_stats));
 
        return 0;
 }
index cfdfd7e2a1726b1399633bdcb6625a6a5731a310..26eaebf4aaa9b11c3b9d8820b835ae07c50219e2 100644 (file)
@@ -1103,7 +1103,7 @@ done:
 out:
        release_sock(sk);
 
-       return 0;
+       return err;
 }
 
 /*
index 7805945a5fd6d311f54f26a66dc5ad9c0e83ece1..a1690845dc6ecf9ecb12de37ac2b9342d678de01 100644 (file)
@@ -412,7 +412,7 @@ int ax25_rt_autobind(ax25_cb *ax25, ax25_address *addr)
 {
        ax25_uid_assoc *user;
        ax25_route *ax25_rt;
-       int err;
+       int err = 0;
 
        if ((ax25_rt = ax25_get_route(addr, NULL)) == NULL)
                return -EHOSTUNREACH;
@@ -453,7 +453,7 @@ int ax25_rt_autobind(ax25_cb *ax25, ax25_address *addr)
 put:
        ax25_put_route(ax25_rt);
 
-       return 0;
+       return err;
 }
 
 struct sk_buff *ax25_rt_build_path(struct sk_buff *skb, ax25_address *src,
index 421c45bd1b95232e0a4ac7a282fdaeabd18fb21d..ed0f22f57668883130d7ac6de37de3b5b7f457b5 100644 (file)
@@ -297,13 +297,12 @@ unsigned int bt_sock_poll(struct file * file, struct socket *sock, poll_table *w
                mask |= POLLERR;
 
        if (sk->sk_shutdown & RCV_SHUTDOWN)
-               mask |= POLLRDHUP;
+               mask |= POLLRDHUP | POLLIN | POLLRDNORM;
 
        if (sk->sk_shutdown == SHUTDOWN_MASK)
                mask |= POLLHUP;
 
-       if (!skb_queue_empty(&sk->sk_receive_queue) ||
-                       (sk->sk_shutdown & RCV_SHUTDOWN))
+       if (!skb_queue_empty(&sk->sk_receive_queue))
                mask |= POLLIN | POLLRDNORM;
 
        if (sk->sk_state == BT_CLOSED)
index c03d2c3ff03ed6cb99dc05d7a4cde5033d951190..89ad25a76202924eadf9bce8aadf761dcea3e8d5 100644 (file)
@@ -61,30 +61,27 @@ static int port_cost(struct net_device *dev)
 }
 
 
-/*
- * Check for port carrier transistions.
- * Called from work queue to allow for calling functions that
- * might sleep (such as speed check), and to debounce.
- */
+/* Check for port carrier transistions. */
 void br_port_carrier_check(struct net_bridge_port *p)
 {
        struct net_device *dev = p->dev;
        struct net_bridge *br = p->br;
 
-       if (netif_carrier_ok(dev))
+       if (netif_running(dev) && netif_carrier_ok(dev))
                p->path_cost = port_cost(dev);
 
-       if (netif_running(br->dev)) {
-               spin_lock_bh(&br->lock);
-               if (netif_carrier_ok(dev)) {
-                       if (p->state == BR_STATE_DISABLED)
-                               br_stp_enable_port(p);
-               } else {
-                       if (p->state != BR_STATE_DISABLED)
-                               br_stp_disable_port(p);
-               }
-               spin_unlock_bh(&br->lock);
+       if (!netif_running(br->dev))
+               return;
+
+       spin_lock_bh(&br->lock);
+       if (netif_running(dev) && netif_carrier_ok(dev)) {
+               if (p->state == BR_STATE_DISABLED)
+                       br_stp_enable_port(p);
+       } else {
+               if (p->state != BR_STATE_DISABLED)
+                       br_stp_disable_port(p);
        }
+       spin_unlock_bh(&br->lock);
 }
 
 static void release_nbp(struct kobject *kobj)
index 826cd5221536cadd3b0d13dfec2e9d3639b92a93..6d04cfdf45413257d3055f876632be64ed3abbd7 100644 (file)
@@ -141,7 +141,7 @@ struct sk_buff *br_handle_frame(struct sk_buff *skb)
        const unsigned char *dest = eth_hdr(skb)->h_dest;
        int (*rhook)(struct sk_buff *skb);
 
-       if (skb->pkt_type == PACKET_LOOPBACK)
+       if (unlikely(skb->pkt_type == PACKET_LOOPBACK))
                return skb;
 
        if (!is_valid_ether_addr(eth_hdr(skb)->h_source))
index 0b586e9d1378fb209e2f377354938788abfd1ad8..0fd01dd17c48c86339db4565a3b5b8c39a436b93 100644 (file)
@@ -9,6 +9,8 @@
  *  and Sakari Ailus <sakari.ailus@nokia.com>
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
+
 #include <linux/version.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -214,7 +216,7 @@ static int caif_device_notify(struct notifier_block *me, unsigned long what,
 
        switch (what) {
        case NETDEV_REGISTER:
-               pr_info("CAIF: %s():register %s\n", __func__, dev->name);
+               netdev_info(dev, "register\n");
                caifd = caif_device_alloc(dev);
                if (caifd == NULL)
                        break;
@@ -225,14 +227,13 @@ static int caif_device_notify(struct notifier_block *me, unsigned long what,
                break;
 
        case NETDEV_UP:
-               pr_info("CAIF: %s(): up %s\n", __func__, dev->name);
+               netdev_info(dev, "up\n");
                caifd = caif_get(dev);
                if (caifd == NULL)
                        break;
                caifdev = netdev_priv(dev);
                if (atomic_read(&caifd->state) == NETDEV_UP) {
-                       pr_info("CAIF: %s():%s already up\n",
-                               __func__, dev->name);
+                       netdev_info(dev, "already up\n");
                        break;
                }
                atomic_set(&caifd->state, what);
@@ -273,7 +274,7 @@ static int caif_device_notify(struct notifier_block *me, unsigned long what,
                caifd = caif_get(dev);
                if (caifd == NULL)
                        break;
-               pr_info("CAIF: %s():going down %s\n", __func__, dev->name);
+               netdev_info(dev, "going down\n");
 
                if (atomic_read(&caifd->state) == NETDEV_GOING_DOWN ||
                        atomic_read(&caifd->state) == NETDEV_DOWN)
@@ -295,11 +296,10 @@ static int caif_device_notify(struct notifier_block *me, unsigned long what,
                caifd = caif_get(dev);
                if (caifd == NULL)
                        break;
-               pr_info("CAIF: %s(): down %s\n", __func__, dev->name);
+               netdev_info(dev, "down\n");
                if (atomic_read(&caifd->in_use))
-                       pr_warning("CAIF: %s(): "
-                                  "Unregistering an active CAIF device: %s\n",
-                                  __func__, dev->name);
+                       netdev_warn(dev,
+                                   "Unregistering an active CAIF device\n");
                cfcnfg_del_phy_layer(get_caif_conf(), &caifd->layer);
                dev_put(dev);
                atomic_set(&caifd->state, what);
@@ -307,7 +307,7 @@ static int caif_device_notify(struct notifier_block *me, unsigned long what,
 
        case NETDEV_UNREGISTER:
                caifd = caif_get(dev);
-               pr_info("CAIF: %s(): unregister %s\n", __func__, dev->name);
+               netdev_info(dev, "unregister\n");
                atomic_set(&caifd->state, what);
                caif_device_destroy(dev);
                break;
@@ -391,7 +391,7 @@ static int __init caif_device_init(void)
        int result;
        cfg = cfcnfg_create();
        if (!cfg) {
-               pr_warning("CAIF: %s(): can't create cfcnfg.\n", __func__);
+               pr_warn("can't create cfcnfg\n");
                goto err_cfcnfg_create_failed;
        }
        result = register_pernet_device(&caif_net_ops);
index 8ce9047861166740a17a2448cb1d4f668fba1d21..fd1f5df0827c782a45c873691e6411da4240a446 100644 (file)
@@ -4,6 +4,8 @@
  * License terms: GNU General Public License (GPL) version 2
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
+
 #include <linux/fs.h>
 #include <linux/init.h>
 #include <linux/module.h>
@@ -157,8 +159,8 @@ static int caif_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
 
        if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >=
                (unsigned)sk->sk_rcvbuf && rx_flow_is_on(cf_sk)) {
-               trace_printk("CAIF: %s():"
-                       " sending flow OFF (queue len = %d %d)\n",
+               trace_printk("CAIF: %s(): "
+                       "sending flow OFF (queue len = %d %d)\n",
                        __func__,
                        atomic_read(&cf_sk->sk.sk_rmem_alloc),
                        sk_rcvbuf_lowwater(cf_sk));
@@ -172,8 +174,8 @@ static int caif_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
                return err;
        if (!sk_rmem_schedule(sk, skb->truesize) && rx_flow_is_on(cf_sk)) {
                set_rx_flow_off(cf_sk);
-               trace_printk("CAIF: %s():"
-                       " sending flow OFF due to rmem_schedule\n",
+               trace_printk("CAIF: %s(): "
+                       "sending flow OFF due to rmem_schedule\n",
                        __func__);
                dbfs_atomic_inc(&cnt.num_rx_flow_off);
                caif_flow_ctrl(sk, CAIF_MODEMCMD_FLOW_OFF_REQ);
@@ -275,8 +277,7 @@ static void caif_ctrl_cb(struct cflayer *layr,
                break;
 
        default:
-               pr_debug("CAIF: %s(): Unexpected flow command %d\n",
-                               __func__, flow);
+               pr_debug("Unexpected flow command %d\n", flow);
        }
 }
 
@@ -536,8 +537,7 @@ static int transmit_skb(struct sk_buff *skb, struct caifsock *cf_sk,
 
                /* Slight paranoia, probably not needed. */
                if (unlikely(loopcnt++ > 1000)) {
-                       pr_warning("CAIF: %s(): transmit retries failed,"
-                               " error = %d\n", __func__, ret);
+                       pr_warn("transmit retries failed, error = %d\n", ret);
                        break;
                }
 
@@ -902,8 +902,7 @@ static int caif_connect(struct socket *sock, struct sockaddr *uaddr,
        cf_sk->maxframe = dev->mtu - (headroom + tailroom);
        dev_put(dev);
        if (cf_sk->maxframe < 1) {
-               pr_warning("CAIF: %s(): CAIF Interface MTU too small (%d)\n",
-                       __func__, dev->mtu);
+               pr_warn("CAIF Interface MTU too small (%d)\n", dev->mtu);
                err = -ENODEV;
                goto out;
        }
index 1c29189b344daa1d885b56f09a9d72871129b7ab..ef93a131310b32096788fe2cee2b7ec4d7d753a5 100644 (file)
@@ -3,6 +3,9 @@
  * Author:     Sjur Brendeland/sjur.brandeland@stericsson.com
  * License terms: GNU General Public License (GPL) version 2
  */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
+
 #include <linux/kernel.h>
 #include <linux/stddef.h>
 #include <linux/slab.h>
@@ -78,7 +81,7 @@ struct cfcnfg *cfcnfg_create(void)
        /* Initiate this layer */
        this = kzalloc(sizeof(struct cfcnfg), GFP_ATOMIC);
        if (!this) {
-               pr_warning("CAIF: %s(): Out of memory\n", __func__);
+               pr_warn("Out of memory\n");
                return NULL;
        }
        this->mux = cfmuxl_create();
@@ -106,7 +109,7 @@ struct cfcnfg *cfcnfg_create(void)
        layer_set_up(this->ctrl, this);
        return this;
 out_of_mem:
-       pr_warning("CAIF: %s(): Out of memory\n", __func__);
+       pr_warn("Out of memory\n");
        kfree(this->mux);
        kfree(this->ctrl);
        kfree(this);
@@ -194,7 +197,7 @@ int cfcnfg_disconn_adapt_layer(struct cfcnfg *cnfg, struct cflayer *adap_layer)
        caif_assert(adap_layer != NULL);
        channel_id = adap_layer->id;
        if (adap_layer->dn == NULL || channel_id == 0) {
-               pr_err("CAIF: %s():adap_layer->id is 0\n", __func__);
+               pr_err("adap_layer->id is 0\n");
                ret = -ENOTCONN;
                goto end;
        }
@@ -204,9 +207,8 @@ int cfcnfg_disconn_adapt_layer(struct cfcnfg *cnfg, struct cflayer *adap_layer)
        layer_set_up(servl, NULL);
        ret = cfctrl_linkdown_req(cnfg->ctrl, channel_id, adap_layer);
        if (servl == NULL) {
-               pr_err("CAIF: %s(): PROTOCOL ERROR "
-                      "- Error removing service_layer Channel_Id(%d)",
-                       __func__, channel_id);
+               pr_err("PROTOCOL ERROR - Error removing service_layer Channel_Id(%d)",
+                      channel_id);
                ret = -EINVAL;
                goto end;
        }
@@ -216,18 +218,14 @@ int cfcnfg_disconn_adapt_layer(struct cfcnfg *cnfg, struct cflayer *adap_layer)
 
                phyinfo = cfcnfg_get_phyinfo(cnfg, phyid);
                if (phyinfo == NULL) {
-                       pr_warning("CAIF: %s(): "
-                               "No interface to send disconnect to\n",
-                               __func__);
+                       pr_warn("No interface to send disconnect to\n");
                        ret = -ENODEV;
                        goto end;
                }
                if (phyinfo->id != phyid ||
                        phyinfo->phy_layer->id != phyid ||
                        phyinfo->frm_layer->id != phyid) {
-                       pr_err("CAIF: %s(): "
-                               "Inconsistency in phy registration\n",
-                               __func__);
+                       pr_err("Inconsistency in phy registration\n");
                        ret = -EINVAL;
                        goto end;
                }
@@ -276,21 +274,20 @@ int cfcnfg_add_adaptation_layer(struct cfcnfg *cnfg,
 {
        struct cflayer *frml;
        if (adap_layer == NULL) {
-               pr_err("CAIF: %s(): adap_layer is zero", __func__);
+               pr_err("adap_layer is zero\n");
                return -EINVAL;
        }
        if (adap_layer->receive == NULL) {
-               pr_err("CAIF: %s(): adap_layer->receive is NULL", __func__);
+               pr_err("adap_layer->receive is NULL\n");
                return -EINVAL;
        }
        if (adap_layer->ctrlcmd == NULL) {
-               pr_err("CAIF: %s(): adap_layer->ctrlcmd == NULL", __func__);
+               pr_err("adap_layer->ctrlcmd == NULL\n");
                return -EINVAL;
        }
        frml = cnfg->phy_layers[param->phyid].frm_layer;
        if (frml == NULL) {
-               pr_err("CAIF: %s(): Specified PHY type does not exist!",
-                       __func__);
+               pr_err("Specified PHY type does not exist!\n");
                return -ENODEV;
        }
        caif_assert(param->phyid == cnfg->phy_layers[param->phyid].id);
@@ -330,9 +327,7 @@ cfcnfg_linkup_rsp(struct cflayer *layer, u8 channel_id, enum cfctrl_srv serv,
        struct net_device *netdev;
 
        if (adapt_layer == NULL) {
-               pr_debug("CAIF: %s(): link setup response "
-                               "but no client exist, send linkdown back\n",
-                               __func__);
+               pr_debug("link setup response but no client exist, send linkdown back\n");
                cfctrl_linkdown_req(cnfg->ctrl, channel_id, NULL);
                return;
        }
@@ -374,13 +369,11 @@ cfcnfg_linkup_rsp(struct cflayer *layer, u8 channel_id, enum cfctrl_srv serv,
                servicel = cfdbgl_create(channel_id, &phyinfo->dev_info);
                break;
        default:
-               pr_err("CAIF: %s(): Protocol error. "
-                       "Link setup response - unknown channel type\n",
-                       __func__);
+               pr_err("Protocol error. Link setup response - unknown channel type\n");
                return;
        }
        if (!servicel) {
-               pr_warning("CAIF: %s(): Out of memory\n", __func__);
+               pr_warn("Out of memory\n");
                return;
        }
        layer_set_dn(servicel, cnfg->mux);
@@ -418,7 +411,7 @@ cfcnfg_add_phy_layer(struct cfcnfg *cnfg, enum cfcnfg_phy_type phy_type,
                }
        }
        if (*phyid == 0) {
-               pr_err("CAIF: %s(): No Available PHY ID\n", __func__);
+               pr_err("No Available PHY ID\n");
                return;
        }
 
@@ -427,7 +420,7 @@ cfcnfg_add_phy_layer(struct cfcnfg *cnfg, enum cfcnfg_phy_type phy_type,
                phy_driver =
                    cfserl_create(CFPHYTYPE_FRAG, *phyid, stx);
                if (!phy_driver) {
-                       pr_warning("CAIF: %s(): Out of memory\n", __func__);
+                       pr_warn("Out of memory\n");
                        return;
                }
 
@@ -436,7 +429,7 @@ cfcnfg_add_phy_layer(struct cfcnfg *cnfg, enum cfcnfg_phy_type phy_type,
                phy_driver = NULL;
                break;
        default:
-               pr_err("CAIF: %s(): %d", __func__, phy_type);
+               pr_err("%d\n", phy_type);
                return;
                break;
        }
@@ -455,7 +448,7 @@ cfcnfg_add_phy_layer(struct cfcnfg *cnfg, enum cfcnfg_phy_type phy_type,
        phy_layer->type = phy_type;
        frml = cffrml_create(*phyid, fcs);
        if (!frml) {
-               pr_warning("CAIF: %s(): Out of memory\n", __func__);
+               pr_warn("Out of memory\n");
                return;
        }
        cnfg->phy_layers[*phyid].frm_layer = frml;
index 563145fdc4c368de2c50c8d9d3510742a7d2e658..08f267a109aa3c677efc4a6795ccfea31fc8d581 100644 (file)
@@ -4,6 +4,8 @@
  * License terms: GNU General Public License (GPL) version 2
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
+
 #include <linux/stddef.h>
 #include <linux/spinlock.h>
 #include <linux/slab.h>
@@ -36,7 +38,7 @@ struct cflayer *cfctrl_create(void)
        struct cfctrl *this =
                kmalloc(sizeof(struct cfctrl), GFP_ATOMIC);
        if (!this) {
-               pr_warning("CAIF: %s(): Out of memory\n", __func__);
+               pr_warn("Out of memory\n");
                return NULL;
        }
        caif_assert(offsetof(struct cfctrl, serv.layer) == 0);
@@ -132,9 +134,7 @@ struct cfctrl_request_info *cfctrl_remove_req(struct cfctrl *ctrl,
        list_for_each_entry_safe(p, tmp, &ctrl->list, list) {
                if (cfctrl_req_eq(req, p)) {
                        if (p != first)
-                               pr_warning("CAIF: %s(): Requests are not "
-                                       "received in order\n",
-                                       __func__);
+                               pr_warn("Requests are not received in order\n");
 
                        atomic_set(&ctrl->rsp_seq_no,
                                         p->sequence_no);
@@ -177,7 +177,7 @@ void cfctrl_enum_req(struct cflayer *layer, u8 physlinkid)
        int ret;
        struct cfpkt *pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN);
        if (!pkt) {
-               pr_warning("CAIF: %s(): Out of memory\n", __func__);
+               pr_warn("Out of memory\n");
                return;
        }
        caif_assert(offsetof(struct cfctrl, serv.layer) == 0);
@@ -189,8 +189,7 @@ void cfctrl_enum_req(struct cflayer *layer, u8 physlinkid)
        ret =
            cfctrl->serv.layer.dn->transmit(cfctrl->serv.layer.dn, pkt);
        if (ret < 0) {
-               pr_err("CAIF: %s(): Could not transmit enum message\n",
-                       __func__);
+               pr_err("Could not transmit enum message\n");
                cfpkt_destroy(pkt);
        }
 }
@@ -208,7 +207,7 @@ int cfctrl_linkup_request(struct cflayer *layer,
        char utility_name[16];
        struct cfpkt *pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN);
        if (!pkt) {
-               pr_warning("CAIF: %s(): Out of memory\n", __func__);
+               pr_warn("Out of memory\n");
                return -ENOMEM;
        }
        cfpkt_addbdy(pkt, CFCTRL_CMD_LINK_SETUP);
@@ -253,13 +252,13 @@ int cfctrl_linkup_request(struct cflayer *layer,
                               param->u.utility.paramlen);
                break;
        default:
-               pr_warning("CAIF: %s():Request setup of bad link type = %d\n",
-                          __func__, param->linktype);
+               pr_warn("Request setup of bad link type = %d\n",
+                       param->linktype);
                return -EINVAL;
        }
        req = kzalloc(sizeof(*req), GFP_KERNEL);
        if (!req) {
-               pr_warning("CAIF: %s(): Out of memory\n", __func__);
+               pr_warn("Out of memory\n");
                return -ENOMEM;
        }
        req->client_layer = user_layer;
@@ -276,8 +275,7 @@ int cfctrl_linkup_request(struct cflayer *layer,
        ret =
            cfctrl->serv.layer.dn->transmit(cfctrl->serv.layer.dn, pkt);
        if (ret < 0) {
-               pr_err("CAIF: %s(): Could not transmit linksetup request\n",
-                       __func__);
+               pr_err("Could not transmit linksetup request\n");
                cfpkt_destroy(pkt);
                return -ENODEV;
        }
@@ -291,7 +289,7 @@ int cfctrl_linkdown_req(struct cflayer *layer, u8 channelid,
        struct cfctrl *cfctrl = container_obj(layer);
        struct cfpkt *pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN);
        if (!pkt) {
-               pr_warning("CAIF: %s(): Out of memory\n", __func__);
+               pr_warn("Out of memory\n");
                return -ENOMEM;
        }
        cfpkt_addbdy(pkt, CFCTRL_CMD_LINK_DESTROY);
@@ -300,8 +298,7 @@ int cfctrl_linkdown_req(struct cflayer *layer, u8 channelid,
        ret =
            cfctrl->serv.layer.dn->transmit(cfctrl->serv.layer.dn, pkt);
        if (ret < 0) {
-               pr_err("CAIF: %s(): Could not transmit link-down request\n",
-                       __func__);
+               pr_err("Could not transmit link-down request\n");
                cfpkt_destroy(pkt);
        }
        return ret;
@@ -313,7 +310,7 @@ void cfctrl_sleep_req(struct cflayer *layer)
        struct cfctrl *cfctrl = container_obj(layer);
        struct cfpkt *pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN);
        if (!pkt) {
-               pr_warning("CAIF: %s(): Out of memory\n", __func__);
+               pr_warn("Out of memory\n");
                return;
        }
        cfpkt_addbdy(pkt, CFCTRL_CMD_SLEEP);
@@ -330,7 +327,7 @@ void cfctrl_wake_req(struct cflayer *layer)
        struct cfctrl *cfctrl = container_obj(layer);
        struct cfpkt *pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN);
        if (!pkt) {
-               pr_warning("CAIF: %s(): Out of memory\n", __func__);
+               pr_warn("Out of memory\n");
                return;
        }
        cfpkt_addbdy(pkt, CFCTRL_CMD_WAKE);
@@ -347,7 +344,7 @@ void cfctrl_getstartreason_req(struct cflayer *layer)
        struct cfctrl *cfctrl = container_obj(layer);
        struct cfpkt *pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN);
        if (!pkt) {
-               pr_warning("CAIF: %s(): Out of memory\n", __func__);
+               pr_warn("Out of memory\n");
                return;
        }
        cfpkt_addbdy(pkt, CFCTRL_CMD_START_REASON);
@@ -364,12 +361,11 @@ void cfctrl_cancel_req(struct cflayer *layr, struct cflayer *adap_layer)
        struct cfctrl_request_info *p, *tmp;
        struct cfctrl *ctrl = container_obj(layr);
        spin_lock(&ctrl->info_list_lock);
-       pr_warning("CAIF: %s(): enter\n", __func__);
+       pr_warn("enter\n");
 
        list_for_each_entry_safe(p, tmp, &ctrl->list, list) {
                if (p->client_layer == adap_layer) {
-                       pr_warning("CAIF: %s(): cancel req :%d\n", __func__,
-                                       p->sequence_no);
+                       pr_warn("cancel req :%d\n", p->sequence_no);
                        list_del(&p->list);
                        kfree(p);
                }
@@ -520,9 +516,8 @@ static int cfctrl_recv(struct cflayer *layer, struct cfpkt *pkt)
                                cfpkt_extr_head(pkt, &param, len);
                                break;
                        default:
-                               pr_warning("CAIF: %s(): Request setup "
-                                          "- invalid link type (%d)",
-                                          __func__, serv);
+                               pr_warn("Request setup - invalid link type (%d)\n",
+                                       serv);
                                goto error;
                        }
 
@@ -532,9 +527,7 @@ static int cfctrl_recv(struct cflayer *layer, struct cfpkt *pkt)
 
                        if (CFCTRL_ERR_BIT == (CFCTRL_ERR_BIT & cmdrsp) ||
                                cfpkt_erroneous(pkt)) {
-                               pr_err("CAIF: %s(): Invalid O/E bit or parse "
-                                      "error on CAIF control channel",
-                                       __func__);
+                               pr_err("Invalid O/E bit or parse error on CAIF control channel\n");
                                cfctrl->res.reject_rsp(cfctrl->serv.layer.up,
                                                       0,
                                                       req ? req->client_layer
@@ -556,8 +549,7 @@ static int cfctrl_recv(struct cflayer *layer, struct cfpkt *pkt)
                cfctrl->res.linkdestroy_rsp(cfctrl->serv.layer.up, linkid);
                break;
        case CFCTRL_CMD_LINK_ERR:
-               pr_err("CAIF: %s(): Frame Error Indication received\n",
-                       __func__);
+               pr_err("Frame Error Indication received\n");
                cfctrl->res.linkerror_ind();
                break;
        case CFCTRL_CMD_ENUM:
@@ -576,7 +568,7 @@ static int cfctrl_recv(struct cflayer *layer, struct cfpkt *pkt)
                cfctrl->res.radioset_rsp();
                break;
        default:
-               pr_err("CAIF: %s(): Unrecognized Control Frame\n", __func__);
+               pr_err("Unrecognized Control Frame\n");
                goto error;
                break;
        }
@@ -595,8 +587,7 @@ static void cfctrl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl,
        case CAIF_CTRLCMD_FLOW_OFF_IND:
                spin_lock(&this->info_list_lock);
                if (!list_empty(&this->list)) {
-                       pr_debug("CAIF: %s(): Received flow off in "
-                                  "control layer", __func__);
+                       pr_debug("Received flow off in control layer\n");
                }
                spin_unlock(&this->info_list_lock);
                break;
@@ -620,7 +611,7 @@ static int handle_loop(struct cfctrl *ctrl, int cmd, struct cfpkt *pkt)
                        if (!ctrl->loop_linkused[linkid])
                                goto found;
                spin_unlock(&ctrl->loop_linkid_lock);
-               pr_err("CAIF: %s(): Out of link-ids\n", __func__);
+               pr_err("Out of link-ids\n");
                return -EINVAL;
 found:
                if (!ctrl->loop_linkused[linkid])
index 676648cac8ddf3aa77f8659187b6aab8738388a0..496fda9ac66f56bee42568e8c0386566c3208be4 100644 (file)
@@ -4,6 +4,8 @@
  * License terms: GNU General Public License (GPL) version 2
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
+
 #include <linux/stddef.h>
 #include <linux/slab.h>
 #include <net/caif/caif_layer.h>
@@ -17,7 +19,7 @@ struct cflayer *cfdbgl_create(u8 channel_id, struct dev_info *dev_info)
 {
        struct cfsrvl *dbg = kmalloc(sizeof(struct cfsrvl), GFP_ATOMIC);
        if (!dbg) {
-               pr_warning("CAIF: %s(): Out of memory\n", __func__);
+               pr_warn("Out of memory\n");
                return NULL;
        }
        caif_assert(offsetof(struct cfsrvl, layer) == 0);
index ed9d53aff28053e5dd98bbaf9eb1ad8d3bb6b591..d3ed264ad6c42b932d84a721b270f88d0d6b574b 100644 (file)
@@ -4,6 +4,8 @@
  * License terms: GNU General Public License (GPL) version 2
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
+
 #include <linux/stddef.h>
 #include <linux/spinlock.h>
 #include <linux/slab.h>
@@ -26,7 +28,7 @@ struct cflayer *cfdgml_create(u8 channel_id, struct dev_info *dev_info)
 {
        struct cfsrvl *dgm = kmalloc(sizeof(struct cfsrvl), GFP_ATOMIC);
        if (!dgm) {
-               pr_warning("CAIF: %s(): Out of memory\n", __func__);
+               pr_warn("Out of memory\n");
                return NULL;
        }
        caif_assert(offsetof(struct cfsrvl, layer) == 0);
@@ -49,14 +51,14 @@ static int cfdgml_receive(struct cflayer *layr, struct cfpkt *pkt)
        caif_assert(layr->ctrlcmd != NULL);
 
        if (cfpkt_extr_head(pkt, &cmd, 1) < 0) {
-               pr_err("CAIF: %s(): Packet is erroneous!\n", __func__);
+               pr_err("Packet is erroneous!\n");
                cfpkt_destroy(pkt);
                return -EPROTO;
        }
 
        if ((cmd & DGM_CMD_BIT) == 0) {
                if (cfpkt_extr_head(pkt, &dgmhdr, 3) < 0) {
-                       pr_err("CAIF: %s(): Packet is erroneous!\n", __func__);
+                       pr_err("Packet is erroneous!\n");
                        cfpkt_destroy(pkt);
                        return -EPROTO;
                }
@@ -75,8 +77,7 @@ static int cfdgml_receive(struct cflayer *layr, struct cfpkt *pkt)
                return 0;
        default:
                cfpkt_destroy(pkt);
-               pr_info("CAIF: %s(): Unknown datagram control %d (0x%x)\n",
-                       __func__, cmd, cmd);
+               pr_info("Unknown datagram control %d (0x%x)\n", cmd, cmd);
                return -EPROTO;
        }
 }
index e86a4ca3b2179e6ae26d0136c5df773e4efa64ac..a445043931ae3f97af3df8a8c2b470ef7cea1321 100644 (file)
@@ -6,6 +6,8 @@
  * License terms: GNU General Public License (GPL) version 2
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
+
 #include <linux/stddef.h>
 #include <linux/spinlock.h>
 #include <linux/slab.h>
@@ -32,7 +34,7 @@ struct cflayer *cffrml_create(u16 phyid, bool use_fcs)
 {
        struct cffrml *this = kmalloc(sizeof(struct cffrml), GFP_ATOMIC);
        if (!this) {
-               pr_warning("CAIF: %s(): Out of memory\n", __func__);
+               pr_warn("Out of memory\n");
                return NULL;
        }
        caif_assert(offsetof(struct cffrml, layer) == 0);
@@ -83,7 +85,7 @@ static int cffrml_receive(struct cflayer *layr, struct cfpkt *pkt)
 
        if (cfpkt_setlen(pkt, len) < 0) {
                ++cffrml_rcv_error;
-               pr_err("CAIF: %s():Framing length error (%d)\n", __func__, len);
+               pr_err("Framing length error (%d)\n", len);
                cfpkt_destroy(pkt);
                return -EPROTO;
        }
@@ -99,14 +101,14 @@ static int cffrml_receive(struct cflayer *layr, struct cfpkt *pkt)
                        cfpkt_add_trail(pkt, &tmp, 2);
                        ++cffrml_rcv_error;
                        ++cffrml_rcv_checsum_error;
-                       pr_info("CAIF: %s(): Frame checksum error "
-                               "(0x%x != 0x%x)\n", __func__, hdrchks, pktchks);
+                       pr_info("Frame checksum error (0x%x != 0x%x)\n",
+                               hdrchks, pktchks);
                        return -EILSEQ;
                }
        }
        if (cfpkt_erroneous(pkt)) {
                ++cffrml_rcv_error;
-               pr_err("CAIF: %s(): Packet is erroneous!\n", __func__);
+               pr_err("Packet is erroneous!\n");
                cfpkt_destroy(pkt);
                return -EPROTO;
        }
@@ -132,7 +134,7 @@ static int cffrml_transmit(struct cflayer *layr, struct cfpkt *pkt)
        cfpkt_add_head(pkt, &tmp, 2);
        cfpkt_info(pkt)->hdr_len += 2;
        if (cfpkt_erroneous(pkt)) {
-               pr_err("CAIF: %s(): Packet is erroneous!\n", __func__);
+               pr_err("Packet is erroneous!\n");
                return -EPROTO;
        }
        ret = layr->dn->transmit(layr->dn, pkt);
index 80c8d332b2586fb1a4a2ddacca97f20fba9047ae..46f34b2e04784d8fd379384851c3d5b19377ddee 100644 (file)
@@ -3,6 +3,9 @@
  * Author:     Sjur Brendeland/sjur.brandeland@stericsson.com
  * License terms: GNU General Public License (GPL) version 2
  */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
+
 #include <linux/stddef.h>
 #include <linux/spinlock.h>
 #include <linux/slab.h>
@@ -190,7 +193,7 @@ static int cfmuxl_receive(struct cflayer *layr, struct cfpkt *pkt)
        u8 id;
        struct cflayer *up;
        if (cfpkt_extr_head(pkt, &id, 1) < 0) {
-               pr_err("CAIF: %s(): erroneous Caif Packet\n", __func__);
+               pr_err("erroneous Caif Packet\n");
                cfpkt_destroy(pkt);
                return -EPROTO;
        }
@@ -199,8 +202,8 @@ static int cfmuxl_receive(struct cflayer *layr, struct cfpkt *pkt)
        up = get_up(muxl, id);
        spin_unlock(&muxl->receive_lock);
        if (up == NULL) {
-               pr_info("CAIF: %s():Received data on unknown link ID = %d "
-                       "(0x%x)  up == NULL", __func__, id, id);
+               pr_info("Received data on unknown link ID = %d (0x%x) up == NULL",
+                       id, id);
                cfpkt_destroy(pkt);
                /*
                 * Don't return ERROR, since modem misbehaves and sends out
@@ -223,9 +226,8 @@ static int cfmuxl_transmit(struct cflayer *layr, struct cfpkt *pkt)
        struct caif_payload_info *info = cfpkt_info(pkt);
        dn = get_dn(muxl, cfpkt_info(pkt)->dev_info);
        if (dn == NULL) {
-               pr_warning("CAIF: %s(): Send data on unknown phy "
-                          "ID = %d (0x%x)\n",
-                          __func__, info->dev_info->id, info->dev_info->id);
+               pr_warn("Send data on unknown phy ID = %d (0x%x)\n",
+                       info->dev_info->id, info->dev_info->id);
                return -ENOTCONN;
        }
        info->hdr_len += 1;
index c49a6695793ac8361b072077aefa4e2b863e8f5c..d7e865e2ff651c13d21a1ad45d402a924864f0bf 100644 (file)
@@ -4,6 +4,8 @@
  * License terms: GNU General Public License (GPL) version 2
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
+
 #include <linux/string.h>
 #include <linux/skbuff.h>
 #include <linux/hardirq.h>
 #define PKT_PREFIX  48
 #define PKT_POSTFIX 2
 #define PKT_LEN_WHEN_EXTENDING 128
-#define PKT_ERROR(pkt, errmsg) do {       \
-    cfpkt_priv(pkt)->erronous = true;     \
-    skb_reset_tail_pointer(&pkt->skb);    \
-    pr_warning("CAIF: " errmsg);\
-  } while (0)
+#define PKT_ERROR(pkt, errmsg)            \
+do {                                      \
+       cfpkt_priv(pkt)->erronous = true;  \
+       skb_reset_tail_pointer(&pkt->skb); \
+       pr_warn(errmsg);                   \
+} while (0)
 
 struct cfpktq {
        struct sk_buff_head head;
@@ -130,13 +133,13 @@ int cfpkt_extr_head(struct cfpkt *pkt, void *data, u16 len)
                return -EPROTO;
 
        if (unlikely(len > skb->len)) {
-               PKT_ERROR(pkt, "cfpkt_extr_head read beyond end of packet\n");
+               PKT_ERROR(pkt, "read beyond end of packet\n");
                return -EPROTO;
        }
 
        if (unlikely(len > skb_headlen(skb))) {
                if (unlikely(skb_linearize(skb) != 0)) {
-                       PKT_ERROR(pkt, "cfpkt_extr_head linearize failed\n");
+                       PKT_ERROR(pkt, "linearize failed\n");
                        return -EPROTO;
                }
        }
@@ -156,11 +159,11 @@ int cfpkt_extr_trail(struct cfpkt *pkt, void *dta, u16 len)
                return -EPROTO;
 
        if (unlikely(skb_linearize(skb) != 0)) {
-               PKT_ERROR(pkt, "cfpkt_extr_trail linearize failed\n");
+               PKT_ERROR(pkt, "linearize failed\n");
                return -EPROTO;
        }
        if (unlikely(skb->data + len > skb_tail_pointer(skb))) {
-               PKT_ERROR(pkt, "cfpkt_extr_trail read beyond end of packet\n");
+               PKT_ERROR(pkt, "read beyond end of packet\n");
                return -EPROTO;
        }
        from = skb_tail_pointer(skb) - len;
@@ -202,7 +205,7 @@ int cfpkt_add_body(struct cfpkt *pkt, const void *data, u16 len)
 
                /* Make sure data is writable */
                if (unlikely(skb_cow_data(skb, addlen, &lastskb) < 0)) {
-                       PKT_ERROR(pkt, "cfpkt_add_body: cow failed\n");
+                       PKT_ERROR(pkt, "cow failed\n");
                        return -EPROTO;
                }
                /*
@@ -211,8 +214,7 @@ int cfpkt_add_body(struct cfpkt *pkt, const void *data, u16 len)
                 * lengths of the top SKB.
                 */
                if (lastskb != skb) {
-                       pr_warning("CAIF: %s(): Packet is non-linear\n",
-                                  __func__);
+                       pr_warn("Packet is non-linear\n");
                        skb->len += len;
                        skb->data_len += len;
                }
@@ -242,14 +244,14 @@ int cfpkt_add_head(struct cfpkt *pkt, const void *data2, u16 len)
        if (unlikely(is_erronous(pkt)))
                return -EPROTO;
        if (unlikely(skb_headroom(skb) < len)) {
-               PKT_ERROR(pkt, "cfpkt_add_head: no headroom\n");
+               PKT_ERROR(pkt, "no headroom\n");
                return -EPROTO;
        }
 
        /* Make sure data is writable */
        ret = skb_cow_data(skb, 0, &lastskb);
        if (unlikely(ret < 0)) {
-               PKT_ERROR(pkt, "cfpkt_add_head: cow failed\n");
+               PKT_ERROR(pkt, "cow failed\n");
                return ret;
        }
 
@@ -283,7 +285,7 @@ inline u16 cfpkt_iterate(struct cfpkt *pkt,
        if (unlikely(is_erronous(pkt)))
                return -EPROTO;
        if (unlikely(skb_linearize(&pkt->skb) != 0)) {
-               PKT_ERROR(pkt, "cfpkt_iterate: linearize failed\n");
+               PKT_ERROR(pkt, "linearize failed\n");
                return -EPROTO;
        }
        return iter_func(data, pkt->skb.data, cfpkt_getlen(pkt));
@@ -309,7 +311,7 @@ int cfpkt_setlen(struct cfpkt *pkt, u16 len)
 
        /* Need to expand SKB */
        if (unlikely(!cfpkt_pad_trail(pkt, len - skb->len)))
-               PKT_ERROR(pkt, "cfpkt_setlen: skb_pad_trail failed\n");
+               PKT_ERROR(pkt, "skb_pad_trail failed\n");
 
        return cfpkt_getlen(pkt);
 }
@@ -380,8 +382,7 @@ struct cfpkt *cfpkt_split(struct cfpkt *pkt, u16 pos)
                return NULL;
 
        if (skb->data + pos > skb_tail_pointer(skb)) {
-               PKT_ERROR(pkt,
-                         "cfpkt_split: trying to split beyond end of packet");
+               PKT_ERROR(pkt, "trying to split beyond end of packet\n");
                return NULL;
        }
 
@@ -455,17 +456,17 @@ int cfpkt_raw_append(struct cfpkt *pkt, void **buf, unsigned int buflen)
                return -EPROTO;
        /* Make sure SKB is writable */
        if (unlikely(skb_cow_data(skb, 0, &lastskb) < 0)) {
-               PKT_ERROR(pkt, "cfpkt_raw_append: skb_cow_data failed\n");
+               PKT_ERROR(pkt, "skb_cow_data failed\n");
                return -EPROTO;
        }
 
        if (unlikely(skb_linearize(skb) != 0)) {
-               PKT_ERROR(pkt, "cfpkt_raw_append: linearize failed\n");
+               PKT_ERROR(pkt, "linearize failed\n");
                return -EPROTO;
        }
 
        if (unlikely(skb_tailroom(skb) < buflen)) {
-               PKT_ERROR(pkt, "cfpkt_raw_append: buffer too short - failed\n");
+               PKT_ERROR(pkt, "buffer too short - failed\n");
                return -EPROTO;
        }
 
@@ -483,14 +484,13 @@ int cfpkt_raw_extract(struct cfpkt *pkt, void **buf, unsigned int buflen)
                return -EPROTO;
 
        if (unlikely(buflen > skb->len)) {
-               PKT_ERROR(pkt, "cfpkt_raw_extract: buflen too large "
-                               "- failed\n");
+               PKT_ERROR(pkt, "buflen too large - failed\n");
                return -EPROTO;
        }
 
        if (unlikely(buflen > skb_headlen(skb))) {
                if (unlikely(skb_linearize(skb) != 0)) {
-                       PKT_ERROR(pkt, "cfpkt_raw_extract: linearize failed\n");
+                       PKT_ERROR(pkt, "linearize failed\n");
                        return -EPROTO;
                }
        }
index 9a699242d104be7fbef70ed4560d6ca3a63ebda3..bde8481e8d2574dd939f84595f8e4354370aa5a7 100644 (file)
@@ -4,6 +4,8 @@
  * License terms: GNU General Public License (GPL) version 2
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
+
 #include <linux/stddef.h>
 #include <linux/spinlock.h>
 #include <linux/slab.h>
@@ -48,7 +50,7 @@ struct cflayer *cfrfml_create(u8 channel_id, struct dev_info *dev_info,
                kzalloc(sizeof(struct cfrfml), GFP_ATOMIC);
 
        if (!this) {
-               pr_warning("CAIF: %s(): Out of memory\n", __func__);
+               pr_warn("Out of memory\n");
                return NULL;
        }
 
@@ -178,9 +180,7 @@ out:
                        cfpkt_destroy(rfml->incomplete_frm);
                rfml->incomplete_frm = NULL;
 
-               pr_info("CAIF: %s(): "
-                               "Connection error %d triggered on RFM link\n",
-                               __func__, err);
+               pr_info("Connection error %d triggered on RFM link\n", err);
 
                /* Trigger connection error upon failure.*/
                layr->up->ctrlcmd(layr->up, CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND,
@@ -280,9 +280,7 @@ static int cfrfml_transmit(struct cflayer *layr, struct cfpkt *pkt)
 out:
 
        if (err != 0) {
-               pr_info("CAIF: %s(): "
-                               "Connection error %d triggered on RFM link\n",
-                               __func__, err);
+               pr_info("Connection error %d triggered on RFM link\n", err);
                /* Trigger connection error upon failure.*/
 
                layr->up->ctrlcmd(layr->up, CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND,
index a11fbd68a13dec6debe45e647122523400f9f5a1..9297f7dea9d8c164d4d5652d7930866154556350 100644 (file)
@@ -4,6 +4,8 @@
  * License terms: GNU General Public License (GPL) version 2
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
+
 #include <linux/stddef.h>
 #include <linux/spinlock.h>
 #include <linux/slab.h>
@@ -34,7 +36,7 @@ struct cflayer *cfserl_create(int type, int instance, bool use_stx)
 {
        struct cfserl *this = kmalloc(sizeof(struct cfserl), GFP_ATOMIC);
        if (!this) {
-               pr_warning("CAIF: %s(): Out of memory\n", __func__);
+               pr_warn("Out of memory\n");
                return NULL;
        }
        caif_assert(offsetof(struct cfserl, layer) == 0);
index f40939a91211b8e2b6ba985f2e1562064723e681..ab5e542526bf4e9e2f65562e56a97ccb96ba85bf 100644 (file)
@@ -4,6 +4,8 @@
  * License terms: GNU General Public License (GPL) version 2
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
+
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/errno.h>
@@ -79,8 +81,7 @@ static void cfservl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl,
                layr->up->ctrlcmd(layr->up, ctrl, phyid);
                break;
        default:
-               pr_warning("CAIF: %s(): "
-                          "Unexpected ctrl in cfsrvl (%d)\n", __func__, ctrl);
+               pr_warn("Unexpected ctrl in cfsrvl (%d)\n", ctrl);
                /* We have both modem and phy flow on, send flow on */
                layr->up->ctrlcmd(layr->up, ctrl, phyid);
                service->phy_flow_on = true;
@@ -107,14 +108,12 @@ static int cfservl_modemcmd(struct cflayer *layr, enum caif_modemcmd ctrl)
                        u8 flow_on = SRVL_FLOW_ON;
                        pkt = cfpkt_create(SRVL_CTRL_PKT_SIZE);
                        if (!pkt) {
-                               pr_warning("CAIF: %s(): Out of memory\n",
-                                       __func__);
+                               pr_warn("Out of memory\n");
                                return -ENOMEM;
                        }
 
                        if (cfpkt_add_head(pkt, &flow_on, 1) < 0) {
-                               pr_err("CAIF: %s(): Packet is erroneous!\n",
-                                       __func__);
+                               pr_err("Packet is erroneous!\n");
                                cfpkt_destroy(pkt);
                                return -EPROTO;
                        }
@@ -131,14 +130,12 @@ static int cfservl_modemcmd(struct cflayer *layr, enum caif_modemcmd ctrl)
                        u8 flow_off = SRVL_FLOW_OFF;
                        pkt = cfpkt_create(SRVL_CTRL_PKT_SIZE);
                        if (!pkt) {
-                               pr_warning("CAIF: %s(): Out of memory\n",
-                                       __func__);
+                               pr_warn("Out of memory\n");
                                return -ENOMEM;
                        }
 
                        if (cfpkt_add_head(pkt, &flow_off, 1) < 0) {
-                               pr_err("CAIF: %s(): Packet is erroneous!\n",
-                                       __func__);
+                               pr_err("Packet is erroneous!\n");
                                cfpkt_destroy(pkt);
                                return -EPROTO;
                        }
index 02795aff57a426fbbd1080214f46c5a1fb569d34..efad410e4c829d098fd7b02f2aaa106d4ea8f782 100644 (file)
@@ -4,6 +4,8 @@
  * License terms: GNU General Public License (GPL) version 2
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
+
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/slab.h>
@@ -26,7 +28,7 @@ struct cflayer *cfutill_create(u8 channel_id, struct dev_info *dev_info)
 {
        struct cfsrvl *util = kmalloc(sizeof(struct cfsrvl), GFP_ATOMIC);
        if (!util) {
-               pr_warning("CAIF: %s(): Out of memory\n", __func__);
+               pr_warn("Out of memory\n");
                return NULL;
        }
        caif_assert(offsetof(struct cfsrvl, layer) == 0);
@@ -47,7 +49,7 @@ static int cfutill_receive(struct cflayer *layr, struct cfpkt *pkt)
        caif_assert(layr->up->receive != NULL);
        caif_assert(layr->up->ctrlcmd != NULL);
        if (cfpkt_extr_head(pkt, &cmd, 1) < 0) {
-               pr_err("CAIF: %s(): Packet is erroneous!\n", __func__);
+               pr_err("Packet is erroneous!\n");
                cfpkt_destroy(pkt);
                return -EPROTO;
        }
@@ -64,16 +66,14 @@ static int cfutill_receive(struct cflayer *layr, struct cfpkt *pkt)
                cfpkt_destroy(pkt);
                return 0;
        case UTIL_REMOTE_SHUTDOWN:      /* Remote Shutdown Request */
-               pr_err("CAIF: %s(): REMOTE SHUTDOWN REQUEST RECEIVED\n",
-                       __func__);
+               pr_err("REMOTE SHUTDOWN REQUEST RECEIVED\n");
                layr->ctrlcmd(layr, CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND, 0);
                service->open = false;
                cfpkt_destroy(pkt);
                return 0;
        default:
                cfpkt_destroy(pkt);
-               pr_warning("CAIF: %s(): Unknown service control %d (0x%x)\n",
-                          __func__, cmd, cmd);
+               pr_warn("Unknown service control %d (0x%x)\n", cmd, cmd);
                return -EPROTO;
        }
 }
index 77cc09faac9a305cfa4a05554ad95bea6d52e08e..3b425b189a99f7dc55885ccf61fa2d951ec12ee1 100644 (file)
@@ -4,6 +4,8 @@
  * License terms: GNU General Public License (GPL) version 2
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
+
 #include <linux/stddef.h>
 #include <linux/slab.h>
 #include <net/caif/caif_layer.h>
@@ -25,7 +27,7 @@ struct cflayer *cfvei_create(u8 channel_id, struct dev_info *dev_info)
 {
        struct cfsrvl *vei = kmalloc(sizeof(struct cfsrvl), GFP_ATOMIC);
        if (!vei) {
-               pr_warning("CAIF: %s(): Out of memory\n", __func__);
+               pr_warn("Out of memory\n");
                return NULL;
        }
        caif_assert(offsetof(struct cfsrvl, layer) == 0);
@@ -47,7 +49,7 @@ static int cfvei_receive(struct cflayer *layr, struct cfpkt *pkt)
 
 
        if (cfpkt_extr_head(pkt, &cmd, 1) < 0) {
-               pr_err("CAIF: %s(): Packet is erroneous!\n", __func__);
+               pr_err("Packet is erroneous!\n");
                cfpkt_destroy(pkt);
                return -EPROTO;
        }
@@ -67,8 +69,7 @@ static int cfvei_receive(struct cflayer *layr, struct cfpkt *pkt)
                cfpkt_destroy(pkt);
                return 0;
        default:                /* SET RS232 PIN */
-               pr_warning("CAIF: %s():Unknown VEI control packet %d (0x%x)!\n",
-                          __func__, cmd, cmd);
+               pr_warn("Unknown VEI control packet %d (0x%x)!\n", cmd, cmd);
                cfpkt_destroy(pkt);
                return -EPROTO;
        }
@@ -86,7 +87,7 @@ static int cfvei_transmit(struct cflayer *layr, struct cfpkt *pkt)
        caif_assert(layr->dn->transmit != NULL);
 
        if (cfpkt_add_head(pkt, &tmp, 1) < 0) {
-               pr_err("CAIF: %s(): Packet is erroneous!\n", __func__);
+               pr_err("Packet is erroneous!\n");
                return -EPROTO;
        }
 
index ada6ee2d48f50a3ab4df69f102778535c4292eba..bf6fef2a0eff19ddacfc0ef980a625886404469f 100644 (file)
@@ -4,6 +4,8 @@
  * License terms: GNU General Public License (GPL) version 2
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
+
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/slab.h>
@@ -21,7 +23,7 @@ struct cflayer *cfvidl_create(u8 channel_id, struct dev_info *dev_info)
 {
        struct cfsrvl *vid = kmalloc(sizeof(struct cfsrvl), GFP_ATOMIC);
        if (!vid) {
-               pr_warning("CAIF: %s(): Out of memory\n", __func__);
+               pr_warn("Out of memory\n");
                return NULL;
        }
        caif_assert(offsetof(struct cfsrvl, layer) == 0);
@@ -38,7 +40,7 @@ static int cfvidl_receive(struct cflayer *layr, struct cfpkt *pkt)
 {
        u32 videoheader;
        if (cfpkt_extr_head(pkt, &videoheader, 4) < 0) {
-               pr_err("CAIF: %s(): Packet is erroneous!\n", __func__);
+               pr_err("Packet is erroneous!\n");
                cfpkt_destroy(pkt);
                return -EPROTO;
        }
index 4293e190ec5328f1da7f40065c9eefcdff5d1f66..86aac24b02256cb0413f36423b7c0a5212243eb9 100644 (file)
@@ -5,6 +5,8 @@
  * License terms: GNU General Public License (GPL) version 2
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
+
 #include <linux/version.h>
 #include <linux/fs.h>
 #include <linux/init.h>
@@ -29,7 +31,7 @@
 #define CAIF_NET_DEFAULT_QUEUE_LEN 500
 
 #undef pr_debug
-#define pr_debug pr_warning
+#define pr_debug pr_warn
 
 /*This list is protected by the rtnl lock. */
 static LIST_HEAD(chnl_net_list);
@@ -142,8 +144,7 @@ static void chnl_flowctrl_cb(struct cflayer *layr, enum caif_ctrlcmd flow,
                                int phyid)
 {
        struct chnl_net *priv = container_of(layr, struct chnl_net, chnl);
-       pr_debug("CAIF: %s(): NET flowctrl func called flow: %s\n",
-               __func__,
+       pr_debug("NET flowctrl func called flow: %s\n",
                flow == CAIF_CTRLCMD_FLOW_ON_IND ? "ON" :
                flow == CAIF_CTRLCMD_INIT_RSP ? "INIT" :
                flow == CAIF_CTRLCMD_FLOW_OFF_IND ? "OFF" :
@@ -196,12 +197,12 @@ static int chnl_net_start_xmit(struct sk_buff *skb, struct net_device *dev)
        priv = netdev_priv(dev);
 
        if (skb->len > priv->netdev->mtu) {
-               pr_warning("CAIF: %s(): Size of skb exceeded MTU\n", __func__);
+               pr_warn("Size of skb exceeded MTU\n");
                return -ENOSPC;
        }
 
        if (!priv->flowenabled) {
-               pr_debug("CAIF: %s(): dropping packets flow off\n", __func__);
+               pr_debug("dropping packets flow off\n");
                return NETDEV_TX_BUSY;
        }
 
@@ -237,7 +238,7 @@ static int chnl_net_open(struct net_device *dev)
        ASSERT_RTNL();
        priv = netdev_priv(dev);
        if (!priv) {
-               pr_debug("CAIF: %s(): chnl_net_open: no priv\n", __func__);
+               pr_debug("chnl_net_open: no priv\n");
                return -ENODEV;
        }
 
@@ -246,18 +247,17 @@ static int chnl_net_open(struct net_device *dev)
                result = caif_connect_client(&priv->conn_req, &priv->chnl,
                                        &llifindex, &headroom, &tailroom);
                if (result != 0) {
-                               pr_debug("CAIF: %s(): err: "
-                                       "Unable to register and open device,"
-                                       " Err:%d\n",
-                                       __func__,
-                                       result);
+                               pr_debug("err: "
+                                        "Unable to register and open device,"
+                                        " Err:%d\n",
+                                        result);
                                goto error;
                }
 
                lldev = dev_get_by_index(dev_net(dev), llifindex);
 
                if (lldev == NULL) {
-                       pr_debug("CAIF: %s(): no interface?\n", __func__);
+                       pr_debug("no interface?\n");
                        result = -ENODEV;
                        goto error;
                }
@@ -279,9 +279,7 @@ static int chnl_net_open(struct net_device *dev)
                dev_put(lldev);
 
                if (mtu < 100) {
-                       pr_warning("CAIF: %s(): "
-                               "CAIF Interface MTU too small (%d)\n",
-                               __func__, mtu);
+                       pr_warn("CAIF Interface MTU too small (%d)\n", mtu);
                        result = -ENODEV;
                        goto error;
                }
@@ -296,33 +294,32 @@ static int chnl_net_open(struct net_device *dev)
        rtnl_lock();
 
        if (result == -ERESTARTSYS) {
-               pr_debug("CAIF: %s(): wait_event_interruptible"
-                        " woken by a signal\n", __func__);
+               pr_debug("wait_event_interruptible woken by a signal\n");
                result = -ERESTARTSYS;
                goto error;
        }
 
        if (result == 0) {
-               pr_debug("CAIF: %s(): connect timeout\n", __func__);
+               pr_debug("connect timeout\n");
                caif_disconnect_client(&priv->chnl);
                priv->state = CAIF_DISCONNECTED;
-               pr_debug("CAIF: %s(): state disconnected\n", __func__);
+               pr_debug("state disconnected\n");
                result = -ETIMEDOUT;
                goto error;
        }
 
        if (priv->state != CAIF_CONNECTED) {
-               pr_debug("CAIF: %s(): connect failed\n", __func__);
+               pr_debug("connect failed\n");
                result = -ECONNREFUSED;
                goto error;
        }
-       pr_debug("CAIF: %s(): CAIF Netdevice connected\n", __func__);
+       pr_debug("CAIF Netdevice connected\n");
        return 0;
 
 error:
        caif_disconnect_client(&priv->chnl);
        priv->state = CAIF_DISCONNECTED;
-       pr_debug("CAIF: %s(): state disconnected\n", __func__);
+       pr_debug("state disconnected\n");
        return result;
 
 }
@@ -413,7 +410,7 @@ static void caif_netlink_parms(struct nlattr *data[],
                                struct caif_connect_request *conn_req)
 {
        if (!data) {
-               pr_warning("CAIF: %s: no params data found\n", __func__);
+               pr_warn("no params data found\n");
                return;
        }
        if (data[IFLA_CAIF_IPV4_CONNID])
@@ -442,8 +439,7 @@ static int ipcaif_newlink(struct net *src_net, struct net_device *dev,
 
        ret = register_netdevice(dev);
        if (ret)
-               pr_warning("CAIF: %s(): device rtml registration failed\n",
-                          __func__);
+               pr_warn("device rtml registration failed\n");
        return ret;
 }
 
index a10e3338f084aaf15eb73b40d46f1f28e96aaaf7..7d77e67e57af681bcdb6a10e54173f592b8f8abf 100644 (file)
@@ -647,12 +647,12 @@ static int raw_sendmsg(struct kiocb *iocb, struct socket *sock,
        err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size);
        if (err < 0)
                goto free_skb;
-       err = sock_tx_timestamp(msg, sk, skb_tx(skb));
+       err = sock_tx_timestamp(sk, &skb_shinfo(skb)->tx_flags);
        if (err < 0)
                goto free_skb;
 
        /* to be able to check the received tx sock reference in raw_rcv() */
-       skb_tx(skb)->prevent_sk_orphan = 1;
+       skb_shinfo(skb)->tx_flags |= SKBTX_DRV_NEEDS_SK_REF;
 
        skb->dev = dev;
        skb->sk  = sk;
index 251997a9548362c5ebc8a0a34842971a0198539a..4df1b7a6c1bff60b8687cbd5285e365cc381a89b 100644 (file)
@@ -746,13 +746,12 @@ unsigned int datagram_poll(struct file *file, struct socket *sock,
        if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue))
                mask |= POLLERR;
        if (sk->sk_shutdown & RCV_SHUTDOWN)
-               mask |= POLLRDHUP;
+               mask |= POLLRDHUP | POLLIN | POLLRDNORM;
        if (sk->sk_shutdown == SHUTDOWN_MASK)
                mask |= POLLHUP;
 
        /* readable? */
-       if (!skb_queue_empty(&sk->sk_receive_queue) ||
-           (sk->sk_shutdown & RCV_SHUTDOWN))
+       if (!skb_queue_empty(&sk->sk_receive_queue))
                mask |= POLLIN | POLLRDNORM;
 
        /* Connection-based need to check for termination and startup */
index b9b22a3c4c8fa36ea3412e22a816d0c738562831..fc2dc933bee5b6053cd0ee8c92646ec1fb143714 100644 (file)
@@ -371,6 +371,14 @@ static inline void netdev_set_addr_lockdep_class(struct net_device *dev)
  *                                                     --ANK (980803)
  */
 
+static inline struct list_head *ptype_head(const struct packet_type *pt)
+{
+       if (pt->type == htons(ETH_P_ALL))
+               return &ptype_all;
+       else
+               return &ptype_base[ntohs(pt->type) & PTYPE_HASH_MASK];
+}
+
 /**
  *     dev_add_pack - add packet handler
  *     @pt: packet type declaration
@@ -386,16 +394,11 @@ static inline void netdev_set_addr_lockdep_class(struct net_device *dev)
 
 void dev_add_pack(struct packet_type *pt)
 {
-       int hash;
+       struct list_head *head = ptype_head(pt);
 
-       spin_lock_bh(&ptype_lock);
-       if (pt->type == htons(ETH_P_ALL))
-               list_add_rcu(&pt->list, &ptype_all);
-       else {
-               hash = ntohs(pt->type) & PTYPE_HASH_MASK;
-               list_add_rcu(&pt->list, &ptype_base[hash]);
-       }
-       spin_unlock_bh(&ptype_lock);
+       spin_lock(&ptype_lock);
+       list_add_rcu(&pt->list, head);
+       spin_unlock(&ptype_lock);
 }
 EXPORT_SYMBOL(dev_add_pack);
 
@@ -414,15 +417,10 @@ EXPORT_SYMBOL(dev_add_pack);
  */
 void __dev_remove_pack(struct packet_type *pt)
 {
-       struct list_head *head;
+       struct list_head *head = ptype_head(pt);
        struct packet_type *pt1;
 
-       spin_lock_bh(&ptype_lock);
-
-       if (pt->type == htons(ETH_P_ALL))
-               head = &ptype_all;
-       else
-               head = &ptype_base[ntohs(pt->type) & PTYPE_HASH_MASK];
+       spin_lock(&ptype_lock);
 
        list_for_each_entry(pt1, head, list) {
                if (pt == pt1) {
@@ -433,7 +431,7 @@ void __dev_remove_pack(struct packet_type *pt)
 
        printk(KERN_WARNING "dev_remove_pack: %p not found.\n", pt);
 out:
-       spin_unlock_bh(&ptype_lock);
+       spin_unlock(&ptype_lock);
 }
 EXPORT_SYMBOL(__dev_remove_pack);
 
@@ -1902,14 +1900,14 @@ static int dev_gso_segment(struct sk_buff *skb)
 
 /*
  * Try to orphan skb early, right before transmission by the device.
- * We cannot orphan skb if tx timestamp is requested, since
- * drivers need to call skb_tstamp_tx() to send the timestamp.
+ * We cannot orphan skb if tx timestamp is requested or the sk-reference
+ * is needed on driver level for other reasons, e.g. see net/can/raw.c
  */
 static inline void skb_orphan_try(struct sk_buff *skb)
 {
        struct sock *sk = skb->sk;
 
-       if (sk && !skb_tx(skb)->flags) {
+       if (sk && !skb_shinfo(skb)->tx_flags) {
                /* skb_tx_hash() wont be able to get sk.
                 * We copy sk_hash into skb->rxhash
                 */
@@ -1930,7 +1928,7 @@ static inline int skb_needs_linearize(struct sk_buff *skb,
                                      struct net_device *dev)
 {
        return skb_is_nonlinear(skb) &&
-              ((skb_has_frags(skb) && !(dev->features & NETIF_F_FRAGLIST)) ||
+              ((skb_has_frag_list(skb) && !(dev->features & NETIF_F_FRAGLIST)) ||
                (skb_shinfo(skb)->nr_frags && (!(dev->features & NETIF_F_SG) ||
                                              illegal_highdma(dev, skb))));
 }
@@ -2259,69 +2257,44 @@ static inline void ____napi_schedule(struct softnet_data *sd,
        __raise_softirq_irqoff(NET_RX_SOFTIRQ);
 }
 
-#ifdef CONFIG_RPS
-
-/* One global table that all flow-based protocols share. */
-struct rps_sock_flow_table *rps_sock_flow_table __read_mostly;
-EXPORT_SYMBOL(rps_sock_flow_table);
-
 /*
- * get_rps_cpu is called from netif_receive_skb and returns the target
- * CPU from the RPS map of the receiving queue for a given skb.
- * rcu_read_lock must be held on entry.
+ * __skb_get_rxhash: calculate a flow hash based on src/dst addresses
+ * and src/dst port numbers. Returns a non-zero hash number on success
+ * and 0 on failure.
  */
-static int get_rps_cpu(struct net_device *dev, struct sk_buff *skb,
-                      struct rps_dev_flow **rflowp)
+__u32 __skb_get_rxhash(struct sk_buff *skb)
 {
+       int nhoff, hash = 0, poff;
        struct ipv6hdr *ip6;
        struct iphdr *ip;
-       struct netdev_rx_queue *rxqueue;
-       struct rps_map *map;
-       struct rps_dev_flow_table *flow_table;
-       struct rps_sock_flow_table *sock_flow_table;
-       int cpu = -1;
        u8 ip_proto;
-       u16 tcpu;
        u32 addr1, addr2, ihl;
        union {
                u32 v32;
                u16 v16[2];
        } ports;
 
-       if (skb_rx_queue_recorded(skb)) {
-               u16 index = skb_get_rx_queue(skb);
-               if (unlikely(index >= dev->num_rx_queues)) {
-                       WARN_ONCE(dev->num_rx_queues > 1, "%s received packet "
-                               "on queue %u, but number of RX queues is %u\n",
-                               dev->name, index, dev->num_rx_queues);
-                       goto done;
-               }
-               rxqueue = dev->_rx + index;
-       } else
-               rxqueue = dev->_rx;
-
-       if (!rxqueue->rps_map && !rxqueue->rps_flow_table)
-               goto done;
-
-       if (skb->rxhash)
-               goto got_hash; /* Skip hash computation on packet header */
+       nhoff = skb_network_offset(skb);
 
        switch (skb->protocol) {
        case __constant_htons(ETH_P_IP):
-               if (!pskb_may_pull(skb, sizeof(*ip)))
+               if (!pskb_may_pull(skb, sizeof(*ip) + nhoff))
                        goto done;
 
-               ip = (struct iphdr *) skb->data;
-               ip_proto = ip->protocol;
+               ip = (struct iphdr *) (skb->data + nhoff);
+               if (ip->frag_off & htons(IP_MF | IP_OFFSET))
+                       ip_proto = 0;
+               else
+                       ip_proto = ip->protocol;
                addr1 = (__force u32) ip->saddr;
                addr2 = (__force u32) ip->daddr;
                ihl = ip->ihl;
                break;
        case __constant_htons(ETH_P_IPV6):
-               if (!pskb_may_pull(skb, sizeof(*ip6)))
+               if (!pskb_may_pull(skb, sizeof(*ip6) + nhoff))
                        goto done;
 
-               ip6 = (struct ipv6hdr *) skb->data;
+               ip6 = (struct ipv6hdr *) (skb->data + nhoff);
                ip_proto = ip6->nexthdr;
                addr1 = (__force u32) ip6->saddr.s6_addr32[3];
                addr2 = (__force u32) ip6->daddr.s6_addr32[3];
@@ -2330,33 +2303,80 @@ static int get_rps_cpu(struct net_device *dev, struct sk_buff *skb,
        default:
                goto done;
        }
-       switch (ip_proto) {
-       case IPPROTO_TCP:
-       case IPPROTO_UDP:
-       case IPPROTO_DCCP:
-       case IPPROTO_ESP:
-       case IPPROTO_AH:
-       case IPPROTO_SCTP:
-       case IPPROTO_UDPLITE:
-               if (pskb_may_pull(skb, (ihl * 4) + 4)) {
-                       ports.v32 = * (__force u32 *) (skb->data + (ihl * 4));
+
+       ports.v32 = 0;
+       poff = proto_ports_offset(ip_proto);
+       if (poff >= 0) {
+               nhoff += ihl * 4 + poff;
+               if (pskb_may_pull(skb, nhoff + 4)) {
+                       ports.v32 = * (__force u32 *) (skb->data + nhoff);
                        if (ports.v16[1] < ports.v16[0])
                                swap(ports.v16[0], ports.v16[1]);
-                       break;
                }
-       default:
-               ports.v32 = 0;
-               break;
        }
 
        /* get a consistent hash (same value on both flow directions) */
        if (addr2 < addr1)
                swap(addr1, addr2);
-       skb->rxhash = jhash_3words(addr1, addr2, ports.v32, hashrnd);
-       if (!skb->rxhash)
-               skb->rxhash = 1;
 
-got_hash:
+       hash = jhash_3words(addr1, addr2, ports.v32, hashrnd);
+       if (!hash)
+               hash = 1;
+
+done:
+       return hash;
+}
+EXPORT_SYMBOL(__skb_get_rxhash);
+
+#ifdef CONFIG_RPS
+
+/* One global table that all flow-based protocols share. */
+struct rps_sock_flow_table *rps_sock_flow_table __read_mostly;
+EXPORT_SYMBOL(rps_sock_flow_table);
+
+/*
+ * get_rps_cpu is called from netif_receive_skb and returns the target
+ * CPU from the RPS map of the receiving queue for a given skb.
+ * rcu_read_lock must be held on entry.
+ */
+static int get_rps_cpu(struct net_device *dev, struct sk_buff *skb,
+                      struct rps_dev_flow **rflowp)
+{
+       struct netdev_rx_queue *rxqueue;
+       struct rps_map *map = NULL;
+       struct rps_dev_flow_table *flow_table;
+       struct rps_sock_flow_table *sock_flow_table;
+       int cpu = -1;
+       u16 tcpu;
+
+       if (skb_rx_queue_recorded(skb)) {
+               u16 index = skb_get_rx_queue(skb);
+               if (unlikely(index >= dev->num_rx_queues)) {
+                       WARN_ONCE(dev->num_rx_queues > 1, "%s received packet "
+                               "on queue %u, but number of RX queues is %u\n",
+                               dev->name, index, dev->num_rx_queues);
+                       goto done;
+               }
+               rxqueue = dev->_rx + index;
+       } else
+               rxqueue = dev->_rx;
+
+       if (rxqueue->rps_map) {
+               map = rcu_dereference(rxqueue->rps_map);
+               if (map && map->len == 1) {
+                       tcpu = map->cpus[0];
+                       if (cpu_online(tcpu))
+                               cpu = tcpu;
+                       goto done;
+               }
+       } else if (!rxqueue->rps_flow_table) {
+               goto done;
+       }
+
+       skb_reset_network_header(skb);
+       if (!skb_get_rxhash(skb))
+               goto done;
+
        flow_table = rcu_dereference(rxqueue->rps_flow_table);
        sock_flow_table = rcu_dereference(rps_sock_flow_table);
        if (flow_table && sock_flow_table) {
@@ -2396,7 +2416,6 @@ got_hash:
                }
        }
 
-       map = rcu_dereference(rxqueue->rps_map);
        if (map) {
                tcpu = map->cpus[((u64) skb->rxhash * map->len) >> 32];
 
@@ -2828,8 +2847,8 @@ static int __netif_receive_skb(struct sk_buff *skb)
        if (!netdev_tstamp_prequeue)
                net_timestamp_check(skb);
 
-       if (vlan_tx_tag_present(skb) && vlan_hwaccel_do_receive(skb))
-               return NET_RX_SUCCESS;
+       if (vlan_tx_tag_present(skb))
+               vlan_hwaccel_do_receive(skb);
 
        /* if we've gotten here through NAPI, check netpoll */
        if (netpoll_receive_skb(skb))
@@ -3050,7 +3069,7 @@ out:
        return netif_receive_skb(skb);
 }
 
-static void napi_gro_flush(struct napi_struct *napi)
+inline void napi_gro_flush(struct napi_struct *napi)
 {
        struct sk_buff *skb, *next;
 
@@ -3063,6 +3082,7 @@ static void napi_gro_flush(struct napi_struct *napi)
        napi->gro_count = 0;
        napi->gro_list = NULL;
 }
+EXPORT_SYMBOL(napi_gro_flush);
 
 enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff *skb)
 {
@@ -3077,7 +3097,7 @@ enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff *skb)
        if (!(skb->dev->features & NETIF_F_GRO) || netpoll_rx_on(skb))
                goto normal;
 
-       if (skb_is_gso(skb) || skb_has_frags(skb))
+       if (skb_is_gso(skb) || skb_has_frag_list(skb))
                goto normal;
 
        rcu_read_lock();
@@ -3156,16 +3176,18 @@ normal:
 }
 EXPORT_SYMBOL(dev_gro_receive);
 
-static gro_result_t
+static inline gro_result_t
 __napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb)
 {
        struct sk_buff *p;
 
        for (p = napi->gro_list; p; p = p->next) {
-               NAPI_GRO_CB(p)->same_flow =
-                       (p->dev == skb->dev) &&
-                       !compare_ether_header(skb_mac_header(p),
+               unsigned long diffs;
+
+               diffs = (unsigned long)p->dev ^ (unsigned long)skb->dev;
+               diffs |= compare_ether_header(skb_mac_header(p),
                                              skb_gro_mac_header(skb));
+               NAPI_GRO_CB(p)->same_flow = !diffs;
                NAPI_GRO_CB(p)->flush = 0;
        }
 
index 7a85367b3c2f8010af24bbd6b6f4249698f9d78d..970eb9817bbcc912b21c2823e2a377b1bd304a25 100644 (file)
@@ -205,18 +205,24 @@ static noinline_for_stack int ethtool_get_drvinfo(struct net_device *dev,
        struct ethtool_drvinfo info;
        const struct ethtool_ops *ops = dev->ethtool_ops;
 
-       if (!ops->get_drvinfo)
-               return -EOPNOTSUPP;
-
        memset(&info, 0, sizeof(info));
        info.cmd = ETHTOOL_GDRVINFO;
-       ops->get_drvinfo(dev, &info);
+       if (ops && 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),
+                       sizeof(info.bus_info));
+               strlcpy(info.driver, dev->dev.parent->driver->name,
+                       sizeof(info.driver));
+       } else {
+               return -EOPNOTSUPP;
+       }
 
        /*
         * this method of obtaining string set info is deprecated;
         * Use ETHTOOL_GSSET_INFO instead.
         */
-       if (ops->get_sset_count) {
+       if (ops && ops->get_sset_count) {
                int rc;
 
                rc = ops->get_sset_count(dev, ETH_SS_TEST);
@@ -229,9 +235,9 @@ static noinline_for_stack int ethtool_get_drvinfo(struct net_device *dev,
                if (rc >= 0)
                        info.n_priv_flags = rc;
        }
-       if (ops->get_regs_len)
+       if (ops && ops->get_regs_len)
                info.regdump_len = ops->get_regs_len(dev);
-       if (ops->get_eeprom_len)
+       if (ops && ops->get_eeprom_len)
                info.eedump_len = ops->get_eeprom_len(dev);
 
        if (copy_to_user(useraddr, &info, sizeof(info)))
@@ -1402,14 +1408,22 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
        if (!dev || !netif_device_present(dev))
                return -ENODEV;
 
-       if (!dev->ethtool_ops)
-               return -EOPNOTSUPP;
-
        if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
                return -EFAULT;
 
+       if (!dev->ethtool_ops) {
+               /* ETHTOOL_GDRVINFO does not require any driver support.
+                * It is also unprivileged and does not change anything,
+                * so we can take a shortcut to it. */
+               if (ethcmd == ETHTOOL_GDRVINFO)
+                       return ethtool_get_drvinfo(dev, useraddr);
+               else
+                       return -EOPNOTSUPP;
+       }
+
        /* Allow some commands to be done by anyone */
        switch (ethcmd) {
+       case ETHTOOL_GSET:
        case ETHTOOL_GDRVINFO:
        case ETHTOOL_GMSGLVL:
        case ETHTOOL_GCOALESCE:
index 1cd98df412dfd52daee9cc9105ceddfea0d87a59..f4657c2127b4a9bc998cb0e91bf5405f83d5846e 100644 (file)
@@ -41,7 +41,9 @@ int verify_iovec(struct msghdr *m, struct iovec *iov, struct sockaddr *address,
 
        if (m->msg_namelen) {
                if (mode == VERIFY_READ) {
-                       err = move_addr_to_kernel(m->msg_name, m->msg_namelen,
+                       void __user *namep;
+                       namep = (void __user __force *) m->msg_name;
+                       err = move_addr_to_kernel(namep, m->msg_namelen,
                                                  address);
                        if (err < 0)
                                return err;
@@ -52,7 +54,7 @@ int verify_iovec(struct msghdr *m, struct iovec *iov, struct sockaddr *address,
        }
 
        size = m->msg_iovlen * sizeof(struct iovec);
-       if (copy_from_user(iov, m->msg_iov, size))
+       if (copy_from_user(iov, (void __user __force *) m->msg_iov, size))
                return -EFAULT;
 
        m->msg_iov = iov;
index af4dfbadf2a09ea496653990ae8e1da823a059e1..76485a3f910bf00446131687c018ab8b044ca691 100644 (file)
@@ -515,7 +515,7 @@ static ssize_t rx_queue_attr_store(struct kobject *kobj, struct attribute *attr,
        return attribute->store(queue, attribute, buf, count);
 }
 
-static struct sysfs_ops rx_queue_sysfs_ops = {
+static const struct sysfs_ops rx_queue_sysfs_ops = {
        .show = rx_queue_attr_show,
        .store = rx_queue_attr_store,
 };
@@ -789,12 +789,13 @@ static const void *net_netlink_ns(struct sock *sk)
        return sock_net(sk);
 }
 
-static struct kobj_ns_type_operations net_ns_type_operations = {
+struct kobj_ns_type_operations net_ns_type_operations = {
        .type = KOBJ_NS_TYPE_NET,
        .current_ns = net_current_ns,
        .netlink_ns = net_netlink_ns,
        .initial_ns = net_initial_ns,
 };
+EXPORT_SYMBOL_GPL(net_ns_type_operations);
 
 static void net_kobj_ns_exit(struct net *net)
 {
index 10a1ea72010d329295ce3936228aa5bffe7dc745..386c2283f14ec580824e8cac355b7da568259abc 100644 (file)
@@ -3907,8 +3907,6 @@ static void __exit pg_cleanup(void)
 {
        struct pktgen_thread *t;
        struct list_head *q, *n;
-       wait_queue_head_t queue;
-       init_waitqueue_head(&queue);
 
        /* Stop all interfaces & threads */
 
index f78d821bd9357dc3a88feb1259219478268858a3..b2a718dfd720f69c46aca7a7ff2ce50f8b14d907 100644 (file)
@@ -612,36 +612,7 @@ static void copy_rtnl_link_stats(struct rtnl_link_stats *a,
 
 static void copy_rtnl_link_stats64(void *v, const struct rtnl_link_stats64 *b)
 {
-       struct rtnl_link_stats64 a;
-
-       a.rx_packets = b->rx_packets;
-       a.tx_packets = b->tx_packets;
-       a.rx_bytes = b->rx_bytes;
-       a.tx_bytes = b->tx_bytes;
-       a.rx_errors = b->rx_errors;
-       a.tx_errors = b->tx_errors;
-       a.rx_dropped = b->rx_dropped;
-       a.tx_dropped = b->tx_dropped;
-
-       a.multicast = b->multicast;
-       a.collisions = b->collisions;
-
-       a.rx_length_errors = b->rx_length_errors;
-       a.rx_over_errors = b->rx_over_errors;
-       a.rx_crc_errors = b->rx_crc_errors;
-       a.rx_frame_errors = b->rx_frame_errors;
-       a.rx_fifo_errors = b->rx_fifo_errors;
-       a.rx_missed_errors = b->rx_missed_errors;
-
-       a.tx_aborted_errors = b->tx_aborted_errors;
-       a.tx_carrier_errors = b->tx_carrier_errors;
-       a.tx_fifo_errors = b->tx_fifo_errors;
-       a.tx_heartbeat_errors = b->tx_heartbeat_errors;
-       a.tx_window_errors = b->tx_window_errors;
-
-       a.rx_compressed = b->rx_compressed;
-       a.tx_compressed = b->tx_compressed;
-       memcpy(v, &a, sizeof(a));
+       memcpy(v, b, sizeof(*b));
 }
 
 /* All VF info */
index c83b421341c01b4a1de702e42d3380fac2f0aa2b..752c1972b3a79eb76f83f4906a7c9355622c8b08 100644 (file)
@@ -202,8 +202,6 @@ struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask,
        skb->data = data;
        skb_reset_tail_pointer(skb);
        skb->end = skb->tail + size;
-       kmemcheck_annotate_bitfield(skb, flags1);
-       kmemcheck_annotate_bitfield(skb, flags2);
 #ifdef NET_SKBUFF_DATA_USES_OFFSET
        skb->mac_header = ~0U;
 #endif
@@ -340,7 +338,7 @@ static void skb_release_data(struct sk_buff *skb)
                                put_page(skb_shinfo(skb)->frags[i].page);
                }
 
-               if (skb_has_frags(skb))
+               if (skb_has_frag_list(skb))
                        skb_drop_fraglist(skb);
 
                kfree(skb->head);
@@ -685,16 +683,10 @@ static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
 
 struct sk_buff *skb_copy(const struct sk_buff *skb, gfp_t gfp_mask)
 {
-       int headerlen = skb->data - skb->head;
-       /*
-        *      Allocate the copy buffer
-        */
-       struct sk_buff *n;
-#ifdef NET_SKBUFF_DATA_USES_OFFSET
-       n = alloc_skb(skb->end + skb->data_len, gfp_mask);
-#else
-       n = alloc_skb(skb->end - skb->head + skb->data_len, gfp_mask);
-#endif
+       int headerlen = skb_headroom(skb);
+       unsigned int size = (skb_end_pointer(skb) - skb->head) + skb->data_len;
+       struct sk_buff *n = alloc_skb(size, gfp_mask);
+
        if (!n)
                return NULL;
 
@@ -726,20 +718,14 @@ EXPORT_SYMBOL(skb_copy);
 
 struct sk_buff *pskb_copy(struct sk_buff *skb, gfp_t gfp_mask)
 {
-       /*
-        *      Allocate the copy buffer
-        */
-       struct sk_buff *n;
-#ifdef NET_SKBUFF_DATA_USES_OFFSET
-       n = alloc_skb(skb->end, gfp_mask);
-#else
-       n = alloc_skb(skb->end - skb->head, gfp_mask);
-#endif
+       unsigned int size = skb_end_pointer(skb) - skb->head;
+       struct sk_buff *n = alloc_skb(size, gfp_mask);
+
        if (!n)
                goto out;
 
        /* Set the data pointer */
-       skb_reserve(n, skb->data - skb->head);
+       skb_reserve(n, skb_headroom(skb));
        /* Set the tail pointer and length */
        skb_put(n, skb_headlen(skb));
        /* Copy the bytes */
@@ -759,7 +745,7 @@ struct sk_buff *pskb_copy(struct sk_buff *skb, gfp_t gfp_mask)
                skb_shinfo(n)->nr_frags = i;
        }
 
-       if (skb_has_frags(skb)) {
+       if (skb_has_frag_list(skb)) {
                skb_shinfo(n)->frag_list = skb_shinfo(skb)->frag_list;
                skb_clone_fraglist(n);
        }
@@ -791,12 +777,9 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
 {
        int i;
        u8 *data;
-#ifdef NET_SKBUFF_DATA_USES_OFFSET
-       int size = nhead + skb->end + ntail;
-#else
-       int size = nhead + (skb->end - skb->head) + ntail;
-#endif
+       int size = nhead + (skb_end_pointer(skb) - skb->head) + ntail;
        long off;
+       bool fastpath;
 
        BUG_ON(nhead < 0);
 
@@ -810,23 +793,36 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
                goto nodata;
 
        /* Copy only real data... and, alas, header. This should be
-        * optimized for the cases when header is void. */
-#ifdef NET_SKBUFF_DATA_USES_OFFSET
-       memcpy(data + nhead, skb->head, skb->tail);
-#else
-       memcpy(data + nhead, skb->head, skb->tail - skb->head);
-#endif
-       memcpy(data + size, skb_end_pointer(skb),
+        * optimized for the cases when header is void.
+        */
+       memcpy(data + nhead, skb->head, skb_tail_pointer(skb) - skb->head);
+
+       memcpy((struct skb_shared_info *)(data + size),
+              skb_shinfo(skb),
               offsetof(struct skb_shared_info, frags[skb_shinfo(skb)->nr_frags]));
 
-       for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
-               get_page(skb_shinfo(skb)->frags[i].page);
+       /* Check if we can avoid taking references on fragments if we own
+        * the last reference on skb->head. (see skb_release_data())
+        */
+       if (!skb->cloned)
+               fastpath = true;
+       else {
+               int delta = skb->nohdr ? (1 << SKB_DATAREF_SHIFT) + 1 : 1;
 
-       if (skb_has_frags(skb))
-               skb_clone_fraglist(skb);
+               fastpath = atomic_read(&skb_shinfo(skb)->dataref) == delta;
+       }
 
-       skb_release_data(skb);
+       if (fastpath) {
+               kfree(skb->head);
+       } else {
+               for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
+                       get_page(skb_shinfo(skb)->frags[i].page);
 
+               if (skb_has_frag_list(skb))
+                       skb_clone_fraglist(skb);
+
+               skb_release_data(skb);
+       }
        off = (data + nhead) - skb->head;
 
        skb->head     = data;
@@ -1099,7 +1095,7 @@ drop_pages:
                for (; i < nfrags; i++)
                        put_page(skb_shinfo(skb)->frags[i].page);
 
-               if (skb_has_frags(skb))
+               if (skb_has_frag_list(skb))
                        skb_drop_fraglist(skb);
                goto done;
        }
@@ -1194,7 +1190,7 @@ unsigned char *__pskb_pull_tail(struct sk_buff *skb, int delta)
        /* Optimization: no fragments, no reasons to preestimate
         * size of pulled pages. Superb.
         */
-       if (!skb_has_frags(skb))
+       if (!skb_has_frag_list(skb))
                goto pull_pages;
 
        /* Estimate size of pulled pages. */
@@ -2323,7 +2319,7 @@ next_skb:
                st->frag_data = NULL;
        }
 
-       if (st->root_skb == st->cur_skb && skb_has_frags(st->root_skb)) {
+       if (st->root_skb == st->cur_skb && skb_has_frag_list(st->root_skb)) {
                st->cur_skb = skb_shinfo(st->root_skb)->frag_list;
                st->frag_idx = 0;
                goto next_skb;
@@ -2893,7 +2889,7 @@ int skb_cow_data(struct sk_buff *skb, int tailbits, struct sk_buff **trailer)
                return -ENOMEM;
 
        /* Easy case. Most of packets will go this way. */
-       if (!skb_has_frags(skb)) {
+       if (!skb_has_frag_list(skb)) {
                /* A little of trouble, not enough of space for trailer.
                 * This should not happen, when stack is tuned to generate
                 * good frames. OK, on miss we reallocate and reserve even more
@@ -2928,7 +2924,7 @@ int skb_cow_data(struct sk_buff *skb, int tailbits, struct sk_buff **trailer)
 
                if (skb1->next == NULL && tailbits) {
                        if (skb_shinfo(skb1)->nr_frags ||
-                           skb_has_frags(skb1) ||
+                           skb_has_frag_list(skb1) ||
                            skb_tailroom(skb1) < tailbits)
                                ntail = tailbits + 128;
                }
@@ -2937,7 +2933,7 @@ int skb_cow_data(struct sk_buff *skb, int tailbits, struct sk_buff **trailer)
                    skb_cloned(skb1) ||
                    ntail ||
                    skb_shinfo(skb1)->nr_frags ||
-                   skb_has_frags(skb1)) {
+                   skb_has_frag_list(skb1)) {
                        struct sk_buff *skb2;
 
                        /* Fuck, we are miserable poor guys... */
@@ -3020,7 +3016,7 @@ void skb_tstamp_tx(struct sk_buff *orig_skb,
        } else {
                /*
                 * no hardware time stamps available,
-                * so keep the skb_shared_tx and only
+                * so keep the shared tx_flags and only
                 * store software time stamp
                 */
                skb->tstamp = ktime_get_real();
index b05b9b6ddb8700989e63e8597f6946ffd205bdba..f3a06c40d5e023585852f3bf031c443a86cc5d7f 100644 (file)
@@ -1557,6 +1557,8 @@ struct sk_buff *sock_alloc_send_skb(struct sock *sk, unsigned long size,
 EXPORT_SYMBOL(sock_alloc_send_skb);
 
 static void __lock_sock(struct sock *sk)
+       __releases(&sk->sk_lock.slock)
+       __acquires(&sk->sk_lock.slock)
 {
        DEFINE_WAIT(wait);
 
@@ -1573,6 +1575,8 @@ static void __lock_sock(struct sock *sk)
 }
 
 static void __release_sock(struct sock *sk)
+       __releases(&sk->sk_lock.slock)
+       __acquires(&sk->sk_lock.slock)
 {
        struct sk_buff *skb = sk->sk_backlog.head;
 
index 8408398cd44e814cece7b9ec92615b1c615d32bd..0581143cb800d9b0b43bd86d0d2dcebf24abd3c1 100644 (file)
@@ -47,37 +47,6 @@ config IP_DCCP_CCID3_DEBUG
 
          If in doubt, say N.
 
-config IP_DCCP_CCID3_RTO
-         int "Use higher bound for nofeedback timer"
-         default 100
-         depends on IP_DCCP_CCID3 && EXPERIMENTAL
-         ---help---
-           Use higher lower bound for nofeedback timer expiration.
-
-           The TFRC nofeedback timer normally expires after the maximum of 4
-           RTTs and twice the current send interval (RFC 3448, 4.3). On LANs
-           with a small RTT this can mean a high processing load and reduced
-           performance, since then the nofeedback timer is triggered very
-           frequently.
-
-           This option enables to set a higher lower bound for the nofeedback
-           value. Values in units of milliseconds can be set here.
-
-           A value of 0 disables this feature by enforcing the value specified
-           in RFC 3448. The following values have been suggested as bounds for
-           experimental use:
-               * 16-20ms to match the typical multimedia inter-frame interval
-               * 100ms as a reasonable compromise [default]
-               * 1000ms corresponds to the lower TCP RTO bound (RFC 2988, 2.4)
-
-           The default of 100ms is a compromise between a large value for
-           efficient DCCP implementations, and a small value to avoid disrupting
-           the network in times of congestion.
-
-           The purpose of the nofeedback timer is to slow DCCP down when there
-           is serious network congestion: experimenting with larger values should
-           therefore not be performed on WANs.
-
 config IP_DCCP_TFRC_LIB
        def_bool y if IP_DCCP_CCID3
 
index 9b3ae9922be1aa446f8b57973356d216de9f82ee..dc18172b1e5911637ab47c83ade8b2425db358ef 100644 (file)
  */
 #include <linux/slab.h>
 #include "../feat.h"
-#include "../ccid.h"
-#include "../dccp.h"
 #include "ccid2.h"
 
 
 #ifdef CONFIG_IP_DCCP_CCID2_DEBUG
 static int ccid2_debug;
 #define ccid2_pr_debug(format, a...)   DCCP_PR_DEBUG(ccid2_debug, format, ##a)
-
-static void ccid2_hc_tx_check_sanity(const struct ccid2_hc_tx_sock *hc)
-{
-       int len = 0;
-       int pipe = 0;
-       struct ccid2_seq *seqp = hc->tx_seqh;
-
-       /* there is data in the chain */
-       if (seqp != hc->tx_seqt) {
-               seqp = seqp->ccid2s_prev;
-               len++;
-               if (!seqp->ccid2s_acked)
-                       pipe++;
-
-               while (seqp != hc->tx_seqt) {
-                       struct ccid2_seq *prev = seqp->ccid2s_prev;
-
-                       len++;
-                       if (!prev->ccid2s_acked)
-                               pipe++;
-
-                       /* packets are sent sequentially */
-                       BUG_ON(dccp_delta_seqno(seqp->ccid2s_seq,
-                                               prev->ccid2s_seq ) >= 0);
-                       BUG_ON(time_before(seqp->ccid2s_sent,
-                                          prev->ccid2s_sent));
-
-                       seqp = prev;
-               }
-       }
-
-       BUG_ON(pipe != hc->tx_pipe);
-       ccid2_pr_debug("len of chain=%d\n", len);
-
-       do {
-               seqp = seqp->ccid2s_prev;
-               len++;
-       } while (seqp != hc->tx_seqh);
-
-       ccid2_pr_debug("total len=%d\n", len);
-       BUG_ON(len != hc->tx_seqbufc * CCID2_SEQBUF_LEN);
-}
 #else
 #define ccid2_pr_debug(format, a...)
-#define ccid2_hc_tx_check_sanity(hc)
 #endif
 
 static int ccid2_hc_tx_alloc_seq(struct ccid2_hc_tx_sock *hc)
@@ -156,19 +111,10 @@ static void ccid2_change_l_ack_ratio(struct sock *sk, u32 val)
        dp->dccps_l_ack_ratio = val;
 }
 
-static void ccid2_change_srtt(struct ccid2_hc_tx_sock *hc, long val)
-{
-       ccid2_pr_debug("change SRTT to %ld\n", val);
-       hc->tx_srtt = val;
-}
-
-static void ccid2_start_rto_timer(struct sock *sk);
-
 static void ccid2_hc_tx_rto_expire(unsigned long data)
 {
        struct sock *sk = (struct sock *)data;
        struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk);
-       long s;
 
        bh_lock_sock(sk);
        if (sock_owned_by_user(sk)) {
@@ -178,23 +124,19 @@ static void ccid2_hc_tx_rto_expire(unsigned long data)
 
        ccid2_pr_debug("RTO_EXPIRE\n");
 
-       ccid2_hc_tx_check_sanity(hc);
-
        /* back-off timer */
        hc->tx_rto <<= 1;
+       if (hc->tx_rto > DCCP_RTO_MAX)
+               hc->tx_rto = DCCP_RTO_MAX;
 
-       s = hc->tx_rto / HZ;
-       if (s > 60)
-               hc->tx_rto = 60 * HZ;
-
-       ccid2_start_rto_timer(sk);
+       sk_reset_timer(sk, &hc->tx_rtotimer, jiffies + hc->tx_rto);
 
        /* adjust pipe, cwnd etc */
        hc->tx_ssthresh = hc->tx_cwnd / 2;
        if (hc->tx_ssthresh < 2)
                hc->tx_ssthresh = 2;
-       hc->tx_cwnd      = 1;
-       hc->tx_pipe      = 0;
+       hc->tx_cwnd     = 1;
+       hc->tx_pipe     = 0;
 
        /* clear state about stuff we sent */
        hc->tx_seqt = hc->tx_seqh;
@@ -204,22 +146,11 @@ static void ccid2_hc_tx_rto_expire(unsigned long data)
        hc->tx_rpseq    = 0;
        hc->tx_rpdupack = -1;
        ccid2_change_l_ack_ratio(sk, 1);
-       ccid2_hc_tx_check_sanity(hc);
 out:
        bh_unlock_sock(sk);
        sock_put(sk);
 }
 
-static void ccid2_start_rto_timer(struct sock *sk)
-{
-       struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk);
-
-       ccid2_pr_debug("setting RTO timeout=%ld\n", hc->tx_rto);
-
-       BUG_ON(timer_pending(&hc->tx_rtotimer));
-       sk_reset_timer(sk, &hc->tx_rtotimer, jiffies + hc->tx_rto);
-}
-
 static void ccid2_hc_tx_packet_sent(struct sock *sk, int more, unsigned int len)
 {
        struct dccp_sock *dp = dccp_sk(sk);
@@ -230,7 +161,7 @@ static void ccid2_hc_tx_packet_sent(struct sock *sk, int more, unsigned int len)
 
        hc->tx_seqh->ccid2s_seq   = dp->dccps_gss;
        hc->tx_seqh->ccid2s_acked = 0;
-       hc->tx_seqh->ccid2s_sent  = jiffies;
+       hc->tx_seqh->ccid2s_sent  = ccid2_time_stamp;
 
        next = hc->tx_seqh->ccid2s_next;
        /* check if we need to alloc more space */
@@ -296,23 +227,20 @@ static void ccid2_hc_tx_packet_sent(struct sock *sk, int more, unsigned int len)
        }
 #endif
 
-       /* setup RTO timer */
-       if (!timer_pending(&hc->tx_rtotimer))
-               ccid2_start_rto_timer(sk);
+       sk_reset_timer(sk, &hc->tx_rtotimer, jiffies + hc->tx_rto);
 
 #ifdef CONFIG_IP_DCCP_CCID2_DEBUG
        do {
                struct ccid2_seq *seqp = hc->tx_seqt;
 
                while (seqp != hc->tx_seqh) {
-                       ccid2_pr_debug("out seq=%llu acked=%d time=%lu\n",
+                       ccid2_pr_debug("out seq=%llu acked=%d time=%u\n",
                                       (unsigned long long)seqp->ccid2s_seq,
                                       seqp->ccid2s_acked, seqp->ccid2s_sent);
                        seqp = seqp->ccid2s_next;
                }
        } while (0);
        ccid2_pr_debug("=========\n");
-       ccid2_hc_tx_check_sanity(hc);
 #endif
 }
 
@@ -378,17 +306,87 @@ out_invalid_option:
        return -1;
 }
 
-static void ccid2_hc_tx_kill_rto_timer(struct sock *sk)
+/**
+ * ccid2_rtt_estimator - Sample RTT and compute RTO using RFC2988 algorithm
+ * This code is almost identical with TCP's tcp_rtt_estimator(), since
+ * - it has a higher sampling frequency (recommended by RFC 1323),
+ * - the RTO does not collapse into RTT due to RTTVAR going towards zero,
+ * - it is simple (cf. more complex proposals such as Eifel timer or research
+ *   which suggests that the gain should be set according to window size),
+ * - in tests it was found to work well with CCID2 [gerrit].
+ */
+static void ccid2_rtt_estimator(struct sock *sk, const long mrtt)
 {
        struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk);
+       long m = mrtt ? : 1;
 
-       sk_stop_timer(sk, &hc->tx_rtotimer);
-       ccid2_pr_debug("deleted RTO timer\n");
+       if (hc->tx_srtt == 0) {
+               /* First measurement m */
+               hc->tx_srtt = m << 3;
+               hc->tx_mdev = m << 1;
+
+               hc->tx_mdev_max = max(hc->tx_mdev, tcp_rto_min(sk));
+               hc->tx_rttvar   = hc->tx_mdev_max;
+
+               hc->tx_rtt_seq  = dccp_sk(sk)->dccps_gss;
+       } else {
+               /* Update scaled SRTT as SRTT += 1/8 * (m - SRTT) */
+               m -= (hc->tx_srtt >> 3);
+               hc->tx_srtt += m;
+
+               /* Similarly, update scaled mdev with regard to |m| */
+               if (m < 0) {
+                       m = -m;
+                       m -= (hc->tx_mdev >> 2);
+                       /*
+                        * This neutralises RTO increase when RTT < SRTT - mdev
+                        * (see P. Sarolahti, A. Kuznetsov,"Congestion Control
+                        * in Linux TCP", USENIX 2002, pp. 49-62).
+                        */
+                       if (m > 0)
+                               m >>= 3;
+               } else {
+                       m -= (hc->tx_mdev >> 2);
+               }
+               hc->tx_mdev += m;
+
+               if (hc->tx_mdev > hc->tx_mdev_max) {
+                       hc->tx_mdev_max = hc->tx_mdev;
+                       if (hc->tx_mdev_max > hc->tx_rttvar)
+                               hc->tx_rttvar = hc->tx_mdev_max;
+               }
+
+               /*
+                * Decay RTTVAR at most once per flight, exploiting that
+                *  1) pipe <= cwnd <= Sequence_Window = W  (RFC 4340, 7.5.2)
+                *  2) AWL = GSS-W+1 <= GAR <= GSS          (RFC 4340, 7.5.1)
+                * GAR is a useful bound for FlightSize = pipe.
+                * AWL is probably too low here, as it over-estimates pipe.
+                */
+               if (after48(dccp_sk(sk)->dccps_gar, hc->tx_rtt_seq)) {
+                       if (hc->tx_mdev_max < hc->tx_rttvar)
+                               hc->tx_rttvar -= (hc->tx_rttvar -
+                                                 hc->tx_mdev_max) >> 2;
+                       hc->tx_rtt_seq  = dccp_sk(sk)->dccps_gss;
+                       hc->tx_mdev_max = tcp_rto_min(sk);
+               }
+       }
+
+       /*
+        * Set RTO from SRTT and RTTVAR
+        * As in TCP, 4 * RTTVAR >= TCP_RTO_MIN, giving a minimum RTO of 200 ms.
+        * This agrees with RFC 4341, 5:
+        *      "Because DCCP does not retransmit data, DCCP does not require
+        *       TCP's recommended minimum timeout of one second".
+        */
+       hc->tx_rto = (hc->tx_srtt >> 3) + hc->tx_rttvar;
+
+       if (hc->tx_rto > DCCP_RTO_MAX)
+               hc->tx_rto = DCCP_RTO_MAX;
 }
 
-static inline void ccid2_new_ack(struct sock *sk,
-                                struct ccid2_seq *seqp,
-                                unsigned int *maxincr)
+static void ccid2_new_ack(struct sock *sk, struct ccid2_seq *seqp,
+                         unsigned int *maxincr)
 {
        struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk);
 
@@ -402,93 +400,27 @@ static inline void ccid2_new_ack(struct sock *sk,
                        hc->tx_cwnd += 1;
                        hc->tx_packets_acked = 0;
        }
-
-       /* update RTO */
-       if (hc->tx_srtt == -1 ||
-           time_after(jiffies, hc->tx_lastrtt + hc->tx_srtt)) {
-               unsigned long r = (long)jiffies - (long)seqp->ccid2s_sent;
-               int s;
-
-               /* first measurement */
-               if (hc->tx_srtt == -1) {
-                       ccid2_pr_debug("R: %lu Time=%lu seq=%llu\n",
-                                      r, jiffies,
-                                      (unsigned long long)seqp->ccid2s_seq);
-                       ccid2_change_srtt(hc, r);
-                       hc->tx_rttvar = r >> 1;
-               } else {
-                       /* RTTVAR */
-                       long tmp = hc->tx_srtt - r;
-                       long srtt;
-
-                       if (tmp < 0)
-                               tmp *= -1;
-
-                       tmp >>= 2;
-                       hc->tx_rttvar *= 3;
-                       hc->tx_rttvar >>= 2;
-                       hc->tx_rttvar += tmp;
-
-                       /* SRTT */
-                       srtt = hc->tx_srtt;
-                       srtt *= 7;
-                       srtt >>= 3;
-                       tmp = r >> 3;
-                       srtt += tmp;
-                       ccid2_change_srtt(hc, srtt);
-               }
-               s = hc->tx_rttvar << 2;
-               /* clock granularity is 1 when based on jiffies */
-               if (!s)
-                       s = 1;
-               hc->tx_rto = hc->tx_srtt + s;
-
-               /* must be at least a second */
-               s = hc->tx_rto / HZ;
-               /* DCCP doesn't require this [but I like it cuz my code sux] */
-#if 1
-               if (s < 1)
-                       hc->tx_rto = HZ;
-#endif
-               /* max 60 seconds */
-               if (s > 60)
-                       hc->tx_rto = HZ * 60;
-
-               hc->tx_lastrtt = jiffies;
-
-               ccid2_pr_debug("srtt: %ld rttvar: %ld rto: %ld (HZ=%d) R=%lu\n",
-                              hc->tx_srtt, hc->tx_rttvar,
-                              hc->tx_rto, HZ, r);
-       }
-
-       /* we got a new ack, so re-start RTO timer */
-       ccid2_hc_tx_kill_rto_timer(sk);
-       ccid2_start_rto_timer(sk);
-}
-
-static void ccid2_hc_tx_dec_pipe(struct sock *sk)
-{
-       struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk);
-
-       if (hc->tx_pipe == 0)
-               DCCP_BUG("pipe == 0");
-       else
-               hc->tx_pipe--;
-
-       if (hc->tx_pipe == 0)
-               ccid2_hc_tx_kill_rto_timer(sk);
+       /*
+        * FIXME: RTT is sampled several times per acknowledgment (for each
+        * entry in the Ack Vector), instead of once per Ack (as in TCP SACK).
+        * This causes the RTT to be over-estimated, since the older entries
+        * in the Ack Vector have earlier sending times.
+        * The cleanest solution is to not use the ccid2s_sent field at all
+        * and instead use DCCP timestamps: requires changes in other places.
+        */
+       ccid2_rtt_estimator(sk, ccid2_time_stamp - seqp->ccid2s_sent);
 }
 
 static void ccid2_congestion_event(struct sock *sk, struct ccid2_seq *seqp)
 {
        struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk);
 
-       if (time_before(seqp->ccid2s_sent, hc->tx_last_cong)) {
+       if ((s32)(seqp->ccid2s_sent - hc->tx_last_cong) < 0) {
                ccid2_pr_debug("Multiple losses in an RTT---treating as one\n");
                return;
        }
 
-       hc->tx_last_cong = jiffies;
+       hc->tx_last_cong = ccid2_time_stamp;
 
        hc->tx_cwnd      = hc->tx_cwnd / 2 ? : 1U;
        hc->tx_ssthresh  = max(hc->tx_cwnd, 2U);
@@ -510,7 +442,6 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
        int done = 0;
        unsigned int maxincr = 0;
 
-       ccid2_hc_tx_check_sanity(hc);
        /* check reverse path congestion */
        seqno = DCCP_SKB_CB(skb)->dccpd_seq;
 
@@ -620,7 +551,7 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
                                        seqp->ccid2s_acked = 1;
                                        ccid2_pr_debug("Got ack for %llu\n",
                                                       (unsigned long long)seqp->ccid2s_seq);
-                                       ccid2_hc_tx_dec_pipe(sk);
+                                       hc->tx_pipe--;
                                }
                                if (seqp == hc->tx_seqt) {
                                        done = 1;
@@ -677,7 +608,7 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
                                 * one ack vector.
                                 */
                                ccid2_congestion_event(sk, seqp);
-                               ccid2_hc_tx_dec_pipe(sk);
+                               hc->tx_pipe--;
                        }
                        if (seqp == hc->tx_seqt)
                                break;
@@ -695,7 +626,11 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
                hc->tx_seqt = hc->tx_seqt->ccid2s_next;
        }
 
-       ccid2_hc_tx_check_sanity(hc);
+       /* restart RTO timer if not all outstanding data has been acked */
+       if (hc->tx_pipe == 0)
+               sk_stop_timer(sk, &hc->tx_rtotimer);
+       else
+               sk_reset_timer(sk, &hc->tx_rtotimer, jiffies + hc->tx_rto);
 }
 
 static int ccid2_hc_tx_init(struct ccid *ccid, struct sock *sk)
@@ -707,12 +642,8 @@ static int ccid2_hc_tx_init(struct ccid *ccid, struct sock *sk)
        /* RFC 4341, 5: initialise ssthresh to arbitrarily high (max) value */
        hc->tx_ssthresh = ~0U;
 
-       /*
-        * RFC 4341, 5: "The cwnd parameter is initialized to at most four
-        * packets for new connections, following the rules from [RFC3390]".
-        * We need to convert the bytes of RFC3390 into the packets of RFC 4341.
-        */
-       hc->tx_cwnd = clamp(4380U / dp->dccps_mss_cache, 2U, 4U);
+       /* Use larger initial windows (RFC 4341, section 5). */
+       hc->tx_cwnd = rfc3390_bytes_to_packets(dp->dccps_mss_cache);
 
        /* Make sure that Ack Ratio is enabled and within bounds. */
        max_ratio = DIV_ROUND_UP(hc->tx_cwnd, 2);
@@ -723,15 +654,11 @@ static int ccid2_hc_tx_init(struct ccid *ccid, struct sock *sk)
        if (ccid2_hc_tx_alloc_seq(hc))
                return -ENOMEM;
 
-       hc->tx_rto       = 3 * HZ;
-       ccid2_change_srtt(hc, -1);
-       hc->tx_rttvar    = -1;
+       hc->tx_rto       = DCCP_TIMEOUT_INIT;
        hc->tx_rpdupack  = -1;
-       hc->tx_last_cong = jiffies;
+       hc->tx_last_cong = ccid2_time_stamp;
        setup_timer(&hc->tx_rtotimer, ccid2_hc_tx_rto_expire,
                        (unsigned long)sk);
-
-       ccid2_hc_tx_check_sanity(hc);
        return 0;
 }
 
@@ -740,7 +667,7 @@ static void ccid2_hc_tx_exit(struct sock *sk)
        struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk);
        int i;
 
-       ccid2_hc_tx_kill_rto_timer(sk);
+       sk_stop_timer(sk, &hc->tx_rtotimer);
 
        for (i = 0; i < hc->tx_seqbufc; i++)
                kfree(hc->tx_seqbuf[i]);
index 1ec6a30103bbb3247b0a25385ab8aa318899ccc7..9731c2dc148715eacace932c37f695989f526450 100644 (file)
 #ifndef _DCCP_CCID2_H_
 #define _DCCP_CCID2_H_
 
-#include <linux/dccp.h>
 #include <linux/timer.h>
 #include <linux/types.h>
 #include "../ccid.h"
+#include "../dccp.h"
+
+/*
+ * CCID-2 timestamping faces the same issues as TCP timestamping.
+ * Hence we reuse/share as much of the code as possible.
+ */
+#define ccid2_time_stamp       tcp_time_stamp
+
 /* NUMDUPACK parameter from RFC 4341, p. 6 */
 #define NUMDUPACK      3
 
-struct sock;
-
 struct ccid2_seq {
        u64                     ccid2s_seq;
-       unsigned long           ccid2s_sent;
+       u32                     ccid2s_sent;
        int                     ccid2s_acked;
        struct ccid2_seq        *ccid2s_prev;
        struct ccid2_seq        *ccid2s_next;
@@ -42,7 +47,12 @@ struct ccid2_seq {
  * struct ccid2_hc_tx_sock - CCID2 TX half connection
  * @tx_{cwnd,ssthresh,pipe}: as per RFC 4341, section 5
  * @tx_packets_acked:       Ack counter for deriving cwnd growth (RFC 3465)
- * @tx_lastrtt:                     time RTT was last measured
+ * @tx_srtt:                smoothed RTT estimate, scaled by 2^3
+ * @tx_mdev:                smoothed RTT variation, scaled by 2^2
+ * @tx_mdev_max:            maximum of @mdev during one flight
+ * @tx_rttvar:              moving average/maximum of @mdev_max
+ * @tx_rto:                 RTO value deriving from SRTT and RTTVAR (RFC 2988)
+ * @tx_rtt_seq:                     to decay RTTVAR at most once per flight
  * @tx_rpseq:               last consecutive seqno
  * @tx_rpdupack:            dupacks since rpseq
  */
@@ -55,14 +65,19 @@ struct ccid2_hc_tx_sock {
        int                     tx_seqbufc;
        struct ccid2_seq        *tx_seqh;
        struct ccid2_seq        *tx_seqt;
-       long                    tx_rto;
-       long                    tx_srtt;
-       long                    tx_rttvar;
-       unsigned long           tx_lastrtt;
+
+       /* RTT measurement: variables/principles are the same as in TCP */
+       u32                     tx_srtt,
+                               tx_mdev,
+                               tx_mdev_max,
+                               tx_rttvar,
+                               tx_rto;
+       u64                     tx_rtt_seq:48;
        struct timer_list       tx_rtotimer;
+
        u64                     tx_rpseq;
        int                     tx_rpdupack;
-       unsigned long           tx_last_cong;
+       u32                     tx_last_cong;
        u64                     tx_high_ack;
 };
 
index 95f7529864972aa34be0ba8ab3fd66b6eb640e47..278e170693229c7d0cc2af20ad6f6f1e8d9fe56c 100644 (file)
@@ -218,9 +218,9 @@ static void ccid3_hc_tx_no_feedback_timer(unsigned long data)
 
        /*
         * Determine new allowed sending rate X as per draft rfc3448bis-00, 4.4
+        * RTO is 0 if and only if no feedback has been received yet.
         */
-       if (hc->tx_t_rto == 0 ||        /* no feedback received yet */
-           hc->tx_p == 0) {
+       if (hc->tx_t_rto == 0 || hc->tx_p == 0) {
 
                /* halve send rate directly */
                hc->tx_x = max(hc->tx_x / 2,
@@ -256,7 +256,7 @@ static void ccid3_hc_tx_no_feedback_timer(unsigned long data)
         * Set new timeout for the nofeedback timer.
         * See comments in packet_recv() regarding the value of t_RTO.
         */
-       if (unlikely(hc->tx_t_rto == 0))        /* no feedback yet */
+       if (unlikely(hc->tx_t_rto == 0))        /* no feedback received yet */
                t_nfb = TFRC_INITIAL_TIMEOUT;
        else
                t_nfb = max(hc->tx_t_rto, 2 * hc->tx_t_ipi);
@@ -372,7 +372,7 @@ static void ccid3_hc_tx_packet_sent(struct sock *sk, int more,
 static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
 {
        struct ccid3_hc_tx_sock *hc = ccid3_hc_tx_sk(sk);
-       struct ccid3_options_received *opt_recv;
+       struct ccid3_options_received *opt_recv = &hc->tx_options_received;
        ktime_t now;
        unsigned long t_nfb;
        u32 pinv, r_sample;
@@ -386,7 +386,6 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
            hc->tx_state != TFRC_SSTATE_NO_FBACK)
                return;
 
-       opt_recv = &hc->tx_options_received;
        now = ktime_get_real();
 
        /* Estimate RTT from history if ACK number is valid */
@@ -461,13 +460,12 @@ done_computing_x:
        sk->sk_write_space(sk);
 
        /*
-        * Update timeout interval for the nofeedback timer.
-        * We use a configuration option to increase the lower bound.
-        * This can help avoid triggering the nofeedback timer too
-        * often ('spinning') on LANs with small RTTs.
+        * Update timeout interval for the nofeedback timer. In order to control
+        * rate halving on networks with very low RTTs (<= 1 ms), use per-route
+        * tunable RTAX_RTO_MIN value as the lower bound.
         */
-       hc->tx_t_rto = max_t(u32, 4 * hc->tx_rtt, (CONFIG_IP_DCCP_CCID3_RTO *
-                                                      (USEC_PER_SEC / 1000)));
+       hc->tx_t_rto = max_t(u32, 4 * hc->tx_rtt,
+                                 USEC_PER_SEC/HZ * tcp_rto_min(sk));
        /*
         * Schedule no feedback timer to expire in
         * max(t_RTO, 2 * s/X)  =  max(t_RTO, 2 * t_ipi)
@@ -489,11 +487,9 @@ static int ccid3_hc_tx_parse_options(struct sock *sk, unsigned char option,
        int rc = 0;
        const struct dccp_sock *dp = dccp_sk(sk);
        struct ccid3_hc_tx_sock *hc = ccid3_hc_tx_sk(sk);
-       struct ccid3_options_received *opt_recv;
+       struct ccid3_options_received *opt_recv = &hc->tx_options_received;
        __be32 opt_val;
 
-       opt_recv = &hc->tx_options_received;
-
        if (opt_recv->ccid3or_seqno != dp->dccps_gsr) {
                opt_recv->ccid3or_seqno              = dp->dccps_gsr;
                opt_recv->ccid3or_loss_event_rate    = ~0;
@@ -567,34 +563,30 @@ static void ccid3_hc_tx_exit(struct sock *sk)
 
 static void ccid3_hc_tx_get_info(struct sock *sk, struct tcp_info *info)
 {
-       struct ccid3_hc_tx_sock *hc;
-
-       /* Listen socks doesn't have a private CCID block */
-       if (sk->sk_state == DCCP_LISTEN)
-               return;
-
-       hc = ccid3_hc_tx_sk(sk);
-       info->tcpi_rto = hc->tx_t_rto;
-       info->tcpi_rtt = hc->tx_rtt;
+       info->tcpi_rto = ccid3_hc_tx_sk(sk)->tx_t_rto;
+       info->tcpi_rtt = ccid3_hc_tx_sk(sk)->tx_rtt;
 }
 
 static int ccid3_hc_tx_getsockopt(struct sock *sk, const int optname, int len,
                                  u32 __user *optval, int __user *optlen)
 {
-       const struct ccid3_hc_tx_sock *hc;
+       const struct ccid3_hc_tx_sock *hc = ccid3_hc_tx_sk(sk);
+       struct tfrc_tx_info tfrc;
        const void *val;
 
-       /* Listen socks doesn't have a private CCID block */
-       if (sk->sk_state == DCCP_LISTEN)
-               return -EINVAL;
-
-       hc = ccid3_hc_tx_sk(sk);
        switch (optname) {
        case DCCP_SOCKOPT_CCID_TX_INFO:
-               if (len < sizeof(hc->tx_tfrc))
+               if (len < sizeof(tfrc))
                        return -EINVAL;
-               len = sizeof(hc->tx_tfrc);
-               val = &hc->tx_tfrc;
+               tfrc.tfrctx_x      = hc->tx_x;
+               tfrc.tfrctx_x_recv = hc->tx_x_recv;
+               tfrc.tfrctx_x_calc = hc->tx_x_calc;
+               tfrc.tfrctx_rtt    = hc->tx_rtt;
+               tfrc.tfrctx_p      = hc->tx_p;
+               tfrc.tfrctx_rto    = hc->tx_t_rto;
+               tfrc.tfrctx_ipi    = hc->tx_t_ipi;
+               len = sizeof(tfrc);
+               val = &tfrc;
                break;
        default:
                return -ENOPROTOOPT;
@@ -701,14 +693,12 @@ static void ccid3_hc_rx_send_feedback(struct sock *sk,
 
 static int ccid3_hc_rx_insert_options(struct sock *sk, struct sk_buff *skb)
 {
-       const struct ccid3_hc_rx_sock *hc;
+       const struct ccid3_hc_rx_sock *hc = ccid3_hc_rx_sk(sk);
        __be32 x_recv, pinv;
 
        if (!(sk->sk_state == DCCP_OPEN || sk->sk_state == DCCP_PARTOPEN))
                return 0;
 
-       hc = ccid3_hc_rx_sk(sk);
-
        if (dccp_packet_without_ack(skb))
                return 0;
 
@@ -749,10 +739,11 @@ static u32 ccid3_first_li(struct sock *sk)
        x_recv = scaled_div32(hc->rx_bytes_recv, delta);
        if (x_recv == 0) {              /* would also trigger divide-by-zero */
                DCCP_WARN("X_recv==0\n");
-               if ((x_recv = hc->rx_x_recv) == 0) {
+               if (hc->rx_x_recv == 0) {
                        DCCP_BUG("stored value of X_recv is zero");
                        return ~0U;
                }
+               x_recv = hc->rx_x_recv;
        }
 
        fval = scaled_div(hc->rx_s, hc->rx_rtt);
@@ -870,30 +861,18 @@ static void ccid3_hc_rx_exit(struct sock *sk)
 
 static void ccid3_hc_rx_get_info(struct sock *sk, struct tcp_info *info)
 {
-       const struct ccid3_hc_rx_sock *hc;
-
-       /* Listen socks doesn't have a private CCID block */
-       if (sk->sk_state == DCCP_LISTEN)
-               return;
-
-       hc = ccid3_hc_rx_sk(sk);
-       info->tcpi_ca_state = hc->rx_state;
+       info->tcpi_ca_state = ccid3_hc_rx_sk(sk)->rx_state;
        info->tcpi_options  |= TCPI_OPT_TIMESTAMPS;
-       info->tcpi_rcv_rtt  = hc->rx_rtt;
+       info->tcpi_rcv_rtt  = ccid3_hc_rx_sk(sk)->rx_rtt;
 }
 
 static int ccid3_hc_rx_getsockopt(struct sock *sk, const int optname, int len,
                                  u32 __user *optval, int __user *optlen)
 {
-       const struct ccid3_hc_rx_sock *hc;
+       const struct ccid3_hc_rx_sock *hc = ccid3_hc_rx_sk(sk);
        struct tfrc_rx_info rx_info;
        const void *val;
 
-       /* Listen socks doesn't have a private CCID block */
-       if (sk->sk_state == DCCP_LISTEN)
-               return -EINVAL;
-
-       hc = ccid3_hc_rx_sk(sk);
        switch (optname) {
        case DCCP_SOCKOPT_CCID_RX_INFO:
                if (len < sizeof(rx_info))
index 03263577665323894733d7d59febb18b556fa49d..b7e569c22f3658f4c9366982902d05a43236a907 100644 (file)
@@ -42,7 +42,7 @@
 #include "lib/tfrc.h"
 #include "../ccid.h"
 
-/* Two seconds as per RFC 3448 4.2 */
+/* Two seconds as per RFC 5348, 4.2 */
 #define TFRC_INITIAL_TIMEOUT      (2 * USEC_PER_SEC)
 
 /* In usecs - half the scheduling granularity as per RFC3448 4.6 */
@@ -95,14 +95,13 @@ enum ccid3_hc_tx_states {
  * @tx_options_received:  Parsed set of retrieved options
  */
 struct ccid3_hc_tx_sock {
-       struct tfrc_tx_info             tx_tfrc;
-#define tx_x                           tx_tfrc.tfrctx_x
-#define tx_x_recv                      tx_tfrc.tfrctx_x_recv
-#define tx_x_calc                      tx_tfrc.tfrctx_x_calc
-#define tx_rtt                         tx_tfrc.tfrctx_rtt
-#define tx_p                           tx_tfrc.tfrctx_p
-#define tx_t_rto                       tx_tfrc.tfrctx_rto
-#define tx_t_ipi                       tx_tfrc.tfrctx_ipi
+       u64                             tx_x;
+       u64                             tx_x_recv;
+       u32                             tx_x_calc;
+       u32                             tx_rtt;
+       u32                             tx_p;
+       u32                             tx_t_rto;
+       u32                             tx_t_ipi;
        u16                             tx_s;
        enum ccid3_hc_tx_states         tx_state:8;
        u8                              tx_last_win_count;
@@ -131,16 +130,12 @@ enum ccid3_hc_rx_states {
 
 /**
  * struct ccid3_hc_rx_sock - CCID3 receiver half-connection socket
- * @rx_x_recv:              Receiver estimate of send rate (RFC 3448 4.3)
- * @rx_rtt:                 Receiver estimate of rtt (non-standard)
- * @rx_p:                   Current loss event rate (RFC 3448 5.4)
  * @rx_last_counter:        Tracks window counter (RFC 4342, 8.1)
  * @rx_state:               Receiver state, one of %ccid3_hc_rx_states
  * @rx_bytes_recv:          Total sum of DCCP payload bytes
  * @rx_x_recv:              Receiver estimate of send rate (RFC 3448, sec. 4.3)
  * @rx_rtt:                 Receiver estimate of RTT
  * @rx_tstamp_last_feedback: Time at which last feedback was sent
- * @rx_tstamp_last_ack:             Time at which last feedback was sent
  * @rx_hist:                Packet history (loss detection + RTT sampling)
  * @rx_li_hist:                     Loss Interval database
  * @rx_s:                   Received packet size in bytes
index baeb1eaf011be83a0dff59717f54e30241e4f0ad..2ef115277bea86a68e644a6c004690ccdb807184 100644 (file)
@@ -693,22 +693,22 @@ void dn_nsp_send_conninit(struct sock *sk, unsigned char msgflg)
        aux = scp->accessdata.acc_userl;
        *skb_put(skb, 1) = aux;
        if (aux > 0)
-       memcpy(skb_put(skb, aux), scp->accessdata.acc_user, aux);
+               memcpy(skb_put(skb, aux), scp->accessdata.acc_user, aux);
 
        aux = scp->accessdata.acc_passl;
        *skb_put(skb, 1) = aux;
        if (aux > 0)
-       memcpy(skb_put(skb, aux), scp->accessdata.acc_pass, aux);
+               memcpy(skb_put(skb, aux), scp->accessdata.acc_pass, aux);
 
        aux = scp->accessdata.acc_accl;
        *skb_put(skb, 1) = aux;
        if (aux > 0)
-       memcpy(skb_put(skb, aux), scp->accessdata.acc_acc, aux);
+               memcpy(skb_put(skb, aux), scp->accessdata.acc_acc, aux);
 
        aux = (__u8)le16_to_cpu(scp->conndata_out.opt_optl);
        *skb_put(skb, 1) = aux;
        if (aux > 0)
-       memcpy(skb_put(skb,aux), scp->conndata_out.opt_data, aux);
+               memcpy(skb_put(skb, aux), scp->conndata_out.opt_data, aux);
 
        scp->persist = dn_nsp_persist(sk);
        scp->persist_fxn = dn_nsp_retrans_conninit;
index dc54bd0d083ba63f9cdec105d38d05d304007357..baa98fb835524a5127a62b538a1a378a2bb960b6 100644 (file)
@@ -1009,7 +1009,6 @@ static int __init aun_udp_initialise(void)
        struct sockaddr_in sin;
 
        skb_queue_head_init(&aun_queue);
-       spin_lock_init(&aun_queue_lock);
        setup_timer(&ab_cleanup_timer, ab_cleanup, 0);
        ab_cleanup_timer.expires = jiffies + (HZ*2);
        add_timer(&ab_cleanup_timer);
@@ -1167,7 +1166,6 @@ static int __init econet_proto_init(void)
                goto out;
        sock_register(&econet_family_ops);
 #ifdef CONFIG_ECONET_AUNUDP
-       spin_lock_init(&aun_queue_lock);
        aun_udp_initialise();
 #endif
 #ifdef CONFIG_ECONET_NATIVE
index 215c83986a9d4562f472a07e05bbbf607c56bbb0..85e7b45513268e6e673920b4e832b1c52924e0df 100644 (file)
@@ -367,7 +367,7 @@ struct net_device *alloc_etherdev_mq(int sizeof_priv, unsigned int queue_count)
 EXPORT_SYMBOL(alloc_etherdev_mq);
 
 static size_t _format_mac_addr(char *buf, int buflen,
-                               const unsigned char *addr, int len)
+                              const unsigned char *addr, int len)
 {
        int i;
        char *cp = buf;
@@ -376,7 +376,7 @@ static size_t _format_mac_addr(char *buf, int buflen,
                cp += scnprintf(cp, buflen - (cp - buf), "%02x", addr[i]);
                if (i == len - 1)
                        break;
-               cp += strlcpy(cp, ":", buflen - (cp - buf));
+               cp += scnprintf(cp, buflen - (cp - buf), ":");
        }
        return cp - buf;
 }
@@ -386,7 +386,7 @@ ssize_t sysfs_format_mac(char *buf, const unsigned char *addr, int len)
        size_t l;
 
        l = _format_mac_addr(buf, PAGE_SIZE, addr, len);
-       l += strlcpy(buf + l, "\n", PAGE_SIZE - l);
+       l += scnprintf(buf + l, PAGE_SIZE - l, "\n");
        return ((ssize_t) l);
 }
 EXPORT_SYMBOL(sysfs_format_mac);
index 571f8950ed06f585f4dca482037d4b7985c256af..5462e2d147a690b69e780c5c161427e6a5f745f8 100644 (file)
@@ -215,8 +215,15 @@ config NET_IPIP
          be inserted in and removed from the running kernel whenever you
          want). Most people won't need this and can say N.
 
+config NET_IPGRE_DEMUX
+       tristate "IP: GRE demultiplexer"
+       help
+        This is helper module to demultiplex GRE packets on GRE version field criteria.
+        Required by ip_gre and pptp modules.
+
 config NET_IPGRE
        tristate "IP: GRE tunnels over IP"
+       depends on NET_IPGRE_DEMUX
        help
          Tunneling means encapsulating data of one protocol type within
          another protocol and sending it over a channel that understands the
index 80ff87ce43aac6a350bbe8e973f91e8eb58e14e9..4978d22f9a75eafe3fe10d8cf93f6e8a2a7f647a 100644 (file)
@@ -20,6 +20,7 @@ obj-$(CONFIG_PROC_FS) += proc.o
 obj-$(CONFIG_IP_MULTIPLE_TABLES) += fib_rules.o
 obj-$(CONFIG_IP_MROUTE) += ipmr.o
 obj-$(CONFIG_NET_IPIP) += ipip.o
+obj-$(CONFIG_NET_IPGRE_DEMUX) += gre.o
 obj-$(CONFIG_NET_IPGRE) += ip_gre.o
 obj-$(CONFIG_SYN_COOKIES) += syncookies.o
 obj-$(CONFIG_INET_AH) += ah4.o
index 6a1100c25a9f881f204934b1687b422384527f9a..f581f77d1097ca140c74e93072113d88ae0cc9bc 100644 (file)
@@ -227,18 +227,16 @@ EXPORT_SYMBOL(inet_ehash_secret);
 
 /*
  * inet_ehash_secret must be set exactly once
- * Instead of using a dedicated spinlock, we (ab)use inetsw_lock
  */
 void build_ehash_secret(void)
 {
        u32 rnd;
+
        do {
                get_random_bytes(&rnd, sizeof(rnd));
        } while (rnd == 0);
-       spin_lock_bh(&inetsw_lock);
-       if (!inet_ehash_secret)
-               inet_ehash_secret = rnd;
-       spin_unlock_bh(&inetsw_lock);
+
+       cmpxchg(&inet_ehash_secret, 0, rnd);
 }
 EXPORT_SYMBOL(build_ehash_secret);
 
index 96c1955b3e2f5b47181c6fe331b581fc161baf27..dcfe7e961c104cea1f4e3ab496ef0a7a361cb30e 100644 (file)
@@ -55,7 +55,7 @@
  *             Stuart Cheshire :       Metricom and grat arp fixes
  *                                     *** FOR 2.1 clean this up ***
  *             Lawrence V. Stefani: (08/12/96) Added FDDI support.
- *             Alan Cox        :       Took the AP1000 nasty FDDI hack and
+ *             Alan Cox        :       Took the AP1000 nasty FDDI hack and
  *                                     folded into the mainstream FDDI code.
  *                                     Ack spit, Linus how did you allow that
  *                                     one in...
@@ -120,7 +120,7 @@ EXPORT_SYMBOL(clip_tbl_hook);
 #endif
 
 #include <asm/system.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 
 #include <linux/netfilter_arp.h>
 
@@ -173,32 +173,32 @@ const struct neigh_ops arp_broken_ops = {
 EXPORT_SYMBOL(arp_broken_ops);
 
 struct neigh_table arp_tbl = {
-       .family =       AF_INET,
-       .entry_size =   sizeof(struct neighbour) + 4,
-       .key_len =      4,
-       .hash =         arp_hash,
-       .constructor  arp_constructor,
-       .proxy_redo =   parp_redo,
-       .id =           "arp_cache",
-       .parms = {
-               .tbl =                  &arp_tbl,
-               .base_reachable_time  30 * HZ,
-               .retrans_time = 1 * HZ,
-               .gc_staletime = 60 * HZ,
-               .reachable_time =               30 * HZ,
-               .delay_probe_time =     5 * HZ,
-               .queue_len =            3,
-               .ucast_probes = 3,
-               .mcast_probes = 3,
-               .anycast_delay =        1 * HZ,
-               .proxy_delay =          (8 * HZ) / 10,
-               .proxy_qlen =           64,
-               .locktime =             1 * HZ,
+       .family         = AF_INET,
+       .entry_size     = sizeof(struct neighbour) + 4,
+       .key_len        = 4,
+       .hash           = arp_hash,
+       .constructor    = arp_constructor,
+       .proxy_redo     = parp_redo,
+       .id             = "arp_cache",
+       .parms          = {
+               .tbl                    = &arp_tbl,
+               .base_reachable_time    = 30 * HZ,
+               .retrans_time           = 1 * HZ,
+               .gc_staletime           = 60 * HZ,
+               .reachable_time         = 30 * HZ,
+               .delay_probe_time       = 5 * HZ,
+               .queue_len              = 3,
+               .ucast_probes           = 3,
+               .mcast_probes           = 3,
+               .anycast_delay          = 1 * HZ,
+               .proxy_delay            = (8 * HZ) / 10,
+               .proxy_qlen             = 64,
+               .locktime               = 1 * HZ,
        },
-       .gc_interval  30 * HZ,
-       .gc_thresh1 =   128,
-       .gc_thresh2 =   512,
-       .gc_thresh3 =   1024,
+       .gc_interval    = 30 * HZ,
+       .gc_thresh1     = 128,
+       .gc_thresh2     = 512,
+       .gc_thresh3     = 1024,
 };
 EXPORT_SYMBOL(arp_tbl);
 
@@ -233,7 +233,7 @@ static u32 arp_hash(const void *pkey, const struct net_device *dev)
 
 static int arp_constructor(struct neighbour *neigh)
 {
-       __be32 addr = *(__be32*)neigh->primary_key;
+       __be32 addr = *(__be32 *)neigh->primary_key;
        struct net_device *dev = neigh->dev;
        struct in_device *in_dev;
        struct neigh_parms *parms;
@@ -296,16 +296,19 @@ static int arp_constructor(struct neighbour *neigh)
                        neigh->ops = &arp_broken_ops;
                        neigh->output = neigh->ops->output;
                        return 0;
+#else
+                       break;
 #endif
-               ;}
+               }
 #endif
                if (neigh->type == RTN_MULTICAST) {
                        neigh->nud_state = NUD_NOARP;
                        arp_mc_map(addr, neigh->ha, dev, 1);
-               } else if (dev->flags&(IFF_NOARP|IFF_LOOPBACK)) {
+               } else if (dev->flags & (IFF_NOARP | IFF_LOOPBACK)) {
                        neigh->nud_state = NUD_NOARP;
                        memcpy(neigh->ha, dev->dev_addr, dev->addr_len);
-               } else if (neigh->type == RTN_BROADCAST || dev->flags&IFF_POINTOPOINT) {
+               } else if (neigh->type == RTN_BROADCAST ||
+                          (dev->flags & IFF_POINTOPOINT)) {
                        neigh->nud_state = NUD_NOARP;
                        memcpy(neigh->ha, dev->broadcast, dev->addr_len);
                }
@@ -315,7 +318,7 @@ static int arp_constructor(struct neighbour *neigh)
                else
                        neigh->ops = &arp_generic_ops;
 
-               if (neigh->nud_state&NUD_VALID)
+               if (neigh->nud_state & NUD_VALID)
                        neigh->output = neigh->ops->connected_output;
                else
                        neigh->output = neigh->ops->output;
@@ -334,7 +337,7 @@ static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb)
        __be32 saddr = 0;
        u8  *dst_ha = NULL;
        struct net_device *dev = neigh->dev;
-       __be32 target = *(__be32*)neigh->primary_key;
+       __be32 target = *(__be32 *)neigh->primary_key;
        int probes = atomic_read(&neigh->probes);
        struct in_device *in_dev;
 
@@ -347,7 +350,8 @@ static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb)
        switch (IN_DEV_ARP_ANNOUNCE(in_dev)) {
        default:
        case 0:         /* By default announce any local IP */
-               if (skb && inet_addr_type(dev_net(dev), ip_hdr(skb)->saddr) == RTN_LOCAL)
+               if (skb && inet_addr_type(dev_net(dev),
+                                         ip_hdr(skb)->saddr) == RTN_LOCAL)
                        saddr = ip_hdr(skb)->saddr;
                break;
        case 1:         /* Restrict announcements of saddr in same subnet */
@@ -369,16 +373,21 @@ static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb)
        if (!saddr)
                saddr = inet_select_addr(dev, target, RT_SCOPE_LINK);
 
-       if ((probes -= neigh->parms->ucast_probes) < 0) {
-               if (!(neigh->nud_state&NUD_VALID))
-                       printk(KERN_DEBUG "trying to ucast probe in NUD_INVALID\n");
+       probes -= neigh->parms->ucast_probes;
+       if (probes < 0) {
+               if (!(neigh->nud_state & NUD_VALID))
+                       printk(KERN_DEBUG
+                              "trying to ucast probe in NUD_INVALID\n");
                dst_ha = neigh->ha;
                read_lock_bh(&neigh->lock);
-       } else if ((probes -= neigh->parms->app_probes) < 0) {
+       } else {
+               probes -= neigh->parms->app_probes;
+               if (probes < 0) {
 #ifdef CONFIG_ARPD
-               neigh_app_ns(neigh);
+                       neigh_app_ns(neigh);
 #endif
-               return;
+                       return;
+               }
        }
 
        arp_send(ARPOP_REQUEST, ETH_P_ARP, target, dev, saddr,
@@ -451,7 +460,8 @@ static int arp_filter(__be32 sip, __be32 tip, struct net_device *dev)
  *     is allowed to use this function, it is scheduled to be removed. --ANK
  */
 
-static int arp_set_predefined(int addr_hint, unsigned char * haddr, __be32 paddr, struct net_device * dev)
+static int arp_set_predefined(int addr_hint, unsigned char *haddr,
+                             __be32 paddr, struct net_device *dev)
 {
        switch (addr_hint) {
        case RTN_LOCAL:
@@ -483,7 +493,8 @@ int arp_find(unsigned char *haddr, struct sk_buff *skb)
 
        paddr = skb_rtable(skb)->rt_gateway;
 
-       if (arp_set_predefined(inet_addr_type(dev_net(dev), paddr), haddr, paddr, dev))
+       if (arp_set_predefined(inet_addr_type(dev_net(dev), paddr), haddr,
+                              paddr, dev))
                return 0;
 
        n = __neigh_lookup(&arp_tbl, &paddr, dev, 1);
@@ -515,13 +526,14 @@ int arp_bind_neighbour(struct dst_entry *dst)
                return -EINVAL;
        if (n == NULL) {
                __be32 nexthop = ((struct rtable *)dst)->rt_gateway;
-               if (dev->flags&(IFF_LOOPBACK|IFF_POINTOPOINT))
+               if (dev->flags & (IFF_LOOPBACK | IFF_POINTOPOINT))
                        nexthop = 0;
                n = __neigh_lookup_errno(
 #if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
-                   dev->type == ARPHRD_ATM ? clip_tbl_hook :
+                                        dev->type == ARPHRD_ATM ?
+                                        clip_tbl_hook :
 #endif
-                   &arp_tbl, &nexthop, dev);
+                                        &arp_tbl, &nexthop, dev);
                if (IS_ERR(n))
                        return PTR_ERR(n);
                dst->neighbour = n;
@@ -543,8 +555,8 @@ static inline int arp_fwd_proxy(struct in_device *in_dev,
 
        if (!IN_DEV_PROXY_ARP(in_dev))
                return 0;
-
-       if ((imi = IN_DEV_MEDIUM_ID(in_dev)) == 0)
+       imi = IN_DEV_MEDIUM_ID(in_dev);
+       if (imi == 0)
                return 1;
        if (imi == -1)
                return 0;
@@ -685,7 +697,7 @@ struct sk_buff *arp_create(int type, int ptype, __be32 dest_ip,
        arp->ar_pln = 4;
        arp->ar_op = htons(type);
 
-       arp_ptr=(unsigned char *)(arp+1);
+       arp_ptr = (unsigned char *)(arp + 1);
 
        memcpy(arp_ptr, src_hw, dev->addr_len);
        arp_ptr += dev->addr_len;
@@ -735,9 +747,8 @@ void arp_send(int type, int ptype, __be32 dest_ip,
 
        skb = arp_create(type, ptype, dest_ip, dev, src_ip,
                         dest_hw, src_hw, target_hw);
-       if (skb == NULL) {
+       if (skb == NULL)
                return;
-       }
 
        arp_xmit(skb);
 }
@@ -815,7 +826,7 @@ static int arp_process(struct sk_buff *skb)
 /*
  *     Extract fields
  */
-       arp_ptr= (unsigned char *)(arp+1);
+       arp_ptr = (unsigned char *)(arp + 1);
        sha     = arp_ptr;
        arp_ptr += dev->addr_len;
        memcpy(&sip, arp_ptr, 4);
@@ -869,16 +880,17 @@ static int arp_process(struct sk_buff *skb)
                addr_type = rt->rt_type;
 
                if (addr_type == RTN_LOCAL) {
-                       int dont_send = 0;
+                       int dont_send;
 
-                       if (!dont_send)
-                               dont_send |= arp_ignore(in_dev,sip,tip);
+                       dont_send = arp_ignore(in_dev, sip, tip);
                        if (!dont_send && IN_DEV_ARPFILTER(in_dev))
-                               dont_send |= arp_filter(sip,tip,dev);
+                               dont_send |= arp_filter(sip, tip, dev);
                        if (!dont_send) {
                                n = neigh_event_ns(&arp_tbl, sha, &sip, dev);
                                if (n) {
-                                       arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,dev->dev_addr,sha);
+                                       arp_send(ARPOP_REPLY, ETH_P_ARP, sip,
+                                                dev, tip, sha, dev->dev_addr,
+                                                sha);
                                        neigh_release(n);
                                }
                        }
@@ -887,8 +899,7 @@ static int arp_process(struct sk_buff *skb)
                        if (addr_type == RTN_UNICAST  &&
                            (arp_fwd_proxy(in_dev, dev, rt) ||
                             arp_fwd_pvlan(in_dev, dev, rt, sip, tip) ||
-                            pneigh_lookup(&arp_tbl, net, &tip, dev, 0)))
-                       {
+                            pneigh_lookup(&arp_tbl, net, &tip, dev, 0))) {
                                n = neigh_event_ns(&arp_tbl, sha, &sip, dev);
                                if (n)
                                        neigh_release(n);
@@ -896,9 +907,12 @@ static int arp_process(struct sk_buff *skb)
                                if (NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED ||
                                    skb->pkt_type == PACKET_HOST ||
                                    in_dev->arp_parms->proxy_delay == 0) {
-                                       arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,dev->dev_addr,sha);
+                                       arp_send(ARPOP_REPLY, ETH_P_ARP, sip,
+                                                dev, tip, sha, dev->dev_addr,
+                                                sha);
                                } else {
-                                       pneigh_enqueue(&arp_tbl, in_dev->arp_parms, skb);
+                                       pneigh_enqueue(&arp_tbl,
+                                                      in_dev->arp_parms, skb);
                                        return 0;
                                }
                                goto out;
@@ -939,7 +953,8 @@ static int arp_process(struct sk_buff *skb)
                if (arp->ar_op != htons(ARPOP_REPLY) ||
                    skb->pkt_type != PACKET_HOST)
                        state = NUD_STALE;
-               neigh_update(n, sha, state, override ? NEIGH_UPDATE_F_OVERRIDE : 0);
+               neigh_update(n, sha, state,
+                            override ? NEIGH_UPDATE_F_OVERRIDE : 0);
                neigh_release(n);
        }
 
@@ -975,7 +990,8 @@ static int arp_rcv(struct sk_buff *skb, struct net_device *dev,
            arp->ar_pln != 4)
                goto freeskb;
 
-       if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)
+       skb = skb_share_check(skb, GFP_ATOMIC);
+       if (skb == NULL)
                goto out_of_mem;
 
        memset(NEIGH_CB(skb), 0, sizeof(struct neighbour_cb));
@@ -1019,7 +1035,7 @@ static int arp_req_set_public(struct net *net, struct arpreq *r,
                return -EINVAL;
        if (!dev && (r->arp_flags & ATF_COM)) {
                dev = dev_getbyhwaddr(net, r->arp_ha.sa_family,
-                               r->arp_ha.sa_data);
+                                     r->arp_ha.sa_data);
                if (!dev)
                        return -ENODEV;
        }
@@ -1033,7 +1049,7 @@ static int arp_req_set_public(struct net *net, struct arpreq *r,
 }
 
 static int arp_req_set(struct net *net, struct arpreq *r,
-               struct net_device * dev)
+                      struct net_device *dev)
 {
        __be32 ip;
        struct neighbour *neigh;
@@ -1046,10 +1062,11 @@ static int arp_req_set(struct net *net, struct arpreq *r,
        if (r->arp_flags & ATF_PERM)
                r->arp_flags |= ATF_COM;
        if (dev == NULL) {
-               struct flowi fl = { .nl_u = { .ip4_u = { .daddr = ip,
-                                                        .tos = RTO_ONLINK } } };
-               struct rtable * rt;
-               if ((err = ip_route_output_key(net, &rt, &fl)) != 0)
+               struct flowi fl = { .nl_u.ip4_u = { .daddr = ip,
+                                                   .tos = RTO_ONLINK } };
+               struct rtable *rt;
+               err = ip_route_output_key(net, &rt, &fl);
+               if (err != 0)
                        return err;
                dev = rt->dst.dev;
                ip_rt_put(rt);
@@ -1083,9 +1100,9 @@ static int arp_req_set(struct net *net, struct arpreq *r,
                unsigned state = NUD_STALE;
                if (r->arp_flags & ATF_PERM)
                        state = NUD_PERMANENT;
-               err = neigh_update(neigh, (r->arp_flags&ATF_COM) ?
+               err = neigh_update(neigh, (r->arp_flags & ATF_COM) ?
                                   r->arp_ha.sa_data : NULL, state,
-                                  NEIGH_UPDATE_F_OVERRIDE|
+                                  NEIGH_UPDATE_F_OVERRIDE |
                                   NEIGH_UPDATE_F_ADMIN);
                neigh_release(neigh);
        }
@@ -1094,12 +1111,12 @@ static int arp_req_set(struct net *net, struct arpreq *r,
 
 static unsigned arp_state_to_flags(struct neighbour *neigh)
 {
-       unsigned flags = 0;
        if (neigh->nud_state&NUD_PERMANENT)
-               flags = ATF_PERM|ATF_COM;
+               return ATF_PERM | ATF_COM;
        else if (neigh->nud_state&NUD_VALID)
-               flags = ATF_COM;
-       return flags;
+               return ATF_COM;
+       else
+               return 0;
 }
 
 /*
@@ -1142,7 +1159,7 @@ static int arp_req_delete_public(struct net *net, struct arpreq *r,
 }
 
 static int arp_req_delete(struct net *net, struct arpreq *r,
-               struct net_device * dev)
+                         struct net_device *dev)
 {
        int err;
        __be32 ip;
@@ -1153,10 +1170,11 @@ static int arp_req_delete(struct net *net, struct arpreq *r,
 
        ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr;
        if (dev == NULL) {
-               struct flowi fl = { .nl_u = { .ip4_u = { .daddr = ip,
-                                                        .tos = RTO_ONLINK } } };
-               struct rtable * rt;
-               if ((err = ip_route_output_key(net, &rt, &fl)) != 0)
+               struct flowi fl = { .nl_u.ip4_u = { .daddr = ip,
+                                                   .tos = RTO_ONLINK } };
+               struct rtable *rt;
+               err = ip_route_output_key(net, &rt, &fl);
+               if (err != 0)
                        return err;
                dev = rt->dst.dev;
                ip_rt_put(rt);
@@ -1166,7 +1184,7 @@ static int arp_req_delete(struct net *net, struct arpreq *r,
        err = -ENXIO;
        neigh = neigh_lookup(&arp_tbl, &ip, dev);
        if (neigh) {
-               if (neigh->nud_state&~NUD_NOARP)
+               if (neigh->nud_state & ~NUD_NOARP)
                        err = neigh_update(neigh, NULL, NUD_FAILED,
                                           NEIGH_UPDATE_F_OVERRIDE|
                                           NEIGH_UPDATE_F_ADMIN);
@@ -1186,24 +1204,24 @@ int arp_ioctl(struct net *net, unsigned int cmd, void __user *arg)
        struct net_device *dev = NULL;
 
        switch (cmd) {
-               case SIOCDARP:
-               case SIOCSARP:
-                       if (!capable(CAP_NET_ADMIN))
-                               return -EPERM;
-               case SIOCGARP:
-                       err = copy_from_user(&r, arg, sizeof(struct arpreq));
-                       if (err)
-                               return -EFAULT;
-                       break;
-               default:
-                       return -EINVAL;
+       case SIOCDARP:
+       case SIOCSARP:
+               if (!capable(CAP_NET_ADMIN))
+                       return -EPERM;
+       case SIOCGARP:
+               err = copy_from_user(&r, arg, sizeof(struct arpreq));
+               if (err)
+                       return -EFAULT;
+               break;
+       default:
+               return -EINVAL;
        }
 
        if (r.arp_pa.sa_family != AF_INET)
                return -EPFNOSUPPORT;
 
        if (!(r.arp_flags & ATF_PUBL) &&
-           (r.arp_flags & (ATF_NETMASK|ATF_DONTPUB)))
+           (r.arp_flags & (ATF_NETMASK | ATF_DONTPUB)))
                return -EINVAL;
        if (!(r.arp_flags & ATF_NETMASK))
                ((struct sockaddr_in *)&r.arp_netmask)->sin_addr.s_addr =
@@ -1211,7 +1229,8 @@ int arp_ioctl(struct net *net, unsigned int cmd, void __user *arg)
        rtnl_lock();
        if (r.arp_dev[0]) {
                err = -ENODEV;
-               if ((dev = __dev_get_by_name(net, r.arp_dev)) == NULL)
+               dev = __dev_get_by_name(net, r.arp_dev);
+               if (dev == NULL)
                        goto out;
 
                /* Mmmm... It is wrong... ARPHRD_NETROM==0 */
@@ -1243,7 +1262,8 @@ out:
        return err;
 }
 
-static int arp_netdev_event(struct notifier_block *this, unsigned long event, void *ptr)
+static int arp_netdev_event(struct notifier_block *this, unsigned long event,
+                           void *ptr)
 {
        struct net_device *dev = ptr;
 
@@ -1311,12 +1331,13 @@ static char *ax2asc2(ax25_address *a, char *buf)
        for (n = 0, s = buf; n < 6; n++) {
                c = (a->ax25_call[n] >> 1) & 0x7F;
 
-               if (c != ' ') *s++ = c;
+               if (c != ' ')
+                       *s++ = c;
        }
 
        *s++ = '-';
-
-       if ((n = ((a->ax25_call[6] >> 1) & 0x0F)) > 9) {
+       n = (a->ax25_call[6] >> 1) & 0x0F;
+       if (n > 9) {
                *s++ = '1';
                n -= 10;
        }
@@ -1325,10 +1346,9 @@ static char *ax2asc2(ax25_address *a, char *buf)
        *s++ = '\0';
 
        if (*buf == '\0' || *buf == '-')
-          return "*";
+               return "*";
 
        return buf;
-
 }
 #endif /* CONFIG_AX25 */
 
@@ -1408,10 +1428,10 @@ static void *arp_seq_start(struct seq_file *seq, loff_t *pos)
 /* ------------------------------------------------------------------------ */
 
 static const struct seq_operations arp_seq_ops = {
-       .start  = arp_seq_start,
-       .next   = neigh_seq_next,
-       .stop   = neigh_seq_stop,
-       .show   = arp_seq_show,
+       .start  = arp_seq_start,
+       .next   = neigh_seq_next,
+       .stop   = neigh_seq_stop,
+       .show   = arp_seq_show,
 };
 
 static int arp_seq_open(struct inode *inode, struct file *file)
diff --git a/net/ipv4/gre.c b/net/ipv4/gre.c
new file mode 100644 (file)
index 0000000..b546736
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ *     GRE over IPv4 demultiplexer driver
+ *
+ *     Authors: Dmitry Kozlov (xeb@mail.ru)
+ *
+ *     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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/kmod.h>
+#include <linux/skbuff.h>
+#include <linux/in.h>
+#include <linux/netdevice.h>
+#include <linux/version.h>
+#include <linux/spinlock.h>
+#include <net/protocol.h>
+#include <net/gre.h>
+
+
+const struct gre_protocol *gre_proto[GREPROTO_MAX] __read_mostly;
+static DEFINE_SPINLOCK(gre_proto_lock);
+
+int gre_add_protocol(const struct gre_protocol *proto, u8 version)
+{
+       if (version >= GREPROTO_MAX)
+               goto err_out;
+
+       spin_lock(&gre_proto_lock);
+       if (gre_proto[version])
+               goto err_out_unlock;
+
+       rcu_assign_pointer(gre_proto[version], proto);
+       spin_unlock(&gre_proto_lock);
+       return 0;
+
+err_out_unlock:
+       spin_unlock(&gre_proto_lock);
+err_out:
+       return -1;
+}
+EXPORT_SYMBOL_GPL(gre_add_protocol);
+
+int gre_del_protocol(const struct gre_protocol *proto, u8 version)
+{
+       if (version >= GREPROTO_MAX)
+               goto err_out;
+
+       spin_lock(&gre_proto_lock);
+       if (gre_proto[version] != proto)
+               goto err_out_unlock;
+       rcu_assign_pointer(gre_proto[version], NULL);
+       spin_unlock(&gre_proto_lock);
+       synchronize_rcu();
+       return 0;
+
+err_out_unlock:
+       spin_unlock(&gre_proto_lock);
+err_out:
+       return -1;
+}
+EXPORT_SYMBOL_GPL(gre_del_protocol);
+
+static int gre_rcv(struct sk_buff *skb)
+{
+       const struct gre_protocol *proto;
+       u8 ver;
+       int ret;
+
+       if (!pskb_may_pull(skb, 12))
+               goto drop;
+
+       ver = skb->data[1]&0x7f;
+       if (ver >= GREPROTO_MAX)
+               goto drop;
+
+       rcu_read_lock();
+       proto = rcu_dereference(gre_proto[ver]);
+       if (!proto || !proto->handler)
+               goto drop_unlock;
+       ret = proto->handler(skb);
+       rcu_read_unlock();
+       return ret;
+
+drop_unlock:
+       rcu_read_unlock();
+drop:
+       kfree_skb(skb);
+       return NET_RX_DROP;
+}
+
+static void gre_err(struct sk_buff *skb, u32 info)
+{
+       const struct gre_protocol *proto;
+       u8 ver;
+
+       if (!pskb_may_pull(skb, 12))
+               goto drop;
+
+       ver = skb->data[1]&0x7f;
+       if (ver >= GREPROTO_MAX)
+               goto drop;
+
+       rcu_read_lock();
+       proto = rcu_dereference(gre_proto[ver]);
+       if (!proto || !proto->err_handler)
+               goto drop_unlock;
+       proto->err_handler(skb, info);
+       rcu_read_unlock();
+       return;
+
+drop_unlock:
+       rcu_read_unlock();
+drop:
+       kfree_skb(skb);
+}
+
+static const struct net_protocol net_gre_protocol = {
+       .handler     = gre_rcv,
+       .err_handler = gre_err,
+       .netns_ok    = 1,
+};
+
+static int __init gre_init(void)
+{
+       pr_info("GRE over IPv4 demultiplexor driver");
+
+       if (inet_add_protocol(&net_gre_protocol, IPPROTO_GRE) < 0) {
+               pr_err("gre: can't add protocol\n");
+               return -EAGAIN;
+       }
+
+       return 0;
+}
+
+static void __exit gre_exit(void)
+{
+       inet_del_protocol(&net_gre_protocol, IPPROTO_GRE);
+}
+
+module_init(gre_init);
+module_exit(gre_exit);
+
+MODULE_DESCRIPTION("GRE over IPv4 demultiplexer driver");
+MODULE_AUTHOR("D. Kozlov (xeb@mail.ru)");
+MODULE_LICENSE("GPL");
+
index a0d847c7cba5c89aec43b340036bf456468f9e9a..96bc7f9475a3f2f0124685cc1b7afb7b58c23d8d 100644 (file)
@@ -379,7 +379,7 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
        inet->tos = ip_hdr(skb)->tos;
        daddr = ipc.addr = rt->rt_src;
        ipc.opt = NULL;
-       ipc.shtx.flags = 0;
+       ipc.tx_flags = 0;
        if (icmp_param->replyopts.optlen) {
                ipc.opt = &icmp_param->replyopts;
                if (ipc.opt->srr)
@@ -538,7 +538,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info)
        inet_sk(sk)->tos = tos;
        ipc.addr = iph->saddr;
        ipc.opt = &icmp_param.replyopts;
-       ipc.shtx.flags = 0;
+       ipc.tx_flags = 0;
 
        {
                struct flowi fl = {
index b7c41654dde543ff310ac63aa696d65a58fd4d36..f4dc879e258eafc5b09c0ead319c7a4d0e61d6a3 100644 (file)
@@ -542,7 +542,7 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev,
        /* If the first fragment is fragmented itself, we split
         * it to two chunks: the first with data and paged part
         * and the second, holding only fragments. */
-       if (skb_has_frags(head)) {
+       if (skb_has_frag_list(head)) {
                struct sk_buff *clone;
                int i, plen = 0;
 
index 945b20a5ad5006b6a8ebf84b22756f7573436c1f..85176895495a790329fd9c8ba863f6092322d7ac 100644 (file)
@@ -44,6 +44,7 @@
 #include <net/net_namespace.h>
 #include <net/netns/generic.h>
 #include <net/rtnetlink.h>
+#include <net/gre.h>
 
 #ifdef CONFIG_IPV6
 #include <net/ipv6.h>
@@ -1278,10 +1279,9 @@ static void ipgre_fb_tunnel_init(struct net_device *dev)
 }
 
 
-static const struct net_protocol ipgre_protocol = {
-       .handler        =       ipgre_rcv,
-       .err_handler    =       ipgre_err,
-       .netns_ok       =       1,
+static const struct gre_protocol ipgre_protocol = {
+       .handler     = ipgre_rcv,
+       .err_handler = ipgre_err,
 };
 
 static void ipgre_destroy_tunnels(struct ipgre_net *ign, struct list_head *head)
@@ -1663,7 +1663,7 @@ static int __init ipgre_init(void)
        if (err < 0)
                return err;
 
-       err = inet_add_protocol(&ipgre_protocol, IPPROTO_GRE);
+       err = gre_add_protocol(&ipgre_protocol, GREPROTO_CISCO);
        if (err < 0) {
                printk(KERN_INFO "ipgre init: can't add protocol\n");
                goto add_proto_failed;
@@ -1683,7 +1683,7 @@ out:
 tap_ops_failed:
        rtnl_link_unregister(&ipgre_link_ops);
 rtnl_link_failed:
-       inet_del_protocol(&ipgre_protocol, IPPROTO_GRE);
+       gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO);
 add_proto_failed:
        unregister_pernet_device(&ipgre_net_ops);
        goto out;
@@ -1693,7 +1693,7 @@ static void __exit ipgre_fini(void)
 {
        rtnl_link_unregister(&ipgre_tap_ops);
        rtnl_link_unregister(&ipgre_link_ops);
-       if (inet_del_protocol(&ipgre_protocol, IPPROTO_GRE) < 0)
+       if (gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO) < 0)
                printk(KERN_INFO "ipgre close: can't remove protocol\n");
        unregister_pernet_device(&ipgre_net_ops);
 }
index 04b69896df5fc743021efd4d4a1705b7de146333..e42762023c27bd405783648f9503f165522e67f3 100644 (file)
@@ -487,7 +487,7 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
         * LATER: this step can be merged to real generation of fragments,
         * we can switch to copy when see the first bad fragment.
         */
-       if (skb_has_frags(skb)) {
+       if (skb_has_frag_list(skb)) {
                struct sk_buff *frag;
                int first_len = skb_pagelen(skb);
                int truesizes = 0;
@@ -837,10 +837,9 @@ int ip_append_data(struct sock *sk,
                inet->cork.length = 0;
                sk->sk_sndmsg_page = NULL;
                sk->sk_sndmsg_off = 0;
-               if ((exthdrlen = rt->dst.header_len) != 0) {
-                       length += exthdrlen;
-                       transhdrlen += exthdrlen;
-               }
+               exthdrlen = rt->dst.header_len;
+               length += exthdrlen;
+               transhdrlen += exthdrlen;
        } else {
                rt = (struct rtable *)inet->cork.dst;
                if (inet->cork.flags & IPCORK_OPT)
@@ -953,7 +952,7 @@ alloc_new_skb:
                                else
                                        /* only the initial fragment is
                                           time stamped */
-                                       ipc->shtx.flags = 0;
+                                       ipc->tx_flags = 0;
                        }
                        if (skb == NULL)
                                goto error;
@@ -964,7 +963,7 @@ alloc_new_skb:
                        skb->ip_summed = csummode;
                        skb->csum = 0;
                        skb_reserve(skb, hh_len);
-                       *skb_tx(skb) = ipc->shtx;
+                       skb_shinfo(skb)->tx_flags = ipc->tx_flags;
 
                        /*
                         *      Find where to start putting bytes.
@@ -1384,7 +1383,7 @@ void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *ar
 
        daddr = ipc.addr = rt->rt_src;
        ipc.opt = NULL;
-       ipc.shtx.flags = 0;
+       ipc.tx_flags = 0;
 
        if (replyopts.opt.optlen) {
                ipc.opt = &replyopts.opt;
index ec036731a70ba0774164de8574c30d0f0e1baa64..3c6f8f3968a6fcc2a7b41e1290ca87cf55640198 100644 (file)
@@ -744,7 +744,7 @@ static void __net_init ipip_fb_tunnel_init(struct net_device *dev)
        ipn->tunnels_wc[0]      = tunnel;
 }
 
-static struct xfrm_tunnel ipip_handler = {
+static struct xfrm_tunnel ipip_handler __read_mostly = {
        .handler        =       ipip_rcv,
        .err_handler    =       ipip_err,
        .priority       =       1,
index 3a43cf36db8701f9b8a99317a60da0e3ac2ad8f4..1e26a4897655bddd2720730956ebe2d15d265ebf 100644 (file)
@@ -29,6 +29,7 @@
 #include <net/netfilter/nf_conntrack.h>
 #include <net/net_namespace.h>
 #include <net/checksum.h>
+#include <net/ip.h>
 
 #define CLUSTERIP_VERSION "0.8"
 
@@ -231,24 +232,22 @@ clusterip_hashfn(const struct sk_buff *skb,
 {
        const struct iphdr *iph = ip_hdr(skb);
        unsigned long hashval;
-       u_int16_t sport, dport;
-       const u_int16_t *ports;
-
-       switch (iph->protocol) {
-       case IPPROTO_TCP:
-       case IPPROTO_UDP:
-       case IPPROTO_UDPLITE:
-       case IPPROTO_SCTP:
-       case IPPROTO_DCCP:
-       case IPPROTO_ICMP:
-               ports = (const void *)iph+iph->ihl*4;
-               sport = ports[0];
-               dport = ports[1];
-               break;
-       default:
+       u_int16_t sport = 0, dport = 0;
+       int poff;
+
+       poff = proto_ports_offset(iph->protocol);
+       if (poff >= 0) {
+               const u_int16_t *ports;
+               u16 _ports[2];
+
+               ports = skb_header_pointer(skb, iph->ihl * 4 + poff, 4, _ports);
+               if (ports) {
+                       sport = ports[0];
+                       dport = ports[1];
+               }
+       } else {
                if (net_ratelimit())
                        pr_info("unknown protocol %u\n", iph->protocol);
-               sport = dport = 0;
        }
 
        switch (config->hash_mode) {
index f2d297351405d8fab1262bb308142202d72e7f5b..65699c24411cfb5cb3ee55428e7e0302feb64716 100644 (file)
@@ -28,8 +28,7 @@
 #include <linux/spinlock.h>
 #include <net/protocol.h>
 
-const struct net_protocol *inet_protos[MAX_INET_PROTOS] ____cacheline_aligned_in_smp;
-static DEFINE_SPINLOCK(inet_proto_lock);
+const struct net_protocol *inet_protos[MAX_INET_PROTOS] __read_mostly;
 
 /*
  *     Add a protocol handler to the hash tables
@@ -37,20 +36,9 @@ static DEFINE_SPINLOCK(inet_proto_lock);
 
 int inet_add_protocol(const struct net_protocol *prot, unsigned char protocol)
 {
-       int hash, ret;
+       int hash = protocol & (MAX_INET_PROTOS - 1);
 
-       hash = protocol & (MAX_INET_PROTOS - 1);
-
-       spin_lock_bh(&inet_proto_lock);
-       if (inet_protos[hash]) {
-               ret = -1;
-       } else {
-               inet_protos[hash] = prot;
-               ret = 0;
-       }
-       spin_unlock_bh(&inet_proto_lock);
-
-       return ret;
+       return !cmpxchg(&inet_protos[hash], NULL, prot) ? 0 : -1;
 }
 EXPORT_SYMBOL(inet_add_protocol);
 
@@ -60,18 +48,9 @@ EXPORT_SYMBOL(inet_add_protocol);
 
 int inet_del_protocol(const struct net_protocol *prot, unsigned char protocol)
 {
-       int hash, ret;
-
-       hash = protocol & (MAX_INET_PROTOS - 1);
+       int ret, hash = protocol & (MAX_INET_PROTOS - 1);
 
-       spin_lock_bh(&inet_proto_lock);
-       if (inet_protos[hash] == prot) {
-               inet_protos[hash] = NULL;
-               ret = 0;
-       } else {
-               ret = -1;
-       }
-       spin_unlock_bh(&inet_proto_lock);
+       ret = (cmpxchg(&inet_protos[hash], prot, NULL) == prot) ? 0 : -1;
 
        synchronize_net();
 
index 009a7b2aa1ef0493f542b4745b334e2964c0b826..1f85ef289895a8c2a4a567089ad5bef7c1271dae 100644 (file)
@@ -505,7 +505,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
 
        ipc.addr = inet->inet_saddr;
        ipc.opt = NULL;
-       ipc.shtx.flags = 0;
+       ipc.tx_flags = 0;
        ipc.oif = sk->sk_bound_dev_if;
 
        if (msg->msg_controllen) {
index 6298f75d5e93c4ad4e838a1982143207e7d3f855..e24d48dd99d3f62760c8ff29158328e62463423f 100644 (file)
@@ -1268,18 +1268,11 @@ skip_hashing:
 
 void rt_bind_peer(struct rtable *rt, int create)
 {
-       static DEFINE_SPINLOCK(rt_peer_lock);
        struct inet_peer *peer;
 
        peer = inet_getpeer(rt->rt_dst, create);
 
-       spin_lock_bh(&rt_peer_lock);
-       if (rt->peer == NULL) {
-               rt->peer = peer;
-               peer = NULL;
-       }
-       spin_unlock_bh(&rt_peer_lock);
-       if (peer)
+       if (peer && cmpxchg(&rt->peer, NULL, peer) != NULL)
                inet_putpeer(peer);
 }
 
index 3fb1428e526eedb521057a49624fa28dde8b41cd..3e8a4dbc721b849e88fed7cb6fa32273b02017aa 100644 (file)
@@ -2389,7 +2389,12 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
                err = tp->af_specific->md5_parse(sk, optval, optlen);
                break;
 #endif
-
+       case TCP_USER_TIMEOUT:
+               /* Cap the max timeout in ms TCP will retry/retrans
+                * before giving up and aborting (ETIMEDOUT) a connection.
+                */
+               icsk->icsk_user_timeout = msecs_to_jiffies(val);
+               break;
        default:
                err = -ENOPROTOOPT;
                break;
@@ -2608,6 +2613,10 @@ static int do_tcp_getsockopt(struct sock *sk, int level,
        case TCP_THIN_DUPACK:
                val = tp->thin_dupack;
                break;
+
+       case TCP_USER_TIMEOUT:
+               val = jiffies_to_msecs(icsk->icsk_user_timeout);
+               break;
        default:
                return -ENOPROTOOPT;
        }
index e663b78a2ef6b6286b549aa65b418fe385f32184..1bc87a05c734e535e605fe388676816947bf3182 100644 (file)
@@ -805,25 +805,12 @@ void tcp_update_metrics(struct sock *sk)
        }
 }
 
-/* Numbers are taken from RFC3390.
- *
- * John Heffner states:
- *
- *     The RFC specifies a window of no more than 4380 bytes
- *     unless 2*MSS > 4380.  Reading the pseudocode in the RFC
- *     is a bit misleading because they use a clamp at 4380 bytes
- *     rather than use a multiplier in the relevant range.
- */
 __u32 tcp_init_cwnd(struct tcp_sock *tp, struct dst_entry *dst)
 {
        __u32 cwnd = (dst ? dst_metric(dst, RTAX_INITCWND) : 0);
 
-       if (!cwnd) {
-               if (tp->mss_cache > 1460)
-                       cwnd = 2;
-               else
-                       cwnd = (tp->mss_cache > 1095) ? 3 : 4;
-       }
+       if (!cwnd)
+               cwnd = rfc3390_bytes_to_packets(tp->mss_cache);
        return min_t(__u32, cwnd, tp->snd_cwnd_clamp);
 }
 
index 020766292bb01009201ec11e60bb0e214854414c..a0232f3a358b2b8fc6cd98b96a98f6b5cc69f1f6 100644 (file)
@@ -2571,7 +2571,6 @@ struct sk_buff **tcp4_gro_receive(struct sk_buff **head, struct sk_buff *skb)
 
        return tcp_gro_receive(head, skb);
 }
-EXPORT_SYMBOL(tcp4_gro_receive);
 
 int tcp4_gro_complete(struct sk_buff *skb)
 {
@@ -2584,7 +2583,6 @@ int tcp4_gro_complete(struct sk_buff *skb)
 
        return tcp_gro_complete(skb);
 }
-EXPORT_SYMBOL(tcp4_gro_complete);
 
 struct proto tcp_prot = {
        .name                   = "TCP",
index de3bd84585881f99f8a23eb28fa9f380516d087c..ea09d2fd50c794a3f04a7178cb7f54cb58c42e2a 100644 (file)
@@ -224,16 +224,10 @@ void tcp_select_initial_window(int __space, __u32 mss,
                }
        }
 
-       /* Set initial window to value enough for senders,
-        * following RFC2414. Senders, not following this RFC,
-        * will be satisfied with 2.
-        */
+       /* Set initial window to value enough for senders, following RFC5681. */
        if (mss > (1 << *rcv_wscale)) {
-               int init_cwnd = 4;
-               if (mss > 1460 * 3)
-                       init_cwnd = 2;
-               else if (mss > 1460)
-                       init_cwnd = 3;
+               int init_cwnd = rfc3390_bytes_to_packets(mss);
+
                /* when initializing use the value from init_rcv_wnd
                 * rather than the default from above
                 */
@@ -2429,6 +2423,12 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst,
                __u8 rcv_wscale;
                /* Set this up on the first call only */
                req->window_clamp = tp->window_clamp ? : dst_metric(dst, RTAX_WINDOW);
+
+               /* limit the window selection if the user enforce a smaller rx buffer */
+               if (sk->sk_userlocks & SOCK_RCVBUF_LOCK &&
+                   (req->window_clamp > tcp_full_space(sk) || req->window_clamp == 0))
+                       req->window_clamp = tcp_full_space(sk);
+
                /* tcp_full_space because it is guaranteed to be the first packet */
                tcp_select_initial_window(tcp_full_space(sk),
                        mss - (ireq->tstamp_ok ? TCPOLEN_TSTAMP_ALIGNED : 0),
@@ -2555,6 +2555,11 @@ static void tcp_connect_init(struct sock *sk)
 
        tcp_initialize_rcv_mss(sk);
 
+       /* limit the window selection if the user enforce a smaller rx buffer */
+       if (sk->sk_userlocks & SOCK_RCVBUF_LOCK &&
+           (tp->window_clamp > tcp_full_space(sk) || tp->window_clamp == 0))
+               tp->window_clamp = tcp_full_space(sk);
+
        tcp_select_initial_window(tcp_full_space(sk),
                                  tp->advmss - (tp->rx_opt.ts_recent_stamp ? tp->tcp_header_len - sizeof(struct tcphdr) : 0),
                                  &tp->rcv_wnd,
index c35b469e851c298814d69583bd593ec1c580dde5..baea4a1290224e86c9f7c3cab646636fe86e35f9 100644 (file)
@@ -138,10 +138,10 @@ static void tcp_mtu_probing(struct inet_connection_sock *icsk, struct sock *sk)
  * retransmissions with an initial RTO of TCP_RTO_MIN.
  */
 static bool retransmits_timed_out(struct sock *sk,
-                                 unsigned int boundary)
+                                 unsigned int boundary,
+                                 unsigned int timeout)
 {
-       unsigned int timeout, linear_backoff_thresh;
-       unsigned int start_ts;
+       unsigned int linear_backoff_thresh, start_ts;
 
        if (!inet_csk(sk)->icsk_retransmits)
                return false;
@@ -151,14 +151,15 @@ static bool retransmits_timed_out(struct sock *sk,
        else
                start_ts = tcp_sk(sk)->retrans_stamp;
 
-       linear_backoff_thresh = ilog2(TCP_RTO_MAX/TCP_RTO_MIN);
-
-       if (boundary <= linear_backoff_thresh)
-               timeout = ((2 << boundary) - 1) * TCP_RTO_MIN;
-       else
-               timeout = ((2 << linear_backoff_thresh) - 1) * TCP_RTO_MIN +
-                         (boundary - linear_backoff_thresh) * TCP_RTO_MAX;
+       if (likely(timeout == 0)) {
+               linear_backoff_thresh = ilog2(TCP_RTO_MAX/TCP_RTO_MIN);
 
+               if (boundary <= linear_backoff_thresh)
+                       timeout = ((2 << boundary) - 1) * TCP_RTO_MIN;
+               else
+                       timeout = ((2 << linear_backoff_thresh) - 1) * TCP_RTO_MIN +
+                               (boundary - linear_backoff_thresh) * TCP_RTO_MAX;
+       }
        return (tcp_time_stamp - start_ts) >= timeout;
 }
 
@@ -174,7 +175,7 @@ static int tcp_write_timeout(struct sock *sk)
                        dst_negative_advice(sk);
                retry_until = icsk->icsk_syn_retries ? : sysctl_tcp_syn_retries;
        } else {
-               if (retransmits_timed_out(sk, sysctl_tcp_retries1)) {
+               if (retransmits_timed_out(sk, sysctl_tcp_retries1, 0)) {
                        /* Black hole detection */
                        tcp_mtu_probing(icsk, sk);
 
@@ -187,14 +188,16 @@ static int tcp_write_timeout(struct sock *sk)
 
                        retry_until = tcp_orphan_retries(sk, alive);
                        do_reset = alive ||
-                                  !retransmits_timed_out(sk, retry_until);
+                                  !retransmits_timed_out(sk, retry_until, 0);
 
                        if (tcp_out_of_resources(sk, do_reset))
                                return 1;
                }
        }
 
-       if (retransmits_timed_out(sk, retry_until)) {
+       if (retransmits_timed_out(sk, retry_until,
+           (1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV) ? 0 :
+           icsk->icsk_user_timeout)) {
                /* Has it gone just too far? */
                tcp_write_err(sk);
                return 1;
@@ -436,7 +439,7 @@ out_reset_timer:
                icsk->icsk_rto = min(icsk->icsk_rto << 1, TCP_RTO_MAX);
        }
        inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, icsk->icsk_rto, TCP_RTO_MAX);
-       if (retransmits_timed_out(sk, sysctl_tcp_retries1 + 1))
+       if (retransmits_timed_out(sk, sysctl_tcp_retries1 + 1, 0))
                __sk_dst_reset(sk);
 
 out:;
@@ -556,7 +559,14 @@ static void tcp_keepalive_timer (unsigned long data)
        elapsed = keepalive_time_elapsed(tp);
 
        if (elapsed >= keepalive_time_when(tp)) {
-               if (icsk->icsk_probes_out >= keepalive_probes(tp)) {
+               /* If the TCP_USER_TIMEOUT option is enabled, use that
+                * to determine when to timeout instead.
+                */
+               if ((icsk->icsk_user_timeout != 0 &&
+                   elapsed >= icsk->icsk_user_timeout &&
+                   icsk->icsk_probes_out > 0) ||
+                   (icsk->icsk_user_timeout == 0 &&
+                   icsk->icsk_probes_out >= keepalive_probes(tp))) {
                        tcp_send_active_reset(sk, GFP_ATOMIC);
                        tcp_write_err(sk);
                        goto out;
index 59186ca7808a20fcf6eda607491bcaba60cf2263..9a17bd2a0a37fdae55aca5aff11324dfa31ac1ca 100644 (file)
@@ -14,8 +14,8 @@
 #include <net/protocol.h>
 #include <net/xfrm.h>
 
-static struct xfrm_tunnel *tunnel4_handlers;
-static struct xfrm_tunnel *tunnel64_handlers;
+static struct xfrm_tunnel *tunnel4_handlers __read_mostly;
+static struct xfrm_tunnel *tunnel64_handlers __read_mostly;
 static DEFINE_MUTEX(tunnel4_mutex);
 
 static inline struct xfrm_tunnel **fam_handlers(unsigned short family)
@@ -39,7 +39,7 @@ int xfrm4_tunnel_register(struct xfrm_tunnel *handler, unsigned short family)
        }
 
        handler->next = *pprev;
-       *pprev = handler;
+       rcu_assign_pointer(*pprev, handler);
 
        ret = 0;
 
@@ -73,6 +73,11 @@ int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler, unsigned short family)
 }
 EXPORT_SYMBOL(xfrm4_tunnel_deregister);
 
+#define for_each_tunnel_rcu(head, handler)             \
+       for (handler = rcu_dereference(head);           \
+            handler != NULL;                           \
+            handler = rcu_dereference(handler->next))  \
+       
 static int tunnel4_rcv(struct sk_buff *skb)
 {
        struct xfrm_tunnel *handler;
@@ -80,7 +85,7 @@ static int tunnel4_rcv(struct sk_buff *skb)
        if (!pskb_may_pull(skb, sizeof(struct iphdr)))
                goto drop;
 
-       for (handler = tunnel4_handlers; handler; handler = handler->next)
+       for_each_tunnel_rcu(tunnel4_handlers, handler)
                if (!handler->handler(skb))
                        return 0;
 
@@ -99,7 +104,7 @@ static int tunnel64_rcv(struct sk_buff *skb)
        if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
                goto drop;
 
-       for (handler = tunnel64_handlers; handler; handler = handler->next)
+       for_each_tunnel_rcu(tunnel64_handlers, handler)
                if (!handler->handler(skb))
                        return 0;
 
@@ -115,7 +120,7 @@ static void tunnel4_err(struct sk_buff *skb, u32 info)
 {
        struct xfrm_tunnel *handler;
 
-       for (handler = tunnel4_handlers; handler; handler = handler->next)
+       for_each_tunnel_rcu(tunnel4_handlers, handler)
                if (!handler->err_handler(skb, info))
                        break;
 }
@@ -125,7 +130,7 @@ static void tunnel64_err(struct sk_buff *skb, u32 info)
 {
        struct xfrm_tunnel *handler;
 
-       for (handler = tunnel64_handlers; handler; handler = handler->next)
+       for_each_tunnel_rcu(tunnel64_handlers, handler)
                if (!handler->err_handler(skb, info))
                        break;
 }
index fb23c2e63b5281a7ca505af3ac94f411e10c4ee6..b3f7e8cf18ac4227d298c7d4d659a7d19c50a244 100644 (file)
@@ -797,7 +797,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
                return -EOPNOTSUPP;
 
        ipc.opt = NULL;
-       ipc.shtx.flags = 0;
+       ipc.tx_flags = 0;
 
        if (up->pending) {
                /*
@@ -845,7 +845,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
        ipc.addr = inet->inet_saddr;
 
        ipc.oif = sk->sk_bound_dev_if;
-       err = sock_tx_timestamp(msg, sk, &ipc.shtx);
+       err = sock_tx_timestamp(sk, &ipc.tx_flags);
        if (err)
                return err;
        if (msg->msg_controllen) {
index 41f5982d20876ecb7ab1df92f5533d451b932ee2..82806455e8598862d1e925ff24a05403e8cd6519 100644 (file)
@@ -58,14 +58,14 @@ static int xfrm_tunnel_err(struct sk_buff *skb, u32 info)
        return -ENOENT;
 }
 
-static struct xfrm_tunnel xfrm_tunnel_handler = {
+static struct xfrm_tunnel xfrm_tunnel_handler __read_mostly = {
        .handler        =       xfrm_tunnel_rcv,
        .err_handler    =       xfrm_tunnel_err,
        .priority       =       2,
 };
 
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-static struct xfrm_tunnel xfrm64_tunnel_handler = {
+static struct xfrm_tunnel xfrm64_tunnel_handler __read_mostly = {
        .handler        =       xfrm_tunnel_rcv,
        .err_handler    =       xfrm_tunnel_err,
        .priority       =       2,
index ab70a3fbcafafee9a080ea0f8c6eab2ce04fc37e..5bc893e28008147b500ea1a6c0aedb7d1c262bbe 100644 (file)
@@ -2964,7 +2964,8 @@ static void addrconf_dad_completed(struct inet6_ifaddr *ifp)
           start sending router solicitations.
         */
 
-       if (ifp->idev->cnf.forwarding == 0 &&
+       if ((ifp->idev->cnf.forwarding == 0 ||
+            ifp->idev->cnf.forwarding == 2) &&
            ifp->idev->cnf.rtr_solicits > 0 &&
            (dev->flags&IFF_LOOPBACK) == 0 &&
            (ipv6_addr_type(&ifp->addr) & IPV6_ADDR_LINKLOCAL)) {
index d40b330c0ee698af62f51f90caf86b2e6cf04c9f..1838927a2243801c614ace6ad1b91bb06a7549b9 100644 (file)
@@ -637,7 +637,7 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
        }
        mtu -= hlen + sizeof(struct frag_hdr);
 
-       if (skb_has_frags(skb)) {
+       if (skb_has_frag_list(skb)) {
                int first_len = skb_pagelen(skb);
                int truesizes = 0;
 
index 0fd027f3f47e170608d75ea735a74f535838b80a..29f99dd75bc6307d35499ed4ca70a46bb855d1d8 100644 (file)
@@ -1372,13 +1372,13 @@ static void __net_init ip6_fb_tnl_dev_init(struct net_device *dev)
        ip6n->tnls_wc[0] = t;
 }
 
-static struct xfrm6_tunnel ip4ip6_handler = {
+static struct xfrm6_tunnel ip4ip6_handler __read_mostly = {
        .handler        = ip4ip6_rcv,
        .err_handler    = ip4ip6_err,
        .priority       =       1,
 };
 
-static struct xfrm6_tunnel ip6ip6_handler = {
+static struct xfrm6_tunnel ip6ip6_handler __read_mostly = {
        .handler        = ip6ip6_rcv,
        .err_handler    = ip6ip6_err,
        .priority       =       1,
index 58841c4ae947f982d3377009066ed636fa37ea75..69a0051cea67b9d22c7fbe6d61718b2ab20111bb 100644 (file)
@@ -1105,6 +1105,18 @@ errout:
        rtnl_set_sk_err(net, RTNLGRP_ND_USEROPT, err);
 }
 
+static inline int accept_ra(struct inet6_dev *in6_dev)
+{
+       /*
+        * If forwarding is enabled, RA are not accepted unless the special
+        * hybrid mode (accept_ra=2) is enabled.
+        */
+       if (in6_dev->cnf.forwarding && in6_dev->cnf.accept_ra < 2)
+               return 0;
+
+       return in6_dev->cnf.accept_ra;
+}
+
 static void ndisc_router_discovery(struct sk_buff *skb)
 {
        struct ra_msg *ra_msg = (struct ra_msg *)skb_transport_header(skb);
@@ -1158,8 +1170,7 @@ static void ndisc_router_discovery(struct sk_buff *skb)
                return;
        }
 
-       /* skip route and link configuration on routers */
-       if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_ra)
+       if (!accept_ra(in6_dev))
                goto skip_linkparms;
 
 #ifdef CONFIG_IPV6_NDISC_NODETYPE
@@ -1309,8 +1320,7 @@ skip_linkparms:
                             NEIGH_UPDATE_F_ISROUTER);
        }
 
-       /* skip route and link configuration on routers */
-       if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_ra)
+       if (!accept_ra(in6_dev))
                goto out;
 
 #ifdef CONFIG_IPV6_ROUTE_INFO
index 578f3c1a16db614614f986947cbae5a7960fcdb5..138a8b36270694ec96ca4a21f51a55b0c1d62e98 100644 (file)
@@ -363,7 +363,7 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev)
        /* If the first fragment is fragmented itself, we split
         * it to two chunks: the first with data and paged part
         * and the second, holding only fragments. */
-       if (skb_has_frags(head)) {
+       if (skb_has_frag_list(head)) {
                struct sk_buff *clone;
                int i, plen = 0;
 
index 1fa3468f0f323782413c1931258c61aa9130f450..9bb936ae24524362fd5748b42360b2955dc474a9 100644 (file)
 #include <linux/spinlock.h>
 #include <net/protocol.h>
 
-const struct inet6_protocol *inet6_protos[MAX_INET_PROTOS];
-static DEFINE_SPINLOCK(inet6_proto_lock);
-
+const struct inet6_protocol *inet6_protos[MAX_INET_PROTOS] __read_mostly;
 
 int inet6_add_protocol(const struct inet6_protocol *prot, unsigned char protocol)
 {
-       int ret, hash = protocol & (MAX_INET_PROTOS - 1);
-
-       spin_lock_bh(&inet6_proto_lock);
-
-       if (inet6_protos[hash]) {
-               ret = -1;
-       } else {
-               inet6_protos[hash] = prot;
-               ret = 0;
-       }
-
-       spin_unlock_bh(&inet6_proto_lock);
+       int hash = protocol & (MAX_INET_PROTOS - 1);
 
-       return ret;
+       return !cmpxchg(&inet6_protos[hash], NULL, prot) ? 0 : -1;
 }
-
 EXPORT_SYMBOL(inet6_add_protocol);
 
 /*
@@ -57,20 +43,10 @@ int inet6_del_protocol(const struct inet6_protocol *prot, unsigned char protocol
 {
        int ret, hash = protocol & (MAX_INET_PROTOS - 1);
 
-       spin_lock_bh(&inet6_proto_lock);
-
-       if (inet6_protos[hash] != prot) {
-               ret = -1;
-       } else {
-               inet6_protos[hash] = NULL;
-               ret = 0;
-       }
-
-       spin_unlock_bh(&inet6_proto_lock);
+       ret = (cmpxchg(&inet6_protos[hash], prot, NULL) == prot) ? 0 : -1;
 
        synchronize_net();
 
        return ret;
 }
-
 EXPORT_SYMBOL(inet6_del_protocol);
index 64cfef1b0a4c556ccf63c2f912c86ec3a1599b82..c7ba3149633fcf79160849498d87ae5e53f695b1 100644 (file)
@@ -458,7 +458,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev,
        /* If the first fragment is fragmented itself, we split
         * it to two chunks: the first with data and paged part
         * and the second, holding only fragments. */
-       if (skb_has_frags(head)) {
+       if (skb_has_frag_list(head)) {
                struct sk_buff *clone;
                int i, plen = 0;
 
index 4699cd3c3118ffefb90d4f1e587683aedddcc866..86618eb3033505df3915533f46359269699ecf7c 100644 (file)
@@ -1132,7 +1132,7 @@ static void __net_init ipip6_fb_tunnel_init(struct net_device *dev)
        sitn->tunnels_wc[0]     = tunnel;
 }
 
-static struct xfrm_tunnel sit_handler = {
+static struct xfrm_tunnel sit_handler __read_mostly = {
        .handler        =       ipip6_rcv,
        .err_handler    =       ipip6_err,
        .priority       =       1,
index fc3c86a474526ee1c3b9c3f644fbe1d14c458f0e..d9864725d0c6a259ba8a4d35cbe08762de5e53f4 100644 (file)
@@ -30,8 +30,8 @@
 #include <net/protocol.h>
 #include <net/xfrm.h>
 
-static struct xfrm6_tunnel *tunnel6_handlers;
-static struct xfrm6_tunnel *tunnel46_handlers;
+static struct xfrm6_tunnel *tunnel6_handlers __read_mostly;
+static struct xfrm6_tunnel *tunnel46_handlers __read_mostly;
 static DEFINE_MUTEX(tunnel6_mutex);
 
 int xfrm6_tunnel_register(struct xfrm6_tunnel *handler, unsigned short family)
@@ -51,7 +51,7 @@ int xfrm6_tunnel_register(struct xfrm6_tunnel *handler, unsigned short family)
        }
 
        handler->next = *pprev;
-       *pprev = handler;
+       rcu_assign_pointer(*pprev, handler);
 
        ret = 0;
 
@@ -88,6 +88,11 @@ int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler, unsigned short family)
 
 EXPORT_SYMBOL(xfrm6_tunnel_deregister);
 
+#define for_each_tunnel_rcu(head, handler)             \
+       for (handler = rcu_dereference(head);           \
+            handler != NULL;                           \
+            handler = rcu_dereference(handler->next))  \
+
 static int tunnel6_rcv(struct sk_buff *skb)
 {
        struct xfrm6_tunnel *handler;
@@ -95,7 +100,7 @@ static int tunnel6_rcv(struct sk_buff *skb)
        if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
                goto drop;
 
-       for (handler = tunnel6_handlers; handler; handler = handler->next)
+       for_each_tunnel_rcu(tunnel6_handlers, handler)
                if (!handler->handler(skb))
                        return 0;
 
@@ -113,7 +118,7 @@ static int tunnel46_rcv(struct sk_buff *skb)
        if (!pskb_may_pull(skb, sizeof(struct iphdr)))
                goto drop;
 
-       for (handler = tunnel46_handlers; handler; handler = handler->next)
+       for_each_tunnel_rcu(tunnel46_handlers, handler)
                if (!handler->handler(skb))
                        return 0;
 
@@ -129,7 +134,7 @@ static void tunnel6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
 {
        struct xfrm6_tunnel *handler;
 
-       for (handler = tunnel6_handlers; handler; handler = handler->next)
+       for_each_tunnel_rcu(tunnel6_handlers, handler)
                if (!handler->err_handler(skb, opt, type, code, offset, info))
                        break;
 }
index 2ce3a8278f26576668ffafd178891451e2b5fc87..ac7584b946a5c38692b626f2c939701e1e5b1cb8 100644 (file)
@@ -317,13 +317,13 @@ static const struct xfrm_type xfrm6_tunnel_type = {
        .output         = xfrm6_tunnel_output,
 };
 
-static struct xfrm6_tunnel xfrm6_tunnel_handler = {
+static struct xfrm6_tunnel xfrm6_tunnel_handler __read_mostly = {
        .handler        = xfrm6_tunnel_rcv,
        .err_handler    = xfrm6_tunnel_err,
        .priority       = 2,
 };
 
-static struct xfrm6_tunnel xfrm46_tunnel_handler = {
+static struct xfrm6_tunnel xfrm46_tunnel_handler __read_mostly = {
        .handler        = xfrm6_tunnel_rcv,
        .err_handler    = xfrm6_tunnel_err,
        .priority       = 2,
index 5bb8353105cca7c761647b94c346cc1da82c42e9..8ee1ff6c742fd6745482f8e0327ab7a3c2d86fe5 100644 (file)
@@ -45,13 +45,11 @@ static int  irlan_eth_close(struct net_device *dev);
 static netdev_tx_t  irlan_eth_xmit(struct sk_buff *skb,
                                         struct net_device *dev);
 static void irlan_eth_set_multicast_list( struct net_device *dev);
-static struct net_device_stats *irlan_eth_get_stats(struct net_device *dev);
 
 static const struct net_device_ops irlan_eth_netdev_ops = {
        .ndo_open               = irlan_eth_open,
        .ndo_stop               = irlan_eth_close,
        .ndo_start_xmit         = irlan_eth_xmit,
-       .ndo_get_stats          = irlan_eth_get_stats,
        .ndo_set_multicast_list = irlan_eth_set_multicast_list,
        .ndo_change_mtu         = eth_change_mtu,
        .ndo_validate_addr      = eth_validate_addr,
@@ -208,10 +206,10 @@ static netdev_tx_t irlan_eth_xmit(struct sk_buff *skb,
                 * tried :-) DB
                 */
                /* irttp_data_request already free the packet */
-               self->stats.tx_dropped++;
+               dev->stats.tx_dropped++;
        } else {
-               self->stats.tx_packets++;
-               self->stats.tx_bytes += len;
+               dev->stats.tx_packets++;
+               dev->stats.tx_bytes += len;
        }
 
        return NETDEV_TX_OK;
@@ -226,15 +224,16 @@ static netdev_tx_t irlan_eth_xmit(struct sk_buff *skb,
 int irlan_eth_receive(void *instance, void *sap, struct sk_buff *skb)
 {
        struct irlan_cb *self = instance;
+       struct net_device *dev = self->dev;
 
        if (skb == NULL) {
-               ++self->stats.rx_dropped;
+               dev->stats.rx_dropped++;
                return 0;
        }
        if (skb->len < ETH_HLEN) {
                IRDA_DEBUG(0, "%s() : IrLAN frame too short (%d)\n",
                           __func__, skb->len);
-               ++self->stats.rx_dropped;
+               dev->stats.rx_dropped++;
                dev_kfree_skb(skb);
                return 0;
        }
@@ -244,10 +243,10 @@ int irlan_eth_receive(void *instance, void *sap, struct sk_buff *skb)
         * might have been previously set by the low level IrDA network
         * device driver
         */
-       skb->protocol = eth_type_trans(skb, self->dev); /* Remove eth header */
+       skb->protocol = eth_type_trans(skb, dev); /* Remove eth header */
 
-       self->stats.rx_packets++;
-       self->stats.rx_bytes += skb->len;
+       dev->stats.rx_packets++;
+       dev->stats.rx_bytes += skb->len;
 
        netif_rx(skb);   /* Eat it! */
 
@@ -348,16 +347,3 @@ static void irlan_eth_set_multicast_list(struct net_device *dev)
        else
                irlan_set_broadcast_filter(self, FALSE);
 }
-
-/*
- * Function irlan_get_stats (dev)
- *
- *    Get the current statistics for this device
- *
- */
-static struct net_device_stats *irlan_eth_get_stats(struct net_device *dev)
-{
-       struct irlan_cb *self = netdev_priv(dev);
-
-       return &self->stats;
-}
index 1ae697681bc735f3f4ed8cf98f9f63745157be36..8d9ce0accc98229e8255853e18b18c2ea4a2d410 100644 (file)
@@ -144,7 +144,6 @@ static void l2tp_eth_dev_recv(struct l2tp_session *session, struct sk_buff *skb,
        nf_reset(skb);
 
        if (dev_forward_skb(dev, skb) == NET_RX_SUCCESS) {
-               dev->last_rx = jiffies;
                dev->stats.rx_packets++;
                dev->stats.rx_bytes += data_len;
        } else
index a87cb3ba2df6eeb146a94a4aba539e99b20b5889..d2b03e0851ef6502f6eeb3064ea93db8e31e7977 100644 (file)
@@ -138,10 +138,8 @@ struct crypto_cipher *ieee80211_aes_key_setup_encrypt(const u8 key[])
        struct crypto_cipher *tfm;
 
        tfm = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC);
-       if (IS_ERR(tfm))
-               return NULL;
-
-       crypto_cipher_setkey(tfm, key, ALG_CCMP_KEY_LEN);
+       if (!IS_ERR(tfm))
+               crypto_cipher_setkey(tfm, key, ALG_CCMP_KEY_LEN);
 
        return tfm;
 }
index 3d097b3d7b62ad86c94a86eec92a3b9b3554c526..b4d66cca76d6d719324cee76d2706881df69e4a0 100644 (file)
@@ -119,10 +119,8 @@ struct crypto_cipher * ieee80211_aes_cmac_key_setup(const u8 key[])
        struct crypto_cipher *tfm;
 
        tfm = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC);
-       if (IS_ERR(tfm))
-               return NULL;
-
-       crypto_cipher_setkey(tfm, key, AES_CMAC_KEY_LEN);
+       if (!IS_ERR(tfm))
+               crypto_cipher_setkey(tfm, key, AES_CMAC_KEY_LEN);
 
        return tfm;
 }
index 965b272499fd7616e4df039e3c878dda678f5cf9..58eab9e8e4eedaaaef445cfc082546c1af1c1328 100644 (file)
@@ -86,6 +86,7 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
                                     tid, 0, reason);
 
        del_timer_sync(&tid_rx->session_timer);
+       del_timer_sync(&tid_rx->reorder_timer);
 
        call_rcu(&tid_rx->rcu_head, ieee80211_free_tid_rx);
 }
@@ -120,6 +121,20 @@ static void sta_rx_agg_session_timer_expired(unsigned long data)
        ieee80211_queue_work(&sta->local->hw, &sta->ampdu_mlme.work);
 }
 
+static void sta_rx_agg_reorder_timer_expired(unsigned long data)
+{
+       u8 *ptid = (u8 *)data;
+       u8 *timer_to_id = ptid - *ptid;
+       struct sta_info *sta = container_of(timer_to_id, struct sta_info,
+                       timer_to_tid[0]);
+
+       rcu_read_lock();
+       spin_lock(&sta->lock);
+       ieee80211_release_reorder_timeout(sta, *ptid);
+       spin_unlock(&sta->lock);
+       rcu_read_unlock();
+}
+
 static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *da, u16 tid,
                                      u8 dialog_token, u16 status, u16 policy,
                                      u16 buf_size, u16 timeout)
@@ -251,11 +266,18 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
                goto end;
        }
 
+       spin_lock_init(&tid_agg_rx->reorder_lock);
+
        /* rx timer */
        tid_agg_rx->session_timer.function = sta_rx_agg_session_timer_expired;
        tid_agg_rx->session_timer.data = (unsigned long)&sta->timer_to_tid[tid];
        init_timer(&tid_agg_rx->session_timer);
 
+       /* rx reorder timer */
+       tid_agg_rx->reorder_timer.function = sta_rx_agg_reorder_timer_expired;
+       tid_agg_rx->reorder_timer.data = (unsigned long)&sta->timer_to_tid[tid];
+       init_timer(&tid_agg_rx->reorder_timer);
+
        /* prepare reordering buffer */
        tid_agg_rx->reorder_buf =
                kcalloc(buf_size, sizeof(struct sk_buff *), GFP_ATOMIC);
index 29ac8e1a509e48ec1170f61f668d8d3d5712d501..5de1ca3f17b93bd13db9c4ba762fd2df8d7aa276 100644 (file)
 #include "rate.h"
 #include "mesh.h"
 
-static bool nl80211_type_check(enum nl80211_iftype type)
-{
-       switch (type) {
-       case NL80211_IFTYPE_ADHOC:
-       case NL80211_IFTYPE_STATION:
-       case NL80211_IFTYPE_MONITOR:
-#ifdef CONFIG_MAC80211_MESH
-       case NL80211_IFTYPE_MESH_POINT:
-#endif
-       case NL80211_IFTYPE_AP:
-       case NL80211_IFTYPE_AP_VLAN:
-       case NL80211_IFTYPE_WDS:
-               return true;
-       default:
-               return false;
-       }
-}
-
-static bool nl80211_params_check(enum nl80211_iftype type,
-                                struct vif_params *params)
-{
-       if (!nl80211_type_check(type))
-               return false;
-
-       return true;
-}
-
 static int ieee80211_add_iface(struct wiphy *wiphy, char *name,
                               enum nl80211_iftype type, u32 *flags,
                               struct vif_params *params)
@@ -55,9 +28,6 @@ static int ieee80211_add_iface(struct wiphy *wiphy, char *name,
        struct ieee80211_sub_if_data *sdata;
        int err;
 
-       if (!nl80211_params_check(type, params))
-               return -EINVAL;
-
        err = ieee80211_if_add(local, name, &dev, type, params);
        if (err || type != NL80211_IFTYPE_MONITOR || !flags)
                return err;
@@ -82,12 +52,6 @@ static int ieee80211_change_iface(struct wiphy *wiphy,
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        int ret;
 
-       if (ieee80211_sdata_running(sdata))
-               return -EBUSY;
-
-       if (!nl80211_params_check(type, params))
-               return -EINVAL;
-
        ret = ieee80211_if_change_type(sdata, type);
        if (ret)
                return ret;
@@ -114,44 +78,30 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
                             u8 key_idx, const u8 *mac_addr,
                             struct key_params *params)
 {
-       struct ieee80211_sub_if_data *sdata;
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct sta_info *sta = NULL;
-       enum ieee80211_key_alg alg;
        struct ieee80211_key *key;
        int err;
 
-       if (!netif_running(dev))
+       if (!ieee80211_sdata_running(sdata))
                return -ENETDOWN;
 
-       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
+       /* reject WEP and TKIP keys if WEP failed to initialize */
        switch (params->cipher) {
        case WLAN_CIPHER_SUITE_WEP40:
-       case WLAN_CIPHER_SUITE_WEP104:
-               alg = ALG_WEP;
-               break;
        case WLAN_CIPHER_SUITE_TKIP:
-               alg = ALG_TKIP;
-               break;
-       case WLAN_CIPHER_SUITE_CCMP:
-               alg = ALG_CCMP;
-               break;
-       case WLAN_CIPHER_SUITE_AES_CMAC:
-               alg = ALG_AES_CMAC;
+       case WLAN_CIPHER_SUITE_WEP104:
+               if (IS_ERR(sdata->local->wep_tx_tfm))
+                       return -EINVAL;
                break;
        default:
-               return -EINVAL;
+               break;
        }
 
-       /* reject WEP and TKIP keys if WEP failed to initialize */
-       if ((alg == ALG_WEP || alg == ALG_TKIP) &&
-           IS_ERR(sdata->local->wep_tx_tfm))
-               return -EINVAL;
-
-       key = ieee80211_key_alloc(alg, key_idx, params->key_len, params->key,
-                                 params->seq_len, params->seq);
-       if (!key)
-               return -ENOMEM;
+       key = ieee80211_key_alloc(params->cipher, key_idx, params->key_len,
+                                 params->key, params->seq_len, params->seq);
+       if (IS_ERR(key))
+               return PTR_ERR(key);
 
        mutex_lock(&sdata->local->sta_mtx);
 
@@ -164,9 +114,10 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
                }
        }
 
-       ieee80211_key_link(key, sdata, sta);
+       err = ieee80211_key_link(key, sdata, sta);
+       if (err)
+               ieee80211_key_free(sdata->local, key);
 
-       err = 0;
  out_unlock:
        mutex_unlock(&sdata->local->sta_mtx);
 
@@ -247,10 +198,10 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
 
        memset(&params, 0, sizeof(params));
 
-       switch (key->conf.alg) {
-       case ALG_TKIP:
-               params.cipher = WLAN_CIPHER_SUITE_TKIP;
+       params.cipher = key->conf.cipher;
 
+       switch (key->conf.cipher) {
+       case WLAN_CIPHER_SUITE_TKIP:
                iv32 = key->u.tkip.tx.iv32;
                iv16 = key->u.tkip.tx.iv16;
 
@@ -268,8 +219,7 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
                params.seq = seq;
                params.seq_len = 6;
                break;
-       case ALG_CCMP:
-               params.cipher = WLAN_CIPHER_SUITE_CCMP;
+       case WLAN_CIPHER_SUITE_CCMP:
                seq[0] = key->u.ccmp.tx_pn[5];
                seq[1] = key->u.ccmp.tx_pn[4];
                seq[2] = key->u.ccmp.tx_pn[3];
@@ -279,14 +229,7 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
                params.seq = seq;
                params.seq_len = 6;
                break;
-       case ALG_WEP:
-               if (key->conf.keylen == 5)
-                       params.cipher = WLAN_CIPHER_SUITE_WEP40;
-               else
-                       params.cipher = WLAN_CIPHER_SUITE_WEP104;
-               break;
-       case ALG_AES_CMAC:
-               params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
+       case WLAN_CIPHER_SUITE_AES_CMAC:
                seq[0] = key->u.aes_cmac.tx_pn[5];
                seq[1] = key->u.aes_cmac.tx_pn[4];
                seq[2] = key->u.aes_cmac.tx_pn[3];
@@ -1143,9 +1086,9 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy,
        p.uapsd = false;
 
        if (drv_conf_tx(local, params->queue, &p)) {
-               printk(KERN_DEBUG "%s: failed to set TX queue "
-                      "parameters for queue %d\n",
-                      wiphy_name(local->hw.wiphy), params->queue);
+               wiphy_debug(local->hw.wiphy,
+                           "failed to set TX queue parameters for queue %d\n",
+                           params->queue);
                return -EINVAL;
        }
 
@@ -1541,11 +1484,11 @@ static int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy,
        return ieee80211_wk_cancel_remain_on_channel(sdata, cookie);
 }
 
-static int ieee80211_action(struct wiphy *wiphy, struct net_device *dev,
-                           struct ieee80211_channel *chan,
-                           enum nl80211_channel_type channel_type,
-                           bool channel_type_valid,
-                           const u8 *buf, size_t len, u64 *cookie)
+static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
+                            struct ieee80211_channel *chan,
+                            enum nl80211_channel_type channel_type,
+                            bool channel_type_valid,
+                            const u8 *buf, size_t len, u64 *cookie)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ieee80211_local *local = sdata->local;
@@ -1575,8 +1518,6 @@ static int ieee80211_action(struct wiphy *wiphy, struct net_device *dev,
                        return -ENOLINK;
                break;
        case NL80211_IFTYPE_STATION:
-               if (!(sdata->u.mgd.flags & IEEE80211_STA_MFP_ENABLED))
-                       flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
                break;
        default:
                return -EOPNOTSUPP;
@@ -1647,6 +1588,6 @@ struct cfg80211_ops mac80211_config_ops = {
        .set_bitrate_mask = ieee80211_set_bitrate_mask,
        .remain_on_channel = ieee80211_remain_on_channel,
        .cancel_remain_on_channel = ieee80211_cancel_remain_on_channel,
-       .action = ieee80211_action,
+       .mgmt_tx = ieee80211_mgmt_tx,
        .set_cqm_rssi_config = ieee80211_set_cqm_rssi_config,
 };
index a694c593ff6ac1e17479ae07d26ad1fd02f258ba..e81ef4e8cb323eeca8ea32492a23cdb96f7a4b43 100644 (file)
@@ -85,13 +85,15 @@ static ssize_t tsf_write(struct file *file,
        if (strncmp(buf, "reset", 5) == 0) {
                if (local->ops->reset_tsf) {
                        drv_reset_tsf(local);
-                       printk(KERN_INFO "%s: debugfs reset TSF\n", wiphy_name(local->hw.wiphy));
+                       wiphy_info(local->hw.wiphy, "debugfs reset TSF\n");
                }
        } else {
                tsf = simple_strtoul(buf, NULL, 0);
                if (local->ops->set_tsf) {
                        drv_set_tsf(local, tsf);
-                       printk(KERN_INFO "%s: debugfs set TSF to %#018llx\n", wiphy_name(local->hw.wiphy), tsf);
+                       wiphy_info(local->hw.wiphy,
+                                  "debugfs set TSF to %#018llx\n", tsf);
+
                }
        }
 
index fa5e76e658ef058b5fb87c4d4647c5025a3e4d71..1647f8dc5cdab475d727c49060c1db0985aaa76d 100644 (file)
@@ -64,26 +64,13 @@ static ssize_t key_algorithm_read(struct file *file,
                                  char __user *userbuf,
                                  size_t count, loff_t *ppos)
 {
-       char *alg;
+       char buf[15];
        struct ieee80211_key *key = file->private_data;
+       u32 c = key->conf.cipher;
 
-       switch (key->conf.alg) {
-       case ALG_WEP:
-               alg = "WEP\n";
-               break;
-       case ALG_TKIP:
-               alg = "TKIP\n";
-               break;
-       case ALG_CCMP:
-               alg = "CCMP\n";
-               break;
-       case ALG_AES_CMAC:
-               alg = "AES-128-CMAC\n";
-               break;
-       default:
-               return 0;
-       }
-       return simple_read_from_buffer(userbuf, count, ppos, alg, strlen(alg));
+       sprintf(buf, "%.2x-%.2x-%.2x:%d\n",
+               c >> 24, (c >> 16) & 0xff, (c >> 8) & 0xff, c & 0xff);
+       return simple_read_from_buffer(userbuf, count, ppos, buf, strlen(buf));
 }
 KEY_OPS(algorithm);
 
@@ -95,21 +82,22 @@ static ssize_t key_tx_spec_read(struct file *file, char __user *userbuf,
        int len;
        struct ieee80211_key *key = file->private_data;
 
-       switch (key->conf.alg) {
-       case ALG_WEP:
+       switch (key->conf.cipher) {
+       case WLAN_CIPHER_SUITE_WEP40:
+       case WLAN_CIPHER_SUITE_WEP104:
                len = scnprintf(buf, sizeof(buf), "\n");
                break;
-       case ALG_TKIP:
+       case WLAN_CIPHER_SUITE_TKIP:
                len = scnprintf(buf, sizeof(buf), "%08x %04x\n",
                                key->u.tkip.tx.iv32,
                                key->u.tkip.tx.iv16);
                break;
-       case ALG_CCMP:
+       case WLAN_CIPHER_SUITE_CCMP:
                tpn = key->u.ccmp.tx_pn;
                len = scnprintf(buf, sizeof(buf), "%02x%02x%02x%02x%02x%02x\n",
                                tpn[0], tpn[1], tpn[2], tpn[3], tpn[4], tpn[5]);
                break;
-       case ALG_AES_CMAC:
+       case WLAN_CIPHER_SUITE_AES_CMAC:
                tpn = key->u.aes_cmac.tx_pn;
                len = scnprintf(buf, sizeof(buf), "%02x%02x%02x%02x%02x%02x\n",
                                tpn[0], tpn[1], tpn[2], tpn[3], tpn[4],
@@ -130,11 +118,12 @@ static ssize_t key_rx_spec_read(struct file *file, char __user *userbuf,
        int i, len;
        const u8 *rpn;
 
-       switch (key->conf.alg) {
-       case ALG_WEP:
+       switch (key->conf.cipher) {
+       case WLAN_CIPHER_SUITE_WEP40:
+       case WLAN_CIPHER_SUITE_WEP104:
                len = scnprintf(buf, sizeof(buf), "\n");
                break;
-       case ALG_TKIP:
+       case WLAN_CIPHER_SUITE_TKIP:
                for (i = 0; i < NUM_RX_DATA_QUEUES; i++)
                        p += scnprintf(p, sizeof(buf)+buf-p,
                                       "%08x %04x\n",
@@ -142,7 +131,7 @@ static ssize_t key_rx_spec_read(struct file *file, char __user *userbuf,
                                       key->u.tkip.rx[i].iv16);
                len = p - buf;
                break;
-       case ALG_CCMP:
+       case WLAN_CIPHER_SUITE_CCMP:
                for (i = 0; i < NUM_RX_DATA_QUEUES + 1; i++) {
                        rpn = key->u.ccmp.rx_pn[i];
                        p += scnprintf(p, sizeof(buf)+buf-p,
@@ -152,7 +141,7 @@ static ssize_t key_rx_spec_read(struct file *file, char __user *userbuf,
                }
                len = p - buf;
                break;
-       case ALG_AES_CMAC:
+       case WLAN_CIPHER_SUITE_AES_CMAC:
                rpn = key->u.aes_cmac.rx_pn;
                p += scnprintf(p, sizeof(buf)+buf-p,
                               "%02x%02x%02x%02x%02x%02x\n",
@@ -174,11 +163,11 @@ static ssize_t key_replays_read(struct file *file, char __user *userbuf,
        char buf[20];
        int len;
 
-       switch (key->conf.alg) {
-       case ALG_CCMP:
+       switch (key->conf.cipher) {
+       case WLAN_CIPHER_SUITE_CCMP:
                len = scnprintf(buf, sizeof(buf), "%u\n", key->u.ccmp.replays);
                break;
-       case ALG_AES_CMAC:
+       case WLAN_CIPHER_SUITE_AES_CMAC:
                len = scnprintf(buf, sizeof(buf), "%u\n",
                                key->u.aes_cmac.replays);
                break;
@@ -196,8 +185,8 @@ static ssize_t key_icverrors_read(struct file *file, char __user *userbuf,
        char buf[20];
        int len;
 
-       switch (key->conf.alg) {
-       case ALG_AES_CMAC:
+       switch (key->conf.cipher) {
+       case WLAN_CIPHER_SUITE_AES_CMAC:
                len = scnprintf(buf, sizeof(buf), "%u\n",
                                key->u.aes_cmac.icverrors);
                break;
index 14123dce544bf960a57d6f06fdbda6bbcc83f88a..6064b7b09e0142f719b1e744ee124267f8d61d1a 100644 (file)
@@ -54,6 +54,20 @@ static inline int drv_add_interface(struct ieee80211_local *local,
        return ret;
 }
 
+static inline int drv_change_interface(struct ieee80211_local *local,
+                                      struct ieee80211_sub_if_data *sdata,
+                                      enum nl80211_iftype type)
+{
+       int ret;
+
+       might_sleep();
+
+       trace_drv_change_interface(local, sdata, type);
+       ret = local->ops->change_interface(&local->hw, &sdata->vif, type);
+       trace_drv_return_int(local, ret);
+       return ret;
+}
+
 static inline void drv_remove_interface(struct ieee80211_local *local,
                                        struct ieee80211_vif *vif)
 {
index 5d5d2a97466837b75b14961bc3b14a48bd5d488e..f6f3d89e43faa206a56888b200030e8f3ed151e8 100644 (file)
@@ -136,6 +136,31 @@ TRACE_EVENT(drv_add_interface,
        )
 );
 
+TRACE_EVENT(drv_change_interface,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sub_if_data *sdata,
+                enum nl80211_iftype type),
+
+       TP_ARGS(local, sdata, type),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               VIF_ENTRY
+               __field(u32, new_type)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               VIF_ASSIGN;
+               __entry->new_type = type;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT  VIF_PR_FMT " new type:%d",
+               LOCAL_PR_ARG, VIF_PR_ARG, __entry->new_type
+       )
+);
+
 TRACE_EVENT(drv_remove_interface,
        TP_PROTO(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata),
 
@@ -336,7 +361,7 @@ TRACE_EVENT(drv_set_key,
                LOCAL_ENTRY
                VIF_ENTRY
                STA_ENTRY
-               __field(enum ieee80211_key_alg, alg)
+               __field(u32, cipher)
                __field(u8, hw_key_idx)
                __field(u8, flags)
                __field(s8, keyidx)
@@ -346,7 +371,7 @@ TRACE_EVENT(drv_set_key,
                LOCAL_ASSIGN;
                VIF_ASSIGN;
                STA_ASSIGN;
-               __entry->alg = key->alg;
+               __entry->cipher = key->cipher;
                __entry->flags = key->flags;
                __entry->keyidx = key->keyidx;
                __entry->hw_key_idx = key->hw_key_idx;
index 9d101fb33861f67ce1c9058b60f680709ca2d27c..11f74f5f7b2f837a3e6159736296478fb3125b8e 100644 (file)
@@ -265,3 +265,31 @@ int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata,
 
        return 0;
 }
+
+void ieee80211_request_smps_work(struct work_struct *work)
+{
+       struct ieee80211_sub_if_data *sdata =
+               container_of(work, struct ieee80211_sub_if_data,
+                            u.mgd.request_smps_work);
+
+       mutex_lock(&sdata->u.mgd.mtx);
+       __ieee80211_request_smps(sdata, sdata->u.mgd.driver_smps_mode);
+       mutex_unlock(&sdata->u.mgd.mtx);
+}
+
+void ieee80211_request_smps(struct ieee80211_vif *vif,
+                           enum ieee80211_smps_mode smps_mode)
+{
+       struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+
+       if (WARN_ON(vif->type != NL80211_IFTYPE_STATION))
+               return;
+
+       if (WARN_ON(smps_mode == IEEE80211_SMPS_OFF))
+               smps_mode = IEEE80211_SMPS_AUTOMATIC;
+
+       ieee80211_queue_work(&sdata->local->hw,
+                            &sdata->u.mgd.request_smps_work);
+}
+/* this might change ... don't want non-open drivers using it */
+EXPORT_SYMBOL_GPL(ieee80211_request_smps);
index c691780725a7fcfbaef4ac39802540288696ee6a..1a3aae54f0cf88a44d9fa819fd94d1518978d8fd 100644 (file)
@@ -427,8 +427,8 @@ struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
                return NULL;
 
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-       printk(KERN_DEBUG "%s: Adding new IBSS station %pM (dev=%s)\n",
-              wiphy_name(local->hw.wiphy), addr, sdata->name);
+       wiphy_debug(local->hw.wiphy, "Adding new IBSS station %pM (dev=%s)\n",
+                   addr, sdata->name);
 #endif
 
        sta = sta_info_alloc(sdata, addr, gfp);
@@ -920,12 +920,14 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
        memcpy(sdata->u.ibss.ssid, params->ssid, IEEE80211_MAX_SSID_LEN);
        sdata->u.ibss.ssid_len = params->ssid_len;
 
+       mutex_unlock(&sdata->u.ibss.mtx);
+
+       mutex_lock(&sdata->local->mtx);
        ieee80211_recalc_idle(sdata->local);
+       mutex_unlock(&sdata->local->mtx);
 
        ieee80211_queue_work(&sdata->local->hw, &sdata->work);
 
-       mutex_unlock(&sdata->u.ibss.mtx);
-
        return 0;
 }
 
@@ -980,7 +982,9 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata)
 
        mutex_unlock(&sdata->u.ibss.mtx);
 
+       mutex_lock(&local->mtx);
        ieee80211_recalc_idle(sdata->local);
+       mutex_unlock(&local->mtx);
 
        return 0;
 }
index 65e0ed6c29753c07084e9a884868df2bd40f2474..4e635e2fabdb14d640b3e5832dc00f45ecb65c4a 100644 (file)
@@ -50,12 +50,6 @@ struct ieee80211_local;
  * increased memory use (about 2 kB of RAM per entry). */
 #define IEEE80211_FRAGMENT_MAX 4
 
-/*
- * Time after which we ignore scan results and no longer report/use
- * them in any way.
- */
-#define IEEE80211_SCAN_RESULT_EXPIRE (10 * HZ)
-
 #define TU_TO_EXP_TIME(x)      (jiffies + usecs_to_jiffies((x) * 1024))
 
 #define IEEE80211_DEFAULT_UAPSD_QUEUES \
@@ -170,6 +164,7 @@ typedef unsigned __bitwise__ ieee80211_rx_result;
 #define IEEE80211_RX_RA_MATCH          BIT(1)
 #define IEEE80211_RX_AMSDU             BIT(2)
 #define IEEE80211_RX_FRAGMENTED                BIT(3)
+#define IEEE80211_MALFORMED_ACTION_FRM BIT(4)
 /* only add flags here that do not change with subframes of an aMPDU */
 
 struct ieee80211_rx_data {
@@ -343,7 +338,10 @@ struct ieee80211_if_managed {
        unsigned long timers_running; /* used for quiesce/restart */
        bool powersave; /* powersave requested for this iface */
        enum ieee80211_smps_mode req_smps, /* requested smps mode */
-                                ap_smps; /* smps mode AP thinks we're in */
+                                ap_smps, /* smps mode AP thinks we're in */
+                                driver_smps_mode; /* smps mode request */
+
+       struct work_struct request_smps_work;
 
        unsigned int flags;
 
@@ -370,6 +368,13 @@ struct ieee80211_if_managed {
         */
        int ave_beacon_signal;
 
+       /*
+        * Number of Beacon frames used in ave_beacon_signal. This can be used
+        * to avoid generating less reliable cqm events that would be based
+        * only on couple of received frames.
+        */
+       unsigned int count_beacon_signal;
+
        /*
         * Last Beacon frame signal strength average (ave_beacon_signal / 16)
         * that triggered a cqm event. 0 indicates that no event has been
@@ -474,6 +479,19 @@ enum ieee80211_sub_if_data_flags {
        IEEE80211_SDATA_DONT_BRIDGE_PACKETS     = BIT(3),
 };
 
+/**
+ * enum ieee80211_sdata_state_bits - virtual interface state bits
+ * @SDATA_STATE_RUNNING: virtual interface is up & running; this
+ *     mirrors netif_running() but is separate for interface type
+ *     change handling while the interface is up
+ * @SDATA_STATE_OFFCHANNEL: This interface is currently in offchannel
+ *     mode, so queues are stopped
+ */
+enum ieee80211_sdata_state_bits {
+       SDATA_STATE_RUNNING,
+       SDATA_STATE_OFFCHANNEL,
+};
+
 struct ieee80211_sub_if_data {
        struct list_head list;
 
@@ -487,6 +505,8 @@ struct ieee80211_sub_if_data {
 
        unsigned int flags;
 
+       unsigned long state;
+
        int drop_unencrypted;
 
        char name[IFNAMSIZ];
@@ -497,6 +517,9 @@ struct ieee80211_sub_if_data {
         */
        bool ht_opmode_valid;
 
+       /* to detect idle changes */
+       bool old_idle;
+
        /* Fragment table for host-based reassembly */
        struct ieee80211_fragment_entry fragments[IEEE80211_FRAGMENT_MAX];
        unsigned int fragment_next;
@@ -508,6 +531,8 @@ struct ieee80211_sub_if_data {
        struct ieee80211_key *default_mgmt_key;
 
        u16 sequence_number;
+       __be16 control_port_protocol;
+       bool control_port_no_encrypt;
 
        struct work_struct work;
        struct sk_buff_head skb_queue;
@@ -595,11 +620,17 @@ enum queue_stop_reason {
  *     determine if we are on the operating channel or not
  * @SCAN_OFF_CHANNEL: We're off our operating channel for scanning,
  *     gets only set in conjunction with SCAN_SW_SCANNING
+ * @SCAN_COMPLETED: Set for our scan work function when the driver reported
+ *     that the scan completed.
+ * @SCAN_ABORTED: Set for our scan work function when the driver reported
+ *     a scan complete for an aborted scan.
  */
 enum {
        SCAN_SW_SCANNING,
        SCAN_HW_SCANNING,
        SCAN_OFF_CHANNEL,
+       SCAN_COMPLETED,
+       SCAN_ABORTED,
 };
 
 /**
@@ -634,7 +665,6 @@ struct ieee80211_local {
        /*
         * work stuff, potentially off-channel (in the future)
         */
-       struct mutex work_mtx;
        struct list_head work_list;
        struct timer_list work_timer;
        struct work_struct work_work;
@@ -656,6 +686,8 @@ struct ieee80211_local {
        int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss, fif_pspoll;
        unsigned int filter_flags; /* FIF_* */
 
+       bool wiphy_ciphers_allocated;
+
        /* protects the aggregated multicast list and filter calls */
        spinlock_t filter_lock;
 
@@ -746,9 +778,10 @@ struct ieee80211_local {
         */
        struct mutex key_mtx;
 
+       /* mutex for scan and work locking */
+       struct mutex mtx;
 
        /* Scanning and BSS list */
-       struct mutex scan_mtx;
        unsigned long scanning;
        struct cfg80211_ssid scan_ssid;
        struct cfg80211_scan_request *int_scan_req;
@@ -870,6 +903,11 @@ struct ieee80211_local {
                struct dentry *keys;
        } debugfs;
 #endif
+
+       /* dummy netdev for use w/ NAPI */
+       struct net_device napi_dev;
+
+       struct napi_struct napi;
 };
 
 static inline struct ieee80211_sub_if_data *
@@ -1071,7 +1109,7 @@ void ieee80211_recalc_idle(struct ieee80211_local *local);
 
 static inline bool ieee80211_sdata_running(struct ieee80211_sub_if_data *sdata)
 {
-       return netif_running(sdata->dev);
+       return test_bit(SDATA_STATE_RUNNING, &sdata->state);
 }
 
 /* tx handling */
@@ -1105,6 +1143,7 @@ void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata,
 int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata,
                               enum ieee80211_smps_mode smps, const u8 *da,
                               const u8 *bssid);
+void ieee80211_request_smps_work(struct work_struct *work);
 
 void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
                                     u16 initiator, u16 reason);
@@ -1131,6 +1170,7 @@ 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);
 void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid);
+void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid);
 
 /* Spectrum management */
 void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata,
@@ -1146,6 +1186,12 @@ int __ieee80211_suspend(struct ieee80211_hw *hw);
 
 static inline int __ieee80211_resume(struct ieee80211_hw *hw)
 {
+       struct ieee80211_local *local = hw_to_local(hw);
+
+       WARN(test_bit(SCAN_HW_SCANNING, &local->scanning),
+               "%s: resume with hardware scan still in progress\n",
+               wiphy_name(hw->wiphy));
+
        return ieee80211_reconfig(hw_to_local(hw));
 }
 #else
index ebbe264e2b0bc659b0e1303bcec285c87158df9f..c1cc200ac81f29a7d50d494e6de45277b99f6683 100644 (file)
@@ -94,21 +94,14 @@ static inline int identical_mac_addr_allowed(int type1, int type2)
                         type2 == NL80211_IFTYPE_AP_VLAN));
 }
 
-static int ieee80211_open(struct net_device *dev)
+static int ieee80211_check_concurrent_iface(struct ieee80211_sub_if_data *sdata,
+                                           enum nl80211_iftype iftype)
 {
-       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       struct ieee80211_sub_if_data *nsdata;
        struct ieee80211_local *local = sdata->local;
-       struct sta_info *sta;
-       u32 changed = 0;
-       int res;
-       u32 hw_reconf_flags = 0;
-       u8 null_addr[ETH_ALEN] = {0};
+       struct ieee80211_sub_if_data *nsdata;
+       struct net_device *dev = sdata->dev;
 
-       /* fail early if user set an invalid address */
-       if (compare_ether_addr(dev->dev_addr, null_addr) &&
-           !is_valid_ether_addr(dev->dev_addr))
-               return -EADDRNOTAVAIL;
+       ASSERT_RTNL();
 
        /* we hold the RTNL here so can safely walk the list */
        list_for_each_entry(nsdata, &local->interfaces, list) {
@@ -125,7 +118,7 @@ static int ieee80211_open(struct net_device *dev)
                         * belonging to the same hardware. Then, however, we're
                         * faced with having to adopt two different TSF timers...
                         */
-                       if (sdata->vif.type == NL80211_IFTYPE_ADHOC &&
+                       if (iftype == NL80211_IFTYPE_ADHOC &&
                            nsdata->vif.type == NL80211_IFTYPE_ADHOC)
                                return -EBUSY;
 
@@ -139,19 +132,36 @@ static int ieee80211_open(struct net_device *dev)
                        /*
                         * check whether it may have the same address
                         */
-                       if (!identical_mac_addr_allowed(sdata->vif.type,
+                       if (!identical_mac_addr_allowed(iftype,
                                                        nsdata->vif.type))
                                return -ENOTUNIQ;
 
                        /*
                         * can only add VLANs to enabled APs
                         */
-                       if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
+                       if (iftype == NL80211_IFTYPE_AP_VLAN &&
                            nsdata->vif.type == NL80211_IFTYPE_AP)
                                sdata->bss = &nsdata->u.ap;
                }
        }
 
+       return 0;
+}
+
+/*
+ * NOTE: Be very careful when changing this function, it must NOT return
+ * an error on interface type changes that have been pre-checked, so most
+ * checks should be in ieee80211_check_concurrent_iface.
+ */
+static int ieee80211_do_open(struct net_device *dev, bool coming_up)
+{
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct ieee80211_local *local = sdata->local;
+       struct sta_info *sta;
+       u32 changed = 0;
+       int res;
+       u32 hw_reconf_flags = 0;
+
        switch (sdata->vif.type) {
        case NL80211_IFTYPE_WDS:
                if (!is_valid_ether_addr(sdata->u.wds.remote_addr))
@@ -177,7 +187,7 @@ static int ieee80211_open(struct net_device *dev)
                /* no special treatment */
                break;
        case NL80211_IFTYPE_UNSPECIFIED:
-       case __NL80211_IFTYPE_AFTER_LAST:
+       case NUM_NL80211_IFTYPES:
                /* cannot happen */
                WARN_ON(1);
                break;
@@ -187,39 +197,30 @@ static int ieee80211_open(struct net_device *dev)
                res = drv_start(local);
                if (res)
                        goto err_del_bss;
+               if (local->ops->napi_poll)
+                       napi_enable(&local->napi);
                /* we're brought up, everything changes */
                hw_reconf_flags = ~0;
                ieee80211_led_radio(local, true);
        }
 
        /*
-        * Check all interfaces and copy the hopefully now-present
-        * MAC address to those that have the special null one.
+        * Copy the hopefully now-present MAC address to
+        * this interface, if it has the special null one.
         */
-       list_for_each_entry(nsdata, &local->interfaces, list) {
-               struct net_device *ndev = nsdata->dev;
-
-               /*
-                * No need to check running since we do not allow
-                * it to start up with this invalid address.
-                */
-               if (compare_ether_addr(null_addr, ndev->dev_addr) == 0) {
-                       memcpy(ndev->dev_addr,
-                              local->hw.wiphy->perm_addr,
-                              ETH_ALEN);
-                       memcpy(ndev->perm_addr, ndev->dev_addr, ETH_ALEN);
+       if (is_zero_ether_addr(dev->dev_addr)) {
+               memcpy(dev->dev_addr,
+                      local->hw.wiphy->perm_addr,
+                      ETH_ALEN);
+               memcpy(dev->perm_addr, dev->dev_addr, ETH_ALEN);
+
+               if (!is_valid_ether_addr(dev->dev_addr)) {
+                       if (!local->open_count)
+                               drv_stop(local);
+                       return -EADDRNOTAVAIL;
                }
        }
 
-       /*
-        * Validate the MAC address for this device.
-        */
-       if (!is_valid_ether_addr(dev->dev_addr)) {
-               if (!local->open_count)
-                       drv_stop(local);
-               return -EADDRNOTAVAIL;
-       }
-
        switch (sdata->vif.type) {
        case NL80211_IFTYPE_AP_VLAN:
                /* no need to tell driver */
@@ -253,9 +254,11 @@ static int ieee80211_open(struct net_device *dev)
                netif_carrier_on(dev);
                break;
        default:
-               res = drv_add_interface(local, &sdata->vif);
-               if (res)
-                       goto err_stop;
+               if (coming_up) {
+                       res = drv_add_interface(local, &sdata->vif);
+                       if (res)
+                               goto err_stop;
+               }
 
                if (ieee80211_vif_is_mesh(&sdata->vif)) {
                        local->fif_other_bss++;
@@ -307,9 +310,13 @@ static int ieee80211_open(struct net_device *dev)
        if (sdata->flags & IEEE80211_SDATA_PROMISC)
                atomic_inc(&local->iff_promiscs);
 
+       mutex_lock(&local->mtx);
        hw_reconf_flags |= __ieee80211_recalc_idle(local);
+       mutex_unlock(&local->mtx);
+
+       if (coming_up)
+               local->open_count++;
 
-       local->open_count++;
        if (hw_reconf_flags) {
                ieee80211_hw_config(local, hw_reconf_flags);
                /*
@@ -324,6 +331,8 @@ static int ieee80211_open(struct net_device *dev)
 
        netif_tx_start_all_queues(dev);
 
+       set_bit(SDATA_STATE_RUNNING, &sdata->state);
+
        return 0;
  err_del_interface:
        drv_remove_interface(local, &sdata->vif);
@@ -337,19 +346,38 @@ static int ieee80211_open(struct net_device *dev)
        return res;
 }
 
-static int ieee80211_stop(struct net_device *dev)
+static int ieee80211_open(struct net_device *dev)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       int err;
+
+       /* fail early if user set an invalid address */
+       if (!is_zero_ether_addr(dev->dev_addr) &&
+           !is_valid_ether_addr(dev->dev_addr))
+               return -EADDRNOTAVAIL;
+
+       err = ieee80211_check_concurrent_iface(sdata, sdata->vif.type);
+       if (err)
+               return err;
+
+       return ieee80211_do_open(dev, true);
+}
+
+static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
+                             bool going_down)
+{
        struct ieee80211_local *local = sdata->local;
        unsigned long flags;
        struct sk_buff *skb, *tmp;
        u32 hw_reconf_flags = 0;
        int i;
 
+       clear_bit(SDATA_STATE_RUNNING, &sdata->state);
+
        /*
         * Stop TX on this interface first.
         */
-       netif_tx_stop_all_queues(dev);
+       netif_tx_stop_all_queues(sdata->dev);
 
        /*
         * Purge work for this interface.
@@ -366,12 +394,9 @@ static int ieee80211_stop(struct net_device *dev)
         * (because if we remove a STA after ops->remove_interface()
         * the driver will have removed the vif info already!)
         *
-        * We could relax this and only unlink the stations from the
-        * hash table and list but keep them on a per-sdata list that
-        * will be inserted back again when the interface is brought
-        * up again, but I don't currently see a use case for that,
-        * except with WDS which gets a STA entry created when it is
-        * brought up.
+        * This is relevant only in AP, WDS and mesh modes, since in
+        * all other modes we've already removed all stations when
+        * disconnecting etc.
         */
        sta_info_flush(local, sdata);
 
@@ -390,11 +415,12 @@ static int ieee80211_stop(struct net_device *dev)
        if (sdata->vif.type == NL80211_IFTYPE_AP)
                local->fif_pspoll--;
 
-       netif_addr_lock_bh(dev);
+       netif_addr_lock_bh(sdata->dev);
        spin_lock_bh(&local->filter_lock);
-       __hw_addr_unsync(&local->mc_list, &dev->mc, dev->addr_len);
+       __hw_addr_unsync(&local->mc_list, &sdata->dev->mc,
+                        sdata->dev->addr_len);
        spin_unlock_bh(&local->filter_lock);
-       netif_addr_unlock_bh(dev);
+       netif_addr_unlock_bh(sdata->dev);
 
        ieee80211_configure_filter(local);
 
@@ -406,11 +432,21 @@ static int ieee80211_stop(struct net_device *dev)
                struct ieee80211_sub_if_data *vlan, *tmpsdata;
                struct beacon_data *old_beacon = sdata->u.ap.beacon;
 
+               /* sdata_running will return false, so this will disable */
+               ieee80211_bss_info_change_notify(sdata,
+                                                BSS_CHANGED_BEACON_ENABLED);
+
                /* remove beacon */
                rcu_assign_pointer(sdata->u.ap.beacon, NULL);
                synchronize_rcu();
                kfree(old_beacon);
 
+               /* free all potentially still buffered bcast frames */
+               while ((skb = skb_dequeue(&sdata->u.ap.ps_bc_buf))) {
+                       local->total_ps_buffered--;
+                       dev_kfree_skb(skb);
+               }
+
                /* down all dependent devices, that is VLANs */
                list_for_each_entry_safe(vlan, tmpsdata, &sdata->u.ap.vlans,
                                         u.vlan.list)
@@ -418,7 +454,8 @@ static int ieee80211_stop(struct net_device *dev)
                WARN_ON(!list_empty(&sdata->u.ap.vlans));
        }
 
-       local->open_count--;
+       if (going_down)
+               local->open_count--;
 
        switch (sdata->vif.type) {
        case NL80211_IFTYPE_AP_VLAN:
@@ -450,27 +487,6 @@ static int ieee80211_stop(struct net_device *dev)
 
                ieee80211_configure_filter(local);
                break;
-       case NL80211_IFTYPE_STATION:
-               del_timer_sync(&sdata->u.mgd.chswitch_timer);
-               del_timer_sync(&sdata->u.mgd.timer);
-               del_timer_sync(&sdata->u.mgd.conn_mon_timer);
-               del_timer_sync(&sdata->u.mgd.bcn_mon_timer);
-               /*
-                * If any of the timers fired while we waited for it, it will
-                * have queued its work. Now the work will be running again
-                * but will not rearm the timer again because it checks
-                * whether the interface is running, which, at this point,
-                * it no longer is.
-                */
-               cancel_work_sync(&sdata->u.mgd.chswitch_work);
-               cancel_work_sync(&sdata->u.mgd.monitor_work);
-               cancel_work_sync(&sdata->u.mgd.beacon_connection_loss_work);
-
-               /* fall through */
-       case NL80211_IFTYPE_ADHOC:
-               if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
-                       del_timer_sync(&sdata->u.ibss.timer);
-               /* fall through */
        case NL80211_IFTYPE_MESH_POINT:
                if (ieee80211_vif_is_mesh(&sdata->vif)) {
                        /* other_bss and allmulti are always set on mesh
@@ -498,27 +514,34 @@ static int ieee80211_stop(struct net_device *dev)
                        ieee80211_scan_cancel(local);
 
                /*
-                * Disable beaconing for AP and mesh, IBSS can't
-                * still be joined to a network at this point.
+                * Disable beaconing here for mesh only, AP and IBSS
+                * are already taken care of.
                 */
-               if (sdata->vif.type == NL80211_IFTYPE_AP ||
-                   sdata->vif.type == NL80211_IFTYPE_MESH_POINT) {
+               if (sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
                        ieee80211_bss_info_change_notify(sdata,
                                BSS_CHANGED_BEACON_ENABLED);
-               }
 
-               /* free all remaining keys, there shouldn't be any */
+               /*
+                * Free all remaining keys, there shouldn't be any,
+                * except maybe group keys in AP more or WDS?
+                */
                ieee80211_free_keys(sdata);
-               drv_remove_interface(local, &sdata->vif);
+
+               if (going_down)
+                       drv_remove_interface(local, &sdata->vif);
        }
 
        sdata->bss = NULL;
 
+       mutex_lock(&local->mtx);
        hw_reconf_flags |= __ieee80211_recalc_idle(local);
+       mutex_unlock(&local->mtx);
 
        ieee80211_recalc_ps(local, -1);
 
        if (local->open_count == 0) {
+               if (local->ops->napi_poll)
+                       napi_disable(&local->napi);
                ieee80211_clear_tx_pending(local);
                ieee80211_stop_device(local);
 
@@ -541,6 +564,13 @@ static int ieee80211_stop(struct net_device *dev)
                }
        }
        spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
+}
+
+static int ieee80211_stop(struct net_device *dev)
+{
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+       ieee80211_do_stop(sdata, true);
 
        return 0;
 }
@@ -585,8 +615,6 @@ static void ieee80211_teardown_sdata(struct net_device *dev)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ieee80211_local *local = sdata->local;
-       struct beacon_data *beacon;
-       struct sk_buff *skb;
        int flushed;
        int i;
 
@@ -599,37 +627,8 @@ static void ieee80211_teardown_sdata(struct net_device *dev)
                __skb_queue_purge(&sdata->fragments[i].skb_list);
        sdata->fragment_next = 0;
 
-       switch (sdata->vif.type) {
-       case NL80211_IFTYPE_AP:
-               beacon = sdata->u.ap.beacon;
-               rcu_assign_pointer(sdata->u.ap.beacon, NULL);
-               synchronize_rcu();
-               kfree(beacon);
-
-               while ((skb = skb_dequeue(&sdata->u.ap.ps_bc_buf))) {
-                       local->total_ps_buffered--;
-                       dev_kfree_skb(skb);
-               }
-
-               break;
-       case NL80211_IFTYPE_MESH_POINT:
-               if (ieee80211_vif_is_mesh(&sdata->vif))
-                       mesh_rmc_free(sdata);
-               break;
-       case NL80211_IFTYPE_ADHOC:
-               if (WARN_ON(sdata->u.ibss.presp))
-                       kfree_skb(sdata->u.ibss.presp);
-               break;
-       case NL80211_IFTYPE_STATION:
-       case NL80211_IFTYPE_WDS:
-       case NL80211_IFTYPE_AP_VLAN:
-       case NL80211_IFTYPE_MONITOR:
-               break;
-       case NL80211_IFTYPE_UNSPECIFIED:
-       case __NL80211_IFTYPE_AFTER_LAST:
-               BUG();
-               break;
-       }
+       if (ieee80211_vif_is_mesh(&sdata->vif))
+               mesh_rmc_free(sdata);
 
        flushed = sta_info_flush(local, sdata);
        WARN_ON(flushed);
@@ -847,6 +846,9 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
        sdata->dev->netdev_ops = &ieee80211_dataif_ops;
        sdata->wdev.iftype = type;
 
+       sdata->control_port_protocol = cpu_to_be16(ETH_P_PAE);
+       sdata->control_port_no_encrypt = false;
+
        /* only monitor differs */
        sdata->dev->type = ARPHRD_ETHER;
 
@@ -878,7 +880,7 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
        case NL80211_IFTYPE_AP_VLAN:
                break;
        case NL80211_IFTYPE_UNSPECIFIED:
-       case __NL80211_IFTYPE_AFTER_LAST:
+       case NUM_NL80211_IFTYPES:
                BUG();
                break;
        }
@@ -886,9 +888,72 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
        ieee80211_debugfs_add_netdev(sdata);
 }
 
+static int ieee80211_runtime_change_iftype(struct ieee80211_sub_if_data *sdata,
+                                          enum nl80211_iftype type)
+{
+       struct ieee80211_local *local = sdata->local;
+       int ret, err;
+
+       ASSERT_RTNL();
+
+       if (!local->ops->change_interface)
+               return -EBUSY;
+
+       switch (sdata->vif.type) {
+       case NL80211_IFTYPE_AP:
+       case NL80211_IFTYPE_STATION:
+       case NL80211_IFTYPE_ADHOC:
+               /*
+                * Could maybe also all others here?
+                * Just not sure how that interacts
+                * with the RX/config path e.g. for
+                * mesh.
+                */
+               break;
+       default:
+               return -EBUSY;
+       }
+
+       switch (type) {
+       case NL80211_IFTYPE_AP:
+       case NL80211_IFTYPE_STATION:
+       case NL80211_IFTYPE_ADHOC:
+               /*
+                * Could probably support everything
+                * but WDS here (WDS do_open can fail
+                * under memory pressure, which this
+                * code isn't prepared to handle).
+                */
+               break;
+       default:
+               return -EBUSY;
+       }
+
+       ret = ieee80211_check_concurrent_iface(sdata, type);
+       if (ret)
+               return ret;
+
+       ieee80211_do_stop(sdata, false);
+
+       ieee80211_teardown_sdata(sdata->dev);
+
+       ret = drv_change_interface(local, sdata, type);
+       if (ret)
+               type = sdata->vif.type;
+
+       ieee80211_setup_sdata(sdata, type);
+
+       err = ieee80211_do_open(sdata->dev, false);
+       WARN(err, "type change: do_open returned %d", err);
+
+       return ret;
+}
+
 int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata,
                             enum nl80211_iftype type)
 {
+       int ret;
+
        ASSERT_RTNL();
 
        if (type == sdata->vif.type)
@@ -899,18 +964,15 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata,
            type == NL80211_IFTYPE_ADHOC)
                return -EOPNOTSUPP;
 
-       /*
-        * We could, here, on changes between IBSS/STA/MESH modes,
-        * invoke an MLME function instead that disassociates etc.
-        * and goes into the requested mode.
-        */
-
-       if (ieee80211_sdata_running(sdata))
-               return -EBUSY;
-
-       /* Purge and reset type-dependent state. */
-       ieee80211_teardown_sdata(sdata->dev);
-       ieee80211_setup_sdata(sdata, type);
+       if (ieee80211_sdata_running(sdata)) {
+               ret = ieee80211_runtime_change_iftype(sdata, type);
+               if (ret)
+                       return ret;
+       } else {
+               /* Purge and reset type-dependent state. */
+               ieee80211_teardown_sdata(sdata->dev);
+               ieee80211_setup_sdata(sdata, type);
+       }
 
        /* reset some values that shouldn't be kept across type changes */
        sdata->vif.bss_conf.basic_rates =
@@ -1167,8 +1229,7 @@ static u32 ieee80211_idle_off(struct ieee80211_local *local,
                return 0;
 
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-       printk(KERN_DEBUG "%s: device no longer idle - %s\n",
-              wiphy_name(local->hw.wiphy), reason);
+       wiphy_debug(local->hw.wiphy, "device no longer idle - %s\n", reason);
 #endif
 
        local->hw.conf.flags &= ~IEEE80211_CONF_IDLE;
@@ -1181,8 +1242,7 @@ static u32 ieee80211_idle_on(struct ieee80211_local *local)
                return 0;
 
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-       printk(KERN_DEBUG "%s: device now idle\n",
-              wiphy_name(local->hw.wiphy));
+       wiphy_debug(local->hw.wiphy, "device now idle\n");
 #endif
 
        drv_flush(local, false);
@@ -1195,28 +1255,61 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local)
 {
        struct ieee80211_sub_if_data *sdata;
        int count = 0;
+       bool working = false, scanning = false;
+       struct ieee80211_work *wk;
 
-       if (!list_empty(&local->work_list))
-               return ieee80211_idle_off(local, "working");
-
-       if (local->scanning)
-               return ieee80211_idle_off(local, "scanning");
+#ifdef CONFIG_PROVE_LOCKING
+       WARN_ON(debug_locks && !lockdep_rtnl_is_held() &&
+               !lockdep_is_held(&local->iflist_mtx));
+#endif
+       lockdep_assert_held(&local->mtx);
 
        list_for_each_entry(sdata, &local->interfaces, list) {
-               if (!ieee80211_sdata_running(sdata))
+               if (!ieee80211_sdata_running(sdata)) {
+                       sdata->vif.bss_conf.idle = true;
                        continue;
+               }
+
+               sdata->old_idle = sdata->vif.bss_conf.idle;
+
                /* do not count disabled managed interfaces */
                if (sdata->vif.type == NL80211_IFTYPE_STATION &&
-                   !sdata->u.mgd.associated)
+                   !sdata->u.mgd.associated) {
+                       sdata->vif.bss_conf.idle = true;
                        continue;
+               }
                /* do not count unused IBSS interfaces */
                if (sdata->vif.type == NL80211_IFTYPE_ADHOC &&
-                   !sdata->u.ibss.ssid_len)
+                   !sdata->u.ibss.ssid_len) {
+                       sdata->vif.bss_conf.idle = true;
                        continue;
+               }
                /* count everything else */
                count++;
        }
 
+       list_for_each_entry(wk, &local->work_list, list) {
+               working = true;
+               wk->sdata->vif.bss_conf.idle = false;
+       }
+
+       if (local->scan_sdata) {
+               scanning = true;
+               local->scan_sdata->vif.bss_conf.idle = false;
+       }
+
+       list_for_each_entry(sdata, &local->interfaces, list) {
+               if (sdata->old_idle == sdata->vif.bss_conf.idle)
+                       continue;
+               if (!ieee80211_sdata_running(sdata))
+                       continue;
+               ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IDLE);
+       }
+
+       if (working)
+               return ieee80211_idle_off(local, "working");
+       if (scanning)
+               return ieee80211_idle_off(local, "scanning");
        if (!count)
                return ieee80211_idle_on(local);
        else
index 1b9d87ed143a1a3b3e46e31f5649ba67f68321b2..3570f8c2bb401d3d4d20cbac6dbc0fddfb395235 100644 (file)
@@ -60,7 +60,7 @@ static struct ieee80211_sta *get_sta_for_key(struct ieee80211_key *key)
        return NULL;
 }
 
-static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
+static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
 {
        struct ieee80211_sub_if_data *sdata;
        struct ieee80211_sta *sta;
@@ -68,8 +68,10 @@ static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
 
        might_sleep();
 
-       if (!key->local->ops->set_key)
-               return;
+       if (!key->local->ops->set_key) {
+               ret = -EOPNOTSUPP;
+               goto out_unsupported;
+       }
 
        assert_key_lock(key->local);
 
@@ -87,10 +89,27 @@ static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
                key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE;
 
        if (ret && ret != -ENOSPC && ret != -EOPNOTSUPP)
-               printk(KERN_ERR "mac80211-%s: failed to set key "
-                      "(%d, %pM) to hardware (%d)\n",
-                      wiphy_name(key->local->hw.wiphy),
-                      key->conf.keyidx, sta ? sta->addr : bcast_addr, ret);
+               wiphy_err(key->local->hw.wiphy,
+                         "failed to set key (%d, %pM) to hardware (%d)\n",
+                         key->conf.keyidx, sta ? sta->addr : bcast_addr, ret);
+
+out_unsupported:
+       if (ret) {
+               switch (key->conf.cipher) {
+               case WLAN_CIPHER_SUITE_WEP40:
+               case WLAN_CIPHER_SUITE_WEP104:
+               case WLAN_CIPHER_SUITE_TKIP:
+               case WLAN_CIPHER_SUITE_CCMP:
+               case WLAN_CIPHER_SUITE_AES_CMAC:
+                       /* all of these we can do in software */
+                       ret = 0;
+                       break;
+               default:
+                       ret = -EINVAL;
+               }
+       }
+
+       return ret;
 }
 
 static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
@@ -121,10 +140,9 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
                          sta, &key->conf);
 
        if (ret)
-               printk(KERN_ERR "mac80211-%s: failed to remove key "
-                      "(%d, %pM) from hardware (%d)\n",
-                      wiphy_name(key->local->hw.wiphy),
-                      key->conf.keyidx, sta ? sta->addr : bcast_addr, ret);
+               wiphy_err(key->local->hw.wiphy,
+                         "failed to remove key (%d, %pM) from hardware (%d)\n",
+                         key->conf.keyidx, sta ? sta->addr : bcast_addr, ret);
 
        key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
 }
@@ -227,20 +245,18 @@ static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
        }
 }
 
-struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg,
-                                         int idx,
-                                         size_t key_len,
+struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
                                          const u8 *key_data,
                                          size_t seq_len, const u8 *seq)
 {
        struct ieee80211_key *key;
-       int i, j;
+       int i, j, err;
 
        BUG_ON(idx < 0 || idx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS);
 
        key = kzalloc(sizeof(struct ieee80211_key) + key_len, GFP_KERNEL);
        if (!key)
-               return NULL;
+               return ERR_PTR(-ENOMEM);
 
        /*
         * Default to software encryption; we'll later upload the
@@ -249,15 +265,16 @@ struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg,
        key->conf.flags = 0;
        key->flags = 0;
 
-       key->conf.alg = alg;
+       key->conf.cipher = cipher;
        key->conf.keyidx = idx;
        key->conf.keylen = key_len;
-       switch (alg) {
-       case ALG_WEP:
+       switch (cipher) {
+       case WLAN_CIPHER_SUITE_WEP40:
+       case WLAN_CIPHER_SUITE_WEP104:
                key->conf.iv_len = WEP_IV_LEN;
                key->conf.icv_len = WEP_ICV_LEN;
                break;
-       case ALG_TKIP:
+       case WLAN_CIPHER_SUITE_TKIP:
                key->conf.iv_len = TKIP_IV_LEN;
                key->conf.icv_len = TKIP_ICV_LEN;
                if (seq) {
@@ -269,7 +286,7 @@ struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg,
                        }
                }
                break;
-       case ALG_CCMP:
+       case WLAN_CIPHER_SUITE_CCMP:
                key->conf.iv_len = CCMP_HDR_LEN;
                key->conf.icv_len = CCMP_MIC_LEN;
                if (seq) {
@@ -278,42 +295,38 @@ struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg,
                                        key->u.ccmp.rx_pn[i][j] =
                                                seq[CCMP_PN_LEN - j - 1];
                }
-               break;
-       case ALG_AES_CMAC:
-               key->conf.iv_len = 0;
-               key->conf.icv_len = sizeof(struct ieee80211_mmie);
-               if (seq)
-                       for (j = 0; j < 6; j++)
-                               key->u.aes_cmac.rx_pn[j] = seq[6 - j - 1];
-               break;
-       }
-       memcpy(key->conf.key, key_data, key_len);
-       INIT_LIST_HEAD(&key->list);
-
-       if (alg == ALG_CCMP) {
                /*
                 * Initialize AES key state here as an optimization so that
                 * it does not need to be initialized for every packet.
                 */
                key->u.ccmp.tfm = ieee80211_aes_key_setup_encrypt(key_data);
-               if (!key->u.ccmp.tfm) {
+               if (IS_ERR(key->u.ccmp.tfm)) {
+                       err = PTR_ERR(key->u.ccmp.tfm);
                        kfree(key);
-                       return NULL;
+                       key = ERR_PTR(err);
                }
-       }
-
-       if (alg == ALG_AES_CMAC) {
+               break;
+       case WLAN_CIPHER_SUITE_AES_CMAC:
+               key->conf.iv_len = 0;
+               key->conf.icv_len = sizeof(struct ieee80211_mmie);
+               if (seq)
+                       for (j = 0; j < 6; j++)
+                               key->u.aes_cmac.rx_pn[j] = seq[6 - j - 1];
                /*
                 * Initialize AES key state here as an optimization so that
                 * it does not need to be initialized for every packet.
                 */
                key->u.aes_cmac.tfm =
                        ieee80211_aes_cmac_key_setup(key_data);
-               if (!key->u.aes_cmac.tfm) {
+               if (IS_ERR(key->u.aes_cmac.tfm)) {
+                       err = PTR_ERR(key->u.aes_cmac.tfm);
                        kfree(key);
-                       return NULL;
+                       key = ERR_PTR(err);
                }
+               break;
        }
+       memcpy(key->conf.key, key_data, key_len);
+       INIT_LIST_HEAD(&key->list);
 
        return key;
 }
@@ -326,9 +339,9 @@ static void __ieee80211_key_destroy(struct ieee80211_key *key)
        if (key->local)
                ieee80211_key_disable_hw_accel(key);
 
-       if (key->conf.alg == ALG_CCMP)
+       if (key->conf.cipher == WLAN_CIPHER_SUITE_CCMP)
                ieee80211_aes_key_free(key->u.ccmp.tfm);
-       if (key->conf.alg == ALG_AES_CMAC)
+       if (key->conf.cipher == WLAN_CIPHER_SUITE_AES_CMAC)
                ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm);
        if (key->local)
                ieee80211_debugfs_key_remove(key);
@@ -336,12 +349,12 @@ static void __ieee80211_key_destroy(struct ieee80211_key *key)
        kfree(key);
 }
 
-void ieee80211_key_link(struct ieee80211_key *key,
-                       struct ieee80211_sub_if_data *sdata,
-                       struct sta_info *sta)
+int ieee80211_key_link(struct ieee80211_key *key,
+                      struct ieee80211_sub_if_data *sdata,
+                      struct sta_info *sta)
 {
        struct ieee80211_key *old_key;
-       int idx;
+       int idx, ret;
 
        BUG_ON(!sdata);
        BUG_ON(!key);
@@ -396,9 +409,11 @@ void ieee80211_key_link(struct ieee80211_key *key,
 
        ieee80211_debugfs_key_add(key);
 
-       ieee80211_key_enable_hw_accel(key);
+       ret = ieee80211_key_enable_hw_accel(key);
 
        mutex_unlock(&sdata->local->key_mtx);
+
+       return ret;
 }
 
 static void __ieee80211_key_free(struct ieee80211_key *key)
index b665bbb7a4711a7bcef6b7c27b41fd331d458d34..cb9a4a65cc68fae008b1ea79a0c0ff84d9651cb8 100644 (file)
@@ -123,18 +123,16 @@ struct ieee80211_key {
        struct ieee80211_key_conf conf;
 };
 
-struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg,
-                                         int idx,
-                                         size_t key_len,
+struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
                                          const u8 *key_data,
                                          size_t seq_len, const u8 *seq);
 /*
  * Insert a key into data structures (sdata, sta if necessary)
  * to make it used, free old key.
  */
-void ieee80211_key_link(struct ieee80211_key *key,
-                       struct ieee80211_sub_if_data *sdata,
-                       struct sta_info *sta);
+int __must_check ieee80211_key_link(struct ieee80211_key *key,
+                                   struct ieee80211_sub_if_data *sdata,
+                                   struct sta_info *sta);
 void ieee80211_key_free(struct ieee80211_local *local,
                        struct ieee80211_key *key);
 void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx);
index ded5c3843e061a13e1d82be4666b746c829c467c..4935b843bcca31ecca7b198da5285a996bc9294f 100644 (file)
@@ -99,11 +99,13 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
        int ret = 0;
        int power;
        enum nl80211_channel_type channel_type;
+       u32 offchannel_flag;
 
        might_sleep();
 
        scan_chan = local->scan_channel;
 
+       offchannel_flag = local->hw.conf.flags & IEEE80211_CONF_OFFCHANNEL;
        if (scan_chan) {
                chan = scan_chan;
                channel_type = NL80211_CHAN_NO_HT;
@@ -117,8 +119,9 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
                channel_type = local->_oper_channel_type;
                local->hw.conf.flags &= ~IEEE80211_CONF_OFFCHANNEL;
        }
+       offchannel_flag ^= local->hw.conf.flags & IEEE80211_CONF_OFFCHANNEL;
 
-       if (chan != local->hw.conf.channel ||
+       if (offchannel_flag || chan != local->hw.conf.channel ||
            channel_type != local->hw.conf.channel_type) {
                local->hw.conf.channel = chan;
                local->hw.conf.channel_type = channel_type;
@@ -302,7 +305,13 @@ void ieee80211_restart_hw(struct ieee80211_hw *hw)
 
        trace_api_restart_hw(local);
 
-       /* use this reason, __ieee80211_resume will unblock it */
+       WARN(test_bit(SCAN_HW_SCANNING, &local->scanning),
+               "%s called with hardware scan in progress\n", __func__);
+
+       if (unlikely(test_bit(SCAN_SW_SCANNING, &local->scanning)))
+               ieee80211_scan_cancel(local);
+
+       /* use this reason, ieee80211_reconfig will unblock it */
        ieee80211_stop_queues_by_reason(hw,
                IEEE80211_QUEUE_STOP_REASON_SUSPEND);
 
@@ -336,9 +345,6 @@ static int ieee80211_ifa_changed(struct notifier_block *nb,
        struct ieee80211_if_managed *ifmgd;
        int c = 0;
 
-       if (!netif_running(ndev))
-               return NOTIFY_DONE;
-
        /* Make sure it's our interface that got changed */
        if (!wdev)
                return NOTIFY_DONE;
@@ -349,6 +355,9 @@ static int ieee80211_ifa_changed(struct notifier_block *nb,
        sdata = IEEE80211_DEV_TO_SUB_IF(ndev);
        bss_conf = &sdata->vif.bss_conf;
 
+       if (!ieee80211_sdata_running(sdata))
+               return NOTIFY_DONE;
+
        /* ARP filtering is only supported in managed mode */
        if (sdata->vif.type != NL80211_IFTYPE_STATION)
                return NOTIFY_DONE;
@@ -390,6 +399,65 @@ static int ieee80211_ifa_changed(struct notifier_block *nb,
 }
 #endif
 
+static int ieee80211_napi_poll(struct napi_struct *napi, int budget)
+{
+       struct ieee80211_local *local =
+               container_of(napi, struct ieee80211_local, napi);
+
+       return local->ops->napi_poll(&local->hw, budget);
+}
+
+void ieee80211_napi_schedule(struct ieee80211_hw *hw)
+{
+       struct ieee80211_local *local = hw_to_local(hw);
+
+       napi_schedule(&local->napi);
+}
+EXPORT_SYMBOL(ieee80211_napi_schedule);
+
+void ieee80211_napi_complete(struct ieee80211_hw *hw)
+{
+       struct ieee80211_local *local = hw_to_local(hw);
+
+       napi_complete(&local->napi);
+}
+EXPORT_SYMBOL(ieee80211_napi_complete);
+
+/* There isn't a lot of sense in it, but you can transmit anything you like */
+static const struct ieee80211_txrx_stypes
+ieee80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = {
+       [NL80211_IFTYPE_ADHOC] = {
+               .tx = 0xffff,
+               .rx = BIT(IEEE80211_STYPE_ACTION >> 4),
+       },
+       [NL80211_IFTYPE_STATION] = {
+               .tx = 0xffff,
+               .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+                       BIT(IEEE80211_STYPE_PROBE_REQ >> 4),
+       },
+       [NL80211_IFTYPE_AP] = {
+               .tx = 0xffff,
+               .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
+                       BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
+                       BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
+                       BIT(IEEE80211_STYPE_DISASSOC >> 4) |
+                       BIT(IEEE80211_STYPE_AUTH >> 4) |
+                       BIT(IEEE80211_STYPE_DEAUTH >> 4) |
+                       BIT(IEEE80211_STYPE_ACTION >> 4),
+       },
+       [NL80211_IFTYPE_AP_VLAN] = {
+               /* copy AP */
+               .tx = 0xffff,
+               .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
+                       BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
+                       BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
+                       BIT(IEEE80211_STYPE_DISASSOC >> 4) |
+                       BIT(IEEE80211_STYPE_AUTH >> 4) |
+                       BIT(IEEE80211_STYPE_DEAUTH >> 4) |
+                       BIT(IEEE80211_STYPE_ACTION >> 4),
+       },
+};
+
 struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
                                        const struct ieee80211_ops *ops)
 {
@@ -419,6 +487,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
        if (!wiphy)
                return NULL;
 
+       wiphy->mgmt_stypes = ieee80211_default_mgmt_stypes;
+
        wiphy->flags |= WIPHY_FLAG_NETNS_OK |
                        WIPHY_FLAG_4ADDR_AP |
                        WIPHY_FLAG_4ADDR_STATION;
@@ -455,7 +525,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
        __hw_addr_init(&local->mc_list);
 
        mutex_init(&local->iflist_mtx);
-       mutex_init(&local->scan_mtx);
+       mutex_init(&local->mtx);
 
        mutex_init(&local->key_mtx);
        spin_lock_init(&local->filter_lock);
@@ -494,6 +564,9 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
        skb_queue_head_init(&local->skb_queue);
        skb_queue_head_init(&local->skb_queue_unreliable);
 
+       /* init dummy netdev for use w/ NAPI */
+       init_dummy_netdev(&local->napi_dev);
+
        return local_to_hw(local);
 }
 EXPORT_SYMBOL(ieee80211_alloc_hw);
@@ -506,6 +579,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
        int channels, max_bitrates;
        bool supp_ht;
        static const u32 cipher_suites[] = {
+               /* keep WEP first, it may be removed below */
                WLAN_CIPHER_SUITE_WEP40,
                WLAN_CIPHER_SUITE_WEP104,
                WLAN_CIPHER_SUITE_TKIP,
@@ -554,6 +628,14 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
        /* mac80211 always supports monitor */
        local->hw.wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR);
 
+#ifndef CONFIG_MAC80211_MESH
+       /* mesh depends on Kconfig, but drivers should set it if they want */
+       local->hw.wiphy->interface_modes &= ~BIT(NL80211_IFTYPE_MESH_POINT);
+#endif
+
+       /* mac80211 supports control port protocol changing */
+       local->hw.wiphy->flags |= WIPHY_FLAG_CONTROL_PORT_PROTOCOL;
+
        if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
                local->hw.wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
        else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)
@@ -589,10 +671,41 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
        if (local->hw.wiphy->max_scan_ie_len)
                local->hw.wiphy->max_scan_ie_len -= local->scan_ies_len;
 
-       local->hw.wiphy->cipher_suites = cipher_suites;
-       local->hw.wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
-       if (!(local->hw.flags & IEEE80211_HW_MFP_CAPABLE))
-               local->hw.wiphy->n_cipher_suites--;
+       /* Set up cipher suites unless driver already did */
+       if (!local->hw.wiphy->cipher_suites) {
+               local->hw.wiphy->cipher_suites = cipher_suites;
+               local->hw.wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
+               if (!(local->hw.flags & IEEE80211_HW_MFP_CAPABLE))
+                       local->hw.wiphy->n_cipher_suites--;
+       }
+       if (IS_ERR(local->wep_tx_tfm) || IS_ERR(local->wep_rx_tfm)) {
+               if (local->hw.wiphy->cipher_suites == cipher_suites) {
+                       local->hw.wiphy->cipher_suites += 2;
+                       local->hw.wiphy->n_cipher_suites -= 2;
+               } else {
+                       u32 *suites;
+                       int r, w = 0;
+
+                       /* Filter out WEP */
+
+                       suites = kmemdup(
+                               local->hw.wiphy->cipher_suites,
+                               sizeof(u32) * local->hw.wiphy->n_cipher_suites,
+                               GFP_KERNEL);
+                       if (!suites)
+                               return -ENOMEM;
+                       for (r = 0; r < local->hw.wiphy->n_cipher_suites; r++) {
+                               u32 suite = local->hw.wiphy->cipher_suites[r];
+                               if (suite == WLAN_CIPHER_SUITE_WEP40 ||
+                                   suite == WLAN_CIPHER_SUITE_WEP104)
+                                       continue;
+                               suites[w++] = suite;
+                       }
+                       local->hw.wiphy->cipher_suites = suites;
+                       local->hw.wiphy->n_cipher_suites = w;
+                       local->wiphy_ciphers_allocated = true;
+               }
+       }
 
        result = wiphy_register(local->hw.wiphy);
        if (result < 0)
@@ -641,16 +754,16 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
 
        result = ieee80211_wep_init(local);
        if (result < 0)
-               printk(KERN_DEBUG "%s: Failed to initialize wep: %d\n",
-                      wiphy_name(local->hw.wiphy), result);
+               wiphy_debug(local->hw.wiphy, "Failed to initialize wep: %d\n",
+                           result);
 
        rtnl_lock();
 
        result = ieee80211_init_rate_ctrl_alg(local,
                                              hw->rate_control_algorithm);
        if (result < 0) {
-               printk(KERN_DEBUG "%s: Failed to initialize rate control "
-                      "algorithm\n", wiphy_name(local->hw.wiphy));
+               wiphy_debug(local->hw.wiphy,
+                           "Failed to initialize rate control algorithm\n");
                goto fail_rate;
        }
 
@@ -659,8 +772,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
                result = ieee80211_if_add(local, "wlan%d", NULL,
                                          NL80211_IFTYPE_STATION, NULL);
                if (result)
-                       printk(KERN_WARNING "%s: Failed to add default virtual iface\n",
-                              wiphy_name(local->hw.wiphy));
+                       wiphy_warn(local->hw.wiphy,
+                                  "Failed to add default virtual iface\n");
        }
 
        rtnl_unlock();
@@ -683,6 +796,9 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
                goto fail_ifa;
 #endif
 
+       netif_napi_add(&local->napi_dev, &local->napi, ieee80211_napi_poll,
+                       local->hw.napi_weight);
+
        return 0;
 
 #ifdef CONFIG_INET
@@ -703,6 +819,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
  fail_workqueue:
        wiphy_unregister(local->hw.wiphy);
  fail_wiphy_register:
+       if (local->wiphy_ciphers_allocated)
+               kfree(local->hw.wiphy->cipher_suites);
        kfree(local->int_scan_req);
        return result;
 }
@@ -738,6 +856,7 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
         */
        del_timer_sync(&local->work_timer);
 
+       cancel_work_sync(&local->restart_work);
        cancel_work_sync(&local->reconfig_filter);
 
        ieee80211_clear_tx_pending(local);
@@ -746,8 +865,7 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
 
        if (skb_queue_len(&local->skb_queue) ||
            skb_queue_len(&local->skb_queue_unreliable))
-               printk(KERN_WARNING "%s: skb_queue not empty\n",
-                      wiphy_name(local->hw.wiphy));
+               wiphy_warn(local->hw.wiphy, "skb_queue not empty\n");
        skb_queue_purge(&local->skb_queue);
        skb_queue_purge(&local->skb_queue_unreliable);
 
@@ -764,7 +882,10 @@ void ieee80211_free_hw(struct ieee80211_hw *hw)
        struct ieee80211_local *local = hw_to_local(hw);
 
        mutex_destroy(&local->iflist_mtx);
-       mutex_destroy(&local->scan_mtx);
+       mutex_destroy(&local->mtx);
+
+       if (local->wiphy_ciphers_allocated)
+               kfree(local->hw.wiphy->cipher_suites);
 
        wiphy_free(local->hw.wiphy);
 }
index b6c163ac22da39fd3327a30f77478e27cb81756c..0cb822cc12e9c52618ddb18d5503db43765b9f11 100644 (file)
  */
 #define IEEE80211_SIGNAL_AVE_WEIGHT    3
 
+/*
+ * How many Beacon frames need to have been used in average signal strength
+ * before starting to indicate signal change events.
+ */
+#define IEEE80211_SIGNAL_AVE_MIN_COUNT 4
+
 #define TMR_RUNNING_TIMER      0
 #define TMR_RUNNING_CHANSW     1
 
@@ -778,16 +784,17 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
                params.uapsd = uapsd;
 
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-               printk(KERN_DEBUG "%s: WMM queue=%d aci=%d acm=%d aifs=%d "
-                      "cWmin=%d cWmax=%d txop=%d uapsd=%d\n",
-                      wiphy_name(local->hw.wiphy), queue, aci, acm,
-                      params.aifs, params.cw_min, params.cw_max, params.txop,
-                      params.uapsd);
+               wiphy_debug(local->hw.wiphy,
+                           "WMM queue=%d aci=%d acm=%d aifs=%d "
+                           "cWmin=%d cWmax=%d txop=%d uapsd=%d\n",
+                           queue, aci, acm,
+                           params.aifs, params.cw_min, params.cw_max,
+                           params.txop, params.uapsd);
 #endif
                if (drv_conf_tx(local, queue, &params))
-                       printk(KERN_DEBUG "%s: failed to set TX queue "
-                              "parameters for queue %d\n",
-                              wiphy_name(local->hw.wiphy), queue);
+                       wiphy_debug(local->hw.wiphy,
+                                   "failed to set TX queue parameters for queue %d\n",
+                                   queue);
        }
 
        /* enable WMM or activate new settings */
@@ -990,6 +997,11 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
 
        if (remove_sta)
                sta_info_destroy_addr(sdata, bssid);
+
+       del_timer_sync(&sdata->u.mgd.conn_mon_timer);
+       del_timer_sync(&sdata->u.mgd.bcn_mon_timer);
+       del_timer_sync(&sdata->u.mgd.timer);
+       del_timer_sync(&sdata->u.mgd.chswitch_timer);
 }
 
 void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata,
@@ -1103,8 +1115,11 @@ static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata)
        printk(KERN_DEBUG "Connection to AP %pM lost.\n", bssid);
 
        ieee80211_set_disassoc(sdata, true);
-       ieee80211_recalc_idle(local);
        mutex_unlock(&ifmgd->mtx);
+
+       mutex_lock(&local->mtx);
+       ieee80211_recalc_idle(local);
+       mutex_unlock(&local->mtx);
        /*
         * must be outside lock due to cfg80211,
         * but that's not a problem.
@@ -1173,7 +1188,9 @@ ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata,
                        sdata->name, bssid, reason_code);
 
        ieee80211_set_disassoc(sdata, true);
+       mutex_lock(&sdata->local->mtx);
        ieee80211_recalc_idle(sdata->local);
+       mutex_unlock(&sdata->local->mtx);
 
        return RX_MGMT_CFG80211_DEAUTH;
 }
@@ -1203,7 +1220,9 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata,
                        sdata->name, mgmt->sa, reason_code);
 
        ieee80211_set_disassoc(sdata, true);
+       mutex_lock(&sdata->local->mtx);
        ieee80211_recalc_idle(sdata->local);
+       mutex_unlock(&sdata->local->mtx);
        return RX_MGMT_CFG80211_DISASSOC;
 }
 
@@ -1540,15 +1559,18 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
        ifmgd->last_beacon_signal = rx_status->signal;
        if (ifmgd->flags & IEEE80211_STA_RESET_SIGNAL_AVE) {
                ifmgd->flags &= ~IEEE80211_STA_RESET_SIGNAL_AVE;
-               ifmgd->ave_beacon_signal = rx_status->signal;
+               ifmgd->ave_beacon_signal = rx_status->signal * 16;
                ifmgd->last_cqm_event_signal = 0;
+               ifmgd->count_beacon_signal = 1;
        } else {
                ifmgd->ave_beacon_signal =
                        (IEEE80211_SIGNAL_AVE_WEIGHT * rx_status->signal * 16 +
                         (16 - IEEE80211_SIGNAL_AVE_WEIGHT) *
                         ifmgd->ave_beacon_signal) / 16;
+               ifmgd->count_beacon_signal++;
        }
        if (bss_conf->cqm_rssi_thold &&
+           ifmgd->count_beacon_signal >= IEEE80211_SIGNAL_AVE_MIN_COUNT &&
            !(local->hw.flags & IEEE80211_HW_SUPPORTS_CQM_RSSI)) {
                int sig = ifmgd->ave_beacon_signal / 16;
                int last_event = ifmgd->last_cqm_event_signal;
@@ -1751,7 +1773,7 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
                struct ieee80211_local *local = sdata->local;
                struct ieee80211_work *wk;
 
-               mutex_lock(&local->work_mtx);
+               mutex_lock(&local->mtx);
                list_for_each_entry(wk, &local->work_list, list) {
                        if (wk->sdata != sdata)
                                continue;
@@ -1783,7 +1805,7 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
                        free_work(wk);
                        break;
                }
-               mutex_unlock(&local->work_mtx);
+               mutex_unlock(&local->mtx);
 
                cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len);
        }
@@ -1840,8 +1862,10 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata)
                                " after %dms, disconnecting.\n",
                                bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ);
                        ieee80211_set_disassoc(sdata, true);
-                       ieee80211_recalc_idle(local);
                        mutex_unlock(&ifmgd->mtx);
+                       mutex_lock(&local->mtx);
+                       ieee80211_recalc_idle(local);
+                       mutex_unlock(&local->mtx);
                        /*
                         * must be outside lock due to cfg80211,
                         * but that's not a problem.
@@ -1917,6 +1941,8 @@ void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata)
         * time -- the code here is properly synchronised.
         */
 
+       cancel_work_sync(&ifmgd->request_smps_work);
+
        cancel_work_sync(&ifmgd->beacon_connection_loss_work);
        if (del_timer_sync(&ifmgd->timer))
                set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running);
@@ -1952,6 +1978,7 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
        INIT_WORK(&ifmgd->chswitch_work, ieee80211_chswitch_work);
        INIT_WORK(&ifmgd->beacon_connection_loss_work,
                  ieee80211_beacon_connection_loss_work);
+       INIT_WORK(&ifmgd->request_smps_work, ieee80211_request_smps_work);
        setup_timer(&ifmgd->timer, ieee80211_sta_timer,
                    (unsigned long) sdata);
        setup_timer(&ifmgd->bcn_mon_timer, ieee80211_sta_bcn_mon_timer,
@@ -2249,6 +2276,9 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
        else
                ifmgd->flags &= ~IEEE80211_STA_CONTROL_PORT;
 
+       sdata->control_port_protocol = req->crypto.control_port_ethertype;
+       sdata->control_port_no_encrypt = req->crypto.control_port_no_encrypt;
+
        ieee80211_add_work(wk);
        return 0;
 }
@@ -2275,7 +2305,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
 
                mutex_unlock(&ifmgd->mtx);
 
-               mutex_lock(&local->work_mtx);
+               mutex_lock(&local->mtx);
                list_for_each_entry(wk, &local->work_list, list) {
                        if (wk->sdata != sdata)
                                continue;
@@ -2294,7 +2324,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
                        free_work(wk);
                        break;
                }
-               mutex_unlock(&local->work_mtx);
+               mutex_unlock(&local->mtx);
 
                /*
                 * If somebody requests authentication and we haven't
@@ -2319,7 +2349,9 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
        if (assoc_bss)
                sta_info_destroy_addr(sdata, bssid);
 
+       mutex_lock(&sdata->local->mtx);
        ieee80211_recalc_idle(sdata->local);
+       mutex_unlock(&sdata->local->mtx);
 
        return 0;
 }
@@ -2357,7 +2389,9 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
                        cookie, !req->local_state_change);
        sta_info_destroy_addr(sdata, bssid);
 
+       mutex_lock(&sdata->local->mtx);
        ieee80211_recalc_idle(sdata->local);
+       mutex_unlock(&sdata->local->mtx);
 
        return 0;
 }
index c36b1911987afec08262139ccaaf5e7887a17735..eeacaa59380a4c4cc91fe7f48d8ca622a13396b0 100644 (file)
@@ -112,8 +112,10 @@ void ieee80211_offchannel_stop_beaconing(struct ieee80211_local *local)
                 * used from user space controlled off-channel operations.
                 */
                if (sdata->vif.type != NL80211_IFTYPE_STATION &&
-                   sdata->vif.type != NL80211_IFTYPE_MONITOR)
+                   sdata->vif.type != NL80211_IFTYPE_MONITOR) {
+                       set_bit(SDATA_STATE_OFFCHANNEL, &sdata->state);
                        netif_tx_stop_all_queues(sdata->dev);
+               }
        }
        mutex_unlock(&local->iflist_mtx);
 }
@@ -131,6 +133,7 @@ void ieee80211_offchannel_stop_station(struct ieee80211_local *local)
                        continue;
 
                if (sdata->vif.type == NL80211_IFTYPE_STATION) {
+                       set_bit(SDATA_STATE_OFFCHANNEL, &sdata->state);
                        netif_tx_stop_all_queues(sdata->dev);
                        if (sdata->u.mgd.associated)
                                ieee80211_offchannel_ps_enable(sdata);
@@ -155,8 +158,20 @@ void ieee80211_offchannel_return(struct ieee80211_local *local,
                                ieee80211_offchannel_ps_disable(sdata);
                }
 
-               if (sdata->vif.type != NL80211_IFTYPE_MONITOR)
+               if (sdata->vif.type != NL80211_IFTYPE_MONITOR) {
+                       clear_bit(SDATA_STATE_OFFCHANNEL, &sdata->state);
+                       /*
+                        * This may wake up queues even though the driver
+                        * currently has them stopped. This is not very
+                        * likely, since the driver won't have gotten any
+                        * (or hardly any) new packets while we weren't
+                        * on the right channel, and even if it happens
+                        * it will at most lead to queueing up one more
+                        * packet per queue in mac80211 rather than on
+                        * the interface qdisc.
+                        */
                        netif_tx_wake_all_queues(sdata->dev);
+               }
 
                /* re-enable beaconing */
                if (enable_beaconing &&
index d287fde0431d6b2e688da5400d0ef9f41d9cf1c2..ce671dfd238c115281608e9fdb96b3ac3ce433fd 100644 (file)
@@ -12,7 +12,8 @@ int __ieee80211_suspend(struct ieee80211_hw *hw)
        struct ieee80211_sub_if_data *sdata;
        struct sta_info *sta;
 
-       ieee80211_scan_cancel(local);
+       if (unlikely(test_bit(SCAN_SW_SCANNING, &local->scanning)))
+               ieee80211_scan_cancel(local);
 
        ieee80211_stop_queues_by_reason(hw,
                        IEEE80211_QUEUE_STOP_REASON_SUSPEND);
index be04d46110fe8cdccc5e07eb810b67ee39c5c20f..4f772de2f21327f0e6a3c78736898caff548abaa 100644 (file)
@@ -368,8 +368,8 @@ int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local,
 
        ref = rate_control_alloc(name, local);
        if (!ref) {
-               printk(KERN_WARNING "%s: Failed to select rate control "
-                      "algorithm\n", wiphy_name(local->hw.wiphy));
+               wiphy_warn(local->hw.wiphy,
+                          "Failed to select rate control algorithm\n");
                return -ENOENT;
        }
 
@@ -380,9 +380,8 @@ int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local,
                sta_info_flush(local, NULL);
        }
 
-       printk(KERN_DEBUG "%s: Selected rate control "
-              "algorithm '%s'\n", wiphy_name(local->hw.wiphy),
-              ref->ops->name);
+       wiphy_debug(local->hw.wiphy, "Selected rate control algorithm '%s'\n",
+                   ref->ops->name);
 
        return 0;
 }
index 47438b4a9af52d33589e9cc1a695f77a8461d987..135f36fd4d5ddc290b7ad7d32cbeba3ed5a154dc 100644 (file)
@@ -162,7 +162,7 @@ static ssize_t rate_control_pid_events_read(struct file *file, char __user *buf,
        file_info->next_entry = (file_info->next_entry + 1) %
                                RC_PID_EVENT_RING_SIZE;
 
-       /* Print information about the event. Note that userpace needs to
+       /* Print information about the event. Note that userspace needs to
         * provide large enough buffers. */
        length = length < RC_PID_PRINT_BUF_SIZE ?
                 length : RC_PID_PRINT_BUF_SIZE;
index fa0f37e4afe4901226b0ccd668ae6a88c136eeb2..ac205a33690f90f8058cdd98e0ea5982657bcb18 100644 (file)
@@ -538,20 +538,12 @@ static void ieee80211_release_reorder_frame(struct ieee80211_hw *hw,
                                            int index,
                                            struct sk_buff_head *frames)
 {
-       struct ieee80211_supported_band *sband;
-       struct ieee80211_rate *rate = NULL;
        struct sk_buff *skb = tid_agg_rx->reorder_buf[index];
-       struct ieee80211_rx_status *status;
 
        if (!skb)
                goto no_frame;
 
-       status = IEEE80211_SKB_RXCB(skb);
-
-       /* release the reordered frames to stack */
-       sband = hw->wiphy->bands[status->band];
-       if (!(status->flag & RX_FLAG_HT))
-               rate = &sband->bitrates[status->rate_idx];
+       /* release the frame from the reorder ring buffer */
        tid_agg_rx->stored_mpdu_num--;
        tid_agg_rx->reorder_buf[index] = NULL;
        __skb_queue_tail(frames, skb);
@@ -580,9 +572,78 @@ static void ieee80211_release_reorder_frames(struct ieee80211_hw *hw,
  * frames that have not yet been received are assumed to be lost and the skb
  * can be released for processing. This may also release other skb's from the
  * reorder buffer if there are no additional gaps between the frames.
+ *
+ * Callers must hold tid_agg_rx->reorder_lock.
  */
 #define HT_RX_REORDER_BUF_TIMEOUT (HZ / 10)
 
+static void ieee80211_sta_reorder_release(struct ieee80211_hw *hw,
+                                         struct tid_ampdu_rx *tid_agg_rx,
+                                         struct sk_buff_head *frames)
+{
+       int index, j;
+
+       /* release the buffer until next missing frame */
+       index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) %
+                                               tid_agg_rx->buf_size;
+       if (!tid_agg_rx->reorder_buf[index] &&
+           tid_agg_rx->stored_mpdu_num > 1) {
+               /*
+                * No buffers ready to be released, but check whether any
+                * frames in the reorder buffer have timed out.
+                */
+               int skipped = 1;
+               for (j = (index + 1) % tid_agg_rx->buf_size; j != index;
+                    j = (j + 1) % tid_agg_rx->buf_size) {
+                       if (!tid_agg_rx->reorder_buf[j]) {
+                               skipped++;
+                               continue;
+                       }
+                       if (!time_after(jiffies, tid_agg_rx->reorder_time[j] +
+                                       HT_RX_REORDER_BUF_TIMEOUT))
+                               goto set_release_timer;
+
+#ifdef CONFIG_MAC80211_HT_DEBUG
+                       if (net_ratelimit())
+                               wiphy_debug(hw->wiphy,
+                                           "release an RX reorder frame due to timeout on earlier frames\n");
+#endif
+                       ieee80211_release_reorder_frame(hw, tid_agg_rx,
+                                                       j, frames);
+
+                       /*
+                        * Increment the head seq# also for the skipped slots.
+                        */
+                       tid_agg_rx->head_seq_num =
+                               (tid_agg_rx->head_seq_num + skipped) & SEQ_MASK;
+                       skipped = 0;
+               }
+       } else while (tid_agg_rx->reorder_buf[index]) {
+               ieee80211_release_reorder_frame(hw, tid_agg_rx, index, frames);
+               index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) %
+                                                       tid_agg_rx->buf_size;
+       }
+
+       if (tid_agg_rx->stored_mpdu_num) {
+               j = index = seq_sub(tid_agg_rx->head_seq_num,
+                                   tid_agg_rx->ssn) % tid_agg_rx->buf_size;
+
+               for (; j != (index - 1) % tid_agg_rx->buf_size;
+                    j = (j + 1) % tid_agg_rx->buf_size) {
+                       if (tid_agg_rx->reorder_buf[j])
+                               break;
+               }
+
+ set_release_timer:
+
+               mod_timer(&tid_agg_rx->reorder_timer,
+                         tid_agg_rx->reorder_time[j] +
+                         HT_RX_REORDER_BUF_TIMEOUT);
+       } else {
+               del_timer(&tid_agg_rx->reorder_timer);
+       }
+}
+
 /*
  * As this function belongs to the RX path it must be under
  * rcu_read_lock protection. It returns false if the frame
@@ -598,14 +659,16 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
        u16 mpdu_seq_num = (sc & IEEE80211_SCTL_SEQ) >> 4;
        u16 head_seq_num, buf_size;
        int index;
+       bool ret = true;
 
        buf_size = tid_agg_rx->buf_size;
        head_seq_num = tid_agg_rx->head_seq_num;
 
+       spin_lock(&tid_agg_rx->reorder_lock);
        /* frame with out of date sequence number */
        if (seq_less(mpdu_seq_num, head_seq_num)) {
                dev_kfree_skb(skb);
-               return true;
+               goto out;
        }
 
        /*
@@ -626,7 +689,7 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
        /* check if we already stored this frame */
        if (tid_agg_rx->reorder_buf[index]) {
                dev_kfree_skb(skb);
-               return true;
+               goto out;
        }
 
        /*
@@ -636,58 +699,19 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
        if (mpdu_seq_num == tid_agg_rx->head_seq_num &&
            tid_agg_rx->stored_mpdu_num == 0) {
                tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num);
-               return false;
+               ret = false;
+               goto out;
        }
 
        /* put the frame in the reordering buffer */
        tid_agg_rx->reorder_buf[index] = skb;
        tid_agg_rx->reorder_time[index] = jiffies;
        tid_agg_rx->stored_mpdu_num++;
-       /* release the buffer until next missing frame */
-       index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) %
-                                               tid_agg_rx->buf_size;
-       if (!tid_agg_rx->reorder_buf[index] &&
-           tid_agg_rx->stored_mpdu_num > 1) {
-               /*
-                * No buffers ready to be released, but check whether any
-                * frames in the reorder buffer have timed out.
-                */
-               int j;
-               int skipped = 1;
-               for (j = (index + 1) % tid_agg_rx->buf_size; j != index;
-                    j = (j + 1) % tid_agg_rx->buf_size) {
-                       if (!tid_agg_rx->reorder_buf[j]) {
-                               skipped++;
-                               continue;
-                       }
-                       if (!time_after(jiffies, tid_agg_rx->reorder_time[j] +
-                                       HT_RX_REORDER_BUF_TIMEOUT))
-                               break;
+       ieee80211_sta_reorder_release(hw, tid_agg_rx, frames);
 
-#ifdef CONFIG_MAC80211_HT_DEBUG
-                       if (net_ratelimit())
-                               printk(KERN_DEBUG "%s: release an RX reorder "
-                                      "frame due to timeout on earlier "
-                                      "frames\n",
-                                      wiphy_name(hw->wiphy));
-#endif
-                       ieee80211_release_reorder_frame(hw, tid_agg_rx,
-                                                       j, frames);
-
-                       /*
-                        * Increment the head seq# also for the skipped slots.
-                        */
-                       tid_agg_rx->head_seq_num =
-                               (tid_agg_rx->head_seq_num + skipped) & SEQ_MASK;
-                       skipped = 0;
-               }
-       } else while (tid_agg_rx->reorder_buf[index]) {
-               ieee80211_release_reorder_frame(hw, tid_agg_rx, index, frames);
-               index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) %
-                                                       tid_agg_rx->buf_size;
-       }
-
-       return true;
+ out:
+       spin_unlock(&tid_agg_rx->reorder_lock);
+       return ret;
 }
 
 /*
@@ -873,6 +897,9 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
 
        if (!is_multicast_ether_addr(hdr->addr1) && stakey) {
                rx->key = stakey;
+               if ((status->flag & RX_FLAG_DECRYPTED) &&
+                   (status->flag & RX_FLAG_IV_STRIPPED))
+                       return RX_CONTINUE;
                /* Skip decryption if the frame is not protected. */
                if (!ieee80211_has_protected(fc))
                        return RX_CONTINUE;
@@ -935,7 +962,8 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
                 * pairwise or station-to-station keys, but for WEP we allow
                 * using a key index as well.
                 */
-               if (rx->key && rx->key->conf.alg != ALG_WEP &&
+               if (rx->key && rx->key->conf.cipher != WLAN_CIPHER_SUITE_WEP40 &&
+                   rx->key->conf.cipher != WLAN_CIPHER_SUITE_WEP104 &&
                    !is_multicast_ether_addr(hdr->addr1))
                        rx->key = NULL;
        }
@@ -951,8 +979,9 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
                return RX_DROP_UNUSABLE;
        /* the hdr variable is invalid now! */
 
-       switch (rx->key->conf.alg) {
-       case ALG_WEP:
+       switch (rx->key->conf.cipher) {
+       case WLAN_CIPHER_SUITE_WEP40:
+       case WLAN_CIPHER_SUITE_WEP104:
                /* Check for weak IVs if possible */
                if (rx->sta && ieee80211_is_data(fc) &&
                    (!(status->flag & RX_FLAG_IV_STRIPPED) ||
@@ -962,15 +991,21 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
 
                result = ieee80211_crypto_wep_decrypt(rx);
                break;
-       case ALG_TKIP:
+       case WLAN_CIPHER_SUITE_TKIP:
                result = ieee80211_crypto_tkip_decrypt(rx);
                break;
-       case ALG_CCMP:
+       case WLAN_CIPHER_SUITE_CCMP:
                result = ieee80211_crypto_ccmp_decrypt(rx);
                break;
-       case ALG_AES_CMAC:
+       case WLAN_CIPHER_SUITE_AES_CMAC:
                result = ieee80211_crypto_aes_cmac_decrypt(rx);
                break;
+       default:
+               /*
+                * We can reach here only with HW-only algorithms
+                * but why didn't it decrypt the frame?!
+                */
+               return RX_DROP_UNUSABLE;
        }
 
        /* either the frame has been decrypted or will be dropped */
@@ -1265,7 +1300,7 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
                /* This is the first fragment of a new frame. */
                entry = ieee80211_reassemble_add(rx->sdata, frag, seq,
                                                 rx->queue, &(rx->skb));
-               if (rx->key && rx->key->conf.alg == ALG_CCMP &&
+               if (rx->key && rx->key->conf.cipher == WLAN_CIPHER_SUITE_CCMP &&
                    ieee80211_has_protected(fc)) {
                        int queue = ieee80211_is_mgmt(fc) ?
                                NUM_RX_DATA_QUEUES : rx->queue;
@@ -1294,7 +1329,7 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
                int i;
                u8 pn[CCMP_PN_LEN], *rpn;
                int queue;
-               if (!rx->key || rx->key->conf.alg != ALG_CCMP)
+               if (!rx->key || rx->key->conf.cipher != WLAN_CIPHER_SUITE_CCMP)
                        return RX_DROP_UNUSABLE;
                memcpy(pn, entry->last_pn, CCMP_PN_LEN);
                for (i = CCMP_PN_LEN - 1; i >= 0; i--) {
@@ -1492,7 +1527,7 @@ static bool ieee80211_frame_allowed(struct ieee80211_rx_data *rx, __le16 fc)
         * Allow EAPOL frames to us/the PAE group address regardless
         * of whether the frame was encrypted or not.
         */
-       if (ehdr->h_proto == htons(ETH_P_PAE) &&
+       if (ehdr->h_proto == rx->sdata->control_port_protocol &&
            (compare_ether_addr(ehdr->h_dest, rx->sdata->vif.addr) == 0 ||
             compare_ether_addr(ehdr->h_dest, pae_group_addr) == 0))
                return true;
@@ -1908,14 +1943,37 @@ static void ieee80211_process_sa_query_req(struct ieee80211_sub_if_data *sdata,
        ieee80211_tx_skb(sdata, skb);
 }
 
+static ieee80211_rx_result debug_noinline
+ieee80211_rx_h_mgmt_check(struct ieee80211_rx_data *rx)
+{
+       struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data;
+
+       /*
+        * From here on, look only at management frames.
+        * Data and control frames are already handled,
+        * and unknown (reserved) frames are useless.
+        */
+       if (rx->skb->len < 24)
+               return RX_DROP_MONITOR;
+
+       if (!ieee80211_is_mgmt(mgmt->frame_control))
+               return RX_DROP_MONITOR;
+
+       if (!(rx->flags & IEEE80211_RX_RA_MATCH))
+               return RX_DROP_MONITOR;
+
+       if (ieee80211_drop_unencrypted_mgmt(rx))
+               return RX_DROP_UNUSABLE;
+
+       return RX_CONTINUE;
+}
+
 static ieee80211_rx_result debug_noinline
 ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
 {
        struct ieee80211_local *local = rx->local;
        struct ieee80211_sub_if_data *sdata = rx->sdata;
        struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data;
-       struct sk_buff *nskb;
-       struct ieee80211_rx_status *status;
        int len = rx->skb->len;
 
        if (!ieee80211_is_action(mgmt->frame_control))
@@ -1931,9 +1989,6 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
        if (!(rx->flags & IEEE80211_RX_RA_MATCH))
                return RX_DROP_UNUSABLE;
 
-       if (ieee80211_drop_unencrypted_mgmt(rx))
-               return RX_DROP_UNUSABLE;
-
        switch (mgmt->u.action.category) {
        case WLAN_CATEGORY_BACK:
                /*
@@ -2024,17 +2079,36 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
                goto queue;
        }
 
+       return RX_CONTINUE;
+
  invalid:
-       /*
-        * For AP mode, hostapd is responsible for handling any action
-        * frames that we didn't handle, including returning unknown
-        * ones. For all other modes we will return them to the sender,
-        * setting the 0x80 bit in the action category, as required by
-        * 802.11-2007 7.3.1.11.
-        */
-       if (sdata->vif.type == NL80211_IFTYPE_AP ||
-           sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
-               return RX_DROP_MONITOR;
+       rx->flags |= IEEE80211_MALFORMED_ACTION_FRM;
+       /* will return in the next handlers */
+       return RX_CONTINUE;
+
+ handled:
+       if (rx->sta)
+               rx->sta->rx_packets++;
+       dev_kfree_skb(rx->skb);
+       return RX_QUEUED;
+
+ queue:
+       rx->skb->pkt_type = IEEE80211_SDATA_QUEUE_TYPE_FRAME;
+       skb_queue_tail(&sdata->skb_queue, rx->skb);
+       ieee80211_queue_work(&local->hw, &sdata->work);
+       if (rx->sta)
+               rx->sta->rx_packets++;
+       return RX_QUEUED;
+}
+
+static ieee80211_rx_result debug_noinline
+ieee80211_rx_h_userspace_mgmt(struct ieee80211_rx_data *rx)
+{
+       struct ieee80211_rx_status *status;
+
+       /* skip known-bad action frames and return them in the next handler */
+       if (rx->flags & IEEE80211_MALFORMED_ACTION_FRM)
+               return RX_CONTINUE;
 
        /*
         * Getting here means the kernel doesn't know how to handle
@@ -2044,10 +2118,44 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
         */
        status = IEEE80211_SKB_RXCB(rx->skb);
 
-       if (cfg80211_rx_action(rx->sdata->dev, status->freq,
-                              rx->skb->data, rx->skb->len,
-                              GFP_ATOMIC))
-               goto handled;
+       if (cfg80211_rx_mgmt(rx->sdata->dev, status->freq,
+                            rx->skb->data, rx->skb->len,
+                            GFP_ATOMIC)) {
+               if (rx->sta)
+                       rx->sta->rx_packets++;
+               dev_kfree_skb(rx->skb);
+               return RX_QUEUED;
+       }
+
+
+       return RX_CONTINUE;
+}
+
+static ieee80211_rx_result debug_noinline
+ieee80211_rx_h_action_return(struct ieee80211_rx_data *rx)
+{
+       struct ieee80211_local *local = rx->local;
+       struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data;
+       struct sk_buff *nskb;
+       struct ieee80211_sub_if_data *sdata = rx->sdata;
+
+       if (!ieee80211_is_action(mgmt->frame_control))
+               return RX_CONTINUE;
+
+       /*
+        * For AP mode, hostapd is responsible for handling any action
+        * frames that we didn't handle, including returning unknown
+        * ones. For all other modes we will return them to the sender,
+        * setting the 0x80 bit in the action category, as required by
+        * 802.11-2007 7.3.1.11.
+        * Newer versions of hostapd shall also use the management frame
+        * registration mechanisms, but older ones still use cooked
+        * monitor interfaces so push all frames there.
+        */
+       if (!(rx->flags & IEEE80211_MALFORMED_ACTION_FRM) &&
+           (sdata->vif.type == NL80211_IFTYPE_AP ||
+            sdata->vif.type == NL80211_IFTYPE_AP_VLAN))
+               return RX_DROP_MONITOR;
 
        /* do not return rejected action frames */
        if (mgmt->u.action.category & 0x80)
@@ -2066,20 +2174,8 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
 
                ieee80211_tx_skb(rx->sdata, nskb);
        }
-
- handled:
-       if (rx->sta)
-               rx->sta->rx_packets++;
        dev_kfree_skb(rx->skb);
        return RX_QUEUED;
-
- queue:
-       rx->skb->pkt_type = IEEE80211_SDATA_QUEUE_TYPE_FRAME;
-       skb_queue_tail(&sdata->skb_queue, rx->skb);
-       ieee80211_queue_work(&local->hw, &sdata->work);
-       if (rx->sta)
-               rx->sta->rx_packets++;
-       return RX_QUEUED;
 }
 
 static ieee80211_rx_result debug_noinline
@@ -2090,15 +2186,6 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx)
        struct ieee80211_mgmt *mgmt = (void *)rx->skb->data;
        __le16 stype;
 
-       if (!(rx->flags & IEEE80211_RX_RA_MATCH))
-               return RX_DROP_MONITOR;
-
-       if (rx->skb->len < 24)
-               return RX_DROP_MONITOR;
-
-       if (ieee80211_drop_unencrypted_mgmt(rx))
-               return RX_DROP_UNUSABLE;
-
        rxs = ieee80211_work_rx_mgmt(rx->sdata, rx->skb);
        if (rxs != RX_CONTINUE)
                return rxs;
@@ -2267,19 +2354,46 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx,
        dev_kfree_skb(skb);
 }
 
+static void ieee80211_rx_handlers_result(struct ieee80211_rx_data *rx,
+                                        ieee80211_rx_result res)
+{
+       switch (res) {
+       case RX_DROP_MONITOR:
+               I802_DEBUG_INC(rx->sdata->local->rx_handlers_drop);
+               if (rx->sta)
+                       rx->sta->rx_dropped++;
+               /* fall through */
+       case RX_CONTINUE: {
+               struct ieee80211_rate *rate = NULL;
+               struct ieee80211_supported_band *sband;
+               struct ieee80211_rx_status *status;
+
+               status = IEEE80211_SKB_RXCB((rx->skb));
+
+               sband = rx->local->hw.wiphy->bands[status->band];
+               if (!(status->flag & RX_FLAG_HT))
+                       rate = &sband->bitrates[status->rate_idx];
+
+               ieee80211_rx_cooked_monitor(rx, rate);
+               break;
+               }
+       case RX_DROP_UNUSABLE:
+               I802_DEBUG_INC(rx->sdata->local->rx_handlers_drop);
+               if (rx->sta)
+                       rx->sta->rx_dropped++;
+               dev_kfree_skb(rx->skb);
+               break;
+       case RX_QUEUED:
+               I802_DEBUG_INC(rx->sdata->local->rx_handlers_queued);
+               break;
+       }
+}
 
-static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata,
-                                        struct ieee80211_rx_data *rx,
-                                        struct sk_buff *skb,
-                                        struct ieee80211_rate *rate)
+static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx,
+                                 struct sk_buff_head *frames)
 {
-       struct sk_buff_head reorder_release;
        ieee80211_rx_result res = RX_DROP_MONITOR;
-
-       __skb_queue_head_init(&reorder_release);
-
-       rx->skb = skb;
-       rx->sdata = sdata;
+       struct sk_buff *skb;
 
 #define CALL_RXH(rxh)                  \
        do {                            \
@@ -2288,17 +2402,7 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata,
                        goto rxh_next;  \
        } while (0);
 
-       /*
-        * NB: the rxh_next label works even if we jump
-        *     to it from here because then the list will
-        *     be empty, which is a trivial check
-        */
-       CALL_RXH(ieee80211_rx_h_passive_scan)
-       CALL_RXH(ieee80211_rx_h_check)
-
-       ieee80211_rx_reorder_ampdu(rx, &reorder_release);
-
-       while ((skb = __skb_dequeue(&reorder_release))) {
+       while ((skb = __skb_dequeue(frames))) {
                /*
                 * all the other fields are valid across frames
                 * that belong to an aMPDU since they are on the
@@ -2316,42 +2420,95 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata,
                CALL_RXH(ieee80211_rx_h_remove_qos_control)
                CALL_RXH(ieee80211_rx_h_amsdu)
 #ifdef CONFIG_MAC80211_MESH
-               if (ieee80211_vif_is_mesh(&sdata->vif))
+               if (ieee80211_vif_is_mesh(&rx->sdata->vif))
                        CALL_RXH(ieee80211_rx_h_mesh_fwding);
 #endif
                CALL_RXH(ieee80211_rx_h_data)
 
                /* special treatment -- needs the queue */
-               res = ieee80211_rx_h_ctrl(rx, &reorder_release);
+               res = ieee80211_rx_h_ctrl(rx, frames);
                if (res != RX_CONTINUE)
                        goto rxh_next;
 
+               CALL_RXH(ieee80211_rx_h_mgmt_check)
                CALL_RXH(ieee80211_rx_h_action)
+               CALL_RXH(ieee80211_rx_h_userspace_mgmt)
+               CALL_RXH(ieee80211_rx_h_action_return)
                CALL_RXH(ieee80211_rx_h_mgmt)
 
+ rxh_next:
+               ieee80211_rx_handlers_result(rx, res);
+
 #undef CALL_RXH
+       }
+}
+
+static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata,
+                                        struct ieee80211_rx_data *rx,
+                                        struct sk_buff *skb)
+{
+       struct sk_buff_head reorder_release;
+       ieee80211_rx_result res = RX_DROP_MONITOR;
+
+       __skb_queue_head_init(&reorder_release);
+
+       rx->skb = skb;
+       rx->sdata = sdata;
+
+#define CALL_RXH(rxh)                  \
+       do {                            \
+               res = rxh(rx);          \
+               if (res != RX_CONTINUE) \
+                       goto rxh_next;  \
+       } while (0);
+
+       CALL_RXH(ieee80211_rx_h_passive_scan)
+       CALL_RXH(ieee80211_rx_h_check)
+
+       ieee80211_rx_reorder_ampdu(rx, &reorder_release);
+
+       ieee80211_rx_handlers(rx, &reorder_release);
+       return;
 
  rxh_next:
-               switch (res) {
-               case RX_DROP_MONITOR:
-                       I802_DEBUG_INC(sdata->local->rx_handlers_drop);
-                       if (rx->sta)
-                               rx->sta->rx_dropped++;
-                       /* fall through */
-               case RX_CONTINUE:
-                       ieee80211_rx_cooked_monitor(rx, rate);
-                       break;
-               case RX_DROP_UNUSABLE:
-                       I802_DEBUG_INC(sdata->local->rx_handlers_drop);
-                       if (rx->sta)
-                               rx->sta->rx_dropped++;
-                       dev_kfree_skb(rx->skb);
-                       break;
-               case RX_QUEUED:
-                       I802_DEBUG_INC(sdata->local->rx_handlers_queued);
-                       break;
-               }
-       }
+       ieee80211_rx_handlers_result(rx, res);
+
+#undef CALL_RXH
+}
+
+/*
+ * This function makes calls into the RX path. Therefore the
+ * caller must hold the sta_info->lock and everything has to
+ * be under rcu_read_lock protection as well.
+ */
+void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid)
+{
+       struct sk_buff_head frames;
+       struct ieee80211_rx_data rx = { };
+       struct tid_ampdu_rx *tid_agg_rx;
+
+       tid_agg_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[tid]);
+       if (!tid_agg_rx)
+               return;
+
+       __skb_queue_head_init(&frames);
+
+       /* construct rx struct */
+       rx.sta = sta;
+       rx.sdata = sta->sdata;
+       rx.local = sta->local;
+       rx.queue = tid;
+       rx.flags |= IEEE80211_RX_RA_MATCH;
+
+       if (unlikely(test_bit(SCAN_HW_SCANNING, &sta->local->scanning) ||
+                    test_bit(SCAN_OFF_CHANNEL, &sta->local->scanning)))
+               rx.flags |= IEEE80211_RX_IN_SCAN;
+
+       spin_lock(&tid_agg_rx->reorder_lock);
+       ieee80211_sta_reorder_release(&sta->local->hw, tid_agg_rx, &frames);
+       spin_unlock(&tid_agg_rx->reorder_lock);
+
+       ieee80211_rx_handlers(&rx, &frames);
 }
 
 /* main receive path */
@@ -2433,7 +2590,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
                break;
        case NL80211_IFTYPE_MONITOR:
        case NL80211_IFTYPE_UNSPECIFIED:
-       case __NL80211_IFTYPE_AFTER_LAST:
+       case NUM_NL80211_IFTYPES:
                /* should never get here */
                WARN_ON(1);
                break;
@@ -2447,8 +2604,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
  * be called with rcu_read_lock protection.
  */
 static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
-                                        struct sk_buff *skb,
-                                        struct ieee80211_rate *rate)
+                                        struct sk_buff *skb)
 {
        struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
        struct ieee80211_local *local = hw_to_local(hw);
@@ -2550,13 +2706,12 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
                        skb_new = skb_copy(skb, GFP_ATOMIC);
                        if (!skb_new) {
                                if (net_ratelimit())
-                                       printk(KERN_DEBUG "%s: failed to copy "
-                                              "multicast frame for %s\n",
-                                              wiphy_name(local->hw.wiphy),
-                                              prev->name);
+                                       wiphy_debug(local->hw.wiphy,
+                                                   "failed to copy multicast frame for %s\n",
+                                                   prev->name);
                                goto next;
                        }
-                       ieee80211_invoke_rx_handlers(prev, &rx, skb_new, rate);
+                       ieee80211_invoke_rx_handlers(prev, &rx, skb_new);
 next:
                        prev = sdata;
                }
@@ -2572,7 +2727,7 @@ next:
                }
        }
        if (prev)
-               ieee80211_invoke_rx_handlers(prev, &rx, skb, rate);
+               ieee80211_invoke_rx_handlers(prev, &rx, skb);
        else
                dev_kfree_skb(skb);
 }
@@ -2615,28 +2770,37 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
        if (WARN_ON(!local->started))
                goto drop;
 
-       if (status->flag & RX_FLAG_HT) {
+       if (likely(!(status->flag & RX_FLAG_FAILED_PLCP_CRC))) {
                /*
-                * rate_idx is MCS index, which can be [0-76] as documented on:
-                *
-                * http://wireless.kernel.org/en/developers/Documentation/ieee80211/802.11n
-                *
-                * Anything else would be some sort of driver or hardware error.
-                * The driver should catch hardware errors.
+                * Validate the rate, unless a PLCP error means that
+                * we probably can't have a valid rate here anyway.
                 */
-               if (WARN((status->rate_idx < 0 ||
-                        status->rate_idx > 76),
-                        "Rate marked as an HT rate but passed "
-                        "status->rate_idx is not "
-                        "an MCS index [0-76]: %d (0x%02x)\n",
-                        status->rate_idx,
-                        status->rate_idx))
-                       goto drop;
-       } else {
-               if (WARN_ON(status->rate_idx < 0 ||
-                           status->rate_idx >= sband->n_bitrates))
-                       goto drop;
-               rate = &sband->bitrates[status->rate_idx];
+
+               if (status->flag & RX_FLAG_HT) {
+                       /*
+                        * rate_idx is MCS index, which can be [0-76]
+                        * as documented on:
+                        *
+                        * http://wireless.kernel.org/en/developers/Documentation/ieee80211/802.11n
+                        *
+                        * Anything else would be some sort of driver or
+                        * hardware error. The driver should catch hardware
+                        * errors.
+                        */
+                       if (WARN((status->rate_idx < 0 ||
+                                status->rate_idx > 76),
+                                "Rate marked as an HT rate but passed "
+                                "status->rate_idx is not "
+                                "an MCS index [0-76]: %d (0x%02x)\n",
+                                status->rate_idx,
+                                status->rate_idx))
+                               goto drop;
+               } else {
+                       if (WARN_ON(status->rate_idx < 0 ||
+                                   status->rate_idx >= sband->n_bitrates))
+                               goto drop;
+                       rate = &sband->bitrates[status->rate_idx];
+               }
        }
 
        /*
@@ -2658,7 +2822,7 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
                return;
        }
 
-       __ieee80211_rx_handle_packet(hw, skb, rate);
+       __ieee80211_rx_handle_packet(hw, skb);
 
        rcu_read_unlock();
 
index 872d7b6ef6b34f6dabdfbd0c491d94306d2fdf04..d60389ba9b952c9cc60782151e24dc9860644235 100644 (file)
@@ -248,14 +248,12 @@ static bool ieee80211_prep_hw_scan(struct ieee80211_local *local)
        return true;
 }
 
-void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
+static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
 {
        struct ieee80211_local *local = hw_to_local(hw);
        bool was_hw_scan;
 
-       trace_api_scan_completed(local, aborted);
-
-       mutex_lock(&local->scan_mtx);
+       mutex_lock(&local->mtx);
 
        /*
         * It's ok to abort a not-yet-running scan (that
@@ -267,7 +265,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
                aborted = true;
 
        if (WARN_ON(!local->scan_req)) {
-               mutex_unlock(&local->scan_mtx);
+               mutex_unlock(&local->mtx);
                return;
        }
 
@@ -275,7 +273,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
        if (was_hw_scan && !aborted && ieee80211_prep_hw_scan(local)) {
                ieee80211_queue_delayed_work(&local->hw,
                                             &local->scan_work, 0);
-               mutex_unlock(&local->scan_mtx);
+               mutex_unlock(&local->mtx);
                return;
        }
 
@@ -291,7 +289,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
        local->scan_channel = NULL;
 
        /* we only have to protect scan_req and hw/sw scan */
-       mutex_unlock(&local->scan_mtx);
+       mutex_unlock(&local->mtx);
 
        ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
        if (was_hw_scan)
@@ -304,12 +302,26 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
        ieee80211_offchannel_return(local, true);
 
  done:
+       mutex_lock(&local->mtx);
        ieee80211_recalc_idle(local);
+       mutex_unlock(&local->mtx);
        ieee80211_mlme_notify_scan_completed(local);
        ieee80211_ibss_notify_scan_completed(local);
        ieee80211_mesh_notify_scan_completed(local);
        ieee80211_queue_work(&local->hw, &local->work_work);
 }
+
+void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
+{
+       struct ieee80211_local *local = hw_to_local(hw);
+
+       trace_api_scan_completed(local, aborted);
+
+       set_bit(SCAN_COMPLETED, &local->scanning);
+       if (aborted)
+               set_bit(SCAN_ABORTED, &local->scanning);
+       ieee80211_queue_delayed_work(&local->hw, &local->scan_work, 0);
+}
 EXPORT_SYMBOL(ieee80211_scan_completed);
 
 static int ieee80211_start_sw_scan(struct ieee80211_local *local)
@@ -447,7 +459,7 @@ static int ieee80211_scan_state_decision(struct ieee80211_local *local,
 
        /* if no more bands/channels left, complete scan and advance to the idle state */
        if (local->scan_channel_idx >= local->scan_req->n_channels) {
-               ieee80211_scan_completed(&local->hw, false);
+               __ieee80211_scan_completed(&local->hw, false);
                return 1;
        }
 
@@ -639,17 +651,25 @@ void ieee80211_scan_work(struct work_struct *work)
        struct ieee80211_sub_if_data *sdata = local->scan_sdata;
        unsigned long next_delay = 0;
 
-       mutex_lock(&local->scan_mtx);
+       if (test_and_clear_bit(SCAN_COMPLETED, &local->scanning)) {
+               bool aborted;
+
+               aborted = test_and_clear_bit(SCAN_ABORTED, &local->scanning);
+               __ieee80211_scan_completed(&local->hw, aborted);
+               return;
+       }
+
+       mutex_lock(&local->mtx);
        if (!sdata || !local->scan_req) {
-               mutex_unlock(&local->scan_mtx);
+               mutex_unlock(&local->mtx);
                return;
        }
 
        if (local->hw_scan_req) {
                int rc = drv_hw_scan(local, sdata, local->hw_scan_req);
-               mutex_unlock(&local->scan_mtx);
+               mutex_unlock(&local->mtx);
                if (rc)
-                       ieee80211_scan_completed(&local->hw, true);
+                       __ieee80211_scan_completed(&local->hw, true);
                return;
        }
 
@@ -661,20 +681,20 @@ void ieee80211_scan_work(struct work_struct *work)
                local->scan_sdata = NULL;
 
                rc = __ieee80211_start_scan(sdata, req);
-               mutex_unlock(&local->scan_mtx);
+               mutex_unlock(&local->mtx);
 
                if (rc)
-                       ieee80211_scan_completed(&local->hw, true);
+                       __ieee80211_scan_completed(&local->hw, true);
                return;
        }
 
-       mutex_unlock(&local->scan_mtx);
+       mutex_unlock(&local->mtx);
 
        /*
         * Avoid re-scheduling when the sdata is going away.
         */
        if (!ieee80211_sdata_running(sdata)) {
-               ieee80211_scan_completed(&local->hw, true);
+               __ieee80211_scan_completed(&local->hw, true);
                return;
        }
 
@@ -711,9 +731,9 @@ int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata,
 {
        int res;
 
-       mutex_lock(&sdata->local->scan_mtx);
+       mutex_lock(&sdata->local->mtx);
        res = __ieee80211_start_scan(sdata, req);
-       mutex_unlock(&sdata->local->scan_mtx);
+       mutex_unlock(&sdata->local->mtx);
 
        return res;
 }
@@ -726,7 +746,7 @@ int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata,
        int ret = -EBUSY;
        enum ieee80211_band band;
 
-       mutex_lock(&local->scan_mtx);
+       mutex_lock(&local->mtx);
 
        /* busy scanning */
        if (local->scan_req)
@@ -761,7 +781,7 @@ int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata,
 
        ret = __ieee80211_start_scan(sdata, sdata->local->int_scan_req);
  unlock:
-       mutex_unlock(&local->scan_mtx);
+       mutex_unlock(&local->mtx);
        return ret;
 }
 
@@ -775,11 +795,11 @@ void ieee80211_scan_cancel(struct ieee80211_local *local)
         * Only call this function when a scan can't be
         * queued -- mostly at suspend under RTNL.
         */
-       mutex_lock(&local->scan_mtx);
+       mutex_lock(&local->mtx);
        abortscan = test_bit(SCAN_SW_SCANNING, &local->scanning) ||
                    (!local->scanning && local->scan_req);
-       mutex_unlock(&local->scan_mtx);
+       mutex_unlock(&local->mtx);
 
        if (abortscan)
-               ieee80211_scan_completed(&local->hw, true);
+               __ieee80211_scan_completed(&local->hw, true);
 }
index 6d86f0c1ad0415acc4d96d0131d27bb2dc77f614..687077e49dc6ecaa44648db98a25138a12c14fd2 100644 (file)
@@ -174,8 +174,7 @@ static void __sta_info_free(struct ieee80211_local *local,
        }
 
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-       printk(KERN_DEBUG "%s: Destroyed STA %pM\n",
-              wiphy_name(local->hw.wiphy), sta->sta.addr);
+       wiphy_debug(local->hw.wiphy, "Destroyed STA %pM\n", sta->sta.addr);
 #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
 
        kfree(sta);
@@ -262,8 +261,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
                sta->last_seq_ctrl[i] = cpu_to_le16(USHRT_MAX);
 
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-       printk(KERN_DEBUG "%s: Allocated STA %pM\n",
-              wiphy_name(local->hw.wiphy), sta->sta.addr);
+       wiphy_debug(local->hw.wiphy, "Allocated STA %pM\n", sta->sta.addr);
 #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
 
 #ifdef CONFIG_MAC80211_MESH
@@ -300,8 +298,9 @@ static int sta_info_finish_insert(struct sta_info *sta, bool async)
                sta->uploaded = true;
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
                if (async)
-                       printk(KERN_DEBUG "%s: Finished adding IBSS STA %pM\n",
-                              wiphy_name(local->hw.wiphy), sta->sta.addr);
+                       wiphy_debug(local->hw.wiphy,
+                                   "Finished adding IBSS STA %pM\n",
+                                   sta->sta.addr);
 #endif
        }
 
@@ -411,8 +410,8 @@ int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU)
                spin_unlock_irqrestore(&local->sta_lock, flags);
 
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-               printk(KERN_DEBUG "%s: Added IBSS STA %pM\n",
-                      wiphy_name(local->hw.wiphy), sta->sta.addr);
+               wiphy_debug(local->hw.wiphy, "Added IBSS STA %pM\n",
+                           sta->sta.addr);
 #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
 
                ieee80211_queue_work(&local->hw, &local->sta_finish_work);
@@ -459,8 +458,7 @@ int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU)
        }
 
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-       printk(KERN_DEBUG "%s: Inserted STA %pM\n",
-              wiphy_name(local->hw.wiphy), sta->sta.addr);
+       wiphy_debug(local->hw.wiphy, "Inserted STA %pM\n", sta->sta.addr);
 #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
 
        /* move reference to rcu-protected */
@@ -690,8 +688,7 @@ static int __must_check __sta_info_destroy(struct sta_info *sta)
 #endif
 
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-       printk(KERN_DEBUG "%s: Removed STA %pM\n",
-              wiphy_name(local->hw.wiphy), sta->sta.addr);
+       wiphy_debug(local->hw.wiphy, "Removed STA %pM\n", sta->sta.addr);
 #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
        cancel_work_sync(&sta->drv_unblock_wk);
 
index 54262e72376d0e662ebbb1b27b02a14e6a869cdb..810c5ce98316549a581d537aebb492a2f5e0065d 100644 (file)
@@ -103,6 +103,7 @@ struct tid_ampdu_tx {
  * @reorder_buf: buffer to reorder incoming aggregated MPDUs
  * @reorder_time: jiffies when skb was added
  * @session_timer: check if peer keeps Tx-ing on the TID (by timeout value)
+ * @reorder_timer: releases expired frames from the reorder buffer.
  * @head_seq_num: head sequence number in reordering buffer.
  * @stored_mpdu_num: number of MPDUs in reordering buffer
  * @ssn: Starting Sequence Number expected to be aggregated.
@@ -110,20 +111,25 @@ struct tid_ampdu_tx {
  * @timeout: reset timer value (in TUs).
  * @dialog_token: dialog token for aggregation session
  * @rcu_head: RCU head used for freeing this struct
+ * @reorder_lock: serializes access to reorder buffer, see below.
  *
  * This structure is protected by RCU and the per-station
  * spinlock. Assignments to the array holding it must hold
- * the spinlock, only the RX path can access it under RCU
- * lock-free. The RX path, since it is single-threaded,
- * can even modify the structure without locking since the
- * only other modifications to it are done when the struct
- * can not yet or no longer be found by the RX path.
+ * the spinlock.
+ *
+ * The @reorder_lock is used to protect the variables and
+ * arrays such as @reorder_buf, @reorder_time, @head_seq_num,
+ * @stored_mpdu_num and @reorder_time from being corrupted by
+ * concurrent access of the RX path and the expired frame
+ * release timer.
  */
 struct tid_ampdu_rx {
        struct rcu_head rcu_head;
+       spinlock_t reorder_lock;
        struct sk_buff **reorder_buf;
        unsigned long *reorder_time;
        struct timer_list session_timer;
+       struct timer_list reorder_timer;
        u16 head_seq_num;
        u16 stored_mpdu_num;
        u16 ssn;
index 10caec5ea8fa7740d9617605adf1590eefa2a730..571b32bfc54c9b14321f6883404e3062d789750a 100644 (file)
@@ -114,11 +114,10 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
 
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
        if (net_ratelimit())
-               printk(KERN_DEBUG "%s: dropped TX filtered frame, "
-                      "queue_len=%d PS=%d @%lu\n",
-                      wiphy_name(local->hw.wiphy),
-                      skb_queue_len(&sta->tx_filtered),
-                      !!test_sta_flags(sta, WLAN_STA_PS_STA), jiffies);
+               wiphy_debug(local->hw.wiphy,
+                           "dropped TX filtered frame, queue_len=%d PS=%d @%lu\n",
+                           skb_queue_len(&sta->tx_filtered),
+                           !!test_sta_flags(sta, WLAN_STA_PS_STA), jiffies);
 #endif
        dev_kfree_skb(skb);
 }
@@ -296,7 +295,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
        }
 
        if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX)
-               cfg80211_action_tx_status(
+               cfg80211_mgmt_tx_status(
                        skb->dev, (unsigned long) skb, skb->data, skb->len,
                        !!(info->flags & IEEE80211_TX_STAT_ACK), GFP_ATOMIC);
 
index c54db966926b455dc3d72ae0f71b7c71d3204861..ccf373788ce9929dc2599034f4db310d1f9ed324 100644 (file)
@@ -351,8 +351,8 @@ static void purge_old_ps_buffers(struct ieee80211_local *local)
 
        local->total_ps_buffered = total;
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
-       printk(KERN_DEBUG "%s: PS buffers full - purged %d frames\n",
-              wiphy_name(local->hw.wiphy), purged);
+       wiphy_debug(local->hw.wiphy, "PS buffers full - purged %d frames\n",
+                   purged);
 #endif
 }
 
@@ -508,6 +508,18 @@ ieee80211_tx_h_ps_buf(struct ieee80211_tx_data *tx)
                return ieee80211_tx_h_multicast_ps_buf(tx);
 }
 
+static ieee80211_tx_result debug_noinline
+ieee80211_tx_h_check_control_port_protocol(struct ieee80211_tx_data *tx)
+{
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
+
+       if (unlikely(tx->sdata->control_port_protocol == tx->skb->protocol &&
+                    tx->sdata->control_port_no_encrypt))
+               info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
+
+       return TX_CONTINUE;
+}
+
 static ieee80211_tx_result debug_noinline
 ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
 {
@@ -527,7 +539,7 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
        else if ((key = rcu_dereference(tx->sdata->default_key)))
                tx->key = key;
        else if (tx->sdata->drop_unencrypted &&
-                (tx->skb->protocol != cpu_to_be16(ETH_P_PAE)) &&
+                (tx->skb->protocol != tx->sdata->control_port_protocol) &&
                 !(info->flags & IEEE80211_TX_CTL_INJECTED) &&
                 (!ieee80211_is_robust_mgmt_frame(hdr) ||
                  (ieee80211_is_action(hdr->frame_control) &&
@@ -543,15 +555,16 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
                tx->key->tx_rx_count++;
                /* TODO: add threshold stuff again */
 
-               switch (tx->key->conf.alg) {
-               case ALG_WEP:
+               switch (tx->key->conf.cipher) {
+               case WLAN_CIPHER_SUITE_WEP40:
+               case WLAN_CIPHER_SUITE_WEP104:
                        if (ieee80211_is_auth(hdr->frame_control))
                                break;
-               case ALG_TKIP:
+               case WLAN_CIPHER_SUITE_TKIP:
                        if (!ieee80211_is_data_present(hdr->frame_control))
                                tx->key = NULL;
                        break;
-               case ALG_CCMP:
+               case WLAN_CIPHER_SUITE_CCMP:
                        if (!ieee80211_is_data_present(hdr->frame_control) &&
                            !ieee80211_use_mfp(hdr->frame_control, tx->sta,
                                               tx->skb))
@@ -561,7 +574,7 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
                                           IEEE80211_KEY_FLAG_SW_MGMT) &&
                                        ieee80211_is_mgmt(hdr->frame_control);
                        break;
-               case ALG_AES_CMAC:
+               case WLAN_CIPHER_SUITE_AES_CMAC:
                        if (!ieee80211_is_mgmt(hdr->frame_control))
                                tx->key = NULL;
                        break;
@@ -946,22 +959,31 @@ ieee80211_tx_h_stats(struct ieee80211_tx_data *tx)
 static ieee80211_tx_result debug_noinline
 ieee80211_tx_h_encrypt(struct ieee80211_tx_data *tx)
 {
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
+
        if (!tx->key)
                return TX_CONTINUE;
 
-       switch (tx->key->conf.alg) {
-       case ALG_WEP:
+       switch (tx->key->conf.cipher) {
+       case WLAN_CIPHER_SUITE_WEP40:
+       case WLAN_CIPHER_SUITE_WEP104:
                return ieee80211_crypto_wep_encrypt(tx);
-       case ALG_TKIP:
+       case WLAN_CIPHER_SUITE_TKIP:
                return ieee80211_crypto_tkip_encrypt(tx);
-       case ALG_CCMP:
+       case WLAN_CIPHER_SUITE_CCMP:
                return ieee80211_crypto_ccmp_encrypt(tx);
-       case ALG_AES_CMAC:
+       case WLAN_CIPHER_SUITE_AES_CMAC:
                return ieee80211_crypto_aes_cmac_encrypt(tx);
+       default:
+               /* handle hw-only algorithm */
+               if (info->control.hw_key) {
+                       ieee80211_tx_set_protected(tx);
+                       return TX_CONTINUE;
+               }
+               break;
+
        }
 
-       /* not reached */
-       WARN_ON(1);
        return TX_DROP;
 }
 
@@ -1339,6 +1361,7 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx)
        CALL_TXH(ieee80211_tx_h_dynamic_ps);
        CALL_TXH(ieee80211_tx_h_check_assoc);
        CALL_TXH(ieee80211_tx_h_ps_buf);
+       CALL_TXH(ieee80211_tx_h_check_control_port_protocol);
        CALL_TXH(ieee80211_tx_h_select_key);
        if (!(tx->local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL))
                CALL_TXH(ieee80211_tx_h_rate_ctrl);
@@ -1511,8 +1534,8 @@ static int ieee80211_skb_resize(struct ieee80211_local *local,
                I802_DEBUG_INC(local->tx_expand_skb_head);
 
        if (pskb_expand_head(skb, head_need, tail_need, GFP_ATOMIC)) {
-               printk(KERN_DEBUG "%s: failed to reallocate TX buffer\n",
-                      wiphy_name(local->hw.wiphy));
+               wiphy_debug(local->hw.wiphy,
+                           "failed to reallocate TX buffer\n");
                return -ENOMEM;
        }
 
@@ -1699,7 +1722,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
        u16 ethertype, hdrlen,  meshhdrlen = 0;
        __le16 fc;
        struct ieee80211_hdr hdr;
-       struct ieee80211s_hdr mesh_hdr;
+       struct ieee80211s_hdr mesh_hdr __maybe_unused;
        const u8 *encaps_data;
        int encaps_len, skip_header_bytes;
        int nh_pos, h_pos;
@@ -1816,7 +1839,8 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
 #endif
        case NL80211_IFTYPE_STATION:
                memcpy(hdr.addr1, sdata->u.mgd.bssid, ETH_ALEN);
-               if (sdata->u.mgd.use_4addr && ethertype != ETH_P_PAE) {
+               if (sdata->u.mgd.use_4addr &&
+                   cpu_to_be16(ethertype) != sdata->control_port_protocol) {
                        fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
                        /* RA TA DA SA */
                        memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN);
@@ -1869,7 +1893,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
        if (!ieee80211_vif_is_mesh(&sdata->vif) &&
                unlikely(!is_multicast_ether_addr(hdr.addr1) &&
                      !(sta_flags & WLAN_STA_AUTHORIZED) &&
-                     !(ethertype == ETH_P_PAE &&
+                     !(cpu_to_be16(ethertype) == sdata->control_port_protocol &&
                       compare_ether_addr(sdata->vif.addr,
                                          skb->data + ETH_ALEN) == 0))) {
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
@@ -2068,8 +2092,7 @@ void ieee80211_tx_pending(unsigned long data)
 
                if (skb_queue_empty(&local->pending[i]))
                        list_for_each_entry_rcu(sdata, &local->interfaces, list)
-                               netif_tx_wake_queue(
-                                       netdev_get_tx_queue(sdata->dev, i));
+                               netif_wake_subqueue(sdata->dev, i);
        }
        spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
 
index 748387d45bc05f8fbab8a579066c7c0771a6cca8..bd40b11d5ab9e514d7e75f887baebf65352e0370 100644 (file)
@@ -283,8 +283,11 @@ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue,
 
        if (skb_queue_empty(&local->pending[queue])) {
                rcu_read_lock();
-               list_for_each_entry_rcu(sdata, &local->interfaces, list)
-                       netif_tx_wake_queue(netdev_get_tx_queue(sdata->dev, queue));
+               list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+                       if (test_bit(SDATA_STATE_OFFCHANNEL, &sdata->state))
+                               continue;
+                       netif_wake_subqueue(sdata->dev, queue);
+               }
                rcu_read_unlock();
        } else
                tasklet_schedule(&local->tx_pending_tasklet);
@@ -323,7 +326,7 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue,
 
        rcu_read_lock();
        list_for_each_entry_rcu(sdata, &local->interfaces, list)
-               netif_tx_stop_queue(netdev_get_tx_queue(sdata->dev, queue));
+               netif_stop_subqueue(sdata->dev, queue);
        rcu_read_unlock();
 }
 
@@ -471,7 +474,7 @@ void ieee80211_iterate_active_interfaces(
 
        list_for_each_entry(sdata, &local->interfaces, list) {
                switch (sdata->vif.type) {
-               case __NL80211_IFTYPE_AFTER_LAST:
+               case NUM_NL80211_IFTYPES:
                case NL80211_IFTYPE_UNSPECIFIED:
                case NL80211_IFTYPE_MONITOR:
                case NL80211_IFTYPE_AP_VLAN:
@@ -505,7 +508,7 @@ void ieee80211_iterate_active_interfaces_atomic(
 
        list_for_each_entry_rcu(sdata, &local->interfaces, list) {
                switch (sdata->vif.type) {
-               case __NL80211_IFTYPE_AFTER_LAST:
+               case NUM_NL80211_IFTYPES:
                case NL80211_IFTYPE_UNSPECIFIED:
                case NL80211_IFTYPE_MONITOR:
                case NL80211_IFTYPE_AP_VLAN:
@@ -1189,7 +1192,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
                        /* ignore virtual */
                        break;
                case NL80211_IFTYPE_UNSPECIFIED:
-               case __NL80211_IFTYPE_AFTER_LAST:
+               case NUM_NL80211_IFTYPES:
                        WARN_ON(1);
                        break;
                }
@@ -1308,7 +1311,7 @@ void ieee80211_recalc_smps(struct ieee80211_local *local,
         */
 
        list_for_each_entry(sdata, &local->interfaces, list) {
-               if (!netif_running(sdata->dev))
+               if (!ieee80211_sdata_running(sdata))
                        continue;
                if (sdata->vif.type != NL80211_IFTYPE_STATION)
                        goto set;
index 9ebc8d8a1f5b20d3e6872610042128848ec0a4a8..f27484c22b9f40bf3876825b451e63670523ea39 100644 (file)
@@ -240,7 +240,7 @@ static int ieee80211_wep_decrypt(struct ieee80211_local *local,
 
        keyidx = skb->data[hdrlen + 3] >> 6;
 
-       if (!key || keyidx != key->conf.keyidx || key->conf.alg != ALG_WEP)
+       if (!key || keyidx != key->conf.keyidx)
                return -1;
 
        klen = 3 + key->conf.keylen;
index 81d4ad64184a2e76d35414586746fa6d03f8cf9d..ae344d1ba0560480665e1b939b15b058f5fddc4c 100644 (file)
@@ -43,7 +43,7 @@ enum work_action {
 /* utils */
 static inline void ASSERT_WORK_MTX(struct ieee80211_local *local)
 {
-       WARN_ON(!mutex_is_locked(&local->work_mtx));
+       lockdep_assert_held(&local->mtx);
 }
 
 /*
@@ -757,7 +757,7 @@ static void ieee80211_work_rx_queued_mgmt(struct ieee80211_local *local,
        mgmt = (struct ieee80211_mgmt *) skb->data;
        fc = le16_to_cpu(mgmt->frame_control);
 
-       mutex_lock(&local->work_mtx);
+       mutex_lock(&local->mtx);
 
        list_for_each_entry(wk, &local->work_list, list) {
                const u8 *bssid = NULL;
@@ -833,7 +833,7 @@ static void ieee80211_work_rx_queued_mgmt(struct ieee80211_local *local,
                WARN(1, "unexpected: %d", rma);
        }
 
-       mutex_unlock(&local->work_mtx);
+       mutex_unlock(&local->mtx);
 
        if (rma != WORK_ACT_DONE)
                goto out;
@@ -845,9 +845,9 @@ static void ieee80211_work_rx_queued_mgmt(struct ieee80211_local *local,
        case WORK_DONE_REQUEUE:
                synchronize_rcu();
                wk->started = false; /* restart */
-               mutex_lock(&local->work_mtx);
+               mutex_lock(&local->mtx);
                list_add_tail(&wk->list, &local->work_list);
-               mutex_unlock(&local->work_mtx);
+               mutex_unlock(&local->mtx);
        }
 
  out:
@@ -888,9 +888,9 @@ static void ieee80211_work_work(struct work_struct *work)
        while ((skb = skb_dequeue(&local->work_skb_queue)))
                ieee80211_work_rx_queued_mgmt(local, skb);
 
-       ieee80211_recalc_idle(local);
+       mutex_lock(&local->mtx);
 
-       mutex_lock(&local->work_mtx);
+       ieee80211_recalc_idle(local);
 
        list_for_each_entry_safe(wk, tmp, &local->work_list, list) {
                bool started = wk->started;
@@ -995,20 +995,16 @@ static void ieee80211_work_work(struct work_struct *work)
                run_again(local, jiffies + HZ/2);
        }
 
-       mutex_lock(&local->scan_mtx);
-
        if (list_empty(&local->work_list) && local->scan_req &&
            !local->scanning)
                ieee80211_queue_delayed_work(&local->hw,
                                             &local->scan_work,
                                             round_jiffies_relative(0));
 
-       mutex_unlock(&local->scan_mtx);
-
-       mutex_unlock(&local->work_mtx);
-
        ieee80211_recalc_idle(local);
 
+       mutex_unlock(&local->mtx);
+
        list_for_each_entry_safe(wk, tmp, &free_work, list) {
                wk->done(wk, NULL);
                list_del(&wk->list);
@@ -1035,16 +1031,15 @@ void ieee80211_add_work(struct ieee80211_work *wk)
        wk->started = false;
 
        local = wk->sdata->local;
-       mutex_lock(&local->work_mtx);
+       mutex_lock(&local->mtx);
        list_add_tail(&wk->list, &local->work_list);
-       mutex_unlock(&local->work_mtx);
+       mutex_unlock(&local->mtx);
 
        ieee80211_queue_work(&local->hw, &local->work_work);
 }
 
 void ieee80211_work_init(struct ieee80211_local *local)
 {
-       mutex_init(&local->work_mtx);
        INIT_LIST_HEAD(&local->work_list);
        setup_timer(&local->work_timer, ieee80211_work_timer,
                    (unsigned long)local);
@@ -1057,7 +1052,7 @@ void ieee80211_work_purge(struct ieee80211_sub_if_data *sdata)
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_work *wk;
 
-       mutex_lock(&local->work_mtx);
+       mutex_lock(&local->mtx);
        list_for_each_entry(wk, &local->work_list, list) {
                if (wk->sdata != sdata)
                        continue;
@@ -1065,19 +1060,19 @@ void ieee80211_work_purge(struct ieee80211_sub_if_data *sdata)
                wk->started = true;
                wk->timeout = jiffies;
        }
-       mutex_unlock(&local->work_mtx);
+       mutex_unlock(&local->mtx);
 
        /* run cleanups etc. */
        ieee80211_work_work(&local->work_work);
 
-       mutex_lock(&local->work_mtx);
+       mutex_lock(&local->mtx);
        list_for_each_entry(wk, &local->work_list, list) {
                if (wk->sdata != sdata)
                        continue;
                WARN_ON(1);
                break;
        }
-       mutex_unlock(&local->work_mtx);
+       mutex_unlock(&local->mtx);
 }
 
 ieee80211_rx_result ieee80211_work_rx_mgmt(struct ieee80211_sub_if_data *sdata,
@@ -1163,7 +1158,7 @@ int ieee80211_wk_cancel_remain_on_channel(struct ieee80211_sub_if_data *sdata,
        struct ieee80211_work *wk, *tmp;
        bool found = false;
 
-       mutex_lock(&local->work_mtx);
+       mutex_lock(&local->mtx);
        list_for_each_entry_safe(wk, tmp, &local->work_list, list) {
                if ((unsigned long) wk == cookie) {
                        wk->timeout = jiffies;
@@ -1171,7 +1166,7 @@ int ieee80211_wk_cancel_remain_on_channel(struct ieee80211_sub_if_data *sdata,
                        break;
                }
        }
-       mutex_unlock(&local->work_mtx);
+       mutex_unlock(&local->mtx);
 
        if (!found)
                return -ENOENT;
index 8d59d27d887e3a0b96d9d995e3138595f0a13c79..43882b36da5559feaf60751c92a9b48fbc1c90fa 100644 (file)
@@ -36,8 +36,8 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx)
        int tail;
 
        hdr = (struct ieee80211_hdr *)skb->data;
-       if (!tx->key || tx->key->conf.alg != ALG_TKIP || skb->len < 24 ||
-           !ieee80211_is_data_present(hdr->frame_control))
+       if (!tx->key || tx->key->conf.cipher != WLAN_CIPHER_SUITE_TKIP ||
+           skb->len < 24 || !ieee80211_is_data_present(hdr->frame_control))
                return TX_CONTINUE;
 
        hdrlen = ieee80211_hdrlen(hdr->frame_control);
@@ -94,7 +94,7 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx)
        if (status->flag & RX_FLAG_MMIC_STRIPPED)
                return RX_CONTINUE;
 
-       if (!rx->key || rx->key->conf.alg != ALG_TKIP ||
+       if (!rx->key || rx->key->conf.cipher != WLAN_CIPHER_SUITE_TKIP ||
            !ieee80211_has_protected(hdr->frame_control) ||
            !ieee80211_is_data_present(hdr->frame_control))
                return RX_CONTINUE;
@@ -221,19 +221,13 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx)
        if (!rx->sta || skb->len - hdrlen < 12)
                return RX_DROP_UNUSABLE;
 
-       if (status->flag & RX_FLAG_DECRYPTED) {
-               if (status->flag & RX_FLAG_IV_STRIPPED) {
-                       /*
-                        * Hardware took care of all processing, including
-                        * replay protection, and stripped the ICV/IV so
-                        * we cannot do any checks here.
-                        */
-                       return RX_CONTINUE;
-               }
-
-               /* let TKIP code verify IV, but skip decryption */
+       /*
+        * Let TKIP code verify IV, but skip decryption.
+        * In the case where hardware checks the IV as well,
+        * we don't even get here, see ieee80211_rx_h_decrypt()
+        */
+       if (status->flag & RX_FLAG_DECRYPTED)
                hwaccel = 1;
-       }
 
        res = ieee80211_tkip_decrypt_data(rx->local->wep_rx_tfm,
                                          key, skb->data + hdrlen,
@@ -447,10 +441,6 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx)
        if (!rx->sta || data_len < 0)
                return RX_DROP_UNUSABLE;
 
-       if ((status->flag & RX_FLAG_DECRYPTED) &&
-           (status->flag & RX_FLAG_IV_STRIPPED))
-               return RX_CONTINUE;
-
        ccmp_hdr2pn(pn, skb->data + hdrlen);
 
        queue = ieee80211_is_mgmt(hdr->frame_control) ?
@@ -564,10 +554,6 @@ ieee80211_crypto_aes_cmac_decrypt(struct ieee80211_rx_data *rx)
        if (!ieee80211_is_mgmt(hdr->frame_control))
                return RX_CONTINUE;
 
-       if ((status->flag & RX_FLAG_DECRYPTED) &&
-           (status->flag & RX_FLAG_IV_STRIPPED))
-               return RX_CONTINUE;
-
        if (skb->len < 24 + sizeof(*mmie))
                return RX_DROP_UNUSABLE;
 
index 4c2f89df5ccecc40f1dc9200772a4e8bb3e85b95..0c043b6ce65e1b3148b249d4560f2e0174798b65 100644 (file)
@@ -40,6 +40,7 @@
 #include <net/udp.h>
 #include <net/icmp.h>                   /* for icmp_send */
 #include <net/route.h>
+#include <net/ip6_checksum.h>
 
 #include <linux/netfilter.h>
 #include <linux/netfilter_ipv4.h>
@@ -637,10 +638,12 @@ void ip_vs_nat_icmp_v6(struct sk_buff *skb, struct ip_vs_protocol *pp,
        }
 
        /* And finally the ICMP checksum */
-       icmph->icmp6_cksum = 0;
-       /* TODO IPv6: is this correct for ICMPv6? */
-       ip_vs_checksum_complete(skb, icmp_offset);
-       skb->ip_summed = CHECKSUM_UNNECESSARY;
+       icmph->icmp6_cksum = ~csum_ipv6_magic(&iph->saddr, &iph->daddr,
+                                             skb->len - icmp_offset,
+                                             IPPROTO_ICMPV6, 0);
+       skb->csum_start = skb_network_header(skb) - skb->head + icmp_offset;
+       skb->csum_offset = offsetof(struct icmp6hdr, icmp6_cksum);
+       skb->ip_summed = CHECKSUM_PARTIAL;
 
        if (inout)
                IP_VS_DBG_PKT(11, pp, skb, (void *)ciph - (void *)iph,
@@ -1381,8 +1384,7 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb,
        if (af == AF_INET && (ip_vs_sync_state & IP_VS_STATE_MASTER) &&
            cp->protocol == IPPROTO_SCTP) {
                if ((cp->state == IP_VS_SCTP_S_ESTABLISHED &&
-                       (atomic_read(&cp->in_pkts) %
-                        sysctl_ip_vs_sync_threshold[1]
+                       (pkts % sysctl_ip_vs_sync_threshold[1]
                         == sysctl_ip_vs_sync_threshold[0])) ||
                                (cp->old_state != cp->state &&
                                 ((cp->state == IP_VS_SCTP_S_CLOSED) ||
@@ -1393,7 +1395,8 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb,
                }
        }
 
-       if (af == AF_INET &&
+       /* Keep this block last: TCP and others with pp->num_states <= 1 */
+       else if (af == AF_INET &&
            (ip_vs_sync_state & IP_VS_STATE_MASTER) &&
            (((cp->protocol != IPPROTO_TCP ||
               cp->state == IP_VS_TCP_S_ESTABLISHED) &&
index 0f0c079c422a03f87616a1c1df76c0e387245a9e..ca8ec8c4f3113678c51ae1961795bc936a590a64 100644 (file)
@@ -61,7 +61,7 @@ static DEFINE_RWLOCK(__ip_vs_svc_lock);
 static DEFINE_RWLOCK(__ip_vs_rs_lock);
 
 /* lock for state and timeout tables */
-static DEFINE_RWLOCK(__ip_vs_securetcp_lock);
+static DEFINE_SPINLOCK(ip_vs_securetcp_lock);
 
 /* lock for drop entry handling */
 static DEFINE_SPINLOCK(__ip_vs_dropentry_lock);
@@ -204,7 +204,7 @@ static void update_defense_level(void)
        spin_unlock(&__ip_vs_droppacket_lock);
 
        /* secure_tcp */
-       write_lock(&__ip_vs_securetcp_lock);
+       spin_lock(&ip_vs_securetcp_lock);
        switch (sysctl_ip_vs_secure_tcp) {
        case 0:
                if (old_secure_tcp >= 2)
@@ -238,7 +238,7 @@ static void update_defense_level(void)
        old_secure_tcp = sysctl_ip_vs_secure_tcp;
        if (to_change >= 0)
                ip_vs_protocol_timeout_change(sysctl_ip_vs_secure_tcp>1);
-       write_unlock(&__ip_vs_securetcp_lock);
+       spin_unlock(&ip_vs_securetcp_lock);
 
        local_bh_enable();
 }
@@ -843,7 +843,7 @@ ip_vs_new_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest,
                        return -EINVAL;
        }
 
-       dest = kzalloc(sizeof(struct ip_vs_dest), GFP_ATOMIC);
+       dest = kzalloc(sizeof(struct ip_vs_dest), GFP_KERNEL);
        if (dest == NULL) {
                pr_err("%s(): no memory.\n", __func__);
                return -ENOMEM;
@@ -1177,7 +1177,7 @@ ip_vs_add_service(struct ip_vs_service_user_kern *u,
        }
 #endif
 
-       svc = kzalloc(sizeof(struct ip_vs_service), GFP_ATOMIC);
+       svc = kzalloc(sizeof(struct ip_vs_service), GFP_KERNEL);
        if (svc == NULL) {
                IP_VS_DBG(1, "%s(): no memory\n", __func__);
                ret = -ENOMEM;
@@ -2155,7 +2155,7 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
        if (cmd != IP_VS_SO_SET_ADD
            && (svc == NULL || svc->protocol != usvc.protocol)) {
                ret = -ESRCH;
-               goto out_unlock;
+               goto out_drop_service;
        }
 
        switch (cmd) {
@@ -2189,6 +2189,7 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
                ret = -EINVAL;
        }
 
+out_drop_service:
        if (svc)
                ip_vs_service_put(svc);
 
index bbc1ac795952349b0dd9813bced3e329b6aaf6c2..727e45b669531338538b123649e696f0be20e775 100644 (file)
@@ -35,7 +35,7 @@
 static LIST_HEAD(ip_vs_schedulers);
 
 /* lock for service table */
-static DEFINE_RWLOCK(__ip_vs_sched_lock);
+static DEFINE_SPINLOCK(ip_vs_sched_lock);
 
 
 /*
@@ -108,7 +108,7 @@ static struct ip_vs_scheduler *ip_vs_sched_getbyname(const char *sched_name)
 
        IP_VS_DBG(2, "%s(): sched_name \"%s\"\n", __func__, sched_name);
 
-       read_lock_bh(&__ip_vs_sched_lock);
+       spin_lock_bh(&ip_vs_sched_lock);
 
        list_for_each_entry(sched, &ip_vs_schedulers, n_list) {
                /*
@@ -122,14 +122,14 @@ static struct ip_vs_scheduler *ip_vs_sched_getbyname(const char *sched_name)
                }
                if (strcmp(sched_name, sched->name)==0) {
                        /* HIT */
-                       read_unlock_bh(&__ip_vs_sched_lock);
+                       spin_unlock_bh(&ip_vs_sched_lock);
                        return sched;
                }
                if (sched->module)
                        module_put(sched->module);
        }
 
-       read_unlock_bh(&__ip_vs_sched_lock);
+       spin_unlock_bh(&ip_vs_sched_lock);
        return NULL;
 }
 
@@ -184,10 +184,10 @@ int register_ip_vs_scheduler(struct ip_vs_scheduler *scheduler)
        /* increase the module use count */
        ip_vs_use_count_inc();
 
-       write_lock_bh(&__ip_vs_sched_lock);
+       spin_lock_bh(&ip_vs_sched_lock);
 
        if (!list_empty(&scheduler->n_list)) {
-               write_unlock_bh(&__ip_vs_sched_lock);
+               spin_unlock_bh(&ip_vs_sched_lock);
                ip_vs_use_count_dec();
                pr_err("%s(): [%s] scheduler already linked\n",
                       __func__, scheduler->name);
@@ -200,7 +200,7 @@ int register_ip_vs_scheduler(struct ip_vs_scheduler *scheduler)
         */
        list_for_each_entry(sched, &ip_vs_schedulers, n_list) {
                if (strcmp(scheduler->name, sched->name) == 0) {
-                       write_unlock_bh(&__ip_vs_sched_lock);
+                       spin_unlock_bh(&ip_vs_sched_lock);
                        ip_vs_use_count_dec();
                        pr_err("%s(): [%s] scheduler already existed "
                               "in the system\n", __func__, scheduler->name);
@@ -211,7 +211,7 @@ int register_ip_vs_scheduler(struct ip_vs_scheduler *scheduler)
         *      Add it into the d-linked scheduler list
         */
        list_add(&scheduler->n_list, &ip_vs_schedulers);
-       write_unlock_bh(&__ip_vs_sched_lock);
+       spin_unlock_bh(&ip_vs_sched_lock);
 
        pr_info("[%s] scheduler registered.\n", scheduler->name);
 
@@ -229,9 +229,9 @@ int unregister_ip_vs_scheduler(struct ip_vs_scheduler *scheduler)
                return -EINVAL;
        }
 
-       write_lock_bh(&__ip_vs_sched_lock);
+       spin_lock_bh(&ip_vs_sched_lock);
        if (list_empty(&scheduler->n_list)) {
-               write_unlock_bh(&__ip_vs_sched_lock);
+               spin_unlock_bh(&ip_vs_sched_lock);
                pr_err("%s(): [%s] scheduler is not in the list. failed\n",
                       __func__, scheduler->name);
                return -EINVAL;
@@ -241,7 +241,7 @@ int unregister_ip_vs_scheduler(struct ip_vs_scheduler *scheduler)
         *      Remove it from the d-linked scheduler list
         */
        list_del(&scheduler->n_list);
-       write_unlock_bh(&__ip_vs_sched_lock);
+       spin_unlock_bh(&ip_vs_sched_lock);
 
        /* decrease the module use count */
        ip_vs_use_count_dec();
index b46a8390896d012dc4524e220a14d817d378dfd7..9228ee0dc11a307a49d131e7f879c738351dcef5 100644 (file)
@@ -448,6 +448,7 @@ hashlimit_init_dst(const struct xt_hashlimit_htable *hinfo,
 {
        __be16 _ports[2], *ports;
        u8 nexthdr;
+       int poff;
 
        memset(dst, 0, sizeof(*dst));
 
@@ -492,19 +493,13 @@ hashlimit_init_dst(const struct xt_hashlimit_htable *hinfo,
                return 0;
        }
 
-       switch (nexthdr) {
-       case IPPROTO_TCP:
-       case IPPROTO_UDP:
-       case IPPROTO_UDPLITE:
-       case IPPROTO_SCTP:
-       case IPPROTO_DCCP:
-               ports = skb_header_pointer(skb, protoff, sizeof(_ports),
+       poff = proto_ports_offset(nexthdr);
+       if (poff >= 0) {
+               ports = skb_header_pointer(skb, protoff + poff, sizeof(_ports),
                                           &_ports);
-               break;
-       default:
+       } else {
                _ports[0] = _ports[1] = 0;
                ports = _ports;
-               break;
        }
        if (!ports)
                return -1;
index 9a17f28b1253cc2c96fc57a1b94cac4fa1621238..3616f27b9d46c08e0f750b47865cc17c3130c5f2 100644 (file)
@@ -488,7 +488,7 @@ retry:
        skb->dev = dev;
        skb->priority = sk->sk_priority;
        skb->mark = sk->sk_mark;
-       err = sock_tx_timestamp(msg, sk, skb_tx(skb));
+       err = sock_tx_timestamp(sk, &skb_shinfo(skb)->tx_flags);
        if (err < 0)
                goto out_unlock;
 
@@ -1209,7 +1209,7 @@ static int packet_snd(struct socket *sock,
        err = skb_copy_datagram_from_iovec(skb, offset, msg->msg_iov, 0, len);
        if (err)
                goto out_free;
-       err = sock_tx_timestamp(msg, sk, skb_tx(skb));
+       err = sock_tx_timestamp(sk, &skb_shinfo(skb)->tx_flags);
        if (err < 0)
                goto out_free;
 
index b2a3ae6cad78e28324e23b857dc0a5773f569786..04e34196c9defa6fe66c3581beb47b1cde185b6a 100644 (file)
@@ -834,6 +834,7 @@ static int pipe_skb_send(struct sock *sk, struct sk_buff *skb)
 {
        struct pep_sock *pn = pep_sk(sk);
        struct pnpipehdr *ph;
+       int err;
 
        if (pn_flow_safe(pn->tx_fc) &&
            !atomic_add_unless(&pn->tx_credits, -1, 0)) {
@@ -852,7 +853,10 @@ static int pipe_skb_send(struct sock *sk, struct sk_buff *skb)
                ph->message_id = PNS_PIPE_DATA;
        ph->pipe_handle = pn->pipe_handle;
 
-       return pn_skb_send(sk, skb, &pipe_srv);
+       err = pn_skb_send(sk, skb, &pipe_srv);
+       if (err && pn_flow_safe(pn->tx_fc))
+               atomic_inc(&pn->tx_credits);
+       return err;
 }
 
 static int pep_sendmsg(struct kiocb *iocb, struct sock *sk,
@@ -872,7 +876,7 @@ static int pep_sendmsg(struct kiocb *iocb, struct sock *sk,
        skb = sock_alloc_send_skb(sk, MAX_PNPIPE_HEADER + len,
                                        flags & MSG_DONTWAIT, &err);
        if (!skb)
-               return -ENOBUFS;
+               return err;
 
        skb_reserve(skb, MAX_PHONET_HEADER + 3);
        err = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len);
index b18e48fae9759cf20d735031bc1f18a7e8857a11..d0a429459370ad822dc90f0d00e9888ca87ee7ea 100644 (file)
@@ -292,8 +292,7 @@ static void phonet_route_autodel(struct net_device *dev)
        if (bitmap_empty(deleted, 64))
                return; /* short-circuit RCU */
        synchronize_rcu();
-       for (i = find_first_bit(deleted, 64); i < 64;
-                       i = find_next_bit(deleted, 64, i + 1)) {
+       for_each_set_bit(i, deleted, 64) {
                rtm_phonet_notify(RTM_DELROUTE, dev, i);
                dev_put(dev);
        }
index 6e9848bf0370dff4a78827839a9a1057e52fb2b0..7c91f739f13848e63e45a174c35c881301a40a03 100644 (file)
@@ -281,7 +281,9 @@ static unsigned int pn_socket_poll(struct file *file, struct socket *sock,
        if (!mask && sk->sk_state == TCP_CLOSE_WAIT)
                return POLLHUP;
 
-       if (sk->sk_state == TCP_ESTABLISHED && atomic_read(&pn->tx_credits))
+       if (sk->sk_state == TCP_ESTABLISHED &&
+               atomic_read(&sk->sk_wmem_alloc) < sk->sk_sndbuf &&
+               atomic_read(&pn->tx_credits))
                mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
 
        return mask;
index aebfecbdb8417cfa3bd3196e2c22f18433a7b08b..bb6ad81b671d055b89fbe74287ed328a834aac03 100644 (file)
 #include <net/sock.h>
 
 #include "rds.h"
-#include "rdma.h"
+
+char *rds_str_array(char **array, size_t elements, size_t index)
+{
+       if ((index < elements) && array[index])
+               return array[index];
+       else
+               return "unknown";
+}
+EXPORT_SYMBOL(rds_str_array);
 
 /* this is just used for stats gathering :/ */
 static DEFINE_SPINLOCK(rds_sock_lock);
@@ -62,7 +70,7 @@ static int rds_release(struct socket *sock)
        struct rds_sock *rs;
        unsigned long flags;
 
-       if (sk == NULL)
+       if (!sk)
                goto out;
 
        rs = rds_sk_to_rs(sk);
@@ -73,7 +81,15 @@ static int rds_release(struct socket *sock)
         * with the socket. */
        rds_clear_recv_queue(rs);
        rds_cong_remove_socket(rs);
+
+       /*
+        * the binding lookup hash uses rcu, we need to
+        * make sure we sychronize_rcu before we free our
+        * entry
+        */
        rds_remove_bound(rs);
+       synchronize_rcu();
+
        rds_send_drop_to(rs, NULL);
        rds_rdma_drop_keys(rs);
        rds_notify_queue_get(rs, NULL);
@@ -83,6 +99,8 @@ static int rds_release(struct socket *sock)
        rds_sock_count--;
        spin_unlock_irqrestore(&rds_sock_lock, flags);
 
+       rds_trans_put(rs->rs_transport);
+
        sock->sk = NULL;
        sock_put(sk);
 out:
@@ -514,7 +532,7 @@ out:
        spin_unlock_irqrestore(&rds_sock_lock, flags);
 }
 
-static void __exit rds_exit(void)
+static void rds_exit(void)
 {
        sock_unregister(rds_family_ops.family);
        proto_unregister(&rds_proto);
@@ -529,7 +547,7 @@ static void __exit rds_exit(void)
 }
 module_exit(rds_exit);
 
-static int __init rds_init(void)
+static int rds_init(void)
 {
        int ret;
 
index 5d95fc007f1aa6244d500561ccc0324063cda221..2f6b3fcc79f81b9985ca5774a7fa3e070a105d11 100644 (file)
 #include <net/sock.h>
 #include <linux/in.h>
 #include <linux/if_arp.h>
+#include <linux/jhash.h>
 #include "rds.h"
 
-/*
- * XXX this probably still needs more work.. no INADDR_ANY, and rbtrees aren't
- * particularly zippy.
- *
- * This is now called for every incoming frame so we arguably care much more
- * about it than we used to.
- */
+#define BIND_HASH_SIZE 1024
+static struct hlist_head bind_hash_table[BIND_HASH_SIZE];
 static DEFINE_SPINLOCK(rds_bind_lock);
-static struct rb_root rds_bind_tree = RB_ROOT;
 
-static struct rds_sock *rds_bind_tree_walk(__be32 addr, __be16 port,
-                                          struct rds_sock *insert)
+static struct hlist_head *hash_to_bucket(__be32 addr, __be16 port)
+{
+       return bind_hash_table + (jhash_2words((u32)addr, (u32)port, 0) &
+                                 (BIND_HASH_SIZE - 1));
+}
+
+static struct rds_sock *rds_bind_lookup(__be32 addr, __be16 port,
+                                       struct rds_sock *insert)
 {
-       struct rb_node **p = &rds_bind_tree.rb_node;
-       struct rb_node *parent = NULL;
        struct rds_sock *rs;
+       struct hlist_node *node;
+       struct hlist_head *head = hash_to_bucket(addr, port);
        u64 cmp;
        u64 needle = ((u64)be32_to_cpu(addr) << 32) | be16_to_cpu(port);
 
-       while (*p) {
-               parent = *p;
-               rs = rb_entry(parent, struct rds_sock, rs_bound_node);
-
+       rcu_read_lock();
+       hlist_for_each_entry_rcu(rs, node, head, rs_bound_node) {
                cmp = ((u64)be32_to_cpu(rs->rs_bound_addr) << 32) |
                      be16_to_cpu(rs->rs_bound_port);
 
-               if (needle < cmp)
-                       p = &(*p)->rb_left;
-               else if (needle > cmp)
-                       p = &(*p)->rb_right;
-               else
+               if (cmp == needle) {
+                       rcu_read_unlock();
                        return rs;
+               }
        }
+       rcu_read_unlock();
 
        if (insert) {
-               rb_link_node(&insert->rs_bound_node, parent, p);
-               rb_insert_color(&insert->rs_bound_node, &rds_bind_tree);
+               /*
+                * make sure our addr and port are set before
+                * we are added to the list, other people
+                * in rcu will find us as soon as the
+                * hlist_add_head_rcu is done
+                */
+               insert->rs_bound_addr = addr;
+               insert->rs_bound_port = port;
+               rds_sock_addref(insert);
+
+               hlist_add_head_rcu(&insert->rs_bound_node, head);
        }
        return NULL;
 }
@@ -86,15 +93,13 @@ static struct rds_sock *rds_bind_tree_walk(__be32 addr, __be16 port,
 struct rds_sock *rds_find_bound(__be32 addr, __be16 port)
 {
        struct rds_sock *rs;
-       unsigned long flags;
 
-       spin_lock_irqsave(&rds_bind_lock, flags);
-       rs = rds_bind_tree_walk(addr, port, NULL);
+       rs = rds_bind_lookup(addr, port, NULL);
+
        if (rs && !sock_flag(rds_rs_to_sk(rs), SOCK_DEAD))
                rds_sock_addref(rs);
        else
                rs = NULL;
-       spin_unlock_irqrestore(&rds_bind_lock, flags);
 
        rdsdebug("returning rs %p for %pI4:%u\n", rs, &addr,
                ntohs(port));
@@ -121,22 +126,15 @@ static int rds_add_bound(struct rds_sock *rs, __be32 addr, __be16 *port)
        do {
                if (rover == 0)
                        rover++;
-               if (rds_bind_tree_walk(addr, cpu_to_be16(rover), rs) == NULL) {
-                       *port = cpu_to_be16(rover);
+               if (!rds_bind_lookup(addr, cpu_to_be16(rover), rs)) {
+                       *port = rs->rs_bound_port;
                        ret = 0;
+                       rdsdebug("rs %p binding to %pI4:%d\n",
+                         rs, &addr, (int)ntohs(*port));
                        break;
                }
        } while (rover++ != last);
 
-       if (ret == 0)  {
-               rs->rs_bound_addr = addr;
-               rs->rs_bound_port = *port;
-               rds_sock_addref(rs);
-
-               rdsdebug("rs %p binding to %pI4:%d\n",
-                 rs, &addr, (int)ntohs(*port));
-       }
-
        spin_unlock_irqrestore(&rds_bind_lock, flags);
 
        return ret;
@@ -153,7 +151,7 @@ void rds_remove_bound(struct rds_sock *rs)
                  rs, &rs->rs_bound_addr,
                  ntohs(rs->rs_bound_port));
 
-               rb_erase(&rs->rs_bound_node, &rds_bind_tree);
+               hlist_del_init_rcu(&rs->rs_bound_node);
                rds_sock_put(rs);
                rs->rs_bound_addr = 0;
        }
@@ -184,7 +182,7 @@ int rds_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
                goto out;
 
        trans = rds_trans_get_preferred(sin->sin_addr.s_addr);
-       if (trans == NULL) {
+       if (!trans) {
                ret = -EADDRNOTAVAIL;
                rds_remove_bound(rs);
                if (printk_ratelimit())
@@ -198,5 +196,9 @@ int rds_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
 
 out:
        release_sock(sk);
+
+       /* we might have called rds_remove_bound on error */
+       if (ret)
+               synchronize_rcu();
        return ret;
 }
index 0871a29f078000ee79370fd20e6d94ca46ba3efd..75ea686f27d5aeedfd220dfbfa514295d6cc8ecc 100644 (file)
@@ -141,7 +141,7 @@ static struct rds_cong_map *rds_cong_from_addr(__be32 addr)
        unsigned long flags;
 
        map = kzalloc(sizeof(struct rds_cong_map), GFP_KERNEL);
-       if (map == NULL)
+       if (!map)
                return NULL;
 
        map->m_addr = addr;
@@ -159,7 +159,7 @@ static struct rds_cong_map *rds_cong_from_addr(__be32 addr)
        ret = rds_cong_tree_walk(addr, map);
        spin_unlock_irqrestore(&rds_cong_lock, flags);
 
-       if (ret == NULL) {
+       if (!ret) {
                ret = map;
                map = NULL;
        }
@@ -205,7 +205,7 @@ int rds_cong_get_maps(struct rds_connection *conn)
        conn->c_lcong = rds_cong_from_addr(conn->c_laddr);
        conn->c_fcong = rds_cong_from_addr(conn->c_faddr);
 
-       if (conn->c_lcong == NULL || conn->c_fcong == NULL)
+       if (!(conn->c_lcong && conn->c_fcong))
                return -ENOMEM;
 
        return 0;
@@ -221,7 +221,7 @@ void rds_cong_queue_updates(struct rds_cong_map *map)
        list_for_each_entry(conn, &map->m_conn_list, c_map_item) {
                if (!test_and_set_bit(0, &conn->c_map_queued)) {
                        rds_stats_inc(s_cong_update_queued);
-                       queue_delayed_work(rds_wq, &conn->c_send_w, 0);
+                       rds_send_xmit(conn);
                }
        }
 
index 7619b671ca2829f0e197a93f6abd06df2f108229..870992e08cae2e86681d569b3ac27d83b6dffb89 100644 (file)
@@ -37,7 +37,6 @@
 
 #include "rds.h"
 #include "loop.h"
-#include "rdma.h"
 
 #define RDS_CONNECTION_HASH_BITS 12
 #define RDS_CONNECTION_HASH_ENTRIES (1 << RDS_CONNECTION_HASH_BITS)
@@ -63,18 +62,7 @@ static struct hlist_head *rds_conn_bucket(__be32 laddr, __be32 faddr)
                var |= RDS_INFO_CONNECTION_FLAG_##suffix;       \
 } while (0)
 
-static inline int rds_conn_is_sending(struct rds_connection *conn)
-{
-       int ret = 0;
-
-       if (!mutex_trylock(&conn->c_send_lock))
-               ret = 1;
-       else
-               mutex_unlock(&conn->c_send_lock);
-
-       return ret;
-}
-
+/* rcu read lock must be held or the connection spinlock */
 static struct rds_connection *rds_conn_lookup(struct hlist_head *head,
                                              __be32 laddr, __be32 faddr,
                                              struct rds_transport *trans)
@@ -82,7 +70,7 @@ static struct rds_connection *rds_conn_lookup(struct hlist_head *head,
        struct rds_connection *conn, *ret = NULL;
        struct hlist_node *pos;
 
-       hlist_for_each_entry(conn, pos, head, c_hash_node) {
+       hlist_for_each_entry_rcu(conn, pos, head, c_hash_node) {
                if (conn->c_faddr == faddr && conn->c_laddr == laddr &&
                                conn->c_trans == trans) {
                        ret = conn;
@@ -129,10 +117,11 @@ static struct rds_connection *__rds_conn_create(__be32 laddr, __be32 faddr,
 {
        struct rds_connection *conn, *parent = NULL;
        struct hlist_head *head = rds_conn_bucket(laddr, faddr);
+       struct rds_transport *loop_trans;
        unsigned long flags;
        int ret;
 
-       spin_lock_irqsave(&rds_conn_lock, flags);
+       rcu_read_lock();
        conn = rds_conn_lookup(head, laddr, faddr, trans);
        if (conn && conn->c_loopback && conn->c_trans != &rds_loop_transport &&
            !is_outgoing) {
@@ -143,12 +132,12 @@ static struct rds_connection *__rds_conn_create(__be32 laddr, __be32 faddr,
                parent = conn;
                conn = parent->c_passive;
        }
-       spin_unlock_irqrestore(&rds_conn_lock, flags);
+       rcu_read_unlock();
        if (conn)
                goto out;
 
        conn = kmem_cache_zalloc(rds_conn_slab, gfp);
-       if (conn == NULL) {
+       if (!conn) {
                conn = ERR_PTR(-ENOMEM);
                goto out;
        }
@@ -159,7 +148,7 @@ static struct rds_connection *__rds_conn_create(__be32 laddr, __be32 faddr,
        spin_lock_init(&conn->c_lock);
        conn->c_next_tx_seq = 1;
 
-       mutex_init(&conn->c_send_lock);
+       init_waitqueue_head(&conn->c_waitq);
        INIT_LIST_HEAD(&conn->c_send_queue);
        INIT_LIST_HEAD(&conn->c_retrans);
 
@@ -175,7 +164,9 @@ static struct rds_connection *__rds_conn_create(__be32 laddr, __be32 faddr,
         * can bind to the destination address then we'd rather the messages
         * flow through loopback rather than either transport.
         */
-       if (rds_trans_get_preferred(faddr)) {
+       loop_trans = rds_trans_get_preferred(faddr);
+       if (loop_trans) {
+               rds_trans_put(loop_trans);
                conn->c_loopback = 1;
                if (is_outgoing && trans->t_prefer_loopback) {
                        /* "outgoing" connection - and the transport
@@ -238,7 +229,7 @@ static struct rds_connection *__rds_conn_create(__be32 laddr, __be32 faddr,
                        kmem_cache_free(rds_conn_slab, conn);
                        conn = found;
                } else {
-                       hlist_add_head(&conn->c_hash_node, head);
+                       hlist_add_head_rcu(&conn->c_hash_node, head);
                        rds_cong_add_conn(conn);
                        rds_conn_count++;
                }
@@ -263,21 +254,91 @@ struct rds_connection *rds_conn_create_outgoing(__be32 laddr, __be32 faddr,
 }
 EXPORT_SYMBOL_GPL(rds_conn_create_outgoing);
 
+void rds_conn_shutdown(struct rds_connection *conn)
+{
+       /* shut it down unless it's down already */
+       if (!rds_conn_transition(conn, RDS_CONN_DOWN, RDS_CONN_DOWN)) {
+               /*
+                * Quiesce the connection mgmt handlers before we start tearing
+                * things down. We don't hold the mutex for the entire
+                * duration of the shutdown operation, else we may be
+                * deadlocking with the CM handler. Instead, the CM event
+                * handler is supposed to check for state DISCONNECTING
+                */
+               mutex_lock(&conn->c_cm_lock);
+               if (!rds_conn_transition(conn, RDS_CONN_UP, RDS_CONN_DISCONNECTING)
+                && !rds_conn_transition(conn, RDS_CONN_ERROR, RDS_CONN_DISCONNECTING)) {
+                       rds_conn_error(conn, "shutdown called in state %d\n",
+                                       atomic_read(&conn->c_state));
+                       mutex_unlock(&conn->c_cm_lock);
+                       return;
+               }
+               mutex_unlock(&conn->c_cm_lock);
+
+               wait_event(conn->c_waitq,
+                          !test_bit(RDS_IN_XMIT, &conn->c_flags));
+
+               conn->c_trans->conn_shutdown(conn);
+               rds_conn_reset(conn);
+
+               if (!rds_conn_transition(conn, RDS_CONN_DISCONNECTING, RDS_CONN_DOWN)) {
+                       /* This can happen - eg when we're in the middle of tearing
+                        * down the connection, and someone unloads the rds module.
+                        * Quite reproduceable with loopback connections.
+                        * Mostly harmless.
+                        */
+                       rds_conn_error(conn,
+                               "%s: failed to transition to state DOWN, "
+                               "current state is %d\n",
+                               __func__,
+                               atomic_read(&conn->c_state));
+                       return;
+               }
+       }
+
+       /* Then reconnect if it's still live.
+        * The passive side of an IB loopback connection is never added
+        * to the conn hash, so we never trigger a reconnect on this
+        * conn - the reconnect is always triggered by the active peer. */
+       cancel_delayed_work_sync(&conn->c_conn_w);
+       rcu_read_lock();
+       if (!hlist_unhashed(&conn->c_hash_node)) {
+               rcu_read_unlock();
+               rds_queue_reconnect(conn);
+       } else {
+               rcu_read_unlock();
+       }
+}
+
+/*
+ * Stop and free a connection.
+ *
+ * This can only be used in very limited circumstances.  It assumes that once
+ * the conn has been shutdown that no one else is referencing the connection.
+ * We can only ensure this in the rmmod path in the current code.
+ */
 void rds_conn_destroy(struct rds_connection *conn)
 {
        struct rds_message *rm, *rtmp;
+       unsigned long flags;
 
        rdsdebug("freeing conn %p for %pI4 -> "
                 "%pI4\n", conn, &conn->c_laddr,
                 &conn->c_faddr);
 
-       hlist_del_init(&conn->c_hash_node);
+       /* Ensure conn will not be scheduled for reconnect */
+       spin_lock_irq(&rds_conn_lock);
+       hlist_del_init_rcu(&conn->c_hash_node);
+       spin_unlock_irq(&rds_conn_lock);
+       synchronize_rcu();
 
-       /* wait for the rds thread to shut it down */
-       atomic_set(&conn->c_state, RDS_CONN_ERROR);
-       cancel_delayed_work(&conn->c_conn_w);
-       queue_work(rds_wq, &conn->c_down_w);
-       flush_workqueue(rds_wq);
+       /* shut the connection down */
+       rds_conn_drop(conn);
+       flush_work(&conn->c_down_w);
+
+       /* make sure lingering queued work won't try to ref the conn */
+       cancel_delayed_work_sync(&conn->c_send_w);
+       cancel_delayed_work_sync(&conn->c_recv_w);
 
        /* tear down queued messages */
        list_for_each_entry_safe(rm, rtmp,
@@ -302,7 +363,9 @@ void rds_conn_destroy(struct rds_connection *conn)
        BUG_ON(!list_empty(&conn->c_retrans));
        kmem_cache_free(rds_conn_slab, conn);
 
+       spin_lock_irqsave(&rds_conn_lock, flags);
        rds_conn_count--;
+       spin_unlock_irqrestore(&rds_conn_lock, flags);
 }
 EXPORT_SYMBOL_GPL(rds_conn_destroy);
 
@@ -316,23 +379,23 @@ static void rds_conn_message_info(struct socket *sock, unsigned int len,
        struct list_head *list;
        struct rds_connection *conn;
        struct rds_message *rm;
-       unsigned long flags;
        unsigned int total = 0;
+       unsigned long flags;
        size_t i;
 
        len /= sizeof(struct rds_info_message);
 
-       spin_lock_irqsave(&rds_conn_lock, flags);
+       rcu_read_lock();
 
        for (i = 0, head = rds_conn_hash; i < ARRAY_SIZE(rds_conn_hash);
             i++, head++) {
-               hlist_for_each_entry(conn, pos, head, c_hash_node) {
+               hlist_for_each_entry_rcu(conn, pos, head, c_hash_node) {
                        if (want_send)
                                list = &conn->c_send_queue;
                        else
                                list = &conn->c_retrans;
 
-                       spin_lock(&conn->c_lock);
+                       spin_lock_irqsave(&conn->c_lock, flags);
 
                        /* XXX too lazy to maintain counts.. */
                        list_for_each_entry(rm, list, m_conn_item) {
@@ -343,11 +406,10 @@ static void rds_conn_message_info(struct socket *sock, unsigned int len,
                                                          conn->c_faddr, 0);
                        }
 
-                       spin_unlock(&conn->c_lock);
+                       spin_unlock_irqrestore(&conn->c_lock, flags);
                }
        }
-
-       spin_unlock_irqrestore(&rds_conn_lock, flags);
+       rcu_read_unlock();
 
        lens->nr = total;
        lens->each = sizeof(struct rds_info_message);
@@ -377,19 +439,17 @@ void rds_for_each_conn_info(struct socket *sock, unsigned int len,
        uint64_t buffer[(item_len + 7) / 8];
        struct hlist_head *head;
        struct hlist_node *pos;
-       struct hlist_node *tmp;
        struct rds_connection *conn;
-       unsigned long flags;
        size_t i;
 
-       spin_lock_irqsave(&rds_conn_lock, flags);
+       rcu_read_lock();
 
        lens->nr = 0;
        lens->each = item_len;
 
        for (i = 0, head = rds_conn_hash; i < ARRAY_SIZE(rds_conn_hash);
             i++, head++) {
-               hlist_for_each_entry_safe(conn, pos, tmp, head, c_hash_node) {
+               hlist_for_each_entry_rcu(conn, pos, head, c_hash_node) {
 
                        /* XXX no c_lock usage.. */
                        if (!visitor(conn, buffer))
@@ -405,8 +465,7 @@ void rds_for_each_conn_info(struct socket *sock, unsigned int len,
                        lens->nr++;
                }
        }
-
-       spin_unlock_irqrestore(&rds_conn_lock, flags);
+       rcu_read_unlock();
 }
 EXPORT_SYMBOL_GPL(rds_for_each_conn_info);
 
@@ -423,8 +482,8 @@ static int rds_conn_info_visitor(struct rds_connection *conn,
                sizeof(cinfo->transport));
        cinfo->flags = 0;
 
-       rds_conn_info_set(cinfo->flags,
-                         rds_conn_is_sending(conn), SENDING);
+       rds_conn_info_set(cinfo->flags, test_bit(RDS_IN_XMIT, &conn->c_flags),
+                         SENDING);
        /* XXX Future: return the state rather than these funky bits */
        rds_conn_info_set(cinfo->flags,
                          atomic_read(&conn->c_state) == RDS_CONN_CONNECTING,
@@ -444,12 +503,12 @@ static void rds_conn_info(struct socket *sock, unsigned int len,
                                sizeof(struct rds_info_connection));
 }
 
-int __init rds_conn_init(void)
+int rds_conn_init(void)
 {
        rds_conn_slab = kmem_cache_create("rds_connection",
                                          sizeof(struct rds_connection),
                                          0, 0, NULL);
-       if (rds_conn_slab == NULL)
+       if (!rds_conn_slab)
                return -ENOMEM;
 
        rds_info_register_func(RDS_INFO_CONNECTIONS, rds_conn_info);
@@ -486,6 +545,18 @@ void rds_conn_drop(struct rds_connection *conn)
 }
 EXPORT_SYMBOL_GPL(rds_conn_drop);
 
+/*
+ * If the connection is down, trigger a connect. We may have scheduled a
+ * delayed reconnect however - in this case we should not interfere.
+ */
+void rds_conn_connect_if_down(struct rds_connection *conn)
+{
+       if (rds_conn_state(conn) == RDS_CONN_DOWN &&
+           !test_and_set_bit(RDS_RECONNECT_PENDING, &conn->c_flags))
+               queue_delayed_work(rds_wq, &conn->c_conn_w, 0);
+}
+EXPORT_SYMBOL_GPL(rds_conn_connect_if_down);
+
 /*
  * An error occurred on the connection
  */
index 8f2d6dd7700a8a0e20192b521c30dc7bc2df553b..b12a3951167dc2f264c465ee4923a98ef98510be 100644 (file)
@@ -53,12 +53,71 @@ MODULE_PARM_DESC(fmr_message_size, " Max size of a RDMA transfer");
 module_param(rds_ib_retry_count, int, 0444);
 MODULE_PARM_DESC(rds_ib_retry_count, " Number of hw retries before reporting an error");
 
+/*
+ * we have a clumsy combination of RCU and a rwsem protecting this list
+ * because it is used both in the get_mr fast path and while blocking in
+ * the FMR flushing path.
+ */
+DECLARE_RWSEM(rds_ib_devices_lock);
 struct list_head rds_ib_devices;
 
 /* NOTE: if also grabbing ibdev lock, grab this first */
 DEFINE_SPINLOCK(ib_nodev_conns_lock);
 LIST_HEAD(ib_nodev_conns);
 
+void rds_ib_nodev_connect(void)
+{
+       struct rds_ib_connection *ic;
+
+       spin_lock(&ib_nodev_conns_lock);
+       list_for_each_entry(ic, &ib_nodev_conns, ib_node)
+               rds_conn_connect_if_down(ic->conn);
+       spin_unlock(&ib_nodev_conns_lock);
+}
+
+void rds_ib_dev_shutdown(struct rds_ib_device *rds_ibdev)
+{
+       struct rds_ib_connection *ic;
+       unsigned long flags;
+
+       spin_lock_irqsave(&rds_ibdev->spinlock, flags);
+       list_for_each_entry(ic, &rds_ibdev->conn_list, ib_node)
+               rds_conn_drop(ic->conn);
+       spin_unlock_irqrestore(&rds_ibdev->spinlock, flags);
+}
+
+/*
+ * rds_ib_destroy_mr_pool() blocks on a few things and mrs drop references
+ * from interrupt context so we push freing off into a work struct in krdsd.
+ */
+static void rds_ib_dev_free(struct work_struct *work)
+{
+       struct rds_ib_ipaddr *i_ipaddr, *i_next;
+       struct rds_ib_device *rds_ibdev = container_of(work,
+                                       struct rds_ib_device, free_work);
+
+       if (rds_ibdev->mr_pool)
+               rds_ib_destroy_mr_pool(rds_ibdev->mr_pool);
+       if (rds_ibdev->mr)
+               ib_dereg_mr(rds_ibdev->mr);
+       if (rds_ibdev->pd)
+               ib_dealloc_pd(rds_ibdev->pd);
+
+       list_for_each_entry_safe(i_ipaddr, i_next, &rds_ibdev->ipaddr_list, list) {
+               list_del(&i_ipaddr->list);
+               kfree(i_ipaddr);
+       }
+
+       kfree(rds_ibdev);
+}
+
+void rds_ib_dev_put(struct rds_ib_device *rds_ibdev)
+{
+       BUG_ON(atomic_read(&rds_ibdev->refcount) <= 0);
+       if (atomic_dec_and_test(&rds_ibdev->refcount))
+               queue_work(rds_wq, &rds_ibdev->free_work);
+}
+
 void rds_ib_add_one(struct ib_device *device)
 {
        struct rds_ib_device *rds_ibdev;
@@ -77,11 +136,14 @@ void rds_ib_add_one(struct ib_device *device)
                goto free_attr;
        }
 
-       rds_ibdev = kmalloc(sizeof *rds_ibdev, GFP_KERNEL);
+       rds_ibdev = kzalloc_node(sizeof(struct rds_ib_device), GFP_KERNEL,
+                                ibdev_to_node(device));
        if (!rds_ibdev)
                goto free_attr;
 
        spin_lock_init(&rds_ibdev->spinlock);
+       atomic_set(&rds_ibdev->refcount, 1);
+       INIT_WORK(&rds_ibdev->free_work, rds_ib_dev_free);
 
        rds_ibdev->max_wrs = dev_attr->max_qp_wr;
        rds_ibdev->max_sge = min(dev_attr->max_sge, RDS_IB_MAX_SGE);
@@ -91,68 +153,107 @@ void rds_ib_add_one(struct ib_device *device)
                        min_t(unsigned int, dev_attr->max_fmr, fmr_pool_size) :
                        fmr_pool_size;
 
+       rds_ibdev->max_initiator_depth = dev_attr->max_qp_init_rd_atom;
+       rds_ibdev->max_responder_resources = dev_attr->max_qp_rd_atom;
+
        rds_ibdev->dev = device;
        rds_ibdev->pd = ib_alloc_pd(device);
-       if (IS_ERR(rds_ibdev->pd))
-               goto free_dev;
+       if (IS_ERR(rds_ibdev->pd)) {
+               rds_ibdev->pd = NULL;
+               goto put_dev;
+       }
 
-       rds_ibdev->mr = ib_get_dma_mr(rds_ibdev->pd,
-                                     IB_ACCESS_LOCAL_WRITE);
-       if (IS_ERR(rds_ibdev->mr))
-               goto err_pd;
+       rds_ibdev->mr = ib_get_dma_mr(rds_ibdev->pd, IB_ACCESS_LOCAL_WRITE);
+       if (IS_ERR(rds_ibdev->mr)) {
+               rds_ibdev->mr = NULL;
+               goto put_dev;
+       }
 
        rds_ibdev->mr_pool = rds_ib_create_mr_pool(rds_ibdev);
        if (IS_ERR(rds_ibdev->mr_pool)) {
                rds_ibdev->mr_pool = NULL;
-               goto err_mr;
+               goto put_dev;
        }
 
        INIT_LIST_HEAD(&rds_ibdev->ipaddr_list);
        INIT_LIST_HEAD(&rds_ibdev->conn_list);
-       list_add_tail(&rds_ibdev->list, &rds_ib_devices);
+
+       down_write(&rds_ib_devices_lock);
+       list_add_tail_rcu(&rds_ibdev->list, &rds_ib_devices);
+       up_write(&rds_ib_devices_lock);
+       atomic_inc(&rds_ibdev->refcount);
 
        ib_set_client_data(device, &rds_ib_client, rds_ibdev);
+       atomic_inc(&rds_ibdev->refcount);
 
-       goto free_attr;
+       rds_ib_nodev_connect();
 
-err_mr:
-       ib_dereg_mr(rds_ibdev->mr);
-err_pd:
-       ib_dealloc_pd(rds_ibdev->pd);
-free_dev:
-       kfree(rds_ibdev);
+put_dev:
+       rds_ib_dev_put(rds_ibdev);
 free_attr:
        kfree(dev_attr);
 }
 
+/*
+ * New connections use this to find the device to associate with the
+ * connection.  It's not in the fast path so we're not concerned about the
+ * performance of the IB call.  (As of this writing, it uses an interrupt
+ * blocking spinlock to serialize walking a per-device list of all registered
+ * clients.)
+ *
+ * RCU is used to handle incoming connections racing with device teardown.
+ * Rather than use a lock to serialize removal from the client_data and
+ * getting a new reference, we use an RCU grace period.  The destruction
+ * path removes the device from client_data and then waits for all RCU
+ * readers to finish.
+ *
+ * A new connection can get NULL from this if its arriving on a
+ * device that is in the process of being removed.
+ */
+struct rds_ib_device *rds_ib_get_client_data(struct ib_device *device)
+{
+       struct rds_ib_device *rds_ibdev;
+
+       rcu_read_lock();
+       rds_ibdev = ib_get_client_data(device, &rds_ib_client);
+       if (rds_ibdev)
+               atomic_inc(&rds_ibdev->refcount);
+       rcu_read_unlock();
+       return rds_ibdev;
+}
+
+/*
+ * The IB stack is letting us know that a device is going away.  This can
+ * happen if the underlying HCA driver is removed or if PCI hotplug is removing
+ * the pci function, for example.
+ *
+ * This can be called at any time and can be racing with any other RDS path.
+ */
 void rds_ib_remove_one(struct ib_device *device)
 {
        struct rds_ib_device *rds_ibdev;
-       struct rds_ib_ipaddr *i_ipaddr, *i_next;
 
        rds_ibdev = ib_get_client_data(device, &rds_ib_client);
        if (!rds_ibdev)
                return;
 
-       list_for_each_entry_safe(i_ipaddr, i_next, &rds_ibdev->ipaddr_list, list) {
-               list_del(&i_ipaddr->list);
-               kfree(i_ipaddr);
-       }
+       rds_ib_dev_shutdown(rds_ibdev);
 
-       rds_ib_destroy_conns(rds_ibdev);
+       /* stop connection attempts from getting a reference to this device. */
+       ib_set_client_data(device, &rds_ib_client, NULL);
 
-       if (rds_ibdev->mr_pool)
-               rds_ib_destroy_mr_pool(rds_ibdev->mr_pool);
-
-       ib_dereg_mr(rds_ibdev->mr);
-
-       while (ib_dealloc_pd(rds_ibdev->pd)) {
-               rdsdebug("Failed to dealloc pd %p\n", rds_ibdev->pd);
-               msleep(1);
-       }
+       down_write(&rds_ib_devices_lock);
+       list_del_rcu(&rds_ibdev->list);
+       up_write(&rds_ib_devices_lock);
 
-       list_del(&rds_ibdev->list);
-       kfree(rds_ibdev);
+       /*
+        * This synchronize rcu is waiting for readers of both the ib
+        * client data and the devices list to finish before we drop
+        * both of those references.
+        */
+       synchronize_rcu();
+       rds_ib_dev_put(rds_ibdev);
+       rds_ib_dev_put(rds_ibdev);
 }
 
 struct ib_client rds_ib_client = {
@@ -186,7 +287,7 @@ static int rds_ib_conn_info_visitor(struct rds_connection *conn,
                rdma_addr_get_sgid(dev_addr, (union ib_gid *) &iinfo->src_gid);
                rdma_addr_get_dgid(dev_addr, (union ib_gid *) &iinfo->dst_gid);
 
-               rds_ibdev = ib_get_client_data(ic->i_cm_id->device, &rds_ib_client);
+               rds_ibdev = ic->rds_ibdev;
                iinfo->max_send_wr = ic->i_send_ring.w_nr;
                iinfo->max_recv_wr = ic->i_recv_ring.w_nr;
                iinfo->max_send_sge = rds_ibdev->max_sge;
@@ -248,29 +349,36 @@ static int rds_ib_laddr_check(__be32 addr)
        return ret;
 }
 
+static void rds_ib_unregister_client(void)
+{
+       ib_unregister_client(&rds_ib_client);
+       /* wait for rds_ib_dev_free() to complete */
+       flush_workqueue(rds_wq);
+}
+
 void rds_ib_exit(void)
 {
        rds_info_deregister_func(RDS_INFO_IB_CONNECTIONS, rds_ib_ic_info);
+       rds_ib_unregister_client();
        rds_ib_destroy_nodev_conns();
-       ib_unregister_client(&rds_ib_client);
        rds_ib_sysctl_exit();
        rds_ib_recv_exit();
        rds_trans_unregister(&rds_ib_transport);
+       rds_ib_fmr_exit();
 }
 
 struct rds_transport rds_ib_transport = {
        .laddr_check            = rds_ib_laddr_check,
        .xmit_complete          = rds_ib_xmit_complete,
        .xmit                   = rds_ib_xmit,
-       .xmit_cong_map          = NULL,
        .xmit_rdma              = rds_ib_xmit_rdma,
+       .xmit_atomic            = rds_ib_xmit_atomic,
        .recv                   = rds_ib_recv,
        .conn_alloc             = rds_ib_conn_alloc,
        .conn_free              = rds_ib_conn_free,
        .conn_connect           = rds_ib_conn_connect,
        .conn_shutdown          = rds_ib_conn_shutdown,
        .inc_copy_to_user       = rds_ib_inc_copy_to_user,
-       .inc_purge              = rds_ib_inc_purge,
        .inc_free               = rds_ib_inc_free,
        .cm_initiate_connect    = rds_ib_cm_initiate_connect,
        .cm_handle_connect      = rds_ib_cm_handle_connect,
@@ -286,16 +394,20 @@ struct rds_transport rds_ib_transport = {
        .t_type                 = RDS_TRANS_IB
 };
 
-int __init rds_ib_init(void)
+int rds_ib_init(void)
 {
        int ret;
 
        INIT_LIST_HEAD(&rds_ib_devices);
 
-       ret = ib_register_client(&rds_ib_client);
+       ret = rds_ib_fmr_init();
        if (ret)
                goto out;
 
+       ret = ib_register_client(&rds_ib_client);
+       if (ret)
+               goto out_fmr_exit;
+
        ret = rds_ib_sysctl_init();
        if (ret)
                goto out_ibreg;
@@ -317,7 +429,9 @@ out_recv:
 out_sysctl:
        rds_ib_sysctl_exit();
 out_ibreg:
-       ib_unregister_client(&rds_ib_client);
+       rds_ib_unregister_client();
+out_fmr_exit:
+       rds_ib_fmr_exit();
 out:
        return ret;
 }
index 64df4e79b29f27ffcb8e8242df4b344284734e74..7ad3d57e06a556563d89513bc86bb170b6cfa815 100644 (file)
@@ -3,11 +3,13 @@
 
 #include <rdma/ib_verbs.h>
 #include <rdma/rdma_cm.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
 #include "rds.h"
 #include "rdma_transport.h"
 
 #define RDS_FMR_SIZE                   256
-#define RDS_FMR_POOL_SIZE              4096
+#define RDS_FMR_POOL_SIZE              8192
 
 #define RDS_IB_MAX_SGE                 8
 #define RDS_IB_RECV_SGE                2
@@ -19,6 +21,9 @@
 
 #define RDS_IB_SUPPORTED_PROTOCOLS     0x00000003      /* minor versions supported */
 
+#define RDS_IB_RECYCLE_BATCH_COUNT     32
+
+extern struct rw_semaphore rds_ib_devices_lock;
 extern struct list_head rds_ib_devices;
 
 /*
@@ -26,20 +31,29 @@ extern struct list_head rds_ib_devices;
  * try and minimize the amount of memory tied up both the device and
  * socket receive queues.
  */
-/* page offset of the final full frag that fits in the page */
-#define RDS_PAGE_LAST_OFF (((PAGE_SIZE  / RDS_FRAG_SIZE) - 1) * RDS_FRAG_SIZE)
 struct rds_page_frag {
        struct list_head        f_item;
-       struct page             *f_page;
-       unsigned long           f_offset;
-       dma_addr_t              f_mapped;
+       struct list_head        f_cache_entry;
+       struct scatterlist      f_sg;
 };
 
 struct rds_ib_incoming {
        struct list_head        ii_frags;
+       struct list_head        ii_cache_entry;
        struct rds_incoming     ii_inc;
 };
 
+struct rds_ib_cache_head {
+       struct list_head *first;
+       unsigned long count;
+};
+
+struct rds_ib_refill_cache {
+       struct rds_ib_cache_head *percpu;
+       struct list_head         *xfer;
+       struct list_head         *ready;
+};
+
 struct rds_ib_connect_private {
        /* Add new fields at the end, and don't permute existing fields. */
        __be32                  dp_saddr;
@@ -53,8 +67,7 @@ struct rds_ib_connect_private {
 };
 
 struct rds_ib_send_work {
-       struct rds_message      *s_rm;
-       struct rds_rdma_op      *s_op;
+       void                    *s_op;
        struct ib_send_wr       s_wr;
        struct ib_sge           s_sge[RDS_IB_MAX_SGE];
        unsigned long           s_queued;
@@ -92,10 +105,11 @@ struct rds_ib_connection {
 
        /* tx */
        struct rds_ib_work_ring i_send_ring;
-       struct rds_message      *i_rm;
+       struct rm_data_op       *i_data_op;
        struct rds_header       *i_send_hdrs;
        u64                     i_send_hdrs_dma;
        struct rds_ib_send_work *i_sends;
+       atomic_t                i_signaled_sends;
 
        /* rx */
        struct tasklet_struct   i_recv_tasklet;
@@ -106,8 +120,9 @@ struct rds_ib_connection {
        struct rds_header       *i_recv_hdrs;
        u64                     i_recv_hdrs_dma;
        struct rds_ib_recv_work *i_recvs;
-       struct rds_page_frag    i_frag;
        u64                     i_ack_recv;     /* last ACK received */
+       struct rds_ib_refill_cache i_cache_incs;
+       struct rds_ib_refill_cache i_cache_frags;
 
        /* sending acks */
        unsigned long           i_ack_flags;
@@ -138,7 +153,6 @@ struct rds_ib_connection {
 
        /* Batched completions */
        unsigned int            i_unsignaled_wrs;
-       long                    i_unsignaled_bytes;
 };
 
 /* This assumes that atomic_t is at least 32 bits */
@@ -164,9 +178,17 @@ struct rds_ib_device {
        unsigned int            max_fmrs;
        int                     max_sge;
        unsigned int            max_wrs;
+       unsigned int            max_initiator_depth;
+       unsigned int            max_responder_resources;
        spinlock_t              spinlock;       /* protect the above */
+       atomic_t                refcount;
+       struct work_struct      free_work;
 };
 
+#define pcidev_to_node(pcidev) pcibus_to_node(pcidev->bus)
+#define ibdev_to_node(ibdev) pcidev_to_node(to_pci_dev(ibdev->dma_device))
+#define rdsibdev_to_node(rdsibdev) ibdev_to_node(rdsibdev->dev)
+
 /* bits for i_ack_flags */
 #define IB_ACK_IN_FLIGHT       0
 #define IB_ACK_REQUESTED       1
@@ -202,6 +224,8 @@ struct rds_ib_statistics {
        uint64_t        s_ib_rdma_mr_pool_flush;
        uint64_t        s_ib_rdma_mr_pool_wait;
        uint64_t        s_ib_rdma_mr_pool_depleted;
+       uint64_t        s_ib_atomic_cswp;
+       uint64_t        s_ib_atomic_fadd;
 };
 
 extern struct workqueue_struct *rds_ib_wq;
@@ -243,6 +267,8 @@ static inline void rds_ib_dma_sync_sg_for_device(struct ib_device *dev,
 extern struct rds_transport rds_ib_transport;
 extern void rds_ib_add_one(struct ib_device *device);
 extern void rds_ib_remove_one(struct ib_device *device);
+struct rds_ib_device *rds_ib_get_client_data(struct ib_device *device);
+void rds_ib_dev_put(struct rds_ib_device *rds_ibdev);
 extern struct ib_client rds_ib_client;
 
 extern unsigned int fmr_pool_size;
@@ -258,7 +284,7 @@ void rds_ib_conn_free(void *arg);
 int rds_ib_conn_connect(struct rds_connection *conn);
 void rds_ib_conn_shutdown(struct rds_connection *conn);
 void rds_ib_state_change(struct sock *sk);
-int __init rds_ib_listen_init(void);
+int rds_ib_listen_init(void);
 void rds_ib_listen_stop(void);
 void __rds_ib_conn_error(struct rds_connection *conn, const char *, ...);
 int rds_ib_cm_handle_connect(struct rdma_cm_id *cm_id,
@@ -275,15 +301,7 @@ void rds_ib_cm_connect_complete(struct rds_connection *conn,
 int rds_ib_update_ipaddr(struct rds_ib_device *rds_ibdev, __be32 ipaddr);
 void rds_ib_add_conn(struct rds_ib_device *rds_ibdev, struct rds_connection *conn);
 void rds_ib_remove_conn(struct rds_ib_device *rds_ibdev, struct rds_connection *conn);
-void __rds_ib_destroy_conns(struct list_head *list, spinlock_t *list_lock);
-static inline void rds_ib_destroy_nodev_conns(void)
-{
-       __rds_ib_destroy_conns(&ib_nodev_conns, &ib_nodev_conns_lock);
-}
-static inline void rds_ib_destroy_conns(struct rds_ib_device *rds_ibdev)
-{
-       __rds_ib_destroy_conns(&rds_ibdev->conn_list, &rds_ibdev->spinlock);
-}
+void rds_ib_destroy_nodev_conns(void);
 struct rds_ib_mr_pool *rds_ib_create_mr_pool(struct rds_ib_device *);
 void rds_ib_get_mr_info(struct rds_ib_device *rds_ibdev, struct rds_info_rdma_connection *iinfo);
 void rds_ib_destroy_mr_pool(struct rds_ib_mr_pool *);
@@ -292,14 +310,16 @@ void *rds_ib_get_mr(struct scatterlist *sg, unsigned long nents,
 void rds_ib_sync_mr(void *trans_private, int dir);
 void rds_ib_free_mr(void *trans_private, int invalidate);
 void rds_ib_flush_mrs(void);
+int rds_ib_fmr_init(void);
+void rds_ib_fmr_exit(void);
 
 /* ib_recv.c */
-int __init rds_ib_recv_init(void);
+int rds_ib_recv_init(void);
 void rds_ib_recv_exit(void);
 int rds_ib_recv(struct rds_connection *conn);
-int rds_ib_recv_refill(struct rds_connection *conn, gfp_t kptr_gfp,
-                      gfp_t page_gfp, int prefill);
-void rds_ib_inc_purge(struct rds_incoming *inc);
+int rds_ib_recv_alloc_caches(struct rds_ib_connection *ic);
+void rds_ib_recv_free_caches(struct rds_ib_connection *ic);
+void rds_ib_recv_refill(struct rds_connection *conn, int prefill);
 void rds_ib_inc_free(struct rds_incoming *inc);
 int rds_ib_inc_copy_to_user(struct rds_incoming *inc, struct iovec *iov,
                             size_t size);
@@ -325,17 +345,19 @@ u32 rds_ib_ring_completed(struct rds_ib_work_ring *ring, u32 wr_id, u32 oldest);
 extern wait_queue_head_t rds_ib_ring_empty_wait;
 
 /* ib_send.c */
+char *rds_ib_wc_status_str(enum ib_wc_status status);
 void rds_ib_xmit_complete(struct rds_connection *conn);
 int rds_ib_xmit(struct rds_connection *conn, struct rds_message *rm,
                unsigned int hdr_off, unsigned int sg, unsigned int off);
 void rds_ib_send_cq_comp_handler(struct ib_cq *cq, void *context);
 void rds_ib_send_init_ring(struct rds_ib_connection *ic);
 void rds_ib_send_clear_ring(struct rds_ib_connection *ic);
-int rds_ib_xmit_rdma(struct rds_connection *conn, struct rds_rdma_op *op);
+int rds_ib_xmit_rdma(struct rds_connection *conn, struct rm_rdma_op *op);
 void rds_ib_send_add_credits(struct rds_connection *conn, unsigned int credits);
 void rds_ib_advertise_credits(struct rds_connection *conn, unsigned int posted);
 int rds_ib_send_grab_credits(struct rds_ib_connection *ic, u32 wanted,
                             u32 *adv_credits, int need_posted, int max_posted);
+int rds_ib_xmit_atomic(struct rds_connection *conn, struct rm_atomic_op *op);
 
 /* ib_stats.c */
 DECLARE_PER_CPU(struct rds_ib_statistics, rds_ib_stats);
@@ -344,7 +366,7 @@ unsigned int rds_ib_stats_info_copy(struct rds_info_iterator *iter,
                                    unsigned int avail);
 
 /* ib_sysctl.c */
-int __init rds_ib_sysctl_init(void);
+int rds_ib_sysctl_init(void);
 void rds_ib_sysctl_exit(void);
 extern unsigned long rds_ib_sysctl_max_send_wr;
 extern unsigned long rds_ib_sysctl_max_recv_wr;
@@ -354,28 +376,4 @@ extern unsigned long rds_ib_sysctl_max_recv_allocation;
 extern unsigned int rds_ib_sysctl_flow_control;
 extern ctl_table rds_ib_sysctl_table[];
 
-/*
- * Helper functions for getting/setting the header and data SGEs in
- * RDS packets (not RDMA)
- *
- * From version 3.1 onwards, header is in front of data in the sge.
- */
-static inline struct ib_sge *
-rds_ib_header_sge(struct rds_ib_connection *ic, struct ib_sge *sge)
-{
-       if (ic->conn->c_version > RDS_PROTOCOL_3_0)
-               return &sge[0];
-       else
-               return &sge[1];
-}
-
-static inline struct ib_sge *
-rds_ib_data_sge(struct rds_ib_connection *ic, struct ib_sge *sge)
-{
-       if (ic->conn->c_version > RDS_PROTOCOL_3_0)
-               return &sge[1];
-       else
-               return &sge[0];
-}
-
 #endif
index f68832798db224d6abffcc08f4ad494fa2b3bc17..bc3dbc1ba61f38cb68a1e5cef1a466254bd52414 100644 (file)
 #include "rds.h"
 #include "ib.h"
 
+static char *rds_ib_event_type_strings[] = {
+#define RDS_IB_EVENT_STRING(foo) \
+               [IB_EVENT_##foo] = __stringify(IB_EVENT_##foo)
+       RDS_IB_EVENT_STRING(CQ_ERR),
+       RDS_IB_EVENT_STRING(QP_FATAL),
+       RDS_IB_EVENT_STRING(QP_REQ_ERR),
+       RDS_IB_EVENT_STRING(QP_ACCESS_ERR),
+       RDS_IB_EVENT_STRING(COMM_EST),
+       RDS_IB_EVENT_STRING(SQ_DRAINED),
+       RDS_IB_EVENT_STRING(PATH_MIG),
+       RDS_IB_EVENT_STRING(PATH_MIG_ERR),
+       RDS_IB_EVENT_STRING(DEVICE_FATAL),
+       RDS_IB_EVENT_STRING(PORT_ACTIVE),
+       RDS_IB_EVENT_STRING(PORT_ERR),
+       RDS_IB_EVENT_STRING(LID_CHANGE),
+       RDS_IB_EVENT_STRING(PKEY_CHANGE),
+       RDS_IB_EVENT_STRING(SM_CHANGE),
+       RDS_IB_EVENT_STRING(SRQ_ERR),
+       RDS_IB_EVENT_STRING(SRQ_LIMIT_REACHED),
+       RDS_IB_EVENT_STRING(QP_LAST_WQE_REACHED),
+       RDS_IB_EVENT_STRING(CLIENT_REREGISTER),
+#undef RDS_IB_EVENT_STRING
+};
+
+static char *rds_ib_event_str(enum ib_event_type type)
+{
+       return rds_str_array(rds_ib_event_type_strings,
+                            ARRAY_SIZE(rds_ib_event_type_strings), type);
+};
+
 /*
  * Set the selected protocol version
  */
@@ -95,7 +125,6 @@ void rds_ib_cm_connect_complete(struct rds_connection *conn, struct rdma_cm_even
 {
        const struct rds_ib_connect_private *dp = NULL;
        struct rds_ib_connection *ic = conn->c_transport_data;
-       struct rds_ib_device *rds_ibdev;
        struct ib_qp_attr qp_attr;
        int err;
 
@@ -111,11 +140,21 @@ void rds_ib_cm_connect_complete(struct rds_connection *conn, struct rdma_cm_even
                }
        }
 
-       printk(KERN_NOTICE "RDS/IB: connected to %pI4 version %u.%u%s\n",
-                       &conn->c_faddr,
-                       RDS_PROTOCOL_MAJOR(conn->c_version),
-                       RDS_PROTOCOL_MINOR(conn->c_version),
-                       ic->i_flowctl ? ", flow control" : "");
+       if (conn->c_version < RDS_PROTOCOL(3,1)) {
+               printk(KERN_NOTICE "RDS/IB: Connection to %pI4 version %u.%u failed,"
+                      " no longer supported\n",
+                      &conn->c_faddr,
+                      RDS_PROTOCOL_MAJOR(conn->c_version),
+                      RDS_PROTOCOL_MINOR(conn->c_version));
+               rds_conn_destroy(conn);
+               return;
+       } else {
+               printk(KERN_NOTICE "RDS/IB: connected to %pI4 version %u.%u%s\n",
+                      &conn->c_faddr,
+                      RDS_PROTOCOL_MAJOR(conn->c_version),
+                      RDS_PROTOCOL_MINOR(conn->c_version),
+                      ic->i_flowctl ? ", flow control" : "");
+       }
 
        /*
         * Init rings and fill recv. this needs to wait until protocol negotiation
@@ -125,7 +164,7 @@ void rds_ib_cm_connect_complete(struct rds_connection *conn, struct rdma_cm_even
        rds_ib_recv_init_ring(ic);
        /* Post receive buffers - as a side effect, this will update
         * the posted credit count. */
-       rds_ib_recv_refill(conn, GFP_KERNEL, GFP_HIGHUSER, 1);
+       rds_ib_recv_refill(conn, 1);
 
        /* Tune RNR behavior */
        rds_ib_tune_rnr(ic, &qp_attr);
@@ -135,12 +174,11 @@ void rds_ib_cm_connect_complete(struct rds_connection *conn, struct rdma_cm_even
        if (err)
                printk(KERN_NOTICE "ib_modify_qp(IB_QP_STATE, RTS): err=%d\n", err);
 
-       /* update ib_device with this local ipaddr & conn */
-       rds_ibdev = ib_get_client_data(ic->i_cm_id->device, &rds_ib_client);
-       err = rds_ib_update_ipaddr(rds_ibdev, conn->c_laddr);
+       /* update ib_device with this local ipaddr */
+       err = rds_ib_update_ipaddr(ic->rds_ibdev, conn->c_laddr);
        if (err)
-               printk(KERN_ERR "rds_ib_update_ipaddr failed (%d)\n", err);
-       rds_ib_add_conn(rds_ibdev, conn);
+               printk(KERN_ERR "rds_ib_update_ipaddr failed (%d)\n",
+                       err);
 
        /* If the peer gave us the last packet it saw, process this as if
         * we had received a regular ACK. */
@@ -153,18 +191,23 @@ void rds_ib_cm_connect_complete(struct rds_connection *conn, struct rdma_cm_even
 static void rds_ib_cm_fill_conn_param(struct rds_connection *conn,
                        struct rdma_conn_param *conn_param,
                        struct rds_ib_connect_private *dp,
-                       u32 protocol_version)
+                       u32 protocol_version,
+                       u32 max_responder_resources,
+                       u32 max_initiator_depth)
 {
+       struct rds_ib_connection *ic = conn->c_transport_data;
+       struct rds_ib_device *rds_ibdev = ic->rds_ibdev;
+
        memset(conn_param, 0, sizeof(struct rdma_conn_param));
-       /* XXX tune these? */
-       conn_param->responder_resources = 1;
-       conn_param->initiator_depth = 1;
+
+       conn_param->responder_resources =
+               min_t(u32, rds_ibdev->max_responder_resources, max_responder_resources);
+       conn_param->initiator_depth =
+               min_t(u32, rds_ibdev->max_initiator_depth, max_initiator_depth);
        conn_param->retry_count = min_t(unsigned int, rds_ib_retry_count, 7);
        conn_param->rnr_retry_count = 7;
 
        if (dp) {
-               struct rds_ib_connection *ic = conn->c_transport_data;
-
                memset(dp, 0, sizeof(*dp));
                dp->dp_saddr = conn->c_laddr;
                dp->dp_daddr = conn->c_faddr;
@@ -189,7 +232,8 @@ static void rds_ib_cm_fill_conn_param(struct rds_connection *conn,
 
 static void rds_ib_cq_event_handler(struct ib_event *event, void *data)
 {
-       rdsdebug("event %u data %p\n", event->event, data);
+       rdsdebug("event %u (%s) data %p\n",
+                event->event, rds_ib_event_str(event->event), data);
 }
 
 static void rds_ib_qp_event_handler(struct ib_event *event, void *data)
@@ -197,16 +241,18 @@ static void rds_ib_qp_event_handler(struct ib_event *event, void *data)
        struct rds_connection *conn = data;
        struct rds_ib_connection *ic = conn->c_transport_data;
 
-       rdsdebug("conn %p ic %p event %u\n", conn, ic, event->event);
+       rdsdebug("conn %p ic %p event %u (%s)\n", conn, ic, event->event,
+                rds_ib_event_str(event->event));
 
        switch (event->event) {
        case IB_EVENT_COMM_EST:
                rdma_notify(ic->i_cm_id, IB_EVENT_COMM_EST);
                break;
        default:
-               rdsdebug("Fatal QP Event %u "
+               rdsdebug("Fatal QP Event %u (%s) "
                        "- connection %pI4->%pI4, reconnecting\n",
-                       event->event, &conn->c_laddr, &conn->c_faddr);
+                       event->event, rds_ib_event_str(event->event),
+                       &conn->c_laddr, &conn->c_faddr);
                rds_conn_drop(conn);
                break;
        }
@@ -224,18 +270,16 @@ static int rds_ib_setup_qp(struct rds_connection *conn)
        struct rds_ib_device *rds_ibdev;
        int ret;
 
-       /* rds_ib_add_one creates a rds_ib_device object per IB device,
-        * and allocates a protection domain, memory range and FMR pool
-        * for each.  If that fails for any reason, it will not register
-        * the rds_ibdev at all.
+       /*
+        * It's normal to see a null device if an incoming connection races
+        * with device removal, so we don't print a warning.
         */
-       rds_ibdev = ib_get_client_data(dev, &rds_ib_client);
-       if (rds_ibdev == NULL) {
-               if (printk_ratelimit())
-                       printk(KERN_NOTICE "RDS/IB: No client_data for device %s\n",
-                                       dev->name);
+       rds_ibdev = rds_ib_get_client_data(dev);
+       if (!rds_ibdev)
                return -EOPNOTSUPP;
-       }
+
+       /* add the conn now so that connection establishment has the dev */
+       rds_ib_add_conn(rds_ibdev, conn);
 
        if (rds_ibdev->max_wrs < ic->i_send_ring.w_nr + 1)
                rds_ib_ring_resize(&ic->i_send_ring, rds_ibdev->max_wrs - 1);
@@ -306,7 +350,7 @@ static int rds_ib_setup_qp(struct rds_connection *conn)
                                           ic->i_send_ring.w_nr *
                                                sizeof(struct rds_header),
                                           &ic->i_send_hdrs_dma, GFP_KERNEL);
-       if (ic->i_send_hdrs == NULL) {
+       if (!ic->i_send_hdrs) {
                ret = -ENOMEM;
                rdsdebug("ib_dma_alloc_coherent send failed\n");
                goto out;
@@ -316,7 +360,7 @@ static int rds_ib_setup_qp(struct rds_connection *conn)
                                           ic->i_recv_ring.w_nr *
                                                sizeof(struct rds_header),
                                           &ic->i_recv_hdrs_dma, GFP_KERNEL);
-       if (ic->i_recv_hdrs == NULL) {
+       if (!ic->i_recv_hdrs) {
                ret = -ENOMEM;
                rdsdebug("ib_dma_alloc_coherent recv failed\n");
                goto out;
@@ -324,22 +368,24 @@ static int rds_ib_setup_qp(struct rds_connection *conn)
 
        ic->i_ack = ib_dma_alloc_coherent(dev, sizeof(struct rds_header),
                                       &ic->i_ack_dma, GFP_KERNEL);
-       if (ic->i_ack == NULL) {
+       if (!ic->i_ack) {
                ret = -ENOMEM;
                rdsdebug("ib_dma_alloc_coherent ack failed\n");
                goto out;
        }
 
-       ic->i_sends = vmalloc(ic->i_send_ring.w_nr * sizeof(struct rds_ib_send_work));
-       if (ic->i_sends == NULL) {
+       ic->i_sends = vmalloc_node(ic->i_send_ring.w_nr * sizeof(struct rds_ib_send_work),
+                                  ibdev_to_node(dev));
+       if (!ic->i_sends) {
                ret = -ENOMEM;
                rdsdebug("send allocation failed\n");
                goto out;
        }
        memset(ic->i_sends, 0, ic->i_send_ring.w_nr * sizeof(struct rds_ib_send_work));
 
-       ic->i_recvs = vmalloc(ic->i_recv_ring.w_nr * sizeof(struct rds_ib_recv_work));
-       if (ic->i_recvs == NULL) {
+       ic->i_recvs = vmalloc_node(ic->i_recv_ring.w_nr * sizeof(struct rds_ib_recv_work),
+                                  ibdev_to_node(dev));
+       if (!ic->i_recvs) {
                ret = -ENOMEM;
                rdsdebug("recv allocation failed\n");
                goto out;
@@ -352,6 +398,7 @@ static int rds_ib_setup_qp(struct rds_connection *conn)
                 ic->i_send_cq, ic->i_recv_cq);
 
 out:
+       rds_ib_dev_put(rds_ibdev);
        return ret;
 }
 
@@ -409,7 +456,7 @@ int rds_ib_cm_handle_connect(struct rdma_cm_id *cm_id,
        struct rds_ib_connection *ic = NULL;
        struct rdma_conn_param conn_param;
        u32 version;
-       int err, destroy = 1;
+       int err = 1, destroy = 1;
 
        /* Check whether the remote protocol version matches ours. */
        version = rds_ib_protocol_compatible(event);
@@ -448,7 +495,6 @@ int rds_ib_cm_handle_connect(struct rdma_cm_id *cm_id,
                        /* Wait and see - our connect may still be succeeding */
                        rds_ib_stats_inc(s_ib_connect_raced);
                }
-               mutex_unlock(&conn->c_cm_lock);
                goto out;
        }
 
@@ -479,20 +525,20 @@ int rds_ib_cm_handle_connect(struct rdma_cm_id *cm_id,
                goto out;
        }
 
-       rds_ib_cm_fill_conn_param(conn, &conn_param, &dp_rep, version);
+       rds_ib_cm_fill_conn_param(conn, &conn_param, &dp_rep, version,
+               event->param.conn.responder_resources,
+               event->param.conn.initiator_depth);
 
        /* rdma_accept() calls rdma_reject() internally if it fails */
        err = rdma_accept(cm_id, &conn_param);
-       mutex_unlock(&conn->c_cm_lock);
-       if (err) {
+       if (err)
                rds_ib_conn_error(conn, "rdma_accept failed (%d)\n", err);
-               goto out;
-       }
-
-       return 0;
 
 out:
-       rdma_reject(cm_id, NULL, 0);
+       if (conn)
+               mutex_unlock(&conn->c_cm_lock);
+       if (err)
+               rdma_reject(cm_id, NULL, 0);
        return destroy;
 }
 
@@ -516,8 +562,8 @@ int rds_ib_cm_initiate_connect(struct rdma_cm_id *cm_id)
                goto out;
        }
 
-       rds_ib_cm_fill_conn_param(conn, &conn_param, &dp, RDS_PROTOCOL_VERSION);
-
+       rds_ib_cm_fill_conn_param(conn, &conn_param, &dp, RDS_PROTOCOL_VERSION,
+               UINT_MAX, UINT_MAX);
        ret = rdma_connect(cm_id, &conn_param);
        if (ret)
                rds_ib_conn_error(conn, "rdma_connect failed (%d)\n", ret);
@@ -601,9 +647,19 @@ void rds_ib_conn_shutdown(struct rds_connection *conn)
                                ic->i_cm_id, err);
                }
 
+               /*
+                * We want to wait for tx and rx completion to finish
+                * before we tear down the connection, but we have to be
+                * careful not to get stuck waiting on a send ring that
+                * only has unsignaled sends in it.  We've shutdown new
+                * sends before getting here so by waiting for signaled
+                * sends to complete we're ensured that there will be no
+                * more tx processing.
+                */
                wait_event(rds_ib_ring_empty_wait,
-                       rds_ib_ring_empty(&ic->i_send_ring) &&
-                       rds_ib_ring_empty(&ic->i_recv_ring));
+                          rds_ib_ring_empty(&ic->i_recv_ring) &&
+                          (atomic_read(&ic->i_signaled_sends) == 0));
+               tasklet_kill(&ic->i_recv_tasklet);
 
                if (ic->i_send_hdrs)
                        ib_dma_free_coherent(dev,
@@ -654,9 +710,12 @@ void rds_ib_conn_shutdown(struct rds_connection *conn)
        BUG_ON(ic->rds_ibdev);
 
        /* Clear pending transmit */
-       if (ic->i_rm) {
-               rds_message_put(ic->i_rm);
-               ic->i_rm = NULL;
+       if (ic->i_data_op) {
+               struct rds_message *rm;
+
+               rm = container_of(ic->i_data_op, struct rds_message, data);
+               rds_message_put(rm);
+               ic->i_data_op = NULL;
        }
 
        /* Clear the ACK state */
@@ -690,12 +749,19 @@ int rds_ib_conn_alloc(struct rds_connection *conn, gfp_t gfp)
 {
        struct rds_ib_connection *ic;
        unsigned long flags;
+       int ret;
 
        /* XXX too lazy? */
        ic = kzalloc(sizeof(struct rds_ib_connection), GFP_KERNEL);
-       if (ic == NULL)
+       if (!ic)
                return -ENOMEM;
 
+       ret = rds_ib_recv_alloc_caches(ic);
+       if (ret) {
+               kfree(ic);
+               return ret;
+       }
+
        INIT_LIST_HEAD(&ic->ib_node);
        tasklet_init(&ic->i_recv_tasklet, rds_ib_recv_tasklet_fn,
                     (unsigned long) ic);
@@ -703,6 +769,7 @@ int rds_ib_conn_alloc(struct rds_connection *conn, gfp_t gfp)
 #ifndef KERNEL_HAS_ATOMIC64
        spin_lock_init(&ic->i_ack_lock);
 #endif
+       atomic_set(&ic->i_signaled_sends, 0);
 
        /*
         * rds_ib_conn_shutdown() waits for these to be emptied so they
@@ -744,6 +811,8 @@ void rds_ib_conn_free(void *arg)
        list_del(&ic->ib_node);
        spin_unlock_irq(lock_ptr);
 
+       rds_ib_recv_free_caches(ic);
+
        kfree(ic);
 }
 
index a54cd63f9e35bd0f3e33a80d9ac06801fb3e0122..8f6e221c9f7836c1db5e459752e7ff577273835d 100644 (file)
  */
 #include <linux/kernel.h>
 #include <linux/slab.h>
+#include <linux/rculist.h>
 
 #include "rds.h"
-#include "rdma.h"
 #include "ib.h"
+#include "xlist.h"
 
+struct workqueue_struct *rds_ib_fmr_wq;
+
+static DEFINE_PER_CPU(unsigned long, clean_list_grace);
+#define CLEAN_LIST_BUSY_BIT 0
 
 /*
  * This is stored as mr->r_trans_private.
@@ -45,7 +50,11 @@ struct rds_ib_mr {
        struct rds_ib_device    *device;
        struct rds_ib_mr_pool   *pool;
        struct ib_fmr           *fmr;
-       struct list_head        list;
+
+       struct xlist_head       xlist;
+
+       /* unmap_list is for freeing */
+       struct list_head        unmap_list;
        unsigned int            remap_count;
 
        struct scatterlist      *sg;
@@ -59,14 +68,16 @@ struct rds_ib_mr {
  */
 struct rds_ib_mr_pool {
        struct mutex            flush_lock;             /* serialize fmr invalidate */
-       struct work_struct      flush_worker;           /* flush worker */
+       struct delayed_work     flush_worker;           /* flush worker */
 
-       spinlock_t              list_lock;              /* protect variables below */
        atomic_t                item_count;             /* total # of MRs */
        atomic_t                dirty_count;            /* # dirty of MRs */
-       struct list_head        drop_list;              /* MRs that have reached their max_maps limit */
-       struct list_head        free_list;              /* unused MRs */
-       struct list_head        clean_list;             /* unused & unamapped MRs */
+
+       struct xlist_head       drop_list;              /* MRs that have reached their max_maps limit */
+       struct xlist_head       free_list;              /* unused MRs */
+       struct xlist_head       clean_list;             /* global unused & unamapped MRs */
+       wait_queue_head_t       flush_wait;
+
        atomic_t                free_pinned;            /* memory pinned by free MRs */
        unsigned long           max_items;
        unsigned long           max_items_soft;
@@ -74,7 +85,7 @@ struct rds_ib_mr_pool {
        struct ib_fmr_attr      fmr_attr;
 };
 
-static int rds_ib_flush_mr_pool(struct rds_ib_mr_pool *pool, int free_all);
+static int rds_ib_flush_mr_pool(struct rds_ib_mr_pool *pool, int free_all, struct rds_ib_mr **);
 static void rds_ib_teardown_mr(struct rds_ib_mr *ibmr);
 static void rds_ib_mr_pool_flush_worker(struct work_struct *work);
 
@@ -83,16 +94,17 @@ static struct rds_ib_device *rds_ib_get_device(__be32 ipaddr)
        struct rds_ib_device *rds_ibdev;
        struct rds_ib_ipaddr *i_ipaddr;
 
-       list_for_each_entry(rds_ibdev, &rds_ib_devices, list) {
-               spin_lock_irq(&rds_ibdev->spinlock);
-               list_for_each_entry(i_ipaddr, &rds_ibdev->ipaddr_list, list) {
+       rcu_read_lock();
+       list_for_each_entry_rcu(rds_ibdev, &rds_ib_devices, list) {
+               list_for_each_entry_rcu(i_ipaddr, &rds_ibdev->ipaddr_list, list) {
                        if (i_ipaddr->ipaddr == ipaddr) {
-                               spin_unlock_irq(&rds_ibdev->spinlock);
+                               atomic_inc(&rds_ibdev->refcount);
+                               rcu_read_unlock();
                                return rds_ibdev;
                        }
                }
-               spin_unlock_irq(&rds_ibdev->spinlock);
        }
+       rcu_read_unlock();
 
        return NULL;
 }
@@ -108,7 +120,7 @@ static int rds_ib_add_ipaddr(struct rds_ib_device *rds_ibdev, __be32 ipaddr)
        i_ipaddr->ipaddr = ipaddr;
 
        spin_lock_irq(&rds_ibdev->spinlock);
-       list_add_tail(&i_ipaddr->list, &rds_ibdev->ipaddr_list);
+       list_add_tail_rcu(&i_ipaddr->list, &rds_ibdev->ipaddr_list);
        spin_unlock_irq(&rds_ibdev->spinlock);
 
        return 0;
@@ -116,17 +128,24 @@ static int rds_ib_add_ipaddr(struct rds_ib_device *rds_ibdev, __be32 ipaddr)
 
 static void rds_ib_remove_ipaddr(struct rds_ib_device *rds_ibdev, __be32 ipaddr)
 {
-       struct rds_ib_ipaddr *i_ipaddr, *next;
+       struct rds_ib_ipaddr *i_ipaddr;
+       struct rds_ib_ipaddr *to_free = NULL;
+
 
        spin_lock_irq(&rds_ibdev->spinlock);
-       list_for_each_entry_safe(i_ipaddr, next, &rds_ibdev->ipaddr_list, list) {
+       list_for_each_entry_rcu(i_ipaddr, &rds_ibdev->ipaddr_list, list) {
                if (i_ipaddr->ipaddr == ipaddr) {
-                       list_del(&i_ipaddr->list);
-                       kfree(i_ipaddr);
+                       list_del_rcu(&i_ipaddr->list);
+                       to_free = i_ipaddr;
                        break;
                }
        }
        spin_unlock_irq(&rds_ibdev->spinlock);
+
+       if (to_free) {
+               synchronize_rcu();
+               kfree(to_free);
+       }
 }
 
 int rds_ib_update_ipaddr(struct rds_ib_device *rds_ibdev, __be32 ipaddr)
@@ -134,8 +153,10 @@ int rds_ib_update_ipaddr(struct rds_ib_device *rds_ibdev, __be32 ipaddr)
        struct rds_ib_device *rds_ibdev_old;
 
        rds_ibdev_old = rds_ib_get_device(ipaddr);
-       if (rds_ibdev_old)
+       if (rds_ibdev_old) {
                rds_ib_remove_ipaddr(rds_ibdev_old, ipaddr);
+               rds_ib_dev_put(rds_ibdev_old);
+       }
 
        return rds_ib_add_ipaddr(rds_ibdev, ipaddr);
 }
@@ -156,6 +177,7 @@ void rds_ib_add_conn(struct rds_ib_device *rds_ibdev, struct rds_connection *con
        spin_unlock_irq(&ib_nodev_conns_lock);
 
        ic->rds_ibdev = rds_ibdev;
+       atomic_inc(&rds_ibdev->refcount);
 }
 
 void rds_ib_remove_conn(struct rds_ib_device *rds_ibdev, struct rds_connection *conn)
@@ -175,18 +197,18 @@ void rds_ib_remove_conn(struct rds_ib_device *rds_ibdev, struct rds_connection *
        spin_unlock(&ib_nodev_conns_lock);
 
        ic->rds_ibdev = NULL;
+       rds_ib_dev_put(rds_ibdev);
 }
 
-void __rds_ib_destroy_conns(struct list_head *list, spinlock_t *list_lock)
+void rds_ib_destroy_nodev_conns(void)
 {
        struct rds_ib_connection *ic, *_ic;
        LIST_HEAD(tmp_list);
 
        /* avoid calling conn_destroy with irqs off */
-       spin_lock_irq(list_lock);
-       list_splice(list, &tmp_list);
-       INIT_LIST_HEAD(list);
-       spin_unlock_irq(list_lock);
+       spin_lock_irq(&ib_nodev_conns_lock);
+       list_splice(&ib_nodev_conns, &tmp_list);
+       spin_unlock_irq(&ib_nodev_conns_lock);
 
        list_for_each_entry_safe(ic, _ic, &tmp_list, ib_node)
                rds_conn_destroy(ic->conn);
@@ -200,12 +222,12 @@ struct rds_ib_mr_pool *rds_ib_create_mr_pool(struct rds_ib_device *rds_ibdev)
        if (!pool)
                return ERR_PTR(-ENOMEM);
 
-       INIT_LIST_HEAD(&pool->free_list);
-       INIT_LIST_HEAD(&pool->drop_list);
-       INIT_LIST_HEAD(&pool->clean_list);
+       INIT_XLIST_HEAD(&pool->free_list);
+       INIT_XLIST_HEAD(&pool->drop_list);
+       INIT_XLIST_HEAD(&pool->clean_list);
        mutex_init(&pool->flush_lock);
-       spin_lock_init(&pool->list_lock);
-       INIT_WORK(&pool->flush_worker, rds_ib_mr_pool_flush_worker);
+       init_waitqueue_head(&pool->flush_wait);
+       INIT_DELAYED_WORK(&pool->flush_worker, rds_ib_mr_pool_flush_worker);
 
        pool->fmr_attr.max_pages = fmr_message_size;
        pool->fmr_attr.max_maps = rds_ibdev->fmr_max_remaps;
@@ -233,34 +255,60 @@ void rds_ib_get_mr_info(struct rds_ib_device *rds_ibdev, struct rds_info_rdma_co
 
 void rds_ib_destroy_mr_pool(struct rds_ib_mr_pool *pool)
 {
-       flush_workqueue(rds_wq);
-       rds_ib_flush_mr_pool(pool, 1);
+       cancel_delayed_work_sync(&pool->flush_worker);
+       rds_ib_flush_mr_pool(pool, 1, NULL);
        WARN_ON(atomic_read(&pool->item_count));
        WARN_ON(atomic_read(&pool->free_pinned));
        kfree(pool);
 }
 
+static void refill_local(struct rds_ib_mr_pool *pool, struct xlist_head *xl,
+                        struct rds_ib_mr **ibmr_ret)
+{
+       struct xlist_head *ibmr_xl;
+       ibmr_xl = xlist_del_head_fast(xl);
+       *ibmr_ret = list_entry(ibmr_xl, struct rds_ib_mr, xlist);
+}
+
 static inline struct rds_ib_mr *rds_ib_reuse_fmr(struct rds_ib_mr_pool *pool)
 {
        struct rds_ib_mr *ibmr = NULL;
-       unsigned long flags;
+       struct xlist_head *ret;
+       unsigned long *flag;
 
-       spin_lock_irqsave(&pool->list_lock, flags);
-       if (!list_empty(&pool->clean_list)) {
-               ibmr = list_entry(pool->clean_list.next, struct rds_ib_mr, list);
-               list_del_init(&ibmr->list);
-       }
-       spin_unlock_irqrestore(&pool->list_lock, flags);
+       preempt_disable();
+       flag = &__get_cpu_var(clean_list_grace);
+       set_bit(CLEAN_LIST_BUSY_BIT, flag);
+       ret = xlist_del_head(&pool->clean_list);
+       if (ret)
+               ibmr = list_entry(ret, struct rds_ib_mr, xlist);
 
+       clear_bit(CLEAN_LIST_BUSY_BIT, flag);
+       preempt_enable();
        return ibmr;
 }
 
+static inline void wait_clean_list_grace(void)
+{
+       int cpu;
+       unsigned long *flag;
+
+       for_each_online_cpu(cpu) {
+               flag = &per_cpu(clean_list_grace, cpu);
+               while (test_bit(CLEAN_LIST_BUSY_BIT, flag))
+                       cpu_relax();
+       }
+}
+
 static struct rds_ib_mr *rds_ib_alloc_fmr(struct rds_ib_device *rds_ibdev)
 {
        struct rds_ib_mr_pool *pool = rds_ibdev->mr_pool;
        struct rds_ib_mr *ibmr = NULL;
        int err = 0, iter = 0;
 
+       if (atomic_read(&pool->dirty_count) >= pool->max_items / 10)
+               queue_delayed_work(rds_ib_fmr_wq, &pool->flush_worker, 10);
+
        while (1) {
                ibmr = rds_ib_reuse_fmr(pool);
                if (ibmr)
@@ -287,19 +335,24 @@ static struct rds_ib_mr *rds_ib_alloc_fmr(struct rds_ib_device *rds_ibdev)
 
                /* We do have some empty MRs. Flush them out. */
                rds_ib_stats_inc(s_ib_rdma_mr_pool_wait);
-               rds_ib_flush_mr_pool(pool, 0);
+               rds_ib_flush_mr_pool(pool, 0, &ibmr);
+               if (ibmr)
+                       return ibmr;
        }
 
-       ibmr = kzalloc(sizeof(*ibmr), GFP_KERNEL);
+       ibmr = kzalloc_node(sizeof(*ibmr), GFP_KERNEL, rdsibdev_to_node(rds_ibdev));
        if (!ibmr) {
                err = -ENOMEM;
                goto out_no_cigar;
        }
 
+       memset(ibmr, 0, sizeof(*ibmr));
+
        ibmr->fmr = ib_alloc_fmr(rds_ibdev->pd,
                        (IB_ACCESS_LOCAL_WRITE |
                         IB_ACCESS_REMOTE_READ |
-                        IB_ACCESS_REMOTE_WRITE),
+                        IB_ACCESS_REMOTE_WRITE|
+                        IB_ACCESS_REMOTE_ATOMIC),
                        &pool->fmr_attr);
        if (IS_ERR(ibmr->fmr)) {
                err = PTR_ERR(ibmr->fmr);
@@ -367,7 +420,8 @@ static int rds_ib_map_fmr(struct rds_ib_device *rds_ibdev, struct rds_ib_mr *ibm
        if (page_cnt > fmr_message_size)
                return -EINVAL;
 
-       dma_pages = kmalloc(sizeof(u64) * page_cnt, GFP_ATOMIC);
+       dma_pages = kmalloc_node(sizeof(u64) * page_cnt, GFP_ATOMIC,
+                                rdsibdev_to_node(rds_ibdev));
        if (!dma_pages)
                return -ENOMEM;
 
@@ -441,7 +495,7 @@ static void __rds_ib_teardown_mr(struct rds_ib_mr *ibmr)
 
                        /* FIXME we need a way to tell a r/w MR
                         * from a r/o MR */
-                       BUG_ON(in_interrupt());
+                       BUG_ON(irqs_disabled());
                        set_page_dirty(page);
                        put_page(page);
                }
@@ -476,34 +530,110 @@ static inline unsigned int rds_ib_flush_goal(struct rds_ib_mr_pool *pool, int fr
        return 0;
 }
 
+/*
+ * given an xlist of mrs, put them all into the list_head for more processing
+ */
+static void xlist_append_to_list(struct xlist_head *xlist, struct list_head *list)
+{
+       struct rds_ib_mr *ibmr;
+       struct xlist_head splice;
+       struct xlist_head *cur;
+       struct xlist_head *next;
+
+       splice.next = NULL;
+       xlist_splice(xlist, &splice);
+       cur = splice.next;
+       while (cur) {
+               next = cur->next;
+               ibmr = list_entry(cur, struct rds_ib_mr, xlist);
+               list_add_tail(&ibmr->unmap_list, list);
+               cur = next;
+       }
+}
+
+/*
+ * this takes a list head of mrs and turns it into an xlist of clusters.
+ * each cluster has an xlist of MR_CLUSTER_SIZE mrs that are ready for
+ * reuse.
+ */
+static void list_append_to_xlist(struct rds_ib_mr_pool *pool,
+                               struct list_head *list, struct xlist_head *xlist,
+                               struct xlist_head **tail_ret)
+{
+       struct rds_ib_mr *ibmr;
+       struct xlist_head *cur_mr = xlist;
+       struct xlist_head *tail_mr = NULL;
+
+       list_for_each_entry(ibmr, list, unmap_list) {
+               tail_mr = &ibmr->xlist;
+               tail_mr->next = NULL;
+               cur_mr->next = tail_mr;
+               cur_mr = tail_mr;
+       }
+       *tail_ret = tail_mr;
+}
+
 /*
  * Flush our pool of MRs.
  * At a minimum, all currently unused MRs are unmapped.
  * If the number of MRs allocated exceeds the limit, we also try
  * to free as many MRs as needed to get back to this limit.
  */
-static int rds_ib_flush_mr_pool(struct rds_ib_mr_pool *pool, int free_all)
+static int rds_ib_flush_mr_pool(struct rds_ib_mr_pool *pool,
+                               int free_all, struct rds_ib_mr **ibmr_ret)
 {
        struct rds_ib_mr *ibmr, *next;
+       struct xlist_head clean_xlist;
+       struct xlist_head *clean_tail;
        LIST_HEAD(unmap_list);
        LIST_HEAD(fmr_list);
        unsigned long unpinned = 0;
-       unsigned long flags;
        unsigned int nfreed = 0, ncleaned = 0, free_goal;
        int ret = 0;
 
        rds_ib_stats_inc(s_ib_rdma_mr_pool_flush);
 
-       mutex_lock(&pool->flush_lock);
+       if (ibmr_ret) {
+               DEFINE_WAIT(wait);
+               while(!mutex_trylock(&pool->flush_lock)) {
+                       ibmr = rds_ib_reuse_fmr(pool);
+                       if (ibmr) {
+                               *ibmr_ret = ibmr;
+                               finish_wait(&pool->flush_wait, &wait);
+                               goto out_nolock;
+                       }
+
+                       prepare_to_wait(&pool->flush_wait, &wait,
+                                       TASK_UNINTERRUPTIBLE);
+                       if (xlist_empty(&pool->clean_list))
+                               schedule();
+
+                       ibmr = rds_ib_reuse_fmr(pool);
+                       if (ibmr) {
+                               *ibmr_ret = ibmr;
+                               finish_wait(&pool->flush_wait, &wait);
+                               goto out_nolock;
+                       }
+               }
+               finish_wait(&pool->flush_wait, &wait);
+       } else
+               mutex_lock(&pool->flush_lock);
+
+       if (ibmr_ret) {
+               ibmr = rds_ib_reuse_fmr(pool);
+               if (ibmr) {
+                       *ibmr_ret = ibmr;
+                       goto out;
+               }
+       }
 
-       spin_lock_irqsave(&pool->list_lock, flags);
        /* Get the list of all MRs to be dropped. Ordering matters -
-        * we want to put drop_list ahead of free_list. */
-       list_splice_init(&pool->free_list, &unmap_list);
-       list_splice_init(&pool->drop_list, &unmap_list);
+        * we want to put drop_list ahead of free_list.
+        */
+       xlist_append_to_list(&pool->drop_list, &unmap_list);
+       xlist_append_to_list(&pool->free_list, &unmap_list);
        if (free_all)
-               list_splice_init(&pool->clean_list, &unmap_list);
-       spin_unlock_irqrestore(&pool->list_lock, flags);
+               xlist_append_to_list(&pool->clean_list, &unmap_list);
 
        free_goal = rds_ib_flush_goal(pool, free_all);
 
@@ -511,19 +641,20 @@ static int rds_ib_flush_mr_pool(struct rds_ib_mr_pool *pool, int free_all)
                goto out;
 
        /* String all ib_mr's onto one list and hand them to ib_unmap_fmr */
-       list_for_each_entry(ibmr, &unmap_list, list)
+       list_for_each_entry(ibmr, &unmap_list, unmap_list)
                list_add(&ibmr->fmr->list, &fmr_list);
+
        ret = ib_unmap_fmr(&fmr_list);
        if (ret)
                printk(KERN_WARNING "RDS/IB: ib_unmap_fmr failed (err=%d)\n", ret);
 
        /* Now we can destroy the DMA mapping and unpin any pages */
-       list_for_each_entry_safe(ibmr, next, &unmap_list, list) {
+       list_for_each_entry_safe(ibmr, next, &unmap_list, unmap_list) {
                unpinned += ibmr->sg_len;
                __rds_ib_teardown_mr(ibmr);
                if (nfreed < free_goal || ibmr->remap_count >= pool->fmr_attr.max_maps) {
                        rds_ib_stats_inc(s_ib_rdma_mr_free);
-                       list_del(&ibmr->list);
+                       list_del(&ibmr->unmap_list);
                        ib_dealloc_fmr(ibmr->fmr);
                        kfree(ibmr);
                        nfreed++;
@@ -531,9 +662,27 @@ static int rds_ib_flush_mr_pool(struct rds_ib_mr_pool *pool, int free_all)
                ncleaned++;
        }
 
-       spin_lock_irqsave(&pool->list_lock, flags);
-       list_splice(&unmap_list, &pool->clean_list);
-       spin_unlock_irqrestore(&pool->list_lock, flags);
+       if (!list_empty(&unmap_list)) {
+               /* we have to make sure that none of the things we're about
+                * to put on the clean list would race with other cpus trying
+                * to pull items off.  The xlist would explode if we managed to
+                * remove something from the clean list and then add it back again
+                * while another CPU was spinning on that same item in xlist_del_head.
+                *
+                * This is pretty unlikely, but just in case  wait for an xlist grace period
+                * here before adding anything back into the clean list.
+                */
+               wait_clean_list_grace();
+
+               list_append_to_xlist(pool, &unmap_list, &clean_xlist, &clean_tail);
+               if (ibmr_ret)
+                       refill_local(pool, &clean_xlist, ibmr_ret);
+
+               /* refill_local may have emptied our list */
+               if (!xlist_empty(&clean_xlist))
+                       xlist_add(clean_xlist.next, clean_tail, &pool->clean_list);
+
+       }
 
        atomic_sub(unpinned, &pool->free_pinned);
        atomic_sub(ncleaned, &pool->dirty_count);
@@ -541,14 +690,35 @@ static int rds_ib_flush_mr_pool(struct rds_ib_mr_pool *pool, int free_all)
 
 out:
        mutex_unlock(&pool->flush_lock);
+       if (waitqueue_active(&pool->flush_wait))
+               wake_up(&pool->flush_wait);
+out_nolock:
        return ret;
 }
 
+int rds_ib_fmr_init(void)
+{
+       rds_ib_fmr_wq = create_workqueue("rds_fmr_flushd");
+       if (!rds_ib_fmr_wq)
+               return -ENOMEM;
+       return 0;
+}
+
+/*
+ * By the time this is called all the IB devices should have been torn down and
+ * had their pools freed.  As each pool is freed its work struct is waited on,
+ * so the pool flushing work queue should be idle by the time we get here.
+ */
+void rds_ib_fmr_exit(void)
+{
+       destroy_workqueue(rds_ib_fmr_wq);
+}
+
 static void rds_ib_mr_pool_flush_worker(struct work_struct *work)
 {
-       struct rds_ib_mr_pool *pool = container_of(work, struct rds_ib_mr_pool, flush_worker);
+       struct rds_ib_mr_pool *pool = container_of(work, struct rds_ib_mr_pool, flush_worker.work);
 
-       rds_ib_flush_mr_pool(pool, 0);
+       rds_ib_flush_mr_pool(pool, 0, NULL);
 }
 
 void rds_ib_free_mr(void *trans_private, int invalidate)
@@ -556,47 +726,49 @@ void rds_ib_free_mr(void *trans_private, int invalidate)
        struct rds_ib_mr *ibmr = trans_private;
        struct rds_ib_device *rds_ibdev = ibmr->device;
        struct rds_ib_mr_pool *pool = rds_ibdev->mr_pool;
-       unsigned long flags;
 
        rdsdebug("RDS/IB: free_mr nents %u\n", ibmr->sg_len);
 
        /* Return it to the pool's free list */
-       spin_lock_irqsave(&pool->list_lock, flags);
        if (ibmr->remap_count >= pool->fmr_attr.max_maps)
-               list_add(&ibmr->list, &pool->drop_list);
+               xlist_add(&ibmr->xlist, &ibmr->xlist, &pool->drop_list);
        else
-               list_add(&ibmr->list, &pool->free_list);
+               xlist_add(&ibmr->xlist, &ibmr->xlist, &pool->free_list);
 
        atomic_add(ibmr->sg_len, &pool->free_pinned);
        atomic_inc(&pool->dirty_count);
-       spin_unlock_irqrestore(&pool->list_lock, flags);
 
        /* If we've pinned too many pages, request a flush */
        if (atomic_read(&pool->free_pinned) >= pool->max_free_pinned ||
            atomic_read(&pool->dirty_count) >= pool->max_items / 10)
-               queue_work(rds_wq, &pool->flush_worker);
+               queue_delayed_work(rds_ib_fmr_wq, &pool->flush_worker, 10);
 
        if (invalidate) {
                if (likely(!in_interrupt())) {
-                       rds_ib_flush_mr_pool(pool, 0);
+                       rds_ib_flush_mr_pool(pool, 0, NULL);
                } else {
                        /* We get here if the user created a MR marked
                         * as use_once and invalidate at the same time. */
-                       queue_work(rds_wq, &pool->flush_worker);
+                       queue_delayed_work(rds_ib_fmr_wq,
+                                          &pool->flush_worker, 10);
                }
        }
+
+       rds_ib_dev_put(rds_ibdev);
 }
 
 void rds_ib_flush_mrs(void)
 {
        struct rds_ib_device *rds_ibdev;
 
+       down_read(&rds_ib_devices_lock);
        list_for_each_entry(rds_ibdev, &rds_ib_devices, list) {
                struct rds_ib_mr_pool *pool = rds_ibdev->mr_pool;
 
                if (pool)
-                       rds_ib_flush_mr_pool(pool, 0);
+                       rds_ib_flush_mr_pool(pool, 0, NULL);
        }
+       up_read(&rds_ib_devices_lock);
 }
 
 void *rds_ib_get_mr(struct scatterlist *sg, unsigned long nents,
@@ -628,6 +800,7 @@ void *rds_ib_get_mr(struct scatterlist *sg, unsigned long nents,
                printk(KERN_WARNING "RDS/IB: map_fmr failed (errno=%d)\n", ret);
 
        ibmr->device = rds_ibdev;
+       rds_ibdev = NULL;
 
  out:
        if (ret) {
@@ -635,5 +808,8 @@ void *rds_ib_get_mr(struct scatterlist *sg, unsigned long nents,
                        rds_ib_free_mr(ibmr, 0);
                ibmr = ERR_PTR(ret);
        }
+       if (rds_ibdev)
+               rds_ib_dev_put(rds_ibdev);
        return ibmr;
 }
+
index c74e9904a6b2c20872917c79bf06a905c1ecd403..e29e0ca32f740d978aeccf23a4fba5453a4e8aa4 100644 (file)
@@ -43,42 +43,6 @@ static struct kmem_cache *rds_ib_incoming_slab;
 static struct kmem_cache *rds_ib_frag_slab;
 static atomic_t        rds_ib_allocation = ATOMIC_INIT(0);
 
-static void rds_ib_frag_drop_page(struct rds_page_frag *frag)
-{
-       rdsdebug("frag %p page %p\n", frag, frag->f_page);
-       __free_page(frag->f_page);
-       frag->f_page = NULL;
-}
-
-static void rds_ib_frag_free(struct rds_page_frag *frag)
-{
-       rdsdebug("frag %p page %p\n", frag, frag->f_page);
-       BUG_ON(frag->f_page != NULL);
-       kmem_cache_free(rds_ib_frag_slab, frag);
-}
-
-/*
- * We map a page at a time.  Its fragments are posted in order.  This
- * is called in fragment order as the fragments get send completion events.
- * Only the last frag in the page performs the unmapping.
- *
- * It's OK for ring cleanup to call this in whatever order it likes because
- * DMA is not in flight and so we can unmap while other ring entries still
- * hold page references in their frags.
- */
-static void rds_ib_recv_unmap_page(struct rds_ib_connection *ic,
-                                  struct rds_ib_recv_work *recv)
-{
-       struct rds_page_frag *frag = recv->r_frag;
-
-       rdsdebug("recv %p frag %p page %p\n", recv, frag, frag->f_page);
-       if (frag->f_mapped)
-               ib_dma_unmap_page(ic->i_cm_id->device,
-                              frag->f_mapped,
-                              RDS_FRAG_SIZE, DMA_FROM_DEVICE);
-       frag->f_mapped = 0;
-}
-
 void rds_ib_recv_init_ring(struct rds_ib_connection *ic)
 {
        struct rds_ib_recv_work *recv;
@@ -95,16 +59,161 @@ void rds_ib_recv_init_ring(struct rds_ib_connection *ic)
                recv->r_wr.sg_list = recv->r_sge;
                recv->r_wr.num_sge = RDS_IB_RECV_SGE;
 
-               sge = rds_ib_data_sge(ic, recv->r_sge);
+               sge = &recv->r_sge[0];
+               sge->addr = ic->i_recv_hdrs_dma + (i * sizeof(struct rds_header));
+               sge->length = sizeof(struct rds_header);
+               sge->lkey = ic->i_mr->lkey;
+
+               sge = &recv->r_sge[1];
                sge->addr = 0;
                sge->length = RDS_FRAG_SIZE;
                sge->lkey = ic->i_mr->lkey;
+       }
+}
 
-               sge = rds_ib_header_sge(ic, recv->r_sge);
-               sge->addr = ic->i_recv_hdrs_dma + (i * sizeof(struct rds_header));
-               sge->length = sizeof(struct rds_header);
-               sge->lkey = ic->i_mr->lkey;
+/*
+ * The entire 'from' list, including the from element itself, is put on
+ * to the tail of the 'to' list.
+ */
+static void list_splice_entire_tail(struct list_head *from,
+                                   struct list_head *to)
+{
+       struct list_head *from_last = from->prev;
+
+       list_splice_tail(from_last, to);
+       list_add_tail(from_last, to);
+}
+
+static void rds_ib_cache_xfer_to_ready(struct rds_ib_refill_cache *cache)
+{
+       struct list_head *tmp;
+
+       tmp = xchg(&cache->xfer, NULL);
+       if (tmp) {
+               if (cache->ready)
+                       list_splice_entire_tail(tmp, cache->ready);
+               else
+                       cache->ready = tmp;
+       }
+}
+
+static int rds_ib_recv_alloc_cache(struct rds_ib_refill_cache *cache)
+{
+       struct rds_ib_cache_head *head;
+       int cpu;
+
+       cache->percpu = alloc_percpu(struct rds_ib_cache_head);
+       if (!cache->percpu)
+              return -ENOMEM;
+
+       for_each_possible_cpu(cpu) {
+               head = per_cpu_ptr(cache->percpu, cpu);
+               head->first = NULL;
+               head->count = 0;
+       }
+       cache->xfer = NULL;
+       cache->ready = NULL;
+
+       return 0;
+}
+
+int rds_ib_recv_alloc_caches(struct rds_ib_connection *ic)
+{
+       int ret;
+
+       ret = rds_ib_recv_alloc_cache(&ic->i_cache_incs);
+       if (!ret) {
+               ret = rds_ib_recv_alloc_cache(&ic->i_cache_frags);
+               if (ret)
+                       free_percpu(ic->i_cache_incs.percpu);
        }
+
+       return ret;
+}
+
+static void rds_ib_cache_splice_all_lists(struct rds_ib_refill_cache *cache,
+                                         struct list_head *caller_list)
+{
+       struct rds_ib_cache_head *head;
+       int cpu;
+
+       for_each_possible_cpu(cpu) {
+               head = per_cpu_ptr(cache->percpu, cpu);
+               if (head->first) {
+                       list_splice_entire_tail(head->first, caller_list);
+                       head->first = NULL;
+               }
+       }
+
+       if (cache->ready) {
+               list_splice_entire_tail(cache->ready, caller_list);
+               cache->ready = NULL;
+       }
+}
+
+void rds_ib_recv_free_caches(struct rds_ib_connection *ic)
+{
+       struct rds_ib_incoming *inc;
+       struct rds_ib_incoming *inc_tmp;
+       struct rds_page_frag *frag;
+       struct rds_page_frag *frag_tmp;
+       LIST_HEAD(list);
+
+       rds_ib_cache_xfer_to_ready(&ic->i_cache_incs);
+       rds_ib_cache_splice_all_lists(&ic->i_cache_incs, &list);
+       free_percpu(ic->i_cache_incs.percpu);
+
+       list_for_each_entry_safe(inc, inc_tmp, &list, ii_cache_entry) {
+               list_del(&inc->ii_cache_entry);
+               WARN_ON(!list_empty(&inc->ii_frags));
+               kmem_cache_free(rds_ib_incoming_slab, inc);
+       }
+
+       rds_ib_cache_xfer_to_ready(&ic->i_cache_frags);
+       rds_ib_cache_splice_all_lists(&ic->i_cache_frags, &list);
+       free_percpu(ic->i_cache_frags.percpu);
+
+       list_for_each_entry_safe(frag, frag_tmp, &list, f_cache_entry) {
+               list_del(&frag->f_cache_entry);
+               WARN_ON(!list_empty(&frag->f_item));
+               kmem_cache_free(rds_ib_frag_slab, frag);
+       }
+}
+
+/* fwd decl */
+static void rds_ib_recv_cache_put(struct list_head *new_item,
+                                 struct rds_ib_refill_cache *cache);
+static struct list_head *rds_ib_recv_cache_get(struct rds_ib_refill_cache *cache);
+
+
+/* Recycle frag and attached recv buffer f_sg */
+static void rds_ib_frag_free(struct rds_ib_connection *ic,
+                            struct rds_page_frag *frag)
+{
+       rdsdebug("frag %p page %p\n", frag, sg_page(&frag->f_sg));
+
+       rds_ib_recv_cache_put(&frag->f_cache_entry, &ic->i_cache_frags);
+}
+
+/* Recycle inc after freeing attached frags */
+void rds_ib_inc_free(struct rds_incoming *inc)
+{
+       struct rds_ib_incoming *ibinc;
+       struct rds_page_frag *frag;
+       struct rds_page_frag *pos;
+       struct rds_ib_connection *ic = inc->i_conn->c_transport_data;
+
+       ibinc = container_of(inc, struct rds_ib_incoming, ii_inc);
+
+       /* Free attached frags */
+       list_for_each_entry_safe(frag, pos, &ibinc->ii_frags, f_item) {
+               list_del_init(&frag->f_item);
+               rds_ib_frag_free(ic, frag);
+       }
+       BUG_ON(!list_empty(&ibinc->ii_frags));
+
+       rdsdebug("freeing ibinc %p inc %p\n", ibinc, inc);
+       rds_ib_recv_cache_put(&ibinc->ii_cache_entry, &ic->i_cache_incs);
 }
 
 static void rds_ib_recv_clear_one(struct rds_ib_connection *ic,
@@ -115,10 +224,8 @@ static void rds_ib_recv_clear_one(struct rds_ib_connection *ic,
                recv->r_ibinc = NULL;
        }
        if (recv->r_frag) {
-               rds_ib_recv_unmap_page(ic, recv);
-               if (recv->r_frag->f_page)
-                       rds_ib_frag_drop_page(recv->r_frag);
-               rds_ib_frag_free(recv->r_frag);
+               ib_dma_unmap_sg(ic->i_cm_id->device, &recv->r_frag->f_sg, 1, DMA_FROM_DEVICE);
+               rds_ib_frag_free(ic, recv->r_frag);
                recv->r_frag = NULL;
        }
 }
@@ -129,84 +236,111 @@ void rds_ib_recv_clear_ring(struct rds_ib_connection *ic)
 
        for (i = 0; i < ic->i_recv_ring.w_nr; i++)
                rds_ib_recv_clear_one(ic, &ic->i_recvs[i]);
-
-       if (ic->i_frag.f_page)
-               rds_ib_frag_drop_page(&ic->i_frag);
 }
 
-static int rds_ib_recv_refill_one(struct rds_connection *conn,
-                                 struct rds_ib_recv_work *recv,
-                                 gfp_t kptr_gfp, gfp_t page_gfp)
+static struct rds_ib_incoming *rds_ib_refill_one_inc(struct rds_ib_connection *ic,
+                                                    gfp_t slab_mask)
 {
-       struct rds_ib_connection *ic = conn->c_transport_data;
-       dma_addr_t dma_addr;
-       struct ib_sge *sge;
-       int ret = -ENOMEM;
+       struct rds_ib_incoming *ibinc;
+       struct list_head *cache_item;
+       int avail_allocs;
 
-       if (recv->r_ibinc == NULL) {
-               if (!atomic_add_unless(&rds_ib_allocation, 1, rds_ib_sysctl_max_recv_allocation)) {
+       cache_item = rds_ib_recv_cache_get(&ic->i_cache_incs);
+       if (cache_item) {
+               ibinc = container_of(cache_item, struct rds_ib_incoming, ii_cache_entry);
+       } else {
+               avail_allocs = atomic_add_unless(&rds_ib_allocation,
+                                                1, rds_ib_sysctl_max_recv_allocation);
+               if (!avail_allocs) {
                        rds_ib_stats_inc(s_ib_rx_alloc_limit);
-                       goto out;
+                       return NULL;
                }
-               recv->r_ibinc = kmem_cache_alloc(rds_ib_incoming_slab,
-                                                kptr_gfp);
-               if (recv->r_ibinc == NULL) {
+               ibinc = kmem_cache_alloc(rds_ib_incoming_slab, slab_mask);
+               if (!ibinc) {
                        atomic_dec(&rds_ib_allocation);
-                       goto out;
+                       return NULL;
                }
-               INIT_LIST_HEAD(&recv->r_ibinc->ii_frags);
-               rds_inc_init(&recv->r_ibinc->ii_inc, conn, conn->c_faddr);
        }
+       INIT_LIST_HEAD(&ibinc->ii_frags);
+       rds_inc_init(&ibinc->ii_inc, ic->conn, ic->conn->c_faddr);
 
-       if (recv->r_frag == NULL) {
-               recv->r_frag = kmem_cache_alloc(rds_ib_frag_slab, kptr_gfp);
-               if (recv->r_frag == NULL)
-                       goto out;
-               INIT_LIST_HEAD(&recv->r_frag->f_item);
-               recv->r_frag->f_page = NULL;
+       return ibinc;
+}
+
+static struct rds_page_frag *rds_ib_refill_one_frag(struct rds_ib_connection *ic,
+                                                   gfp_t slab_mask, gfp_t page_mask)
+{
+       struct rds_page_frag *frag;
+       struct list_head *cache_item;
+       int ret;
+
+       cache_item = rds_ib_recv_cache_get(&ic->i_cache_frags);
+       if (cache_item) {
+               frag = container_of(cache_item, struct rds_page_frag, f_cache_entry);
+       } else {
+               frag = kmem_cache_alloc(rds_ib_frag_slab, slab_mask);
+               if (!frag)
+                       return NULL;
+
+               sg_init_table(&frag->f_sg, 1);
+               ret = rds_page_remainder_alloc(&frag->f_sg,
+                                              RDS_FRAG_SIZE, page_mask);
+               if (ret) {
+                       kmem_cache_free(rds_ib_frag_slab, frag);
+                       return NULL;
+               }
        }
 
-       if (ic->i_frag.f_page == NULL) {
-               ic->i_frag.f_page = alloc_page(page_gfp);
-               if (ic->i_frag.f_page == NULL)
-                       goto out;
-               ic->i_frag.f_offset = 0;
+       INIT_LIST_HEAD(&frag->f_item);
+
+       return frag;
+}
+
+static int rds_ib_recv_refill_one(struct rds_connection *conn,
+                                 struct rds_ib_recv_work *recv, int prefill)
+{
+       struct rds_ib_connection *ic = conn->c_transport_data;
+       struct ib_sge *sge;
+       int ret = -ENOMEM;
+       gfp_t slab_mask = GFP_NOWAIT;
+       gfp_t page_mask = GFP_NOWAIT;
+
+       if (prefill) {
+               slab_mask = GFP_KERNEL;
+               page_mask = GFP_HIGHUSER;
        }
 
-       dma_addr = ib_dma_map_page(ic->i_cm_id->device,
-                                 ic->i_frag.f_page,
-                                 ic->i_frag.f_offset,
-                                 RDS_FRAG_SIZE,
-                                 DMA_FROM_DEVICE);
-       if (ib_dma_mapping_error(ic->i_cm_id->device, dma_addr))
-               goto out;
+       if (!ic->i_cache_incs.ready)
+               rds_ib_cache_xfer_to_ready(&ic->i_cache_incs);
+       if (!ic->i_cache_frags.ready)
+               rds_ib_cache_xfer_to_ready(&ic->i_cache_frags);
 
        /*
-        * Once we get the RDS_PAGE_LAST_OFF frag then rds_ib_frag_unmap()
-        * must be called on this recv.  This happens as completions hit
-        * in order or on connection shutdown.
+        * ibinc was taken from recv if recv contained the start of a message.
+        * recvs that were continuations will still have this allocated.
         */
-       recv->r_frag->f_page = ic->i_frag.f_page;
-       recv->r_frag->f_offset = ic->i_frag.f_offset;
-       recv->r_frag->f_mapped = dma_addr;
+       if (!recv->r_ibinc) {
+               recv->r_ibinc = rds_ib_refill_one_inc(ic, slab_mask);
+               if (!recv->r_ibinc)
+                       goto out;
+       }
 
-       sge = rds_ib_data_sge(ic, recv->r_sge);
-       sge->addr = dma_addr;
-       sge->length = RDS_FRAG_SIZE;
+       WARN_ON(recv->r_frag); /* leak! */
+       recv->r_frag = rds_ib_refill_one_frag(ic, slab_mask, page_mask);
+       if (!recv->r_frag)
+               goto out;
+
+       ret = ib_dma_map_sg(ic->i_cm_id->device, &recv->r_frag->f_sg,
+                           1, DMA_FROM_DEVICE);
+       WARN_ON(ret != 1);
 
-       sge = rds_ib_header_sge(ic, recv->r_sge);
+       sge = &recv->r_sge[0];
        sge->addr = ic->i_recv_hdrs_dma + (recv - ic->i_recvs) * sizeof(struct rds_header);
        sge->length = sizeof(struct rds_header);
 
-       get_page(recv->r_frag->f_page);
-
-       if (ic->i_frag.f_offset < RDS_PAGE_LAST_OFF) {
-               ic->i_frag.f_offset += RDS_FRAG_SIZE;
-       } else {
-               put_page(ic->i_frag.f_page);
-               ic->i_frag.f_page = NULL;
-               ic->i_frag.f_offset = 0;
-       }
+       sge = &recv->r_sge[1];
+       sge->addr = sg_dma_address(&recv->r_frag->f_sg);
+       sge->length = sg_dma_len(&recv->r_frag->f_sg);
 
        ret = 0;
 out:
@@ -216,13 +350,11 @@ out:
 /*
  * This tries to allocate and post unused work requests after making sure that
  * they have all the allocations they need to queue received fragments into
- * sockets.  The i_recv_mutex is held here so that ring_alloc and _unalloc
- * pairs don't go unmatched.
+ * sockets.
  *
  * -1 is returned if posting fails due to temporary resource exhaustion.
  */
-int rds_ib_recv_refill(struct rds_connection *conn, gfp_t kptr_gfp,
-                      gfp_t page_gfp, int prefill)
+void rds_ib_recv_refill(struct rds_connection *conn, int prefill)
 {
        struct rds_ib_connection *ic = conn->c_transport_data;
        struct rds_ib_recv_work *recv;
@@ -236,28 +368,25 @@ int rds_ib_recv_refill(struct rds_connection *conn, gfp_t kptr_gfp,
                if (pos >= ic->i_recv_ring.w_nr) {
                        printk(KERN_NOTICE "Argh - ring alloc returned pos=%u\n",
                                        pos);
-                       ret = -EINVAL;
                        break;
                }
 
                recv = &ic->i_recvs[pos];
-               ret = rds_ib_recv_refill_one(conn, recv, kptr_gfp, page_gfp);
+               ret = rds_ib_recv_refill_one(conn, recv, prefill);
                if (ret) {
-                       ret = -1;
                        break;
                }
 
                /* XXX when can this fail? */
                ret = ib_post_recv(ic->i_cm_id->qp, &recv->r_wr, &failed_wr);
                rdsdebug("recv %p ibinc %p page %p addr %lu ret %d\n", recv,
-                        recv->r_ibinc, recv->r_frag->f_page,
-                        (long) recv->r_frag->f_mapped, ret);
+                        recv->r_ibinc, sg_page(&recv->r_frag->f_sg),
+                        (long) sg_dma_address(&recv->r_frag->f_sg), ret);
                if (ret) {
                        rds_ib_conn_error(conn, "recv post on "
                               "%pI4 returned %d, disconnecting and "
                               "reconnecting\n", &conn->c_faddr,
                               ret);
-                       ret = -1;
                        break;
                }
 
@@ -270,37 +399,73 @@ int rds_ib_recv_refill(struct rds_connection *conn, gfp_t kptr_gfp,
 
        if (ret)
                rds_ib_ring_unalloc(&ic->i_recv_ring, 1);
-       return ret;
 }
 
-void rds_ib_inc_purge(struct rds_incoming *inc)
+/*
+ * We want to recycle several types of recv allocations, like incs and frags.
+ * To use this, the *_free() function passes in the ptr to a list_head within
+ * the recyclee, as well as the cache to put it on.
+ *
+ * First, we put the memory on a percpu list. When this reaches a certain size,
+ * We move it to an intermediate non-percpu list in a lockless manner, with some
+ * xchg/compxchg wizardry.
+ *
+ * N.B. Instead of a list_head as the anchor, we use a single pointer, which can
+ * be NULL and xchg'd. The list is actually empty when the pointer is NULL, and
+ * list_empty() will return true with one element is actually present.
+ */
+static void rds_ib_recv_cache_put(struct list_head *new_item,
+                                struct rds_ib_refill_cache *cache)
 {
-       struct rds_ib_incoming *ibinc;
-       struct rds_page_frag *frag;
-       struct rds_page_frag *pos;
+       unsigned long flags;
+       struct rds_ib_cache_head *chp;
+       struct list_head *old;
 
-       ibinc = container_of(inc, struct rds_ib_incoming, ii_inc);
-       rdsdebug("purging ibinc %p inc %p\n", ibinc, inc);
+       local_irq_save(flags);
 
-       list_for_each_entry_safe(frag, pos, &ibinc->ii_frags, f_item) {
-               list_del_init(&frag->f_item);
-               rds_ib_frag_drop_page(frag);
-               rds_ib_frag_free(frag);
-       }
+       chp = per_cpu_ptr(cache->percpu, smp_processor_id());
+       if (!chp->first)
+               INIT_LIST_HEAD(new_item);
+       else /* put on front */
+               list_add_tail(new_item, chp->first);
+       chp->first = new_item;
+       chp->count++;
+
+       if (chp->count < RDS_IB_RECYCLE_BATCH_COUNT)
+               goto end;
+
+       /*
+        * Return our per-cpu first list to the cache's xfer by atomically
+        * grabbing the current xfer list, appending it to our per-cpu list,
+        * and then atomically returning that entire list back to the
+        * cache's xfer list as long as it's still empty.
+        */
+       do {
+               old = xchg(&cache->xfer, NULL);
+               if (old)
+                       list_splice_entire_tail(old, chp->first);
+               old = cmpxchg(&cache->xfer, NULL, chp->first);
+       } while (old);
+
+       chp->first = NULL;
+       chp->count = 0;
+end:
+       local_irq_restore(flags);
 }
 
-void rds_ib_inc_free(struct rds_incoming *inc)
+static struct list_head *rds_ib_recv_cache_get(struct rds_ib_refill_cache *cache)
 {
-       struct rds_ib_incoming *ibinc;
-
-       ibinc = container_of(inc, struct rds_ib_incoming, ii_inc);
+       struct list_head *head = cache->ready;
+
+       if (head) {
+               if (!list_empty(head)) {
+                       cache->ready = head->next;
+                       list_del_init(head);
+               } else
+                       cache->ready = NULL;
+       }
 
-       rds_ib_inc_purge(inc);
-       rdsdebug("freeing ibinc %p inc %p\n", ibinc, inc);
-       BUG_ON(!list_empty(&ibinc->ii_frags));
-       kmem_cache_free(rds_ib_incoming_slab, ibinc);
-       atomic_dec(&rds_ib_allocation);
-       BUG_ON(atomic_read(&rds_ib_allocation) < 0);
+       return head;
 }
 
 int rds_ib_inc_copy_to_user(struct rds_incoming *inc, struct iovec *first_iov,
@@ -336,13 +501,13 @@ int rds_ib_inc_copy_to_user(struct rds_incoming *inc, struct iovec *first_iov,
                to_copy = min_t(unsigned long, to_copy, len - copied);
 
                rdsdebug("%lu bytes to user [%p, %zu] + %lu from frag "
-                        "[%p, %lu] + %lu\n",
+                        "[%p, %u] + %lu\n",
                         to_copy, iov->iov_base, iov->iov_len, iov_off,
-                        frag->f_page, frag->f_offset, frag_off);
+                        sg_page(&frag->f_sg), frag->f_sg.offset, frag_off);
 
                /* XXX needs + offset for multiple recvs per page */
-               ret = rds_page_copy_to_user(frag->f_page,
-                                           frag->f_offset + frag_off,
+               ret = rds_page_copy_to_user(sg_page(&frag->f_sg),
+                                           frag->f_sg.offset + frag_off,
                                            iov->iov_base + iov_off,
                                            to_copy);
                if (ret) {
@@ -557,47 +722,6 @@ u64 rds_ib_piggyb_ack(struct rds_ib_connection *ic)
        return rds_ib_get_ack(ic);
 }
 
-static struct rds_header *rds_ib_get_header(struct rds_connection *conn,
-                                           struct rds_ib_recv_work *recv,
-                                           u32 data_len)
-{
-       struct rds_ib_connection *ic = conn->c_transport_data;
-       void *hdr_buff = &ic->i_recv_hdrs[recv - ic->i_recvs];
-       void *addr;
-       u32 misplaced_hdr_bytes;
-
-       /*
-        * Support header at the front (RDS 3.1+) as well as header-at-end.
-        *
-        * Cases:
-        * 1) header all in header buff (great!)
-        * 2) header all in data page (copy all to header buff)
-        * 3) header split across hdr buf + data page
-        *    (move bit in hdr buff to end before copying other bit from data page)
-        */
-       if (conn->c_version > RDS_PROTOCOL_3_0 || data_len == RDS_FRAG_SIZE)
-               return hdr_buff;
-
-       if (data_len <= (RDS_FRAG_SIZE - sizeof(struct rds_header))) {
-               addr = kmap_atomic(recv->r_frag->f_page, KM_SOFTIRQ0);
-               memcpy(hdr_buff,
-                      addr + recv->r_frag->f_offset + data_len,
-                      sizeof(struct rds_header));
-               kunmap_atomic(addr, KM_SOFTIRQ0);
-               return hdr_buff;
-       }
-
-       misplaced_hdr_bytes = (sizeof(struct rds_header) - (RDS_FRAG_SIZE - data_len));
-
-       memmove(hdr_buff + misplaced_hdr_bytes, hdr_buff, misplaced_hdr_bytes);
-
-       addr = kmap_atomic(recv->r_frag->f_page, KM_SOFTIRQ0);
-       memcpy(hdr_buff, addr + recv->r_frag->f_offset + data_len,
-              sizeof(struct rds_header) - misplaced_hdr_bytes);
-       kunmap_atomic(addr, KM_SOFTIRQ0);
-       return hdr_buff;
-}
-
 /*
  * It's kind of lame that we're copying from the posted receive pages into
  * long-lived bitmaps.  We could have posted the bitmaps and rdma written into
@@ -639,7 +763,7 @@ static void rds_ib_cong_recv(struct rds_connection *conn,
                to_copy = min(RDS_FRAG_SIZE - frag_off, PAGE_SIZE - map_off);
                BUG_ON(to_copy & 7); /* Must be 64bit aligned. */
 
-               addr = kmap_atomic(frag->f_page, KM_SOFTIRQ0);
+               addr = kmap_atomic(sg_page(&frag->f_sg), KM_SOFTIRQ0);
 
                src = addr + frag_off;
                dst = (void *)map->m_page_addrs[map_page] + map_off;
@@ -710,7 +834,7 @@ static void rds_ib_process_recv(struct rds_connection *conn,
        }
        data_len -= sizeof(struct rds_header);
 
-       ihdr = rds_ib_get_header(conn, recv, data_len);
+       ihdr = &ic->i_recv_hdrs[recv - ic->i_recvs];
 
        /* Validate the checksum. */
        if (!rds_message_verify_checksum(ihdr)) {
@@ -742,12 +866,12 @@ static void rds_ib_process_recv(struct rds_connection *conn,
                 * the inc is freed.  We don't go that route, so we have to drop the
                 * page ref ourselves.  We can't just leave the page on the recv
                 * because that confuses the dma mapping of pages and each recv's use
-                * of a partial page.  We can leave the frag, though, it will be
-                * reused.
+                * of a partial page.
                 *
                 * FIXME: Fold this into the code path below.
                 */
-               rds_ib_frag_drop_page(recv->r_frag);
+               rds_ib_frag_free(ic, recv->r_frag);
+               recv->r_frag = NULL;
                return;
        }
 
@@ -757,7 +881,7 @@ static void rds_ib_process_recv(struct rds_connection *conn,
         * into the inc and save the inc so we can hang upcoming fragments
         * off its list.
         */
-       if (ibinc == NULL) {
+       if (!ibinc) {
                ibinc = recv->r_ibinc;
                recv->r_ibinc = NULL;
                ic->i_ibinc = ibinc;
@@ -842,32 +966,38 @@ static inline void rds_poll_cq(struct rds_ib_connection *ic,
        struct rds_ib_recv_work *recv;
 
        while (ib_poll_cq(ic->i_recv_cq, 1, &wc) > 0) {
-               rdsdebug("wc wr_id 0x%llx status %u byte_len %u imm_data %u\n",
-                        (unsigned long long)wc.wr_id, wc.status, wc.byte_len,
+               rdsdebug("wc wr_id 0x%llx status %u (%s) byte_len %u imm_data %u\n",
+                        (unsigned long long)wc.wr_id, wc.status,
+                        rds_ib_wc_status_str(wc.status), wc.byte_len,
                         be32_to_cpu(wc.ex.imm_data));
                rds_ib_stats_inc(s_ib_rx_cq_event);
 
                recv = &ic->i_recvs[rds_ib_ring_oldest(&ic->i_recv_ring)];
 
-               rds_ib_recv_unmap_page(ic, recv);
+               ib_dma_unmap_sg(ic->i_cm_id->device, &recv->r_frag->f_sg, 1, DMA_FROM_DEVICE);
 
                /*
                 * Also process recvs in connecting state because it is possible
                 * to get a recv completion _before_ the rdmacm ESTABLISHED
                 * event is processed.
                 */
-               if (rds_conn_up(conn) || rds_conn_connecting(conn)) {
+               if (wc.status == IB_WC_SUCCESS) {
+                       rds_ib_process_recv(conn, recv, wc.byte_len, state);
+               } else {
                        /* We expect errors as the qp is drained during shutdown */
-                       if (wc.status == IB_WC_SUCCESS) {
-                               rds_ib_process_recv(conn, recv, wc.byte_len, state);
-                       } else {
-                               rds_ib_conn_error(conn, "recv completion on "
-                                      "%pI4 had status %u, disconnecting and "
-                                      "reconnecting\n", &conn->c_faddr,
-                                      wc.status);
-                       }
+                       if (rds_conn_up(conn) || rds_conn_connecting(conn))
+                               rds_ib_conn_error(conn, "recv completion on %pI4 had "
+                                                 "status %u (%s), disconnecting and "
+                                                 "reconnecting\n", &conn->c_faddr,
+                                                 wc.status,
+                                                 rds_ib_wc_status_str(wc.status));
                }
 
+               /*
+                * It's very important that we only free this ring entry if we've truly
+                * freed the resources allocated to the entry.  The refilling path can
+                * leak if we don't.
+                */
                rds_ib_ring_free(&ic->i_recv_ring, 1);
        }
 }
@@ -897,11 +1027,8 @@ void rds_ib_recv_tasklet_fn(unsigned long data)
        if (rds_ib_ring_empty(&ic->i_recv_ring))
                rds_ib_stats_inc(s_ib_rx_ring_empty);
 
-       /*
-        * If the ring is running low, then schedule the thread to refill.
-        */
        if (rds_ib_ring_low(&ic->i_recv_ring))
-               queue_delayed_work(rds_wq, &conn->c_recv_w, 0);
+               rds_ib_recv_refill(conn, 0);
 }
 
 int rds_ib_recv(struct rds_connection *conn)
@@ -910,25 +1037,13 @@ int rds_ib_recv(struct rds_connection *conn)
        int ret = 0;
 
        rdsdebug("conn %p\n", conn);
-
-       /*
-        * If we get a temporary posting failure in this context then
-        * we're really low and we want the caller to back off for a bit.
-        */
-       mutex_lock(&ic->i_recv_mutex);
-       if (rds_ib_recv_refill(conn, GFP_KERNEL, GFP_HIGHUSER, 0))
-               ret = -ENOMEM;
-       else
-               rds_ib_stats_inc(s_ib_rx_refill_from_thread);
-       mutex_unlock(&ic->i_recv_mutex);
-
        if (rds_conn_up(conn))
                rds_ib_attempt_ack(ic);
 
        return ret;
 }
 
-int __init rds_ib_recv_init(void)
+int rds_ib_recv_init(void)
 {
        struct sysinfo si;
        int ret = -ENOMEM;
@@ -939,14 +1054,14 @@ int __init rds_ib_recv_init(void)
 
        rds_ib_incoming_slab = kmem_cache_create("rds_ib_incoming",
                                        sizeof(struct rds_ib_incoming),
-                                       0, 0, NULL);
-       if (rds_ib_incoming_slab == NULL)
+                                       0, SLAB_HWCACHE_ALIGN, NULL);
+       if (!rds_ib_incoming_slab)
                goto out;
 
        rds_ib_frag_slab = kmem_cache_create("rds_ib_frag",
                                        sizeof(struct rds_page_frag),
-                                       0, 0, NULL);
-       if (rds_ib_frag_slab == NULL)
+                                       0, SLAB_HWCACHE_ALIGN, NULL);
+       if (!rds_ib_frag_slab)
                kmem_cache_destroy(rds_ib_incoming_slab);
        else
                ret = 0;
index 17fa80803ab01ccbd0fa1279ed448c1bd51d501d..71f373c421bc4d8b6a97f2be7201a2dc8c2290e8 100644 (file)
 #include <linux/dmapool.h>
 
 #include "rds.h"
-#include "rdma.h"
 #include "ib.h"
 
-static void rds_ib_send_rdma_complete(struct rds_message *rm,
-                                     int wc_status)
+static char *rds_ib_wc_status_strings[] = {
+#define RDS_IB_WC_STATUS_STR(foo) \
+               [IB_WC_##foo] = __stringify(IB_WC_##foo)
+       RDS_IB_WC_STATUS_STR(SUCCESS),
+       RDS_IB_WC_STATUS_STR(LOC_LEN_ERR),
+       RDS_IB_WC_STATUS_STR(LOC_QP_OP_ERR),
+       RDS_IB_WC_STATUS_STR(LOC_EEC_OP_ERR),
+       RDS_IB_WC_STATUS_STR(LOC_PROT_ERR),
+       RDS_IB_WC_STATUS_STR(WR_FLUSH_ERR),
+       RDS_IB_WC_STATUS_STR(MW_BIND_ERR),
+       RDS_IB_WC_STATUS_STR(BAD_RESP_ERR),
+       RDS_IB_WC_STATUS_STR(LOC_ACCESS_ERR),
+       RDS_IB_WC_STATUS_STR(REM_INV_REQ_ERR),
+       RDS_IB_WC_STATUS_STR(REM_ACCESS_ERR),
+       RDS_IB_WC_STATUS_STR(REM_OP_ERR),
+       RDS_IB_WC_STATUS_STR(RETRY_EXC_ERR),
+       RDS_IB_WC_STATUS_STR(RNR_RETRY_EXC_ERR),
+       RDS_IB_WC_STATUS_STR(LOC_RDD_VIOL_ERR),
+       RDS_IB_WC_STATUS_STR(REM_INV_RD_REQ_ERR),
+       RDS_IB_WC_STATUS_STR(REM_ABORT_ERR),
+       RDS_IB_WC_STATUS_STR(INV_EECN_ERR),
+       RDS_IB_WC_STATUS_STR(INV_EEC_STATE_ERR),
+       RDS_IB_WC_STATUS_STR(FATAL_ERR),
+       RDS_IB_WC_STATUS_STR(RESP_TIMEOUT_ERR),
+       RDS_IB_WC_STATUS_STR(GENERAL_ERR),
+#undef RDS_IB_WC_STATUS_STR
+};
+
+char *rds_ib_wc_status_str(enum ib_wc_status status)
+{
+       return rds_str_array(rds_ib_wc_status_strings,
+                            ARRAY_SIZE(rds_ib_wc_status_strings), status);
+}
+
+/*
+ * Convert IB-specific error message to RDS error message and call core
+ * completion handler.
+ */
+static void rds_ib_send_complete(struct rds_message *rm,
+                                int wc_status,
+                                void (*complete)(struct rds_message *rm, int status))
 {
        int notify_status;
 
@@ -60,69 +98,125 @@ static void rds_ib_send_rdma_complete(struct rds_message *rm,
                notify_status = RDS_RDMA_OTHER_ERROR;
                break;
        }
-       rds_rdma_send_complete(rm, notify_status);
+       complete(rm, notify_status);
+}
+
+static void rds_ib_send_unmap_data(struct rds_ib_connection *ic,
+                                  struct rm_data_op *op,
+                                  int wc_status)
+{
+       if (op->op_nents)
+               ib_dma_unmap_sg(ic->i_cm_id->device,
+                               op->op_sg, op->op_nents,
+                               DMA_TO_DEVICE);
 }
 
 static void rds_ib_send_unmap_rdma(struct rds_ib_connection *ic,
-                                  struct rds_rdma_op *op)
+                                  struct rm_rdma_op *op,
+                                  int wc_status)
 {
-       if (op->r_mapped) {
+       if (op->op_mapped) {
                ib_dma_unmap_sg(ic->i_cm_id->device,
-                       op->r_sg, op->r_nents,
-                       op->r_write ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
-               op->r_mapped = 0;
+                               op->op_sg, op->op_nents,
+                               op->op_write ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+               op->op_mapped = 0;
        }
+
+       /* If the user asked for a completion notification on this
+        * message, we can implement three different semantics:
+        *  1.  Notify when we received the ACK on the RDS message
+        *      that was queued with the RDMA. This provides reliable
+        *      notification of RDMA status at the expense of a one-way
+        *      packet delay.
+        *  2.  Notify when the IB stack gives us the completion event for
+        *      the RDMA operation.
+        *  3.  Notify when the IB stack gives us the completion event for
+        *      the accompanying RDS messages.
+        * Here, we implement approach #3. To implement approach #2,
+        * we would need to take an event for the rdma WR. To implement #1,
+        * don't call rds_rdma_send_complete at all, and fall back to the notify
+        * handling in the ACK processing code.
+        *
+        * Note: There's no need to explicitly sync any RDMA buffers using
+        * ib_dma_sync_sg_for_cpu - the completion for the RDMA
+        * operation itself unmapped the RDMA buffers, which takes care
+        * of synching.
+        */
+       rds_ib_send_complete(container_of(op, struct rds_message, rdma),
+                            wc_status, rds_rdma_send_complete);
+
+       if (op->op_write)
+               rds_stats_add(s_send_rdma_bytes, op->op_bytes);
+       else
+               rds_stats_add(s_recv_rdma_bytes, op->op_bytes);
 }
 
-static void rds_ib_send_unmap_rm(struct rds_ib_connection *ic,
-                         struct rds_ib_send_work *send,
-                         int wc_status)
+static void rds_ib_send_unmap_atomic(struct rds_ib_connection *ic,
+                                    struct rm_atomic_op *op,
+                                    int wc_status)
 {
-       struct rds_message *rm = send->s_rm;
-
-       rdsdebug("ic %p send %p rm %p\n", ic, send, rm);
-
-       ib_dma_unmap_sg(ic->i_cm_id->device,
-                    rm->m_sg, rm->m_nents,
-                    DMA_TO_DEVICE);
-
-       if (rm->m_rdma_op != NULL) {
-               rds_ib_send_unmap_rdma(ic, rm->m_rdma_op);
-
-               /* If the user asked for a completion notification on this
-                * message, we can implement three different semantics:
-                *  1.  Notify when we received the ACK on the RDS message
-                *      that was queued with the RDMA. This provides reliable
-                *      notification of RDMA status at the expense of a one-way
-                *      packet delay.
-                *  2.  Notify when the IB stack gives us the completion event for
-                *      the RDMA operation.
-                *  3.  Notify when the IB stack gives us the completion event for
-                *      the accompanying RDS messages.
-                * Here, we implement approach #3. To implement approach #2,
-                * call rds_rdma_send_complete from the cq_handler. To implement #1,
-                * don't call rds_rdma_send_complete at all, and fall back to the notify
-                * handling in the ACK processing code.
-                *
-                * Note: There's no need to explicitly sync any RDMA buffers using
-                * ib_dma_sync_sg_for_cpu - the completion for the RDMA
-                * operation itself unmapped the RDMA buffers, which takes care
-                * of synching.
-                */
-               rds_ib_send_rdma_complete(rm, wc_status);
+       /* unmap atomic recvbuf */
+       if (op->op_mapped) {
+               ib_dma_unmap_sg(ic->i_cm_id->device, op->op_sg, 1,
+                               DMA_FROM_DEVICE);
+               op->op_mapped = 0;
+       }
 
-               if (rm->m_rdma_op->r_write)
-                       rds_stats_add(s_send_rdma_bytes, rm->m_rdma_op->r_bytes);
-               else
-                       rds_stats_add(s_recv_rdma_bytes, rm->m_rdma_op->r_bytes);
+       rds_ib_send_complete(container_of(op, struct rds_message, atomic),
+                            wc_status, rds_atomic_send_complete);
+
+       if (op->op_type == RDS_ATOMIC_TYPE_CSWP)
+               rds_ib_stats_inc(s_ib_atomic_cswp);
+       else
+               rds_ib_stats_inc(s_ib_atomic_fadd);
+}
+
+/*
+ * Unmap the resources associated with a struct send_work.
+ *
+ * Returns the rm for no good reason other than it is unobtainable
+ * other than by switching on wr.opcode, currently, and the caller,
+ * the event handler, needs it.
+ */
+static struct rds_message *rds_ib_send_unmap_op(struct rds_ib_connection *ic,
+                                               struct rds_ib_send_work *send,
+                                               int wc_status)
+{
+       struct rds_message *rm = NULL;
+
+       /* In the error case, wc.opcode sometimes contains garbage */
+       switch (send->s_wr.opcode) {
+       case IB_WR_SEND:
+               if (send->s_op) {
+                       rm = container_of(send->s_op, struct rds_message, data);
+                       rds_ib_send_unmap_data(ic, send->s_op, wc_status);
+               }
+               break;
+       case IB_WR_RDMA_WRITE:
+       case IB_WR_RDMA_READ:
+               if (send->s_op) {
+                       rm = container_of(send->s_op, struct rds_message, rdma);
+                       rds_ib_send_unmap_rdma(ic, send->s_op, wc_status);
+               }
+               break;
+       case IB_WR_ATOMIC_FETCH_AND_ADD:
+       case IB_WR_ATOMIC_CMP_AND_SWP:
+               if (send->s_op) {
+                       rm = container_of(send->s_op, struct rds_message, atomic);
+                       rds_ib_send_unmap_atomic(ic, send->s_op, wc_status);
+               }
+               break;
+       default:
+               if (printk_ratelimit())
+                       printk(KERN_NOTICE
+                              "RDS/IB: %s: unexpected opcode 0x%x in WR!\n",
+                              __func__, send->s_wr.opcode);
+               break;
        }
 
-       /* If anyone waited for this message to get flushed out, wake
-        * them up now */
-       rds_message_unmapped(rm);
+       send->s_wr.opcode = 0xdead;
 
-       rds_message_put(rm);
-       send->s_rm = NULL;
+       return rm;
 }
 
 void rds_ib_send_init_ring(struct rds_ib_connection *ic)
@@ -133,23 +227,18 @@ void rds_ib_send_init_ring(struct rds_ib_connection *ic)
        for (i = 0, send = ic->i_sends; i < ic->i_send_ring.w_nr; i++, send++) {
                struct ib_sge *sge;
 
-               send->s_rm = NULL;
                send->s_op = NULL;
 
                send->s_wr.wr_id = i;
                send->s_wr.sg_list = send->s_sge;
-               send->s_wr.num_sge = 1;
-               send->s_wr.opcode = IB_WR_SEND;
-               send->s_wr.send_flags = 0;
                send->s_wr.ex.imm_data = 0;
 
-               sge = rds_ib_data_sge(ic, send->s_sge);
-               sge->lkey = ic->i_mr->lkey;
-
-               sge = rds_ib_header_sge(ic, send->s_sge);
+               sge = &send->s_sge[0];
                sge->addr = ic->i_send_hdrs_dma + (i * sizeof(struct rds_header));
                sge->length = sizeof(struct rds_header);
                sge->lkey = ic->i_mr->lkey;
+
+               send->s_sge[1].lkey = ic->i_mr->lkey;
        }
 }
 
@@ -159,15 +248,23 @@ void rds_ib_send_clear_ring(struct rds_ib_connection *ic)
        u32 i;
 
        for (i = 0, send = ic->i_sends; i < ic->i_send_ring.w_nr; i++, send++) {
-               if (send->s_wr.opcode == 0xdead)
-                       continue;
-               if (send->s_rm)
-                       rds_ib_send_unmap_rm(ic, send, IB_WC_WR_FLUSH_ERR);
-               if (send->s_op)
-                       rds_ib_send_unmap_rdma(ic, send->s_op);
+               if (send->s_op && send->s_wr.opcode != 0xdead)
+                       rds_ib_send_unmap_op(ic, send, IB_WC_WR_FLUSH_ERR);
        }
 }
 
+/*
+ * The only fast path caller always has a non-zero nr, so we don't
+ * bother testing nr before performing the atomic sub.
+ */
+static void rds_ib_sub_signaled(struct rds_ib_connection *ic, int nr)
+{
+       if ((atomic_sub_return(nr, &ic->i_signaled_sends) == 0) &&
+           waitqueue_active(&rds_ib_ring_empty_wait))
+               wake_up(&rds_ib_ring_empty_wait);
+       BUG_ON(atomic_read(&ic->i_signaled_sends) < 0);
+}
+
 /*
  * The _oldest/_free ring operations here race cleanly with the alloc/unalloc
  * operations performed in the send path.  As the sender allocs and potentially
@@ -178,12 +275,14 @@ void rds_ib_send_cq_comp_handler(struct ib_cq *cq, void *context)
 {
        struct rds_connection *conn = context;
        struct rds_ib_connection *ic = conn->c_transport_data;
+       struct rds_message *rm = NULL;
        struct ib_wc wc;
        struct rds_ib_send_work *send;
        u32 completed;
        u32 oldest;
        u32 i = 0;
        int ret;
+       int nr_sig = 0;
 
        rdsdebug("cq %p conn %p\n", cq, conn);
        rds_ib_stats_inc(s_ib_tx_cq_call);
@@ -192,8 +291,9 @@ void rds_ib_send_cq_comp_handler(struct ib_cq *cq, void *context)
                rdsdebug("ib_req_notify_cq send failed: %d\n", ret);
 
        while (ib_poll_cq(cq, 1, &wc) > 0) {
-               rdsdebug("wc wr_id 0x%llx status %u byte_len %u imm_data %u\n",
-                        (unsigned long long)wc.wr_id, wc.status, wc.byte_len,
+               rdsdebug("wc wr_id 0x%llx status %u (%s) byte_len %u imm_data %u\n",
+                        (unsigned long long)wc.wr_id, wc.status,
+                        rds_ib_wc_status_str(wc.status), wc.byte_len,
                         be32_to_cpu(wc.ex.imm_data));
                rds_ib_stats_inc(s_ib_tx_cq_event);
 
@@ -210,51 +310,30 @@ void rds_ib_send_cq_comp_handler(struct ib_cq *cq, void *context)
 
                for (i = 0; i < completed; i++) {
                        send = &ic->i_sends[oldest];
+                       if (send->s_wr.send_flags & IB_SEND_SIGNALED)
+                               nr_sig++;
 
-                       /* In the error case, wc.opcode sometimes contains garbage */
-                       switch (send->s_wr.opcode) {
-                       case IB_WR_SEND:
-                               if (send->s_rm)
-                                       rds_ib_send_unmap_rm(ic, send, wc.status);
-                               break;
-                       case IB_WR_RDMA_WRITE:
-                       case IB_WR_RDMA_READ:
-                               /* Nothing to be done - the SG list will be unmapped
-                                * when the SEND completes. */
-                               break;
-                       default:
-                               if (printk_ratelimit())
-                                       printk(KERN_NOTICE
-                                               "RDS/IB: %s: unexpected opcode 0x%x in WR!\n",
-                                               __func__, send->s_wr.opcode);
-                               break;
-                       }
+                       rm = rds_ib_send_unmap_op(ic, send, wc.status);
 
-                       send->s_wr.opcode = 0xdead;
-                       send->s_wr.num_sge = 1;
                        if (send->s_queued + HZ/2 < jiffies)
                                rds_ib_stats_inc(s_ib_tx_stalled);
 
-                       /* If a RDMA operation produced an error, signal this right
-                        * away. If we don't, the subsequent SEND that goes with this
-                        * RDMA will be canceled with ERR_WFLUSH, and the application
-                        * never learn that the RDMA failed. */
-                       if (unlikely(wc.status == IB_WC_REM_ACCESS_ERR && send->s_op)) {
-                               struct rds_message *rm;
-
-                               rm = rds_send_get_message(conn, send->s_op);
-                               if (rm) {
-                                       if (rm->m_rdma_op)
-                                               rds_ib_send_unmap_rdma(ic, rm->m_rdma_op);
-                                       rds_ib_send_rdma_complete(rm, wc.status);
-                                       rds_message_put(rm);
+                       if (send->s_op) {
+                               if (send->s_op == rm->m_final_op) {
+                                       /* If anyone waited for this message to get flushed out, wake
+                                        * them up now */
+                                       rds_message_unmapped(rm);
                                }
+                               rds_message_put(rm);
+                               send->s_op = NULL;
                        }
 
                        oldest = (oldest + 1) % ic->i_send_ring.w_nr;
                }
 
                rds_ib_ring_free(&ic->i_send_ring, completed);
+               rds_ib_sub_signaled(ic, nr_sig);
+               nr_sig = 0;
 
                if (test_and_clear_bit(RDS_LL_SEND_FULL, &conn->c_flags) ||
                    test_bit(0, &conn->c_map_queued))
@@ -262,10 +341,10 @@ void rds_ib_send_cq_comp_handler(struct ib_cq *cq, void *context)
 
                /* We expect errors as the qp is drained during shutdown */
                if (wc.status != IB_WC_SUCCESS && rds_conn_up(conn)) {
-                       rds_ib_conn_error(conn,
-                               "send completion on %pI4 "
-                               "had status %u, disconnecting and reconnecting\n",
-                               &conn->c_faddr, wc.status);
+                       rds_ib_conn_error(conn, "send completion on %pI4 had status "
+                                         "%u (%s), disconnecting and reconnecting\n",
+                                         &conn->c_faddr, wc.status,
+                                         rds_ib_wc_status_str(wc.status));
                }
        }
 }
@@ -294,7 +373,7 @@ void rds_ib_send_cq_comp_handler(struct ib_cq *cq, void *context)
  * credits (see rds_ib_send_add_credits below).
  *
  * The RDS send code is essentially single-threaded; rds_send_xmit
- * grabs c_send_lock to ensure exclusive access to the send ring.
+ * sets RDS_IN_XMIT to ensure exclusive access to the send ring.
  * However, the ACK sending code is independent and can race with
  * message SENDs.
  *
@@ -413,40 +492,21 @@ void rds_ib_advertise_credits(struct rds_connection *conn, unsigned int posted)
                set_bit(IB_ACK_REQUESTED, &ic->i_ack_flags);
 }
 
-static inline void
-rds_ib_xmit_populate_wr(struct rds_ib_connection *ic,
-               struct rds_ib_send_work *send, unsigned int pos,
-               unsigned long buffer, unsigned int length,
-               int send_flags)
+static inline int rds_ib_set_wr_signal_state(struct rds_ib_connection *ic,
+                                            struct rds_ib_send_work *send,
+                                            bool notify)
 {
-       struct ib_sge *sge;
-
-       WARN_ON(pos != send - ic->i_sends);
-
-       send->s_wr.send_flags = send_flags;
-       send->s_wr.opcode = IB_WR_SEND;
-       send->s_wr.num_sge = 2;
-       send->s_wr.next = NULL;
-       send->s_queued = jiffies;
-       send->s_op = NULL;
-
-       if (length != 0) {
-               sge = rds_ib_data_sge(ic, send->s_sge);
-               sge->addr = buffer;
-               sge->length = length;
-               sge->lkey = ic->i_mr->lkey;
-
-               sge = rds_ib_header_sge(ic, send->s_sge);
-       } else {
-               /* We're sending a packet with no payload. There is only
-                * one SGE */
-               send->s_wr.num_sge = 1;
-               sge = &send->s_sge[0];
+       /*
+        * We want to delay signaling completions just enough to get
+        * the batching benefits but not so much that we create dead time
+        * on the wire.
+        */
+       if (ic->i_unsignaled_wrs-- == 0 || notify) {
+               ic->i_unsignaled_wrs = rds_ib_sysctl_max_unsig_wrs;
+               send->s_wr.send_flags |= IB_SEND_SIGNALED;
+               return 1;
        }
-
-       sge->addr = ic->i_send_hdrs_dma + (pos * sizeof(struct rds_header));
-       sge->length = sizeof(struct rds_header);
-       sge->lkey = ic->i_mr->lkey;
+       return 0;
 }
 
 /*
@@ -475,13 +535,14 @@ int rds_ib_xmit(struct rds_connection *conn, struct rds_message *rm,
        u32 pos;
        u32 i;
        u32 work_alloc;
-       u32 credit_alloc;
+       u32 credit_alloc = 0;
        u32 posted;
        u32 adv_credits = 0;
        int send_flags = 0;
-       int sent;
+       int bytes_sent = 0;
        int ret;
        int flow_controlled = 0;
+       int nr_sig = 0;
 
        BUG_ON(off % RDS_FRAG_SIZE);
        BUG_ON(hdr_off != 0 && hdr_off != sizeof(struct rds_header));
@@ -507,14 +568,13 @@ int rds_ib_xmit(struct rds_connection *conn, struct rds_message *rm,
                goto out;
        }
 
-       credit_alloc = work_alloc;
        if (ic->i_flowctl) {
                credit_alloc = rds_ib_send_grab_credits(ic, work_alloc, &posted, 0, RDS_MAX_ADV_CREDIT);
                adv_credits += posted;
                if (credit_alloc < work_alloc) {
                        rds_ib_ring_unalloc(&ic->i_send_ring, work_alloc - credit_alloc);
                        work_alloc = credit_alloc;
-                       flow_controlled++;
+                       flow_controlled = 1;
                }
                if (work_alloc == 0) {
                        set_bit(RDS_LL_SEND_FULL, &conn->c_flags);
@@ -525,31 +585,25 @@ int rds_ib_xmit(struct rds_connection *conn, struct rds_message *rm,
        }
 
        /* map the message the first time we see it */
-       if (ic->i_rm == NULL) {
-               /*
-               printk(KERN_NOTICE "rds_ib_xmit prep msg dport=%u flags=0x%x len=%d\n",
-                               be16_to_cpu(rm->m_inc.i_hdr.h_dport),
-                               rm->m_inc.i_hdr.h_flags,
-                               be32_to_cpu(rm->m_inc.i_hdr.h_len));
-                  */
-               if (rm->m_nents) {
-                       rm->m_count = ib_dma_map_sg(dev,
-                                        rm->m_sg, rm->m_nents, DMA_TO_DEVICE);
-                       rdsdebug("ic %p mapping rm %p: %d\n", ic, rm, rm->m_count);
-                       if (rm->m_count == 0) {
+       if (!ic->i_data_op) {
+               if (rm->data.op_nents) {
+                       rm->data.op_count = ib_dma_map_sg(dev,
+                                                         rm->data.op_sg,
+                                                         rm->data.op_nents,
+                                                         DMA_TO_DEVICE);
+                       rdsdebug("ic %p mapping rm %p: %d\n", ic, rm, rm->data.op_count);
+                       if (rm->data.op_count == 0) {
                                rds_ib_stats_inc(s_ib_tx_sg_mapping_failure);
                                rds_ib_ring_unalloc(&ic->i_send_ring, work_alloc);
                                ret = -ENOMEM; /* XXX ? */
                                goto out;
                        }
                } else {
-                       rm->m_count = 0;
+                       rm->data.op_count = 0;
                }
 
-               ic->i_unsignaled_wrs = rds_ib_sysctl_max_unsig_wrs;
-               ic->i_unsignaled_bytes = rds_ib_sysctl_max_unsig_bytes;
                rds_message_addref(rm);
-               ic->i_rm = rm;
+               ic->i_data_op = &rm->data;
 
                /* Finalize the header */
                if (test_bit(RDS_MSG_ACK_REQUIRED, &rm->m_flags))
@@ -559,10 +613,10 @@ int rds_ib_xmit(struct rds_connection *conn, struct rds_message *rm,
 
                /* If it has a RDMA op, tell the peer we did it. This is
                 * used by the peer to release use-once RDMA MRs. */
-               if (rm->m_rdma_op) {
+               if (rm->rdma.op_active) {
                        struct rds_ext_header_rdma ext_hdr;
 
-                       ext_hdr.h_rdma_rkey = cpu_to_be32(rm->m_rdma_op->r_key);
+                       ext_hdr.h_rdma_rkey = cpu_to_be32(rm->rdma.op_rkey);
                        rds_message_add_extension(&rm->m_inc.i_hdr,
                                        RDS_EXTHDR_RDMA, &ext_hdr, sizeof(ext_hdr));
                }
@@ -582,99 +636,77 @@ int rds_ib_xmit(struct rds_connection *conn, struct rds_message *rm,
                /*
                 * Update adv_credits since we reset the ACK_REQUIRED bit.
                 */
-               rds_ib_send_grab_credits(ic, 0, &posted, 1, RDS_MAX_ADV_CREDIT - adv_credits);
-               adv_credits += posted;
-               BUG_ON(adv_credits > 255);
+               if (ic->i_flowctl) {
+                       rds_ib_send_grab_credits(ic, 0, &posted, 1, RDS_MAX_ADV_CREDIT - adv_credits);
+                       adv_credits += posted;
+                       BUG_ON(adv_credits > 255);
+               }
        }
 
-       send = &ic->i_sends[pos];
-       first = send;
-       prev = NULL;
-       scat = &rm->m_sg[sg];
-       sent = 0;
-       i = 0;
-
        /* Sometimes you want to put a fence between an RDMA
         * READ and the following SEND.
         * We could either do this all the time
         * or when requested by the user. Right now, we let
         * the application choose.
         */
-       if (rm->m_rdma_op && rm->m_rdma_op->r_fence)
+       if (rm->rdma.op_active && rm->rdma.op_fence)
                send_flags = IB_SEND_FENCE;
 
-       /*
-        * We could be copying the header into the unused tail of the page.
-        * That would need to be changed in the future when those pages might
-        * be mapped userspace pages or page cache pages.  So instead we always
-        * use a second sge and our long-lived ring of mapped headers.  We send
-        * the header after the data so that the data payload can be aligned on
-        * the receiver.
-        */
+       /* Each frag gets a header. Msgs may be 0 bytes */
+       send = &ic->i_sends[pos];
+       first = send;
+       prev = NULL;
+       scat = &ic->i_data_op->op_sg[sg];
+       i = 0;
+       do {
+               unsigned int len = 0;
 
-       /* handle a 0-len message */
-       if (be32_to_cpu(rm->m_inc.i_hdr.h_len) == 0) {
-               rds_ib_xmit_populate_wr(ic, send, pos, 0, 0, send_flags);
-               goto add_header;
-       }
+               /* Set up the header */
+               send->s_wr.send_flags = send_flags;
+               send->s_wr.opcode = IB_WR_SEND;
+               send->s_wr.num_sge = 1;
+               send->s_wr.next = NULL;
+               send->s_queued = jiffies;
+               send->s_op = NULL;
 
-       /* if there's data reference it with a chain of work reqs */
-       for (; i < work_alloc && scat != &rm->m_sg[rm->m_count]; i++) {
-               unsigned int len;
+               send->s_sge[0].addr = ic->i_send_hdrs_dma
+                       + (pos * sizeof(struct rds_header));
+               send->s_sge[0].length = sizeof(struct rds_header);
 
-               send = &ic->i_sends[pos];
+               memcpy(&ic->i_send_hdrs[pos], &rm->m_inc.i_hdr, sizeof(struct rds_header));
 
-               len = min(RDS_FRAG_SIZE, ib_sg_dma_len(dev, scat) - off);
-               rds_ib_xmit_populate_wr(ic, send, pos,
-                               ib_sg_dma_address(dev, scat) + off, len,
-                               send_flags);
+               /* Set up the data, if present */
+               if (i < work_alloc
+                   && scat != &rm->data.op_sg[rm->data.op_count]) {
+                       len = min(RDS_FRAG_SIZE, ib_sg_dma_len(dev, scat) - off);
+                       send->s_wr.num_sge = 2;
 
-               /*
-                * We want to delay signaling completions just enough to get
-                * the batching benefits but not so much that we create dead time
-                * on the wire.
-                */
-               if (ic->i_unsignaled_wrs-- == 0) {
-                       ic->i_unsignaled_wrs = rds_ib_sysctl_max_unsig_wrs;
-                       send->s_wr.send_flags |= IB_SEND_SIGNALED | IB_SEND_SOLICITED;
-               }
+                       send->s_sge[1].addr = ib_sg_dma_address(dev, scat) + off;
+                       send->s_sge[1].length = len;
 
-               ic->i_unsignaled_bytes -= len;
-               if (ic->i_unsignaled_bytes <= 0) {
-                       ic->i_unsignaled_bytes = rds_ib_sysctl_max_unsig_bytes;
-                       send->s_wr.send_flags |= IB_SEND_SIGNALED | IB_SEND_SOLICITED;
+                       bytes_sent += len;
+                       off += len;
+                       if (off == ib_sg_dma_len(dev, scat)) {
+                               scat++;
+                               off = 0;
+                       }
                }
 
+               rds_ib_set_wr_signal_state(ic, send, 0);
+
                /*
                 * Always signal the last one if we're stopping due to flow control.
                 */
-               if (flow_controlled && i == (work_alloc-1))
+               if (ic->i_flowctl && flow_controlled && i == (work_alloc-1))
                        send->s_wr.send_flags |= IB_SEND_SIGNALED | IB_SEND_SOLICITED;
 
+               if (send->s_wr.send_flags & IB_SEND_SIGNALED)
+                       nr_sig++;
+
                rdsdebug("send %p wr %p num_sge %u next %p\n", send,
                         &send->s_wr, send->s_wr.num_sge, send->s_wr.next);
 
-               sent += len;
-               off += len;
-               if (off == ib_sg_dma_len(dev, scat)) {
-                       scat++;
-                       off = 0;
-               }
-
-add_header:
-               /* Tack on the header after the data. The header SGE should already
-                * have been set up to point to the right header buffer. */
-               memcpy(&ic->i_send_hdrs[pos], &rm->m_inc.i_hdr, sizeof(struct rds_header));
-
-               if (0) {
-                       struct rds_header *hdr = &ic->i_send_hdrs[pos];
-
-                       printk(KERN_NOTICE "send WR dport=%u flags=0x%x len=%d\n",
-                               be16_to_cpu(hdr->h_dport),
-                               hdr->h_flags,
-                               be32_to_cpu(hdr->h_len));
-               }
-               if (adv_credits) {
+               if (ic->i_flowctl && adv_credits) {
                        struct rds_header *hdr = &ic->i_send_hdrs[pos];
 
                        /* add credit and redo the header checksum */
@@ -689,20 +721,25 @@ add_header:
                prev = send;
 
                pos = (pos + 1) % ic->i_send_ring.w_nr;
-       }
+               send = &ic->i_sends[pos];
+               i++;
+
+       } while (i < work_alloc
+                && scat != &rm->data.op_sg[rm->data.op_count]);
 
        /* Account the RDS header in the number of bytes we sent, but just once.
         * The caller has no concept of fragmentation. */
        if (hdr_off == 0)
-               sent += sizeof(struct rds_header);
+               bytes_sent += sizeof(struct rds_header);
 
        /* if we finished the message then send completion owns it */
-       if (scat == &rm->m_sg[rm->m_count]) {
-               prev->s_rm = ic->i_rm;
-               prev->s_wr.send_flags |= IB_SEND_SIGNALED | IB_SEND_SOLICITED;
-               ic->i_rm = NULL;
+       if (scat == &rm->data.op_sg[rm->data.op_count]) {
+               prev->s_op = ic->i_data_op;
+               prev->s_wr.send_flags |= IB_SEND_SOLICITED;
+               ic->i_data_op = NULL;
        }
 
+       /* Put back wrs & credits we didn't use */
        if (i < work_alloc) {
                rds_ib_ring_unalloc(&ic->i_send_ring, work_alloc - i);
                work_alloc = i;
@@ -710,6 +747,9 @@ add_header:
        if (ic->i_flowctl && i < credit_alloc)
                rds_ib_send_add_credits(conn, credit_alloc - i);
 
+       if (nr_sig)
+               atomic_add(nr_sig, &ic->i_signaled_sends);
+
        /* XXX need to worry about failed_wr and partial sends. */
        failed_wr = &first->s_wr;
        ret = ib_post_send(ic->i_cm_id->qp, &first->s_wr, &failed_wr);
@@ -720,32 +760,127 @@ add_header:
                printk(KERN_WARNING "RDS/IB: ib_post_send to %pI4 "
                       "returned %d\n", &conn->c_faddr, ret);
                rds_ib_ring_unalloc(&ic->i_send_ring, work_alloc);
-               if (prev->s_rm) {
-                       ic->i_rm = prev->s_rm;
-                       prev->s_rm = NULL;
+               rds_ib_sub_signaled(ic, nr_sig);
+               if (prev->s_op) {
+                       ic->i_data_op = prev->s_op;
+                       prev->s_op = NULL;
                }
 
                rds_ib_conn_error(ic->conn, "ib_post_send failed\n");
                goto out;
        }
 
-       ret = sent;
+       ret = bytes_sent;
 out:
        BUG_ON(adv_credits);
        return ret;
 }
 
-int rds_ib_xmit_rdma(struct rds_connection *conn, struct rds_rdma_op *op)
+/*
+ * Issue atomic operation.
+ * A simplified version of the rdma case, we always map 1 SG, and
+ * only 8 bytes, for the return value from the atomic operation.
+ */
+int rds_ib_xmit_atomic(struct rds_connection *conn, struct rm_atomic_op *op)
+{
+       struct rds_ib_connection *ic = conn->c_transport_data;
+       struct rds_ib_send_work *send = NULL;
+       struct ib_send_wr *failed_wr;
+       struct rds_ib_device *rds_ibdev;
+       u32 pos;
+       u32 work_alloc;
+       int ret;
+       int nr_sig = 0;
+
+       rds_ibdev = ib_get_client_data(ic->i_cm_id->device, &rds_ib_client);
+
+       work_alloc = rds_ib_ring_alloc(&ic->i_send_ring, 1, &pos);
+       if (work_alloc != 1) {
+               rds_ib_ring_unalloc(&ic->i_send_ring, work_alloc);
+               rds_ib_stats_inc(s_ib_tx_ring_full);
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       /* address of send request in ring */
+       send = &ic->i_sends[pos];
+       send->s_queued = jiffies;
+
+       if (op->op_type == RDS_ATOMIC_TYPE_CSWP) {
+               send->s_wr.opcode = IB_WR_MASKED_ATOMIC_CMP_AND_SWP;
+               send->s_wr.wr.atomic.compare_add = op->op_m_cswp.compare;
+               send->s_wr.wr.atomic.swap = op->op_m_cswp.swap;
+               send->s_wr.wr.atomic.compare_add_mask = op->op_m_cswp.compare_mask;
+               send->s_wr.wr.atomic.swap_mask = op->op_m_cswp.swap_mask;
+       } else { /* FADD */
+               send->s_wr.opcode = IB_WR_MASKED_ATOMIC_FETCH_AND_ADD;
+               send->s_wr.wr.atomic.compare_add = op->op_m_fadd.add;
+               send->s_wr.wr.atomic.swap = 0;
+               send->s_wr.wr.atomic.compare_add_mask = op->op_m_fadd.nocarry_mask;
+               send->s_wr.wr.atomic.swap_mask = 0;
+       }
+       nr_sig = rds_ib_set_wr_signal_state(ic, send, op->op_notify);
+       send->s_wr.num_sge = 1;
+       send->s_wr.next = NULL;
+       send->s_wr.wr.atomic.remote_addr = op->op_remote_addr;
+       send->s_wr.wr.atomic.rkey = op->op_rkey;
+       send->s_op = op;
+       rds_message_addref(container_of(send->s_op, struct rds_message, atomic));
+
+       /* map 8 byte retval buffer to the device */
+       ret = ib_dma_map_sg(ic->i_cm_id->device, op->op_sg, 1, DMA_FROM_DEVICE);
+       rdsdebug("ic %p mapping atomic op %p. mapped %d pg\n", ic, op, ret);
+       if (ret != 1) {
+               rds_ib_ring_unalloc(&ic->i_send_ring, work_alloc);
+               rds_ib_stats_inc(s_ib_tx_sg_mapping_failure);
+               ret = -ENOMEM; /* XXX ? */
+               goto out;
+       }
+
+       /* Convert our struct scatterlist to struct ib_sge */
+       send->s_sge[0].addr = ib_sg_dma_address(ic->i_cm_id->device, op->op_sg);
+       send->s_sge[0].length = ib_sg_dma_len(ic->i_cm_id->device, op->op_sg);
+       send->s_sge[0].lkey = ic->i_mr->lkey;
+
+       rdsdebug("rva %Lx rpa %Lx len %u\n", op->op_remote_addr,
+                send->s_sge[0].addr, send->s_sge[0].length);
+
+       if (nr_sig)
+               atomic_add(nr_sig, &ic->i_signaled_sends);
+
+       failed_wr = &send->s_wr;
+       ret = ib_post_send(ic->i_cm_id->qp, &send->s_wr, &failed_wr);
+       rdsdebug("ic %p send %p (wr %p) ret %d wr %p\n", ic,
+                send, &send->s_wr, ret, failed_wr);
+       BUG_ON(failed_wr != &send->s_wr);
+       if (ret) {
+               printk(KERN_WARNING "RDS/IB: atomic ib_post_send to %pI4 "
+                      "returned %d\n", &conn->c_faddr, ret);
+               rds_ib_ring_unalloc(&ic->i_send_ring, work_alloc);
+               rds_ib_sub_signaled(ic, nr_sig);
+               goto out;
+       }
+
+       if (unlikely(failed_wr != &send->s_wr)) {
+               printk(KERN_WARNING "RDS/IB: atomic ib_post_send() rc=%d, but failed_wqe updated!\n", ret);
+               BUG_ON(failed_wr != &send->s_wr);
+       }
+
+out:
+       return ret;
+}
+
+int rds_ib_xmit_rdma(struct rds_connection *conn, struct rm_rdma_op *op)
 {
        struct rds_ib_connection *ic = conn->c_transport_data;
        struct rds_ib_send_work *send = NULL;
        struct rds_ib_send_work *first;
        struct rds_ib_send_work *prev;
        struct ib_send_wr *failed_wr;
-       struct rds_ib_device *rds_ibdev;
        struct scatterlist *scat;
        unsigned long len;
-       u64 remote_addr = op->r_remote_addr;
+       u64 remote_addr = op->op_remote_addr;
+       u32 max_sge = ic->rds_ibdev->max_sge;
        u32 pos;
        u32 work_alloc;
        u32 i;
@@ -753,29 +888,28 @@ int rds_ib_xmit_rdma(struct rds_connection *conn, struct rds_rdma_op *op)
        int sent;
        int ret;
        int num_sge;
-
-       rds_ibdev = ib_get_client_data(ic->i_cm_id->device, &rds_ib_client);
-
-       /* map the message the first time we see it */
-       if (!op->r_mapped) {
-               op->r_count = ib_dma_map_sg(ic->i_cm_id->device,
-                                       op->r_sg, op->r_nents, (op->r_write) ?
-                                       DMA_TO_DEVICE : DMA_FROM_DEVICE);
-               rdsdebug("ic %p mapping op %p: %d\n", ic, op, op->r_count);
-               if (op->r_count == 0) {
+       int nr_sig = 0;
+
+       /* map the op the first time we see it */
+       if (!op->op_mapped) {
+               op->op_count = ib_dma_map_sg(ic->i_cm_id->device,
+                                            op->op_sg, op->op_nents, (op->op_write) ?
+                                            DMA_TO_DEVICE : DMA_FROM_DEVICE);
+               rdsdebug("ic %p mapping op %p: %d\n", ic, op, op->op_count);
+               if (op->op_count == 0) {
                        rds_ib_stats_inc(s_ib_tx_sg_mapping_failure);
                        ret = -ENOMEM; /* XXX ? */
                        goto out;
                }
 
-               op->r_mapped = 1;
+               op->op_mapped = 1;
        }
 
        /*
         * Instead of knowing how to return a partial rdma read/write we insist that there
         * be enough work requests to send the entire message.
         */
-       i = ceil(op->r_count, rds_ibdev->max_sge);
+       i = ceil(op->op_count, max_sge);
 
        work_alloc = rds_ib_ring_alloc(&ic->i_send_ring, i, &pos);
        if (work_alloc != i) {
@@ -788,30 +922,24 @@ int rds_ib_xmit_rdma(struct rds_connection *conn, struct rds_rdma_op *op)
        send = &ic->i_sends[pos];
        first = send;
        prev = NULL;
-       scat = &op->r_sg[0];
+       scat = &op->op_sg[0];
        sent = 0;
-       num_sge = op->r_count;
+       num_sge = op->op_count;
 
-       for (i = 0; i < work_alloc && scat != &op->r_sg[op->r_count]; i++) {
+       for (i = 0; i < work_alloc && scat != &op->op_sg[op->op_count]; i++) {
                send->s_wr.send_flags = 0;
                send->s_queued = jiffies;
-               /*
-                * We want to delay signaling completions just enough to get
-                * the batching benefits but not so much that we create dead time on the wire.
-                */
-               if (ic->i_unsignaled_wrs-- == 0) {
-                       ic->i_unsignaled_wrs = rds_ib_sysctl_max_unsig_wrs;
-                       send->s_wr.send_flags = IB_SEND_SIGNALED;
-               }
+               send->s_op = NULL;
+
+               nr_sig += rds_ib_set_wr_signal_state(ic, send, op->op_notify);
 
-               send->s_wr.opcode = op->r_write ? IB_WR_RDMA_WRITE : IB_WR_RDMA_READ;
+               send->s_wr.opcode = op->op_write ? IB_WR_RDMA_WRITE : IB_WR_RDMA_READ;
                send->s_wr.wr.rdma.remote_addr = remote_addr;
-               send->s_wr.wr.rdma.rkey = op->r_key;
-               send->s_op = op;
+               send->s_wr.wr.rdma.rkey = op->op_rkey;
 
-               if (num_sge > rds_ibdev->max_sge) {
-                       send->s_wr.num_sge = rds_ibdev->max_sge;
-                       num_sge -= rds_ibdev->max_sge;
+               if (num_sge > max_sge) {
+                       send->s_wr.num_sge = max_sge;
+                       num_sge -= max_sge;
                } else {
                        send->s_wr.num_sge = num_sge;
                }
@@ -821,7 +949,7 @@ int rds_ib_xmit_rdma(struct rds_connection *conn, struct rds_rdma_op *op)
                if (prev)
                        prev->s_wr.next = &send->s_wr;
 
-               for (j = 0; j < send->s_wr.num_sge && scat != &op->r_sg[op->r_count]; j++) {
+               for (j = 0; j < send->s_wr.num_sge && scat != &op->op_sg[op->op_count]; j++) {
                        len = ib_sg_dma_len(ic->i_cm_id->device, scat);
                        send->s_sge[j].addr =
                                 ib_sg_dma_address(ic->i_cm_id->device, scat);
@@ -843,15 +971,20 @@ int rds_ib_xmit_rdma(struct rds_connection *conn, struct rds_rdma_op *op)
                        send = ic->i_sends;
        }
 
-       /* if we finished the message then send completion owns it */
-       if (scat == &op->r_sg[op->r_count])
-               prev->s_wr.send_flags = IB_SEND_SIGNALED;
+       /* give a reference to the last op */
+       if (scat == &op->op_sg[op->op_count]) {
+               prev->s_op = op;
+               rds_message_addref(container_of(op, struct rds_message, rdma));
+       }
 
        if (i < work_alloc) {
                rds_ib_ring_unalloc(&ic->i_send_ring, work_alloc - i);
                work_alloc = i;
        }
 
+       if (nr_sig)
+               atomic_add(nr_sig, &ic->i_signaled_sends);
+
        failed_wr = &first->s_wr;
        ret = ib_post_send(ic->i_cm_id->qp, &first->s_wr, &failed_wr);
        rdsdebug("ic %p first %p (wr %p) ret %d wr %p\n", ic,
@@ -861,6 +994,7 @@ int rds_ib_xmit_rdma(struct rds_connection *conn, struct rds_rdma_op *op)
                printk(KERN_WARNING "RDS/IB: rdma ib_post_send to %pI4 "
                       "returned %d\n", &conn->c_faddr, ret);
                rds_ib_ring_unalloc(&ic->i_send_ring, work_alloc);
+               rds_ib_sub_signaled(ic, nr_sig);
                goto out;
        }
 
index d2c904dd6fbcb9e1eeb275f84cc062a273bb98ec..2d5965d6e97c039517d219bfdad3f28f7437b1d7 100644 (file)
@@ -67,6 +67,8 @@ static const char *const rds_ib_stat_names[] = {
        "ib_rdma_mr_pool_flush",
        "ib_rdma_mr_pool_wait",
        "ib_rdma_mr_pool_depleted",
+       "ib_atomic_cswp",
+       "ib_atomic_fadd",
 };
 
 unsigned int rds_ib_stats_info_copy(struct rds_info_iterator *iter,
index 03f01cb4e0fee40487585088b9a6a0b2d9219049..fc3da37220fd671133326d5c915ae6f8a947c644 100644 (file)
@@ -49,10 +49,6 @@ unsigned long rds_ib_sysctl_max_unsig_wrs = 16;
 static unsigned long rds_ib_sysctl_max_unsig_wr_min = 1;
 static unsigned long rds_ib_sysctl_max_unsig_wr_max = 64;
 
-unsigned long rds_ib_sysctl_max_unsig_bytes = (16 << 20);
-static unsigned long rds_ib_sysctl_max_unsig_bytes_min = 1;
-static unsigned long rds_ib_sysctl_max_unsig_bytes_max = ~0UL;
-
 /*
  * This sysctl does nothing.
  *
@@ -93,15 +89,6 @@ ctl_table rds_ib_sysctl_table[] = {
                .extra1         = &rds_ib_sysctl_max_unsig_wr_min,
                .extra2         = &rds_ib_sysctl_max_unsig_wr_max,
        },
-       {
-               .procname       = "max_unsignaled_bytes",
-               .data           = &rds_ib_sysctl_max_unsig_bytes,
-               .maxlen         = sizeof(unsigned long),
-               .mode           = 0644,
-               .proc_handler   = proc_doulongvec_minmax,
-               .extra1         = &rds_ib_sysctl_max_unsig_bytes_min,
-               .extra2         = &rds_ib_sysctl_max_unsig_bytes_max,
-       },
        {
                .procname       = "max_recv_allocation",
                .data           = &rds_ib_sysctl_max_recv_allocation,
@@ -132,10 +119,10 @@ void rds_ib_sysctl_exit(void)
                unregister_sysctl_table(rds_ib_sysctl_hdr);
 }
 
-int __init rds_ib_sysctl_init(void)
+int rds_ib_sysctl_init(void)
 {
        rds_ib_sysctl_hdr = register_sysctl_paths(rds_ib_sysctl_path, rds_ib_sysctl_table);
-       if (rds_ib_sysctl_hdr == NULL)
+       if (!rds_ib_sysctl_hdr)
                return -ENOMEM;
        return 0;
 }
index c45c4173a44d44eb9ceee633e0cec271f2182411..4fdf1b6e84fff6fd25b2040544245921332b9f89 100644 (file)
@@ -76,7 +76,7 @@ void rds_info_register_func(int optname, rds_info_func func)
        BUG_ON(optname < RDS_INFO_FIRST || optname > RDS_INFO_LAST);
 
        spin_lock(&rds_info_lock);
-       BUG_ON(rds_info_funcs[offset] != NULL);
+       BUG_ON(rds_info_funcs[offset]);
        rds_info_funcs[offset] = func;
        spin_unlock(&rds_info_lock);
 }
@@ -102,7 +102,7 @@ EXPORT_SYMBOL_GPL(rds_info_deregister_func);
  */
 void rds_info_iter_unmap(struct rds_info_iterator *iter)
 {
-       if (iter->addr != NULL) {
+       if (iter->addr) {
                kunmap_atomic(iter->addr, KM_USER0);
                iter->addr = NULL;
        }
@@ -117,7 +117,7 @@ void rds_info_copy(struct rds_info_iterator *iter, void *data,
        unsigned long this;
 
        while (bytes) {
-               if (iter->addr == NULL)
+               if (!iter->addr)
                        iter->addr = kmap_atomic(*iter->pages, KM_USER0);
 
                this = min(bytes, PAGE_SIZE - iter->offset);
@@ -188,7 +188,7 @@ int rds_info_getsockopt(struct socket *sock, int optname, char __user *optval,
                        >> PAGE_SHIFT;
 
        pages = kmalloc(nr_pages * sizeof(struct page *), GFP_KERNEL);
-       if (pages == NULL) {
+       if (!pages) {
                ret = -ENOMEM;
                goto out;
        }
@@ -206,7 +206,7 @@ int rds_info_getsockopt(struct socket *sock, int optname, char __user *optval,
 
 call_func:
        func = rds_info_funcs[optname - RDS_INFO_FIRST];
-       if (func == NULL) {
+       if (!func) {
                ret = -ENOPROTOOPT;
                goto out;
        }
@@ -234,7 +234,7 @@ call_func:
                ret = -EFAULT;
 
 out:
-       for (i = 0; pages != NULL && i < nr_pages; i++)
+       for (i = 0; pages && i < nr_pages; i++)
                put_page(pages[i]);
        kfree(pages);
 
index c8f3d3525cb9b187daeca402f71cb5b88356ce41..56808cac0fc795dc1564b1928f816be1502473ce 100644 (file)
@@ -264,7 +264,6 @@ struct rds_transport rds_iw_transport = {
        .laddr_check            = rds_iw_laddr_check,
        .xmit_complete          = rds_iw_xmit_complete,
        .xmit                   = rds_iw_xmit,
-       .xmit_cong_map          = NULL,
        .xmit_rdma              = rds_iw_xmit_rdma,
        .recv                   = rds_iw_recv,
        .conn_alloc             = rds_iw_conn_alloc,
@@ -272,7 +271,6 @@ struct rds_transport rds_iw_transport = {
        .conn_connect           = rds_iw_conn_connect,
        .conn_shutdown          = rds_iw_conn_shutdown,
        .inc_copy_to_user       = rds_iw_inc_copy_to_user,
-       .inc_purge              = rds_iw_inc_purge,
        .inc_free               = rds_iw_inc_free,
        .cm_initiate_connect    = rds_iw_cm_initiate_connect,
        .cm_handle_connect      = rds_iw_cm_handle_connect,
@@ -289,7 +287,7 @@ struct rds_transport rds_iw_transport = {
        .t_prefer_loopback      = 1,
 };
 
-int __init rds_iw_init(void)
+int rds_iw_init(void)
 {
        int ret;
 
index eef2f0c2847604078a326df106c09403520410e8..543e665fafe3ae2cb92e3772425a79c1a6f95ffc 100644 (file)
@@ -70,7 +70,7 @@ struct rds_iw_send_work {
        struct rds_message      *s_rm;
 
        /* We should really put these into a union: */
-       struct rds_rdma_op      *s_op;
+       struct rm_rdma_op       *s_op;
        struct rds_iw_mapping   *s_mapping;
        struct ib_mr            *s_mr;
        struct ib_fast_reg_page_list *s_page_list;
@@ -284,7 +284,7 @@ void rds_iw_conn_free(void *arg);
 int rds_iw_conn_connect(struct rds_connection *conn);
 void rds_iw_conn_shutdown(struct rds_connection *conn);
 void rds_iw_state_change(struct sock *sk);
-int __init rds_iw_listen_init(void);
+int rds_iw_listen_init(void);
 void rds_iw_listen_stop(void);
 void __rds_iw_conn_error(struct rds_connection *conn, const char *, ...);
 int rds_iw_cm_handle_connect(struct rdma_cm_id *cm_id,
@@ -321,12 +321,11 @@ void rds_iw_flush_mrs(void);
 void rds_iw_remove_cm_id(struct rds_iw_device *rds_iwdev, struct rdma_cm_id *cm_id);
 
 /* ib_recv.c */
-int __init rds_iw_recv_init(void);
+int rds_iw_recv_init(void);
 void rds_iw_recv_exit(void);
 int rds_iw_recv(struct rds_connection *conn);
 int rds_iw_recv_refill(struct rds_connection *conn, gfp_t kptr_gfp,
                       gfp_t page_gfp, int prefill);
-void rds_iw_inc_purge(struct rds_incoming *inc);
 void rds_iw_inc_free(struct rds_incoming *inc);
 int rds_iw_inc_copy_to_user(struct rds_incoming *inc, struct iovec *iov,
                             size_t size);
@@ -358,7 +357,7 @@ int rds_iw_xmit(struct rds_connection *conn, struct rds_message *rm,
 void rds_iw_send_cq_comp_handler(struct ib_cq *cq, void *context);
 void rds_iw_send_init_ring(struct rds_iw_connection *ic);
 void rds_iw_send_clear_ring(struct rds_iw_connection *ic);
-int rds_iw_xmit_rdma(struct rds_connection *conn, struct rds_rdma_op *op);
+int rds_iw_xmit_rdma(struct rds_connection *conn, struct rm_rdma_op *op);
 void rds_iw_send_add_credits(struct rds_connection *conn, unsigned int credits);
 void rds_iw_advertise_credits(struct rds_connection *conn, unsigned int posted);
 int rds_iw_send_grab_credits(struct rds_iw_connection *ic, u32 wanted,
@@ -371,7 +370,7 @@ unsigned int rds_iw_stats_info_copy(struct rds_info_iterator *iter,
                                    unsigned int avail);
 
 /* ib_sysctl.c */
-int __init rds_iw_sysctl_init(void);
+int rds_iw_sysctl_init(void);
 void rds_iw_sysctl_exit(void);
 extern unsigned long rds_iw_sysctl_max_send_wr;
 extern unsigned long rds_iw_sysctl_max_recv_wr;
index b5dd6ac39be86b87afc1bd7761971a11550e572f..712cf2d1f28ef36e3bf567540b036ca41179faaf 100644 (file)
@@ -257,7 +257,7 @@ static int rds_iw_setup_qp(struct rds_connection *conn)
         * the rds_iwdev at all.
         */
        rds_iwdev = ib_get_client_data(dev, &rds_iw_client);
-       if (rds_iwdev == NULL) {
+       if (!rds_iwdev) {
                if (printk_ratelimit())
                        printk(KERN_NOTICE "RDS/IW: No client_data for device %s\n",
                                        dev->name);
@@ -292,7 +292,7 @@ static int rds_iw_setup_qp(struct rds_connection *conn)
                                           ic->i_send_ring.w_nr *
                                                sizeof(struct rds_header),
                                           &ic->i_send_hdrs_dma, GFP_KERNEL);
-       if (ic->i_send_hdrs == NULL) {
+       if (!ic->i_send_hdrs) {
                ret = -ENOMEM;
                rdsdebug("ib_dma_alloc_coherent send failed\n");
                goto out;
@@ -302,7 +302,7 @@ static int rds_iw_setup_qp(struct rds_connection *conn)
                                           ic->i_recv_ring.w_nr *
                                                sizeof(struct rds_header),
                                           &ic->i_recv_hdrs_dma, GFP_KERNEL);
-       if (ic->i_recv_hdrs == NULL) {
+       if (!ic->i_recv_hdrs) {
                ret = -ENOMEM;
                rdsdebug("ib_dma_alloc_coherent recv failed\n");
                goto out;
@@ -310,14 +310,14 @@ static int rds_iw_setup_qp(struct rds_connection *conn)
 
        ic->i_ack = ib_dma_alloc_coherent(dev, sizeof(struct rds_header),
                                       &ic->i_ack_dma, GFP_KERNEL);
-       if (ic->i_ack == NULL) {
+       if (!ic->i_ack) {
                ret = -ENOMEM;
                rdsdebug("ib_dma_alloc_coherent ack failed\n");
                goto out;
        }
 
        ic->i_sends = vmalloc(ic->i_send_ring.w_nr * sizeof(struct rds_iw_send_work));
-       if (ic->i_sends == NULL) {
+       if (!ic->i_sends) {
                ret = -ENOMEM;
                rdsdebug("send allocation failed\n");
                goto out;
@@ -325,7 +325,7 @@ static int rds_iw_setup_qp(struct rds_connection *conn)
        rds_iw_send_init_ring(ic);
 
        ic->i_recvs = vmalloc(ic->i_recv_ring.w_nr * sizeof(struct rds_iw_recv_work));
-       if (ic->i_recvs == NULL) {
+       if (!ic->i_recvs) {
                ret = -ENOMEM;
                rdsdebug("recv allocation failed\n");
                goto out;
@@ -696,7 +696,7 @@ int rds_iw_conn_alloc(struct rds_connection *conn, gfp_t gfp)
 
        /* XXX too lazy? */
        ic = kzalloc(sizeof(struct rds_iw_connection), GFP_KERNEL);
-       if (ic == NULL)
+       if (!ic)
                return -ENOMEM;
 
        INIT_LIST_HEAD(&ic->iw_node);
index 13dc1862d86264288eb0455056d289008d072234..4e152e2daa3d02cc1ca2397853d00cbca8d75809 100644 (file)
@@ -34,7 +34,6 @@
 #include <linux/slab.h>
 
 #include "rds.h"
-#include "rdma.h"
 #include "iw.h"
 
 
index 3d479067d54dbd02810f9c6b1bf2d373d9388cbf..5e57347f49ff040968067b50ac35283e4463acd7 100644 (file)
@@ -53,7 +53,7 @@ static void rds_iw_frag_drop_page(struct rds_page_frag *frag)
 static void rds_iw_frag_free(struct rds_page_frag *frag)
 {
        rdsdebug("frag %p page %p\n", frag, frag->f_page);
-       BUG_ON(frag->f_page != NULL);
+       BUG_ON(frag->f_page);
        kmem_cache_free(rds_iw_frag_slab, frag);
 }
 
@@ -143,14 +143,14 @@ static int rds_iw_recv_refill_one(struct rds_connection *conn,
        struct ib_sge *sge;
        int ret = -ENOMEM;
 
-       if (recv->r_iwinc == NULL) {
+       if (!recv->r_iwinc) {
                if (!atomic_add_unless(&rds_iw_allocation, 1, rds_iw_sysctl_max_recv_allocation)) {
                        rds_iw_stats_inc(s_iw_rx_alloc_limit);
                        goto out;
                }
                recv->r_iwinc = kmem_cache_alloc(rds_iw_incoming_slab,
                                                 kptr_gfp);
-               if (recv->r_iwinc == NULL) {
+               if (!recv->r_iwinc) {
                        atomic_dec(&rds_iw_allocation);
                        goto out;
                }
@@ -158,17 +158,17 @@ static int rds_iw_recv_refill_one(struct rds_connection *conn,
                rds_inc_init(&recv->r_iwinc->ii_inc, conn, conn->c_faddr);
        }
 
-       if (recv->r_frag == NULL) {
+       if (!recv->r_frag) {
                recv->r_frag = kmem_cache_alloc(rds_iw_frag_slab, kptr_gfp);
-               if (recv->r_frag == NULL)
+               if (!recv->r_frag)
                        goto out;
                INIT_LIST_HEAD(&recv->r_frag->f_item);
                recv->r_frag->f_page = NULL;
        }
 
-       if (ic->i_frag.f_page == NULL) {
+       if (!ic->i_frag.f_page) {
                ic->i_frag.f_page = alloc_page(page_gfp);
-               if (ic->i_frag.f_page == NULL)
+               if (!ic->i_frag.f_page)
                        goto out;
                ic->i_frag.f_offset = 0;
        }
@@ -273,7 +273,7 @@ int rds_iw_recv_refill(struct rds_connection *conn, gfp_t kptr_gfp,
        return ret;
 }
 
-void rds_iw_inc_purge(struct rds_incoming *inc)
+static void rds_iw_inc_purge(struct rds_incoming *inc)
 {
        struct rds_iw_incoming *iwinc;
        struct rds_page_frag *frag;
@@ -716,7 +716,7 @@ static void rds_iw_process_recv(struct rds_connection *conn,
         * into the inc and save the inc so we can hang upcoming fragments
         * off its list.
         */
-       if (iwinc == NULL) {
+       if (!iwinc) {
                iwinc = recv->r_iwinc;
                recv->r_iwinc = NULL;
                ic->i_iwinc = iwinc;
@@ -887,7 +887,7 @@ int rds_iw_recv(struct rds_connection *conn)
        return ret;
 }
 
-int __init rds_iw_recv_init(void)
+int rds_iw_recv_init(void)
 {
        struct sysinfo si;
        int ret = -ENOMEM;
@@ -899,13 +899,13 @@ int __init rds_iw_recv_init(void)
        rds_iw_incoming_slab = kmem_cache_create("rds_iw_incoming",
                                        sizeof(struct rds_iw_incoming),
                                        0, 0, NULL);
-       if (rds_iw_incoming_slab == NULL)
+       if (!rds_iw_incoming_slab)
                goto out;
 
        rds_iw_frag_slab = kmem_cache_create("rds_iw_frag",
                                        sizeof(struct rds_page_frag),
                                        0, 0, NULL);
-       if (rds_iw_frag_slab == NULL)
+       if (!rds_iw_frag_slab)
                kmem_cache_destroy(rds_iw_incoming_slab);
        else
                ret = 0;
index 52182ff7519edcde8b7dee746b72282fe6eb832f..6280ea020d4eb0293b3c76be3a2e8e87920aff49 100644 (file)
@@ -36,7 +36,6 @@
 #include <linux/dmapool.h>
 
 #include "rds.h"
-#include "rdma.h"
 #include "iw.h"
 
 static void rds_iw_send_rdma_complete(struct rds_message *rm,
@@ -64,13 +63,13 @@ static void rds_iw_send_rdma_complete(struct rds_message *rm,
 }
 
 static void rds_iw_send_unmap_rdma(struct rds_iw_connection *ic,
-                                  struct rds_rdma_op *op)
+                                  struct rm_rdma_op *op)
 {
-       if (op->r_mapped) {
+       if (op->op_mapped) {
                ib_dma_unmap_sg(ic->i_cm_id->device,
-                       op->r_sg, op->r_nents,
-                       op->r_write ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
-               op->r_mapped = 0;
+                       op->op_sg, op->op_nents,
+                       op->op_write ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+               op->op_mapped = 0;
        }
 }
 
@@ -83,11 +82,11 @@ static void rds_iw_send_unmap_rm(struct rds_iw_connection *ic,
        rdsdebug("ic %p send %p rm %p\n", ic, send, rm);
 
        ib_dma_unmap_sg(ic->i_cm_id->device,
-                    rm->m_sg, rm->m_nents,
+                    rm->data.op_sg, rm->data.op_nents,
                     DMA_TO_DEVICE);
 
-       if (rm->m_rdma_op != NULL) {
-               rds_iw_send_unmap_rdma(ic, rm->m_rdma_op);
+       if (rm->rdma.op_active) {
+               rds_iw_send_unmap_rdma(ic, &rm->rdma);
 
                /* If the user asked for a completion notification on this
                 * message, we can implement three different semantics:
@@ -111,10 +110,10 @@ static void rds_iw_send_unmap_rm(struct rds_iw_connection *ic,
                 */
                rds_iw_send_rdma_complete(rm, wc_status);
 
-               if (rm->m_rdma_op->r_write)
-                       rds_stats_add(s_send_rdma_bytes, rm->m_rdma_op->r_bytes);
+               if (rm->rdma.op_write)
+                       rds_stats_add(s_send_rdma_bytes, rm->rdma.op_bytes);
                else
-                       rds_stats_add(s_recv_rdma_bytes, rm->m_rdma_op->r_bytes);
+                       rds_stats_add(s_recv_rdma_bytes, rm->rdma.op_bytes);
        }
 
        /* If anyone waited for this message to get flushed out, wake
@@ -556,25 +555,27 @@ int rds_iw_xmit(struct rds_connection *conn, struct rds_message *rm,
        }
 
        /* map the message the first time we see it */
-       if (ic->i_rm == NULL) {
+       if (!ic->i_rm) {
                /*
                printk(KERN_NOTICE "rds_iw_xmit prep msg dport=%u flags=0x%x len=%d\n",
                                be16_to_cpu(rm->m_inc.i_hdr.h_dport),
                                rm->m_inc.i_hdr.h_flags,
                                be32_to_cpu(rm->m_inc.i_hdr.h_len));
                   */
-               if (rm->m_nents) {
-                       rm->m_count = ib_dma_map_sg(dev,
-                                        rm->m_sg, rm->m_nents, DMA_TO_DEVICE);
-                       rdsdebug("ic %p mapping rm %p: %d\n", ic, rm, rm->m_count);
-                       if (rm->m_count == 0) {
+               if (rm->data.op_nents) {
+                       rm->data.op_count = ib_dma_map_sg(dev,
+                                                         rm->data.op_sg,
+                                                         rm->data.op_nents,
+                                                         DMA_TO_DEVICE);
+                       rdsdebug("ic %p mapping rm %p: %d\n", ic, rm, rm->data.op_count);
+                       if (rm->data.op_count == 0) {
                                rds_iw_stats_inc(s_iw_tx_sg_mapping_failure);
                                rds_iw_ring_unalloc(&ic->i_send_ring, work_alloc);
                                ret = -ENOMEM; /* XXX ? */
                                goto out;
                        }
                } else {
-                       rm->m_count = 0;
+                       rm->data.op_count = 0;
                }
 
                ic->i_unsignaled_wrs = rds_iw_sysctl_max_unsig_wrs;
@@ -590,10 +591,10 @@ int rds_iw_xmit(struct rds_connection *conn, struct rds_message *rm,
 
                /* If it has a RDMA op, tell the peer we did it. This is
                 * used by the peer to release use-once RDMA MRs. */
-               if (rm->m_rdma_op) {
+               if (rm->rdma.op_active) {
                        struct rds_ext_header_rdma ext_hdr;
 
-                       ext_hdr.h_rdma_rkey = cpu_to_be32(rm->m_rdma_op->r_key);
+                       ext_hdr.h_rdma_rkey = cpu_to_be32(rm->rdma.op_rkey);
                        rds_message_add_extension(&rm->m_inc.i_hdr,
                                        RDS_EXTHDR_RDMA, &ext_hdr, sizeof(ext_hdr));
                }
@@ -621,7 +622,7 @@ int rds_iw_xmit(struct rds_connection *conn, struct rds_message *rm,
        send = &ic->i_sends[pos];
        first = send;
        prev = NULL;
-       scat = &rm->m_sg[sg];
+       scat = &rm->data.op_sg[sg];
        sent = 0;
        i = 0;
 
@@ -631,7 +632,7 @@ int rds_iw_xmit(struct rds_connection *conn, struct rds_message *rm,
         * or when requested by the user. Right now, we let
         * the application choose.
         */
-       if (rm->m_rdma_op && rm->m_rdma_op->r_fence)
+       if (rm->rdma.op_active && rm->rdma.op_fence)
                send_flags = IB_SEND_FENCE;
 
        /*
@@ -650,7 +651,7 @@ int rds_iw_xmit(struct rds_connection *conn, struct rds_message *rm,
        }
 
        /* if there's data reference it with a chain of work reqs */
-       for (; i < work_alloc && scat != &rm->m_sg[rm->m_count]; i++) {
+       for (; i < work_alloc && scat != &rm->data.op_sg[rm->data.op_count]; i++) {
                unsigned int len;
 
                send = &ic->i_sends[pos];
@@ -728,7 +729,7 @@ add_header:
                sent += sizeof(struct rds_header);
 
        /* if we finished the message then send completion owns it */
-       if (scat == &rm->m_sg[rm->m_count]) {
+       if (scat == &rm->data.op_sg[rm->data.op_count]) {
                prev->s_rm = ic->i_rm;
                prev->s_wr.send_flags |= IB_SEND_SIGNALED | IB_SEND_SOLICITED;
                ic->i_rm = NULL;
@@ -784,7 +785,7 @@ static void rds_iw_build_send_fastreg(struct rds_iw_device *rds_iwdev, struct rd
        ib_update_fast_reg_key(send->s_mr, send->s_remap_count++);
 }
 
-int rds_iw_xmit_rdma(struct rds_connection *conn, struct rds_rdma_op *op)
+int rds_iw_xmit_rdma(struct rds_connection *conn, struct rm_rdma_op *op)
 {
        struct rds_iw_connection *ic = conn->c_transport_data;
        struct rds_iw_send_work *send = NULL;
@@ -794,7 +795,7 @@ int rds_iw_xmit_rdma(struct rds_connection *conn, struct rds_rdma_op *op)
        struct rds_iw_device *rds_iwdev;
        struct scatterlist *scat;
        unsigned long len;
-       u64 remote_addr = op->r_remote_addr;
+       u64 remote_addr = op->op_remote_addr;
        u32 pos, fr_pos;
        u32 work_alloc;
        u32 i;
@@ -806,21 +807,21 @@ int rds_iw_xmit_rdma(struct rds_connection *conn, struct rds_rdma_op *op)
        rds_iwdev = ib_get_client_data(ic->i_cm_id->device, &rds_iw_client);
 
        /* map the message the first time we see it */
-       if (!op->r_mapped) {
-               op->r_count = ib_dma_map_sg(ic->i_cm_id->device,
-                                       op->r_sg, op->r_nents, (op->r_write) ?
-                                       DMA_TO_DEVICE : DMA_FROM_DEVICE);
-               rdsdebug("ic %p mapping op %p: %d\n", ic, op, op->r_count);
-               if (op->r_count == 0) {
+       if (!op->op_mapped) {
+               op->op_count = ib_dma_map_sg(ic->i_cm_id->device,
+                                            op->op_sg, op->op_nents, (op->op_write) ?
+                                            DMA_TO_DEVICE : DMA_FROM_DEVICE);
+               rdsdebug("ic %p mapping op %p: %d\n", ic, op, op->op_count);
+               if (op->op_count == 0) {
                        rds_iw_stats_inc(s_iw_tx_sg_mapping_failure);
                        ret = -ENOMEM; /* XXX ? */
                        goto out;
                }
 
-               op->r_mapped = 1;
+               op->op_mapped = 1;
        }
 
-       if (!op->r_write) {
+       if (!op->op_write) {
                /* Alloc space on the send queue for the fastreg */
                work_alloc = rds_iw_ring_alloc(&ic->i_send_ring, 1, &fr_pos);
                if (work_alloc != 1) {
@@ -835,7 +836,7 @@ int rds_iw_xmit_rdma(struct rds_connection *conn, struct rds_rdma_op *op)
         * Instead of knowing how to return a partial rdma read/write we insist that there
         * be enough work requests to send the entire message.
         */
-       i = ceil(op->r_count, rds_iwdev->max_sge);
+       i = ceil(op->op_count, rds_iwdev->max_sge);
 
        work_alloc = rds_iw_ring_alloc(&ic->i_send_ring, i, &pos);
        if (work_alloc != i) {
@@ -846,17 +847,17 @@ int rds_iw_xmit_rdma(struct rds_connection *conn, struct rds_rdma_op *op)
        }
 
        send = &ic->i_sends[pos];
-       if (!op->r_write) {
+       if (!op->op_write) {
                first = prev = &ic->i_sends[fr_pos];
        } else {
                first = send;
                prev = NULL;
        }
-       scat = &op->r_sg[0];
+       scat = &op->op_sg[0];
        sent = 0;
-       num_sge = op->r_count;
+       num_sge = op->op_count;
 
-       for (i = 0; i < work_alloc && scat != &op->r_sg[op->r_count]; i++) {
+       for (i = 0; i < work_alloc && scat != &op->op_sg[op->op_count]; i++) {
                send->s_wr.send_flags = 0;
                send->s_queued = jiffies;
 
@@ -873,13 +874,13 @@ int rds_iw_xmit_rdma(struct rds_connection *conn, struct rds_rdma_op *op)
                 * for local access after RDS is finished with it, using
                 * IB_WR_RDMA_READ_WITH_INV will invalidate it after the read has completed.
                 */
-               if (op->r_write)
+               if (op->op_write)
                        send->s_wr.opcode = IB_WR_RDMA_WRITE;
                else
                        send->s_wr.opcode = IB_WR_RDMA_READ_WITH_INV;
 
                send->s_wr.wr.rdma.remote_addr = remote_addr;
-               send->s_wr.wr.rdma.rkey = op->r_key;
+               send->s_wr.wr.rdma.rkey = op->op_rkey;
                send->s_op = op;
 
                if (num_sge > rds_iwdev->max_sge) {
@@ -893,7 +894,7 @@ int rds_iw_xmit_rdma(struct rds_connection *conn, struct rds_rdma_op *op)
                if (prev)
                        prev->s_wr.next = &send->s_wr;
 
-               for (j = 0; j < send->s_wr.num_sge && scat != &op->r_sg[op->r_count]; j++) {
+               for (j = 0; j < send->s_wr.num_sge && scat != &op->op_sg[op->op_count]; j++) {
                        len = ib_sg_dma_len(ic->i_cm_id->device, scat);
 
                        if (send->s_wr.opcode == IB_WR_RDMA_READ_WITH_INV)
@@ -927,7 +928,7 @@ int rds_iw_xmit_rdma(struct rds_connection *conn, struct rds_rdma_op *op)
        }
 
        /* if we finished the message then send completion owns it */
-       if (scat == &op->r_sg[op->r_count])
+       if (scat == &op->op_sg[op->op_count])
                first->s_wr.send_flags = IB_SEND_SIGNALED;
 
        if (i < work_alloc) {
@@ -941,9 +942,9 @@ int rds_iw_xmit_rdma(struct rds_connection *conn, struct rds_rdma_op *op)
         * adapters do not allow using the lkey for this at all.  To bypass this use a
         * fastreg_mr (or possibly a dma_mr)
         */
-       if (!op->r_write) {
+       if (!op->op_write) {
                rds_iw_build_send_fastreg(rds_iwdev, ic, &ic->i_sends[fr_pos],
-                       op->r_count, sent, conn->c_xmit_rm->m_rs->rs_user_addr);
+                       op->op_count, sent, conn->c_xmit_rm->m_rs->rs_user_addr);
                work_alloc++;
        }
 
index 1c4428a61a0259baf3c1af1611f23608ffea0c5d..23e3a9a26aaf36285fef39e8b909ce0d8b62327a 100644 (file)
@@ -122,10 +122,10 @@ void rds_iw_sysctl_exit(void)
                unregister_sysctl_table(rds_iw_sysctl_hdr);
 }
 
-int __init rds_iw_sysctl_init(void)
+int rds_iw_sysctl_init(void)
 {
        rds_iw_sysctl_hdr = register_sysctl_paths(rds_iw_sysctl_path, rds_iw_sysctl_table);
-       if (rds_iw_sysctl_hdr == NULL)
+       if (!rds_iw_sysctl_hdr)
                return -ENOMEM;
        return 0;
 }
index dd9879379457e29bc9afcb45bacbb58b4ffd092e..c390156b426fc936c6b05fd607f4c32ddb1e3a81 100644 (file)
@@ -61,10 +61,17 @@ static int rds_loop_xmit(struct rds_connection *conn, struct rds_message *rm,
                         unsigned int hdr_off, unsigned int sg,
                         unsigned int off)
 {
+       /* Do not send cong updates to loopback */
+       if (rm->m_inc.i_hdr.h_flags & RDS_FLAG_CONG_BITMAP) {
+               rds_cong_map_updated(conn->c_fcong, ~(u64) 0);
+               return sizeof(struct rds_header) + RDS_CONG_MAP_BYTES;
+       }
+
        BUG_ON(hdr_off || sg || off);
 
        rds_inc_init(&rm->m_inc, conn, conn->c_laddr);
-       rds_message_addref(rm); /* for the inc */
+       /* For the embedded inc. Matching put is in loop_inc_free() */
+       rds_message_addref(rm);
 
        rds_recv_incoming(conn, conn->c_laddr, conn->c_faddr, &rm->m_inc,
                          GFP_KERNEL, KM_USER0);
@@ -77,16 +84,14 @@ static int rds_loop_xmit(struct rds_connection *conn, struct rds_message *rm,
        return sizeof(struct rds_header) + be32_to_cpu(rm->m_inc.i_hdr.h_len);
 }
 
-static int rds_loop_xmit_cong_map(struct rds_connection *conn,
-                                 struct rds_cong_map *map,
-                                 unsigned long offset)
+/*
+ * See rds_loop_xmit(). Since our inc is embedded in the rm, we
+ * make sure the rm lives at least until the inc is done.
+ */
+static void rds_loop_inc_free(struct rds_incoming *inc)
 {
-       BUG_ON(offset);
-       BUG_ON(map != conn->c_lcong);
-
-       rds_cong_map_updated(conn->c_fcong, ~(u64) 0);
-
-       return sizeof(struct rds_header) + RDS_CONG_MAP_BYTES;
+        struct rds_message *rm = container_of(inc, struct rds_message, m_inc);
+        rds_message_put(rm);
 }
 
 /* we need to at least give the thread something to succeed */
@@ -112,7 +117,7 @@ static int rds_loop_conn_alloc(struct rds_connection *conn, gfp_t gfp)
        unsigned long flags;
 
        lc = kzalloc(sizeof(struct rds_loop_connection), GFP_KERNEL);
-       if (lc == NULL)
+       if (!lc)
                return -ENOMEM;
 
        INIT_LIST_HEAD(&lc->loop_node);
@@ -169,14 +174,12 @@ void rds_loop_exit(void)
  */
 struct rds_transport rds_loop_transport = {
        .xmit                   = rds_loop_xmit,
-       .xmit_cong_map          = rds_loop_xmit_cong_map,
        .recv                   = rds_loop_recv,
        .conn_alloc             = rds_loop_conn_alloc,
        .conn_free              = rds_loop_conn_free,
        .conn_connect           = rds_loop_conn_connect,
        .conn_shutdown          = rds_loop_conn_shutdown,
        .inc_copy_to_user       = rds_message_inc_copy_to_user,
-       .inc_purge              = rds_message_inc_purge,
-       .inc_free               = rds_message_inc_free,
+       .inc_free               = rds_loop_inc_free,
        .t_name                 = "loopback",
 };
index 9a1d67e001ba60a79608275ecfa3ed452f373b19..84f937f11d475870710abbbfc746b06c4160b5f3 100644 (file)
@@ -34,9 +34,6 @@
 #include <linux/slab.h>
 
 #include "rds.h"
-#include "rdma.h"
-
-static DECLARE_WAIT_QUEUE_HEAD(rds_message_flush_waitq);
 
 static unsigned int    rds_exthdr_size[__RDS_EXTHDR_MAX] = {
 [RDS_EXTHDR_NONE]      = 0,
@@ -63,29 +60,31 @@ static void rds_message_purge(struct rds_message *rm)
        if (unlikely(test_bit(RDS_MSG_PAGEVEC, &rm->m_flags)))
                return;
 
-       for (i = 0; i < rm->m_nents; i++) {
-               rdsdebug("putting data page %p\n", (void *)sg_page(&rm->m_sg[i]));
+       for (i = 0; i < rm->data.op_nents; i++) {
+               rdsdebug("putting data page %p\n", (void *)sg_page(&rm->data.op_sg[i]));
                /* XXX will have to put_page for page refs */
-               __free_page(sg_page(&rm->m_sg[i]));
+               __free_page(sg_page(&rm->data.op_sg[i]));
        }
-       rm->m_nents = 0;
+       rm->data.op_nents = 0;
 
-       if (rm->m_rdma_op)
-               rds_rdma_free_op(rm->m_rdma_op);
-       if (rm->m_rdma_mr)
-               rds_mr_put(rm->m_rdma_mr);
-}
+       if (rm->rdma.op_active)
+               rds_rdma_free_op(&rm->rdma);
+       if (rm->rdma.op_rdma_mr)
+               rds_mr_put(rm->rdma.op_rdma_mr);
 
-void rds_message_inc_purge(struct rds_incoming *inc)
-{
-       struct rds_message *rm = container_of(inc, struct rds_message, m_inc);
-       rds_message_purge(rm);
+       if (rm->atomic.op_active)
+               rds_atomic_free_op(&rm->atomic);
+       if (rm->atomic.op_rdma_mr)
+               rds_mr_put(rm->atomic.op_rdma_mr);
 }
 
 void rds_message_put(struct rds_message *rm)
 {
        rdsdebug("put rm %p ref %d\n", rm, atomic_read(&rm->m_refcount));
-
+       if (atomic_read(&rm->m_refcount) == 0) {
+printk(KERN_CRIT "danger refcount zero on %p\n", rm);
+WARN_ON(1);
+       }
        if (atomic_dec_and_test(&rm->m_refcount)) {
                BUG_ON(!list_empty(&rm->m_sock_item));
                BUG_ON(!list_empty(&rm->m_conn_item));
@@ -96,12 +95,6 @@ void rds_message_put(struct rds_message *rm)
 }
 EXPORT_SYMBOL_GPL(rds_message_put);
 
-void rds_message_inc_free(struct rds_incoming *inc)
-{
-       struct rds_message *rm = container_of(inc, struct rds_message, m_inc);
-       rds_message_put(rm);
-}
-
 void rds_message_populate_header(struct rds_header *hdr, __be16 sport,
                                 __be16 dport, u64 seq)
 {
@@ -214,41 +207,68 @@ int rds_message_add_rdma_dest_extension(struct rds_header *hdr, u32 r_key, u32 o
 }
 EXPORT_SYMBOL_GPL(rds_message_add_rdma_dest_extension);
 
-struct rds_message *rds_message_alloc(unsigned int nents, gfp_t gfp)
+/*
+ * Each rds_message is allocated with extra space for the scatterlist entries
+ * rds ops will need. This is to minimize memory allocation count. Then, each rds op
+ * can grab SGs when initializing its part of the rds_message.
+ */
+struct rds_message *rds_message_alloc(unsigned int extra_len, gfp_t gfp)
 {
        struct rds_message *rm;
 
-       rm = kzalloc(sizeof(struct rds_message) +
-                    (nents * sizeof(struct scatterlist)), gfp);
+       rm = kzalloc(sizeof(struct rds_message) + extra_len, gfp);
        if (!rm)
                goto out;
 
-       if (nents)
-               sg_init_table(rm->m_sg, nents);
+       rm->m_used_sgs = 0;
+       rm->m_total_sgs = extra_len / sizeof(struct scatterlist);
+
        atomic_set(&rm->m_refcount, 1);
        INIT_LIST_HEAD(&rm->m_sock_item);
        INIT_LIST_HEAD(&rm->m_conn_item);
        spin_lock_init(&rm->m_rs_lock);
+       init_waitqueue_head(&rm->m_flush_wait);
 
 out:
        return rm;
 }
 
+/*
+ * RDS ops use this to grab SG entries from the rm's sg pool.
+ */
+struct scatterlist *rds_message_alloc_sgs(struct rds_message *rm, int nents)
+{
+       struct scatterlist *sg_first = (struct scatterlist *) &rm[1];
+       struct scatterlist *sg_ret;
+
+       WARN_ON(rm->m_used_sgs + nents > rm->m_total_sgs);
+       WARN_ON(!nents);
+
+       sg_ret = &sg_first[rm->m_used_sgs];
+       sg_init_table(sg_ret, nents);
+       rm->m_used_sgs += nents;
+
+       return sg_ret;
+}
+
 struct rds_message *rds_message_map_pages(unsigned long *page_addrs, unsigned int total_len)
 {
        struct rds_message *rm;
        unsigned int i;
+       int num_sgs = ceil(total_len, PAGE_SIZE);
+       int extra_bytes = num_sgs * sizeof(struct scatterlist);
 
-       rm = rds_message_alloc(ceil(total_len, PAGE_SIZE), GFP_KERNEL);
-       if (rm == NULL)
+       rm = rds_message_alloc(extra_bytes, GFP_NOWAIT);
+       if (!rm)
                return ERR_PTR(-ENOMEM);
 
        set_bit(RDS_MSG_PAGEVEC, &rm->m_flags);
        rm->m_inc.i_hdr.h_len = cpu_to_be32(total_len);
-       rm->m_nents = ceil(total_len, PAGE_SIZE);
+       rm->data.op_nents = ceil(total_len, PAGE_SIZE);
+       rm->data.op_sg = rds_message_alloc_sgs(rm, num_sgs);
 
-       for (i = 0; i < rm->m_nents; ++i) {
-               sg_set_page(&rm->m_sg[i],
+       for (i = 0; i < rm->data.op_nents; ++i) {
+               sg_set_page(&rm->data.op_sg[i],
                                virt_to_page(page_addrs[i]),
                                PAGE_SIZE, 0);
        }
@@ -256,40 +276,33 @@ struct rds_message *rds_message_map_pages(unsigned long *page_addrs, unsigned in
        return rm;
 }
 
-struct rds_message *rds_message_copy_from_user(struct iovec *first_iov,
+int rds_message_copy_from_user(struct rds_message *rm, struct iovec *first_iov,
                                               size_t total_len)
 {
        unsigned long to_copy;
        unsigned long iov_off;
        unsigned long sg_off;
-       struct rds_message *rm;
        struct iovec *iov;
        struct scatterlist *sg;
-       int ret;
-
-       rm = rds_message_alloc(ceil(total_len, PAGE_SIZE), GFP_KERNEL);
-       if (rm == NULL) {
-               ret = -ENOMEM;
-               goto out;
-       }
+       int ret = 0;
 
        rm->m_inc.i_hdr.h_len = cpu_to_be32(total_len);
 
        /*
         * now allocate and copy in the data payload.
         */
-       sg = rm->m_sg;
+       sg = rm->data.op_sg;
        iov = first_iov;
        iov_off = 0;
        sg_off = 0; /* Dear gcc, sg->page will be null from kzalloc. */
 
        while (total_len) {
-               if (sg_page(sg) == NULL) {
+               if (!sg_page(sg)) {
                        ret = rds_page_remainder_alloc(sg, total_len,
                                                       GFP_HIGHUSER);
                        if (ret)
                                goto out;
-                       rm->m_nents++;
+                       rm->data.op_nents++;
                        sg_off = 0;
                }
 
@@ -320,14 +333,8 @@ struct rds_message *rds_message_copy_from_user(struct iovec *first_iov,
                        sg++;
        }
 
-       ret = 0;
 out:
-       if (ret) {
-               if (rm)
-                       rds_message_put(rm);
-               rm = ERR_PTR(ret);
-       }
-       return rm;
+       return ret;
 }
 
 int rds_message_inc_copy_to_user(struct rds_incoming *inc,
@@ -348,7 +355,7 @@ int rds_message_inc_copy_to_user(struct rds_incoming *inc,
 
        iov = first_iov;
        iov_off = 0;
-       sg = rm->m_sg;
+       sg = rm->data.op_sg;
        vec_off = 0;
        copied = 0;
 
@@ -394,15 +401,14 @@ int rds_message_inc_copy_to_user(struct rds_incoming *inc,
  */
 void rds_message_wait(struct rds_message *rm)
 {
-       wait_event(rds_message_flush_waitq,
+       wait_event_interruptible(rm->m_flush_wait,
                        !test_bit(RDS_MSG_MAPPED, &rm->m_flags));
 }
 
 void rds_message_unmapped(struct rds_message *rm)
 {
        clear_bit(RDS_MSG_MAPPED, &rm->m_flags);
-       if (waitqueue_active(&rds_message_flush_waitq))
-               wake_up(&rds_message_flush_waitq);
+       wake_up_interruptible(&rm->m_flush_wait);
 }
 EXPORT_SYMBOL_GPL(rds_message_unmapped);
 
index 595a952d4b17f069c60a457701d6e207f68e621b..5e44f5ae78987315757b1243f7bcd43373bd5df4 100644 (file)
@@ -116,7 +116,7 @@ int rds_page_remainder_alloc(struct scatterlist *scat, unsigned long bytes,
        /* jump straight to allocation if we're trying for a huge page */
        if (bytes >= PAGE_SIZE) {
                page = alloc_page(gfp);
-               if (page == NULL) {
+               if (!page) {
                        ret = -ENOMEM;
                } else {
                        sg_set_page(scat, page, PAGE_SIZE, 0);
@@ -162,7 +162,7 @@ int rds_page_remainder_alloc(struct scatterlist *scat, unsigned long bytes,
                rem = &per_cpu(rds_page_remainders, get_cpu());
                local_irq_save(flags);
 
-               if (page == NULL) {
+               if (!page) {
                        ret = -ENOMEM;
                        break;
                }
@@ -186,6 +186,7 @@ out:
                 ret ? 0 : scat->length);
        return ret;
 }
+EXPORT_SYMBOL_GPL(rds_page_remainder_alloc);
 
 static int rds_page_remainder_cpu_notify(struct notifier_block *self,
                                         unsigned long action, void *hcpu)
index 75fd13bb631bbc06bf8493c06c266951b6e47c95..48064673fc76dc7b19792fe3d5a7bcb49592ef98 100644 (file)
@@ -35,7 +35,7 @@
 #include <linux/rbtree.h>
 #include <linux/dma-mapping.h> /* for DMA_*_DEVICE */
 
-#include "rdma.h"
+#include "rds.h"
 
 /*
  * XXX
@@ -130,14 +130,22 @@ void rds_rdma_drop_keys(struct rds_sock *rs)
 {
        struct rds_mr *mr;
        struct rb_node *node;
+       unsigned long flags;
 
        /* Release any MRs associated with this socket */
+       spin_lock_irqsave(&rs->rs_rdma_lock, flags);
        while ((node = rb_first(&rs->rs_rdma_keys))) {
                mr = container_of(node, struct rds_mr, r_rb_node);
                if (mr->r_trans == rs->rs_transport)
                        mr->r_invalidate = 0;
+               rb_erase(&mr->r_rb_node, &rs->rs_rdma_keys);
+               RB_CLEAR_NODE(&mr->r_rb_node);
+               spin_unlock_irqrestore(&rs->rs_rdma_lock, flags);
+               rds_destroy_mr(mr);
                rds_mr_put(mr);
+               spin_lock_irqsave(&rs->rs_rdma_lock, flags);
        }
+       spin_unlock_irqrestore(&rs->rs_rdma_lock, flags);
 
        if (rs->rs_transport && rs->rs_transport->flush_mrs)
                rs->rs_transport->flush_mrs();
@@ -181,7 +189,7 @@ static int __rds_rdma_map(struct rds_sock *rs, struct rds_get_mr_args *args,
                goto out;
        }
 
-       if (rs->rs_transport->get_mr == NULL) {
+       if (!rs->rs_transport->get_mr) {
                ret = -EOPNOTSUPP;
                goto out;
        }
@@ -197,13 +205,13 @@ static int __rds_rdma_map(struct rds_sock *rs, struct rds_get_mr_args *args,
 
        /* XXX clamp nr_pages to limit the size of this alloc? */
        pages = kcalloc(nr_pages, sizeof(struct page *), GFP_KERNEL);
-       if (pages == NULL) {
+       if (!pages) {
                ret = -ENOMEM;
                goto out;
        }
 
        mr = kzalloc(sizeof(struct rds_mr), GFP_KERNEL);
-       if (mr == NULL) {
+       if (!mr) {
                ret = -ENOMEM;
                goto out;
        }
@@ -230,13 +238,13 @@ static int __rds_rdma_map(struct rds_sock *rs, struct rds_get_mr_args *args,
         * r/o or r/w. We need to assume r/w, or we'll do a lot of RDMA to
         * the zero page.
         */
-       ret = rds_pin_pages(args->vec.addr & PAGE_MASK, nr_pages, pages, 1);
+       ret = rds_pin_pages(args->vec.addr, nr_pages, pages, 1);
        if (ret < 0)
                goto out;
 
        nents = ret;
        sg = kcalloc(nents, sizeof(*sg), GFP_KERNEL);
-       if (sg == NULL) {
+       if (!sg) {
                ret = -ENOMEM;
                goto out;
        }
@@ -406,68 +414,127 @@ void rds_rdma_unuse(struct rds_sock *rs, u32 r_key, int force)
 
        spin_lock_irqsave(&rs->rs_rdma_lock, flags);
        mr = rds_mr_tree_walk(&rs->rs_rdma_keys, r_key, NULL);
-       if (mr && (mr->r_use_once || force)) {
+       if (!mr) {
+               printk(KERN_ERR "rds: trying to unuse MR with unknown r_key %u!\n", r_key);
+               spin_unlock_irqrestore(&rs->rs_rdma_lock, flags);
+               return;
+       }
+
+       if (mr->r_use_once || force) {
                rb_erase(&mr->r_rb_node, &rs->rs_rdma_keys);
                RB_CLEAR_NODE(&mr->r_rb_node);
                zot_me = 1;
-       } else if (mr)
-               atomic_inc(&mr->r_refcount);
+       }
        spin_unlock_irqrestore(&rs->rs_rdma_lock, flags);
 
        /* May have to issue a dma_sync on this memory region.
         * Note we could avoid this if the operation was a RDMA READ,
         * but at this point we can't tell. */
-       if (mr != NULL) {
-               if (mr->r_trans->sync_mr)
-                       mr->r_trans->sync_mr(mr->r_trans_private, DMA_FROM_DEVICE);
-
-               /* If the MR was marked as invalidate, this will
-                * trigger an async flush. */
-               if (zot_me)
-                       rds_destroy_mr(mr);
-               rds_mr_put(mr);
-       }
+       if (mr->r_trans->sync_mr)
+               mr->r_trans->sync_mr(mr->r_trans_private, DMA_FROM_DEVICE);
+
+       /* If the MR was marked as invalidate, this will
+        * trigger an async flush. */
+       if (zot_me)
+               rds_destroy_mr(mr);
+       rds_mr_put(mr);
 }
 
-void rds_rdma_free_op(struct rds_rdma_op *ro)
+void rds_rdma_free_op(struct rm_rdma_op *ro)
 {
        unsigned int i;
 
-       for (i = 0; i < ro->r_nents; i++) {
-               struct page *page = sg_page(&ro->r_sg[i]);
+       for (i = 0; i < ro->op_nents; i++) {
+               struct page *page = sg_page(&ro->op_sg[i]);
 
                /* Mark page dirty if it was possibly modified, which
                 * is the case for a RDMA_READ which copies from remote
                 * to local memory */
-               if (!ro->r_write) {
-                       BUG_ON(in_interrupt());
+               if (!ro->op_write) {
+                       BUG_ON(irqs_disabled());
                        set_page_dirty(page);
                }
                put_page(page);
        }
 
-       kfree(ro->r_notifier);
-       kfree(ro);
+       kfree(ro->op_notifier);
+       ro->op_notifier = NULL;
+       ro->op_active = 0;
+}
+
+void rds_atomic_free_op(struct rm_atomic_op *ao)
+{
+       struct page *page = sg_page(ao->op_sg);
+
+       /* Mark page dirty if it was possibly modified, which
+        * is the case for a RDMA_READ which copies from remote
+        * to local memory */
+       set_page_dirty(page);
+       put_page(page);
+
+       kfree(ao->op_notifier);
+       ao->op_notifier = NULL;
+       ao->op_active = 0;
+}
+
+
+/*
+ * Count the number of pages needed to describe an incoming iovec.
+ */
+static int rds_rdma_pages(struct rds_rdma_args *args)
+{
+       struct rds_iovec vec;
+       struct rds_iovec __user *local_vec;
+       unsigned int tot_pages = 0;
+       unsigned int nr_pages;
+       unsigned int i;
+
+       local_vec = (struct rds_iovec __user *)(unsigned long) args->local_vec_addr;
+
+       /* figure out the number of pages in the vector */
+       for (i = 0; i < args->nr_local; i++) {
+               if (copy_from_user(&vec, &local_vec[i],
+                                  sizeof(struct rds_iovec)))
+                       return -EFAULT;
+
+               nr_pages = rds_pages_in_vec(&vec);
+               if (nr_pages == 0)
+                       return -EINVAL;
+
+               tot_pages += nr_pages;
+       }
+
+       return tot_pages;
+}
+
+int rds_rdma_extra_size(struct rds_rdma_args *args)
+{
+       return rds_rdma_pages(args) * sizeof(struct scatterlist);
 }
 
 /*
- * args is a pointer to an in-kernel copy in the sendmsg cmsg.
+ * The application asks for a RDMA transfer.
+ * Extract all arguments and set up the rdma_op
  */
-static struct rds_rdma_op *rds_rdma_prepare(struct rds_sock *rs,
-                                           struct rds_rdma_args *args)
+int rds_cmsg_rdma_args(struct rds_sock *rs, struct rds_message *rm,
+                         struct cmsghdr *cmsg)
 {
+       struct rds_rdma_args *args;
        struct rds_iovec vec;
-       struct rds_rdma_op *op = NULL;
+       struct rm_rdma_op *op = &rm->rdma;
        unsigned int nr_pages;
-       unsigned int max_pages;
        unsigned int nr_bytes;
        struct page **pages = NULL;
        struct rds_iovec __user *local_vec;
-       struct scatterlist *sg;
        unsigned int nr;
        unsigned int i, j;
-       int ret;
+       int ret = 0;
+
+       if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct rds_rdma_args))
+           || rm->rdma.op_active)
+               return -EINVAL;
 
+       args = CMSG_DATA(cmsg);
 
        if (rs->rs_bound_addr == 0) {
                ret = -ENOTCONN; /* XXX not a great errno */
@@ -479,61 +546,38 @@ static struct rds_rdma_op *rds_rdma_prepare(struct rds_sock *rs,
                goto out;
        }
 
-       nr_pages = 0;
-       max_pages = 0;
-
-       local_vec = (struct rds_iovec __user *)(unsigned long) args->local_vec_addr;
-
-       /* figure out the number of pages in the vector */
-       for (i = 0; i < args->nr_local; i++) {
-               if (copy_from_user(&vec, &local_vec[i],
-                                  sizeof(struct rds_iovec))) {
-                       ret = -EFAULT;
-                       goto out;
-               }
-
-               nr = rds_pages_in_vec(&vec);
-               if (nr == 0) {
-                       ret = -EINVAL;
-                       goto out;
-               }
-
-               max_pages = max(nr, max_pages);
-               nr_pages += nr;
-       }
-
-       pages = kcalloc(max_pages, sizeof(struct page *), GFP_KERNEL);
-       if (pages == NULL) {
-               ret = -ENOMEM;
+       nr_pages = rds_rdma_pages(args);
+       if (nr_pages < 0)
                goto out;
-       }
 
-       op = kzalloc(offsetof(struct rds_rdma_op, r_sg[nr_pages]), GFP_KERNEL);
-       if (op == NULL) {
+       pages = kcalloc(nr_pages, sizeof(struct page *), GFP_KERNEL);
+       if (!pages) {
                ret = -ENOMEM;
                goto out;
        }
 
-       op->r_write = !!(args->flags & RDS_RDMA_READWRITE);
-       op->r_fence = !!(args->flags & RDS_RDMA_FENCE);
-       op->r_notify = !!(args->flags & RDS_RDMA_NOTIFY_ME);
-       op->r_recverr = rs->rs_recverr;
+       op->op_write = !!(args->flags & RDS_RDMA_READWRITE);
+       op->op_fence = !!(args->flags & RDS_RDMA_FENCE);
+       op->op_notify = !!(args->flags & RDS_RDMA_NOTIFY_ME);
+       op->op_silent = !!(args->flags & RDS_RDMA_SILENT);
+       op->op_active = 1;
+       op->op_recverr = rs->rs_recverr;
        WARN_ON(!nr_pages);
-       sg_init_table(op->r_sg, nr_pages);
+       op->op_sg = rds_message_alloc_sgs(rm, nr_pages);
 
-       if (op->r_notify || op->r_recverr) {
+       if (op->op_notify || op->op_recverr) {
                /* We allocate an uninitialized notifier here, because
                 * we don't want to do that in the completion handler. We
                 * would have to use GFP_ATOMIC there, and don't want to deal
                 * with failed allocations.
                 */
-               op->r_notifier = kmalloc(sizeof(struct rds_notifier), GFP_KERNEL);
-               if (!op->r_notifier) {
+               op->op_notifier = kmalloc(sizeof(struct rds_notifier), GFP_KERNEL);
+               if (!op->op_notifier) {
                        ret = -ENOMEM;
                        goto out;
                }
-               op->r_notifier->n_user_token = args->user_token;
-               op->r_notifier->n_status = RDS_RDMA_SUCCESS;
+               op->op_notifier->n_user_token = args->user_token;
+               op->op_notifier->n_status = RDS_RDMA_SUCCESS;
        }
 
        /* The cookie contains the R_Key of the remote memory region, and
@@ -543,15 +587,17 @@ static struct rds_rdma_op *rds_rdma_prepare(struct rds_sock *rs,
         * destination address (which is really an offset into the MR)
         * FIXME: We may want to move this into ib_rdma.c
         */
-       op->r_key = rds_rdma_cookie_key(args->cookie);
-       op->r_remote_addr = args->remote_vec.addr + rds_rdma_cookie_offset(args->cookie);
+       op->op_rkey = rds_rdma_cookie_key(args->cookie);
+       op->op_remote_addr = args->remote_vec.addr + rds_rdma_cookie_offset(args->cookie);
 
        nr_bytes = 0;
 
        rdsdebug("RDS: rdma prepare nr_local %llu rva %llx rkey %x\n",
               (unsigned long long)args->nr_local,
               (unsigned long long)args->remote_vec.addr,
-              op->r_key);
+              op->op_rkey);
+
+       local_vec = (struct rds_iovec __user *)(unsigned long) args->local_vec_addr;
 
        for (i = 0; i < args->nr_local; i++) {
                if (copy_from_user(&vec, &local_vec[i],
@@ -569,15 +615,10 @@ static struct rds_rdma_op *rds_rdma_prepare(struct rds_sock *rs,
                rs->rs_user_addr = vec.addr;
                rs->rs_user_bytes = vec.bytes;
 
-               /* did the user change the vec under us? */
-               if (nr > max_pages || op->r_nents + nr > nr_pages) {
-                       ret = -EINVAL;
-                       goto out;
-               }
                /* If it's a WRITE operation, we want to pin the pages for reading.
                 * If it's a READ operation, we need to pin the pages for writing.
                 */
-               ret = rds_pin_pages(vec.addr & PAGE_MASK, nr, pages, !op->r_write);
+               ret = rds_pin_pages(vec.addr, nr, pages, !op->op_write);
                if (ret < 0)
                        goto out;
 
@@ -588,8 +629,9 @@ static struct rds_rdma_op *rds_rdma_prepare(struct rds_sock *rs,
 
                for (j = 0; j < nr; j++) {
                        unsigned int offset = vec.addr & ~PAGE_MASK;
+                       struct scatterlist *sg;
 
-                       sg = &op->r_sg[op->r_nents + j];
+                       sg = &op->op_sg[op->op_nents + j];
                        sg_set_page(sg, pages[j],
                                        min_t(unsigned int, vec.bytes, PAGE_SIZE - offset),
                                        offset);
@@ -601,10 +643,9 @@ static struct rds_rdma_op *rds_rdma_prepare(struct rds_sock *rs,
                        vec.bytes -= sg->length;
                }
 
-               op->r_nents += nr;
+               op->op_nents += nr;
        }
 
-
        if (nr_bytes > args->remote_vec.bytes) {
                rdsdebug("RDS nr_bytes %u remote_bytes %u do not match\n",
                                nr_bytes,
@@ -612,38 +653,17 @@ static struct rds_rdma_op *rds_rdma_prepare(struct rds_sock *rs,
                ret = -EINVAL;
                goto out;
        }
-       op->r_bytes = nr_bytes;
+       op->op_bytes = nr_bytes;
 
        ret = 0;
 out:
        kfree(pages);
-       if (ret) {
-               if (op)
-                       rds_rdma_free_op(op);
-               op = ERR_PTR(ret);
-       }
-       return op;
-}
-
-/*
- * The application asks for a RDMA transfer.
- * Extract all arguments and set up the rdma_op
- */
-int rds_cmsg_rdma_args(struct rds_sock *rs, struct rds_message *rm,
-                         struct cmsghdr *cmsg)
-{
-       struct rds_rdma_op *op;
-
-       if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct rds_rdma_args)) ||
-           rm->m_rdma_op != NULL)
-               return -EINVAL;
+       if (ret)
+               rds_rdma_free_op(op);
 
-       op = rds_rdma_prepare(rs, CMSG_DATA(cmsg));
-       if (IS_ERR(op))
-               return PTR_ERR(op);
        rds_stats_inc(s_send_rdma);
-       rm->m_rdma_op = op;
-       return 0;
+
+       return ret;
 }
 
 /*
@@ -673,7 +693,7 @@ int rds_cmsg_rdma_dest(struct rds_sock *rs, struct rds_message *rm,
 
        spin_lock_irqsave(&rs->rs_rdma_lock, flags);
        mr = rds_mr_tree_walk(&rs->rs_rdma_keys, r_key, NULL);
-       if (mr == NULL)
+       if (!mr)
                err = -EINVAL;  /* invalid r_key */
        else
                atomic_inc(&mr->r_refcount);
@@ -681,7 +701,7 @@ int rds_cmsg_rdma_dest(struct rds_sock *rs, struct rds_message *rm,
 
        if (mr) {
                mr->r_trans->sync_mr(mr->r_trans_private, DMA_TO_DEVICE);
-               rm->m_rdma_mr = mr;
+               rm->rdma.op_rdma_mr = mr;
        }
        return err;
 }
@@ -699,5 +719,98 @@ int rds_cmsg_rdma_map(struct rds_sock *rs, struct rds_message *rm,
            rm->m_rdma_cookie != 0)
                return -EINVAL;
 
-       return __rds_rdma_map(rs, CMSG_DATA(cmsg), &rm->m_rdma_cookie, &rm->m_rdma_mr);
+       return __rds_rdma_map(rs, CMSG_DATA(cmsg), &rm->m_rdma_cookie, &rm->rdma.op_rdma_mr);
+}
+
+/*
+ * Fill in rds_message for an atomic request.
+ */
+int rds_cmsg_atomic(struct rds_sock *rs, struct rds_message *rm,
+                   struct cmsghdr *cmsg)
+{
+       struct page *page = NULL;
+       struct rds_atomic_args *args;
+       int ret = 0;
+
+       if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct rds_atomic_args))
+        || rm->atomic.op_active)
+               return -EINVAL;
+
+       args = CMSG_DATA(cmsg);
+
+       /* Nonmasked & masked cmsg ops converted to masked hw ops */
+       switch (cmsg->cmsg_type) {
+       case RDS_CMSG_ATOMIC_FADD:
+               rm->atomic.op_type = RDS_ATOMIC_TYPE_FADD;
+               rm->atomic.op_m_fadd.add = args->fadd.add;
+               rm->atomic.op_m_fadd.nocarry_mask = 0;
+               break;
+       case RDS_CMSG_MASKED_ATOMIC_FADD:
+               rm->atomic.op_type = RDS_ATOMIC_TYPE_FADD;
+               rm->atomic.op_m_fadd.add = args->m_fadd.add;
+               rm->atomic.op_m_fadd.nocarry_mask = args->m_fadd.nocarry_mask;
+               break;
+       case RDS_CMSG_ATOMIC_CSWP:
+               rm->atomic.op_type = RDS_ATOMIC_TYPE_CSWP;
+               rm->atomic.op_m_cswp.compare = args->cswp.compare;
+               rm->atomic.op_m_cswp.swap = args->cswp.swap;
+               rm->atomic.op_m_cswp.compare_mask = ~0;
+               rm->atomic.op_m_cswp.swap_mask = ~0;
+               break;
+       case RDS_CMSG_MASKED_ATOMIC_CSWP:
+               rm->atomic.op_type = RDS_ATOMIC_TYPE_CSWP;
+               rm->atomic.op_m_cswp.compare = args->m_cswp.compare;
+               rm->atomic.op_m_cswp.swap = args->m_cswp.swap;
+               rm->atomic.op_m_cswp.compare_mask = args->m_cswp.compare_mask;
+               rm->atomic.op_m_cswp.swap_mask = args->m_cswp.swap_mask;
+               break;
+       default:
+               BUG(); /* should never happen */
+       }
+
+       rm->atomic.op_notify = !!(args->flags & RDS_RDMA_NOTIFY_ME);
+       rm->atomic.op_silent = !!(args->flags & RDS_RDMA_SILENT);
+       rm->atomic.op_active = 1;
+       rm->atomic.op_recverr = rs->rs_recverr;
+       rm->atomic.op_sg = rds_message_alloc_sgs(rm, 1);
+
+       /* verify 8 byte-aligned */
+       if (args->local_addr & 0x7) {
+               ret = -EFAULT;
+               goto err;
+       }
+
+       ret = rds_pin_pages(args->local_addr, 1, &page, 1);
+       if (ret != 1)
+               goto err;
+       ret = 0;
+
+       sg_set_page(rm->atomic.op_sg, page, 8, offset_in_page(args->local_addr));
+
+       if (rm->atomic.op_notify || rm->atomic.op_recverr) {
+               /* We allocate an uninitialized notifier here, because
+                * we don't want to do that in the completion handler. We
+                * would have to use GFP_ATOMIC there, and don't want to deal
+                * with failed allocations.
+                */
+               rm->atomic.op_notifier = kmalloc(sizeof(*rm->atomic.op_notifier), GFP_KERNEL);
+               if (!rm->atomic.op_notifier) {
+                       ret = -ENOMEM;
+                       goto err;
+               }
+
+               rm->atomic.op_notifier->n_user_token = args->user_token;
+               rm->atomic.op_notifier->n_status = RDS_RDMA_SUCCESS;
+       }
+
+       rm->atomic.op_rkey = rds_rdma_cookie_key(args->cookie);
+       rm->atomic.op_remote_addr = args->remote_addr + rds_rdma_cookie_offset(args->cookie);
+
+       return ret;
+err:
+       if (page)
+               put_page(page);
+       kfree(rm->atomic.op_notifier);
+
+       return ret;
 }
diff --git a/net/rds/rdma.h b/net/rds/rdma.h
deleted file mode 100644 (file)
index 909c398..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-#ifndef _RDS_RDMA_H
-#define _RDS_RDMA_H
-
-#include <linux/rbtree.h>
-#include <linux/spinlock.h>
-#include <linux/scatterlist.h>
-
-#include "rds.h"
-
-struct rds_mr {
-       struct rb_node          r_rb_node;
-       atomic_t                r_refcount;
-       u32                     r_key;
-
-       /* A copy of the creation flags */
-       unsigned int            r_use_once:1;
-       unsigned int            r_invalidate:1;
-       unsigned int            r_write:1;
-
-       /* This is for RDS_MR_DEAD.
-        * It would be nice & consistent to make this part of the above
-        * bit field here, but we need to use test_and_set_bit.
-        */
-       unsigned long           r_state;
-       struct rds_sock         *r_sock; /* back pointer to the socket that owns us */
-       struct rds_transport    *r_trans;
-       void                    *r_trans_private;
-};
-
-/* Flags for mr->r_state */
-#define RDS_MR_DEAD            0
-
-struct rds_rdma_op {
-       u32                     r_key;
-       u64                     r_remote_addr;
-       unsigned int            r_write:1;
-       unsigned int            r_fence:1;
-       unsigned int            r_notify:1;
-       unsigned int            r_recverr:1;
-       unsigned int            r_mapped:1;
-       struct rds_notifier     *r_notifier;
-       unsigned int            r_bytes;
-       unsigned int            r_nents;
-       unsigned int            r_count;
-       struct scatterlist      r_sg[0];
-};
-
-static inline rds_rdma_cookie_t rds_rdma_make_cookie(u32 r_key, u32 offset)
-{
-       return r_key | (((u64) offset) << 32);
-}
-
-static inline u32 rds_rdma_cookie_key(rds_rdma_cookie_t cookie)
-{
-       return cookie;
-}
-
-static inline u32 rds_rdma_cookie_offset(rds_rdma_cookie_t cookie)
-{
-       return cookie >> 32;
-}
-
-int rds_get_mr(struct rds_sock *rs, char __user *optval, int optlen);
-int rds_get_mr_for_dest(struct rds_sock *rs, char __user *optval, int optlen);
-int rds_free_mr(struct rds_sock *rs, char __user *optval, int optlen);
-void rds_rdma_drop_keys(struct rds_sock *rs);
-int rds_cmsg_rdma_args(struct rds_sock *rs, struct rds_message *rm,
-                         struct cmsghdr *cmsg);
-int rds_cmsg_rdma_dest(struct rds_sock *rs, struct rds_message *rm,
-                         struct cmsghdr *cmsg);
-int rds_cmsg_rdma_args(struct rds_sock *rs, struct rds_message *rm,
-                         struct cmsghdr *cmsg);
-int rds_cmsg_rdma_map(struct rds_sock *rs, struct rds_message *rm,
-                         struct cmsghdr *cmsg);
-void rds_rdma_free_op(struct rds_rdma_op *ro);
-void rds_rdma_send_complete(struct rds_message *rm, int);
-
-extern void __rds_put_mr_final(struct rds_mr *mr);
-static inline void rds_mr_put(struct rds_mr *mr)
-{
-       if (atomic_dec_and_test(&mr->r_refcount))
-               __rds_put_mr_final(mr);
-}
-
-#endif
index e599ba2f950d72e03c4bc98f7b1a9b86742134e7..e6ed10aee190afa60a74b9f07222dc7ad8083fd0 100644 (file)
 
 static struct rdma_cm_id *rds_rdma_listen_id;
 
+static char *rds_cm_event_strings[] = {
+#define RDS_CM_EVENT_STRING(foo) \
+               [RDMA_CM_EVENT_##foo] = __stringify(RDMA_CM_EVENT_##foo)
+       RDS_CM_EVENT_STRING(ADDR_RESOLVED),
+       RDS_CM_EVENT_STRING(ADDR_ERROR),
+       RDS_CM_EVENT_STRING(ROUTE_RESOLVED),
+       RDS_CM_EVENT_STRING(ROUTE_ERROR),
+       RDS_CM_EVENT_STRING(CONNECT_REQUEST),
+       RDS_CM_EVENT_STRING(CONNECT_RESPONSE),
+       RDS_CM_EVENT_STRING(CONNECT_ERROR),
+       RDS_CM_EVENT_STRING(UNREACHABLE),
+       RDS_CM_EVENT_STRING(REJECTED),
+       RDS_CM_EVENT_STRING(ESTABLISHED),
+       RDS_CM_EVENT_STRING(DISCONNECTED),
+       RDS_CM_EVENT_STRING(DEVICE_REMOVAL),
+       RDS_CM_EVENT_STRING(MULTICAST_JOIN),
+       RDS_CM_EVENT_STRING(MULTICAST_ERROR),
+       RDS_CM_EVENT_STRING(ADDR_CHANGE),
+       RDS_CM_EVENT_STRING(TIMEWAIT_EXIT),
+#undef RDS_CM_EVENT_STRING
+};
+
+static char *rds_cm_event_str(enum rdma_cm_event_type type)
+{
+       return rds_str_array(rds_cm_event_strings,
+                            ARRAY_SIZE(rds_cm_event_strings), type);
+};
+
 int rds_rdma_cm_event_handler(struct rdma_cm_id *cm_id,
                              struct rdma_cm_event *event)
 {
@@ -44,8 +72,8 @@ int rds_rdma_cm_event_handler(struct rdma_cm_id *cm_id,
        struct rds_transport *trans;
        int ret = 0;
 
-       rdsdebug("conn %p id %p handling event %u\n", conn, cm_id,
-                event->event);
+       rdsdebug("conn %p id %p handling event %u (%s)\n", conn, cm_id,
+                event->event, rds_cm_event_str(event->event));
 
        if (cm_id->device->node_type == RDMA_NODE_RNIC)
                trans = &rds_iw_transport;
@@ -109,7 +137,8 @@ int rds_rdma_cm_event_handler(struct rdma_cm_id *cm_id,
 
        default:
                /* things like device disconnect? */
-               printk(KERN_ERR "RDS: unknown event %u!\n", event->event);
+               printk(KERN_ERR "RDS: unknown event %u (%s)!\n",
+                      event->event, rds_cm_event_str(event->event));
                break;
        }
 
@@ -117,12 +146,13 @@ out:
        if (conn)
                mutex_unlock(&conn->c_cm_lock);
 
-       rdsdebug("id %p event %u handling ret %d\n", cm_id, event->event, ret);
+       rdsdebug("id %p event %u (%s) handling ret %d\n", cm_id, event->event,
+                rds_cm_event_str(event->event), ret);
 
        return ret;
 }
 
-static int __init rds_rdma_listen_init(void)
+static int rds_rdma_listen_init(void)
 {
        struct sockaddr_in sin;
        struct rdma_cm_id *cm_id;
@@ -177,7 +207,7 @@ static void rds_rdma_listen_stop(void)
        }
 }
 
-int __init rds_rdma_init(void)
+int rds_rdma_init(void)
 {
        int ret;
 
index c224b5bb3ba9368fd00fad5f6a25f90d68364ebd..8103dcf8b97679b1f73ed1a339d348fd0da6a28b 100644 (file)
@@ -80,6 +80,7 @@ enum {
 /* Bits for c_flags */
 #define RDS_LL_SEND_FULL       0
 #define RDS_RECONNECT_PENDING  1
+#define RDS_IN_XMIT            2
 
 struct rds_connection {
        struct hlist_node       c_hash_node;
@@ -91,12 +92,13 @@ struct rds_connection {
        struct rds_cong_map     *c_lcong;
        struct rds_cong_map     *c_fcong;
 
-       struct mutex            c_send_lock;    /* protect send ring */
        struct rds_message      *c_xmit_rm;
        unsigned long           c_xmit_sg;
        unsigned int            c_xmit_hdr_off;
        unsigned int            c_xmit_data_off;
+       unsigned int            c_xmit_atomic_sent;
        unsigned int            c_xmit_rdma_sent;
+       unsigned int            c_xmit_data_sent;
 
        spinlock_t              c_lock;         /* protect msg queues */
        u64                     c_next_tx_seq;
@@ -116,11 +118,10 @@ struct rds_connection {
        struct delayed_work     c_conn_w;
        struct work_struct      c_down_w;
        struct mutex            c_cm_lock;      /* protect conn state & cm */
+       wait_queue_head_t       c_waitq;
 
        struct list_head        c_map_item;
        unsigned long           c_map_queued;
-       unsigned long           c_map_offset;
-       unsigned long           c_map_bytes;
 
        unsigned int            c_unacked_packets;
        unsigned int            c_unacked_bytes;
@@ -206,6 +207,48 @@ struct rds_incoming {
        rds_rdma_cookie_t       i_rdma_cookie;
 };
 
+struct rds_mr {
+       struct rb_node          r_rb_node;
+       atomic_t                r_refcount;
+       u32                     r_key;
+
+       /* A copy of the creation flags */
+       unsigned int            r_use_once:1;
+       unsigned int            r_invalidate:1;
+       unsigned int            r_write:1;
+
+       /* This is for RDS_MR_DEAD.
+        * It would be nice & consistent to make this part of the above
+        * bit field here, but we need to use test_and_set_bit.
+        */
+       unsigned long           r_state;
+       struct rds_sock         *r_sock; /* back pointer to the socket that owns us */
+       struct rds_transport    *r_trans;
+       void                    *r_trans_private;
+};
+
+/* Flags for mr->r_state */
+#define RDS_MR_DEAD            0
+
+static inline rds_rdma_cookie_t rds_rdma_make_cookie(u32 r_key, u32 offset)
+{
+       return r_key | (((u64) offset) << 32);
+}
+
+static inline u32 rds_rdma_cookie_key(rds_rdma_cookie_t cookie)
+{
+       return cookie;
+}
+
+static inline u32 rds_rdma_cookie_offset(rds_rdma_cookie_t cookie)
+{
+       return cookie >> 32;
+}
+
+/* atomic operation types */
+#define RDS_ATOMIC_TYPE_CSWP           0
+#define RDS_ATOMIC_TYPE_FADD           1
+
 /*
  * m_sock_item and m_conn_item are on lists that are serialized under
  * conn->c_lock.  m_sock_item has additional meaning in that once it is empty
@@ -258,13 +301,71 @@ struct rds_message {
         *   -> rs->rs_lock
         */
        spinlock_t              m_rs_lock;
+       wait_queue_head_t       m_flush_wait;
+
        struct rds_sock         *m_rs;
-       struct rds_rdma_op      *m_rdma_op;
+
+       /* cookie to send to remote, in rds header */
        rds_rdma_cookie_t       m_rdma_cookie;
-       struct rds_mr           *m_rdma_mr;
-       unsigned int            m_nents;
-       unsigned int            m_count;
-       struct scatterlist      m_sg[0];
+
+       unsigned int            m_used_sgs;
+       unsigned int            m_total_sgs;
+
+       void                    *m_final_op;
+
+       struct {
+               struct rm_atomic_op {
+                       int                     op_type;
+                       union {
+                               struct {
+                                       uint64_t        compare;
+                                       uint64_t        swap;
+                                       uint64_t        compare_mask;
+                                       uint64_t        swap_mask;
+                               } op_m_cswp;
+                               struct {
+                                       uint64_t        add;
+                                       uint64_t        nocarry_mask;
+                               } op_m_fadd;
+                       };
+
+                       u32                     op_rkey;
+                       u64                     op_remote_addr;
+                       unsigned int            op_notify:1;
+                       unsigned int            op_recverr:1;
+                       unsigned int            op_mapped:1;
+                       unsigned int            op_silent:1;
+                       unsigned int            op_active:1;
+                       struct scatterlist      *op_sg;
+                       struct rds_notifier     *op_notifier;
+
+                       struct rds_mr           *op_rdma_mr;
+               } atomic;
+               struct rm_rdma_op {
+                       u32                     op_rkey;
+                       u64                     op_remote_addr;
+                       unsigned int            op_write:1;
+                       unsigned int            op_fence:1;
+                       unsigned int            op_notify:1;
+                       unsigned int            op_recverr:1;
+                       unsigned int            op_mapped:1;
+                       unsigned int            op_silent:1;
+                       unsigned int            op_active:1;
+                       unsigned int            op_bytes;
+                       unsigned int            op_nents;
+                       unsigned int            op_count;
+                       struct scatterlist      *op_sg;
+                       struct rds_notifier     *op_notifier;
+
+                       struct rds_mr           *op_rdma_mr;
+               } rdma;
+               struct rm_data_op {
+                       unsigned int            op_active:1;
+                       unsigned int            op_nents;
+                       unsigned int            op_count;
+                       struct scatterlist      *op_sg;
+               } data;
+       };
 };
 
 /*
@@ -305,10 +406,6 @@ struct rds_notifier {
  *                 transport is responsible for other serialization, including
  *                 rds_recv_incoming().  This is called in process context but
  *                 should try hard not to block.
- *
- * @xmit_cong_map: This asks the transport to send the local bitmap down the
- *                given connection.  XXX get a better story about the bitmap
- *                flag and header.
  */
 
 #define RDS_TRANS_IB   0
@@ -332,13 +429,11 @@ struct rds_transport {
        void (*xmit_complete)(struct rds_connection *conn);
        int (*xmit)(struct rds_connection *conn, struct rds_message *rm,
                    unsigned int hdr_off, unsigned int sg, unsigned int off);
-       int (*xmit_cong_map)(struct rds_connection *conn,
-                            struct rds_cong_map *map, unsigned long offset);
-       int (*xmit_rdma)(struct rds_connection *conn, struct rds_rdma_op *op);
+       int (*xmit_rdma)(struct rds_connection *conn, struct rm_rdma_op *op);
+       int (*xmit_atomic)(struct rds_connection *conn, struct rm_atomic_op *op);
        int (*recv)(struct rds_connection *conn);
        int (*inc_copy_to_user)(struct rds_incoming *inc, struct iovec *iov,
                                size_t size);
-       void (*inc_purge)(struct rds_incoming *inc);
        void (*inc_free)(struct rds_incoming *inc);
 
        int (*cm_handle_connect)(struct rdma_cm_id *cm_id,
@@ -367,17 +462,11 @@ struct rds_sock {
         * bound_addr used for both incoming and outgoing, no INADDR_ANY
         * support.
         */
-       struct rb_node          rs_bound_node;
+       struct hlist_node       rs_bound_node;
        __be32                  rs_bound_addr;
        __be32                  rs_conn_addr;
        __be16                  rs_bound_port;
        __be16                  rs_conn_port;
-
-       /*
-        * This is only used to communicate the transport between bind and
-        * initiating connections.  All other trans use is referenced through
-        * the connection.
-        */
        struct rds_transport    *rs_transport;
 
        /*
@@ -466,8 +555,8 @@ struct rds_statistics {
        uint64_t        s_recv_ping;
        uint64_t        s_send_queue_empty;
        uint64_t        s_send_queue_full;
-       uint64_t        s_send_sem_contention;
-       uint64_t        s_send_sem_queue_raced;
+       uint64_t        s_send_lock_contention;
+       uint64_t        s_send_lock_queue_raced;
        uint64_t        s_send_immediate_retry;
        uint64_t        s_send_delayed_retry;
        uint64_t        s_send_drop_acked;
@@ -487,6 +576,7 @@ struct rds_statistics {
 };
 
 /* af_rds.c */
+char *rds_str_array(char **array, size_t elements, size_t index);
 void rds_sock_addref(struct rds_sock *rs);
 void rds_sock_put(struct rds_sock *rs);
 void rds_wake_sk_sleep(struct rds_sock *rs);
@@ -521,15 +611,17 @@ void rds_cong_exit(void);
 struct rds_message *rds_cong_update_alloc(struct rds_connection *conn);
 
 /* conn.c */
-int __init rds_conn_init(void);
+int rds_conn_init(void);
 void rds_conn_exit(void);
 struct rds_connection *rds_conn_create(__be32 laddr, __be32 faddr,
                                       struct rds_transport *trans, gfp_t gfp);
 struct rds_connection *rds_conn_create_outgoing(__be32 laddr, __be32 faddr,
                               struct rds_transport *trans, gfp_t gfp);
+void rds_conn_shutdown(struct rds_connection *conn);
 void rds_conn_destroy(struct rds_connection *conn);
 void rds_conn_reset(struct rds_connection *conn);
 void rds_conn_drop(struct rds_connection *conn);
+void rds_conn_connect_if_down(struct rds_connection *conn);
 void rds_for_each_conn_info(struct socket *sock, unsigned int len,
                          struct rds_info_iterator *iter,
                          struct rds_info_lengths *lens,
@@ -566,7 +658,8 @@ rds_conn_connecting(struct rds_connection *conn)
 
 /* message.c */
 struct rds_message *rds_message_alloc(unsigned int nents, gfp_t gfp);
-struct rds_message *rds_message_copy_from_user(struct iovec *first_iov,
+struct scatterlist *rds_message_alloc_sgs(struct rds_message *rm, int nents);
+int rds_message_copy_from_user(struct rds_message *rm, struct iovec *first_iov,
                                               size_t total_len);
 struct rds_message *rds_message_map_pages(unsigned long *page_addrs, unsigned int total_len);
 void rds_message_populate_header(struct rds_header *hdr, __be16 sport,
@@ -580,7 +673,6 @@ int rds_message_get_version_extension(struct rds_header *hdr, unsigned int *vers
 int rds_message_add_rdma_dest_extension(struct rds_header *hdr, u32 r_key, u32 offset);
 int rds_message_inc_copy_to_user(struct rds_incoming *inc,
                                 struct iovec *first_iov, size_t size);
-void rds_message_inc_purge(struct rds_incoming *inc);
 void rds_message_inc_free(struct rds_incoming *inc);
 void rds_message_addref(struct rds_message *rm);
 void rds_message_put(struct rds_message *rm);
@@ -636,14 +728,39 @@ void rds_send_drop_to(struct rds_sock *rs, struct sockaddr_in *dest);
 typedef int (*is_acked_func)(struct rds_message *rm, uint64_t ack);
 void rds_send_drop_acked(struct rds_connection *conn, u64 ack,
                         is_acked_func is_acked);
-int rds_send_acked_before(struct rds_connection *conn, u64 seq);
 void rds_send_remove_from_sock(struct list_head *messages, int status);
 int rds_send_pong(struct rds_connection *conn, __be16 dport);
 struct rds_message *rds_send_get_message(struct rds_connection *,
-                                        struct rds_rdma_op *);
+                                        struct rm_rdma_op *);
 
 /* rdma.c */
 void rds_rdma_unuse(struct rds_sock *rs, u32 r_key, int force);
+int rds_get_mr(struct rds_sock *rs, char __user *optval, int optlen);
+int rds_get_mr_for_dest(struct rds_sock *rs, char __user *optval, int optlen);
+int rds_free_mr(struct rds_sock *rs, char __user *optval, int optlen);
+void rds_rdma_drop_keys(struct rds_sock *rs);
+int rds_rdma_extra_size(struct rds_rdma_args *args);
+int rds_cmsg_rdma_args(struct rds_sock *rs, struct rds_message *rm,
+                         struct cmsghdr *cmsg);
+int rds_cmsg_rdma_dest(struct rds_sock *rs, struct rds_message *rm,
+                         struct cmsghdr *cmsg);
+int rds_cmsg_rdma_args(struct rds_sock *rs, struct rds_message *rm,
+                         struct cmsghdr *cmsg);
+int rds_cmsg_rdma_map(struct rds_sock *rs, struct rds_message *rm,
+                         struct cmsghdr *cmsg);
+void rds_rdma_free_op(struct rm_rdma_op *ro);
+void rds_atomic_free_op(struct rm_atomic_op *ao);
+void rds_rdma_send_complete(struct rds_message *rm, int wc_status);
+void rds_atomic_send_complete(struct rds_message *rm, int wc_status);
+int rds_cmsg_atomic(struct rds_sock *rs, struct rds_message *rm,
+                   struct cmsghdr *cmsg);
+
+extern void __rds_put_mr_final(struct rds_mr *mr);
+static inline void rds_mr_put(struct rds_mr *mr)
+{
+       if (atomic_dec_and_test(&mr->r_refcount))
+               __rds_put_mr_final(mr);
+}
 
 /* stats.c */
 DECLARE_PER_CPU_SHARED_ALIGNED(struct rds_statistics, rds_stats);
@@ -657,14 +774,14 @@ DECLARE_PER_CPU_SHARED_ALIGNED(struct rds_statistics, rds_stats);
        put_cpu();                                      \
 } while (0)
 #define rds_stats_add(member, count) rds_stats_add_which(rds_stats, member, count)
-int __init rds_stats_init(void);
+int rds_stats_init(void);
 void rds_stats_exit(void);
 void rds_stats_info_copy(struct rds_info_iterator *iter,
                         uint64_t *values, const char *const *names,
                         size_t nr);
 
 /* sysctl.c */
-int __init rds_sysctl_init(void);
+int rds_sysctl_init(void);
 void rds_sysctl_exit(void);
 extern unsigned long rds_sysctl_sndbuf_min;
 extern unsigned long rds_sysctl_sndbuf_default;
@@ -678,9 +795,10 @@ extern unsigned long rds_sysctl_trace_flags;
 extern unsigned int  rds_sysctl_trace_level;
 
 /* threads.c */
-int __init rds_threads_init(void);
+int rds_threads_init(void);
 void rds_threads_exit(void);
 extern struct workqueue_struct *rds_wq;
+void rds_queue_reconnect(struct rds_connection *conn);
 void rds_connect_worker(struct work_struct *);
 void rds_shutdown_worker(struct work_struct *);
 void rds_send_worker(struct work_struct *);
@@ -691,9 +809,10 @@ void rds_connect_complete(struct rds_connection *conn);
 int rds_trans_register(struct rds_transport *trans);
 void rds_trans_unregister(struct rds_transport *trans);
 struct rds_transport *rds_trans_get_preferred(__be32 addr);
+void rds_trans_put(struct rds_transport *trans);
 unsigned int rds_trans_stats_info_copy(struct rds_info_iterator *iter,
                                       unsigned int avail);
-int __init rds_trans_init(void);
+int rds_trans_init(void);
 void rds_trans_exit(void);
 
 #endif
index c93588c2d553cf6b162ab500cf1fd72dbbc9c26c..68800f02aa3047c12f59eb47c7c71db84c5127aa 100644 (file)
@@ -36,7 +36,6 @@
 #include <linux/in.h>
 
 #include "rds.h"
-#include "rdma.h"
 
 void rds_inc_init(struct rds_incoming *inc, struct rds_connection *conn,
                  __be32 saddr)
@@ -210,7 +209,7 @@ void rds_recv_incoming(struct rds_connection *conn, __be32 saddr, __be32 daddr,
        }
 
        rs = rds_find_bound(daddr, inc->i_hdr.h_dport);
-       if (rs == NULL) {
+       if (!rs) {
                rds_stats_inc(s_recv_drop_no_sock);
                goto out;
        }
@@ -251,7 +250,7 @@ static int rds_next_incoming(struct rds_sock *rs, struct rds_incoming **inc)
 {
        unsigned long flags;
 
-       if (*inc == NULL) {
+       if (!*inc) {
                read_lock_irqsave(&rs->rs_recv_lock, flags);
                if (!list_empty(&rs->rs_recv_queue)) {
                        *inc = list_entry(rs->rs_recv_queue.next,
@@ -334,10 +333,10 @@ int rds_notify_queue_get(struct rds_sock *rs, struct msghdr *msghdr)
 
                if (msghdr) {
                        cmsg.user_token = notifier->n_user_token;
-                       cmsg.status  = notifier->n_status;
+                       cmsg.status = notifier->n_status;
 
                        err = put_cmsg(msghdr, SOL_RDS, RDS_CMSG_RDMA_STATUS,
-                                       sizeof(cmsg), &cmsg);
+                                      sizeof(cmsg), &cmsg);
                        if (err)
                                break;
                }
index 9c1c6bcaa6c9532e9abdbbd198b8ab6e6c7b9400..9b951a0ab6b7f6a7c3bdb14a7e1c23e630f3ec99 100644 (file)
@@ -37,7 +37,6 @@
 #include <linux/list.h>
 
 #include "rds.h"
-#include "rdma.h"
 
 /* When transmitting messages in rds_send_xmit, we need to emerge from
  * time to time and briefly release the CPU. Otherwise the softlock watchdog
@@ -54,7 +53,8 @@ module_param(send_batch_count, int, 0444);
 MODULE_PARM_DESC(send_batch_count, " batch factor when working the send queue");
 
 /*
- * Reset the send state. Caller must hold c_send_lock when calling here.
+ * Reset the send state.  Callers must ensure that this doesn't race with
+ * rds_send_xmit().
  */
 void rds_send_reset(struct rds_connection *conn)
 {
@@ -62,18 +62,22 @@ void rds_send_reset(struct rds_connection *conn)
        unsigned long flags;
 
        if (conn->c_xmit_rm) {
+               rm = conn->c_xmit_rm;
+               conn->c_xmit_rm = NULL;
                /* Tell the user the RDMA op is no longer mapped by the
                 * transport. This isn't entirely true (it's flushed out
                 * independently) but as the connection is down, there's
                 * no ongoing RDMA to/from that memory */
-               rds_message_unmapped(conn->c_xmit_rm);
-               rds_message_put(conn->c_xmit_rm);
-               conn->c_xmit_rm = NULL;
+               rds_message_unmapped(rm);
+               rds_message_put(rm);
        }
+
        conn->c_xmit_sg = 0;
        conn->c_xmit_hdr_off = 0;
        conn->c_xmit_data_off = 0;
+       conn->c_xmit_atomic_sent = 0;
        conn->c_xmit_rdma_sent = 0;
+       conn->c_xmit_data_sent = 0;
 
        conn->c_map_queued = 0;
 
@@ -90,6 +94,25 @@ void rds_send_reset(struct rds_connection *conn)
        spin_unlock_irqrestore(&conn->c_lock, flags);
 }
 
+static int acquire_in_xmit(struct rds_connection *conn)
+{
+       return test_and_set_bit(RDS_IN_XMIT, &conn->c_flags) == 0;
+}
+
+static void release_in_xmit(struct rds_connection *conn)
+{
+       clear_bit(RDS_IN_XMIT, &conn->c_flags);
+       smp_mb__after_clear_bit();
+       /*
+        * We don't use wait_on_bit()/wake_up_bit() because our waking is in a
+        * hot path and finding waiters is very rare.  We don't want to walk
+        * the system-wide hashed waitqueue buckets in the fast path only to
+        * almost never find waiters.
+        */
+       if (waitqueue_active(&conn->c_waitq))
+               wake_up_all(&conn->c_waitq);
+}
+
 /*
  * We're making the concious trade-off here to only send one message
  * down the connection at a time.
@@ -109,102 +132,69 @@ int rds_send_xmit(struct rds_connection *conn)
        struct rds_message *rm;
        unsigned long flags;
        unsigned int tmp;
-       unsigned int send_quota = send_batch_count;
        struct scatterlist *sg;
        int ret = 0;
-       int was_empty = 0;
        LIST_HEAD(to_be_dropped);
 
+restart:
+
        /*
         * sendmsg calls here after having queued its message on the send
         * queue.  We only have one task feeding the connection at a time.  If
         * another thread is already feeding the queue then we back off.  This
         * avoids blocking the caller and trading per-connection data between
         * caches per message.
-        *
-        * The sem holder will issue a retry if they notice that someone queued
-        * a message after they stopped walking the send queue but before they
-        * dropped the sem.
         */
-       if (!mutex_trylock(&conn->c_send_lock)) {
-               rds_stats_inc(s_send_sem_contention);
+       if (!acquire_in_xmit(conn)) {
+               rds_stats_inc(s_send_lock_contention);
                ret = -ENOMEM;
                goto out;
        }
 
+       /*
+        * rds_conn_shutdown() sets the conn state and then tests RDS_IN_XMIT,
+        * we do the opposite to avoid races.
+        */
+       if (!rds_conn_up(conn)) {
+               release_in_xmit(conn);
+               ret = 0;
+               goto out;
+       }
+
        if (conn->c_trans->xmit_prepare)
                conn->c_trans->xmit_prepare(conn);
 
        /*
         * spin trying to push headers and data down the connection until
-        * the connection doens't make forward progress.
+        * the connection doesn't make forward progress.
         */
-       while (--send_quota) {
-               /*
-                * See if need to send a congestion map update if we're
-                * between sending messages.  The send_sem protects our sole
-                * use of c_map_offset and _bytes.
-                * Note this is used only by transports that define a special
-                * xmit_cong_map function. For all others, we create allocate
-                * a cong_map message and treat it just like any other send.
-                */
-               if (conn->c_map_bytes) {
-                       ret = conn->c_trans->xmit_cong_map(conn, conn->c_lcong,
-                                               conn->c_map_offset);
-                       if (ret <= 0)
-                               break;
+       while (1) {
 
-                       conn->c_map_offset += ret;
-                       conn->c_map_bytes -= ret;
-                       if (conn->c_map_bytes)
-                               continue;
-               }
-
-               /* If we're done sending the current message, clear the
-                * offset and S/G temporaries.
-                */
                rm = conn->c_xmit_rm;
-               if (rm != NULL &&
-                   conn->c_xmit_hdr_off == sizeof(struct rds_header) &&
-                   conn->c_xmit_sg == rm->m_nents) {
-                       conn->c_xmit_rm = NULL;
-                       conn->c_xmit_sg = 0;
-                       conn->c_xmit_hdr_off = 0;
-                       conn->c_xmit_data_off = 0;
-                       conn->c_xmit_rdma_sent = 0;
 
-                       /* Release the reference to the previous message. */
-                       rds_message_put(rm);
-                       rm = NULL;
-               }
-
-               /* If we're asked to send a cong map update, do so.
+               /*
+                * If between sending messages, we can send a pending congestion
+                * map update.
                 */
-               if (rm == NULL && test_and_clear_bit(0, &conn->c_map_queued)) {
-                       if (conn->c_trans->xmit_cong_map != NULL) {
-                               conn->c_map_offset = 0;
-                               conn->c_map_bytes = sizeof(struct rds_header) +
-                                       RDS_CONG_MAP_BYTES;
-                               continue;
-                       }
-
+               if (!rm && test_and_clear_bit(0, &conn->c_map_queued)) {
                        rm = rds_cong_update_alloc(conn);
                        if (IS_ERR(rm)) {
                                ret = PTR_ERR(rm);
                                break;
                        }
+                       rm->data.op_active = 1;
 
                        conn->c_xmit_rm = rm;
                }
 
                /*
-                * Grab the next message from the send queue, if there is one.
+                * If not already working on one, grab the next message.
                 *
                 * c_xmit_rm holds a ref while we're sending this message down
                 * the connction.  We can use this ref while holding the
                 * send_sem.. rds_send_reset() is serialized with it.
                 */
-               if (rm == NULL) {
+               if (!rm) {
                        unsigned int len;
 
                        spin_lock_irqsave(&conn->c_lock, flags);
@@ -224,10 +214,8 @@ int rds_send_xmit(struct rds_connection *conn)
 
                        spin_unlock_irqrestore(&conn->c_lock, flags);
 
-                       if (rm == NULL) {
-                               was_empty = 1;
+                       if (!rm)
                                break;
-                       }
 
                        /* Unfortunately, the way Infiniband deals with
                         * RDMA to a bad MR key is by moving the entire
@@ -236,13 +224,12 @@ int rds_send_xmit(struct rds_connection *conn)
                         * connection.
                         * Therefore, we never retransmit messages with RDMA ops.
                         */
-                       if (rm->m_rdma_op &&
+                       if (rm->rdma.op_active &&
                            test_bit(RDS_MSG_RETRANSMITTED, &rm->m_flags)) {
                                spin_lock_irqsave(&conn->c_lock, flags);
                                if (test_and_clear_bit(RDS_MSG_ON_CONN, &rm->m_flags))
                                        list_move(&rm->m_conn_item, &to_be_dropped);
                                spin_unlock_irqrestore(&conn->c_lock, flags);
-                               rds_message_put(rm);
                                continue;
                        }
 
@@ -263,23 +250,55 @@ int rds_send_xmit(struct rds_connection *conn)
                        conn->c_xmit_rm = rm;
                }
 
-               /*
-                * Try and send an rdma message.  Let's see if we can
-                * keep this simple and require that the transport either
-                * send the whole rdma or none of it.
-                */
-               if (rm->m_rdma_op && !conn->c_xmit_rdma_sent) {
-                       ret = conn->c_trans->xmit_rdma(conn, rm->m_rdma_op);
+               /* The transport either sends the whole rdma or none of it */
+               if (rm->rdma.op_active && !conn->c_xmit_rdma_sent) {
+                       rm->m_final_op = &rm->rdma;
+                       ret = conn->c_trans->xmit_rdma(conn, &rm->rdma);
                        if (ret)
                                break;
                        conn->c_xmit_rdma_sent = 1;
+
                        /* The transport owns the mapped memory for now.
                         * You can't unmap it while it's on the send queue */
                        set_bit(RDS_MSG_MAPPED, &rm->m_flags);
                }
 
-               if (conn->c_xmit_hdr_off < sizeof(struct rds_header) ||
-                   conn->c_xmit_sg < rm->m_nents) {
+               if (rm->atomic.op_active && !conn->c_xmit_atomic_sent) {
+                       rm->m_final_op = &rm->atomic;
+                       ret = conn->c_trans->xmit_atomic(conn, &rm->atomic);
+                       if (ret)
+                               break;
+                       conn->c_xmit_atomic_sent = 1;
+
+                       /* The transport owns the mapped memory for now.
+                        * You can't unmap it while it's on the send queue */
+                       set_bit(RDS_MSG_MAPPED, &rm->m_flags);
+               }
+
+               /*
+                * A number of cases require an RDS header to be sent
+                * even if there is no data.
+                * We permit 0-byte sends; rds-ping depends on this.
+                * However, if there are exclusively attached silent ops,
+                * we skip the hdr/data send, to enable silent operation.
+                */
+               if (rm->data.op_nents == 0) {
+                       int ops_present;
+                       int all_ops_are_silent = 1;
+
+                       ops_present = (rm->atomic.op_active || rm->rdma.op_active);
+                       if (rm->atomic.op_active && !rm->atomic.op_silent)
+                               all_ops_are_silent = 0;
+                       if (rm->rdma.op_active && !rm->rdma.op_silent)
+                               all_ops_are_silent = 0;
+
+                       if (ops_present && all_ops_are_silent
+                           && !rm->m_rdma_cookie)
+                               rm->data.op_active = 0;
+               }
+
+               if (rm->data.op_active && !conn->c_xmit_data_sent) {
+                       rm->m_final_op = &rm->data;
                        ret = conn->c_trans->xmit(conn, rm,
                                                  conn->c_xmit_hdr_off,
                                                  conn->c_xmit_sg,
@@ -295,7 +314,7 @@ int rds_send_xmit(struct rds_connection *conn)
                                ret -= tmp;
                        }
 
-                       sg = &rm->m_sg[conn->c_xmit_sg];
+                       sg = &rm->data.op_sg[conn->c_xmit_sg];
                        while (ret) {
                                tmp = min_t(int, ret, sg->length -
                                                      conn->c_xmit_data_off);
@@ -306,49 +325,63 @@ int rds_send_xmit(struct rds_connection *conn)
                                        sg++;
                                        conn->c_xmit_sg++;
                                        BUG_ON(ret != 0 &&
-                                              conn->c_xmit_sg == rm->m_nents);
+                                              conn->c_xmit_sg == rm->data.op_nents);
                                }
                        }
+
+                       if (conn->c_xmit_hdr_off == sizeof(struct rds_header) &&
+                           (conn->c_xmit_sg == rm->data.op_nents))
+                               conn->c_xmit_data_sent = 1;
                }
-       }
 
-       /* Nuke any messages we decided not to retransmit. */
-       if (!list_empty(&to_be_dropped))
-               rds_send_remove_from_sock(&to_be_dropped, RDS_RDMA_DROPPED);
+               /*
+                * A rm will only take multiple times through this loop
+                * if there is a data op. Thus, if the data is sent (or there was
+                * none), then we're done with the rm.
+                */
+               if (!rm->data.op_active || conn->c_xmit_data_sent) {
+                       conn->c_xmit_rm = NULL;
+                       conn->c_xmit_sg = 0;
+                       conn->c_xmit_hdr_off = 0;
+                       conn->c_xmit_data_off = 0;
+                       conn->c_xmit_rdma_sent = 0;
+                       conn->c_xmit_atomic_sent = 0;
+                       conn->c_xmit_data_sent = 0;
+
+                       rds_message_put(rm);
+               }
+       }
 
        if (conn->c_trans->xmit_complete)
                conn->c_trans->xmit_complete(conn);
 
-       /*
-        * We might be racing with another sender who queued a message but
-        * backed off on noticing that we held the c_send_lock.  If we check
-        * for queued messages after dropping the sem then either we'll
-        * see the queued message or the queuer will get the sem.  If we
-        * notice the queued message then we trigger an immediate retry.
-        *
-        * We need to be careful only to do this when we stopped processing
-        * the send queue because it was empty.  It's the only way we
-        * stop processing the loop when the transport hasn't taken
-        * responsibility for forward progress.
-        */
-       mutex_unlock(&conn->c_send_lock);
+       release_in_xmit(conn);
 
-       if (conn->c_map_bytes || (send_quota == 0 && !was_empty)) {
-               /* We exhausted the send quota, but there's work left to
-                * do. Return and (re-)schedule the send worker.
-                */
-               ret = -EAGAIN;
+       /* Nuke any messages we decided not to retransmit. */
+       if (!list_empty(&to_be_dropped)) {
+               /* irqs on here, so we can put(), unlike above */
+               list_for_each_entry(rm, &to_be_dropped, m_conn_item)
+                       rds_message_put(rm);
+               rds_send_remove_from_sock(&to_be_dropped, RDS_RDMA_DROPPED);
        }
 
-       if (ret == 0 && was_empty) {
-               /* A simple bit test would be way faster than taking the
-                * spin lock */
-               spin_lock_irqsave(&conn->c_lock, flags);
+       /*
+        * Other senders can queue a message after we last test the send queue
+        * but before we clear RDS_IN_XMIT.  In that case they'd back off and
+        * not try and send their newly queued message.  We need to check the
+        * send queue after having cleared RDS_IN_XMIT so that their message
+        * doesn't get stuck on the send queue.
+        *
+        * If the transport cannot continue (i.e ret != 0), then it must
+        * call us when more room is available, such as from the tx
+        * completion handler.
+        */
+       if (ret == 0) {
+               smp_mb();
                if (!list_empty(&conn->c_send_queue)) {
-                       rds_stats_inc(s_send_sem_queue_raced);
-                       ret = -EAGAIN;
+                       rds_stats_inc(s_send_lock_queue_raced);
+                       goto restart;
                }
-               spin_unlock_irqrestore(&conn->c_lock, flags);
        }
 out:
        return ret;
@@ -376,52 +409,60 @@ static inline int rds_send_is_acked(struct rds_message *rm, u64 ack,
 }
 
 /*
- * Returns true if there are no messages on the send and retransmit queues
- * which have a sequence number greater than or equal to the given sequence
- * number.
+ * This is pretty similar to what happens below in the ACK
+ * handling code - except that we call here as soon as we get
+ * the IB send completion on the RDMA op and the accompanying
+ * message.
  */
-int rds_send_acked_before(struct rds_connection *conn, u64 seq)
+void rds_rdma_send_complete(struct rds_message *rm, int status)
 {
-       struct rds_message *rm, *tmp;
-       int ret = 1;
+       struct rds_sock *rs = NULL;
+       struct rm_rdma_op *ro;
+       struct rds_notifier *notifier;
+       unsigned long flags;
 
-       spin_lock(&conn->c_lock);
+       spin_lock_irqsave(&rm->m_rs_lock, flags);
 
-       list_for_each_entry_safe(rm, tmp, &conn->c_retrans, m_conn_item) {
-               if (be64_to_cpu(rm->m_inc.i_hdr.h_sequence) < seq)
-                       ret = 0;
-               break;
-       }
+       ro = &rm->rdma;
+       if (test_bit(RDS_MSG_ON_SOCK, &rm->m_flags) &&
+           ro->op_active && ro->op_notify && ro->op_notifier) {
+               notifier = ro->op_notifier;
+               rs = rm->m_rs;
+               sock_hold(rds_rs_to_sk(rs));
 
-       list_for_each_entry_safe(rm, tmp, &conn->c_send_queue, m_conn_item) {
-               if (be64_to_cpu(rm->m_inc.i_hdr.h_sequence) < seq)
-                       ret = 0;
-               break;
+               notifier->n_status = status;
+               spin_lock(&rs->rs_lock);
+               list_add_tail(&notifier->n_list, &rs->rs_notify_queue);
+               spin_unlock(&rs->rs_lock);
+
+               ro->op_notifier = NULL;
        }
 
-       spin_unlock(&conn->c_lock);
+       spin_unlock_irqrestore(&rm->m_rs_lock, flags);
 
-       return ret;
+       if (rs) {
+               rds_wake_sk_sleep(rs);
+               sock_put(rds_rs_to_sk(rs));
+       }
 }
+EXPORT_SYMBOL_GPL(rds_rdma_send_complete);
 
 /*
- * This is pretty similar to what happens below in the ACK
- * handling code - except that we call here as soon as we get
- * the IB send completion on the RDMA op and the accompanying
- * message.
+ * Just like above, except looks at atomic op
  */
-void rds_rdma_send_complete(struct rds_message *rm, int status)
+void rds_atomic_send_complete(struct rds_message *rm, int status)
 {
        struct rds_sock *rs = NULL;
-       struct rds_rdma_op *ro;
+       struct rm_atomic_op *ao;
        struct rds_notifier *notifier;
+       unsigned long flags;
 
-       spin_lock(&rm->m_rs_lock);
+       spin_lock_irqsave(&rm->m_rs_lock, flags);
 
-       ro = rm->m_rdma_op;
-       if (test_bit(RDS_MSG_ON_SOCK, &rm->m_flags) &&
-           ro && ro->r_notify && ro->r_notifier) {
-               notifier = ro->r_notifier;
+       ao = &rm->atomic;
+       if (test_bit(RDS_MSG_ON_SOCK, &rm->m_flags)
+           && ao->op_active && ao->op_notify && ao->op_notifier) {
+               notifier = ao->op_notifier;
                rs = rm->m_rs;
                sock_hold(rds_rs_to_sk(rs));
 
@@ -430,17 +471,17 @@ void rds_rdma_send_complete(struct rds_message *rm, int status)
                list_add_tail(&notifier->n_list, &rs->rs_notify_queue);
                spin_unlock(&rs->rs_lock);
 
-               ro->r_notifier = NULL;
+               ao->op_notifier = NULL;
        }
 
-       spin_unlock(&rm->m_rs_lock);
+       spin_unlock_irqrestore(&rm->m_rs_lock, flags);
 
        if (rs) {
                rds_wake_sk_sleep(rs);
                sock_put(rds_rs_to_sk(rs));
        }
 }
-EXPORT_SYMBOL_GPL(rds_rdma_send_complete);
+EXPORT_SYMBOL_GPL(rds_atomic_send_complete);
 
 /*
  * This is the same as rds_rdma_send_complete except we
@@ -448,15 +489,23 @@ EXPORT_SYMBOL_GPL(rds_rdma_send_complete);
  * socket, socket lock) and can just move the notifier.
  */
 static inline void
-__rds_rdma_send_complete(struct rds_sock *rs, struct rds_message *rm, int status)
+__rds_send_complete(struct rds_sock *rs, struct rds_message *rm, int status)
 {
-       struct rds_rdma_op *ro;
+       struct rm_rdma_op *ro;
+       struct rm_atomic_op *ao;
+
+       ro = &rm->rdma;
+       if (ro->op_active && ro->op_notify && ro->op_notifier) {
+               ro->op_notifier->n_status = status;
+               list_add_tail(&ro->op_notifier->n_list, &rs->rs_notify_queue);
+               ro->op_notifier = NULL;
+       }
 
-       ro = rm->m_rdma_op;
-       if (ro && ro->r_notify && ro->r_notifier) {
-               ro->r_notifier->n_status = status;
-               list_add_tail(&ro->r_notifier->n_list, &rs->rs_notify_queue);
-               ro->r_notifier = NULL;
+       ao = &rm->atomic;
+       if (ao->op_active && ao->op_notify && ao->op_notifier) {
+               ao->op_notifier->n_status = status;
+               list_add_tail(&ao->op_notifier->n_list, &rs->rs_notify_queue);
+               ao->op_notifier = NULL;
        }
 
        /* No need to wake the app - caller does this */
@@ -468,7 +517,7 @@ __rds_rdma_send_complete(struct rds_sock *rs, struct rds_message *rm, int status
  * So speed is not an issue here.
  */
 struct rds_message *rds_send_get_message(struct rds_connection *conn,
-                                        struct rds_rdma_op *op)
+                                        struct rm_rdma_op *op)
 {
        struct rds_message *rm, *tmp, *found = NULL;
        unsigned long flags;
@@ -476,7 +525,7 @@ struct rds_message *rds_send_get_message(struct rds_connection *conn,
        spin_lock_irqsave(&conn->c_lock, flags);
 
        list_for_each_entry_safe(rm, tmp, &conn->c_retrans, m_conn_item) {
-               if (rm->m_rdma_op == op) {
+               if (&rm->rdma == op) {
                        atomic_inc(&rm->m_refcount);
                        found = rm;
                        goto out;
@@ -484,7 +533,7 @@ struct rds_message *rds_send_get_message(struct rds_connection *conn,
        }
 
        list_for_each_entry_safe(rm, tmp, &conn->c_send_queue, m_conn_item) {
-               if (rm->m_rdma_op == op) {
+               if (&rm->rdma == op) {
                        atomic_inc(&rm->m_refcount);
                        found = rm;
                        break;
@@ -544,19 +593,20 @@ void rds_send_remove_from_sock(struct list_head *messages, int status)
                spin_lock(&rs->rs_lock);
 
                if (test_and_clear_bit(RDS_MSG_ON_SOCK, &rm->m_flags)) {
-                       struct rds_rdma_op *ro = rm->m_rdma_op;
+                       struct rm_rdma_op *ro = &rm->rdma;
                        struct rds_notifier *notifier;
 
                        list_del_init(&rm->m_sock_item);
                        rds_send_sndbuf_remove(rs, rm);
 
-                       if (ro && ro->r_notifier && (status || ro->r_notify)) {
-                               notifier = ro->r_notifier;
+                       if (ro->op_active && ro->op_notifier &&
+                              (ro->op_notify || (ro->op_recverr && status))) {
+                               notifier = ro->op_notifier;
                                list_add_tail(&notifier->n_list,
                                                &rs->rs_notify_queue);
                                if (!notifier->n_status)
                                        notifier->n_status = status;
-                               rm->m_rdma_op->r_notifier = NULL;
+                               rm->rdma.op_notifier = NULL;
                        }
                        was_on_sock = 1;
                        rm->m_rs = NULL;
@@ -619,9 +669,8 @@ void rds_send_drop_to(struct rds_sock *rs, struct sockaddr_in *dest)
 {
        struct rds_message *rm, *tmp;
        struct rds_connection *conn;
-       unsigned long flags, flags2;
+       unsigned long flags;
        LIST_HEAD(list);
-       int wake = 0;
 
        /* get all the messages we're dropping under the rs lock */
        spin_lock_irqsave(&rs->rs_lock, flags);
@@ -631,59 +680,54 @@ void rds_send_drop_to(struct rds_sock *rs, struct sockaddr_in *dest)
                             dest->sin_port != rm->m_inc.i_hdr.h_dport))
                        continue;
 
-               wake = 1;
                list_move(&rm->m_sock_item, &list);
                rds_send_sndbuf_remove(rs, rm);
                clear_bit(RDS_MSG_ON_SOCK, &rm->m_flags);
        }
 
        /* order flag updates with the rs lock */
-       if (wake)
-               smp_mb__after_clear_bit();
+       smp_mb__after_clear_bit();
 
        spin_unlock_irqrestore(&rs->rs_lock, flags);
 
-       conn = NULL;
+       if (list_empty(&list))
+               return;
 
-       /* now remove the messages from the conn list as needed */
+       /* Remove the messages from the conn */
        list_for_each_entry(rm, &list, m_sock_item) {
-               /* We do this here rather than in the loop above, so that
-                * we don't have to nest m_rs_lock under rs->rs_lock */
-               spin_lock_irqsave(&rm->m_rs_lock, flags2);
-               /* If this is a RDMA operation, notify the app. */
-               spin_lock(&rs->rs_lock);
-               __rds_rdma_send_complete(rs, rm, RDS_RDMA_CANCELED);
-               spin_unlock(&rs->rs_lock);
-               rm->m_rs = NULL;
-               spin_unlock_irqrestore(&rm->m_rs_lock, flags2);
 
+               conn = rm->m_inc.i_conn;
+
+               spin_lock_irqsave(&conn->c_lock, flags);
                /*
-                * If we see this flag cleared then we're *sure* that someone
-                * else beat us to removing it from the conn.  If we race
-                * with their flag update we'll get the lock and then really
-                * see that the flag has been cleared.
+                * Maybe someone else beat us to removing rm from the conn.
+                * If we race with their flag update we'll get the lock and
+                * then really see that the flag has been cleared.
                 */
-               if (!test_bit(RDS_MSG_ON_CONN, &rm->m_flags))
+               if (!test_and_clear_bit(RDS_MSG_ON_CONN, &rm->m_flags)) {
+                       spin_unlock_irqrestore(&conn->c_lock, flags);
                        continue;
-
-               if (conn != rm->m_inc.i_conn) {
-                       if (conn)
-                               spin_unlock_irqrestore(&conn->c_lock, flags);
-                       conn = rm->m_inc.i_conn;
-                       spin_lock_irqsave(&conn->c_lock, flags);
                }
+               list_del_init(&rm->m_conn_item);
+               spin_unlock_irqrestore(&conn->c_lock, flags);
 
-               if (test_and_clear_bit(RDS_MSG_ON_CONN, &rm->m_flags)) {
-                       list_del_init(&rm->m_conn_item);
-                       rds_message_put(rm);
-               }
-       }
+               /*
+                * Couldn't grab m_rs_lock in top loop (lock ordering),
+                * but we can now.
+                */
+               spin_lock_irqsave(&rm->m_rs_lock, flags);
 
-       if (conn)
-               spin_unlock_irqrestore(&conn->c_lock, flags);
+               spin_lock(&rs->rs_lock);
+               __rds_send_complete(rs, rm, RDS_RDMA_CANCELED);
+               spin_unlock(&rs->rs_lock);
 
-       if (wake)
-               rds_wake_sk_sleep(rs);
+               rm->m_rs = NULL;
+               spin_unlock_irqrestore(&rm->m_rs_lock, flags);
+
+               rds_message_put(rm);
+       }
+
+       rds_wake_sk_sleep(rs);
 
        while (!list_empty(&list)) {
                rm = list_entry(list.next, struct rds_message, m_sock_item);
@@ -763,6 +807,63 @@ out:
        return *queued;
 }
 
+/*
+ * rds_message is getting to be quite complicated, and we'd like to allocate
+ * it all in one go. This figures out how big it needs to be up front.
+ */
+static int rds_rm_size(struct msghdr *msg, int data_len)
+{
+       struct cmsghdr *cmsg;
+       int size = 0;
+       int cmsg_groups = 0;
+       int retval;
+
+       for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
+               if (!CMSG_OK(msg, cmsg))
+                       return -EINVAL;
+
+               if (cmsg->cmsg_level != SOL_RDS)
+                       continue;
+
+               switch (cmsg->cmsg_type) {
+               case RDS_CMSG_RDMA_ARGS:
+                       cmsg_groups |= 1;
+                       retval = rds_rdma_extra_size(CMSG_DATA(cmsg));
+                       if (retval < 0)
+                               return retval;
+                       size += retval;
+
+                       break;
+
+               case RDS_CMSG_RDMA_DEST:
+               case RDS_CMSG_RDMA_MAP:
+                       cmsg_groups |= 2;
+                       /* these are valid but do no add any size */
+                       break;
+
+               case RDS_CMSG_ATOMIC_CSWP:
+               case RDS_CMSG_ATOMIC_FADD:
+               case RDS_CMSG_MASKED_ATOMIC_CSWP:
+               case RDS_CMSG_MASKED_ATOMIC_FADD:
+                       cmsg_groups |= 1;
+                       size += sizeof(struct scatterlist);
+                       break;
+
+               default:
+                       return -EINVAL;
+               }
+
+       }
+
+       size += ceil(data_len, PAGE_SIZE) * sizeof(struct scatterlist);
+
+       /* Ensure (DEST, MAP) are never used with (ARGS, ATOMIC) */
+       if (cmsg_groups == 3)
+               return -EINVAL;
+
+       return size;
+}
+
 static int rds_cmsg_send(struct rds_sock *rs, struct rds_message *rm,
                         struct msghdr *msg, int *allocated_mr)
 {
@@ -777,7 +878,7 @@ static int rds_cmsg_send(struct rds_sock *rs, struct rds_message *rm,
                        continue;
 
                /* As a side effect, RDMA_DEST and RDMA_MAP will set
-                * rm->m_rdma_cookie and rm->m_rdma_mr.
+                * rm->rdma.m_rdma_cookie and rm->rdma.m_rdma_mr.
                 */
                switch (cmsg->cmsg_type) {
                case RDS_CMSG_RDMA_ARGS:
@@ -793,6 +894,12 @@ static int rds_cmsg_send(struct rds_sock *rs, struct rds_message *rm,
                        if (!ret)
                                *allocated_mr = 1;
                        break;
+               case RDS_CMSG_ATOMIC_CSWP:
+               case RDS_CMSG_ATOMIC_FADD:
+               case RDS_CMSG_MASKED_ATOMIC_CSWP:
+               case RDS_CMSG_MASKED_ATOMIC_FADD:
+                       ret = rds_cmsg_atomic(rs, rm, cmsg);
+                       break;
 
                default:
                        return -EINVAL;
@@ -850,13 +957,26 @@ int rds_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
                goto out;
        }
 
-       rm = rds_message_copy_from_user(msg->msg_iov, payload_len);
-       if (IS_ERR(rm)) {
-               ret = PTR_ERR(rm);
-               rm = NULL;
+       /* size of rm including all sgs */
+       ret = rds_rm_size(msg, payload_len);
+       if (ret < 0)
+               goto out;
+
+       rm = rds_message_alloc(ret, GFP_KERNEL);
+       if (!rm) {
+               ret = -ENOMEM;
                goto out;
        }
 
+       /* Attach data to the rm */
+       if (payload_len) {
+               rm->data.op_sg = rds_message_alloc_sgs(rm, ceil(payload_len, PAGE_SIZE));
+               ret = rds_message_copy_from_user(rm, msg->msg_iov, payload_len);
+               if (ret)
+                       goto out;
+       }
+       rm->data.op_active = 1;
+
        rm->m_daddr = daddr;
 
        /* rds_conn_create has a spinlock that runs with IRQ off.
@@ -879,22 +999,23 @@ int rds_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
        if (ret)
                goto out;
 
-       if ((rm->m_rdma_cookie || rm->m_rdma_op) &&
-           conn->c_trans->xmit_rdma == NULL) {
+       if (rm->rdma.op_active && !conn->c_trans->xmit_rdma) {
                if (printk_ratelimit())
                        printk(KERN_NOTICE "rdma_op %p conn xmit_rdma %p\n",
-                               rm->m_rdma_op, conn->c_trans->xmit_rdma);
+                              &rm->rdma, conn->c_trans->xmit_rdma);
                ret = -EOPNOTSUPP;
                goto out;
        }
 
-       /* If the connection is down, trigger a connect. We may
-        * have scheduled a delayed reconnect however - in this case
-        * we should not interfere.
-        */
-       if (rds_conn_state(conn) == RDS_CONN_DOWN &&
-           !test_and_set_bit(RDS_RECONNECT_PENDING, &conn->c_flags))
-               queue_delayed_work(rds_wq, &conn->c_conn_w, 0);
+       if (rm->atomic.op_active && !conn->c_trans->xmit_atomic) {
+               if (printk_ratelimit())
+                       printk(KERN_NOTICE "atomic_op %p conn xmit_atomic %p\n",
+                              &rm->atomic, conn->c_trans->xmit_atomic);
+               ret = -EOPNOTSUPP;
+               goto out;
+       }
+
+       rds_conn_connect_if_down(conn);
 
        ret = rds_cong_wait(conn->c_fcong, dport, nonblock, rs);
        if (ret) {
@@ -938,7 +1059,7 @@ int rds_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
        rds_stats_inc(s_send_queued);
 
        if (!test_bit(RDS_LL_SEND_FULL, &conn->c_flags))
-               rds_send_worker(&conn->c_send_w.work);
+               rds_send_xmit(conn);
 
        rds_message_put(rm);
        return payload_len;
@@ -966,20 +1087,15 @@ rds_send_pong(struct rds_connection *conn, __be16 dport)
        int ret = 0;
 
        rm = rds_message_alloc(0, GFP_ATOMIC);
-       if (rm == NULL) {
+       if (!rm) {
                ret = -ENOMEM;
                goto out;
        }
 
        rm->m_daddr = conn->c_faddr;
+       rm->data.op_active = 1;
 
-       /* If the connection is down, trigger a connect. We may
-        * have scheduled a delayed reconnect however - in this case
-        * we should not interfere.
-        */
-       if (rds_conn_state(conn) == RDS_CONN_DOWN &&
-           !test_and_set_bit(RDS_RECONNECT_PENDING, &conn->c_flags))
-               queue_delayed_work(rds_wq, &conn->c_conn_w, 0);
+       rds_conn_connect_if_down(conn);
 
        ret = rds_cong_wait(conn->c_fcong, dport, 1, NULL);
        if (ret)
@@ -999,7 +1115,9 @@ rds_send_pong(struct rds_connection *conn, __be16 dport)
        rds_stats_inc(s_send_queued);
        rds_stats_inc(s_send_pong);
 
-       queue_delayed_work(rds_wq, &conn->c_send_w, 0);
+       if (!test_bit(RDS_LL_SEND_FULL, &conn->c_flags))
+               rds_send_xmit(conn);
+
        rds_message_put(rm);
        return 0;
 
index 7598eb07cfb149264355695d4582f28e7b9b0962..10c759ccac0c7a5d134e1cd49b41c45651e657c1 100644 (file)
@@ -57,8 +57,8 @@ static const char *const rds_stat_names[] = {
        "recv_ping",
        "send_queue_empty",
        "send_queue_full",
-       "send_sem_contention",
-       "send_sem_queue_raced",
+       "send_lock_contention",
+       "send_lock_queue_raced",
        "send_immediate_retry",
        "send_delayed_retry",
        "send_drop_acked",
@@ -143,7 +143,7 @@ void rds_stats_exit(void)
        rds_info_deregister_func(RDS_INFO_COUNTERS, rds_stats_info);
 }
 
-int __init rds_stats_init(void)
+int rds_stats_init(void)
 {
        rds_info_register_func(RDS_INFO_COUNTERS, rds_stats_info);
        return 0;
index 7829a20325d3281018dfe0520c450d47a066e890..25ad0c77a26cd16cca2d96681fae4f77373757bf 100644 (file)
@@ -105,13 +105,13 @@ void rds_sysctl_exit(void)
                unregister_sysctl_table(rds_sysctl_reg_table);
 }
 
-int __init rds_sysctl_init(void)
+int rds_sysctl_init(void)
 {
        rds_sysctl_reconnect_min = msecs_to_jiffies(1);
        rds_sysctl_reconnect_min_jiffies = rds_sysctl_reconnect_min;
 
        rds_sysctl_reg_table = register_sysctl_paths(rds_sysctl_path, rds_sysctl_rds_table);
-       if (rds_sysctl_reg_table == NULL)
+       if (!rds_sysctl_reg_table)
                return -ENOMEM;
        return 0;
 }
index babf4577ff7d3f06835e073e48733edeceb97db3..eeb08e6ab96b0c79b3553dbcef9899eee5fbdac2 100644 (file)
@@ -200,7 +200,7 @@ static int rds_tcp_conn_alloc(struct rds_connection *conn, gfp_t gfp)
        struct rds_tcp_connection *tc;
 
        tc = kmem_cache_alloc(rds_tcp_conn_slab, gfp);
-       if (tc == NULL)
+       if (!tc)
                return -ENOMEM;
 
        tc->t_sock = NULL;
@@ -258,7 +258,6 @@ struct rds_transport rds_tcp_transport = {
        .laddr_check            = rds_tcp_laddr_check,
        .xmit_prepare           = rds_tcp_xmit_prepare,
        .xmit_complete          = rds_tcp_xmit_complete,
-       .xmit_cong_map          = rds_tcp_xmit_cong_map,
        .xmit                   = rds_tcp_xmit,
        .recv                   = rds_tcp_recv,
        .conn_alloc             = rds_tcp_conn_alloc,
@@ -266,7 +265,6 @@ struct rds_transport rds_tcp_transport = {
        .conn_connect           = rds_tcp_conn_connect,
        .conn_shutdown          = rds_tcp_conn_shutdown,
        .inc_copy_to_user       = rds_tcp_inc_copy_to_user,
-       .inc_purge              = rds_tcp_inc_purge,
        .inc_free               = rds_tcp_inc_free,
        .stats_info_copy        = rds_tcp_stats_info_copy,
        .exit                   = rds_tcp_exit,
@@ -276,14 +274,14 @@ struct rds_transport rds_tcp_transport = {
        .t_prefer_loopback      = 1,
 };
 
-int __init rds_tcp_init(void)
+int rds_tcp_init(void)
 {
        int ret;
 
        rds_tcp_conn_slab = kmem_cache_create("rds_tcp_connection",
                                              sizeof(struct rds_tcp_connection),
                                              0, 0, NULL);
-       if (rds_tcp_conn_slab == NULL) {
+       if (!rds_tcp_conn_slab) {
                ret = -ENOMEM;
                goto out;
        }
index 844fa6b9cf5aeb2e5bc1a9cad3a3b2b747449929..f5e6f7bebb5013acbf6b74fe76faf44ab391bfcb 100644 (file)
@@ -43,7 +43,7 @@ struct rds_tcp_statistics {
 };
 
 /* tcp.c */
-int __init rds_tcp_init(void);
+int rds_tcp_init(void);
 void rds_tcp_exit(void);
 void rds_tcp_tune(struct socket *sock);
 void rds_tcp_nonagle(struct socket *sock);
@@ -61,16 +61,15 @@ void rds_tcp_conn_shutdown(struct rds_connection *conn);
 void rds_tcp_state_change(struct sock *sk);
 
 /* tcp_listen.c */
-int __init rds_tcp_listen_init(void);
+int rds_tcp_listen_init(void);
 void rds_tcp_listen_stop(void);
 void rds_tcp_listen_data_ready(struct sock *sk, int bytes);
 
 /* tcp_recv.c */
-int __init rds_tcp_recv_init(void);
+int rds_tcp_recv_init(void);
 void rds_tcp_recv_exit(void);
 void rds_tcp_data_ready(struct sock *sk, int bytes);
 int rds_tcp_recv(struct rds_connection *conn);
-void rds_tcp_inc_purge(struct rds_incoming *inc);
 void rds_tcp_inc_free(struct rds_incoming *inc);
 int rds_tcp_inc_copy_to_user(struct rds_incoming *inc, struct iovec *iov,
                             size_t size);
@@ -81,8 +80,6 @@ void rds_tcp_xmit_complete(struct rds_connection *conn);
 int rds_tcp_xmit(struct rds_connection *conn, struct rds_message *rm,
                 unsigned int hdr_off, unsigned int sg, unsigned int off);
 void rds_tcp_write_space(struct sock *sk);
-int rds_tcp_xmit_cong_map(struct rds_connection *conn,
-                         struct rds_cong_map *map, unsigned long offset);
 
 /* tcp_stats.c */
 DECLARE_PER_CPU(struct rds_tcp_statistics, rds_tcp_stats);
index c397524c039cdb28140ff5f6c0fe2359cebfa3b5..a65ee78db0c54e1062186b9b132fe46fac380c91 100644 (file)
@@ -45,7 +45,7 @@ void rds_tcp_state_change(struct sock *sk)
 
        read_lock(&sk->sk_callback_lock);
        conn = sk->sk_user_data;
-       if (conn == NULL) {
+       if (!conn) {
                state_change = sk->sk_state_change;
                goto out;
        }
index 975183fe6950a34b242ef55db011e6f04c1c6772..ae27869dfc2137a342918f558082c1e58e1d4e88 100644 (file)
@@ -116,7 +116,7 @@ void rds_tcp_listen_data_ready(struct sock *sk, int bytes)
 
        read_lock(&sk->sk_callback_lock);
        ready = sk->sk_user_data;
-       if (ready == NULL) { /* check for teardown race */
+       if (!ready) { /* check for teardown race */
                ready = sk->sk_data_ready;
                goto out;
        }
@@ -135,7 +135,7 @@ out:
        ready(sk, bytes);
 }
 
-int __init rds_tcp_listen_init(void)
+int rds_tcp_listen_init(void)
 {
        struct sockaddr_in sin;
        struct socket *sock = NULL;
@@ -178,7 +178,7 @@ void rds_tcp_listen_stop(void)
        struct socket *sock = rds_tcp_listen_sock;
        struct sock *sk;
 
-       if (sock == NULL)
+       if (!sock)
                return;
 
        sk = sock->sk;
index 1aba6878fa5dc42d4c54473350fde61d714a184c..7017f3af80b671cca7b403d99e8006444eb1c8bb 100644 (file)
@@ -39,7 +39,7 @@
 
 static struct kmem_cache *rds_tcp_incoming_slab;
 
-void rds_tcp_inc_purge(struct rds_incoming *inc)
+static void rds_tcp_inc_purge(struct rds_incoming *inc)
 {
        struct rds_tcp_incoming *tinc;
        tinc = container_of(inc, struct rds_tcp_incoming, ti_inc);
@@ -190,10 +190,10 @@ static int rds_tcp_data_recv(read_descriptor_t *desc, struct sk_buff *skb,
         * processing.
         */
        while (left) {
-               if (tinc == NULL) {
+               if (!tinc) {
                        tinc = kmem_cache_alloc(rds_tcp_incoming_slab,
                                                arg->gfp);
-                       if (tinc == NULL) {
+                       if (!tinc) {
                                desc->error = -ENOMEM;
                                goto out;
                        }
@@ -229,7 +229,7 @@ static int rds_tcp_data_recv(read_descriptor_t *desc, struct sk_buff *skb,
 
                if (left && tc->t_tinc_data_rem) {
                        clone = skb_clone(skb, arg->gfp);
-                       if (clone == NULL) {
+                       if (!clone) {
                                desc->error = -ENOMEM;
                                goto out;
                        }
@@ -326,7 +326,7 @@ void rds_tcp_data_ready(struct sock *sk, int bytes)
 
        read_lock(&sk->sk_callback_lock);
        conn = sk->sk_user_data;
-       if (conn == NULL) { /* check for teardown race */
+       if (!conn) { /* check for teardown race */
                ready = sk->sk_data_ready;
                goto out;
        }
@@ -342,12 +342,12 @@ out:
        ready(sk, bytes);
 }
 
-int __init rds_tcp_recv_init(void)
+int rds_tcp_recv_init(void)
 {
        rds_tcp_incoming_slab = kmem_cache_create("rds_tcp_incoming",
                                        sizeof(struct rds_tcp_incoming),
                                        0, 0, NULL);
-       if (rds_tcp_incoming_slab == NULL)
+       if (!rds_tcp_incoming_slab)
                return -ENOMEM;
        return 0;
 }
index a28b895ff0d10194730463b218e3ccb526cdea50..2979fb4a4b9aaf8df3b0216d69cac828885df398 100644 (file)
@@ -76,56 +76,6 @@ int rds_tcp_sendmsg(struct socket *sock, void *data, unsigned int len)
        return kernel_sendmsg(sock, &msg, &vec, 1, vec.iov_len);
 }
 
-/* the core send_sem serializes this with other xmit and shutdown */
-int rds_tcp_xmit_cong_map(struct rds_connection *conn,
-                         struct rds_cong_map *map, unsigned long offset)
-{
-       static struct rds_header rds_tcp_map_header = {
-               .h_flags = RDS_FLAG_CONG_BITMAP,
-       };
-       struct rds_tcp_connection *tc = conn->c_transport_data;
-       unsigned long i;
-       int ret;
-       int copied = 0;
-
-       /* Some problem claims cpu_to_be32(constant) isn't a constant. */
-       rds_tcp_map_header.h_len = cpu_to_be32(RDS_CONG_MAP_BYTES);
-
-       if (offset < sizeof(struct rds_header)) {
-               ret = rds_tcp_sendmsg(tc->t_sock,
-                                     (void *)&rds_tcp_map_header + offset,
-                                     sizeof(struct rds_header) - offset);
-               if (ret <= 0)
-                       return ret;
-               offset += ret;
-               copied = ret;
-               if (offset < sizeof(struct rds_header))
-                       return ret;
-       }
-
-       offset -= sizeof(struct rds_header);
-       i = offset / PAGE_SIZE;
-       offset = offset % PAGE_SIZE;
-       BUG_ON(i >= RDS_CONG_MAP_PAGES);
-
-       do {
-               ret = tc->t_sock->ops->sendpage(tc->t_sock,
-                                       virt_to_page(map->m_page_addrs[i]),
-                                       offset, PAGE_SIZE - offset,
-                                       MSG_DONTWAIT);
-               if (ret <= 0)
-                       break;
-               copied += ret;
-               offset += ret;
-               if (offset == PAGE_SIZE) {
-                       offset = 0;
-                       i++;
-               }
-       } while (i < RDS_CONG_MAP_PAGES);
-
-        return copied ? copied : ret;
-}
-
 /* the core send_sem serializes this with other xmit and shutdown */
 int rds_tcp_xmit(struct rds_connection *conn, struct rds_message *rm,
                 unsigned int hdr_off, unsigned int sg, unsigned int off)
@@ -166,21 +116,21 @@ int rds_tcp_xmit(struct rds_connection *conn, struct rds_message *rm,
                        goto out;
        }
 
-       while (sg < rm->m_nents) {
+       while (sg < rm->data.op_nents) {
                ret = tc->t_sock->ops->sendpage(tc->t_sock,
-                                               sg_page(&rm->m_sg[sg]),
-                                               rm->m_sg[sg].offset + off,
-                                               rm->m_sg[sg].length - off,
+                                               sg_page(&rm->data.op_sg[sg]),
+                                               rm->data.op_sg[sg].offset + off,
+                                               rm->data.op_sg[sg].length - off,
                                                MSG_DONTWAIT|MSG_NOSIGNAL);
-               rdsdebug("tcp sendpage %p:%u:%u ret %d\n", (void *)sg_page(&rm->m_sg[sg]),
-                        rm->m_sg[sg].offset + off, rm->m_sg[sg].length - off,
+               rdsdebug("tcp sendpage %p:%u:%u ret %d\n", (void *)sg_page(&rm->data.op_sg[sg]),
+                        rm->data.op_sg[sg].offset + off, rm->data.op_sg[sg].length - off,
                         ret);
                if (ret <= 0)
                        break;
 
                off += ret;
                done += ret;
-               if (off == rm->m_sg[sg].length) {
+               if (off == rm->data.op_sg[sg].length) {
                        off = 0;
                        sg++;
                }
@@ -226,7 +176,7 @@ void rds_tcp_write_space(struct sock *sk)
 
        read_lock(&sk->sk_callback_lock);
        conn = sk->sk_user_data;
-       if (conn == NULL) {
+       if (!conn) {
                write_space = sk->sk_write_space;
                goto out;
        }
index 786c20eaaf5e44a1cb1a2d7bdd284c7ad2cedf53..0fd90f8c5f59c75c18c244701f3230f93c408d85 100644 (file)
@@ -61,7 +61,7 @@
  *
  * Transition to state DISCONNECTING/DOWN:
  *  -  Inside the shutdown worker; synchronizes with xmit path
- *     through c_send_lock, and with connection management callbacks
+ *     through RDS_IN_XMIT, and with connection management callbacks
  *     via c_cm_lock.
  *
  *     For receive callbacks, we rely on the underlying transport
@@ -110,7 +110,7 @@ EXPORT_SYMBOL_GPL(rds_connect_complete);
  * We should *always* start with a random backoff; otherwise a broken connection
  * will always take several iterations to be re-established.
  */
-static void rds_queue_reconnect(struct rds_connection *conn)
+void rds_queue_reconnect(struct rds_connection *conn)
 {
        unsigned long rand;
 
@@ -156,58 +156,6 @@ void rds_connect_worker(struct work_struct *work)
        }
 }
 
-void rds_shutdown_worker(struct work_struct *work)
-{
-       struct rds_connection *conn = container_of(work, struct rds_connection, c_down_w);
-
-       /* shut it down unless it's down already */
-       if (!rds_conn_transition(conn, RDS_CONN_DOWN, RDS_CONN_DOWN)) {
-               /*
-                * Quiesce the connection mgmt handlers before we start tearing
-                * things down. We don't hold the mutex for the entire
-                * duration of the shutdown operation, else we may be
-                * deadlocking with the CM handler. Instead, the CM event
-                * handler is supposed to check for state DISCONNECTING
-                */
-               mutex_lock(&conn->c_cm_lock);
-               if (!rds_conn_transition(conn, RDS_CONN_UP, RDS_CONN_DISCONNECTING) &&
-                   !rds_conn_transition(conn, RDS_CONN_ERROR, RDS_CONN_DISCONNECTING)) {
-                       rds_conn_error(conn, "shutdown called in state %d\n",
-                                       atomic_read(&conn->c_state));
-                       mutex_unlock(&conn->c_cm_lock);
-                       return;
-               }
-               mutex_unlock(&conn->c_cm_lock);
-
-               mutex_lock(&conn->c_send_lock);
-               conn->c_trans->conn_shutdown(conn);
-               rds_conn_reset(conn);
-               mutex_unlock(&conn->c_send_lock);
-
-               if (!rds_conn_transition(conn, RDS_CONN_DISCONNECTING, RDS_CONN_DOWN)) {
-                       /* This can happen - eg when we're in the middle of tearing
-                        * down the connection, and someone unloads the rds module.
-                        * Quite reproduceable with loopback connections.
-                        * Mostly harmless.
-                        */
-                       rds_conn_error(conn,
-                               "%s: failed to transition to state DOWN, "
-                               "current state is %d\n",
-                               __func__,
-                               atomic_read(&conn->c_state));
-                       return;
-               }
-       }
-
-       /* Then reconnect if it's still live.
-        * The passive side of an IB loopback connection is never added
-        * to the conn hash, so we never trigger a reconnect on this
-        * conn - the reconnect is always triggered by the active peer. */
-       cancel_delayed_work(&conn->c_conn_w);
-       if (!hlist_unhashed(&conn->c_hash_node))
-               rds_queue_reconnect(conn);
-}
-
 void rds_send_worker(struct work_struct *work)
 {
        struct rds_connection *conn = container_of(work, struct rds_connection, c_send_w.work);
@@ -252,15 +200,22 @@ void rds_recv_worker(struct work_struct *work)
        }
 }
 
+void rds_shutdown_worker(struct work_struct *work)
+{
+       struct rds_connection *conn = container_of(work, struct rds_connection, c_down_w);
+
+       rds_conn_shutdown(conn);
+}
+
 void rds_threads_exit(void)
 {
        destroy_workqueue(rds_wq);
 }
 
-int __init rds_threads_init(void)
+int rds_threads_init(void)
 {
-       rds_wq = create_workqueue("krdsd");
-       if (rds_wq == NULL)
+       rds_wq = create_singlethread_workqueue("krdsd");
+       if (!rds_wq)
                return -ENOMEM;
 
        return 0;
index 7e106790135353c036d6fa0dcba3345cf072f3dd..7f2ac4fec3678b28715b95094c6346bcc49333e1 100644 (file)
@@ -71,19 +71,28 @@ void rds_trans_unregister(struct rds_transport *trans)
 }
 EXPORT_SYMBOL_GPL(rds_trans_unregister);
 
+void rds_trans_put(struct rds_transport *trans)
+{
+       if (trans && trans->t_owner)
+               module_put(trans->t_owner);
+}
+
 struct rds_transport *rds_trans_get_preferred(__be32 addr)
 {
        struct rds_transport *ret = NULL;
-       int i;
+       struct rds_transport *trans;
+       unsigned int i;
 
        if (IN_LOOPBACK(ntohl(addr)))
                return &rds_loop_transport;
 
        down_read(&rds_trans_sem);
-       for (i = 0; i < RDS_TRANS_COUNT; i++)
-       {
-               if (transports[i] && (transports[i]->laddr_check(addr) == 0)) {
-                       ret = transports[i];
+       for (i = 0; i < RDS_TRANS_COUNT; i++) {
+               trans = transports[i];
+
+               if (trans && (trans->laddr_check(addr) == 0) &&
+                   (!trans->t_owner || try_module_get(trans->t_owner))) {
+                       ret = trans;
                        break;
                }
        }
diff --git a/net/rds/xlist.h b/net/rds/xlist.h
new file mode 100644 (file)
index 0000000..e6b5190
--- /dev/null
@@ -0,0 +1,80 @@
+#ifndef _LINUX_XLIST_H
+#define _LINUX_XLIST_H
+
+#include <linux/stddef.h>
+#include <linux/poison.h>
+#include <linux/prefetch.h>
+#include <asm/system.h>
+
+struct xlist_head {
+       struct xlist_head *next;
+};
+
+static inline void INIT_XLIST_HEAD(struct xlist_head *list)
+{
+       list->next = NULL;
+}
+
+static inline int xlist_empty(struct xlist_head *head)
+{
+       return head->next == NULL;
+}
+
+static inline void xlist_add(struct xlist_head *new, struct xlist_head *tail,
+                            struct xlist_head *head)
+{
+       struct xlist_head *cur;
+       struct xlist_head *check;
+
+       while (1) {
+               cur = head->next;
+               tail->next = cur;
+               check = cmpxchg(&head->next, cur, new);
+               if (check == cur)
+                       break;
+       }
+}
+
+static inline struct xlist_head *xlist_del_head(struct xlist_head *head)
+{
+       struct xlist_head *cur;
+       struct xlist_head *check;
+       struct xlist_head *next;
+
+       while (1) {
+               cur = head->next;
+               if (!cur)
+                       goto out;
+
+               next = cur->next;
+               check = cmpxchg(&head->next, cur, next);
+               if (check == cur)
+                       goto out;
+       }
+out:
+       return cur;
+}
+
+static inline struct xlist_head *xlist_del_head_fast(struct xlist_head *head)
+{
+       struct xlist_head *cur;
+
+       cur = head->next;
+       if (!cur)
+               return NULL;
+
+       head->next = cur->next;
+       return cur;
+}
+
+static inline void xlist_splice(struct xlist_head *list,
+                               struct xlist_head *head)
+{
+       struct xlist_head *cur;
+
+       WARN_ON(head->next);
+       cur = xchg(&list->next, NULL);
+       head->next = cur;
+}
+
+#endif
index 2f691fb180d127751877003af00e624334da474c..a36270a994d763d75f5d1c7cff272d0305a88835 100644 (file)
@@ -518,6 +518,16 @@ config NET_ACT_SKBEDIT
          To compile this code as a module, choose M here: the
          module will be called act_skbedit.
 
+config NET_ACT_CSUM
+        tristate "Checksum Updating"
+        depends on NET_CLS_ACT && INET
+        ---help---
+         Say Y here to update some common checksum after some direct
+         packet alterations.
+
+         To compile this code as a module, choose M here: the
+         module will be called act_csum.
+
 config NET_CLS_IND
        bool "Incoming device classification"
        depends on NET_CLS_U32 || NET_CLS_FW
index f14e71bfa58fdcea59bf31485ea1f26ae998574a..960f5dba63041559835978dd0c5d63c2d3229436 100644 (file)
@@ -15,6 +15,7 @@ obj-$(CONFIG_NET_ACT_NAT)     += act_nat.o
 obj-$(CONFIG_NET_ACT_PEDIT)    += act_pedit.o
 obj-$(CONFIG_NET_ACT_SIMP)     += act_simple.o
 obj-$(CONFIG_NET_ACT_SKBEDIT)  += act_skbedit.o
+obj-$(CONFIG_NET_ACT_CSUM)     += act_csum.o
 obj-$(CONFIG_NET_SCH_FIFO)     += sch_fifo.o
 obj-$(CONFIG_NET_SCH_CBQ)      += sch_cbq.o
 obj-$(CONFIG_NET_SCH_HTB)      += sch_htb.o
diff --git a/net/sched/act_csum.c b/net/sched/act_csum.c
new file mode 100644 (file)
index 0000000..67dc7ce
--- /dev/null
@@ -0,0 +1,595 @@
+/*
+ * Checksum updating actions
+ *
+ * Copyright (c) 2010 Gregoire Baron <baronchon@n7mm.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.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+
+#include <linux/netlink.h>
+#include <net/netlink.h>
+#include <linux/rtnetlink.h>
+
+#include <linux/skbuff.h>
+
+#include <net/ip.h>
+#include <net/ipv6.h>
+#include <net/icmp.h>
+#include <linux/icmpv6.h>
+#include <linux/igmp.h>
+#include <net/tcp.h>
+#include <net/udp.h>
+#include <net/ip6_checksum.h>
+
+#include <net/act_api.h>
+
+#include <linux/tc_act/tc_csum.h>
+#include <net/tc_act/tc_csum.h>
+
+#define CSUM_TAB_MASK 15
+static struct tcf_common *tcf_csum_ht[CSUM_TAB_MASK + 1];
+static u32 csum_idx_gen;
+static DEFINE_RWLOCK(csum_lock);
+
+static struct tcf_hashinfo csum_hash_info = {
+       .htab   = tcf_csum_ht,
+       .hmask  = CSUM_TAB_MASK,
+       .lock   = &csum_lock,
+};
+
+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,
+                        struct tc_action *a, int ovr, int bind)
+{
+       struct nlattr *tb[TCA_CSUM_MAX + 1];
+       struct tc_csum *parm;
+       struct tcf_common *pc;
+       struct tcf_csum *p;
+       int ret = 0, err;
+
+       if (nla == NULL)
+               return -EINVAL;
+
+       err = nla_parse_nested(tb, TCA_CSUM_MAX, nla,csum_policy);
+       if (err < 0)
+               return err;
+
+       if (tb[TCA_CSUM_PARMS] == NULL)
+               return -EINVAL;
+       parm = nla_data(tb[TCA_CSUM_PARMS]);
+
+       pc = tcf_hash_check(parm->index, a, bind, &csum_hash_info);
+       if (!pc) {
+               pc = tcf_hash_create(parm->index, est, a, sizeof(*p), bind,
+                                    &csum_idx_gen, &csum_hash_info);
+               if (IS_ERR(pc))
+                       return PTR_ERR(pc);
+               p = to_tcf_csum(pc);
+               ret = ACT_P_CREATED;
+       } else {
+               p = to_tcf_csum(pc);
+               if (!ovr) {
+                       tcf_hash_release(pc, bind, &csum_hash_info);
+                       return -EEXIST;
+               }
+       }
+
+       spin_lock_bh(&p->tcf_lock);
+       p->tcf_action = parm->action;
+       p->update_flags = parm->update_flags;
+       spin_unlock_bh(&p->tcf_lock);
+
+       if (ret == ACT_P_CREATED)
+               tcf_hash_insert(pc, &csum_hash_info);
+
+       return ret;
+}
+
+static int tcf_csum_cleanup(struct tc_action *a, int bind)
+{
+       struct tcf_csum *p = a->priv;
+       return tcf_hash_release(&p->common, bind, &csum_hash_info);
+}
+
+/**
+ * tcf_csum_skb_nextlayer - Get next layer pointer
+ * @skb: sk_buff to use
+ * @ihl: previous summed headers length
+ * @ipl: complete packet length
+ * @jhl: next header length
+ *
+ * Check the expected next layer availability in the specified sk_buff.
+ * Return the next layer pointer if pass, NULL otherwise.
+ */
+static void *tcf_csum_skb_nextlayer(struct sk_buff *skb,
+                                   unsigned int ihl, unsigned int ipl,
+                                   unsigned int jhl)
+{
+       int ntkoff = skb_network_offset(skb);
+       int hl = ihl + jhl;
+
+       if (!pskb_may_pull(skb, ipl + ntkoff) || (ipl < hl) ||
+           (skb_cloned(skb) &&
+            !skb_clone_writable(skb, hl + ntkoff) &&
+            pskb_expand_head(skb, 0, 0, GFP_ATOMIC)))
+               return NULL;
+       else
+               return (void *)(skb_network_header(skb) + ihl);
+}
+
+static int tcf_csum_ipv4_icmp(struct sk_buff *skb,
+                             unsigned int ihl, unsigned int ipl)
+{
+       struct icmphdr *icmph;
+
+       icmph = tcf_csum_skb_nextlayer(skb, ihl, ipl, sizeof(*icmph));
+       if (icmph == NULL)
+               return 0;
+
+       icmph->checksum = 0;
+       skb->csum = csum_partial(icmph, ipl - ihl, 0);
+       icmph->checksum = csum_fold(skb->csum);
+
+       skb->ip_summed = CHECKSUM_NONE;
+
+       return 1;
+}
+
+static int tcf_csum_ipv4_igmp(struct sk_buff *skb,
+                             unsigned int ihl, unsigned int ipl)
+{
+       struct igmphdr *igmph;
+
+       igmph = tcf_csum_skb_nextlayer(skb, ihl, ipl, sizeof(*igmph));
+       if (igmph == NULL)
+               return 0;
+
+       igmph->csum = 0;
+       skb->csum = csum_partial(igmph, ipl - ihl, 0);
+       igmph->csum = csum_fold(skb->csum);
+
+       skb->ip_summed = CHECKSUM_NONE;
+
+       return 1;
+}
+
+static int tcf_csum_ipv6_icmp(struct sk_buff *skb, struct ipv6hdr *ip6h,
+                             unsigned int ihl, unsigned int ipl)
+{
+       struct icmp6hdr *icmp6h;
+
+       icmp6h = tcf_csum_skb_nextlayer(skb, ihl, ipl, sizeof(*icmp6h));
+       if (icmp6h == NULL)
+               return 0;
+
+       icmp6h->icmp6_cksum = 0;
+       skb->csum = csum_partial(icmp6h, ipl - ihl, 0);
+       icmp6h->icmp6_cksum = csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr,
+                                             ipl - ihl, IPPROTO_ICMPV6,
+                                             skb->csum);
+
+       skb->ip_summed = CHECKSUM_NONE;
+
+       return 1;
+}
+
+static int tcf_csum_ipv4_tcp(struct sk_buff *skb, struct iphdr *iph,
+                            unsigned int ihl, unsigned int ipl)
+{
+       struct tcphdr *tcph;
+
+       tcph = tcf_csum_skb_nextlayer(skb, ihl, ipl, sizeof(*tcph));
+       if (tcph == NULL)
+               return 0;
+
+       tcph->check = 0;
+       skb->csum = csum_partial(tcph, ipl - ihl, 0);
+       tcph->check = tcp_v4_check(ipl - ihl,
+                                  iph->saddr, iph->daddr, skb->csum);
+
+       skb->ip_summed = CHECKSUM_NONE;
+
+       return 1;
+}
+
+static int tcf_csum_ipv6_tcp(struct sk_buff *skb, struct ipv6hdr *ip6h,
+                            unsigned int ihl, unsigned int ipl)
+{
+       struct tcphdr *tcph;
+
+       tcph = tcf_csum_skb_nextlayer(skb, ihl, ipl, sizeof(*tcph));
+       if (tcph == NULL)
+               return 0;
+
+       tcph->check = 0;
+       skb->csum = csum_partial(tcph, ipl - ihl, 0);
+       tcph->check = csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr,
+                                     ipl - ihl, IPPROTO_TCP,
+                                     skb->csum);
+
+       skb->ip_summed = CHECKSUM_NONE;
+
+       return 1;
+}
+
+static int tcf_csum_ipv4_udp(struct sk_buff *skb, struct iphdr *iph,
+                            unsigned int ihl, unsigned int ipl, int udplite)
+{
+       struct udphdr *udph;
+       u16 ul;
+
+       /*
+        * Support both UDP and UDPLITE checksum algorithms, Don't use
+        * udph->len to get the real length without any protocol check,
+        * UDPLITE uses udph->len for another thing,
+        * Use iph->tot_len, or just ipl.
+        */
+
+       udph = tcf_csum_skb_nextlayer(skb, ihl, ipl, sizeof(*udph));
+       if (udph == NULL)
+               return 0;
+
+       ul = ntohs(udph->len);
+
+       if (udplite || udph->check) {
+
+               udph->check = 0;
+
+               if (udplite) {
+                       if (ul == 0)
+                               skb->csum = csum_partial(udph, ipl - ihl, 0);
+                       else if ((ul >= sizeof(*udph)) && (ul <= ipl - ihl))
+                               skb->csum = csum_partial(udph, ul, 0);
+                       else
+                               goto ignore_obscure_skb;
+               } else {
+                       if (ul != ipl - ihl)
+                               goto ignore_obscure_skb;
+
+                       skb->csum = csum_partial(udph, ul, 0);
+               }
+
+               udph->check = csum_tcpudp_magic(iph->saddr, iph->daddr,
+                                               ul, iph->protocol,
+                                               skb->csum);
+
+               if (!udph->check)
+                       udph->check = CSUM_MANGLED_0;
+       }
+
+       skb->ip_summed = CHECKSUM_NONE;
+
+ignore_obscure_skb:
+       return 1;
+}
+
+static int tcf_csum_ipv6_udp(struct sk_buff *skb, struct ipv6hdr *ip6h,
+                            unsigned int ihl, unsigned int ipl, int udplite)
+{
+       struct udphdr *udph;
+       u16 ul;
+
+       /*
+        * Support both UDP and UDPLITE checksum algorithms, Don't use
+        * udph->len to get the real length without any protocol check,
+        * UDPLITE uses udph->len for another thing,
+        * Use ip6h->payload_len + sizeof(*ip6h) ... , or just ipl.
+        */
+
+       udph = tcf_csum_skb_nextlayer(skb, ihl, ipl, sizeof(*udph));
+       if (udph == NULL)
+               return 0;
+
+       ul = ntohs(udph->len);
+
+       udph->check = 0;
+
+       if (udplite) {
+               if (ul == 0)
+                       skb->csum = csum_partial(udph, ipl - ihl, 0);
+
+               else if ((ul >= sizeof(*udph)) && (ul <= ipl - ihl))
+                       skb->csum = csum_partial(udph, ul, 0);
+
+               else
+                       goto ignore_obscure_skb;
+       } else {
+               if (ul != ipl - ihl)
+                       goto ignore_obscure_skb;
+
+               skb->csum = csum_partial(udph, ul, 0);
+       }
+
+       udph->check = csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr, ul,
+                                     udplite ? IPPROTO_UDPLITE : IPPROTO_UDP,
+                                     skb->csum);
+
+       if (!udph->check)
+               udph->check = CSUM_MANGLED_0;
+
+       skb->ip_summed = CHECKSUM_NONE;
+
+ignore_obscure_skb:
+       return 1;
+}
+
+static int tcf_csum_ipv4(struct sk_buff *skb, u32 update_flags)
+{
+       struct iphdr *iph;
+       int ntkoff;
+
+       ntkoff = skb_network_offset(skb);
+
+       if (!pskb_may_pull(skb, sizeof(*iph) + ntkoff))
+               goto fail;
+
+       iph = ip_hdr(skb);
+
+       switch (iph->frag_off & htons(IP_OFFSET) ? 0 : iph->protocol) {
+       case IPPROTO_ICMP:
+               if (update_flags & TCA_CSUM_UPDATE_FLAG_ICMP)
+                       if (!tcf_csum_ipv4_icmp(skb, iph->ihl * 4,
+                                               ntohs(iph->tot_len)))
+                               goto fail;
+               break;
+       case IPPROTO_IGMP:
+               if (update_flags & TCA_CSUM_UPDATE_FLAG_IGMP)
+                       if (!tcf_csum_ipv4_igmp(skb, iph->ihl * 4,
+                                               ntohs(iph->tot_len)))
+                               goto fail;
+               break;
+       case IPPROTO_TCP:
+               if (update_flags & TCA_CSUM_UPDATE_FLAG_TCP)
+                       if (!tcf_csum_ipv4_tcp(skb, iph, iph->ihl * 4,
+                                              ntohs(iph->tot_len)))
+                               goto fail;
+               break;
+       case IPPROTO_UDP:
+               if (update_flags & TCA_CSUM_UPDATE_FLAG_UDP)
+                       if (!tcf_csum_ipv4_udp(skb, iph, iph->ihl * 4,
+                                              ntohs(iph->tot_len), 0))
+                               goto fail;
+               break;
+       case IPPROTO_UDPLITE:
+               if (update_flags & TCA_CSUM_UPDATE_FLAG_UDPLITE)
+                       if (!tcf_csum_ipv4_udp(skb, iph, iph->ihl * 4,
+                                              ntohs(iph->tot_len), 1))
+                               goto fail;
+               break;
+       }
+
+       if (update_flags & TCA_CSUM_UPDATE_FLAG_IPV4HDR) {
+               if (skb_cloned(skb) &&
+                   !skb_clone_writable(skb, sizeof(*iph) + ntkoff) &&
+                   pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
+                       goto fail;
+
+               ip_send_check(iph);
+       }
+
+       return 1;
+
+fail:
+       return 0;
+}
+
+static int tcf_csum_ipv6_hopopts(struct ipv6_opt_hdr *ip6xh,
+                                unsigned int ixhl, unsigned int *pl)
+{
+       int off, len, optlen;
+       unsigned char *xh = (void *)ip6xh;
+
+       off = sizeof(*ip6xh);
+       len = ixhl - off;
+
+       while (len > 1) {
+               switch (xh[off]) {
+               case IPV6_TLV_PAD0:
+                       optlen = 1;
+                       break;
+               case IPV6_TLV_JUMBO:
+                       optlen = xh[off + 1] + 2;
+                       if (optlen != 6 || len < 6 || (off & 3) != 2)
+                               /* wrong jumbo option length/alignment */
+                               return 0;
+                       *pl = ntohl(*(__be32 *)(xh + off + 2));
+                       goto done;
+               default:
+                       optlen = xh[off + 1] + 2;
+                       if (optlen > len)
+                               /* ignore obscure options */
+                               goto done;
+                       break;
+               }
+               off += optlen;
+               len -= optlen;
+       }
+
+done:
+       return 1;
+}
+
+static int tcf_csum_ipv6(struct sk_buff *skb, u32 update_flags)
+{
+       struct ipv6hdr *ip6h;
+       struct ipv6_opt_hdr *ip6xh;
+       unsigned int hl, ixhl;
+       unsigned int pl;
+       int ntkoff;
+       u8 nexthdr;
+
+       ntkoff = skb_network_offset(skb);
+
+       hl = sizeof(*ip6h);
+
+       if (!pskb_may_pull(skb, hl + ntkoff))
+               goto fail;
+
+       ip6h = ipv6_hdr(skb);
+
+       pl = ntohs(ip6h->payload_len);
+       nexthdr = ip6h->nexthdr;
+
+       do {
+               switch (nexthdr) {
+               case NEXTHDR_FRAGMENT:
+                       goto ignore_skb;
+               case NEXTHDR_ROUTING:
+               case NEXTHDR_HOP:
+               case NEXTHDR_DEST:
+                       if (!pskb_may_pull(skb, hl + sizeof(*ip6xh) + ntkoff))
+                               goto fail;
+                       ip6xh = (void *)(skb_network_header(skb) + hl);
+                       ixhl = ipv6_optlen(ip6xh);
+                       if (!pskb_may_pull(skb, hl + ixhl + ntkoff))
+                               goto fail;
+                       if ((nexthdr == NEXTHDR_HOP) &&
+                           !(tcf_csum_ipv6_hopopts(ip6xh, ixhl, &pl)))
+                               goto fail;
+                       nexthdr = ip6xh->nexthdr;
+                       hl += ixhl;
+                       break;
+               case IPPROTO_ICMPV6:
+                       if (update_flags & TCA_CSUM_UPDATE_FLAG_ICMP)
+                               if (!tcf_csum_ipv6_icmp(skb, ip6h,
+                                                       hl, pl + sizeof(*ip6h)))
+                                       goto fail;
+                       goto done;
+               case IPPROTO_TCP:
+                       if (update_flags & TCA_CSUM_UPDATE_FLAG_TCP)
+                               if (!tcf_csum_ipv6_tcp(skb, ip6h,
+                                                      hl, pl + sizeof(*ip6h)))
+                                       goto fail;
+                       goto done;
+               case IPPROTO_UDP:
+                       if (update_flags & TCA_CSUM_UPDATE_FLAG_UDP)
+                               if (!tcf_csum_ipv6_udp(skb, ip6h, hl,
+                                                      pl + sizeof(*ip6h), 0))
+                                       goto fail;
+                       goto done;
+               case IPPROTO_UDPLITE:
+                       if (update_flags & TCA_CSUM_UPDATE_FLAG_UDPLITE)
+                               if (!tcf_csum_ipv6_udp(skb, ip6h, hl,
+                                                      pl + sizeof(*ip6h), 1))
+                                       goto fail;
+                       goto done;
+               default:
+                       goto ignore_skb;
+               }
+       } while (pskb_may_pull(skb, hl + 1 + ntkoff));
+
+done:
+ignore_skb:
+       return 1;
+
+fail:
+       return 0;
+}
+
+static int tcf_csum(struct sk_buff *skb,
+                   struct tc_action *a, struct tcf_result *res)
+{
+       struct tcf_csum *p = a->priv;
+       int action;
+       u32 update_flags;
+
+       spin_lock(&p->tcf_lock);
+       p->tcf_tm.lastuse = jiffies;
+       p->tcf_bstats.bytes += qdisc_pkt_len(skb);
+       p->tcf_bstats.packets++;
+       action = p->tcf_action;
+       update_flags = p->update_flags;
+       spin_unlock(&p->tcf_lock);
+
+       if (unlikely(action == TC_ACT_SHOT))
+               goto drop;
+
+       switch (skb->protocol) {
+       case cpu_to_be16(ETH_P_IP):
+               if (!tcf_csum_ipv4(skb, update_flags))
+                       goto drop;
+               break;
+       case cpu_to_be16(ETH_P_IPV6):
+               if (!tcf_csum_ipv6(skb, update_flags))
+                       goto drop;
+               break;
+       }
+
+       return action;
+
+drop:
+       spin_lock(&p->tcf_lock);
+       p->tcf_qstats.drops++;
+       spin_unlock(&p->tcf_lock);
+       return TC_ACT_SHOT;
+}
+
+static int tcf_csum_dump(struct sk_buff *skb,
+                        struct tc_action *a, int bind, int ref)
+{
+       unsigned char *b = skb_tail_pointer(skb);
+       struct tcf_csum *p = a->priv;
+       struct tc_csum opt = {
+               .update_flags = p->update_flags,
+               .index   = p->tcf_index,
+               .action  = p->tcf_action,
+               .refcnt  = p->tcf_refcnt - ref,
+               .bindcnt = p->tcf_bindcnt - bind,
+       };
+       struct tcf_t t;
+
+       NLA_PUT(skb, TCA_CSUM_PARMS, sizeof(opt), &opt);
+       t.install = jiffies_to_clock_t(jiffies - p->tcf_tm.install);
+       t.lastuse = jiffies_to_clock_t(jiffies - p->tcf_tm.lastuse);
+       t.expires = jiffies_to_clock_t(p->tcf_tm.expires);
+       NLA_PUT(skb, TCA_CSUM_TM, sizeof(t), &t);
+
+       return skb->len;
+
+nla_put_failure:
+       nlmsg_trim(skb, b);
+       return -1;
+}
+
+static struct tc_action_ops act_csum_ops = {
+       .kind           = "csum",
+       .hinfo          = &csum_hash_info,
+       .type           = TCA_ACT_CSUM,
+       .capab          = TCA_CAP_NONE,
+       .owner          = THIS_MODULE,
+       .act            = tcf_csum,
+       .dump           = tcf_csum_dump,
+       .cleanup        = tcf_csum_cleanup,
+       .lookup         = tcf_hash_search,
+       .init           = tcf_csum_init,
+       .walk           = tcf_generic_walker
+};
+
+MODULE_DESCRIPTION("Checksum updating actions");
+MODULE_LICENSE("GPL");
+
+static int __init csum_init_module(void)
+{
+       return tcf_register_action(&act_csum_ops);
+}
+
+static void __exit csum_cleanup_module(void)
+{
+       tcf_unregister_action(&act_csum_ops);
+}
+
+module_init(csum_init_module);
+module_exit(csum_cleanup_module);
index e17096e3913ccb983cf8abd533da20d30cf37b62..5b271a18bc3a54199510d8d7c6b8f2844afefcf9 100644 (file)
@@ -111,44 +111,41 @@ static u32 flow_get_proto(struct sk_buff *skb)
        }
 }
 
-static int has_ports(u8 protocol)
-{
-       switch (protocol) {
-       case IPPROTO_TCP:
-       case IPPROTO_UDP:
-       case IPPROTO_UDPLITE:
-       case IPPROTO_SCTP:
-       case IPPROTO_DCCP:
-       case IPPROTO_ESP:
-               return 1;
-       default:
-               return 0;
-       }
-}
-
 static u32 flow_get_proto_src(struct sk_buff *skb)
 {
        switch (skb->protocol) {
        case htons(ETH_P_IP): {
                struct iphdr *iph;
+               int poff;
 
                if (!pskb_network_may_pull(skb, sizeof(*iph)))
                        break;
                iph = ip_hdr(skb);
-               if (!(iph->frag_off&htons(IP_MF|IP_OFFSET)) &&
-                   has_ports(iph->protocol) &&
-                   pskb_network_may_pull(skb, iph->ihl * 4 + 2))
-                       return ntohs(*(__be16 *)((void *)iph + iph->ihl * 4));
+               if (iph->frag_off & htons(IP_MF|IP_OFFSET))
+                       break;
+               poff = proto_ports_offset(iph->protocol);
+               if (poff >= 0 &&
+                   pskb_network_may_pull(skb, iph->ihl * 4 + 2 + poff)) {
+                       iph = ip_hdr(skb);
+                       return ntohs(*(__be16 *)((void *)iph + iph->ihl * 4 +
+                                                poff));
+               }
                break;
        }
        case htons(ETH_P_IPV6): {
                struct ipv6hdr *iph;
+               int poff;
 
-               if (!pskb_network_may_pull(skb, sizeof(*iph) + 2))
+               if (!pskb_network_may_pull(skb, sizeof(*iph)))
                        break;
                iph = ipv6_hdr(skb);
-               if (has_ports(iph->nexthdr))
-                       return ntohs(*(__be16 *)&iph[1]);
+               poff = proto_ports_offset(iph->nexthdr);
+               if (poff >= 0 &&
+                   pskb_network_may_pull(skb, sizeof(*iph) + poff + 2)) {
+                       iph = ipv6_hdr(skb);
+                       return ntohs(*(__be16 *)((void *)iph + sizeof(*iph) +
+                                                poff));
+               }
                break;
        }
        }
@@ -161,24 +158,36 @@ static u32 flow_get_proto_dst(struct sk_buff *skb)
        switch (skb->protocol) {
        case htons(ETH_P_IP): {
                struct iphdr *iph;
+               int poff;
 
                if (!pskb_network_may_pull(skb, sizeof(*iph)))
                        break;
                iph = ip_hdr(skb);
-               if (!(iph->frag_off&htons(IP_MF|IP_OFFSET)) &&
-                   has_ports(iph->protocol) &&
-                   pskb_network_may_pull(skb, iph->ihl * 4 + 4))
-                       return ntohs(*(__be16 *)((void *)iph + iph->ihl * 4 + 2));
+               if (iph->frag_off & htons(IP_MF|IP_OFFSET))
+                       break;
+               poff = proto_ports_offset(iph->protocol);
+               if (poff >= 0 &&
+                   pskb_network_may_pull(skb, iph->ihl * 4 + 4 + poff)) {
+                       iph = ip_hdr(skb);
+                       return ntohs(*(__be16 *)((void *)iph + iph->ihl * 4 +
+                                                2 + poff));
+               }
                break;
        }
        case htons(ETH_P_IPV6): {
                struct ipv6hdr *iph;
+               int poff;
 
-               if (!pskb_network_may_pull(skb, sizeof(*iph) + 4))
+               if (!pskb_network_may_pull(skb, sizeof(*iph)))
                        break;
                iph = ipv6_hdr(skb);
-               if (has_ports(iph->nexthdr))
-                       return ntohs(*(__be16 *)((void *)&iph[1] + 2));
+               poff = proto_ports_offset(iph->nexthdr);
+               if (poff >= 0 &&
+                   pskb_network_may_pull(skb, sizeof(*iph) + poff + 4)) {
+                       iph = ipv6_hdr(skb);
+                       return ntohs(*(__be16 *)((void *)iph + sizeof(*iph) +
+                                                poff + 2));
+               }
                break;
        }
        }
@@ -297,6 +306,11 @@ static u32 flow_get_vlan_tag(const struct sk_buff *skb)
        return tag & VLAN_VID_MASK;
 }
 
+static u32 flow_get_rxhash(struct sk_buff *skb)
+{
+       return skb_get_rxhash(skb);
+}
+
 static u32 flow_key_get(struct sk_buff *skb, int key)
 {
        switch (key) {
@@ -334,6 +348,8 @@ static u32 flow_key_get(struct sk_buff *skb, int key)
                return flow_get_skgid(skb);
        case FLOW_KEY_VLAN_TAG:
                return flow_get_vlan_tag(skb);
+       case FLOW_KEY_RXHASH:
+               return flow_get_rxhash(skb);
        default:
                WARN_ON(1);
                return 0;
index 3bcac8aa333c2a322fb7283ce0803480e893d5d4..34da5e29ea1a8026388805cfba52e782ba01c9ec 100644 (file)
@@ -223,6 +223,11 @@ META_COLLECTOR(int_maclen)
        dst->value = skb->mac_len;
 }
 
+META_COLLECTOR(int_rxhash)
+{
+       dst->value = skb_get_rxhash(skb);
+}
+
 /**************************************************************************
  * Netfilter
  **************************************************************************/
@@ -541,6 +546,7 @@ static struct meta_ops __meta_ops[TCF_META_TYPE_MAX+1][TCF_META_ID_MAX+1] = {
                [META_ID(SK_SENDMSG_OFF)]       = META_FUNC(int_sk_sendmsg_off),
                [META_ID(SK_WRITE_PENDING)]     = META_FUNC(int_sk_write_pend),
                [META_ID(VLAN_TAG)]             = META_FUNC(int_vlan_tag),
+               [META_ID(RXHASH)]               = META_FUNC(int_rxhash),
        }
 };
 
index 408eea7086aace341d1ed9812d956db35cfdfb86..6fb3d41c0e41174d35d4d96612c493effcb1da4c 100644 (file)
@@ -360,7 +360,7 @@ static struct qdisc_size_table *qdisc_get_stab(struct nlattr *opt)
                tsize = nla_len(tb[TCA_STAB_DATA]) / sizeof(u16);
        }
 
-       if (!s || tsize != s->tsize || (!tab && tsize > 0))
+       if (tsize != s->tsize || (!tab && tsize > 0))
                return ERR_PTR(-EINVAL);
 
        spin_lock(&qdisc_stab_lock);
index 201cbac2b32ce0ccd8375b066005b6ba69759ddd..3cf478d012dd4f29b7a67f951c2cfa901b64248f 100644 (file)
@@ -123,40 +123,39 @@ static unsigned sfq_hash(struct sfq_sched_data *q, struct sk_buff *skb)
        case htons(ETH_P_IP):
        {
                const struct iphdr *iph;
+               int poff;
 
                if (!pskb_network_may_pull(skb, sizeof(*iph)))
                        goto err;
                iph = ip_hdr(skb);
                h = (__force u32)iph->daddr;
                h2 = (__force u32)iph->saddr ^ iph->protocol;
-               if (!(iph->frag_off&htons(IP_MF|IP_OFFSET)) &&
-                   (iph->protocol == IPPROTO_TCP ||
-                    iph->protocol == IPPROTO_UDP ||
-                    iph->protocol == IPPROTO_UDPLITE ||
-                    iph->protocol == IPPROTO_SCTP ||
-                    iph->protocol == IPPROTO_DCCP ||
-                    iph->protocol == IPPROTO_ESP) &&
-                    pskb_network_may_pull(skb, iph->ihl * 4 + 4))
-                       h2 ^= *(((u32*)iph) + iph->ihl);
+               if (iph->frag_off & htons(IP_MF|IP_OFFSET))
+                       break;
+               poff = proto_ports_offset(iph->protocol);
+               if (poff >= 0 &&
+                   pskb_network_may_pull(skb, iph->ihl * 4 + 4 + poff)) {
+                       iph = ip_hdr(skb);
+                       h2 ^= *(u32*)((void *)iph + iph->ihl * 4 + poff);
+               }
                break;
        }
        case htons(ETH_P_IPV6):
        {
                struct ipv6hdr *iph;
+               int poff;
 
                if (!pskb_network_may_pull(skb, sizeof(*iph)))
                        goto err;
                iph = ipv6_hdr(skb);
                h = (__force u32)iph->daddr.s6_addr32[3];
                h2 = (__force u32)iph->saddr.s6_addr32[3] ^ iph->nexthdr;
-               if ((iph->nexthdr == IPPROTO_TCP ||
-                    iph->nexthdr == IPPROTO_UDP ||
-                    iph->nexthdr == IPPROTO_UDPLITE ||
-                    iph->nexthdr == IPPROTO_SCTP ||
-                    iph->nexthdr == IPPROTO_DCCP ||
-                    iph->nexthdr == IPPROTO_ESP) &&
-                   pskb_network_may_pull(skb, sizeof(*iph) + 4))
-                       h2 ^= *(u32*)&iph[1];
+               poff = proto_ports_offset(iph->nexthdr);
+               if (poff >= 0 &&
+                   pskb_network_may_pull(skb, sizeof(*iph) + 4 + poff)) {
+                       iph = ipv6_hdr(skb);
+                       h2 ^= *(u32*)((void *)iph + sizeof(*iph) + poff);
+               }
                break;
        }
        default:
index 0b85e5256434858783e4cbb586faab2841ecbdd4..5f1fb8bd862dea391a2930f34d59d2129743ebaf 100644 (file)
@@ -48,6 +48,8 @@
  * be incorporated into the next SCTP release.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/types.h>
 #include <linux/fcntl.h>
 #include <linux/poll.h>
index 476caaf100ed740e0b72138721f1baf6ff90f584..6c8556459a751b3e2faa6b0442b804396ff6de7e 100644 (file)
@@ -37,6 +37,8 @@
  * be incorporated into the next SCTP release.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/net.h>
index ccb6dc48d15b6ecf123887cd23d00ffec1ec3c4a..397296fb156fd094169db1cacb0f940d936c6bc6 100644 (file)
@@ -43,6 +43,8 @@
  * be incorporated into the next SCTP release.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <net/sctp/sctp.h>
 #include <net/sctp/sm.h>
 #include <linux/interrupt.h>
index 732689140fb864d40f0cd109e92288bb74373a4c..95e0c8eda1a0b2c16463297ee7a0d5f45d3e884d 100644 (file)
@@ -47,6 +47,8 @@
  * be incorporated into the next SCTP release.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/types.h>
@@ -336,7 +338,7 @@ static void sctp_v6_get_saddr(struct sctp_sock *sk,
                memcpy(saddr, baddr, sizeof(union sctp_addr));
                SCTP_DEBUG_PRINTK("saddr: %pI6\n", &saddr->v6.sin6_addr);
        } else {
-               printk(KERN_ERR "%s: asoc:%p Could not find a valid source "
+               pr_err("%s: asoc:%p Could not find a valid source "
                       "address for the dest:%pI6\n",
                       __func__, asoc, &daddr->v6.sin6_addr);
        }
index f73ec0ea93ba374f6b15810abe6789828dafa0d4..8ef8e7d9eb61bbf74b6c023f4e33ee360085f84c 100644 (file)
@@ -38,6 +38,8 @@
  * be incorporated into the next SCTP release.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <net/sctp/sctp.h>
 
@@ -134,8 +136,7 @@ void sctp_dbg_objcnt_init(void)
        ent = proc_create("sctp_dbg_objcnt", 0,
                          proc_net_sctp, &sctp_objcnt_ops);
        if (!ent)
-               printk(KERN_WARNING
-                       "sctp_dbg_objcnt: Unable to create /proc entry.\n");
+               pr_warn("sctp_dbg_objcnt: Unable to create /proc entry.\n");
 }
 
 /* Cleanup the objcount entry in the proc filesystem.  */
index a646681f5acdffe30cd7b5b2f06c3bbf413609a6..901764b17aeedb1c77a1a8c4b2eb615670004fc5 100644 (file)
@@ -41,6 +41,8 @@
  * be incorporated into the next SCTP release.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/wait.h>
index c04b2eb591868627280269fd5379d2307f9802f7..8c6d379b4bb682634c27c3fef9f4bfc17786e507 100644 (file)
@@ -46,6 +46,8 @@
  * be incorporated into the next SCTP release.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/types.h>
 #include <linux/list.h>   /* For struct list_head */
 #include <linux/socket.h>
@@ -1463,23 +1465,23 @@ static void sctp_check_transmitted(struct sctp_outq *q,
                                        /* Display the end of the
                                         * current range.
                                         */
-                                       SCTP_DEBUG_PRINTK("-%08x",
-                                                         dbg_last_ack_tsn);
+                                       SCTP_DEBUG_PRINTK_CONT("-%08x",
+                                                              dbg_last_ack_tsn);
                                }
 
                                /* Start a new range.  */
-                               SCTP_DEBUG_PRINTK(",%08x", tsn);
+                               SCTP_DEBUG_PRINTK_CONT(",%08x", tsn);
                                dbg_ack_tsn = tsn;
                                break;
 
                        case 1: /* The last TSN was NOT ACKed. */
                                if (dbg_last_kept_tsn != dbg_kept_tsn) {
                                        /* Display the end of current range. */
-                                       SCTP_DEBUG_PRINTK("-%08x",
-                                                         dbg_last_kept_tsn);
+                                       SCTP_DEBUG_PRINTK_CONT("-%08x",
+                                                              dbg_last_kept_tsn);
                                }
 
-                               SCTP_DEBUG_PRINTK("\n");
+                               SCTP_DEBUG_PRINTK_CONT("\n");
 
                                /* FALL THROUGH... */
                        default:
@@ -1526,18 +1528,18 @@ static void sctp_check_transmitted(struct sctp_outq *q,
                                        break;
 
                                if (dbg_last_kept_tsn != dbg_kept_tsn)
-                                       SCTP_DEBUG_PRINTK("-%08x",
-                                                         dbg_last_kept_tsn);
+                                       SCTP_DEBUG_PRINTK_CONT("-%08x",
+                                                              dbg_last_kept_tsn);
 
-                               SCTP_DEBUG_PRINTK(",%08x", tsn);
+                               SCTP_DEBUG_PRINTK_CONT(",%08x", tsn);
                                dbg_kept_tsn = tsn;
                                break;
 
                        case 0:
                                if (dbg_last_ack_tsn != dbg_ack_tsn)
-                                       SCTP_DEBUG_PRINTK("-%08x",
-                                                         dbg_last_ack_tsn);
-                               SCTP_DEBUG_PRINTK("\n");
+                                       SCTP_DEBUG_PRINTK_CONT("-%08x",
+                                                              dbg_last_ack_tsn);
+                               SCTP_DEBUG_PRINTK_CONT("\n");
 
                                /* FALL THROUGH... */
                        default:
@@ -1556,17 +1558,17 @@ static void sctp_check_transmitted(struct sctp_outq *q,
        switch (dbg_prt_state) {
        case 0:
                if (dbg_last_ack_tsn != dbg_ack_tsn) {
-                       SCTP_DEBUG_PRINTK("-%08x\n", dbg_last_ack_tsn);
+                       SCTP_DEBUG_PRINTK_CONT("-%08x\n", dbg_last_ack_tsn);
                } else {
-                       SCTP_DEBUG_PRINTK("\n");
+                       SCTP_DEBUG_PRINTK_CONT("\n");
                }
        break;
 
        case 1:
                if (dbg_last_kept_tsn != dbg_kept_tsn) {
-                       SCTP_DEBUG_PRINTK("-%08x\n", dbg_last_kept_tsn);
+                       SCTP_DEBUG_PRINTK_CONT("-%08x\n", dbg_last_kept_tsn);
                } else {
-                       SCTP_DEBUG_PRINTK("\n");
+                       SCTP_DEBUG_PRINTK_CONT("\n");
                }
        }
 #endif /* SCTP_DEBUG */
index db3a42b8b34962594b7c8fe3e38b45cb68b19f83..2e63e9dc010e46c5b656cc220efce78e43b08c78 100644 (file)
@@ -22,6 +22,8 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/kprobes.h>
 #include <linux/socket.h>
@@ -192,7 +194,7 @@ static __init int sctpprobe_init(void)
        if (ret)
                goto remove_proc;
 
-       pr_info("SCTP probe registered (port=%d)\n", port);
+       pr_info("probe registered (port=%d)\n", port);
 
        return 0;
 
index 5027b83f1cc0c840f6015bb9418356ae61c17242..f774e657641a607a65ee44b293722f2c0bdfe974 100644 (file)
@@ -46,6 +46,8 @@
  * be incorporated into the next SCTP release.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/netdevice.h>
@@ -707,8 +709,7 @@ static int sctp_ctl_sock_init(void)
                                           &init_net);
 
        if (err < 0) {
-               printk(KERN_ERR
-                      "SCTP: Failed to create the SCTP control socket.\n");
+               pr_err("Failed to create the SCTP control socket\n");
                return err;
        }
        return 0;
@@ -1206,7 +1207,7 @@ SCTP_STATIC __init int sctp_init(void)
                                        __get_free_pages(GFP_ATOMIC, order);
        } while (!sctp_assoc_hashtable && --order > 0);
        if (!sctp_assoc_hashtable) {
-               printk(KERN_ERR "SCTP: Failed association hash alloc.\n");
+               pr_err("Failed association hash alloc\n");
                status = -ENOMEM;
                goto err_ahash_alloc;
        }
@@ -1220,7 +1221,7 @@ SCTP_STATIC __init int sctp_init(void)
        sctp_ep_hashtable = (struct sctp_hashbucket *)
                kmalloc(64 * sizeof(struct sctp_hashbucket), GFP_KERNEL);
        if (!sctp_ep_hashtable) {
-               printk(KERN_ERR "SCTP: Failed endpoint_hash alloc.\n");
+               pr_err("Failed endpoint_hash alloc\n");
                status = -ENOMEM;
                goto err_ehash_alloc;
        }
@@ -1239,7 +1240,7 @@ SCTP_STATIC __init int sctp_init(void)
                                        __get_free_pages(GFP_ATOMIC, order);
        } while (!sctp_port_hashtable && --order > 0);
        if (!sctp_port_hashtable) {
-               printk(KERN_ERR "SCTP: Failed bind hash alloc.");
+               pr_err("Failed bind hash alloc\n");
                status = -ENOMEM;
                goto err_bhash_alloc;
        }
@@ -1248,8 +1249,7 @@ SCTP_STATIC __init int sctp_init(void)
                INIT_HLIST_HEAD(&sctp_port_hashtable[i].chain);
        }
 
-       printk(KERN_INFO "SCTP: Hash tables configured "
-                        "(established %d bind %d)\n",
+       pr_info("Hash tables configured (established %d bind %d)\n",
                sctp_assoc_hashsize, sctp_port_hashsize);
 
        /* Disable ADDIP by default. */
@@ -1290,8 +1290,7 @@ SCTP_STATIC __init int sctp_init(void)
 
        /* Initialize the control inode/socket for handling OOTB packets.  */
        if ((status = sctp_ctl_sock_init())) {
-               printk (KERN_ERR
-                       "SCTP: Failed to initialize the SCTP control sock.\n");
+               pr_err("Failed to initialize the SCTP control sock\n");
                goto err_ctl_sock_init;
        }
 
index 246f92924658b7d5dca18ae4d4a212d590b3e4d8..2cc46f0962ca37b63e398c633f794c5986977095 100644 (file)
@@ -50,6 +50,8 @@
  * be incorporated into the next SCTP release.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/ip.h>
index f5e5e27cac5ee5918f815fecf1cebbbc6be3203e..b21b218d564f20f9f9b04e39412a0499377d8d62 100644 (file)
@@ -47,6 +47,8 @@
  * be incorporated into the next SCTP release.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/skbuff.h>
 #include <linux/types.h>
 #include <linux/socket.h>
@@ -1146,26 +1148,23 @@ static int sctp_side_effects(sctp_event_t event_type, sctp_subtype_t subtype,
 
        case SCTP_DISPOSITION_VIOLATION:
                if (net_ratelimit())
-                       printk(KERN_ERR "sctp protocol violation state %d "
-                              "chunkid %d\n", state, subtype.chunk);
+                       pr_err("protocol violation state %d chunkid %d\n",
+                              state, subtype.chunk);
                break;
 
        case SCTP_DISPOSITION_NOT_IMPL:
-               printk(KERN_WARNING "sctp unimplemented feature in state %d, "
-                      "event_type %d, event_id %d\n",
-                      state, event_type, subtype.chunk);
+               pr_warn("unimplemented feature in state %d, event_type %d, event_id %d\n",
+                       state, event_type, subtype.chunk);
                break;
 
        case SCTP_DISPOSITION_BUG:
-               printk(KERN_ERR "sctp bug in state %d, "
-                      "event_type %d, event_id %d\n",
+               pr_err("bug in state %d, event_type %d, event_id %d\n",
                       state, event_type, subtype.chunk);
                BUG();
                break;
 
        default:
-               printk(KERN_ERR "sctp impossible disposition %d "
-                      "in state %d, event_type %d, event_id %d\n",
+               pr_err("impossible disposition %d in state %d, event_type %d, event_id %d\n",
                       status, state, event_type, subtype.chunk);
                BUG();
                break;
@@ -1679,8 +1678,8 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
                        sctp_cmd_send_asconf(asoc);
                        break;
                default:
-                       printk(KERN_WARNING "Impossible command: %u, %p\n",
-                              cmd->verb, cmd->obj.ptr);
+                       pr_warn("Impossible command: %u, %p\n",
+                               cmd->verb, cmd->obj.ptr);
                        break;
                }
 
index d344dc481ccc7a22d517c13995e825a73bed21ce..4b4eb7c96bbdb32027834f38ec4ad2f307e84616 100644 (file)
@@ -50,6 +50,8 @@
  * be incorporated into the next SCTP release.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/ip.h>
@@ -1138,18 +1140,16 @@ sctp_disposition_t sctp_sf_backbeat_8_3(const struct sctp_endpoint *ep,
        if (unlikely(!link)) {
                if (from_addr.sa.sa_family == AF_INET6) {
                        if (net_ratelimit())
-                               printk(KERN_WARNING
-                                   "%s association %p could not find address %pI6\n",
-                                   __func__,
-                                   asoc,
-                                   &from_addr.v6.sin6_addr);
+                               pr_warn("%s association %p could not find address %pI6\n",
+                                       __func__,
+                                       asoc,
+                                       &from_addr.v6.sin6_addr);
                } else {
                        if (net_ratelimit())
-                               printk(KERN_WARNING
-                                   "%s association %p could not find address %pI4\n",
-                                   __func__,
-                                   asoc,
-                                   &from_addr.v4.sin_addr.s_addr);
+                               pr_warn("%s association %p could not find address %pI4\n",
+                                       __func__,
+                                       asoc,
+                                       &from_addr.v4.sin_addr.s_addr);
                }
                return SCTP_DISPOSITION_DISCARD;
        }
index 6d9b3aafcc5dbd4327a0d5a89e4fa03d4b710e5c..546d4387fb3caee906ad543c0528674b0f4f876b 100644 (file)
@@ -46,6 +46,8 @@
  * be incorporated into the next SCTP release.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/skbuff.h>
 #include <net/sctp/sctp.h>
 #include <net/sctp/sm.h>
@@ -66,15 +68,19 @@ static const sctp_sm_table_entry_t bug = {
        .name = "sctp_sf_bug"
 };
 
-#define DO_LOOKUP(_max, _type, _table) \
-       if ((event_subtype._type > (_max))) { \
-               printk(KERN_WARNING \
-                      "sctp table %p possible attack:" \
-                      " event %d exceeds max %d\n", \
-                      _table, event_subtype._type, _max); \
-               return &bug; \
-       } \
-       return &_table[event_subtype._type][(int)state];
+#define DO_LOOKUP(_max, _type, _table)                                 \
+({                                                                     \
+       const sctp_sm_table_entry_t *rtn;                               \
+                                                                       \
+       if ((event_subtype._type > (_max))) {                           \
+               pr_warn("table %p possible attack: event %d exceeds max %d\n", \
+                       _table, event_subtype._type, _max);             \
+               rtn = &bug;                                             \
+       } else                                                          \
+               rtn = &_table[event_subtype._type][(int)state];         \
+                                                                       \
+       rtn;                                                            \
+})
 
 const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type,
                                                  sctp_state_t state,
@@ -83,21 +89,15 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type,
        switch (event_type) {
        case SCTP_EVENT_T_CHUNK:
                return sctp_chunk_event_lookup(event_subtype.chunk, state);
-               break;
        case SCTP_EVENT_T_TIMEOUT:
-               DO_LOOKUP(SCTP_EVENT_TIMEOUT_MAX, timeout,
-                         timeout_event_table);
-               break;
-
+               return DO_LOOKUP(SCTP_EVENT_TIMEOUT_MAX, timeout,
+                                timeout_event_table);
        case SCTP_EVENT_T_OTHER:
-               DO_LOOKUP(SCTP_EVENT_OTHER_MAX, other, other_event_table);
-               break;
-
+               return DO_LOOKUP(SCTP_EVENT_OTHER_MAX, other,
+                                other_event_table);
        case SCTP_EVENT_T_PRIMITIVE:
-               DO_LOOKUP(SCTP_EVENT_PRIMITIVE_MAX, primitive,
-                         primitive_event_table);
-               break;
-
+               return DO_LOOKUP(SCTP_EVENT_PRIMITIVE_MAX, primitive,
+                                primitive_event_table);
        default:
                /* Yikes!  We got an illegal event type.  */
                return &bug;
index ca44917872d2553b98f4e2f3601f95fe0f2c414f..6a691d84aef4223ddea29759f7bf8f4b8c25aa0e 100644 (file)
@@ -57,6 +57,8 @@
  * be incorporated into the next SCTP release.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/wait.h>
@@ -2458,9 +2460,8 @@ static int sctp_setsockopt_delayed_ack(struct sock *sk,
                if (params.sack_delay == 0 && params.sack_freq == 0)
                        return 0;
        } else if (optlen == sizeof(struct sctp_assoc_value)) {
-               printk(KERN_WARNING "SCTP: Use of struct sctp_assoc_value "
-                      "in delayed_ack socket option deprecated\n");
-               printk(KERN_WARNING "SCTP: Use struct sctp_sack_info instead\n");
+               pr_warn("Use of struct sctp_assoc_value in delayed_ack socket option deprecated\n");
+               pr_warn("Use struct sctp_sack_info instead\n");
                if (copy_from_user(&params, optval, optlen))
                        return -EFAULT;
 
@@ -2868,10 +2869,8 @@ static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, unsigned
        int val;
 
        if (optlen == sizeof(int)) {
-               printk(KERN_WARNING
-                  "SCTP: Use of int in maxseg socket option deprecated\n");
-               printk(KERN_WARNING
-                  "SCTP: Use struct sctp_assoc_value instead\n");
+               pr_warn("Use of int in maxseg socket option deprecated\n");
+               pr_warn("Use struct sctp_assoc_value instead\n");
                if (copy_from_user(&val, optval, optlen))
                        return -EFAULT;
                params.assoc_id = 0;
@@ -3121,10 +3120,8 @@ static int sctp_setsockopt_maxburst(struct sock *sk,
        int assoc_id = 0;
 
        if (optlen == sizeof(int)) {
-               printk(KERN_WARNING
-                  "SCTP: Use of int in max_burst socket option deprecated\n");
-               printk(KERN_WARNING
-                  "SCTP: Use struct sctp_assoc_value instead\n");
+               pr_warn("Use of int in max_burst socket option deprecated\n");
+               pr_warn("Use struct sctp_assoc_value instead\n");
                if (copy_from_user(&val, optval, optlen))
                        return -EFAULT;
        } else if (optlen == sizeof(struct sctp_assoc_value)) {
@@ -3595,7 +3592,40 @@ out:
 /* The SCTP ioctl handler. */
 SCTP_STATIC int sctp_ioctl(struct sock *sk, int cmd, unsigned long arg)
 {
-       return -ENOIOCTLCMD;
+       int rc = -ENOTCONN;
+
+       sctp_lock_sock(sk);
+
+       /*
+        * SEQPACKET-style sockets in LISTENING state are valid, for
+        * SCTP, so only discard TCP-style sockets in LISTENING state.
+        */
+       if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING))
+               goto out;
+
+       switch (cmd) {
+       case SIOCINQ: {
+               struct sk_buff *skb;
+               unsigned int amount = 0;
+
+               skb = skb_peek(&sk->sk_receive_queue);
+               if (skb != NULL) {
+                       /*
+                        * We will only return the amount of this packet since
+                        * that is all that will be read.
+                        */
+                       amount = skb->len;
+               }
+               rc = put_user(amount, (int __user *)arg);
+       }
+               break;
+       default:
+               rc = -ENOIOCTLCMD;
+               break;
+       }
+out:
+       sctp_release_sock(sk);
+       return rc;
 }
 
 /* This is the function which gets called during socket creation to
@@ -4281,9 +4311,8 @@ static int sctp_getsockopt_delayed_ack(struct sock *sk, int len,
                if (copy_from_user(&params, optval, len))
                        return -EFAULT;
        } else if (len == sizeof(struct sctp_assoc_value)) {
-               printk(KERN_WARNING "SCTP: Use of struct sctp_assoc_value "
-                      "in delayed_ack socket option deprecated\n");
-               printk(KERN_WARNING "SCTP: Use struct sctp_sack_info instead\n");
+               pr_warn("Use of struct sctp_assoc_value in delayed_ack socket option deprecated\n");
+               pr_warn("Use struct sctp_sack_info instead\n");
                if (copy_from_user(&params, optval, len))
                        return -EFAULT;
        } else
@@ -4929,10 +4958,8 @@ static int sctp_getsockopt_maxseg(struct sock *sk, int len,
        struct sctp_association *asoc;
 
        if (len == sizeof(int)) {
-               printk(KERN_WARNING
-                  "SCTP: Use of int in maxseg socket option deprecated\n");
-               printk(KERN_WARNING
-                  "SCTP: Use struct sctp_assoc_value instead\n");
+               pr_warn("Use of int in maxseg socket option deprecated\n");
+               pr_warn("Use struct sctp_assoc_value instead\n");
                params.assoc_id = 0;
        } else if (len >= sizeof(struct sctp_assoc_value)) {
                len = sizeof(struct sctp_assoc_value);
@@ -5023,10 +5050,8 @@ static int sctp_getsockopt_maxburst(struct sock *sk, int len,
        struct sctp_association *asoc;
 
        if (len == sizeof(int)) {
-               printk(KERN_WARNING
-                  "SCTP: Use of int in max_burst socket option deprecated\n");
-               printk(KERN_WARNING
-                  "SCTP: Use struct sctp_assoc_value instead\n");
+               pr_warn("Use of int in max_burst socket option deprecated\n");
+               pr_warn("Use struct sctp_assoc_value instead\n");
                params.assoc_id = 0;
        } else if (len >= sizeof(struct sctp_assoc_value)) {
                len = sizeof(struct sctp_assoc_value);
@@ -5586,8 +5611,7 @@ SCTP_STATIC int sctp_listen_start(struct sock *sk, int backlog)
                tfm = crypto_alloc_hash(sctp_hmac_alg, 0, CRYPTO_ALG_ASYNC);
                if (IS_ERR(tfm)) {
                        if (net_ratelimit()) {
-                               printk(KERN_INFO
-                                      "SCTP: failed to load transform for %s: %ld\n",
+                               pr_info("failed to load transform for %s: %ld\n",
                                        sctp_hmac_alg, PTR_ERR(tfm));
                        }
                        return -ENOSYS;
@@ -5716,13 +5740,12 @@ unsigned int sctp_poll(struct file *file, struct socket *sock, poll_table *wait)
        if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue))
                mask |= POLLERR;
        if (sk->sk_shutdown & RCV_SHUTDOWN)
-               mask |= POLLRDHUP;
+               mask |= POLLRDHUP | POLLIN | POLLRDNORM;
        if (sk->sk_shutdown == SHUTDOWN_MASK)
                mask |= POLLHUP;
 
        /* Is it readable?  Reconsider this code with TCP-style support.  */
-       if (!skb_queue_empty(&sk->sk_receive_queue) ||
-           (sk->sk_shutdown & RCV_SHUTDOWN))
+       if (!skb_queue_empty(&sk->sk_receive_queue))
                mask |= POLLIN | POLLRDNORM;
 
        /* The association is either gone or not ready.  */
index 132046cb82fc764ae758a0535aad8816946ae1d2..d3ae493d234aaebe0e60c97e17479659e4a4c181 100644 (file)
@@ -48,6 +48,8 @@
  * be incorporated into the next SCTP release.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/slab.h>
 #include <linux/types.h>
 #include <linux/random.h>
@@ -244,10 +246,9 @@ void sctp_transport_update_pmtu(struct sctp_transport *t, u32 pmtu)
        struct dst_entry *dst;
 
        if (unlikely(pmtu < SCTP_DEFAULT_MINSEGMENT)) {
-               printk(KERN_WARNING "%s: Reported pmtu %d too low, "
-                      "using default minimum of %d\n",
-                      __func__, pmtu,
-                      SCTP_DEFAULT_MINSEGMENT);
+               pr_warn("%s: Reported pmtu %d too low, using default minimum of %d\n",
+                       __func__, pmtu,
+                       SCTP_DEFAULT_MINSEGMENT);
                /* Use default minimum segment size and disable
                 * pmtu discovery on this transport.
                 */
index 2270b941bcc76ec0e52cc0d1321d8572164299e1..717a5f1c8792baca7fd6079ca075851e1849fcdd 100644 (file)
@@ -535,14 +535,13 @@ void sock_release(struct socket *sock)
 }
 EXPORT_SYMBOL(sock_release);
 
-int sock_tx_timestamp(struct msghdr *msg, struct sock *sk,
-                     union skb_shared_tx *shtx)
+int sock_tx_timestamp(struct sock *sk, __u8 *tx_flags)
 {
-       shtx->flags = 0;
+       *tx_flags = 0;
        if (sock_flag(sk, SOCK_TIMESTAMPING_TX_HARDWARE))
-               shtx->hardware = 1;
+               *tx_flags |= SKBTX_HW_TSTAMP;
        if (sock_flag(sk, SOCK_TIMESTAMPING_TX_SOFTWARE))
-               shtx->software = 1;
+               *tx_flags |= SKBTX_SW_TSTAMP;
        return 0;
 }
 EXPORT_SYMBOL(sock_tx_timestamp);
@@ -1919,7 +1918,8 @@ SYSCALL_DEFINE3(sendmsg, int, fd, struct msghdr __user *, msg, unsigned, flags)
                 * Afterwards, it will be a kernel pointer. Thus the compiler-assisted
                 * checking falls down on this.
                 */
-               if (copy_from_user(ctl_buf, (void __user *)msg_sys.msg_control,
+               if (copy_from_user(ctl_buf,
+                                  (void __user __force *)msg_sys.msg_control,
                                   ctl_len))
                        goto out_freectl;
                msg_sys.msg_control = ctl_buf;
@@ -3054,14 +3054,19 @@ int kernel_getsockopt(struct socket *sock, int level, int optname,
                        char *optval, int *optlen)
 {
        mm_segment_t oldfs = get_fs();
+       char __user *uoptval;
+       int __user *uoptlen;
        int err;
 
+       uoptval = (char __user __force *) optval;
+       uoptlen = (int __user __force *) optlen;
+
        set_fs(KERNEL_DS);
        if (level == SOL_SOCKET)
-               err = sock_getsockopt(sock, level, optname, optval, optlen);
+               err = sock_getsockopt(sock, level, optname, uoptval, uoptlen);
        else
-               err = sock->ops->getsockopt(sock, level, optname, optval,
-                                           optlen);
+               err = sock->ops->getsockopt(sock, level, optname, uoptval,
+                                           uoptlen);
        set_fs(oldfs);
        return err;
 }
@@ -3071,13 +3076,16 @@ int kernel_setsockopt(struct socket *sock, int level, int optname,
                        char *optval, unsigned int optlen)
 {
        mm_segment_t oldfs = get_fs();
+       char __user *uoptval;
        int err;
 
+       uoptval = (char __user __force *) optval;
+
        set_fs(KERNEL_DS);
        if (level == SOL_SOCKET)
-               err = sock_setsockopt(sock, level, optname, optval, optlen);
+               err = sock_setsockopt(sock, level, optname, uoptval, optlen);
        else
-               err = sock->ops->setsockopt(sock, level, optname, optval,
+               err = sock->ops->setsockopt(sock, level, optname, uoptval,
                                            optlen);
        set_fs(oldfs);
        return err;
index a008c6689305bd7b037a5226f1107a878c943060..b11248c2d788f5a1075b9aea1dd502bf0fd61b07 100644 (file)
@@ -143,6 +143,19 @@ static void bcbuf_decr_acks(struct sk_buff *buf)
 }
 
 
+static void bclink_set_last_sent(void)
+{
+       if (bcl->next_out)
+               bcl->fsm_msg_cnt = mod(buf_seqno(bcl->next_out) - 1);
+       else
+               bcl->fsm_msg_cnt = mod(bcl->next_out_no - 1);
+}
+
+u32 tipc_bclink_get_last_sent(void)
+{
+       return bcl->fsm_msg_cnt;
+}
+
 /**
  * bclink_set_gap - set gap according to contents of current deferred pkt queue
  *
@@ -237,8 +250,10 @@ void tipc_bclink_acknowledge(struct tipc_node *n_ptr, u32 acked)
 
        /* Try resolving broadcast link congestion, if necessary */
 
-       if (unlikely(bcl->next_out))
+       if (unlikely(bcl->next_out)) {
                tipc_link_push_queue(bcl);
+               bclink_set_last_sent();
+       }
        if (unlikely(released && !list_empty(&bcl->waiting_ports)))
                tipc_link_wakeup_ports(bcl, 0);
        spin_unlock_bh(&bc_lock);
@@ -395,7 +410,7 @@ int tipc_bclink_send_msg(struct sk_buff *buf)
        if (unlikely(res == -ELINKCONG))
                buf_discard(buf);
        else
-               bcl->stats.sent_info++;
+               bclink_set_last_sent();
 
        if (bcl->out_queue_size > bcl->stats.max_queue_sz)
                bcl->stats.max_queue_sz = bcl->out_queue_size;
@@ -529,15 +544,6 @@ receive:
        tipc_node_unlock(node);
 }
 
-u32 tipc_bclink_get_last_sent(void)
-{
-       u32 last_sent = mod(bcl->next_out_no - 1);
-
-       if (bcl->next_out)
-               last_sent = mod(buf_seqno(bcl->next_out) - 1);
-       return last_sent;
-}
-
 u32 tipc_bclink_acks_missing(struct tipc_node *n_ptr)
 {
        return (n_ptr->bclink.supported &&
@@ -570,6 +576,7 @@ static int tipc_bcbearer_send(struct sk_buff *buf,
                msg = buf_msg(buf);
                msg_set_non_seq(msg, 1);
                msg_set_mc_netid(msg, tipc_net_id);
+               bcl->stats.sent_info++;
        }
 
        /* Send buffer over bearers until all targets reached */
@@ -609,11 +616,13 @@ static int tipc_bcbearer_send(struct sk_buff *buf,
                bcbearer->remains = bcbearer->remains_new;
        }
 
-       /* Unable to reach all targets */
+       /*
+        * Unable to reach all targets (indicate success, since currently
+        * there isn't code in place to properly block & unblock the
+        * pseudo-bearer used by the broadcast link)
+        */
 
-       bcbearer->bearer.publ.blocked = 1;
-       bcl->stats.bearer_congs++;
-       return 1;
+       return TIPC_OK;
 }
 
 /**
index 69646811798542cb29b37e66dd424679464a30a9..466b861dab91acb0fb6fbcab76e24585e755fd48 100644 (file)
@@ -169,6 +169,7 @@ void tipc_core_stop(void)
        tipc_nametbl_stop();
        tipc_ref_table_stop();
        tipc_socket_stop();
+       tipc_log_resize(0);
 }
 
 /**
@@ -203,7 +204,9 @@ static int __init tipc_init(void)
 {
        int res;
 
-       tipc_log_resize(CONFIG_TIPC_LOG);
+       if (tipc_log_resize(CONFIG_TIPC_LOG) != 0)
+               warn("Unable to create log buffer\n");
+
        info("Activated (version " TIPC_MOD_VER
             " compiled " __DATE__ " " __TIME__ ")\n");
 
@@ -230,7 +233,6 @@ static void __exit tipc_exit(void)
        tipc_core_stop_net();
        tipc_core_stop();
        info("Deactivated\n");
-       tipc_log_resize(0);
 }
 
 module_init(tipc_init);
index fc1fcf5e6b53625e4bc22ad29228af151de6288f..f28d1ae931257275607911d766405fdfa0b79c47 100644 (file)
@@ -203,6 +203,14 @@ void tipc_disc_recv_msg(struct sk_buff *buf, struct bearer *b_ptr)
                                return;
                }
                spin_lock_bh(&n_ptr->lock);
+
+               /* Don't talk to neighbor during cleanup after last session */
+
+               if (n_ptr->cleanup_required) {
+                       spin_unlock_bh(&n_ptr->lock);
+                       return;
+               }
+
                link = n_ptr->links[b_ptr->identity];
                if (!link) {
                        dbg("creating link\n");
index 6230d16020c49917f5f28e06b514d379f698205d..6e988ba485fde54bed1b2dde5038a05f354d24d8 100644 (file)
@@ -72,17 +72,26 @@ static int send_msg(struct sk_buff *buf, struct tipc_bearer *tb_ptr,
 {
        struct sk_buff *clone;
        struct net_device *dev;
+       int delta;
 
        clone = skb_clone(buf, GFP_ATOMIC);
-       if (clone) {
-               skb_reset_network_header(clone);
-               dev = ((struct eth_bearer *)(tb_ptr->usr_handle))->dev;
-               clone->dev = dev;
-               dev_hard_header(clone, dev, ETH_P_TIPC,
-                                &dest->dev_addr.eth_addr,
-                                dev->dev_addr, clone->len);
-               dev_queue_xmit(clone);
+       if (!clone)
+               return 0;
+
+       dev = ((struct eth_bearer *)(tb_ptr->usr_handle))->dev;
+       delta = dev->hard_header_len - skb_headroom(buf);
+
+       if ((delta > 0) &&
+           pskb_expand_head(clone, SKB_DATA_ALIGN(delta), 0, GFP_ATOMIC)) {
+               kfree_skb(clone);
+               return 0;
        }
+
+       skb_reset_network_header(clone);
+       clone->dev = dev;
+       dev_hard_header(clone, dev, ETH_P_TIPC, &dest->dev_addr.eth_addr,
+                       dev->dev_addr, clone->len);
+       dev_queue_xmit(clone);
        return 0;
 }
 
@@ -92,15 +101,12 @@ static int send_msg(struct sk_buff *buf, struct tipc_bearer *tb_ptr,
  * Accept only packets explicitly sent to this node, or broadcast packets;
  * ignores packets sent using Ethernet multicast, and traffic sent to other
  * nodes (which can happen if interface is running in promiscuous mode).
- * Routine truncates any Ethernet padding/CRC appended to the message,
- * and ensures message size matches actual length
  */
 
 static int recv_msg(struct sk_buff *buf, struct net_device *dev,
                    struct packet_type *pt, struct net_device *orig_dev)
 {
        struct eth_bearer *eb_ptr = (struct eth_bearer *)pt->af_packet_priv;
-       u32 size;
 
        if (!net_eq(dev_net(dev), &init_net)) {
                kfree_skb(buf);
@@ -109,13 +115,9 @@ static int recv_msg(struct sk_buff *buf, struct net_device *dev,
 
        if (likely(eb_ptr->bearer)) {
                if (likely(buf->pkt_type <= PACKET_BROADCAST)) {
-                       size = msg_size((struct tipc_msg *)buf->data);
-                       skb_trim(buf, size);
-                       if (likely(buf->len == size)) {
-                               buf->next = NULL;
-                               tipc_recv_msg(buf, eb_ptr->bearer);
-                               return 0;
-                       }
+                       buf->next = NULL;
+                       tipc_recv_msg(buf, eb_ptr->bearer);
+                       return 0;
                }
        }
        kfree_skb(buf);
@@ -133,6 +135,16 @@ static int enable_bearer(struct tipc_bearer *tb_ptr)
        struct eth_bearer *eb_ptr = &eth_bearers[0];
        struct eth_bearer *stop = &eth_bearers[MAX_ETH_BEARERS];
        char *driver_name = strchr((const char *)tb_ptr->name, ':') + 1;
+       int pending_dev = 0;
+
+       /* Find unused Ethernet bearer structure */
+
+       while (eb_ptr->dev) {
+               if (!eb_ptr->bearer)
+                       pending_dev++;
+               if (++eb_ptr == stop)
+                       return pending_dev ? -EAGAIN : -EDQUOT;
+       }
 
        /* Find device with specified name */
 
index a3616b99529b72ef1085fe95c99fd972e95e6b93..a6a3102bb4d6b9acb78d7e5a9dca11aca0ac5c54 100644 (file)
@@ -1802,6 +1802,15 @@ static int link_recv_buf_validate(struct sk_buff *buf)
        return pskb_may_pull(buf, hdr_size);
 }
 
+/**
+ * tipc_recv_msg - process TIPC messages arriving from off-node
+ * @head: pointer to message buffer chain
+ * @tb_ptr: pointer to bearer message arrived on
+ *
+ * Invoked with no locks held.  Bearer pointer must point to a valid bearer
+ * structure (i.e. cannot be NULL), but bearer can be inactive.
+ */
+
 void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *tb_ptr)
 {
        read_lock_bh(&tipc_net_lock);
@@ -1819,6 +1828,11 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *tb_ptr)
 
                head = head->next;
 
+               /* Ensure bearer is still enabled */
+
+               if (unlikely(!b_ptr->active))
+                       goto cont;
+
                /* Ensure message is well-formed */
 
                if (unlikely(!link_recv_buf_validate(buf)))
@@ -1855,13 +1869,22 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *tb_ptr)
                                goto cont;
                }
 
-               /* Locate unicast link endpoint that should handle message */
+               /* Locate neighboring node that sent message */
 
                n_ptr = tipc_node_find(msg_prevnode(msg));
                if (unlikely(!n_ptr))
                        goto cont;
                tipc_node_lock(n_ptr);
 
+               /* Don't talk to neighbor during cleanup after last session */
+
+               if (n_ptr->cleanup_required) {
+                       tipc_node_unlock(n_ptr);
+                       goto cont;
+               }
+
+               /* Locate unicast link endpoint that should handle message */
+
                l_ptr = n_ptr->links[b_ptr->identity];
                if (unlikely(!l_ptr)) {
                        tipc_node_unlock(n_ptr);
index 8ba79620db3f705941fa04ba25aeda92f1215d98..c13c2c7c4b575205d7ce8a397121acf30f09d724 100644 (file)
@@ -613,8 +613,7 @@ struct publication *tipc_nametbl_remove_publ(u32 type, u32 lower,
 }
 
 /*
- * tipc_nametbl_translate(): Translate tipc_name -> tipc_portid.
- *                      Very time-critical.
+ * tipc_nametbl_translate - translate name to port id
  *
  * Note: on entry 'destnode' is the search domain used during translation;
  *       on exit it passes back the node address of the matching port (if any)
@@ -685,7 +684,6 @@ found:
        }
        spin_unlock_bh(&seq->lock);
 not_found:
-       *destnode = 0;
        read_unlock_bh(&tipc_nametbl_lock);
        return 0;
 }
@@ -877,7 +875,7 @@ static void subseq_list(struct sub_seq *sseq, struct print_buf *buf, u32 depth,
                        u32 index)
 {
        char portIdStr[27];
-       char *scopeStr;
+       const char *scope_str[] = {"", " zone", " cluster", " node"};
        struct publication *publ = sseq->zone_list;
 
        tipc_printf(buf, "%-10u %-10u ", sseq->lower, sseq->upper);
@@ -893,15 +891,8 @@ static void subseq_list(struct sub_seq *sseq, struct print_buf *buf, u32 depth,
                         tipc_node(publ->node), publ->ref);
                tipc_printf(buf, "%-26s ", portIdStr);
                if (depth > 3) {
-                       if (publ->node != tipc_own_addr)
-                               scopeStr = "";
-                       else if (publ->scope == TIPC_NODE_SCOPE)
-                               scopeStr = "node";
-                       else if (publ->scope == TIPC_CLUSTER_SCOPE)
-                               scopeStr = "cluster";
-                       else
-                               scopeStr = "zone";
-                       tipc_printf(buf, "%-10u %s", publ->key, scopeStr);
+                       tipc_printf(buf, "%-10u %s", publ->key,
+                                   scope_str[publ->scope]);
                }
 
                publ = publ->zone_list_next;
@@ -951,24 +942,19 @@ static void nameseq_list(struct name_seq *seq, struct print_buf *buf, u32 depth,
 
 static void nametbl_header(struct print_buf *buf, u32 depth)
 {
-       tipc_printf(buf, "Type       ");
-
-       if (depth > 1)
-               tipc_printf(buf, "Lower      Upper      ");
-       if (depth > 2)
-               tipc_printf(buf, "Port Identity              ");
-       if (depth > 3)
-               tipc_printf(buf, "Publication");
-
-       tipc_printf(buf, "\n-----------");
-
-       if (depth > 1)
-               tipc_printf(buf, "--------------------- ");
-       if (depth > 2)
-               tipc_printf(buf, "-------------------------- ");
-       if (depth > 3)
-               tipc_printf(buf, "------------------");
-
+       const char *header[] = {
+               "Type       ",
+               "Lower      Upper      ",
+               "Port Identity              ",
+               "Publication Scope"
+       };
+
+       int i;
+
+       if (depth > 4)
+               depth = 4;
+       for (i = 0; i < depth; i++)
+               tipc_printf(buf, header[i]);
        tipc_printf(buf, "\n");
 }
 
index f61b7694138b5f7c0a208cfd2ce883d7a6c88d4b..7e05af47a1961be3b0c8f1d3f3383143741279a7 100644 (file)
@@ -248,6 +248,7 @@ void tipc_net_route_msg(struct sk_buff *buf)
 
        /* Handle message for another node */
        msg_dbg(msg, "NET>SEND>: ");
+       skb_trim(buf, msg_size(msg));
        tipc_link_send(buf, dnode, msg_link_selector(msg));
 }
 
index b634942caba5d5ed9204269c327b9fa6fef4512f..b702c7bf580f8d9a2a780d2a24c6cc8c46a630bb 100644 (file)
@@ -237,8 +237,7 @@ void tipc_node_link_down(struct tipc_node *n_ptr, struct link *l_ptr)
 
 int tipc_node_has_active_links(struct tipc_node *n_ptr)
 {
-       return (n_ptr &&
-               ((n_ptr->active_links[0]) || (n_ptr->active_links[1])));
+       return n_ptr->active_links[0] != NULL;
 }
 
 int tipc_node_has_redundant_links(struct tipc_node *n_ptr)
@@ -384,6 +383,20 @@ static void node_established_contact(struct tipc_node *n_ptr)
                                  tipc_highest_allowed_slave);
 }
 
+static void node_cleanup_finished(unsigned long node_addr)
+{
+       struct tipc_node *n_ptr;
+
+       read_lock_bh(&tipc_net_lock);
+       n_ptr = tipc_node_find(node_addr);
+       if (n_ptr) {
+               tipc_node_lock(n_ptr);
+               n_ptr->cleanup_required = 0;
+               tipc_node_unlock(n_ptr);
+       }
+       read_unlock_bh(&tipc_net_lock);
+}
+
 static void node_lost_contact(struct tipc_node *n_ptr)
 {
        struct cluster *c_ptr;
@@ -458,6 +471,11 @@ static void node_lost_contact(struct tipc_node *n_ptr)
                tipc_k_signal((Handler)ns->handle_node_down,
                              (unsigned long)ns->usr_handle);
        }
+
+       /* Prevent re-contact with node until all cleanup is done */
+
+       n_ptr->cleanup_required = 1;
+       tipc_k_signal((Handler)node_cleanup_finished, n_ptr->addr);
 }
 
 /**
index 6f990da5d143cb30b63a87576c21f483186fbbc6..45f3db3a595d0d9b7fd7f5cb14a84a5df73613e3 100644 (file)
@@ -52,6 +52,7 @@
  * @active_links: pointers to active links to node
  * @links: pointers to all links to node
  * @working_links: number of working links to node (both active and standby)
+ * @cleanup_required: non-zero if cleaning up after a prior loss of contact
  * @link_cnt: number of links to node
  * @permit_changeover: non-zero if node has redundant links to this system
  * @routers: bitmap (used for multicluster communication)
@@ -78,6 +79,7 @@ struct tipc_node {
        struct link *links[MAX_BEARERS];
        int link_cnt;
        int working_links;
+       int cleanup_required;
        int permit_changeover;
        u32 routers[512/32];
        int last_router;
index 0737680e9266021f528f5addec9ff0acefbec406..d760336f2ca815cb8ef8dcf35ef0bc8ec56898bd 100644 (file)
@@ -588,19 +588,10 @@ void tipc_port_recv_proto_msg(struct sk_buff *buf)
        if (!p_ptr) {
                err = TIPC_ERR_NO_PORT;
        } else if (p_ptr->publ.connected) {
-               if (port_peernode(p_ptr) != msg_orignode(msg))
+               if ((port_peernode(p_ptr) != msg_orignode(msg)) ||
+                   (port_peerport(p_ptr) != msg_origport(msg))) {
                        err = TIPC_ERR_NO_PORT;
-               if (port_peerport(p_ptr) != msg_origport(msg))
-                       err = TIPC_ERR_NO_PORT;
-               if (!err && msg_routed(msg)) {
-                       u32 seqno = msg_transp_seqno(msg);
-                       u32 myno =  ++p_ptr->last_in_seqno;
-                       if (seqno != myno) {
-                               err = TIPC_ERR_NO_PORT;
-                               abort_buf = port_build_self_abort_msg(p_ptr, err);
-                       }
-               }
-               if (msg_type(msg) == CONN_ACK) {
+               } else if (msg_type(msg) == CONN_ACK) {
                        int wakeup = tipc_port_congested(p_ptr) &&
                                     p_ptr->publ.congested &&
                                     p_ptr->wakeup;
@@ -1473,7 +1464,7 @@ int tipc_forward2name(u32 ref,
        msg_set_destnode(msg, destnode);
        msg_set_destport(msg, destport);
 
-       if (likely(destport || destnode)) {
+       if (likely(destport)) {
                p_ptr->sent++;
                if (likely(destnode == tipc_own_addr))
                        return tipc_port_recv_sections(p_ptr, num_sect, msg_sect);
@@ -1551,7 +1542,7 @@ int tipc_forward_buf2name(u32 ref,
        skb_push(buf, LONG_H_SIZE);
        skb_copy_to_linear_data(buf, msg, LONG_H_SIZE);
        msg_dbg(buf_msg(buf),"PREP:");
-       if (likely(destport || destnode)) {
+       if (likely(destport)) {
                p_ptr->sent++;
                if (destnode == tipc_own_addr)
                        return tipc_port_recv_msg(buf);
index 66e889ba48fd4d61088bd6e3f5e0721d7348d20b..f7ac94de24fefc0e78298310a991185c1bca7217 100644 (file)
@@ -64,6 +64,7 @@ struct tipc_sock {
        struct sock sk;
        struct tipc_port *p;
        struct tipc_portid peer_name;
+       long conn_timeout;
 };
 
 #define tipc_sk(sk) ((struct tipc_sock *)(sk))
@@ -240,9 +241,9 @@ static int tipc_create(struct net *net, struct socket *sock, int protocol,
        sock->state = state;
 
        sock_init_data(sock, sk);
-       sk->sk_rcvtimeo = msecs_to_jiffies(CONN_TIMEOUT_DEFAULT);
        sk->sk_backlog_rcv = backlog_rcv;
        tipc_sk(sk)->p = tp_ptr;
+       tipc_sk(sk)->conn_timeout = msecs_to_jiffies(CONN_TIMEOUT_DEFAULT);
 
        spin_unlock_bh(tp_ptr->lock);
 
@@ -429,36 +430,55 @@ static int get_name(struct socket *sock, struct sockaddr *uaddr,
  * to handle any preventable race conditions, so TIPC will do the same ...
  *
  * TIPC sets the returned events as follows:
- * a) POLLRDNORM and POLLIN are set if the socket's receive queue is non-empty
- *    or if a connection-oriented socket is does not have an active connection
- *    (i.e. a read operation will not block).
- * b) POLLOUT is set except when a socket's connection has been terminated
- *    (i.e. a write operation will not block).
- * c) POLLHUP is set when a socket's connection has been terminated.
- *
- * IMPORTANT: The fact that a read or write operation will not block does NOT
- * imply that the operation will succeed!
+ *
+ * socket state                flags set
+ * ------------                ---------
+ * unconnected         no read flags
+ *                     no write flags
+ *
+ * connecting          POLLIN/POLLRDNORM if ACK/NACK in rx queue
+ *                     no write flags
+ *
+ * connected           POLLIN/POLLRDNORM if data in rx queue
+ *                     POLLOUT if port is not congested
+ *
+ * disconnecting       POLLIN/POLLRDNORM/POLLHUP
+ *                     no write flags
+ *
+ * listening           POLLIN if SYN in rx queue
+ *                     no write flags
+ *
+ * ready               POLLIN/POLLRDNORM if data in rx queue
+ * [connectionless]    POLLOUT (since port cannot be congested)
+ *
+ * IMPORTANT: The fact that a read or write operation is indicated does NOT
+ * imply that the operation will succeed, merely that it should be performed
+ * and will not block.
  */
 
 static unsigned int poll(struct file *file, struct socket *sock,
                         poll_table *wait)
 {
        struct sock *sk = sock->sk;
-       u32 mask;
+       u32 mask = 0;
 
        poll_wait(file, sk_sleep(sk), wait);
 
-       if (!skb_queue_empty(&sk->sk_receive_queue) ||
-           (sock->state == SS_UNCONNECTED) ||
-           (sock->state == SS_DISCONNECTING))
-               mask = (POLLRDNORM | POLLIN);
-       else
-               mask = 0;
-
-       if (sock->state == SS_DISCONNECTING)
-               mask |= POLLHUP;
-       else
-               mask |= POLLOUT;
+       switch ((int)sock->state) {
+       case SS_READY:
+       case SS_CONNECTED:
+               if (!tipc_sk_port(sk)->congested)
+                       mask |= POLLOUT;
+               /* fall thru' */
+       case SS_CONNECTING:
+       case SS_LISTENING:
+               if (!skb_queue_empty(&sk->sk_receive_queue))
+                       mask |= (POLLIN | POLLRDNORM);
+               break;
+       case SS_DISCONNECTING:
+               mask = (POLLIN | POLLRDNORM | POLLHUP);
+               break;
+       }
 
        return mask;
 }
@@ -1026,9 +1046,8 @@ static int recv_stream(struct kiocb *iocb, struct socket *sock,
        struct sk_buff *buf;
        struct tipc_msg *msg;
        unsigned int sz;
-       int sz_to_copy;
+       int sz_to_copy, target, needed;
        int sz_copied = 0;
-       int needed;
        char __user *crs = m->msg_iov->iov_base;
        unsigned char *buf_crs;
        u32 err;
@@ -1050,6 +1069,8 @@ static int recv_stream(struct kiocb *iocb, struct socket *sock,
                goto exit;
        }
 
+       target = sock_rcvlowat(sk, flags & MSG_WAITALL, buf_len);
+
 restart:
 
        /* Look for a message in receive queue; wait if necessary */
@@ -1138,7 +1159,7 @@ restart:
 
        if ((sz_copied < buf_len) &&    /* didn't get all requested data */
            (!skb_queue_empty(&sk->sk_receive_queue) ||
-            (flags & MSG_WAITALL)) &&  /* and more is ready or required */
+           (sz_copied < target)) &&    /* and more is ready or required */
            (!(flags & MSG_PEEK)) &&    /* and aren't just peeking at data */
            (!err))                     /* and haven't reached a FIN */
                goto restart;
@@ -1365,6 +1386,7 @@ static int connect(struct socket *sock, struct sockaddr *dest, int destlen,
        struct msghdr m = {NULL,};
        struct sk_buff *buf;
        struct tipc_msg *msg;
+       long timeout;
        int res;
 
        lock_sock(sk);
@@ -1379,7 +1401,7 @@ static int connect(struct socket *sock, struct sockaddr *dest, int destlen,
        /* For now, TIPC does not support the non-blocking form of connect() */
 
        if (flags & O_NONBLOCK) {
-               res = -EWOULDBLOCK;
+               res = -EOPNOTSUPP;
                goto exit;
        }
 
@@ -1425,11 +1447,12 @@ static int connect(struct socket *sock, struct sockaddr *dest, int destlen,
 
        /* Wait until an 'ACK' or 'RST' arrives, or a timeout occurs */
 
+       timeout = tipc_sk(sk)->conn_timeout;
        release_sock(sk);
        res = wait_event_interruptible_timeout(*sk_sleep(sk),
                        (!skb_queue_empty(&sk->sk_receive_queue) ||
                        (sock->state != SS_CONNECTING)),
-                       sk->sk_rcvtimeo);
+                       timeout ? timeout : MAX_SCHEDULE_TIMEOUT);
        lock_sock(sk);
 
        if (res > 0) {
@@ -1692,7 +1715,7 @@ static int setsockopt(struct socket *sock,
                res = tipc_set_portunreturnable(tport->ref, value);
                break;
        case TIPC_CONN_TIMEOUT:
-               sk->sk_rcvtimeo = msecs_to_jiffies(value);
+               tipc_sk(sk)->conn_timeout = msecs_to_jiffies(value);
                /* no need to set "res", since already 0 at this point */
                break;
        default:
@@ -1747,7 +1770,7 @@ static int getsockopt(struct socket *sock,
                res = tipc_portunreturnable(tport->ref, &value);
                break;
        case TIPC_CONN_TIMEOUT:
-               value = jiffies_to_msecs(sk->sk_rcvtimeo);
+               value = jiffies_to_msecs(tipc_sk(sk)->conn_timeout);
                /* no need to set "res", since already 0 at this point */
                break;
         case TIPC_NODE_RECVQ_DEPTH:
index 0b39b2451ea59958c0819c51faf337d000cbb88d..c586da3f4f188f0b723cf43e77b431b292ab7b2e 100644 (file)
@@ -2033,11 +2033,10 @@ static unsigned int unix_poll(struct file *file, struct socket *sock, poll_table
        if (sk->sk_shutdown == SHUTDOWN_MASK)
                mask |= POLLHUP;
        if (sk->sk_shutdown & RCV_SHUTDOWN)
-               mask |= POLLRDHUP;
+               mask |= POLLRDHUP | POLLIN | POLLRDNORM;
 
        /* readable? */
-       if (!skb_queue_empty(&sk->sk_receive_queue) ||
-           (sk->sk_shutdown & RCV_SHUTDOWN))
+       if (!skb_queue_empty(&sk->sk_receive_queue))
                mask |= POLLIN | POLLRDNORM;
 
        /* Connection-based need to check for termination and startup */
index d6d046b9f6f2d7d85f8a10680cf662519838e877..d587ad284b3d847fb4e4eefe293f305500015f22 100644 (file)
@@ -253,11 +253,16 @@ int cfg80211_switch_netns(struct cfg80211_registered_device *rdev,
                        WARN_ON(err);
                        wdev->netdev->features |= NETIF_F_NETNS_LOCAL;
                }
+
+               return err;
        }
 
        wiphy_net_set(&rdev->wiphy, net);
 
-       return err;
+       err = device_rename(&rdev->wiphy.dev, dev_name(&rdev->wiphy.dev));
+       WARN_ON(err);
+
+       return 0;
 }
 
 static void cfg80211_rfkill_poll(struct rfkill *rfkill, void *data)
@@ -428,7 +433,7 @@ int wiphy_register(struct wiphy *wiphy)
 
        /* sanity check ifmodes */
        WARN_ON(!ifmodes);
-       ifmodes &= ((1 << __NL80211_IFTYPE_AFTER_LAST) - 1) & ~1;
+       ifmodes &= ((1 << NUM_NL80211_IFTYPES) - 1) & ~1;
        if (WARN_ON(ifmodes != wiphy->interface_modes))
                wiphy->interface_modes = ifmodes;
 
@@ -683,8 +688,8 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
                INIT_WORK(&wdev->cleanup_work, wdev_cleanup_work);
                INIT_LIST_HEAD(&wdev->event_list);
                spin_lock_init(&wdev->event_lock);
-               INIT_LIST_HEAD(&wdev->action_registrations);
-               spin_lock_init(&wdev->action_registrations_lock);
+               INIT_LIST_HEAD(&wdev->mgmt_registrations);
+               spin_lock_init(&wdev->mgmt_registrations_lock);
 
                mutex_lock(&rdev->devlist_mtx);
                list_add_rcu(&wdev->list, &rdev->netdev_list);
@@ -804,7 +809,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
                        sysfs_remove_link(&dev->dev.kobj, "phy80211");
                        list_del_rcu(&wdev->list);
                        rdev->devlist_generation++;
-                       cfg80211_mlme_purge_actions(wdev);
+                       cfg80211_mlme_purge_registrations(wdev);
 #ifdef CONFIG_CFG80211_WEXT
                        kfree(wdev->wext.keys);
 #endif
index 63d57ae399c3f9d73da4f2bf963867a6699af4c4..58ab2c791d287c58426458dea9d685ce49770a2f 100644 (file)
@@ -331,16 +331,17 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
                               const u8 *resp_ie, size_t resp_ie_len,
                               u16 status, bool wextev,
                               struct cfg80211_bss *bss);
-int cfg80211_mlme_register_action(struct wireless_dev *wdev, u32 snd_pid,
-                                 const u8 *match_data, int match_len);
-void cfg80211_mlme_unregister_actions(struct wireless_dev *wdev, u32 nlpid);
-void cfg80211_mlme_purge_actions(struct wireless_dev *wdev);
-int cfg80211_mlme_action(struct cfg80211_registered_device *rdev,
-                        struct net_device *dev,
-                        struct ieee80211_channel *chan,
-                        enum nl80211_channel_type channel_type,
-                        bool channel_type_valid,
-                        const u8 *buf, size_t len, u64 *cookie);
+int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_pid,
+                               u16 frame_type, const u8 *match_data,
+                               int match_len);
+void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlpid);
+void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev);
+int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
+                         struct net_device *dev,
+                         struct ieee80211_channel *chan,
+                         enum nl80211_channel_type channel_type,
+                         bool channel_type_valid,
+                         const u8 *buf, size_t len, u64 *cookie);
 
 /* SME */
 int __cfg80211_connect(struct cfg80211_registered_device *rdev,
index d1a3fb99fdf2caaa83e5b476dd3166c18f436161..8515b1e5c5781075897a769b46608f2fe89f4cd7 100644 (file)
@@ -149,7 +149,7 @@ void __cfg80211_send_deauth(struct net_device *dev,
        struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
        const u8 *bssid = mgmt->bssid;
        int i;
-       bool found = false;
+       bool found = false, was_current = false;
 
        ASSERT_WDEV_LOCK(wdev);
 
@@ -159,6 +159,7 @@ void __cfg80211_send_deauth(struct net_device *dev,
                cfg80211_put_bss(&wdev->current_bss->pub);
                wdev->current_bss = NULL;
                found = true;
+               was_current = true;
        } else for (i = 0; i < MAX_AUTH_BSSES; i++) {
                if (wdev->auth_bsses[i] &&
                    memcmp(wdev->auth_bsses[i]->pub.bssid, bssid, ETH_ALEN) == 0) {
@@ -183,7 +184,7 @@ void __cfg80211_send_deauth(struct net_device *dev,
 
        nl80211_send_deauth(rdev, dev, buf, len, GFP_KERNEL);
 
-       if (wdev->sme_state == CFG80211_SME_CONNECTED) {
+       if (wdev->sme_state == CFG80211_SME_CONNECTED && was_current) {
                u16 reason_code;
                bool from_ap;
 
@@ -747,31 +748,51 @@ void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr,
 }
 EXPORT_SYMBOL(cfg80211_new_sta);
 
-struct cfg80211_action_registration {
+struct cfg80211_mgmt_registration {
        struct list_head list;
 
        u32 nlpid;
 
        int match_len;
 
+       __le16 frame_type;
+
        u8 match[];
 };
 
-int cfg80211_mlme_register_action(struct wireless_dev *wdev, u32 snd_pid,
-                                 const u8 *match_data, int match_len)
+int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_pid,
+                               u16 frame_type, const u8 *match_data,
+                               int match_len)
 {
-       struct cfg80211_action_registration *reg, *nreg;
+       struct cfg80211_mgmt_registration *reg, *nreg;
        int err = 0;
+       u16 mgmt_type;
+
+       if (!wdev->wiphy->mgmt_stypes)
+               return -EOPNOTSUPP;
+
+       if ((frame_type & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT)
+               return -EINVAL;
+
+       if (frame_type & ~(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE))
+               return -EINVAL;
+
+       mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4;
+       if (!(wdev->wiphy->mgmt_stypes[wdev->iftype].rx & BIT(mgmt_type)))
+               return -EINVAL;
 
        nreg = kzalloc(sizeof(*reg) + match_len, GFP_KERNEL);
        if (!nreg)
                return -ENOMEM;
 
-       spin_lock_bh(&wdev->action_registrations_lock);
+       spin_lock_bh(&wdev->mgmt_registrations_lock);
 
-       list_for_each_entry(reg, &wdev->action_registrations, list) {
+       list_for_each_entry(reg, &wdev->mgmt_registrations, list) {
                int mlen = min(match_len, reg->match_len);
 
+               if (frame_type != le16_to_cpu(reg->frame_type))
+                       continue;
+
                if (memcmp(reg->match, match_data, mlen) == 0) {
                        err = -EALREADY;
                        break;
@@ -786,62 +807,75 @@ int cfg80211_mlme_register_action(struct wireless_dev *wdev, u32 snd_pid,
        memcpy(nreg->match, match_data, match_len);
        nreg->match_len = match_len;
        nreg->nlpid = snd_pid;
-       list_add(&nreg->list, &wdev->action_registrations);
+       nreg->frame_type = cpu_to_le16(frame_type);
+       list_add(&nreg->list, &wdev->mgmt_registrations);
 
  out:
-       spin_unlock_bh(&wdev->action_registrations_lock);
+       spin_unlock_bh(&wdev->mgmt_registrations_lock);
        return err;
 }
 
-void cfg80211_mlme_unregister_actions(struct wireless_dev *wdev, u32 nlpid)
+void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlpid)
 {
-       struct cfg80211_action_registration *reg, *tmp;
+       struct cfg80211_mgmt_registration *reg, *tmp;
 
-       spin_lock_bh(&wdev->action_registrations_lock);
+       spin_lock_bh(&wdev->mgmt_registrations_lock);
 
-       list_for_each_entry_safe(reg, tmp, &wdev->action_registrations, list) {
+       list_for_each_entry_safe(reg, tmp, &wdev->mgmt_registrations, list) {
                if (reg->nlpid == nlpid) {
                        list_del(&reg->list);
                        kfree(reg);
                }
        }
 
-       spin_unlock_bh(&wdev->action_registrations_lock);
+       spin_unlock_bh(&wdev->mgmt_registrations_lock);
 }
 
-void cfg80211_mlme_purge_actions(struct wireless_dev *wdev)
+void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev)
 {
-       struct cfg80211_action_registration *reg, *tmp;
+       struct cfg80211_mgmt_registration *reg, *tmp;
 
-       spin_lock_bh(&wdev->action_registrations_lock);
+       spin_lock_bh(&wdev->mgmt_registrations_lock);
 
-       list_for_each_entry_safe(reg, tmp, &wdev->action_registrations, list) {
+       list_for_each_entry_safe(reg, tmp, &wdev->mgmt_registrations, list) {
                list_del(&reg->list);
                kfree(reg);
        }
 
-       spin_unlock_bh(&wdev->action_registrations_lock);
+       spin_unlock_bh(&wdev->mgmt_registrations_lock);
 }
 
-int cfg80211_mlme_action(struct cfg80211_registered_device *rdev,
-                        struct net_device *dev,
-                        struct ieee80211_channel *chan,
-                        enum nl80211_channel_type channel_type,
-                        bool channel_type_valid,
-                        const u8 *buf, size_t len, u64 *cookie)
+int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
+                         struct net_device *dev,
+                         struct ieee80211_channel *chan,
+                         enum nl80211_channel_type channel_type,
+                         bool channel_type_valid,
+                         const u8 *buf, size_t len, u64 *cookie)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        const struct ieee80211_mgmt *mgmt;
+       u16 stype;
+
+       if (!wdev->wiphy->mgmt_stypes)
+               return -EOPNOTSUPP;
 
-       if (rdev->ops->action == NULL)
+       if (!rdev->ops->mgmt_tx)
                return -EOPNOTSUPP;
+
        if (len < 24 + 1)
                return -EINVAL;
 
        mgmt = (const struct ieee80211_mgmt *) buf;
-       if (!ieee80211_is_action(mgmt->frame_control))
+
+       if (!ieee80211_is_mgmt(mgmt->frame_control))
                return -EINVAL;
-       if (mgmt->u.action.category != WLAN_CATEGORY_PUBLIC) {
+
+       stype = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE;
+       if (!(wdev->wiphy->mgmt_stypes[wdev->iftype].tx & BIT(stype >> 4)))
+               return -EINVAL;
+
+       if (ieee80211_is_action(mgmt->frame_control) &&
+           mgmt->u.action.category != WLAN_CATEGORY_PUBLIC) {
                /* Verify that we are associated with the destination AP */
                wdev_lock(wdev);
 
@@ -862,64 +896,75 @@ int cfg80211_mlme_action(struct cfg80211_registered_device *rdev,
                return -EINVAL;
 
        /* Transmit the Action frame as requested by user space */
-       return rdev->ops->action(&rdev->wiphy, dev, chan, channel_type,
-                                channel_type_valid, buf, len, cookie);
+       return rdev->ops->mgmt_tx(&rdev->wiphy, dev, chan, channel_type,
+                                 channel_type_valid, buf, len, cookie);
 }
 
-bool cfg80211_rx_action(struct net_device *dev, int freq, const u8 *buf,
-                       size_t len, gfp_t gfp)
+bool cfg80211_rx_mgmt(struct net_device *dev, int freq, const u8 *buf,
+                     size_t len, gfp_t gfp)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct wiphy *wiphy = wdev->wiphy;
        struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
-       struct cfg80211_action_registration *reg;
-       const u8 *action_data;
-       int action_data_len;
+       struct cfg80211_mgmt_registration *reg;
+       const struct ieee80211_txrx_stypes *stypes =
+               &wiphy->mgmt_stypes[wdev->iftype];
+       struct ieee80211_mgmt *mgmt = (void *)buf;
+       const u8 *data;
+       int data_len;
        bool result = false;
+       __le16 ftype = mgmt->frame_control &
+               cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE);
+       u16 stype;
 
-       /* frame length - min size excluding category */
-       action_data_len = len - (IEEE80211_MIN_ACTION_SIZE - 1);
+       stype = (le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE) >> 4;
 
-       /* action data starts with category */
-       action_data = buf + IEEE80211_MIN_ACTION_SIZE - 1;
+       if (!(stypes->rx & BIT(stype)))
+               return false;
 
-       spin_lock_bh(&wdev->action_registrations_lock);
+       data = buf + ieee80211_hdrlen(mgmt->frame_control);
+       data_len = len - ieee80211_hdrlen(mgmt->frame_control);
+
+       spin_lock_bh(&wdev->mgmt_registrations_lock);
+
+       list_for_each_entry(reg, &wdev->mgmt_registrations, list) {
+               if (reg->frame_type != ftype)
+                       continue;
 
-       list_for_each_entry(reg, &wdev->action_registrations, list) {
-               if (reg->match_len > action_data_len)
+               if (reg->match_len > data_len)
                        continue;
 
-               if (memcmp(reg->match, action_data, reg->match_len))
+               if (memcmp(reg->match, data, reg->match_len))
                        continue;
 
                /* found match! */
 
                /* Indicate the received Action frame to user space */
-               if (nl80211_send_action(rdev, dev, reg->nlpid, freq,
-                                       buf, len, gfp))
+               if (nl80211_send_mgmt(rdev, dev, reg->nlpid, freq,
+                                     buf, len, gfp))
                        continue;
 
                result = true;
                break;
        }
 
-       spin_unlock_bh(&wdev->action_registrations_lock);
+       spin_unlock_bh(&wdev->mgmt_registrations_lock);
 
        return result;
 }
-EXPORT_SYMBOL(cfg80211_rx_action);
+EXPORT_SYMBOL(cfg80211_rx_mgmt);
 
-void cfg80211_action_tx_status(struct net_device *dev, u64 cookie,
-                              const u8 *buf, size_t len, bool ack, gfp_t gfp)
+void cfg80211_mgmt_tx_status(struct net_device *dev, u64 cookie,
+                            const u8 *buf, size_t len, bool ack, gfp_t gfp)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct wiphy *wiphy = wdev->wiphy;
        struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
 
        /* Indicate TX status of the Action frame to user space */
-       nl80211_send_action_tx_status(rdev, dev, cookie, buf, len, ack, gfp);
+       nl80211_send_mgmt_tx_status(rdev, dev, cookie, buf, len, ack, gfp);
 }
-EXPORT_SYMBOL(cfg80211_action_tx_status);
+EXPORT_SYMBOL(cfg80211_mgmt_tx_status);
 
 void cfg80211_cqm_rssi_notify(struct net_device *dev,
                              enum nl80211_cqm_rssi_threshold_event rssi_event,
index 37902a54e9c154fb8dbed3e1d996d8a198bdc17b..85a23de7bff346204c456519ca6a8692bfac7eb9 100644 (file)
@@ -136,6 +136,8 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
                .len = sizeof(struct nl80211_sta_flag_update),
        },
        [NL80211_ATTR_CONTROL_PORT] = { .type = NLA_FLAG },
+       [NL80211_ATTR_CONTROL_PORT_ETHERTYPE] = { .type = NLA_U16 },
+       [NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT] = { .type = NLA_FLAG },
        [NL80211_ATTR_PRIVACY] = { .type = NLA_FLAG },
        [NL80211_ATTR_CIPHER_SUITE_GROUP] = { .type = NLA_U32 },
        [NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 },
@@ -156,6 +158,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
 
        [NL80211_ATTR_WIPHY_TX_POWER_SETTING] = { .type = NLA_U32 },
        [NL80211_ATTR_WIPHY_TX_POWER_LEVEL] = { .type = NLA_U32 },
+       [NL80211_ATTR_FRAME_TYPE] = { .type = NLA_U16 },
 };
 
 /* policy for the attributes */
@@ -437,6 +440,8 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
        struct ieee80211_rate *rate;
        int i;
        u16 ifmodes = dev->wiphy.interface_modes;
+       const struct ieee80211_txrx_stypes *mgmt_stypes =
+                               dev->wiphy.mgmt_stypes;
 
        hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_WIPHY);
        if (!hdr)
@@ -471,6 +476,9 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
        NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_PMKIDS,
                   dev->wiphy.max_num_pmkids);
 
+       if (dev->wiphy.flags & WIPHY_FLAG_CONTROL_PORT_PROTOCOL)
+               NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE);
+
        nl_modes = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_IFTYPES);
        if (!nl_modes)
                goto nla_put_failure;
@@ -587,7 +595,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
        CMD(flush_pmksa, FLUSH_PMKSA);
        CMD(remain_on_channel, REMAIN_ON_CHANNEL);
        CMD(set_bitrate_mask, SET_TX_BITRATE_MASK);
-       CMD(action, ACTION);
+       CMD(mgmt_tx, FRAME);
        if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) {
                i++;
                NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS);
@@ -608,6 +616,55 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
 
        nla_nest_end(msg, nl_cmds);
 
+       if (mgmt_stypes) {
+               u16 stypes;
+               struct nlattr *nl_ftypes, *nl_ifs;
+               enum nl80211_iftype ift;
+
+               nl_ifs = nla_nest_start(msg, NL80211_ATTR_TX_FRAME_TYPES);
+               if (!nl_ifs)
+                       goto nla_put_failure;
+
+               for (ift = 0; ift < NUM_NL80211_IFTYPES; ift++) {
+                       nl_ftypes = nla_nest_start(msg, ift);
+                       if (!nl_ftypes)
+                               goto nla_put_failure;
+                       i = 0;
+                       stypes = mgmt_stypes[ift].tx;
+                       while (stypes) {
+                               if (stypes & 1)
+                                       NLA_PUT_U16(msg, NL80211_ATTR_FRAME_TYPE,
+                                                   (i << 4) | IEEE80211_FTYPE_MGMT);
+                               stypes >>= 1;
+                               i++;
+                       }
+                       nla_nest_end(msg, nl_ftypes);
+               }
+
+               nla_nest_end(msg, nl_ifs);
+
+               nl_ifs = nla_nest_start(msg, NL80211_ATTR_RX_FRAME_TYPES);
+               if (!nl_ifs)
+                       goto nla_put_failure;
+
+               for (ift = 0; ift < NUM_NL80211_IFTYPES; ift++) {
+                       nl_ftypes = nla_nest_start(msg, ift);
+                       if (!nl_ftypes)
+                               goto nla_put_failure;
+                       i = 0;
+                       stypes = mgmt_stypes[ift].rx;
+                       while (stypes) {
+                               if (stypes & 1)
+                                       NLA_PUT_U16(msg, NL80211_ATTR_FRAME_TYPE,
+                                                   (i << 4) | IEEE80211_FTYPE_MGMT);
+                               stypes >>= 1;
+                               i++;
+                       }
+                       nla_nest_end(msg, nl_ftypes);
+               }
+               nla_nest_end(msg, nl_ifs);
+       }
+
        return genlmsg_end(msg, hdr);
 
  nla_put_failure:
@@ -3572,6 +3629,21 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
        if (err)
                goto unlock_rtnl;
 
+       if (key.idx >= 0) {
+               int i;
+               bool ok = false;
+               for (i = 0; i < rdev->wiphy.n_cipher_suites; i++) {
+                       if (key.p.cipher == rdev->wiphy.cipher_suites[i]) {
+                               ok = true;
+                               break;
+                       }
+               }
+               if (!ok) {
+                       err = -EINVAL;
+                       goto out;
+               }
+       }
+
        if (!rdev->ops->auth) {
                err = -EOPNOTSUPP;
                goto out;
@@ -3624,7 +3696,8 @@ unlock_rtnl:
        return err;
 }
 
-static int nl80211_crypto_settings(struct genl_info *info,
+static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev,
+                                  struct genl_info *info,
                                   struct cfg80211_crypto_settings *settings,
                                   int cipher_limit)
 {
@@ -3632,6 +3705,19 @@ static int nl80211_crypto_settings(struct genl_info *info,
 
        settings->control_port = info->attrs[NL80211_ATTR_CONTROL_PORT];
 
+       if (info->attrs[NL80211_ATTR_CONTROL_PORT_ETHERTYPE]) {
+               u16 proto;
+               proto = nla_get_u16(
+                       info->attrs[NL80211_ATTR_CONTROL_PORT_ETHERTYPE]);
+               settings->control_port_ethertype = cpu_to_be16(proto);
+               if (!(rdev->wiphy.flags & WIPHY_FLAG_CONTROL_PORT_PROTOCOL) &&
+                   proto != ETH_P_PAE)
+                       return -EINVAL;
+               if (info->attrs[NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT])
+                       settings->control_port_no_encrypt = true;
+       } else
+               settings->control_port_ethertype = cpu_to_be16(ETH_P_PAE);
+
        if (info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]) {
                void *data;
                int len, i;
@@ -3759,7 +3845,7 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
        if (info->attrs[NL80211_ATTR_PREV_BSSID])
                prev_bssid = nla_data(info->attrs[NL80211_ATTR_PREV_BSSID]);
 
-       err = nl80211_crypto_settings(info, &crypto, 1);
+       err = nl80211_crypto_settings(rdev, info, &crypto, 1);
        if (!err)
                err = cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid,
                                          ssid, ssid_len, ie, ie_len, use_mfp,
@@ -4236,7 +4322,7 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
 
        connect.privacy = info->attrs[NL80211_ATTR_PRIVACY];
 
-       err = nl80211_crypto_settings(info, &connect.crypto,
+       err = nl80211_crypto_settings(rdev, info, &connect.crypto,
                                      NL80211_MAX_NR_CIPHER_SUITES);
        if (err)
                return err;
@@ -4717,17 +4803,18 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb,
        return err;
 }
 
-static int nl80211_register_action(struct sk_buff *skb, struct genl_info *info)
+static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info)
 {
        struct cfg80211_registered_device *rdev;
        struct net_device *dev;
+       u16 frame_type = IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION;
        int err;
 
        if (!info->attrs[NL80211_ATTR_FRAME_MATCH])
                return -EINVAL;
 
-       if (nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH]) < 1)
-               return -EINVAL;
+       if (info->attrs[NL80211_ATTR_FRAME_TYPE])
+               frame_type = nla_get_u16(info->attrs[NL80211_ATTR_FRAME_TYPE]);
 
        rtnl_lock();
 
@@ -4742,12 +4829,13 @@ static int nl80211_register_action(struct sk_buff *skb, struct genl_info *info)
        }
 
        /* not much point in registering if we can't reply */
-       if (!rdev->ops->action) {
+       if (!rdev->ops->mgmt_tx) {
                err = -EOPNOTSUPP;
                goto out;
        }
 
-       err = cfg80211_mlme_register_action(dev->ieee80211_ptr, info->snd_pid,
+       err = cfg80211_mlme_register_mgmt(dev->ieee80211_ptr, info->snd_pid,
+                       frame_type,
                        nla_data(info->attrs[NL80211_ATTR_FRAME_MATCH]),
                        nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH]));
  out:
@@ -4758,7 +4846,7 @@ static int nl80211_register_action(struct sk_buff *skb, struct genl_info *info)
        return err;
 }
 
-static int nl80211_action(struct sk_buff *skb, struct genl_info *info)
+static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
 {
        struct cfg80211_registered_device *rdev;
        struct net_device *dev;
@@ -4781,7 +4869,7 @@ static int nl80211_action(struct sk_buff *skb, struct genl_info *info)
        if (err)
                goto unlock_rtnl;
 
-       if (!rdev->ops->action) {
+       if (!rdev->ops->mgmt_tx) {
                err = -EOPNOTSUPP;
                goto out;
        }
@@ -4824,17 +4912,17 @@ static int nl80211_action(struct sk_buff *skb, struct genl_info *info)
        }
 
        hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
-                            NL80211_CMD_ACTION);
+                            NL80211_CMD_FRAME);
 
        if (IS_ERR(hdr)) {
                err = PTR_ERR(hdr);
                goto free_msg;
        }
-       err = cfg80211_mlme_action(rdev, dev, chan, channel_type,
-                                  channel_type_valid,
-                                  nla_data(info->attrs[NL80211_ATTR_FRAME]),
-                                  nla_len(info->attrs[NL80211_ATTR_FRAME]),
-                                  &cookie);
+       err = cfg80211_mlme_mgmt_tx(rdev, dev, chan, channel_type,
+                                   channel_type_valid,
+                                   nla_data(info->attrs[NL80211_ATTR_FRAME]),
+                                   nla_len(info->attrs[NL80211_ATTR_FRAME]),
+                                   &cookie);
        if (err)
                goto free_msg;
 
@@ -5333,14 +5421,14 @@ static struct genl_ops nl80211_ops[] = {
                .flags = GENL_ADMIN_PERM,
        },
        {
-               .cmd = NL80211_CMD_REGISTER_ACTION,
-               .doit = nl80211_register_action,
+               .cmd = NL80211_CMD_REGISTER_FRAME,
+               .doit = nl80211_register_mgmt,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
        },
        {
-               .cmd = NL80211_CMD_ACTION,
-               .doit = nl80211_action,
+               .cmd = NL80211_CMD_FRAME,
+               .doit = nl80211_tx_mgmt,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
        },
@@ -6040,9 +6128,9 @@ void nl80211_send_sta_event(struct cfg80211_registered_device *rdev,
                                nl80211_mlme_mcgrp.id, gfp);
 }
 
-int nl80211_send_action(struct cfg80211_registered_device *rdev,
-                       struct net_device *netdev, u32 nlpid,
-                       int freq, const u8 *buf, size_t len, gfp_t gfp)
+int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
+                     struct net_device *netdev, u32 nlpid,
+                     int freq, const u8 *buf, size_t len, gfp_t gfp)
 {
        struct sk_buff *msg;
        void *hdr;
@@ -6052,7 +6140,7 @@ int nl80211_send_action(struct cfg80211_registered_device *rdev,
        if (!msg)
                return -ENOMEM;
 
-       hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_ACTION);
+       hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME);
        if (!hdr) {
                nlmsg_free(msg);
                return -ENOMEM;
@@ -6080,10 +6168,10 @@ int nl80211_send_action(struct cfg80211_registered_device *rdev,
        return -ENOBUFS;
 }
 
-void nl80211_send_action_tx_status(struct cfg80211_registered_device *rdev,
-                                  struct net_device *netdev, u64 cookie,
-                                  const u8 *buf, size_t len, bool ack,
-                                  gfp_t gfp)
+void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev,
+                                struct net_device *netdev, u64 cookie,
+                                const u8 *buf, size_t len, bool ack,
+                                gfp_t gfp)
 {
        struct sk_buff *msg;
        void *hdr;
@@ -6092,7 +6180,7 @@ void nl80211_send_action_tx_status(struct cfg80211_registered_device *rdev,
        if (!msg)
                return;
 
-       hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_ACTION_TX_STATUS);
+       hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME_TX_STATUS);
        if (!hdr) {
                nlmsg_free(msg);
                return;
@@ -6179,7 +6267,7 @@ static int nl80211_netlink_notify(struct notifier_block * nb,
 
        list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list)
                list_for_each_entry_rcu(wdev, &rdev->netdev_list, list)
-                       cfg80211_mlme_unregister_actions(wdev, notify->pid);
+                       cfg80211_mlme_unregister_socket(wdev, notify->pid);
 
        rcu_read_unlock();
 
index 2ad7fbc7d9f1ad907d3ef7638cb3241c93c622d7..30d2f939150d78e3da6529e5e34f9685c96c4283 100644 (file)
@@ -74,13 +74,13 @@ void nl80211_send_sta_event(struct cfg80211_registered_device *rdev,
                            struct net_device *dev, const u8 *mac_addr,
                            struct station_info *sinfo, gfp_t gfp);
 
-int nl80211_send_action(struct cfg80211_registered_device *rdev,
-                       struct net_device *netdev, u32 nlpid, int freq,
-                       const u8 *buf, size_t len, gfp_t gfp);
-void nl80211_send_action_tx_status(struct cfg80211_registered_device *rdev,
-                                  struct net_device *netdev, u64 cookie,
-                                  const u8 *buf, size_t len, bool ack,
-                                  gfp_t gfp);
+int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
+                     struct net_device *netdev, u32 nlpid, int freq,
+                     const u8 *buf, size_t len, gfp_t gfp);
+void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev,
+                                struct net_device *netdev, u64 cookie,
+                                const u8 *buf, size_t len, bool ack,
+                                gfp_t gfp);
 
 void
 nl80211_send_cqm_rssi_notify(struct cfg80211_registered_device *rdev,
index f180db0de66cbc2163ce3dab641b46cb647226d2..b0d9a08447c9f7656b03ff6dfcb2971537a74b9d 100644 (file)
@@ -36,6 +36,7 @@
 #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>
 #include <net/cfg80211.h>
@@ -181,14 +182,6 @@ static bool is_alpha2_set(const char *alpha2)
        return false;
 }
 
-static bool is_alpha_upper(char letter)
-{
-       /* ASCII A - Z */
-       if (letter >= 65 && letter <= 90)
-               return true;
-       return false;
-}
-
 static bool is_unknown_alpha2(const char *alpha2)
 {
        if (!alpha2)
@@ -220,7 +213,7 @@ static bool is_an_alpha2(const char *alpha2)
 {
        if (!alpha2)
                return false;
-       if (is_alpha_upper(alpha2[0]) && is_alpha_upper(alpha2[1]))
+       if (isalpha(alpha2[0]) && isalpha(alpha2[1]))
                return true;
        return false;
 }
@@ -1399,6 +1392,11 @@ static DECLARE_WORK(reg_work, reg_todo);
 
 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]);
+
        spin_lock(&reg_requests_lock);
        list_add_tail(&request->list, &reg_requests_list);
        spin_unlock(&reg_requests_lock);
index 9f2cef3e0ca0cd21640127a27fd72edba88434a5..74a9e3cce45249a4ab21a909fa28806127409f7f 100644 (file)
@@ -110,6 +110,13 @@ static int wiphy_resume(struct device *dev)
        return ret;
 }
 
+static const void *wiphy_namespace(struct device *d)
+{
+       struct wiphy *wiphy = container_of(d, struct wiphy, dev);
+
+       return wiphy_net(wiphy);
+}
+
 struct class ieee80211_class = {
        .name = "ieee80211",
        .owner = THIS_MODULE,
@@ -120,6 +127,8 @@ struct class ieee80211_class = {
 #endif
        .suspend = wiphy_suspend,
        .resume = wiphy_resume,
+       .ns_type = &net_ns_type_operations,
+       .namespace = wiphy_namespace,
 };
 
 int wiphy_sysfs_init(void)
index 0c8a1e8b76903313ef0c413cc36261ec8af9399b..bca32eb8f446a90161c314e55042627953e84328 100644 (file)
@@ -183,7 +183,14 @@ int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
                        return -EINVAL;
                break;
        default:
-               return -EINVAL;
+               /*
+                * We don't know anything about this algorithm,
+                * allow using it -- but the driver must check
+                * all parameters! We still check below whether
+                * or not the driver supports this algorithm,
+                * of course.
+                */
+               break;
        }
 
        if (params->seq) {
@@ -221,7 +228,7 @@ const unsigned char bridge_tunnel_header[] __aligned(2) =
        { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 };
 EXPORT_SYMBOL(bridge_tunnel_header);
 
-unsigned int ieee80211_hdrlen(__le16 fc)
+unsigned int __attribute_const__ ieee80211_hdrlen(__le16 fc)
 {
        unsigned int hdrlen = 24;
 
@@ -823,7 +830,7 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
                        /* monitor can't bridge anyway */
                        break;
                case NL80211_IFTYPE_UNSPECIFIED:
-               case __NL80211_IFTYPE_AFTER_LAST:
+               case NUM_NL80211_IFTYPES:
                        /* not happening */
                        break;
                }
index 8f5116f5af19988555316eb5b97c7465a0890677..dc675a3daa3de94953fab7c388582b66a921fb85 100644 (file)
@@ -611,7 +611,7 @@ struct iw_statistics *get_wireless_stats(struct net_device *dev)
 #endif
 
 #ifdef CONFIG_CFG80211_WEXT
-       if (dev->ieee80211_ptr && dev->ieee80211_ptr &&
+       if (dev->ieee80211_ptr &&
            dev->ieee80211_ptr->wiphy &&
            dev->ieee80211_ptr->wiphy->wext &&
            dev->ieee80211_ptr->wiphy->wext->get_wireless_stats)
index 9818198add8a21444ba9183bbb8e4fc2c2199491..6fffe62d7c25b27cc9c6d6bc58635aa91f333e9f 100644 (file)
@@ -197,6 +197,8 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev,
        wdev->wext.connect.ssid_len = len;
 
        wdev->wext.connect.crypto.control_port = false;
+       wdev->wext.connect.crypto.control_port_ethertype =
+                                       cpu_to_be16(ETH_P_PAE);
 
        err = cfg80211_mgd_wext_connect(rdev, wdev);
  out: