]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
authorDavid S. Miller <davem@davemloft.net>
Thu, 4 Feb 2010 03:38:22 +0000 (19:38 -0800)
committerDavid S. Miller <davem@davemloft.net>
Thu, 4 Feb 2010 03:38:22 +0000 (19:38 -0800)
653 files changed:
Documentation/DocBook/mac80211.tmpl
Documentation/feature-removal-schedule.txt
Documentation/isdn/INTERFACE.CAPI
Documentation/networking/ip-sysctl.txt
Documentation/networking/ixgbevf.txt [new file with mode: 0755]
Documentation/networking/regulatory.txt
Documentation/powerpc/dts-bindings/fsl/can.txt [new file with mode: 0644]
Documentation/powerpc/dts-bindings/fsl/mpc5200.txt
MAINTAINERS
arch/ia64/kvm/Kconfig
arch/powerpc/boot/dts/mpc8569mds.dts
arch/powerpc/kvm/Kconfig
arch/powerpc/platforms/85xx/mpc85xx_mds.c
arch/s390/kvm/Kconfig
arch/x86/kvm/Kconfig
drivers/Makefile
drivers/atm/fore200e.c
drivers/atm/idt77252.c
drivers/atm/lanai.c
drivers/atm/nicstar.c
drivers/firmware/iscsi_ibft.c
drivers/infiniband/hw/cxgb3/iwch_cm.c
drivers/isdn/capi/capi.c
drivers/isdn/capi/capidrv.c
drivers/isdn/capi/kcapi.c
drivers/isdn/gigaset/capi.c
drivers/isdn/hardware/avm/avmcard.h
drivers/isdn/hardware/avm/b1.c
drivers/isdn/hardware/avm/b1dma.c
drivers/isdn/hardware/avm/b1isa.c
drivers/isdn/hardware/avm/b1pci.c
drivers/isdn/hardware/avm/b1pcmcia.c
drivers/isdn/hardware/avm/c4.c
drivers/isdn/hardware/avm/t1isa.c
drivers/isdn/hardware/avm/t1pci.c
drivers/isdn/hardware/eicon/capimain.c
drivers/isdn/hardware/eicon/diva_didd.c
drivers/isdn/hardware/eicon/divasi.c
drivers/isdn/hardware/eicon/divasproc.c
drivers/isdn/hysdn/hycapi.c
drivers/media/dvb/dvb-core/dvb_net.c
drivers/message/i2o/i2o_proc.c
drivers/misc/iwmc3200top/fw-download.c
drivers/misc/iwmc3200top/iwmc3200top.h
drivers/misc/iwmc3200top/log.h
drivers/misc/iwmc3200top/main.c
drivers/net/3c59x.c
drivers/net/8139cp.c
drivers/net/8139too.c
drivers/net/Kconfig
drivers/net/Makefile
drivers/net/acenic.c
drivers/net/amd8111e.c
drivers/net/arcnet/com20020-pci.c
drivers/net/ariadne.c
drivers/net/arm/ep93xx_eth.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/b44.c
drivers/net/benet/be_cmds.c
drivers/net/benet/be_cmds.h
drivers/net/benet/be_ethtool.c
drivers/net/bnx2.c
drivers/net/bnx2.h
drivers/net/bnx2x_main.c
drivers/net/bonding/bond_main.c
drivers/net/can/at91_can.c
drivers/net/can/bfin_can.c
drivers/net/can/dev.c
drivers/net/can/mcp251x.c
drivers/net/can/mscan/Kconfig
drivers/net/can/mscan/mpc5xxx_can.c
drivers/net/can/mscan/mscan.c
drivers/net/can/mscan/mscan.h
drivers/net/can/sja1000/Kconfig
drivers/net/can/sja1000/Makefile
drivers/net/can/sja1000/ems_pci.c
drivers/net/can/sja1000/kvaser_pci.c
drivers/net/can/sja1000/plx_pci.c [new file with mode: 0644]
drivers/net/can/sja1000/sja1000.c
drivers/net/can/ti_hecc.c
drivers/net/can/usb/ems_usb.c
drivers/net/can/vcan.c
drivers/net/cassini.c
drivers/net/chelsio/common.h
drivers/net/chelsio/subr.c
drivers/net/cxgb3/cxgb3_main.c
drivers/net/cxgb3/cxgb3_offload.c
drivers/net/cxgb3/sge.c
drivers/net/defxx.c
drivers/net/dl2k.h
drivers/net/e100.c
drivers/net/e1000/e1000_main.c
drivers/net/e1000e/82571.c
drivers/net/e1000e/defines.h
drivers/net/e1000e/e1000.h
drivers/net/e1000e/es2lan.c
drivers/net/e1000e/hw.h
drivers/net/e1000e/ich8lan.c
drivers/net/e1000e/lib.c
drivers/net/e1000e/netdev.c
drivers/net/enic/enic.h
drivers/net/enic/enic_main.c
drivers/net/enic/enic_res.c
drivers/net/enic/vnic_dev.c
drivers/net/enic/vnic_enet.h
drivers/net/enic/vnic_intr.c
drivers/net/enic/vnic_intr.h
drivers/net/enic/vnic_nic.h
drivers/net/epic100.c
drivers/net/ethoc.c
drivers/net/fealnx.c
drivers/net/forcedeth.c
drivers/net/hamachi.c
drivers/net/hp100.c
drivers/net/igb/igb_main.c
drivers/net/igbvf/netdev.c
drivers/net/ioc3-eth.c
drivers/net/ipg.c
drivers/net/irda/Kconfig
drivers/net/irda/Makefile
drivers/net/irda/donauboe.c
drivers/net/irda/sh_sir.c [new file with mode: 0644]
drivers/net/irda/via-ircc.c
drivers/net/irda/vlsi_ir.c
drivers/net/ixgb/ixgb_main.c
drivers/net/ixgbe/Makefile
drivers/net/ixgbe/ixgbe.h
drivers/net/ixgbe/ixgbe_82599.c
drivers/net/ixgbe/ixgbe_common.c
drivers/net/ixgbe/ixgbe_common.h
drivers/net/ixgbe/ixgbe_ethtool.c
drivers/net/ixgbe/ixgbe_main.c
drivers/net/ixgbe/ixgbe_mbx.c [new file with mode: 0644]
drivers/net/ixgbe/ixgbe_mbx.h [new file with mode: 0644]
drivers/net/ixgbe/ixgbe_sriov.c [new file with mode: 0644]
drivers/net/ixgbe/ixgbe_sriov.h [new file with mode: 0644]
drivers/net/ixgbe/ixgbe_type.h
drivers/net/ixgbevf/Makefile [new file with mode: 0644]
drivers/net/ixgbevf/defines.h [new file with mode: 0644]
drivers/net/ixgbevf/ethtool.c [new file with mode: 0644]
drivers/net/ixgbevf/ixgbevf.h [new file with mode: 0644]
drivers/net/ixgbevf/ixgbevf_main.c [new file with mode: 0644]
drivers/net/ixgbevf/mbx.c [new file with mode: 0644]
drivers/net/ixgbevf/mbx.h [new file with mode: 0644]
drivers/net/ixgbevf/regs.h [new file with mode: 0644]
drivers/net/ixgbevf/vf.c [new file with mode: 0644]
drivers/net/ixgbevf/vf.h [new file with mode: 0644]
drivers/net/jme.c
drivers/net/lib82596.c
drivers/net/mac8390.c
drivers/net/macvlan.c
drivers/net/meth.c
drivers/net/mlx4/main.c
drivers/net/mv643xx_eth.c
drivers/net/myri10ge/myri10ge.c
drivers/net/myri_sbus.c
drivers/net/natsemi.c
drivers/net/ne2k-pci.c
drivers/net/netxen/Makefile
drivers/net/netxen/netxen_nic.h
drivers/net/netxen/netxen_nic_ctx.c
drivers/net/netxen/netxen_nic_ethtool.c
drivers/net/netxen/netxen_nic_hdr.h
drivers/net/netxen/netxen_nic_hw.c
drivers/net/netxen/netxen_nic_hw.h
drivers/net/netxen/netxen_nic_init.c
drivers/net/netxen/netxen_nic_main.c
drivers/net/niu.c
drivers/net/ns83820.c
drivers/net/octeon/octeon_mgmt.c
drivers/net/pasemi_mac.c
drivers/net/pci-skeleton.c
drivers/net/pcmcia/axnet_cs.c
drivers/net/pcnet32.c
drivers/net/phy/marvell.c
drivers/net/phy/smsc.c
drivers/net/ppp_generic.c
drivers/net/qla3xxx.c
drivers/net/qlcnic/Makefile [new file with mode: 0644]
drivers/net/qlcnic/qlcnic.h [new file with mode: 0644]
drivers/net/qlcnic/qlcnic_ctx.c [new file with mode: 0644]
drivers/net/qlcnic/qlcnic_ethtool.c [new file with mode: 0644]
drivers/net/qlcnic/qlcnic_hdr.h [new file with mode: 0644]
drivers/net/qlcnic/qlcnic_hw.c [new file with mode: 0644]
drivers/net/qlcnic/qlcnic_init.c [new file with mode: 0644]
drivers/net/qlcnic/qlcnic_main.c [new file with mode: 0644]
drivers/net/qlge/qlge.h
drivers/net/qlge/qlge_dbg.c
drivers/net/qlge/qlge_main.c
drivers/net/qlge/qlge_mpi.c
drivers/net/r6040.c
drivers/net/r8169.c
drivers/net/rrunner.c
drivers/net/s2io.c
drivers/net/sc92031.c
drivers/net/sfc/efx.c
drivers/net/sfc/efx.h
drivers/net/sfc/ethtool.c
drivers/net/sfc/falcon.c
drivers/net/sfc/mcdi.c
drivers/net/sfc/mcdi.h
drivers/net/sfc/mcdi_pcol.h
drivers/net/sfc/mcdi_phy.c
drivers/net/sfc/mdio_10g.c
drivers/net/sfc/mdio_10g.h
drivers/net/sfc/net_driver.h
drivers/net/sfc/nic.c
drivers/net/sfc/qt202x_phy.c
drivers/net/sfc/selftest.c
drivers/net/sfc/selftest.h
drivers/net/sfc/siena.c
drivers/net/sfc/tenxpress.c
drivers/net/sh_eth.c
drivers/net/sis190.c
drivers/net/sis900.c
drivers/net/skfp/skfddi.c
drivers/net/skge.c
drivers/net/sky2.c
drivers/net/sky2.h
drivers/net/smc911x.c
drivers/net/smsc9420.c
drivers/net/spider_net.c
drivers/net/starfire.c
drivers/net/stmmac/Kconfig
drivers/net/stmmac/Makefile
drivers/net/stmmac/common.h
drivers/net/stmmac/descs.h
drivers/net/stmmac/dwmac100.c [moved from drivers/net/stmmac/mac100.c with 69% similarity]
drivers/net/stmmac/dwmac100.h [moved from drivers/net/stmmac/mac100.h with 100% similarity]
drivers/net/stmmac/dwmac1000.h [moved from drivers/net/stmmac/gmac.h with 95% similarity]
drivers/net/stmmac/dwmac1000_core.c [new file with mode: 0644]
drivers/net/stmmac/dwmac1000_dma.c [moved from drivers/net/stmmac/gmac.c with 54% similarity]
drivers/net/stmmac/dwmac_dma.h [new file with mode: 0644]
drivers/net/stmmac/dwmac_lib.c [new file with mode: 0644]
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/sundance.c
drivers/net/sungem.c
drivers/net/sunhme.c
drivers/net/sunvnet.c
drivers/net/tc35815.c
drivers/net/tehuti.c
drivers/net/tg3.c
drivers/net/tg3.h
drivers/net/tlan.c
drivers/net/tlan.h
drivers/net/tokenring/3c359.c
drivers/net/tokenring/abyss.c
drivers/net/tokenring/lanstreamer.c
drivers/net/tokenring/olympic.c
drivers/net/tokenring/tmspci.c
drivers/net/tulip/21142.c
drivers/net/tulip/de2104x.c
drivers/net/tulip/dmfe.c
drivers/net/tulip/eeprom.c
drivers/net/tulip/interrupt.c
drivers/net/tulip/media.c
drivers/net/tulip/pnic.c
drivers/net/tulip/pnic2.c
drivers/net/tulip/timer.c
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/tun.c
drivers/net/typhoon.c
drivers/net/ucc_geth.c
drivers/net/usb/catc.c
drivers/net/usb/mcs7830.c
drivers/net/usb/rtl8150.c
drivers/net/via-rhine.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/wan/dscc4.c
drivers/net/wan/farsync.c
drivers/net/wan/lmc/lmc_main.c
drivers/net/wan/pc300_drv.c
drivers/net/wan/pc300too.c
drivers/net/wan/pci200syn.c
drivers/net/wan/wanxl.c
drivers/net/wimax/i2400m/driver.c
drivers/net/wimax/i2400m/fw.c
drivers/net/wireless/adm8211.c
drivers/net/wireless/airo.c
drivers/net/wireless/at76c50x-usb.c
drivers/net/wireless/ath/ar9170/ar9170.h
drivers/net/wireless/ath/ar9170/hw.h
drivers/net/wireless/ath/ar9170/mac.c
drivers/net/wireless/ath/ar9170/main.c
drivers/net/wireless/ath/ar9170/usb.c
drivers/net/wireless/ath/ath5k/ath5k.h
drivers/net/wireless/ath/ath5k/base.c
drivers/net/wireless/ath/ath5k/pcu.c
drivers/net/wireless/ath/ath5k/qcu.c
drivers/net/wireless/ath/ath5k/reset.c
drivers/net/wireless/ath/ath9k/Makefile
drivers/net/wireless/ath/ath9k/ahb.c
drivers/net/wireless/ath/ath9k/ath9k.h
drivers/net/wireless/ath/ath9k/beacon.c
drivers/net/wireless/ath/ath9k/debug.c
drivers/net/wireless/ath/ath9k/debug.h
drivers/net/wireless/ath/ath9k/gpio.c [new file with mode: 0644]
drivers/net/wireless/ath/ath9k/hw.c
drivers/net/wireless/ath/ath9k/hw.h
drivers/net/wireless/ath/ath9k/init.c [new file with mode: 0644]
drivers/net/wireless/ath/ath9k/mac.h
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/pci.c
drivers/net/wireless/ath/ath9k/rc.h
drivers/net/wireless/ath/ath9k/recv.c
drivers/net/wireless/ath/ath9k/virtual.c
drivers/net/wireless/ath/ath9k/xmit.c
drivers/net/wireless/atmel_pci.c
drivers/net/wireless/b43/Kconfig
drivers/net/wireless/b43/Makefile
drivers/net/wireless/b43/b43.h
drivers/net/wireless/b43/dma.c
drivers/net/wireless/b43/main.c
drivers/net/wireless/b43/phy_lp.c
drivers/net/wireless/b43/phy_n.c
drivers/net/wireless/b43/phy_n.h
drivers/net/wireless/b43/pio.h
drivers/net/wireless/b43/tables_nphy.c
drivers/net/wireless/b43/tables_nphy.h
drivers/net/wireless/b43legacy/main.c
drivers/net/wireless/hostap/hostap_hw.c
drivers/net/wireless/hostap/hostap_pci.c
drivers/net/wireless/hostap/hostap_plx.c
drivers/net/wireless/ipw2x00/ipw2100.c
drivers/net/wireless/ipw2x00/ipw2200.c
drivers/net/wireless/iwlwifi/iwl-1000.c
drivers/net/wireless/iwlwifi/iwl-3945.c
drivers/net/wireless/iwlwifi/iwl-3945.h
drivers/net/wireless/iwlwifi/iwl-4965.c
drivers/net/wireless/iwlwifi/iwl-5000.c
drivers/net/wireless/iwlwifi/iwl-6000.c
drivers/net/wireless/iwlwifi/iwl-agn.c
drivers/net/wireless/iwlwifi/iwl-calib.c
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-debug.h
drivers/net/wireless/iwlwifi/iwl-debugfs.c
drivers/net/wireless/iwlwifi/iwl-dev.h
drivers/net/wireless/iwlwifi/iwl-devtrace.c
drivers/net/wireless/iwlwifi/iwl-devtrace.h
drivers/net/wireless/iwlwifi/iwl-hcmd.c
drivers/net/wireless/iwlwifi/iwl3945-base.c
drivers/net/wireless/iwmc3200wifi/iwm.h
drivers/net/wireless/iwmc3200wifi/rx.c
drivers/net/wireless/libertas/Kconfig
drivers/net/wireless/libertas/Makefile
drivers/net/wireless/libertas/assoc.c
drivers/net/wireless/libertas/cmd.c
drivers/net/wireless/libertas/cmd.h
drivers/net/wireless/libertas/cmdresp.c
drivers/net/wireless/libertas/defs.h
drivers/net/wireless/libertas/dev.h
drivers/net/wireless/libertas/ethtool.c
drivers/net/wireless/libertas/main.c
drivers/net/wireless/libertas/mesh.c
drivers/net/wireless/libertas/mesh.h
drivers/net/wireless/libertas/scan.c
drivers/net/wireless/libertas/tx.c
drivers/net/wireless/libertas/wext.c
drivers/net/wireless/libertas_tf/main.c
drivers/net/wireless/mac80211_hwsim.c
drivers/net/wireless/mwl8k.c
drivers/net/wireless/orinoco/orinoco_nortel.c
drivers/net/wireless/orinoco/orinoco_pci.c
drivers/net/wireless/orinoco/orinoco_plx.c
drivers/net/wireless/orinoco/orinoco_tmd.c
drivers/net/wireless/p54/main.c
drivers/net/wireless/p54/p54pci.c
drivers/net/wireless/prism54/islpci_hotplug.c
drivers/net/wireless/rndis_wlan.c
drivers/net/wireless/rt2x00/Kconfig
drivers/net/wireless/rt2x00/rt2400pci.c
drivers/net/wireless/rt2x00/rt2500pci.c
drivers/net/wireless/rt2x00/rt2500usb.c
drivers/net/wireless/rt2x00/rt2800lib.c
drivers/net/wireless/rt2x00/rt2800lib.h
drivers/net/wireless/rt2x00/rt2800pci.c
drivers/net/wireless/rt2x00/rt2800usb.c
drivers/net/wireless/rt2x00/rt2800usb.h
drivers/net/wireless/rt2x00/rt2x00.h
drivers/net/wireless/rt2x00/rt2x00dev.c
drivers/net/wireless/rt2x00/rt2x00mac.c
drivers/net/wireless/rt2x00/rt2x00pci.c
drivers/net/wireless/rt2x00/rt2x00queue.c
drivers/net/wireless/rt2x00/rt2x00queue.h
drivers/net/wireless/rt2x00/rt61pci.c
drivers/net/wireless/rt2x00/rt73usb.c
drivers/net/wireless/rtl818x/rtl8180.h
drivers/net/wireless/rtl818x/rtl8180_dev.c
drivers/net/wireless/rtl818x/rtl8187.h
drivers/net/wireless/rtl818x/rtl8187_dev.c
drivers/net/wireless/rtl818x/rtl8187_leds.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_cmd.c
drivers/net/wireless/wl12xx/wl1251_cmd.h
drivers/net/wireless/wl12xx/wl1251_debugfs.c
drivers/net/wireless/wl12xx/wl1251_init.c
drivers/net/wireless/wl12xx/wl1251_init.h
drivers/net/wireless/wl12xx/wl1251_main.c
drivers/net/wireless/wl12xx/wl1251_ps.c
drivers/net/wireless/wl12xx/wl1251_rx.c
drivers/net/wireless/wl12xx/wl1251_tx.c
drivers/net/wireless/wl12xx/wl1251_tx.h
drivers/net/wireless/wl12xx/wl1271.h
drivers/net/wireless/wl12xx/wl1271_acx.c
drivers/net/wireless/wl12xx/wl1271_acx.h
drivers/net/wireless/wl12xx/wl1271_boot.c
drivers/net/wireless/wl12xx/wl1271_cmd.c
drivers/net/wireless/wl12xx/wl1271_cmd.h
drivers/net/wireless/wl12xx/wl1271_conf.h
drivers/net/wireless/wl12xx/wl1271_debugfs.c
drivers/net/wireless/wl12xx/wl1271_event.c
drivers/net/wireless/wl12xx/wl1271_event.h
drivers/net/wireless/wl12xx/wl1271_init.c
drivers/net/wireless/wl12xx/wl1271_main.c
drivers/net/wireless/wl12xx/wl1271_ps.c
drivers/net/wireless/wl12xx/wl1271_reg.h
drivers/net/wireless/wl12xx/wl1271_spi.c
drivers/net/wireless/wl12xx/wl1271_tx.c
drivers/net/wireless/zd1211rw/zd_mac.c
drivers/net/wireless/zd1211rw/zd_usb.c
drivers/net/xilinx_emaclite.c
drivers/net/yellowfin.c
drivers/s390/net/qeth_core.h
drivers/s390/net/qeth_core_main.c
drivers/s390/net/qeth_core_mpc.h
drivers/s390/net/qeth_core_sys.c
drivers/s390/net/qeth_l2_main.c
drivers/s390/net/qeth_l3.h
drivers/s390/net/qeth_l3_main.c
drivers/s390/net/qeth_l3_sys.c
drivers/staging/rtl8187se/ieee80211/ieee80211.h
drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c
drivers/staging/rtl8187se/r8180_core.c
drivers/staging/wlags49_h2/wl_netdev.c
drivers/vhost/Kconfig [new file with mode: 0644]
drivers/vhost/Makefile [new file with mode: 0644]
drivers/vhost/net.c [new file with mode: 0644]
drivers/vhost/vhost.c [new file with mode: 0644]
drivers/vhost/vhost.h [new file with mode: 0644]
drivers/virtio/virtio_ring.c
include/linux/Kbuild
include/linux/can/dev.h
include/linux/can/netlink.h
include/linux/ieee80211.h
include/linux/if_tun.h
include/linux/igmp.h
include/linux/in.h
include/linux/inetdevice.h
include/linux/isdn/capilli.h
include/linux/llc.h
include/linux/miscdevice.h
include/linux/netdevice.h
include/linux/netpoll.h
include/linux/nl80211.h
include/linux/rtnetlink.h
include/linux/stmmac.h [new file with mode: 0644]
include/linux/sysctl.h
include/linux/vhost.h [new file with mode: 0644]
include/linux/virtio.h
include/net/cfg80211.h
include/net/dst.h
include/net/icmp.h
include/net/inet_sock.h
include/net/llc.h
include/net/llc_conn.h
include/net/mac80211.h
include/net/phonet/pep.h
include/net/pkt_sched.h
include/net/request_sock.h
include/net/sch_generic.h
include/net/snmp.h
include/net/tcp.h
include/net/xfrm.h
lib/vsprintf.c
mm/mmu_context.c
net/8021q/vlan.c
net/8021q/vlan_core.c
net/8021q/vlan_dev.c
net/8021q/vlanproc.c
net/atm/addr.c
net/atm/atm_misc.c
net/atm/atm_sysfs.c
net/atm/br2684.c
net/atm/clip.c
net/atm/common.c
net/atm/ioctl.c
net/atm/lec.c
net/atm/mpc.c
net/atm/mpoa_caches.c
net/atm/mpoa_proc.c
net/atm/pppoatm.c
net/atm/proc.c
net/atm/pvc.c
net/atm/raw.c
net/atm/resources.c
net/atm/signaling.c
net/atm/svc.c
net/bluetooth/cmtp/capi.c
net/bridge/br_if.c
net/can/af_can.c
net/can/af_can.h
net/can/proc.c
net/core/dev.c
net/core/fib_rules.c
net/core/neighbour.c
net/core/netpoll.c
net/core/rtnetlink.c
net/core/sock.c
net/dccp/ipv4.c
net/dccp/ipv6.c
net/ethernet/eth.c
net/ipv4/arp.c
net/ipv4/devinet.c
net/ipv4/fib_frontend.c
net/ipv4/fib_semantics.c
net/ipv4/icmp.c
net/ipv4/igmp.c
net/ipv4/inet_connection_sock.c
net/ipv4/ip_fragment.c
net/ipv4/ip_gre.c
net/ipv4/ip_sockglue.c
net/ipv4/ipcomp.c
net/ipv4/ipip.c
net/ipv4/proc.c
net/ipv4/route.c
net/ipv4/syncookies.c
net/ipv4/tcp.c
net/ipv4/tcp_ipv4.c
net/ipv4/tcp_output.c
net/ipv4/tcp_timer.c
net/ipv4/udp.c
net/ipv4/udplite.c
net/ipv6/addrconf.c
net/ipv6/af_inet6.c
net/ipv6/anycast.c
net/ipv6/fib6_rules.c
net/ipv6/icmp.c
net/ipv6/ip6_fib.c
net/ipv6/ip6_flowlabel.c
net/ipv6/ip6_tunnel.c
net/ipv6/ipcomp6.c
net/ipv6/mcast.c
net/ipv6/ndisc.c
net/ipv6/proc.c
net/ipv6/raw.c
net/ipv6/reassembly.c
net/ipv6/route.c
net/ipv6/sit.c
net/ipv6/syncookies.c
net/ipv6/sysctl_net_ipv6.c
net/ipv6/tcp_ipv6.c
net/ipv6/udp.c
net/ipv6/udplite.c
net/ipv6/xfrm6_tunnel.c
net/irda/ircomm/ircomm_tty.c
net/key/af_key.c
net/llc/af_llc.c
net/llc/llc_conn.c
net/llc/llc_core.c
net/llc/llc_output.c
net/llc/llc_proc.c
net/llc/llc_sap.c
net/mac80211/Kconfig
net/mac80211/Makefile
net/mac80211/agg-rx.c
net/mac80211/agg-tx.c
net/mac80211/cfg.c
net/mac80211/debugfs.c
net/mac80211/debugfs_key.c
net/mac80211/debugfs_netdev.c
net/mac80211/debugfs_netdev.h
net/mac80211/debugfs_sta.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/mesh.c
net/mac80211/mesh_hwmp.c
net/mac80211/mesh_pathtbl.c
net/mac80211/mesh_plink.c
net/mac80211/mlme.c
net/mac80211/offchannel.c [new file with mode: 0644]
net/mac80211/pm.c
net/mac80211/rate.c
net/mac80211/rate.h
net/mac80211/rx.c
net/mac80211/scan.c
net/mac80211/spectmgmt.c
net/mac80211/sta_info.c
net/mac80211/sta_info.h
net/mac80211/status.c
net/mac80211/tkip.c
net/mac80211/tx.c
net/mac80211/util.c
net/mac80211/wme.c
net/mac80211/work.c [new file with mode: 0644]
net/netlink/genetlink.c
net/packet/af_packet.c
net/phonet/datagram.c
net/phonet/pep-gprs.c
net/phonet/pep.c
net/phonet/pn_dev.c
net/sched/sch_api.c
net/sched/sch_fifo.c
net/sctp/proc.c
net/sctp/socket.c
net/sysctl_net.c
net/tipc/Kconfig
net/tipc/core.c
net/unix/af_unix.c
net/unix/sysctl_net_unix.c
net/wireless/.gitignore [new file with mode: 0644]
net/wireless/Kconfig
net/wireless/Makefile
net/wireless/chan.c
net/wireless/core.c
net/wireless/core.h
net/wireless/db.txt [new file with mode: 0644]
net/wireless/genregdb.awk [new file with mode: 0644]
net/wireless/mlme.c
net/wireless/nl80211.c
net/wireless/nl80211.h
net/wireless/reg.c
net/wireless/reg.h
net/wireless/regdb.h [new file with mode: 0644]
net/wireless/scan.c
net/wireless/sme.c
net/wireless/util.c
net/wireless/wext-compat.c
net/wireless/wext-proc.c
net/xfrm/xfrm_proc.c
net/xfrm/xfrm_sysctl.c

index f3f37f141dbdb4a00ab621e07a9c1fa361a1f782..971d1c0c83e5893ad2c54878542d6a93298e5cab 100644 (file)
@@ -144,7 +144,7 @@ usage should require reading the full document.
         this though and the recommendation to allow only a single
         interface in STA mode at first!
       </para>
-!Finclude/net/mac80211.h ieee80211_if_init_conf
+!Finclude/net/mac80211.h ieee80211_vif
     </chapter>
 
     <chapter id="rx-tx">
index 0a46833c1b764dfc4e983edfb55030e938e40948..2f93ac06c4144eda56c323965691be720e29687f 100644 (file)
@@ -88,27 +88,6 @@ Who: Luis R. Rodriguez <lrodriguez@atheros.com>
 
 ---------------------------
 
-What:  CONFIG_WIRELESS_OLD_REGULATORY - old static regulatory information
-When:  March 2010 / desktop catchup
-
-Why:   The old regulatory infrastructure has been replaced with a new one
-       which does not require statically defined regulatory domains. We do
-       not want to keep static regulatory domains in the kernel due to the
-       the dynamic nature of regulatory law and localization. We kept around
-       the old static definitions for the regulatory domains of:
-
-               * US
-               * JP
-               * EU
-
-       and used by default the US when CONFIG_WIRELESS_OLD_REGULATORY was
-       set. We will remove this option once the standard Linux desktop catches
-       up with the new userspace APIs we have implemented.
-
-Who:   Luis R. Rodriguez <lrodriguez@atheros.com>
-
----------------------------
-
 What:  dev->power.power_state
 When:  July 2007
 Why:   Broken design for runtime control over driver power states, confusing
index 5fe8de5cc7275f768b3c1106c5276f56ab35e256..f172091fb7cd4c592980a36272b2a61a4db71b7e 100644 (file)
@@ -149,10 +149,11 @@ char *(*procinfo)(struct capi_ctr *ctrlr)
        pointer to a callback function returning the entry for the device in
        the CAPI controller info table, /proc/capi/controller
 
-read_proc_t *ctr_read_proc
-       pointer to the read_proc callback function for the device's proc file
-       system entry, /proc/capi/controllers/<n>; will be called with a
-       pointer to the device's capi_ctr structure as the last (data) argument
+const struct file_operations *proc_fops
+       pointers to callback functions for the device's proc file
+       system entry, /proc/capi/controllers/<n>; pointer to the device's
+       capi_ctr structure is available from struct proc_dir_entry::data
+       which is available from struct inode.
 
 Note: Callback functions except send_message() are never called in interrupt
 context.
index 006b39dec87d66f88edc62f9547482f554a6519e..2dc7a1d9768638e05ca3495b077064dc772bb773 100644 (file)
@@ -692,6 +692,25 @@ proxy_arp - BOOLEAN
        conf/{all,interface}/proxy_arp is set to TRUE,
        it will be disabled otherwise
 
+proxy_arp_pvlan - BOOLEAN
+       Private VLAN proxy arp.
+       Basically allow proxy arp replies back to the same interface
+       (from which the ARP request/solicitation was received).
+
+       This is done to support (ethernet) switch features, like RFC
+       3069, where the individual ports are NOT allowed to
+       communicate with each other, but they are allowed to talk to
+       the upstream router.  As described in RFC 3069, it is possible
+       to allow these hosts to communicate through the upstream
+       router by proxy_arp'ing. Don't need to be used together with
+       proxy_arp.
+
+       This technology is known by different names:
+         In RFC 3069 it is called VLAN Aggregation.
+         Cisco and Allied Telesyn call it Private VLAN.
+         Hewlett-Packard call it Source-Port filtering or port-isolation.
+         Ericsson call it MAC-Forced Forwarding (RFC Draft).
+
 shared_media - BOOLEAN
        Send(router) or accept(host) RFC1620 shared media redirects.
        Overrides ip_secure_redirects.
@@ -833,9 +852,18 @@ arp_notify - BOOLEAN
            or hardware address changes.
 
 arp_accept - BOOLEAN
-       Define behavior when gratuitous arp replies are received:
-       0 - drop gratuitous arp frames
-       1 - accept gratuitous arp frames
+       Define behavior for gratuitous ARP frames who's IP is not
+       already present in the ARP table:
+       0 - don't create new entries in the ARP table
+       1 - create new entries in the ARP table
+
+       Both replies and requests type gratuitous arp will trigger the
+       ARP table to be updated, if this setting is on.
+
+       If the ARP table already contains the IP address of the
+       gratuitous arp frame, the arp table will be updated regardless
+       if this setting is on or off.
+
 
 app_solicit - INTEGER
        The maximum number of probes to send to the user space ARP daemon
diff --git a/Documentation/networking/ixgbevf.txt b/Documentation/networking/ixgbevf.txt
new file mode 100755 (executable)
index 0000000..19015de
--- /dev/null
@@ -0,0 +1,90 @@
+Linux* Base Driver for Intel(R) Network Connection
+==================================================
+
+November 24, 2009
+
+Contents
+========
+
+- In This Release
+- Identifying Your Adapter
+- Known Issues/Troubleshooting
+- Support
+
+In This Release
+===============
+
+This file describes the ixgbevf Linux* Base Driver for Intel Network
+Connection.
+
+The ixgbevf driver supports 82599-based virtual function devices that can only
+be activated on kernels with CONFIG_PCI_IOV enabled.
+
+The ixgbevf driver supports virtual functions generated by the ixgbe driver
+with a max_vfs value of 1 or greater.
+
+The guest OS loading the ixgbevf driver must support MSI-X interrupts.
+
+VLANs: There is a limit of a total of 32 shared VLANs to 1 or more VFs.
+
+Identifying Your Adapter
+========================
+
+For more information on how to identify your adapter, go to the Adapter &
+Driver ID Guide at:
+
+    http://support.intel.com/support/network/sb/CS-008441.htm
+
+Known Issues/Troubleshooting
+============================
+
+  Unloading Physical Function (PF) Driver Causes System Reboots When VM is
+  Running and VF is Loaded on the VM
+  ------------------------------------------------------------------------
+  Do not unload the PF driver (ixgbe) while VFs are assigned to guests.
+
+Support
+=======
+
+For general information, go to the Intel support website at:
+
+    http://support.intel.com
+
+or the Intel Wired Networking project hosted by Sourceforge at:
+
+    http://sourceforge.net/projects/e1000
+
+If an issue is identified with the released source code on the supported
+kernel with a supported adapter, email the specific information related
+to the issue to e1000-devel@lists.sf.net
+
+License
+=======
+
+Intel 10 Gigabit Linux driver.
+Copyright(c) 1999 - 2009 Intel Corporation.
+
+This program is free software; you can redistribute it and/or modify it
+under the terms and conditions of the GNU General Public License,
+version 2, as published by the Free Software Foundation.
+
+This program is distributed in the hope it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+The full GNU General Public License is included in this distribution in
+the file called "COPYING".
+
+Trademarks
+==========
+
+Intel, Itanium, and Pentium are trademarks or registered trademarks of
+Intel Corporation or its subsidiaries in the United States and other
+countries.
+
+* Other names and brands may be claimed as the property of others.
index ee31369e9e5baec8300136a1d2992be5a8bb2c97..9551622d0a7b845fe982076b3657ef59ef1ed6b7 100644 (file)
@@ -188,3 +188,27 @@ Then in some part of your code after your wiphy has been registered:
                       &mydriver_jp_regdom.reg_rules[i],
                       sizeof(struct ieee80211_reg_rule));
        regulatory_struct_hint(rd);
+
+Statically compiled regulatory database
+---------------------------------------
+
+In most situations the userland solution using CRDA as described
+above is the preferred solution.  However in some cases a set of
+rules built into the kernel itself may be desirable.  To account
+for this situation, a configuration option has been provided
+(i.e. CONFIG_CFG80211_INTERNAL_REGDB).  With this option enabled,
+the wireless database information contained in net/wireless/db.txt is
+used to generate a data structure encoded in net/wireless/regdb.c.
+That option also enables code in net/wireless/reg.c which queries
+the data in regdb.c as an alternative to using CRDA.
+
+The file net/wireless/db.txt should be kept up-to-date with the db.txt
+file available in the git repository here:
+
+    git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-regdb.git
+
+Again, most users in most situations should be using the CRDA package
+provided with their distribution, and in most other situations users
+should be building and using CRDA on their own rather than using
+this option.  If you are not absolutely sure that you should be using
+CONFIG_CFG80211_INTERNAL_REGDB then _DO_NOT_USE_IT_.
diff --git a/Documentation/powerpc/dts-bindings/fsl/can.txt b/Documentation/powerpc/dts-bindings/fsl/can.txt
new file mode 100644 (file)
index 0000000..2fa4fcd
--- /dev/null
@@ -0,0 +1,53 @@
+CAN Device Tree Bindings
+------------------------
+
+(c) 2006-2009 Secret Lab Technologies Ltd
+Grant Likely <grant.likely@secretlab.ca>
+
+fsl,mpc5200-mscan nodes
+-----------------------
+In addition to the required compatible-, reg- and interrupt-properties, you can
+also specify which clock source shall be used for the controller:
+
+- fsl,mscan-clock-source : a string describing the clock source. Valid values
+                          are: "ip" for ip bus clock
+                                "ref" for reference clock (XTAL)
+                          "ref" is default in case this property is not
+                          present.
+
+fsl,mpc5121-mscan nodes
+-----------------------
+In addition to the required compatible-, reg- and interrupt-properties, you can
+also specify which clock source and divider shall be used for the controller:
+
+- fsl,mscan-clock-source : a string describing the clock source. Valid values
+                          are: "ip" for ip bus clock
+                               "ref" for reference clock
+                               "sys" for system clock
+                          If this property is not present, an optimal CAN
+                          clock source and frequency based on the system
+                          clock will be selected. If this is not possible,
+                          the reference clock will be used.
+
+- fsl,mscan-clock-divider: for the reference and system clock, an additional
+                          clock divider can be specified. By default, a
+                          value of 1 is used.
+
+Note that the MPC5121 Rev. 1 processor is not supported.
+
+Examples:
+       can@1300 {
+               compatible = "fsl,mpc5121-mscan";
+               interrupts = <12 0x8>;
+               interrupt-parent = <&ipic>;
+               reg = <0x1300 0x80>;
+       };
+
+       can@1380 {
+               compatible = "fsl,mpc5121-mscan";
+               interrupts = <13 0x8>;
+               interrupt-parent = <&ipic>;
+               reg = <0x1380 0x80>;
+               fsl,mscan-clock-source = "ref";
+               fsl,mscan-clock-divider = <3>;
+       };
index 5c6602dbfdc22aae9cffc284b7303193616af2a7..4ccb2cd5df94a423a60acfdc0d5fcfb6d2cfdded 100644 (file)
@@ -195,11 +195,4 @@ External interrupts:
 
 fsl,mpc5200-mscan nodes
 -----------------------
-In addition to the required compatible-, reg- and interrupt-properites, you can
-also specify which clock source shall be used for the controller:
-
-- fsl,mscan-clock-source- a string describing the clock source. Valid values
-                         are:  "ip" for ip bus clock
-                               "ref" for reference clock (XTAL)
-                         "ref" is default in case this property is not
-                         present.
+See file can.txt in this directory.
index 03f38c18f3236718bf4bff40fa5ffaffce5bbcbe..f19e0989a5a200b7e5fa7656916d7fc820a35506 100644 (file)
@@ -4443,6 +4443,13 @@ S:       Supported
 F:     Documentation/networking/LICENSE.qla3xxx
 F:     drivers/net/qla3xxx.*
 
+QLOGIC QLCNIC (1/10)Gb ETHERNET DRIVER
+M:     Amit Kumar Salecha <amit.salecha@qlogic.com>
+M:     linux-driver@qlogic.com
+L:     netdev@vger.kernel.org
+S:     Supported
+F:     drivers/net/qlcnic/
+
 QLOGIC QLGE 10Gb ETHERNET DRIVER
 M:     Ron Mercer <ron.mercer@qlogic.com>
 M:     linux-driver@qlogic.com
@@ -5794,6 +5801,15 @@ S:       Maintained
 F:     Documentation/filesystems/vfat.txt
 F:     fs/fat/
 
+VIRTIO HOST (VHOST)
+M:     "Michael S. Tsirkin" <mst@redhat.com>
+L:     kvm@vger.kernel.org
+L:     virtualization@lists.osdl.org
+L:     netdev@vger.kernel.org
+S:     Maintained
+F:     drivers/vhost/
+F:     include/linux/vhost.h
+
 VIA RHINE NETWORK DRIVER
 M:     Roger Luethi <rl@hellgate.ch>
 S:     Maintained
index ef3e7be29caf6dd7b18f04afa21c3e5fdb43e753..01c75797119c568bd4d16919d3a122354a8b1a9c 100644 (file)
@@ -47,6 +47,7 @@ config KVM_INTEL
          Provides support for KVM on Itanium 2 processors equipped with the VT
          extensions.
 
+source drivers/vhost/Kconfig
 source drivers/virtio/Kconfig
 
 endif # VIRTUALIZATION
index 795eb362fcf920c2d1fa1528f53ce71faa566298..8b72eaff5b0329e56ffb27279076b6ef111724e4 100644 (file)
                        rx-clock-name = "none";
                        tx-clock-name = "clk12";
                        pio-handle = <&pio1>;
+                       tbi-handle = <&tbi1>;
                        phy-handle = <&qe_phy0>;
                        phy-connection-type = "rgmii-id";
                };
                                reg = <0x6>;
                                device_type = "ethernet-phy";
                        };
-                       tbi-phy@11 {
+                       tbi1: tbi-phy@11 {
                                reg = <0x11>;
                                device_type = "tbi-phy";
                        };
                        reg = <0x3520 0x18>;
                        compatible = "fsl,ucc-mdio";
 
-                       tbi0: tbi-phy@15 {
+                       tbi6: tbi-phy@15 {
                        reg = <0x15>;
                        device_type = "tbi-phy";
                        };
                        #size-cells = <0>;
                        reg = <0x3720 0x38>;
                        compatible = "fsl,ucc-mdio";
-                       tbi1: tbi-phy@17 {
+                       tbi8: tbi-phy@17 {
                                reg = <0x17>;
                                device_type = "tbi-phy";
                        };
                        rx-clock-name = "none";
                        tx-clock-name = "clk12";
                        pio-handle = <&pio3>;
+                       tbi-handle = <&tbi3>;
                        phy-handle = <&qe_phy2>;
                        phy-connection-type = "rgmii-id";
                };
 
+               mdio@2320 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0x2320 0x18>;
+                       compatible = "fsl,ucc-mdio";
+                       tbi3: tbi-phy@11 {
+                               reg = <0x11>;
+                               device_type = "tbi-phy";
+                       };
+               };
+
                enet1: ucc@3000 {
                        device_type = "network";
                        compatible = "ucc_geth";
                        rx-clock-name = "none";
                        tx-clock-name = "clk17";
                        pio-handle = <&pio2>;
+                       tbi-handle = <&tbi2>;
                        phy-handle = <&qe_phy1>;
                        phy-connection-type = "rgmii-id";
                };
 
+               mdio@3120 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0x3120 0x18>;
+                       compatible = "fsl,ucc-mdio";
+                       tbi2: tbi-phy@11 {
+                               reg = <0x11>;
+                               device_type = "tbi-phy";
+                       };
+               };
+
                enet3: ucc@3200 {
                        device_type = "network";
                        compatible = "ucc_geth";
                        rx-clock-name = "none";
                        tx-clock-name = "clk17";
                        pio-handle = <&pio4>;
+                       tbi-handle = <&tbi4>;
                        phy-handle = <&qe_phy3>;
                        phy-connection-type = "rgmii-id";
                };
 
+               mdio@3320 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0x3320 0x18>;
+                       compatible = "fsl,ucc-mdio";
+                       tbi4: tbi-phy@11 {
+                               reg = <0x11>;
+                               device_type = "tbi-phy";
+                       };
+               };
+
                enet5: ucc@3400 {
                        device_type = "network";
                        compatible = "ucc_geth";
                        local-mac-address = [ 00 00 00 00 00 00 ];
                        rx-clock-name = "none";
                        tx-clock-name = "none";
-                       tbi-handle = <&tbi0>;
+                       tbi-handle = <&tbi6>;
                        phy-handle = <&qe_phy5>;
                        phy-connection-type = "sgmii";
                };
                        local-mac-address = [ 00 00 00 00 00 00 ];
                        rx-clock-name = "none";
                        tx-clock-name = "none";
-                       tbi-handle = <&tbi1>;
+                       tbi-handle = <&tbi8>;
                        phy-handle = <&qe_phy7>;
                        phy-connection-type = "sgmii";
                };
index 07703f72330e1f0f468be6a0ce75d4b19a12daa8..e28841fbfb8dd90a51a93e54d1f6dbb289a3dce2 100644 (file)
@@ -75,6 +75,7 @@ config KVM_E500
 
          If unsure, say N.
 
+source drivers/vhost/Kconfig
 source drivers/virtio/Kconfig
 
 endif # VIRTUALIZATION
index 21f61b8c445b8863b0c22969c205983b21b2b6b7..04ed2156db1c34b637b7e567fcde9a158238b2c9 100644 (file)
@@ -237,6 +237,8 @@ static void __init mpc85xx_mds_setup_arch(void)
                } else if (machine_is(mpc8569_mds)) {
 #define BCSR7_UCC12_GETHnRST   (0x1 << 2)
 #define BCSR8_UEM_MARVELL_RST  (0x1 << 1)
+#define BCSR_UCC_RGMII         (0x1 << 6)
+#define BCSR_UCC_RTBI          (0x1 << 5)
                        /*
                         * U-Boot mangles interrupt polarity for Marvell PHYs,
                         * so reset built-in and UEM Marvell PHYs, this puts
@@ -247,6 +249,28 @@ static void __init mpc85xx_mds_setup_arch(void)
 
                        setbits8(&bcsr_regs[7], BCSR7_UCC12_GETHnRST);
                        clrbits8(&bcsr_regs[8], BCSR8_UEM_MARVELL_RST);
+
+                       for (np = NULL; (np = of_find_compatible_node(np,
+                                                       "network",
+                                                       "ucc_geth")) != NULL;) {
+                               const unsigned int *prop;
+                               int ucc_num;
+
+                               prop = of_get_property(np, "cell-index", NULL);
+                               if (prop == NULL)
+                                       continue;
+
+                               ucc_num = *prop - 1;
+
+                               prop = of_get_property(np, "phy-connection-type", NULL);
+                               if (prop == NULL)
+                                       continue;
+
+                               if (strcmp("rtbi", (const char *)prop) == 0)
+                                       clrsetbits_8(&bcsr_regs[7 + ucc_num],
+                                               BCSR_UCC_RGMII, BCSR_UCC_RTBI);
+                       }
+
                }
                iounmap(bcsr_regs);
        }
index 6ee55ae84ce2284f1bbb5c6120da55a8c0c42fc8..a7251580891cfef25483e683460d58f498eb65b6 100644 (file)
@@ -35,6 +35,7 @@ config KVM
 
 # OK, it's a little counter-intuitive to do this, but it puts it neatly under
 # the virtualization menu.
+source drivers/vhost/Kconfig
 source drivers/virtio/Kconfig
 
 endif # VIRTUALIZATION
index 4cd4983324668dea20618e6492d73f9a3f6f5b75..3c4d0109ad2051c71d9022c6d370a9ac47234cb0 100644 (file)
@@ -65,6 +65,7 @@ config KVM_AMD
 
 # OK, it's a little counter-intuitive to do this, but it puts it neatly under
 # the virtualization menu.
+source drivers/vhost/Kconfig
 source drivers/lguest/Kconfig
 source drivers/virtio/Kconfig
 
index 6ee53c7a57a1c5162265156bced43d6364c73237..81e36596b1e91fe4b7670c42cd6bd98070bd208a 100644 (file)
@@ -106,6 +106,7 @@ obj-$(CONFIG_HID)           += hid/
 obj-$(CONFIG_PPC_PS3)          += ps3/
 obj-$(CONFIG_OF)               += of/
 obj-$(CONFIG_SSB)              += ssb/
+obj-$(CONFIG_VHOST_NET)                += vhost/
 obj-$(CONFIG_VIRTIO)           += virtio/
 obj-$(CONFIG_VLYNQ)            += vlynq/
 obj-$(CONFIG_STAGING)          += staging/
index bc53fed89b1e5d5199b929c5ad36c76bf983c4ff..f7d6ebaa0418fd2d877bda38d66d2d0a27188f83 100644 (file)
@@ -2064,12 +2064,10 @@ fore200e_get_esi(struct fore200e* fore200e)
        return -EBUSY;
     }
        
-    printk(FORE200E "device %s, rev. %c, S/N: %d, ESI: %02x:%02x:%02x:%02x:%02x:%02x\n", 
+    printk(FORE200E "device %s, rev. %c, S/N: %d, ESI: %pM\n",
           fore200e->name, 
           (prom->hw_revision & 0xFF) + '@',    /* probably meaningless with SBA boards */
-          prom->serial_number & 0xFFFF,
-          prom->mac_addr[ 2 ], prom->mac_addr[ 3 ], prom->mac_addr[ 4 ],
-          prom->mac_addr[ 5 ], prom->mac_addr[ 6 ], prom->mac_addr[ 7 ]);
+          prom->serial_number & 0xFFFF, &prom->mac_addr[2]);
        
     for (i = 0; i < ESI_LEN; i++) {
        fore200e->esi[ i ] = fore200e->atm_dev->esi[ i ] = prom->mac_addr[ i + 2 ];
@@ -2845,13 +2843,12 @@ fore200e_proc_read(struct atm_dev *dev, loff_t* pos, char* page)
                "   interrupt line:\t\t%s\n"
                "   physical base address:\t0x%p\n"
                "   virtual base address:\t0x%p\n"
-               "   factory address (ESI):\t%02x:%02x:%02x:%02x:%02x:%02x\n"
+               "   factory address (ESI):\t%pM\n"
                "   board serial number:\t\t%d\n\n",
                fore200e_irq_itoa(fore200e->irq),
                (void*)fore200e->phys_base,
                fore200e->virt_base,
-               fore200e->esi[0], fore200e->esi[1], fore200e->esi[2],
-               fore200e->esi[3], fore200e->esi[4], fore200e->esi[5],
+               fore200e->esi,
                fore200e->esi[4] * 256 + fore200e->esi[5]);
 
        return len;
index e33ae0025b1214c45e0380e495d7e135dc4a59a5..01f36c08cb52cb7ac5a91d3c844c4feb3cc6114d 100644 (file)
@@ -3557,10 +3557,7 @@ init_card(struct atm_dev *dev)
        if (tmp) {
                memcpy(card->atmdev->esi, tmp->dev_addr, 6);
 
-               printk("%s: ESI %02x:%02x:%02x:%02x:%02x:%02x\n",
-                      card->name, card->atmdev->esi[0], card->atmdev->esi[1],
-                      card->atmdev->esi[2], card->atmdev->esi[3],
-                      card->atmdev->esi[4], card->atmdev->esi[5]);
+               printk("%s: ESI %pM\n", card->name, card->atmdev->esi);
        }
        /*
         * XXX: </hack>
index cf97c34cbaf142dfeb1c5df68f0c5121a4cf6b4b..7fe7c324e7ef5213fa5cd616024ed8d58a84f508 100644 (file)
@@ -998,9 +998,7 @@ static int __devinit eeprom_validate(struct lanai_dev *lanai)
                            (unsigned int) e[EEPROM_MAC_REV + i]);
                        return -EIO;
                }
-       DPRINTK("eeprom: MAC address = %02X:%02X:%02X:%02X:%02X:%02X\n",
-               e[EEPROM_MAC + 0], e[EEPROM_MAC + 1], e[EEPROM_MAC + 2],
-               e[EEPROM_MAC + 3], e[EEPROM_MAC + 4], e[EEPROM_MAC + 5]);
+       DPRINTK("eeprom: MAC address = %pM\n", &e[EEPROM_MAC]);
        /* Verify serial number */
        lanai->serialno = eeprom_be4(lanai, EEPROM_SERIAL);
        v = eeprom_be4(lanai, EEPROM_SERIAL_REV);
@@ -2483,14 +2481,8 @@ static int lanai_proc_read(struct atm_dev *atmdev, loff_t *pos, char *page)
                return sprintf(page, "revision: board=%d, pci_if=%d\n",
                    lanai->board_rev, (int) lanai->pci->revision);
        if (left-- == 0)
-               return sprintf(page, "EEPROM ESI: "
-                   "%02X:%02X:%02X:%02X:%02X:%02X\n",
-                   lanai->eeprom[EEPROM_MAC + 0],
-                   lanai->eeprom[EEPROM_MAC + 1],
-                   lanai->eeprom[EEPROM_MAC + 2],
-                   lanai->eeprom[EEPROM_MAC + 3],
-                   lanai->eeprom[EEPROM_MAC + 4],
-                   lanai->eeprom[EEPROM_MAC + 5]);
+               return sprintf(page, "EEPROM ESI: %pM\n",
+                   &lanai->eeprom[EEPROM_MAC]);
        if (left-- == 0)
                return sprintf(page, "status: SOOL=%d, LOCD=%d, LED=%d, "
                    "GPIN=%d\n", (lanai->status & STATUS_SOOL) ? 1 : 0,
index 3da804b1627d6b7e8578b381aae4b2c3f7c51be1..50838407b11792e61bbff23373e33ace90ab0a8d 100644 (file)
@@ -807,9 +807,7 @@ static int __devinit ns_init_card(int i, struct pci_dev *pcidev)
       }
    }
 
-   printk("nicstar%d: MAC address %02X:%02X:%02X:%02X:%02X:%02X\n", i,
-          card->atmdev->esi[0], card->atmdev->esi[1], card->atmdev->esi[2],
-          card->atmdev->esi[3], card->atmdev->esi[4], card->atmdev->esi[5]);
+   printk("nicstar%d: MAC address %pM\n", i, card->atmdev->esi);
 
    card->atmdev->dev_data = card;
    card->atmdev->ci_range.vpi_bits = card->vpibits;
index 051d1ebbd2876b68db9df2209161b13da7e8d7bb..5aeb3b541c804a04db0c696eefd3369b8215f444 100644 (file)
@@ -380,7 +380,6 @@ static ssize_t ibft_attr_show_nic(struct ibft_kobject *entry,
        struct ibft_nic *nic = entry->nic;
        void *ibft_loc = entry->header;
        char *str = buf;
-       char *mac;
        int val;
 
        if (!nic)
@@ -421,10 +420,7 @@ static ssize_t ibft_attr_show_nic(struct ibft_kobject *entry,
                str += sprintf(str, "%d\n", nic->vlan);
                break;
        case ibft_eth_mac:
-               mac = nic->mac;
-               str += sprintf(str, "%02x:%02x:%02x:%02x:%02x:%02x\n",
-                              (u8)mac[0], (u8)mac[1], (u8)mac[2],
-                              (u8)mac[3], (u8)mac[4], (u8)mac[5]);
+               str += sprintf(str, "%pM\n", nic->mac);
                break;
        case ibft_eth_hostname:
                str += sprintf_string(str, nic->hostname_len,
index 66b41351910ad390d5ec70dbb18c5ab99a196f45..d94388b81a4005b1e5d0dab5bdb780910c1d3665 100644 (file)
@@ -1371,15 +1371,8 @@ static int pass_accept_req(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
        tim.mac_addr = req->dst_mac;
        tim.vlan_tag = ntohs(req->vlan_tag);
        if (tdev->ctl(tdev, GET_IFF_FROM_MAC, &tim) < 0 || !tim.dev) {
-               printk(KERN_ERR
-                       "%s bad dst mac %02x %02x %02x %02x %02x %02x\n",
-                       __func__,
-                       req->dst_mac[0],
-                       req->dst_mac[1],
-                       req->dst_mac[2],
-                       req->dst_mac[3],
-                       req->dst_mac[4],
-                       req->dst_mac[5]);
+               printk(KERN_ERR "%s bad dst mac %pM\n",
+                       __func__, req->dst_mac);
                goto reject;
        }
 
index 65bf91e16a42725c7aeb5754fdb5954553fd73af..79f9364aded67f1f648b78ea57727d282fff11e3 100644 (file)
@@ -33,6 +33,7 @@
 #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
 #include <linux/skbuff.h>
 #include <linux/proc_fs.h>
+#include <linux/seq_file.h>
 #include <linux/poll.h>
 #include <linux/capi.h>
 #include <linux/kernelcapi.h>
@@ -1407,114 +1408,84 @@ static void capinc_tty_exit(void)
  * /proc/capi/capi20:
  *  minor applid nrecvctlpkt nrecvdatapkt nsendctlpkt nsenddatapkt
  */
-static int proc_capidev_read_proc(char *page, char **start, off_t off,
-                                       int count, int *eof, void *data)
+static int capi20_proc_show(struct seq_file *m, void *v)
 {
         struct capidev *cdev;
        struct list_head *l;
-       int len = 0;
 
        read_lock(&capidev_list_lock);
        list_for_each(l, &capidev_list) {
                cdev = list_entry(l, struct capidev, list);
-               len += sprintf(page+len, "0 %d %lu %lu %lu %lu\n",
+               seq_printf(m, "0 %d %lu %lu %lu %lu\n",
                        cdev->ap.applid,
                        cdev->ap.nrecvctlpkt,
                        cdev->ap.nrecvdatapkt,
                        cdev->ap.nsentctlpkt,
                        cdev->ap.nsentdatapkt);
-               if (len <= off) {
-                       off -= len;
-                       len = 0;
-               } else {
-                       if (len-off > count)
-                               goto endloop;
-               }
        }
-
-endloop:
        read_unlock(&capidev_list_lock);
-       if (len < count)
-               *eof = 1;
-       if (len > count) len = count;
-       if (len < 0) len = 0;
-       return len;
+       return 0;
 }
 
+static int capi20_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, capi20_proc_show, NULL);
+}
+
+static const struct file_operations capi20_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = capi20_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
 /*
  * /proc/capi/capi20ncci:
  *  applid ncci
  */
-static int proc_capincci_read_proc(char *page, char **start, off_t off,
-                                       int count, int *eof, void *data)
+static int capi20ncci_proc_show(struct seq_file *m, void *v)
 {
         struct capidev *cdev;
         struct capincci *np;
        struct list_head *l;
-       int len = 0;
 
        read_lock(&capidev_list_lock);
        list_for_each(l, &capidev_list) {
                cdev = list_entry(l, struct capidev, list);
                for (np=cdev->nccis; np; np = np->next) {
-                       len += sprintf(page+len, "%d 0x%x\n",
+                       seq_printf(m, "%d 0x%x\n",
                                       cdev->ap.applid,
                                       np->ncci);
-                       if (len <= off) {
-                               off -= len;
-                               len = 0;
-                       } else {
-                               if (len-off > count)
-                                       goto endloop;
-                       }
                }
        }
-endloop:
        read_unlock(&capidev_list_lock);
-       *start = page+off;
-       if (len < count)
-               *eof = 1;
-       if (len>count) len = count;
-       if (len<0) len = 0;
-       return len;
+       return 0;
 }
 
-static struct procfsentries {
-  char *name;
-  mode_t mode;
-  int (*read_proc)(char *page, char **start, off_t off,
-                                       int count, int *eof, void *data);
-  struct proc_dir_entry *procent;
-} procfsentries[] = {
-   /* { "capi",                  S_IFDIR, 0 }, */
-   { "capi/capi20",      0      , proc_capidev_read_proc },
-   { "capi/capi20ncci",   0     , proc_capincci_read_proc },
+static int capi20ncci_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, capi20ncci_proc_show, NULL);
+}
+
+static const struct file_operations capi20ncci_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = capi20ncci_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
 };
 
 static void __init proc_init(void)
 {
-    int nelem = ARRAY_SIZE(procfsentries);
-    int i;
-
-    for (i=0; i < nelem; i++) {
-        struct procfsentries *p = procfsentries + i;
-       p->procent = create_proc_entry(p->name, p->mode, NULL);
-       if (p->procent) p->procent->read_proc = p->read_proc;
-    }
+       proc_create("capi/capi20", 0, NULL, &capi20_proc_fops);
+       proc_create("capi/capi20ncci", 0, NULL, &capi20ncci_proc_fops);
 }
 
 static void __exit proc_exit(void)
 {
-    int nelem = ARRAY_SIZE(procfsentries);
-    int i;
-
-    for (i=nelem-1; i >= 0; i--) {
-        struct procfsentries *p = procfsentries + i;
-       if (p->procent) {
-          remove_proc_entry(p->name, NULL);
-          p->procent = NULL;
-       }
-    }
+       remove_proc_entry("capi/capi20", NULL);
+       remove_proc_entry("capi/capi20ncci", NULL);
 }
 
 /* -------- init function and module interface ---------------------- */
index 66b7d7a864748df9e3cede96d6a6f6d055fe3b75..bb450152fb74ef11789dedf1cb5156304a0d1b71 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/isdn.h>
 #include <linux/isdnif.h>
 #include <linux/proc_fs.h>
+#include <linux/seq_file.h>
 #include <linux/capi.h>
 #include <linux/kernelcapi.h>
 #include <linux/ctype.h>
@@ -2229,59 +2230,37 @@ static void lower_callback(unsigned int cmd, u32 contr, void *data)
  * /proc/capi/capidrv:
  * nrecvctlpkt nrecvdatapkt nsendctlpkt nsenddatapkt
  */
-static int proc_capidrv_read_proc(char *page, char **start, off_t off,
-                                       int count, int *eof, void *data)
+static int capidrv_proc_show(struct seq_file *m, void *v)
 {
-       int len = 0;
-
-       len += sprintf(page+len, "%lu %lu %lu %lu\n",
+       seq_printf(m, "%lu %lu %lu %lu\n",
                        global.ap.nrecvctlpkt,
                        global.ap.nrecvdatapkt,
                        global.ap.nsentctlpkt,
                        global.ap.nsentdatapkt);
-       if (off+count >= len)
-          *eof = 1;
-       if (len < off)
-           return 0;
-       *start = page + off;
-       return ((count < len-off) ? count : len-off);
+       return 0;
+}
+
+static int capidrv_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, capidrv_proc_show, NULL);
 }
 
-static struct procfsentries {
-  char *name;
-  mode_t mode;
-  int (*read_proc)(char *page, char **start, off_t off,
-                                       int count, int *eof, void *data);
-  struct proc_dir_entry *procent;
-} procfsentries[] = {
-   /* { "capi",                  S_IFDIR, 0 }, */
-   { "capi/capidrv",     0      , proc_capidrv_read_proc },
+static const struct file_operations capidrv_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = capidrv_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
 };
 
 static void __init proc_init(void)
 {
-    int nelem = ARRAY_SIZE(procfsentries);
-    int i;
-
-    for (i=0; i < nelem; i++) {
-        struct procfsentries *p = procfsentries + i;
-       p->procent = create_proc_entry(p->name, p->mode, NULL);
-       if (p->procent) p->procent->read_proc = p->read_proc;
-    }
+       proc_create("capi/capidrv", 0, NULL, &capidrv_proc_fops);
 }
 
 static void __exit proc_exit(void)
 {
-    int nelem = ARRAY_SIZE(procfsentries);
-    int i;
-
-    for (i=nelem-1; i >= 0; i--) {
-        struct procfsentries *p = procfsentries + i;
-       if (p->procent) {
-          remove_proc_entry(p->name, NULL);
-          p->procent = NULL;
-       }
-    }
+       remove_proc_entry("capi/capidrv", NULL);
 }
 
 static int __init capidrv_init(void)
index dc506ab99cac03c1d9ca42a8053a5a0d5ff1cf2b..b0bacf377c18b4b39e0d3be22254a31270a563dc 100644 (file)
@@ -490,13 +490,7 @@ attach_capi_ctr(struct capi_ctr *card)
        card->traceflag = showcapimsgs;
 
        sprintf(card->procfn, "capi/controllers/%d", card->cnr);
-       card->procent = create_proc_entry(card->procfn, 0, NULL);
-       if (card->procent) {
-          card->procent->read_proc = 
-               (int (*)(char *,char **,off_t,int,int *,void *))
-                       card->ctr_read_proc;
-          card->procent->data = card;
-       }
+       card->procent = proc_create_data(card->procfn, 0, NULL, card->proc_fops, card);
 
        ncards++;
        printk(KERN_NOTICE "kcapi: Controller [%03d]: %s attached\n",
index 3f5cd06af104f42c069e697d2f265e33a929c74a..6f0ae32906bfbe569850cd08b5a1b8f9b4ef9bd1 100644 (file)
@@ -13,6 +13,8 @@
 
 #include "gigaset.h"
 #include <linux/ctype.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
 #include <linux/isdn/capilli.h>
 #include <linux/isdn/capicmd.h>
 #include <linux/isdn/capiutil.h>
@@ -2106,35 +2108,22 @@ static char *gigaset_procinfo(struct capi_ctr *ctr)
        return ctr->name;       /* ToDo: more? */
 }
 
-/**
- * gigaset_ctr_read_proc() - build controller proc file entry
- * @page:      buffer of PAGE_SIZE bytes for receiving the entry.
- * @start:     unused.
- * @off:       unused.
- * @count:     unused.
- * @eof:       unused.
- * @ctr:       controller descriptor structure.
- *
- * Return value: length of generated entry
- */
-static int gigaset_ctr_read_proc(char *page, char **start, off_t off,
-                         int count, int *eof, struct capi_ctr *ctr)
+static int gigaset_proc_show(struct seq_file *m, void *v)
 {
+       struct capi_ctr *ctr = m->private;
        struct cardstate *cs = ctr->driverdata;
        char *s;
        int i;
-       int len = 0;
-       len += sprintf(page+len, "%-16s %s\n", "name", ctr->name);
-       len += sprintf(page+len, "%-16s %s %s\n", "dev",
+
+       seq_printf(m, "%-16s %s\n", "name", ctr->name);
+       seq_printf(m, "%-16s %s %s\n", "dev",
                        dev_driver_string(cs->dev), dev_name(cs->dev));
-       len += sprintf(page+len, "%-16s %d\n", "id", cs->myid);
+       seq_printf(m, "%-16s %d\n", "id", cs->myid);
        if (cs->gotfwver)
-               len += sprintf(page+len, "%-16s %d.%d.%d.%d\n", "firmware",
+               seq_printf(m, "%-16s %d.%d.%d.%d\n", "firmware",
                        cs->fwver[0], cs->fwver[1], cs->fwver[2], cs->fwver[3]);
-       len += sprintf(page+len, "%-16s %d\n", "channels",
-                       cs->channels);
-       len += sprintf(page+len, "%-16s %s\n", "onechannel",
-                       cs->onechannel ? "yes" : "no");
+       seq_printf(m, "%-16s %d\n", "channels", cs->channels);
+       seq_printf(m, "%-16s %s\n", "onechannel", cs->onechannel ? "yes" : "no");
 
        switch (cs->mode) {
        case M_UNKNOWN:
@@ -2152,7 +2141,7 @@ static int gigaset_ctr_read_proc(char *page, char **start, off_t off,
        default:
                s = "??";
        }
-       len += sprintf(page+len, "%-16s %s\n", "mode", s);
+       seq_printf(m, "%-16s %s\n", "mode", s);
 
        switch (cs->mstate) {
        case MS_UNINITIALIZED:
@@ -2176,25 +2165,21 @@ static int gigaset_ctr_read_proc(char *page, char **start, off_t off,
        default:
                s = "??";
        }
-       len += sprintf(page+len, "%-16s %s\n", "mstate", s);
+       seq_printf(m, "%-16s %s\n", "mstate", s);
 
-       len += sprintf(page+len, "%-16s %s\n", "running",
-                       cs->running ? "yes" : "no");
-       len += sprintf(page+len, "%-16s %s\n", "connected",
-                       cs->connected ? "yes" : "no");
-       len += sprintf(page+len, "%-16s %s\n", "isdn_up",
-                       cs->isdn_up ? "yes" : "no");
-       len += sprintf(page+len, "%-16s %s\n", "cidmode",
-                       cs->cidmode ? "yes" : "no");
+       seq_printf(m, "%-16s %s\n", "running", cs->running ? "yes" : "no");
+       seq_printf(m, "%-16s %s\n", "connected", cs->connected ? "yes" : "no");
+       seq_printf(m, "%-16s %s\n", "isdn_up", cs->isdn_up ? "yes" : "no");
+       seq_printf(m, "%-16s %s\n", "cidmode", cs->cidmode ? "yes" : "no");
 
        for (i = 0; i < cs->channels; i++) {
-               len += sprintf(page+len, "[%d]%-13s %d\n", i, "corrupted",
+               seq_printf(m, "[%d]%-13s %d\n", i, "corrupted",
                                cs->bcs[i].corrupted);
-               len += sprintf(page+len, "[%d]%-13s %d\n", i, "trans_down",
+               seq_printf(m, "[%d]%-13s %d\n", i, "trans_down",
                                cs->bcs[i].trans_down);
-               len += sprintf(page+len, "[%d]%-13s %d\n", i, "trans_up",
+               seq_printf(m, "[%d]%-13s %d\n", i, "trans_up",
                                cs->bcs[i].trans_up);
-               len += sprintf(page+len, "[%d]%-13s %d\n", i, "chstate",
+               seq_printf(m, "[%d]%-13s %d\n", i, "chstate",
                                cs->bcs[i].chstate);
                switch (cs->bcs[i].proto2) {
                case L2_BITSYNC:
@@ -2209,11 +2194,23 @@ static int gigaset_ctr_read_proc(char *page, char **start, off_t off,
                default:
                        s = "??";
                }
-               len += sprintf(page+len, "[%d]%-13s %s\n", i, "proto2", s);
+               seq_printf(m, "[%d]%-13s %s\n", i, "proto2", s);
        }
-       return len;
+       return 0;
 }
 
+static int gigaset_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, gigaset_proc_show, PDE(inode)->data);
+}
+
+static const struct file_operations gigaset_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = gigaset_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
 
 static struct capi_driver capi_driver_gigaset = {
        .name           = "gigaset",
@@ -2256,7 +2253,7 @@ int gigaset_isdn_register(struct cardstate *cs, const char *isdnid)
        iif->ctr.release_appl  = gigaset_release_appl;
        iif->ctr.send_message  = gigaset_send_message;
        iif->ctr.procinfo      = gigaset_procinfo;
-       iif->ctr.ctr_read_proc = gigaset_ctr_read_proc;
+       iif->ctr.proc_fops = &gigaset_proc_fops;
        INIT_LIST_HEAD(&iif->appls);
        skb_queue_head_init(&iif->sendqueue);
        atomic_set(&iif->sendqlen, 0);
index d964f07e4a566e3f60b13664e49784adc3f360c9..a70e8854461dfc63df09f67c16be8e1b1001d31b 100644 (file)
@@ -556,8 +556,7 @@ u16  b1_send_message(struct capi_ctr *ctrl, struct sk_buff *skb);
 void b1_parse_version(avmctrl_info *card);
 irqreturn_t b1_interrupt(int interrupt, void *devptr);
 
-int b1ctl_read_proc(char *page, char **start, off_t off,
-                       int count, int *eof, struct capi_ctr *ctrl);
+extern const struct file_operations b1ctl_proc_fops;
 
 avmcard_dmainfo *avmcard_dma_alloc(char *name, struct pci_dev *,
                                   long rsize, long ssize);
@@ -577,7 +576,6 @@ void b1dma_register_appl(struct capi_ctr *ctrl,
                                capi_register_params *rp);
 void b1dma_release_appl(struct capi_ctr *ctrl, u16 appl);
 u16  b1dma_send_message(struct capi_ctr *ctrl, struct sk_buff *skb);
-int b1dmactl_read_proc(char *page, char **start, off_t off,
-                       int count, int *eof, struct capi_ctr *ctrl);
+extern const struct file_operations b1dmactl_proc_fops;
 
 #endif /* _AVMCARD_H_ */
index a7c0083e78a7bc063e03505bc36ae2f5864ace44..c38fa0f4c7296ea451fd47ba892813c69762ae77 100644 (file)
@@ -12,6 +12,8 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
 #include <linux/skbuff.h>
 #include <linux/delay.h>
 #include <linux/mm.h>
@@ -634,18 +636,17 @@ irqreturn_t b1_interrupt(int interrupt, void *devptr)
 }
 
 /* ------------------------------------------------------------- */
-int b1ctl_read_proc(char *page, char **start, off_t off,
-                       int count, int *eof, struct capi_ctr *ctrl)
+static int b1ctl_proc_show(struct seq_file *m, void *v)
 {
+       struct capi_ctr *ctrl = m->private;
        avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
        avmcard *card = cinfo->card;
        u8 flag;
-       int len = 0;
        char *s;
 
-       len += sprintf(page+len, "%-16s %s\n", "name", card->name);
-       len += sprintf(page+len, "%-16s 0x%x\n", "io", card->port);
-       len += sprintf(page+len, "%-16s %d\n", "irq", card->irq);
+       seq_printf(m, "%-16s %s\n", "name", card->name);
+       seq_printf(m, "%-16s 0x%x\n", "io", card->port);
+       seq_printf(m, "%-16s %d\n", "irq", card->irq);
        switch (card->cardtype) {
        case avm_b1isa: s = "B1 ISA"; break;
        case avm_b1pci: s = "B1 PCI"; break;
@@ -658,20 +659,20 @@ int b1ctl_read_proc(char *page, char **start, off_t off,
        case avm_c2: s = "C2"; break;
        default: s = "???"; break;
        }
-       len += sprintf(page+len, "%-16s %s\n", "type", s);
+       seq_printf(m, "%-16s %s\n", "type", s);
        if (card->cardtype == avm_t1isa)
-          len += sprintf(page+len, "%-16s %d\n", "cardnr", card->cardnr);
+               seq_printf(m, "%-16s %d\n", "cardnr", card->cardnr);
        if ((s = cinfo->version[VER_DRIVER]) != NULL)
-          len += sprintf(page+len, "%-16s %s\n", "ver_driver", s);
+               seq_printf(m, "%-16s %s\n", "ver_driver", s);
        if ((s = cinfo->version[VER_CARDTYPE]) != NULL)
-          len += sprintf(page+len, "%-16s %s\n", "ver_cardtype", s);
+               seq_printf(m, "%-16s %s\n", "ver_cardtype", s);
        if ((s = cinfo->version[VER_SERIAL]) != NULL)
-          len += sprintf(page+len, "%-16s %s\n", "ver_serial", s);
+               seq_printf(m, "%-16s %s\n", "ver_serial", s);
 
        if (card->cardtype != avm_m1) {
                flag = ((u8 *)(ctrl->profile.manu))[3];
                if (flag)
-                       len += sprintf(page+len, "%-16s%s%s%s%s%s%s%s\n",
+                       seq_printf(m, "%-16s%s%s%s%s%s%s%s\n",
                        "protocol",
                        (flag & 0x01) ? " DSS1" : "",
                        (flag & 0x02) ? " CT1" : "",
@@ -685,7 +686,7 @@ int b1ctl_read_proc(char *page, char **start, off_t off,
        if (card->cardtype != avm_m1) {
                flag = ((u8 *)(ctrl->profile.manu))[5];
                if (flag)
-                       len += sprintf(page+len, "%-16s%s%s%s%s\n",
+                       seq_printf(m, "%-16s%s%s%s%s\n",
                        "linetype",
                        (flag & 0x01) ? " point to point" : "",
                        (flag & 0x02) ? " point to multipoint" : "",
@@ -693,16 +694,25 @@ int b1ctl_read_proc(char *page, char **start, off_t off,
                        (flag & 0x04) ? " leased line with D-channel" : ""
                        );
        }
-       len += sprintf(page+len, "%-16s %s\n", "cardname", cinfo->cardname);
-
-       if (off+count >= len)
-          *eof = 1;
-       if (len < off)
-           return 0;
-       *start = page + off;
-       return ((count < len-off) ? count : len-off);
+       seq_printf(m, "%-16s %s\n", "cardname", cinfo->cardname);
+
+       return 0;
+}
+
+static int b1ctl_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, b1ctl_proc_show, PDE(inode)->data);
 }
 
+const struct file_operations b1ctl_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = b1ctl_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+EXPORT_SYMBOL(b1ctl_proc_fops);
+
 /* ------------------------------------------------------------- */
 
 #ifdef CONFIG_PCI
@@ -781,8 +791,6 @@ EXPORT_SYMBOL(b1_send_message);
 EXPORT_SYMBOL(b1_parse_version);
 EXPORT_SYMBOL(b1_interrupt);
 
-EXPORT_SYMBOL(b1ctl_read_proc);
-
 static int __init b1_init(void)
 {
        char *p;
index 0e84aaae43fd430f1ca2a3a41a357e40f452e8c8..124550d0dbf361f2d28a006f6b9787e83c02685a 100644 (file)
@@ -11,6 +11,8 @@
 
 #include <linux/module.h>
 #include <linux/kernel.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
 #include <linux/skbuff.h>
 #include <linux/delay.h>
 #include <linux/mm.h>
@@ -855,21 +857,20 @@ u16 b1dma_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
 
 /* ------------------------------------------------------------- */
 
-int b1dmactl_read_proc(char *page, char **start, off_t off,
-                       int count, int *eof, struct capi_ctr *ctrl)
+static int b1dmactl_proc_show(struct seq_file *m, void *v)
 {
+       struct capi_ctr *ctrl = m->private;
        avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
        avmcard *card = cinfo->card;
        u8 flag;
-       int len = 0;
        char *s;
        u32 txoff, txlen, rxoff, rxlen, csr;
        unsigned long flags;
 
-       len += sprintf(page+len, "%-16s %s\n", "name", card->name);
-       len += sprintf(page+len, "%-16s 0x%x\n", "io", card->port);
-       len += sprintf(page+len, "%-16s %d\n", "irq", card->irq);
-       len += sprintf(page+len, "%-16s 0x%lx\n", "membase", card->membase);
+       seq_printf(m, "%-16s %s\n", "name", card->name);
+       seq_printf(m, "%-16s 0x%x\n", "io", card->port);
+       seq_printf(m, "%-16s %d\n", "irq", card->irq);
+       seq_printf(m, "%-16s 0x%lx\n", "membase", card->membase);
        switch (card->cardtype) {
        case avm_b1isa: s = "B1 ISA"; break;
        case avm_b1pci: s = "B1 PCI"; break;
@@ -882,18 +883,18 @@ int b1dmactl_read_proc(char *page, char **start, off_t off,
        case avm_c2: s = "C2"; break;
        default: s = "???"; break;
        }
-       len += sprintf(page+len, "%-16s %s\n", "type", s);
+       seq_printf(m, "%-16s %s\n", "type", s);
        if ((s = cinfo->version[VER_DRIVER]) != NULL)
-          len += sprintf(page+len, "%-16s %s\n", "ver_driver", s);
+               seq_printf(m, "%-16s %s\n", "ver_driver", s);
        if ((s = cinfo->version[VER_CARDTYPE]) != NULL)
-          len += sprintf(page+len, "%-16s %s\n", "ver_cardtype", s);
+               seq_printf(m, "%-16s %s\n", "ver_cardtype", s);
        if ((s = cinfo->version[VER_SERIAL]) != NULL)
-          len += sprintf(page+len, "%-16s %s\n", "ver_serial", s);
+               seq_printf(m, "%-16s %s\n", "ver_serial", s);
 
        if (card->cardtype != avm_m1) {
                flag = ((u8 *)(ctrl->profile.manu))[3];
                if (flag)
-                       len += sprintf(page+len, "%-16s%s%s%s%s%s%s%s\n",
+                       seq_printf(m, "%-16s%s%s%s%s%s%s%s\n",
                        "protocol",
                        (flag & 0x01) ? " DSS1" : "",
                        (flag & 0x02) ? " CT1" : "",
@@ -907,7 +908,7 @@ int b1dmactl_read_proc(char *page, char **start, off_t off,
        if (card->cardtype != avm_m1) {
                flag = ((u8 *)(ctrl->profile.manu))[5];
                if (flag)
-                       len += sprintf(page+len, "%-16s%s%s%s%s\n",
+                       seq_printf(m, "%-16s%s%s%s%s\n",
                        "linetype",
                        (flag & 0x01) ? " point to point" : "",
                        (flag & 0x02) ? " point to multipoint" : "",
@@ -915,7 +916,7 @@ int b1dmactl_read_proc(char *page, char **start, off_t off,
                        (flag & 0x04) ? " leased line with D-channel" : ""
                        );
        }
-       len += sprintf(page+len, "%-16s %s\n", "cardname", cinfo->cardname);
+       seq_printf(m, "%-16s %s\n", "cardname", cinfo->cardname);
 
 
        spin_lock_irqsave(&card->lock, flags);
@@ -930,27 +931,30 @@ int b1dmactl_read_proc(char *page, char **start, off_t off,
 
        spin_unlock_irqrestore(&card->lock, flags);
 
-        len += sprintf(page+len, "%-16s 0x%lx\n",
-                               "csr (cached)", (unsigned long)card->csr);
-        len += sprintf(page+len, "%-16s 0x%lx\n",
-                               "csr", (unsigned long)csr);
-        len += sprintf(page+len, "%-16s %lu\n",
-                               "txoff", (unsigned long)txoff);
-        len += sprintf(page+len, "%-16s %lu\n",
-                               "txlen", (unsigned long)txlen);
-        len += sprintf(page+len, "%-16s %lu\n",
-                               "rxoff", (unsigned long)rxoff);
-        len += sprintf(page+len, "%-16s %lu\n",
-                               "rxlen", (unsigned long)rxlen);
-
-       if (off+count >= len)
-          *eof = 1;
-       if (len < off)
-           return 0;
-       *start = page + off;
-       return ((count < len-off) ? count : len-off);
+       seq_printf(m, "%-16s 0x%lx\n", "csr (cached)", (unsigned long)card->csr);
+       seq_printf(m, "%-16s 0x%lx\n", "csr", (unsigned long)csr);
+       seq_printf(m, "%-16s %lu\n", "txoff", (unsigned long)txoff);
+       seq_printf(m, "%-16s %lu\n", "txlen", (unsigned long)txlen);
+       seq_printf(m, "%-16s %lu\n", "rxoff", (unsigned long)rxoff);
+       seq_printf(m, "%-16s %lu\n", "rxlen", (unsigned long)rxlen);
+
+       return 0;
+}
+
+static int b1dmactl_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, b1dmactl_proc_show, PDE(inode)->data);
 }
 
+const struct file_operations b1dmactl_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = b1dmactl_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+EXPORT_SYMBOL(b1dmactl_proc_fops);
+
 /* ------------------------------------------------------------- */
 
 EXPORT_SYMBOL(b1dma_reset);
@@ -963,7 +967,6 @@ EXPORT_SYMBOL(b1dma_reset_ctr);
 EXPORT_SYMBOL(b1dma_register_appl);
 EXPORT_SYMBOL(b1dma_release_appl);
 EXPORT_SYMBOL(b1dma_send_message);
-EXPORT_SYMBOL(b1dmactl_read_proc);
 
 static int __init b1dma_init(void)
 {
index 6461a32bc838af31dceb5ea4073c17c5f3c79e41..ff5390546f92a935d911cd74c31bb358853e563f 100644 (file)
@@ -121,7 +121,7 @@ static int b1isa_probe(struct pci_dev *pdev)
        cinfo->capi_ctrl.load_firmware = b1_load_firmware;
        cinfo->capi_ctrl.reset_ctr     = b1_reset_ctr;
        cinfo->capi_ctrl.procinfo      = b1isa_procinfo;
-       cinfo->capi_ctrl.ctr_read_proc = b1ctl_read_proc;
+       cinfo->capi_ctrl.proc_fops = &b1ctl_proc_fops;
        strcpy(cinfo->capi_ctrl.name, card->name);
 
        retval = attach_capi_ctr(&cinfo->capi_ctrl);
index 5b314a2c40493eb7e88441b96fa6f0a523e6933f..c97e4315079d8c15593818d5a0e93bc1e19003d9 100644 (file)
@@ -112,7 +112,7 @@ static int b1pci_probe(struct capicardparams *p, struct pci_dev *pdev)
        cinfo->capi_ctrl.load_firmware = b1_load_firmware;
        cinfo->capi_ctrl.reset_ctr     = b1_reset_ctr;
        cinfo->capi_ctrl.procinfo      = b1pci_procinfo;
-       cinfo->capi_ctrl.ctr_read_proc = b1ctl_read_proc;
+       cinfo->capi_ctrl.proc_fops = &b1ctl_proc_fops;
        strcpy(cinfo->capi_ctrl.name, card->name);
        cinfo->capi_ctrl.owner         = THIS_MODULE;
 
@@ -251,7 +251,7 @@ static int b1pciv4_probe(struct capicardparams *p, struct pci_dev *pdev)
        cinfo->capi_ctrl.load_firmware = b1dma_load_firmware;
        cinfo->capi_ctrl.reset_ctr     = b1dma_reset_ctr;
        cinfo->capi_ctrl.procinfo      = b1pciv4_procinfo;
-       cinfo->capi_ctrl.ctr_read_proc = b1dmactl_read_proc;
+       cinfo->capi_ctrl.proc_fops = &b1dmactl_proc_fops;
        strcpy(cinfo->capi_ctrl.name, card->name);
 
        retval = attach_capi_ctr(&cinfo->capi_ctrl);
index 7740403b40e14685638b1d60c5d05a755332e6ae..d6391e0afeeaf76425a70ded1b4aa1d167c3aaaa 100644 (file)
@@ -108,7 +108,7 @@ static int b1pcmcia_add_card(unsigned int port, unsigned irq,
        cinfo->capi_ctrl.load_firmware = b1_load_firmware;
        cinfo->capi_ctrl.reset_ctr     = b1_reset_ctr;
        cinfo->capi_ctrl.procinfo      = b1pcmcia_procinfo;
-       cinfo->capi_ctrl.ctr_read_proc = b1ctl_read_proc;
+       cinfo->capi_ctrl.proc_fops = &b1ctl_proc_fops;
        strcpy(cinfo->capi_ctrl.name, card->name);
 
        retval = attach_capi_ctr(&cinfo->capi_ctrl);
index 6833301a45fc604f11a9f6833d852fe069c7bfaf..de6e6b31181938484e0c0d425502b7fdc47f9b98 100644 (file)
@@ -11,6 +11,8 @@
 
 #include <linux/module.h>
 #include <linux/kernel.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
 #include <linux/skbuff.h>
 #include <linux/delay.h>
 #include <linux/mm.h>
@@ -1062,19 +1064,18 @@ static char *c4_procinfo(struct capi_ctr *ctrl)
        return cinfo->infobuf;
 }
 
-static int c4_read_proc(char *page, char **start, off_t off,
-                       int count, int *eof, struct capi_ctr *ctrl)
+static int c4_proc_show(struct seq_file *m, void *v)
 {
+       struct capi_ctr *ctrl = m->private;
        avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
        avmcard *card = cinfo->card;
        u8 flag;
-       int len = 0;
        char *s;
 
-       len += sprintf(page+len, "%-16s %s\n", "name", card->name);
-       len += sprintf(page+len, "%-16s 0x%x\n", "io", card->port);
-       len += sprintf(page+len, "%-16s %d\n", "irq", card->irq);
-       len += sprintf(page+len, "%-16s 0x%lx\n", "membase", card->membase);
+       seq_printf(m, "%-16s %s\n", "name", card->name);
+       seq_printf(m, "%-16s 0x%x\n", "io", card->port);
+       seq_printf(m, "%-16s %d\n", "irq", card->irq);
+       seq_printf(m, "%-16s 0x%lx\n", "membase", card->membase);
        switch (card->cardtype) {
        case avm_b1isa: s = "B1 ISA"; break;
        case avm_b1pci: s = "B1 PCI"; break;
@@ -1087,18 +1088,18 @@ static int c4_read_proc(char *page, char **start, off_t off,
        case avm_c2: s = "C2"; break;
        default: s = "???"; break;
        }
-       len += sprintf(page+len, "%-16s %s\n", "type", s);
+       seq_printf(m, "%-16s %s\n", "type", s);
        if ((s = cinfo->version[VER_DRIVER]) != NULL)
-          len += sprintf(page+len, "%-16s %s\n", "ver_driver", s);
+               seq_printf(m, "%-16s %s\n", "ver_driver", s);
        if ((s = cinfo->version[VER_CARDTYPE]) != NULL)
-          len += sprintf(page+len, "%-16s %s\n", "ver_cardtype", s);
+               seq_printf(m, "%-16s %s\n", "ver_cardtype", s);
        if ((s = cinfo->version[VER_SERIAL]) != NULL)
-          len += sprintf(page+len, "%-16s %s\n", "ver_serial", s);
+               seq_printf(m, "%-16s %s\n", "ver_serial", s);
 
        if (card->cardtype != avm_m1) {
                flag = ((u8 *)(ctrl->profile.manu))[3];
                if (flag)
-                       len += sprintf(page+len, "%-16s%s%s%s%s%s%s%s\n",
+                       seq_printf(m, "%-16s%s%s%s%s%s%s%s\n",
                        "protocol",
                        (flag & 0x01) ? " DSS1" : "",
                        (flag & 0x02) ? " CT1" : "",
@@ -1112,7 +1113,7 @@ static int c4_read_proc(char *page, char **start, off_t off,
        if (card->cardtype != avm_m1) {
                flag = ((u8 *)(ctrl->profile.manu))[5];
                if (flag)
-                       len += sprintf(page+len, "%-16s%s%s%s%s\n",
+                       seq_printf(m, "%-16s%s%s%s%s\n",
                        "linetype",
                        (flag & 0x01) ? " point to point" : "",
                        (flag & 0x02) ? " point to multipoint" : "",
@@ -1120,16 +1121,24 @@ static int c4_read_proc(char *page, char **start, off_t off,
                        (flag & 0x04) ? " leased line with D-channel" : ""
                        );
        }
-       len += sprintf(page+len, "%-16s %s\n", "cardname", cinfo->cardname);
-
-       if (off+count >= len)
-          *eof = 1;
-       if (len < off)
-           return 0;
-       *start = page + off;
-       return ((count < len-off) ? count : len-off);
+       seq_printf(m, "%-16s %s\n", "cardname", cinfo->cardname);
+
+       return 0;
 }
 
+static int c4_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, c4_proc_show, PDE(inode)->data);
+}
+
+static const struct file_operations c4_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = c4_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
 /* ------------------------------------------------------------- */
 
 static int c4_add_card(struct capicardparams *p, struct pci_dev *dev,
@@ -1201,7 +1210,7 @@ static int c4_add_card(struct capicardparams *p, struct pci_dev *dev,
                cinfo->capi_ctrl.load_firmware = c4_load_firmware;
                cinfo->capi_ctrl.reset_ctr     = c4_reset_ctr;
                cinfo->capi_ctrl.procinfo      = c4_procinfo;
-               cinfo->capi_ctrl.ctr_read_proc = c4_read_proc;
+               cinfo->capi_ctrl.proc_fops = &c4_proc_fops;
                strcpy(cinfo->capi_ctrl.name, card->name);
 
                retval = attach_capi_ctr(&cinfo->capi_ctrl);
index 1c53fd49adb6e36f35445c9a86d76e6b9e70eaaa..baeeb3c2a3ee1cc720bb28e07bae96f02d7bfb94 100644 (file)
@@ -429,7 +429,7 @@ static int t1isa_probe(struct pci_dev *pdev, int cardnr)
        cinfo->capi_ctrl.load_firmware = t1isa_load_firmware;
        cinfo->capi_ctrl.reset_ctr     = t1isa_reset_ctr;
        cinfo->capi_ctrl.procinfo      = t1isa_procinfo;
-       cinfo->capi_ctrl.ctr_read_proc = b1ctl_read_proc;
+       cinfo->capi_ctrl.proc_fops = &b1ctl_proc_fops;
        strcpy(cinfo->capi_ctrl.name, card->name);
 
        retval = attach_capi_ctr(&cinfo->capi_ctrl);
index e6d298d751465af4411143831b7bb4b9d2b3057a..5a3f830980185c45614fb4fbf59f51924032223c 100644 (file)
@@ -119,7 +119,7 @@ static int t1pci_add_card(struct capicardparams *p, struct pci_dev *pdev)
        cinfo->capi_ctrl.load_firmware = b1dma_load_firmware;
        cinfo->capi_ctrl.reset_ctr     = b1dma_reset_ctr;
        cinfo->capi_ctrl.procinfo      = t1pci_procinfo;
-       cinfo->capi_ctrl.ctr_read_proc = b1dmactl_read_proc;
+       cinfo->capi_ctrl.proc_fops = &b1dmactl_proc_fops;
        strcpy(cinfo->capi_ctrl.name, card->name);
 
        retval = attach_capi_ctr(&cinfo->capi_ctrl);
index 98fcdfc7ca555ca7440923e268b4f3cf24af0862..0f073cd73763f98dc7698e3c2bec2d0ef42c7102 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <asm/uaccess.h>
+#include <linux/seq_file.h>
 #include <linux/skbuff.h>
 
 #include "os_capi.h"
@@ -75,25 +76,32 @@ void diva_os_free_message_buffer(diva_os_message_buffer_s * dmb)
 /*
  * proc function for controller info
  */
-static int diva_ctl_read_proc(char *page, char **start, off_t off,
-                             int count, int *eof, struct capi_ctr *ctrl)
+static int diva_ctl_proc_show(struct seq_file *m, void *v)
 {
+       struct capi_ctr *ctrl = m->private;
        diva_card *card = (diva_card *) ctrl->driverdata;
-       int len = 0;
-
-       len += sprintf(page + len, "%s\n", ctrl->name);
-       len += sprintf(page + len, "Serial No. : %s\n", ctrl->serial);
-       len += sprintf(page + len, "Id         : %d\n", card->Id);
-       len += sprintf(page + len, "Channels   : %d\n", card->d.channels);
-
-       if (off + count >= len)
-               *eof = 1;
-       if (len < off)
-               return 0;
-       *start = page + off;
-       return ((count < len - off) ? count : len - off);
+
+       seq_printf(m, "%s\n", ctrl->name);
+       seq_printf(m, "Serial No. : %s\n", ctrl->serial);
+       seq_printf(m, "Id         : %d\n", card->Id);
+       seq_printf(m, "Channels   : %d\n", card->d.channels);
+
+       return 0;
+}
+
+static int diva_ctl_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, diva_ctl_proc_show, NULL);
 }
 
+static const struct file_operations diva_ctl_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = diva_ctl_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
 /*
  * set additional os settings in capi_ctr struct
  */
@@ -102,7 +110,7 @@ void diva_os_set_controller_struct(struct capi_ctr *ctrl)
        ctrl->driver_name = DRIVERLNAME;
        ctrl->load_firmware = NULL;
        ctrl->reset_ctr = NULL;
-       ctrl->ctr_read_proc = diva_ctl_read_proc;
+       ctrl->proc_fops = &diva_ctl_proc_fops;
        ctrl->owner = THIS_MODULE;
 }
 
index 993b14cf1778bb2ba85b2a43cbd0a7242f2a7370..5d06a7437824fa7246966fb5a5f5cfc3ddd0cc17 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/proc_fs.h>
+#include <linux/seq_file.h>
 #include <net/net_namespace.h>
 
 #include "platform.h"
@@ -62,39 +63,41 @@ static char *getrev(const char *revision)
        return rev;
 }
 
-static int
-proc_read(char *page, char **start, off_t off, int count, int *eof,
-         void *data)
+static int divadidd_proc_show(struct seq_file *m, void *v)
 {
-       int len = 0;
        char tmprev[32];
 
        strcpy(tmprev, main_revision);
-       len += sprintf(page + len, "%s\n", DRIVERNAME);
-       len += sprintf(page + len, "name     : %s\n", DRIVERLNAME);
-       len += sprintf(page + len, "release  : %s\n", DRIVERRELEASE_DIDD);
-       len += sprintf(page + len, "build    : %s(%s)\n",
+       seq_printf(m, "%s\n", DRIVERNAME);
+       seq_printf(m, "name     : %s\n", DRIVERLNAME);
+       seq_printf(m, "release  : %s\n", DRIVERRELEASE_DIDD);
+       seq_printf(m, "build    : %s(%s)\n",
                       diva_didd_common_code_build, DIVA_BUILD);
-       len += sprintf(page + len, "revision : %s\n", getrev(tmprev));
-
-       if (off + count >= len)
-               *eof = 1;
-       if (len < off)
-               return 0;
-       *start = page + off;
-       return ((count < len - off) ? count : len - off);
+       seq_printf(m, "revision : %s\n", getrev(tmprev));
+
+       return 0;
 }
 
+static int divadidd_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, divadidd_proc_show, NULL);
+}
+
+static const struct file_operations divadidd_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = divadidd_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
 static int DIVA_INIT_FUNCTION create_proc(void)
 {
        proc_net_eicon = proc_mkdir("eicon", init_net.proc_net);
 
        if (proc_net_eicon) {
-               if ((proc_didd =
-                    create_proc_entry(DRIVERLNAME, S_IFREG | S_IRUGO,
-                                      proc_net_eicon))) {
-                       proc_didd->read_proc = proc_read;
-               }
+               proc_didd = proc_create(DRIVERLNAME, S_IRUGO, proc_net_eicon,
+                                       &divadidd_proc_fops);
                return (1);
        }
        return (0);
index 69e71ebe7841830bf2af1dc68b894186b776cb91..f577719ab3fa3a71d04bd7c81ee311e438efd1e0 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/poll.h>
 #include <linux/proc_fs.h>
 #include <linux/skbuff.h>
+#include <linux/seq_file.h>
 #include <linux/smp_lock.h>
 #include <asm/uaccess.h>
 
@@ -86,39 +87,40 @@ static void diva_um_timer_function(unsigned long data);
 extern struct proc_dir_entry *proc_net_eicon;
 static struct proc_dir_entry *um_idi_proc_entry = NULL;
 
-static int
-um_idi_proc_read(char *page, char **start, off_t off, int count, int *eof,
-                void *data)
+static int um_idi_proc_show(struct seq_file *m, void *v)
 {
-       int len = 0;
        char tmprev[32];
 
-       len += sprintf(page + len, "%s\n", DRIVERNAME);
-       len += sprintf(page + len, "name     : %s\n", DRIVERLNAME);
-       len += sprintf(page + len, "release  : %s\n", DRIVERRELEASE_IDI);
+       seq_printf(m, "%s\n", DRIVERNAME);
+       seq_printf(m, "name     : %s\n", DRIVERLNAME);
+       seq_printf(m, "release  : %s\n", DRIVERRELEASE_IDI);
        strcpy(tmprev, main_revision);
-       len += sprintf(page + len, "revision : %s\n", getrev(tmprev));
-       len += sprintf(page + len, "build    : %s\n", DIVA_BUILD);
-       len += sprintf(page + len, "major    : %d\n", major);
-
-       if (off + count >= len)
-               *eof = 1;
-       if (len < off)
-               return 0;
-       *start = page + off;
-       return ((count < len - off) ? count : len - off);
+       seq_printf(m, "revision : %s\n", getrev(tmprev));
+       seq_printf(m, "build    : %s\n", DIVA_BUILD);
+       seq_printf(m, "major    : %d\n", major);
+
+       return 0;
+}
+
+static int um_idi_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, um_idi_proc_show, NULL);
 }
 
+static const struct file_operations um_idi_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = um_idi_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
 static int DIVA_INIT_FUNCTION create_um_idi_proc(void)
 {
-       um_idi_proc_entry = create_proc_entry(DRIVERLNAME,
-                                             S_IFREG | S_IRUGO | S_IWUSR,
-                                             proc_net_eicon);
+       um_idi_proc_entry = proc_create(DRIVERLNAME, S_IRUGO, proc_net_eicon,
+                                       &um_idi_proc_fops);
        if (!um_idi_proc_entry)
                return (0);
-
-       um_idi_proc_entry->read_proc = um_idi_proc_read;
-
        return (1);
 }
 
index 040827288ec91ea43d3eb71b3cac194fa3adf4f9..46d44a94262408127699d4c0bfe3fd8619a57b92 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/kernel.h>
 #include <linux/poll.h>
 #include <linux/proc_fs.h>
+#include <linux/seq_file.h>
 #include <linux/list.h>
 #include <asm/uaccess.h>
 
@@ -141,14 +142,10 @@ void remove_divas_proc(void)
        }
 }
 
-/*
-** write group_optimization 
-*/
-static int
-write_grp_opt(struct file *file, const char __user *buffer, unsigned long count,
-             void *data)
+static ssize_t grp_opt_proc_write(struct file *file, const char __user *buffer,
+                                 size_t count, loff_t *pos)
 {
-       diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) data;
+       diva_os_xdi_adapter_t *a = PDE(file->f_path.dentry->d_inode)->data;
        PISDN_ADAPTER IoAdapter = IoAdapters[a->controller - 1];
 
        if ((count == 1) || (count == 2)) {
@@ -172,14 +169,10 @@ write_grp_opt(struct file *file, const char __user *buffer, unsigned long count,
        return (-EINVAL);
 }
 
-/*
-** write dynamic_l1_down
-*/
-static int
-write_d_l1_down(struct file *file, const char __user *buffer, unsigned long count,
-               void *data)
+static ssize_t d_l1_down_proc_write(struct file *file, const char __user *buffer,
+                                   size_t count, loff_t *pos)
 {
-       diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) data;
+       diva_os_xdi_adapter_t *a = PDE(file->f_path.dentry->d_inode)->data;
        PISDN_ADAPTER IoAdapter = IoAdapters[a->controller - 1];
 
        if ((count == 1) || (count == 2)) {
@@ -203,63 +196,62 @@ write_d_l1_down(struct file *file, const char __user *buffer, unsigned long coun
        return (-EINVAL);
 }
 
-
-/*
-** read dynamic_l1_down 
-*/
-static int
-read_d_l1_down(char *page, char **start, off_t off, int count, int *eof,
-              void *data)
+static int d_l1_down_proc_show(struct seq_file *m, void *v)
 {
-       int len = 0;
-       diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) data;
+       diva_os_xdi_adapter_t *a = m->private;
        PISDN_ADAPTER IoAdapter = IoAdapters[a->controller - 1];
 
-       len += sprintf(page + len, "%s\n",
+       seq_printf(m, "%s\n",
                       (IoAdapter->capi_cfg.
                        cfg_1 & DIVA_XDI_CAPI_CFG_1_DYNAMIC_L1_ON) ? "1" :
                       "0");
+       return 0;
+}
 
-       if (off + count >= len)
-               *eof = 1;
-       if (len < off)
-               return 0;
-       *start = page + off;
-       return ((count < len - off) ? count : len - off);
+static int d_l1_down_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, d_l1_down_proc_show, PDE(inode)->data);
 }
 
-/*
-** read group_optimization
-*/
-static int
-read_grp_opt(char *page, char **start, off_t off, int count, int *eof,
-            void *data)
+static const struct file_operations d_l1_down_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = d_l1_down_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+       .write          = d_l1_down_proc_write,
+};
+
+static int grp_opt_proc_show(struct seq_file *m, void *v)
 {
-       int len = 0;
-       diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) data;
+       diva_os_xdi_adapter_t *a = m->private;
        PISDN_ADAPTER IoAdapter = IoAdapters[a->controller - 1];
 
-       len += sprintf(page + len, "%s\n",
+       seq_printf(m, "%s\n",
                       (IoAdapter->capi_cfg.
                        cfg_1 & DIVA_XDI_CAPI_CFG_1_GROUP_POPTIMIZATION_ON)
                       ? "1" : "0");
+       return 0;
+}
 
-       if (off + count >= len)
-               *eof = 1;
-       if (len < off)
-               return 0;
-       *start = page + off;
-       return ((count < len - off) ? count : len - off);
+static int grp_opt_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, grp_opt_proc_show, PDE(inode)->data);
 }
 
-/*
-** info write
-*/
-static int
-info_write(struct file *file, const char __user *buffer, unsigned long count,
-          void *data)
+static const struct file_operations grp_opt_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = grp_opt_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+       .write          = grp_opt_proc_write,
+};
+
+static ssize_t info_proc_write(struct file *file, const char __user *buffer,
+                              size_t count, loff_t *pos)
 {
-       diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) data;
+       diva_os_xdi_adapter_t *a = PDE(file->f_path.dentry->d_inode)->data;
        PISDN_ADAPTER IoAdapter = IoAdapters[a->controller - 1];
        char c[4];
 
@@ -277,63 +269,46 @@ info_write(struct file *file, const char __user *buffer, unsigned long count,
        return (-EINVAL);
 }
 
-/*
-** info read
-*/
-static int
-info_read(char *page, char **start, off_t off, int count, int *eof,
-         void *data)
+static int info_proc_show(struct seq_file *m, void *v)
 {
        int i = 0;
-       int len = 0;
        char *p;
        char tmpser[16];
-       diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) data;
+       diva_os_xdi_adapter_t *a = m->private;
        PISDN_ADAPTER IoAdapter = IoAdapters[a->controller - 1];
 
-       len +=
-           sprintf(page + len, "Name        : %s\n",
-                   IoAdapter->Properties.Name);
-       len += sprintf(page + len, "DSP state   : %08x\n", a->dsp_mask);
-       len += sprintf(page + len, "Channels    : %02d\n",
-                      IoAdapter->Properties.Channels);
-       len += sprintf(page + len, "E. max/used : %03d/%03d\n",
+       seq_printf(m, "Name        : %s\n", IoAdapter->Properties.Name);
+       seq_printf(m, "DSP state   : %08x\n", a->dsp_mask);
+       seq_printf(m, "Channels    : %02d\n", IoAdapter->Properties.Channels);
+       seq_printf(m, "E. max/used : %03d/%03d\n",
                       IoAdapter->e_max, IoAdapter->e_count);
        diva_get_vserial_number(IoAdapter, tmpser);
-       len += sprintf(page + len, "Serial      : %s\n", tmpser);
-       len +=
-           sprintf(page + len, "IRQ         : %d\n",
-                   IoAdapter->irq_info.irq_nr);
-       len += sprintf(page + len, "CardIndex   : %d\n", a->CardIndex);
-       len += sprintf(page + len, "CardOrdinal : %d\n", a->CardOrdinal);
-       len += sprintf(page + len, "Controller  : %d\n", a->controller);
-       len += sprintf(page + len, "Bus-Type    : %s\n",
+       seq_printf(m, "Serial      : %s\n", tmpser);
+       seq_printf(m, "IRQ         : %d\n", IoAdapter->irq_info.irq_nr);
+       seq_printf(m, "CardIndex   : %d\n", a->CardIndex);
+       seq_printf(m, "CardOrdinal : %d\n", a->CardOrdinal);
+       seq_printf(m, "Controller  : %d\n", a->controller);
+       seq_printf(m, "Bus-Type    : %s\n",
                       (a->Bus ==
                        DIVAS_XDI_ADAPTER_BUS_ISA) ? "ISA" : "PCI");
-       len += sprintf(page + len, "Port-Name   : %s\n", a->port_name);
+       seq_printf(m, "Port-Name   : %s\n", a->port_name);
        if (a->Bus == DIVAS_XDI_ADAPTER_BUS_PCI) {
-               len +=
-                   sprintf(page + len, "PCI-bus     : %d\n",
-                           a->resources.pci.bus);
-               len +=
-                   sprintf(page + len, "PCI-func    : %d\n",
-                           a->resources.pci.func);
+               seq_printf(m, "PCI-bus     : %d\n", a->resources.pci.bus);
+               seq_printf(m, "PCI-func    : %d\n", a->resources.pci.func);
                for (i = 0; i < 8; i++) {
                        if (a->resources.pci.bar[i]) {
-                               len +=
-                                   sprintf(page + len,
+                               seq_printf(m,
                                            "Mem / I/O %d : 0x%x / mapped : 0x%lx",
                                            i, a->resources.pci.bar[i],
                                            (unsigned long) a->resources.
                                            pci.addr[i]);
                                if (a->resources.pci.length[i]) {
-                                       len +=
-                                           sprintf(page + len,
+                                       seq_printf(m,
                                                    " / length : %d",
                                                    a->resources.pci.
                                                    length[i]);
                                }
-                               len += sprintf(page + len, "\n");
+                               seq_putc(m, '\n');
                        }
                }
        }
@@ -353,16 +328,25 @@ info_read(char *page, char **start, off_t off, int count, int *eof,
        } else {
                p = "ready";
        }
-       len += sprintf(page + len, "State       : %s\n", p);
+       seq_printf(m, "State       : %s\n", p);
 
-       if (off + count >= len)
-               *eof = 1;
-       if (len < off)
-               return 0;
-       *start = page + off;
-       return ((count < len - off) ? count : len - off);
+       return 0;
+}
+
+static int info_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, info_proc_show, PDE(inode)->data);
 }
 
+static const struct file_operations info_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = info_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+       .write          = info_proc_write,
+};
+
 /*
 ** adapter proc init/de-init
 */
@@ -380,28 +364,20 @@ int create_adapter_proc(diva_os_xdi_adapter_t * a)
                return (0);
        a->proc_adapter_dir = (void *) de;
 
-       if (!(pe =
-            create_proc_entry(info_proc_name, S_IFREG | S_IRUGO | S_IWUSR, de)))
+       pe = proc_create_data(info_proc_name, S_IRUGO | S_IWUSR, de,
+                             &info_proc_fops, a);
+       if (!pe)
                return (0);
        a->proc_info = (void *) pe;
-       pe->write_proc = info_write;
-       pe->read_proc = info_read;
-       pe->data = a;
 
-       if ((pe = create_proc_entry(grp_opt_proc_name,
-                              S_IFREG | S_IRUGO | S_IWUSR, de))) {
+       pe = proc_create_data(grp_opt_proc_name, S_IRUGO | S_IWUSR, de,
+                             &grp_opt_proc_fops, a);
+       if (pe)
                a->proc_grp_opt = (void *) pe;
-               pe->write_proc = write_grp_opt;
-               pe->read_proc = read_grp_opt;
-               pe->data = a;
-       }
-       if ((pe = create_proc_entry(d_l1_down_proc_name,
-                              S_IFREG | S_IRUGO | S_IWUSR, de))) {
+       pe = proc_create_data(d_l1_down_proc_name, S_IRUGO | S_IWUSR, de,
+                             &d_l1_down_proc_fops, a);
+       if (pe)
                a->proc_d_l1_down = (void *) pe;
-               pe->write_proc = write_d_l1_down;
-               pe->read_proc = read_d_l1_down;
-               pe->data = a;
-       }
 
        DBG_TRC(("proc entry %s created", tmp));
 
index 4ffaa14b9fc4fd92a47a083b0521207471be7977..fe874afa4f81347e773a062a1ba2546338cc8581 100644 (file)
@@ -11,6 +11,8 @@
  */
 
 #include <linux/module.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
 #include <linux/signal.h>
 #include <linux/kernel.h>
 #include <linux/skbuff.h>
@@ -432,26 +434,16 @@ static u16 hycapi_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
        return retval;
 }
 
-/*********************************************************************
-hycapi_read_proc
-
-Informations provided in the /proc/capi-entries.
-
-*********************************************************************/
-
-static int hycapi_read_proc(char *page, char **start, off_t off,
-                           int count, int *eof, struct capi_ctr *ctrl)
+static int hycapi_proc_show(struct seq_file *m, void *v)
 {
+       struct capi_ctr *ctrl = m->private;
        hycapictrl_info *cinfo = (hycapictrl_info *)(ctrl->driverdata);
        hysdn_card *card = cinfo->card;
-       int len = 0;
        char *s;
-#ifdef HYCAPI_PRINTFNAMES
-       printk(KERN_NOTICE "hycapi_read_proc\n");    
-#endif
-       len += sprintf(page+len, "%-16s %s\n", "name", cinfo->cardname);
-       len += sprintf(page+len, "%-16s 0x%x\n", "io", card->iobase);
-       len += sprintf(page+len, "%-16s %d\n", "irq", card->irq);
+
+       seq_printf(m, "%-16s %s\n", "name", cinfo->cardname);
+       seq_printf(m, "%-16s 0x%x\n", "io", card->iobase);
+       seq_printf(m, "%-16s %d\n", "irq", card->irq);
     
        switch (card->brdtype) {
                case BD_PCCARD:  s = "HYSDN Hycard"; break;
@@ -461,24 +453,32 @@ static int hycapi_read_proc(char *page, char **start, off_t off,
                case BD_PLEXUS: s = "HYSDN Plexus30"; break;
                default: s = "???"; break;
        }
-       len += sprintf(page+len, "%-16s %s\n", "type", s);
+       seq_printf(m, "%-16s %s\n", "type", s);
        if ((s = cinfo->version[VER_DRIVER]) != NULL)
-               len += sprintf(page+len, "%-16s %s\n", "ver_driver", s);
+               seq_printf(m, "%-16s %s\n", "ver_driver", s);
        if ((s = cinfo->version[VER_CARDTYPE]) != NULL)
-               len += sprintf(page+len, "%-16s %s\n", "ver_cardtype", s);
+               seq_printf(m, "%-16s %s\n", "ver_cardtype", s);
        if ((s = cinfo->version[VER_SERIAL]) != NULL)
-               len += sprintf(page+len, "%-16s %s\n", "ver_serial", s);
+               seq_printf(m, "%-16s %s\n", "ver_serial", s);
     
-       len += sprintf(page+len, "%-16s %s\n", "cardname", cinfo->cardname);
+       seq_printf(m, "%-16s %s\n", "cardname", cinfo->cardname);
     
-       if (off+count >= len)
-               *eof = 1;
-       if (len < off)
-               return 0;
-       *start = page + off;
-       return ((count < len-off) ? count : len-off);
+       return 0;
+}
+
+static int hycapi_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, hycapi_proc_show, PDE(inode)->data);
 }
 
+static const struct file_operations hycapi_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = hycapi_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
 /**************************************************************
 hycapi_load_firmware
 
@@ -774,7 +774,7 @@ hycapi_capi_create(hysdn_card *card)
                ctrl->load_firmware = hycapi_load_firmware;
                ctrl->reset_ctr     = hycapi_reset_ctr;
                ctrl->procinfo      = hycapi_procinfo;
-               ctrl->ctr_read_proc = hycapi_read_proc;
+               ctrl->proc_fops = &hycapi_proc_fops;
                strcpy(ctrl->name, cinfo->cardname);
                ctrl->owner = THIS_MODULE;
 
index 8b8558fcb04280410b8761ed3d36aefbc778c27a..da6552d32cfed8c1556c8685ed22e1aa54da41af 100644 (file)
@@ -949,11 +949,8 @@ static int dvb_net_filter_sec_set(struct net_device *dev,
        (*secfilter)->filter_mask[10] = mac_mask[1];
        (*secfilter)->filter_mask[11]=mac_mask[0];
 
-       dprintk("%s: filter mac=%02x %02x %02x %02x %02x %02x\n",
-              dev->name, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
-       dprintk("%s: filter mask=%02x %02x %02x %02x %02x %02x\n",
-              dev->name, mac_mask[0], mac_mask[1], mac_mask[2],
-              mac_mask[3], mac_mask[4], mac_mask[5]);
+       dprintk("%s: filter mac=%pM\n", dev->name, mac);
+       dprintk("%s: filter mask=%pM\n", dev->name, mac_mask);
 
        return 0;
 }
index 7045c45da9b160030fdd07859b373708656d2ea0..949a648f8e2e16c9dcd6447ccbb66d526dbfd088 100644 (file)
@@ -111,10 +111,7 @@ static int print_serial_number(struct seq_file *seq, u8 * serialno, int max_len)
                break;
 
        case I2O_SNFORMAT_LAN48_MAC:    /* LAN-48 MAC Address */
-               seq_printf(seq,
-                          "LAN-48 MAC address @ %02X:%02X:%02X:%02X:%02X:%02X",
-                          serialno[2], serialno[3],
-                          serialno[4], serialno[5], serialno[6], serialno[7]);
+               seq_printf(seq, "LAN-48 MAC address @ %pM", &serialno[2]);
                break;
 
        case I2O_SNFORMAT_WAN:  /* WAN MAC Address */
@@ -126,10 +123,8 @@ static int print_serial_number(struct seq_file *seq, u8 * serialno, int max_len)
        case I2O_SNFORMAT_LAN64_MAC:    /* LAN-64 MAC Address */
                /* FIXME: Figure out what a LAN-64 address really looks like?? */
                seq_printf(seq,
-                          "LAN-64 MAC address @ [?:%02X:%02X:?] %02X:%02X:%02X:%02X:%02X:%02X",
-                          serialno[8], serialno[9],
-                          serialno[2], serialno[3],
-                          serialno[4], serialno[5], serialno[6], serialno[7]);
+                          "LAN-64 MAC address @ [?:%02X:%02X:?] %pM",
+                          serialno[8], serialno[9], &serialno[2]);
                break;
 
        case I2O_SNFORMAT_DDM:  /* I2O DDM */
index 50d431e469f5e4318d37c6d322cc2fa7e36e8ef4..9dbaeb574e6380c936381a781617cde8bb8c9412 100644 (file)
@@ -43,15 +43,14 @@ static int iwmct_fw_parser_init(struct iwmct_priv *priv, const u8 *file,
        struct iwmct_parser *parser = &priv->parser;
        struct iwmct_fw_hdr *fw_hdr = &parser->versions;
 
-       LOG_INFOEX(priv, INIT, "-->\n");
+       LOG_TRACE(priv, FW_DOWNLOAD, "-->\n");
 
        LOG_INFO(priv, FW_DOWNLOAD, "file_size=%zd\n", file_size);
 
        parser->file = file;
        parser->file_size = file_size;
        parser->cur_pos = 0;
-       parser->buf = NULL;
-
+       parser->entry_point = 0;
        parser->buf = kzalloc(block_size, GFP_KERNEL);
        if (!parser->buf) {
                LOG_ERROR(priv, FW_DOWNLOAD, "kzalloc error\n");
@@ -70,7 +69,7 @@ static int iwmct_fw_parser_init(struct iwmct_priv *priv, const u8 *file,
 
        parser->cur_pos += sizeof(struct iwmct_fw_hdr);
 
-       LOG_INFOEX(priv, INIT, "<--\n");
+       LOG_TRACE(priv, FW_DOWNLOAD, "<--\n");
        return 0;
 }
 
@@ -113,7 +112,7 @@ static int iwmct_parse_next_section(struct iwmct_priv *priv, const u8 **p_sec,
        struct iwmct_dbg *dbg = &priv->dbg;
        struct iwmct_fw_sec_hdr *sec_hdr;
 
-       LOG_INFOEX(priv, INIT, "-->\n");
+       LOG_TRACE(priv, FW_DOWNLOAD, "-->\n");
 
        while (parser->cur_pos + sizeof(struct iwmct_fw_sec_hdr)
                <= parser->file_size) {
@@ -152,7 +151,7 @@ static int iwmct_parse_next_section(struct iwmct_priv *priv, const u8 **p_sec,
                        "finished with section cur_pos=%zd\n", parser->cur_pos);
        }
 
-       LOG_INFOEX(priv, INIT, "<--\n");
+       LOG_TRACE(priv, INIT, "<--\n");
        return 0;
 }
 
@@ -167,7 +166,7 @@ static int iwmct_download_section(struct iwmct_priv *priv, const u8 *p_sec,
        int ret = 0;
        u32 cmd = 0;
 
-       LOG_INFOEX(priv, INIT, "-->\n");
+       LOG_TRACE(priv, FW_DOWNLOAD, "-->\n");
        LOG_INFO(priv, FW_DOWNLOAD, "Download address 0x%x size 0x%zx\n",
                                addr, sec_size);
 
@@ -229,7 +228,7 @@ static int iwmct_download_section(struct iwmct_priv *priv, const u8 *p_sec,
                hdr->cmd = cpu_to_le32(cmd);
                /* send it down */
                /* TODO: add more proper sending and error checking */
-               ret = iwmct_tx(priv, 0, parser->buf, trans_size);
+               ret = iwmct_tx(priv, parser->buf, trans_size);
                if (ret != 0) {
                        LOG_INFO(priv, FW_DOWNLOAD,
                                "iwmct_tx returned %d\n", ret);
@@ -251,7 +250,7 @@ static int iwmct_download_section(struct iwmct_priv *priv, const u8 *p_sec,
        if (sent < sec_size)
                ret = -EINVAL;
 exit:
-       LOG_INFOEX(priv, INIT, "<--\n");
+       LOG_TRACE(priv, FW_DOWNLOAD, "<--\n");
        return ret;
 }
 
@@ -262,7 +261,7 @@ static int iwmct_kick_fw(struct iwmct_priv *priv, bool jump)
        int ret;
        u32 cmd;
 
-       LOG_INFOEX(priv, INIT, "-->\n");
+       LOG_TRACE(priv, FW_DOWNLOAD, "-->\n");
 
        memset(parser->buf, 0, parser->buf_size);
        cmd = IWMC_CMD_SIGNATURE << CMD_HDR_SIGNATURE_POS;
@@ -281,11 +280,11 @@ static int iwmct_kick_fw(struct iwmct_priv *priv, bool jump)
        LOG_HEXDUMP(FW_DOWNLOAD, parser->buf, sizeof(*hdr));
        /* send it down */
        /* TODO: add more proper sending and error checking */
-       ret = iwmct_tx(priv, 0, parser->buf, IWMC_SDIO_BLK_SIZE);
+       ret = iwmct_tx(priv, parser->buf, IWMC_SDIO_BLK_SIZE);
        if (ret)
                LOG_INFO(priv, FW_DOWNLOAD, "iwmct_tx returned %d", ret);
 
-       LOG_INFOEX(priv, INIT, "<--\n");
+       LOG_TRACE(priv, FW_DOWNLOAD, "<--\n");
        return 0;
 }
 
@@ -298,8 +297,16 @@ int iwmct_fw_load(struct iwmct_priv *priv)
        __le32 addr;
        int ret;
 
-       /* clear parser struct */
-       memset(&priv->parser, 0, sizeof(struct iwmct_parser));
+
+       LOG_INFO(priv, FW_DOWNLOAD, "barker download request 0x%x is:\n",
+                       priv->barker);
+       LOG_INFO(priv, FW_DOWNLOAD, "*******  Top FW %s requested ********\n",
+                       (priv->barker & BARKER_DNLOAD_TOP_MSK) ? "was" : "not");
+       LOG_INFO(priv, FW_DOWNLOAD, "*******  GPS FW %s requested ********\n",
+                       (priv->barker & BARKER_DNLOAD_GPS_MSK) ? "was" : "not");
+       LOG_INFO(priv, FW_DOWNLOAD, "*******  BT FW %s requested ********\n",
+                       (priv->barker & BARKER_DNLOAD_BT_MSK) ? "was" : "not");
+
 
        /* get the firmware */
        ret = request_firmware(&raw, fw_name, &priv->func->dev);
@@ -317,6 +324,7 @@ int iwmct_fw_load(struct iwmct_priv *priv)
 
        LOG_INFO(priv, FW_DOWNLOAD, "Read firmware '%s'\n", fw_name);
 
+       /* clear parser struct */
        ret = iwmct_fw_parser_init(priv, raw->data, raw->size, priv->trans_len);
        if (ret < 0) {
                LOG_ERROR(priv, FW_DOWNLOAD,
@@ -324,7 +332,6 @@ int iwmct_fw_load(struct iwmct_priv *priv)
                goto exit;
        }
 
-       /* checksum  */
        if (!iwmct_checksum(priv)) {
                LOG_ERROR(priv, FW_DOWNLOAD, "checksum error\n");
                ret = -EINVAL;
@@ -333,23 +340,18 @@ int iwmct_fw_load(struct iwmct_priv *priv)
 
        /* download firmware to device */
        while (iwmct_parse_next_section(priv, &pdata, &len, &addr)) {
-               if (iwmct_download_section(priv, pdata, len, addr)) {
+               ret = iwmct_download_section(priv, pdata, len, addr);
+               if (ret) {
                        LOG_ERROR(priv, FW_DOWNLOAD,
                                  "%s download section failed\n", fw_name);
-                       ret = -EIO;
                        goto exit;
                }
        }
 
-       iwmct_kick_fw(priv, !!(priv->barker & BARKER_DNLOAD_JUMP_MSK));
+       ret = iwmct_kick_fw(priv, !!(priv->barker & BARKER_DNLOAD_JUMP_MSK));
 
 exit:
        kfree(priv->parser.buf);
-
-       if (raw)
-               release_firmware(raw);
-
-       raw = NULL;
-
+       release_firmware(raw);
        return ret;
 }
index 43bd510e18720512841451a3620d140c7838ce6d..740ff0738ea8797d809263812b7cea72752281f4 100644 (file)
@@ -196,9 +196,7 @@ struct iwmct_priv {
        struct list_head read_req_list;
 };
 
-extern int iwmct_tx(struct iwmct_priv *priv, unsigned int addr,
-               void *src, int count);
-
+extern int iwmct_tx(struct iwmct_priv *priv, void *src, int count);
 extern int iwmct_fw_load(struct iwmct_priv *priv);
 
 extern void iwmct_dbg_init_params(struct iwmct_priv *drv);
index aba8121f978ca743e52ae9cdf1a2473ee1e28e02..4434bb16cea70798d846eac4c0ebd41437361c06 100644 (file)
 #define LOG_SEV_INFO                   3
 #define LOG_SEV_INFOEX                 4
 
-#define LOG_SEV_FILTER_ALL             \
-       (BIT(LOG_SEV_CRITICAL) |        \
-        BIT(LOG_SEV_ERROR)    |        \
-        BIT(LOG_SEV_WARNING)  |        \
-        BIT(LOG_SEV_INFO)     |        \
+/* Log levels not defined for FW */
+#define LOG_SEV_TRACE                  5
+#define LOG_SEV_DUMP                   6
+
+#define LOG_SEV_FW_FILTER_ALL          \
+       (BIT(LOG_SEV_CRITICAL)  |       \
+        BIT(LOG_SEV_ERROR)     |       \
+        BIT(LOG_SEV_WARNING)   |       \
+        BIT(LOG_SEV_INFO)      |       \
         BIT(LOG_SEV_INFOEX))
 
+#define LOG_SEV_FILTER_ALL             \
+       (BIT(LOG_SEV_CRITICAL)  |       \
+        BIT(LOG_SEV_ERROR)     |       \
+        BIT(LOG_SEV_WARNING)   |       \
+        BIT(LOG_SEV_INFO)      |       \
+        BIT(LOG_SEV_INFOEX)    |       \
+        BIT(LOG_SEV_TRACE)     |       \
+        BIT(LOG_SEV_DUMP))
+
 /* log source */
 #define LOG_SRC_INIT                   0
 #define LOG_SRC_DEBUGFS                        1
@@ -104,16 +117,16 @@ do {                                                                      \
                         __func__, __LINE__, ##args);                   \
 } while (0)
 
-#define LOG_INFOEX(priv, src, fmt, args...)                            \
+#define LOG_TRACE(priv, src, fmt, args...)                             \
 do {                                                                   \
-       if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_INFOEX))       \
+       if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_TRACE))        \
                dev_dbg(priv2dev(priv), "%s %d: " fmt,                  \
                         __func__, __LINE__, ##args);                   \
 } while (0)
 
 #define LOG_HEXDUMP(src, ptr, len)                                     \
 do {                                                                   \
-       if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_INFOEX))       \
+       if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_DUMP)) \
                print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_NONE,        \
                                16, 1, ptr, len, false);                \
 } while (0)
@@ -142,7 +155,7 @@ ssize_t store_iwmct_log_level_fw(struct device *d,
 #define LOG_ERROR(priv, src, fmt, args...)
 #define LOG_WARNING(priv, src, fmt, args...)
 #define LOG_INFO(priv, src, fmt, args...)
-#define LOG_INFOEX(priv, src, fmt, args...)
+#define LOG_TRACE(priv, src, fmt, args...)
 #define LOG_HEXDUMP(src, ptr, len)
 
 static inline void iwmct_log_top_message(struct iwmct_priv *priv,
index fafcaa481d74a29b14a9080f002ec81d8200b51b..dd0a3913bf6d00cd14dfec797fa89026b4218d87 100644 (file)
@@ -49,6 +49,20 @@ MODULE_LICENSE("GPL");
 MODULE_AUTHOR(DRIVER_COPYRIGHT);
 MODULE_FIRMWARE(FW_NAME(FW_API_VER));
 
+
+static inline int __iwmct_tx(struct iwmct_priv *priv, void *src, int count)
+{
+       return sdio_memcpy_toio(priv->func, IWMC_SDIO_DATA_ADDR, src, count);
+
+}
+int iwmct_tx(struct iwmct_priv *priv, void *src, int count)
+{
+       int ret;
+       sdio_claim_host(priv->func);
+       ret =  __iwmct_tx(priv, src, count);
+       sdio_release_host(priv->func);
+       return ret;
+}
 /*
  * This workers main task is to wait for OP_OPR_ALIVE
  * from TOP FW until ALIVE_MSG_TIMOUT timeout is elapsed.
@@ -66,7 +80,7 @@ static void iwmct_rescan_worker(struct work_struct *ws)
 
        ret = bus_rescan_devices(priv->func->dev.bus);
        if (ret < 0)
-               LOG_INFO(priv, FW_DOWNLOAD, "bus_rescan_devices FAILED!!!\n");
+               LOG_INFO(priv, INIT, "bus_rescan_devices FAILED!!!\n");
 }
 
 static void op_top_message(struct iwmct_priv *priv, struct top_msg *msg)
@@ -137,7 +151,7 @@ int iwmct_send_hcmd(struct iwmct_priv *priv, u8 *cmd, u16 len)
        int ret;
        u8 *buf;
 
-       LOG_INFOEX(priv, FW_MSG, "Sending hcmd:\n");
+       LOG_TRACE(priv, FW_MSG, "Sending hcmd:\n");
 
        /* add padding to 256 for IWMC */
        ((struct top_msg *)cmd)->hdr.flags |= CMD_FLAG_PADDING_256;
@@ -158,27 +172,12 @@ int iwmct_send_hcmd(struct iwmct_priv *priv, u8 *cmd, u16 len)
        }
 
        memcpy(buf, cmd, len);
-
-       sdio_claim_host(priv->func);
-       ret = sdio_memcpy_toio(priv->func, IWMC_SDIO_DATA_ADDR, buf,
-                              FW_HCMD_BLOCK_SIZE);
-       sdio_release_host(priv->func);
+       ret = iwmct_tx(priv, buf, FW_HCMD_BLOCK_SIZE);
 
        kfree(buf);
        return ret;
 }
 
-int iwmct_tx(struct iwmct_priv *priv, unsigned int addr,
-       void *src, int count)
-{
-       int ret;
-
-       sdio_claim_host(priv->func);
-       ret = sdio_memcpy_toio(priv->func, addr, src, count);
-       sdio_release_host(priv->func);
-
-       return ret;
-}
 
 static void iwmct_irq_read_worker(struct work_struct *ws)
 {
@@ -192,7 +191,7 @@ static void iwmct_irq_read_worker(struct work_struct *ws)
 
        priv = container_of(ws, struct iwmct_priv, isr_worker);
 
-       LOG_INFO(priv, IRQ, "enter iwmct_irq_read_worker %p\n", ws);
+       LOG_TRACE(priv, IRQ, "enter iwmct_irq_read_worker %p\n", ws);
 
        /* --------------------- Handshake with device -------------------- */
        sdio_claim_host(priv->func);
@@ -273,8 +272,7 @@ static void iwmct_irq_read_worker(struct work_struct *ws)
 
                if (barker & BARKER_DNLOAD_SYNC_MSK) {
                        /* Send the same barker back */
-                       ret = sdio_memcpy_toio(priv->func, IWMC_SDIO_DATA_ADDR,
-                                              buf, iosize);
+                       ret = __iwmct_tx(priv, buf, iosize);
                        if (ret) {
                                LOG_ERROR(priv, IRQ,
                                         "error %d echoing barker\n", ret);
@@ -292,15 +290,6 @@ static void iwmct_irq_read_worker(struct work_struct *ws)
 
        sdio_release_host(priv->func);
 
-
-       LOG_INFO(priv, IRQ, "barker download request 0x%x is:\n", priv->barker);
-       LOG_INFO(priv, IRQ, "*******  Top FW %s requested ********\n",
-                       (priv->barker & BARKER_DNLOAD_TOP_MSK) ? "was" : "not");
-       LOG_INFO(priv, IRQ, "*******  GPS FW %s requested ********\n",
-                       (priv->barker & BARKER_DNLOAD_GPS_MSK) ? "was" : "not");
-       LOG_INFO(priv, IRQ, "*******  BT FW %s requested ********\n",
-                       (priv->barker & BARKER_DNLOAD_BT_MSK) ? "was" : "not");
-
        if (priv->dbg.fw_download)
                iwmct_fw_load(priv);
        else
@@ -312,7 +301,7 @@ exit_release:
        sdio_release_host(priv->func);
 exit:
        kfree(buf);
-       LOG_INFO(priv, IRQ, "exit iwmct_irq_read_worker\n");
+       LOG_TRACE(priv, IRQ, "exit iwmct_irq_read_worker\n");
 }
 
 static void iwmct_irq(struct sdio_func *func)
@@ -325,12 +314,12 @@ static void iwmct_irq(struct sdio_func *func)
 
        priv = sdio_get_drvdata(func);
 
-       LOG_INFO(priv, IRQ, "enter iwmct_irq\n");
+       LOG_TRACE(priv, IRQ, "enter iwmct_irq\n");
 
        /* read the function's status register */
        val = sdio_readb(func, IWMC_SDIO_INTR_STATUS_ADDR, &ret);
 
-       LOG_INFO(priv, IRQ, "iir value = %d, ret=%d\n", val, ret);
+       LOG_TRACE(priv, IRQ, "iir value = %d, ret=%d\n", val, ret);
 
        if (!val) {
                LOG_ERROR(priv, IRQ, "iir = 0, exiting ISR\n");
@@ -372,7 +361,7 @@ static void iwmct_irq(struct sdio_func *func)
 
        queue_work(priv->wq, &priv->isr_worker);
 
-       LOG_INFO(priv, IRQ, "exit iwmct_irq\n");
+       LOG_TRACE(priv, IRQ, "exit iwmct_irq\n");
 
        return;
 
@@ -660,7 +649,7 @@ static int __init iwmct_init(void)
 
        /* Default log filter settings */
        iwmct_log_set_filter(LOG_SRC_ALL, LOG_SEV_FILTER_RUNTIME);
-       iwmct_log_set_filter(LOG_SRC_FW_MSG, LOG_SEV_FILTER_ALL);
+       iwmct_log_set_filter(LOG_SRC_FW_MSG, LOG_SEV_FW_FILTER_ALL);
        iwmct_log_set_fw_filter(LOG_SRC_ALL, FW_LOG_SEV_FILTER_RUNTIME);
 
        rc = sdio_register_driver(&iwmct_driver);
index 39db0e96815dfba17d6dc8cab444a8181c06da71..5df46c230b073c437a493fa37e4842c1e56e9d74 100644 (file)
@@ -375,7 +375,7 @@ static struct vortex_chip_info {
 };
 
 
-static struct pci_device_id vortex_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(vortex_pci_tbl) = {
        { 0x10B7, 0x5900, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C590 },
        { 0x10B7, 0x5920, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C592 },
        { 0x10B7, 0x5970, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C597 },
index 3f452bcbfb9e857f49161131b39c4f770b4ad377..9d59654748b1a7ce1f3acfeb55bda3c3375be3af 100644 (file)
@@ -394,7 +394,7 @@ static int cp_get_eeprom(struct net_device *dev,
 static int cp_set_eeprom(struct net_device *dev,
                         struct ethtool_eeprom *eeprom, u8 *data);
 
-static struct pci_device_id cp_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(cp_pci_tbl) = {
        { PCI_DEVICE(PCI_VENDOR_ID_REALTEK,     PCI_DEVICE_ID_REALTEK_8139), },
        { PCI_DEVICE(PCI_VENDOR_ID_TTTECH,      PCI_DEVICE_ID_TTTECH_MC322), },
        { },
index 25f7339daabd61f86c149e890ac3e3bd02240ecc..321e73aabb2b18f1be9e096be30253ba0925d120 100644 (file)
@@ -231,7 +231,7 @@ static const struct {
 };
 
 
-static struct pci_device_id rtl8139_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(rtl8139_pci_tbl) = {
        {0x10ec, 0x8139, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
        {0x10ec, 0x8138, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
        {0x1113, 0x1211, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
index dd9a09c72dfff2b080f09499a4afe8d6b2ad68ad..cb0e534418e3033263304d1c4caaf92a3b78d421 100644 (file)
@@ -2618,6 +2618,28 @@ config IXGBE_DCB
 
          If unsure, say N.
 
+config IXGBEVF
+       tristate "Intel(R) 82599 Virtual Function Ethernet support"
+       depends on PCI_MSI
+       ---help---
+         This driver supports Intel(R) 82599 virtual functions.  For more
+         information on how to identify your adapter, go to the Adapter &
+         Driver ID Guide at:
+
+         <http://support.intel.com/support/network/sb/CS-008441.htm>
+
+         For general information and support, go to the Intel support
+         website at:
+
+         <http://support.intel.com>
+
+         More specific information on configuring the driver is in
+         <file:Documentation/networking/ixgbevf.txt>.
+
+         To compile this driver as a module, choose M here. The module
+         will be called ixgbevf.  MSI-X interrupt support is required
+         for this driver to work correctly.
+
 config IXGB
        tristate "Intel(R) PRO/10GbE support"
        depends on PCI
@@ -2756,6 +2778,13 @@ config BNX2X
          To compile this driver as a module, choose M here: the module
          will be called bnx2x.  This is recommended.
 
+config QLCNIC
+       tristate "QLOGIC QLCNIC 1/10Gb Converged Ethernet NIC Support"
+       depends on PCI
+       help
+         This driver supports QLogic QLE8240 and QLE8242 Converged Ethernet
+         devices.
+
 config QLGE
        tristate "QLogic QLGE 10Gb Ethernet Driver Support"
        depends on PCI
index ad1346dd9da9e3e0f5a2558f1f0c1e8478a53fba..0b763cbe9b1f23c09a3096df2d395241112abe21 100644 (file)
@@ -14,6 +14,7 @@ obj-$(CONFIG_IBM_NEW_EMAC) += ibm_newemac/
 obj-$(CONFIG_IGB) += igb/
 obj-$(CONFIG_IGBVF) += igbvf/
 obj-$(CONFIG_IXGBE) += ixgbe/
+obj-$(CONFIG_IXGBEVF) += ixgbevf/
 obj-$(CONFIG_IXGB) += ixgb/
 obj-$(CONFIG_IP1000) += ipg.o
 obj-$(CONFIG_CHELSIO_T1) += chelsio/
@@ -148,6 +149,7 @@ ll_temac-objs := ll_temac_main.o ll_temac_mdio.o
 obj-$(CONFIG_XILINX_LL_TEMAC) += ll_temac.o
 obj-$(CONFIG_XILINX_EMACLITE) += xilinx_emaclite.o
 obj-$(CONFIG_QLA3XXX) += qla3xxx.o
+obj-$(CONFIG_QLCNIC) += qlcnic/
 obj-$(CONFIG_QLGE) += qlge/
 
 obj-$(CONFIG_PPP) += ppp_generic.o
index d82a9a994753c2a8061bd5102be797767bcaf2b6..ec624ab03e88de9d51d6953df780f8d01956d72e 100644 (file)
 #define PCI_DEVICE_ID_SGI_ACENIC       0x0009
 #endif
 
-static struct pci_device_id acenic_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(acenic_pci_tbl) = {
        { PCI_VENDOR_ID_ALTEON, PCI_DEVICE_ID_ALTEON_ACENIC_FIBRE,
          PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, },
        { PCI_VENDOR_ID_ALTEON, PCI_DEVICE_ID_ALTEON_ACENIC_COPPER,
index 766aabfdfc755ee6b18b862fa482b2987e13e2cd..bb27b27d967287e32650f81ca6cedbd6f5aa53ae 100644 (file)
@@ -113,7 +113,7 @@ MODULE_PARM_DESC(coalesce, "Enable or Disable interrupt coalescing, 1: Enable, 0
 module_param_array(dynamic_ipg, bool, NULL, 0);
 MODULE_PARM_DESC(dynamic_ipg, "Enable or Disable dynamic IPG, 1: Enable, 0: Disable");
 
-static struct pci_device_id amd8111e_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(amd8111e_pci_tbl) = {
 
        { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD8111E_7462,
         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
@@ -1176,8 +1176,7 @@ static irqreturn_t amd8111e_interrupt(int irq, void *dev_id)
                        /* Schedule a polling routine */
                        __napi_schedule(&lp->napi);
                } else if (intren0 & RINTEN0) {
-                       printk("************Driver bug! \
-                               interrupt while in poll\n");
+                       printk("************Driver bug! interrupt while in poll\n");
                        /* Fix by disable receive interrupts */
                        writel(RINTEN0, mmio + INTEN0);
                }
index dbf4de39754d1f4009edfdb02f4bfa1e80e56baa..b68e1eb405ff4d4622c59ef453fc9ecb0b608fab 100644 (file)
@@ -144,7 +144,7 @@ static void __devexit com20020pci_remove(struct pci_dev *pdev)
        free_netdev(dev);
 }
 
-static struct pci_device_id com20020pci_id_table[] = {
+static DEFINE_PCI_DEVICE_TABLE(com20020pci_id_table) = {
        { 0x1571, 0xa001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
        { 0x1571, 0xa002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
        { 0x1571, 0xa003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
index c35af3e106b1fa38355993c7b53865f488682d52..e2c202493fa797ef3b2a473e662ea91a141381cc 100644 (file)
@@ -123,9 +123,7 @@ static void ariadne_reset(struct net_device *dev);
 static irqreturn_t ariadne_interrupt(int irq, void *data);
 static int ariadne_close(struct net_device *dev);
 static struct net_device_stats *ariadne_get_stats(struct net_device *dev);
-#ifdef HAVE_MULTICAST
 static void set_multicast_list(struct net_device *dev);
-#endif
 
 
 static void memcpyw(volatile u_short *dest, u_short *src, int len)
index b25467ac895c3e8f232506030665c398fe80f73e..bf72d57a0afdab7c8f48467d9b7d664935ea8144 100644 (file)
@@ -9,6 +9,8 @@
  * (at your option) any later version.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
+
 #include <linux/dma-mapping.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -20,9 +22,9 @@
 #include <linux/moduleparam.h>
 #include <linux/platform_device.h>
 #include <linux/delay.h>
-#include <mach/ep93xx-regs.h>
-#include <mach/platform.h>
-#include <asm/io.h>
+#include <linux/io.h>
+
+#include <mach/hardware.h>
 
 #define DRV_MODULE_NAME                "ep93xx-eth"
 #define DRV_MODULE_VERSION     "0.1"
@@ -185,7 +187,47 @@ struct ep93xx_priv
 #define wrw(ep, off, val)      __raw_writew((val), (ep)->base_addr + (off))
 #define wrl(ep, off, val)      __raw_writel((val), (ep)->base_addr + (off))
 
-static int ep93xx_mdio_read(struct net_device *dev, int phy_id, int reg);
+static int ep93xx_mdio_read(struct net_device *dev, int phy_id, int reg)
+{
+       struct ep93xx_priv *ep = netdev_priv(dev);
+       int data;
+       int i;
+
+       wrl(ep, REG_MIICMD, REG_MIICMD_READ | (phy_id << 5) | reg);
+
+       for (i = 0; i < 10; i++) {
+               if ((rdl(ep, REG_MIISTS) & REG_MIISTS_BUSY) == 0)
+                       break;
+               msleep(1);
+       }
+
+       if (i == 10) {
+               pr_info("mdio read timed out\n");
+               data = 0xffff;
+       } else {
+               data = rdl(ep, REG_MIIDATA);
+       }
+
+       return data;
+}
+
+static void ep93xx_mdio_write(struct net_device *dev, int phy_id, int reg, int data)
+{
+       struct ep93xx_priv *ep = netdev_priv(dev);
+       int i;
+
+       wrl(ep, REG_MIIDATA, data);
+       wrl(ep, REG_MIICMD, REG_MIICMD_WRITE | (phy_id << 5) | reg);
+
+       for (i = 0; i < 10; i++) {
+               if ((rdl(ep, REG_MIISTS) & REG_MIISTS_BUSY) == 0)
+                       break;
+               msleep(1);
+       }
+
+       if (i == 10)
+               pr_info("mdio write timed out\n");
+}
 
 static struct net_device_stats *ep93xx_get_stats(struct net_device *dev)
 {
@@ -217,14 +259,11 @@ static int ep93xx_rx(struct net_device *dev, int processed, int budget)
                rstat->rstat1 = 0;
 
                if (!(rstat0 & RSTAT0_EOF))
-                       printk(KERN_CRIT "ep93xx_rx: not end-of-frame "
-                                        " %.8x %.8x\n", rstat0, rstat1);
+                       pr_crit("not end-of-frame %.8x %.8x\n", rstat0, rstat1);
                if (!(rstat0 & RSTAT0_EOB))
-                       printk(KERN_CRIT "ep93xx_rx: not end-of-buffer "
-                                        " %.8x %.8x\n", rstat0, rstat1);
+                       pr_crit("not end-of-buffer %.8x %.8x\n", rstat0, rstat1);
                if ((rstat1 & RSTAT1_BUFFER_INDEX) >> 16 != entry)
-                       printk(KERN_CRIT "ep93xx_rx: entry mismatch "
-                                        " %.8x %.8x\n", rstat0, rstat1);
+                       pr_crit("entry mismatch %.8x %.8x\n", rstat0, rstat1);
 
                if (!(rstat0 & RSTAT0_RWE)) {
                        ep->stats.rx_errors++;
@@ -241,8 +280,7 @@ static int ep93xx_rx(struct net_device *dev, int processed, int budget)
 
                length = rstat1 & RSTAT1_FRAME_LENGTH;
                if (length > MAX_PKT_SIZE) {
-                       printk(KERN_NOTICE "ep93xx_rx: invalid length "
-                                        " %.8x %.8x\n", rstat0, rstat1);
+                       pr_notice("invalid length %.8x %.8x\n", rstat0, rstat1);
                        goto err;
                }
 
@@ -371,11 +409,9 @@ static void ep93xx_tx_complete(struct net_device *dev)
                tstat->tstat0 = 0;
 
                if (tstat0 & TSTAT0_FA)
-                       printk(KERN_CRIT "ep93xx_tx_complete: frame aborted "
-                                        " %.8x\n", tstat0);
+                       pr_crit("frame aborted %.8x\n", tstat0);
                if ((tstat0 & TSTAT0_BUFFER_INDEX) != entry)
-                       printk(KERN_CRIT "ep93xx_tx_complete: entry mismatch "
-                                        " %.8x\n", tstat0);
+                       pr_crit("entry mismatch %.8x\n", tstat0);
 
                if (tstat0 & TSTAT0_TXWE) {
                        int length = ep->descs->tdesc[entry].tdesc1 & 0xfff;
@@ -536,7 +572,7 @@ static int ep93xx_start_hw(struct net_device *dev)
        }
 
        if (i == 10) {
-               printk(KERN_CRIT DRV_MODULE_NAME ": hw failed to reset\n");
+               pr_crit("hw failed to reset\n");
                return 1;
        }
 
@@ -581,7 +617,7 @@ static int ep93xx_start_hw(struct net_device *dev)
        }
 
        if (i == 10) {
-               printk(KERN_CRIT DRV_MODULE_NAME ": hw failed to start\n");
+               pr_crit("hw failed to start\n");
                return 1;
        }
 
@@ -617,7 +653,7 @@ static void ep93xx_stop_hw(struct net_device *dev)
        }
 
        if (i == 10)
-               printk(KERN_CRIT DRV_MODULE_NAME ": hw failed to reset\n");
+               pr_crit("hw failed to reset\n");
 }
 
 static int ep93xx_open(struct net_device *dev)
@@ -681,48 +717,6 @@ static int ep93xx_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
        return generic_mii_ioctl(&ep->mii, data, cmd, NULL);
 }
 
-static int ep93xx_mdio_read(struct net_device *dev, int phy_id, int reg)
-{
-       struct ep93xx_priv *ep = netdev_priv(dev);
-       int data;
-       int i;
-
-       wrl(ep, REG_MIICMD, REG_MIICMD_READ | (phy_id << 5) | reg);
-
-       for (i = 0; i < 10; i++) {
-               if ((rdl(ep, REG_MIISTS) & REG_MIISTS_BUSY) == 0)
-                       break;
-               msleep(1);
-       }
-
-       if (i == 10) {
-               printk(KERN_INFO DRV_MODULE_NAME ": mdio read timed out\n");
-               data = 0xffff;
-       } else {
-               data = rdl(ep, REG_MIIDATA);
-       }
-
-       return data;
-}
-
-static void ep93xx_mdio_write(struct net_device *dev, int phy_id, int reg, int data)
-{
-       struct ep93xx_priv *ep = netdev_priv(dev);
-       int i;
-
-       wrl(ep, REG_MIIDATA, data);
-       wrl(ep, REG_MIICMD, REG_MIICMD_WRITE | (phy_id << 5) | reg);
-
-       for (i = 0; i < 10; i++) {
-               if ((rdl(ep, REG_MIISTS) & REG_MIISTS_BUSY) == 0)
-                       break;
-               msleep(1);
-       }
-
-       if (i == 10)
-               printk(KERN_INFO DRV_MODULE_NAME ": mdio write timed out\n");
-}
-
 static void ep93xx_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
        strcpy(info->driver, DRV_MODULE_NAME);
@@ -825,12 +819,19 @@ static int ep93xx_eth_probe(struct platform_device *pdev)
        struct ep93xx_eth_data *data;
        struct net_device *dev;
        struct ep93xx_priv *ep;
+       struct resource *mem;
+       int irq;
        int err;
 
        if (pdev == NULL)
                return -ENODEV;
        data = pdev->dev.platform_data;
 
+       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       irq = platform_get_irq(pdev, 0);
+       if (!mem || irq < 0)
+               return -ENXIO;
+
        dev = ep93xx_dev_alloc(data);
        if (dev == NULL) {
                err = -ENOMEM;
@@ -842,23 +843,21 @@ static int ep93xx_eth_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, dev);
 
-       ep->res = request_mem_region(pdev->resource[0].start,
-                       pdev->resource[0].end - pdev->resource[0].start + 1,
-                       dev_name(&pdev->dev));
+       ep->res = request_mem_region(mem->start, resource_size(mem),
+                                    dev_name(&pdev->dev));
        if (ep->res == NULL) {
                dev_err(&pdev->dev, "Could not reserve memory region\n");
                err = -ENOMEM;
                goto err_out;
        }
 
-       ep->base_addr = ioremap(pdev->resource[0].start,
-                       pdev->resource[0].end - pdev->resource[0].start);
+       ep->base_addr = ioremap(mem->start, resource_size(mem));
        if (ep->base_addr == NULL) {
                dev_err(&pdev->dev, "Failed to ioremap ethernet registers\n");
                err = -EIO;
                goto err_out;
        }
-       ep->irq = pdev->resource[1].start;
+       ep->irq = irq;
 
        ep->mii.phy_id = data->phy_id;
        ep->mii.phy_id_mask = 0x1f;
@@ -877,11 +876,8 @@ static int ep93xx_eth_probe(struct platform_device *pdev)
                goto err_out;
        }
 
-       printk(KERN_INFO "%s: ep93xx on-chip ethernet, IRQ %d, "
-                        "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x.\n", dev->name,
-                       ep->irq, data->dev_addr[0], data->dev_addr[1],
-                       data->dev_addr[2], data->dev_addr[3],
-                       data->dev_addr[4], data->dev_addr[5]);
+       printk(KERN_INFO "%s: ep93xx on-chip ethernet, IRQ %d, %pM\n",
+                       dev->name, ep->irq, dev->dev_addr);
 
        return 0;
 
index 2f4be59b9c0bfd29c8efd838f8b6da1ec03f5eb0..d98095df05bec8c316c3ae6dc43d42586d138e64 100644 (file)
@@ -35,7 +35,7 @@ char atl1c_driver_version[] = ATL1C_DRV_VERSION;
  * { Vendor ID, Device ID, SubVendor ID, SubDevice ID,
  *   Class, Class Mask, private data (not used) }
  */
-static struct pci_device_id atl1c_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(atl1c_pci_tbl) = {
        {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATTANSIC_L1C)},
        {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATTANSIC_L2C)},
        /* required last entry */
@@ -2596,11 +2596,8 @@ static int __devinit atl1c_probe(struct pci_dev *pdev,
        memcpy(netdev->dev_addr, adapter->hw.mac_addr, netdev->addr_len);
        memcpy(netdev->perm_addr, adapter->hw.mac_addr, netdev->addr_len);
        if (netif_msg_probe(adapter))
-               dev_dbg(&pdev->dev,
-                       "mac address : %02x-%02x-%02x-%02x-%02x-%02x\n",
-                       adapter->hw.mac_addr[0], adapter->hw.mac_addr[1],
-                       adapter->hw.mac_addr[2], adapter->hw.mac_addr[3],
-                       adapter->hw.mac_addr[4], adapter->hw.mac_addr[5]);
+               dev_dbg(&pdev->dev, "mac address : %pM\n",
+                       adapter->hw.mac_addr);
 
        atl1c_hw_set_mac_addr(&adapter->hw);
        INIT_WORK(&adapter->common_task, atl1c_common_task);
index 08f8c0969e9bb02eef11bf26dcdfa2a615cfe2ce..d59f8e89c65d9f5b0e678ca0ee27794fdacb97bb 100644 (file)
@@ -35,7 +35,7 @@ char atl1e_driver_version[] = DRV_VERSION;
  * { Vendor ID, Device ID, SubVendor ID, SubDevice ID,
  *   Class, Class Mask, private data (not used) }
  */
-static struct pci_device_id atl1e_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(atl1e_pci_tbl) = {
        {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATTANSIC_L1E)},
        {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, 0x1066)},
        /* required last entry */
@@ -2378,10 +2378,7 @@ static int __devinit atl1e_probe(struct pci_dev *pdev,
 
        memcpy(netdev->dev_addr, adapter->hw.mac_addr, netdev->addr_len);
        memcpy(netdev->perm_addr, adapter->hw.mac_addr, netdev->addr_len);
-       dev_dbg(&pdev->dev, "mac address : %02x-%02x-%02x-%02x-%02x-%02x\n",
-                       adapter->hw.mac_addr[0], adapter->hw.mac_addr[1],
-                       adapter->hw.mac_addr[2], adapter->hw.mac_addr[3],
-                       adapter->hw.mac_addr[4], adapter->hw.mac_addr[5]);
+       dev_dbg(&pdev->dev, "mac address : %pM\n", adapter->hw.mac_addr);
 
        INIT_WORK(&adapter->reset_task, atl1e_reset_task);
        INIT_WORK(&adapter->link_chg_task, atl1e_link_chg_task);
index b6cf3263127c77be7b7dd3f68521e3fb910aa1a4..9ba547069db3c44d13005532e550837ea1bb8350 100644 (file)
@@ -232,7 +232,7 @@ static void __devinit atl1_check_options(struct atl1_adapter *adapter)
 /*
  * atl1_pci_tbl - PCI Device ID Table
  */
-static const struct pci_device_id atl1_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(atl1_pci_tbl) = {
        {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATTANSIC_L1)},
        /* required last entry */
        {0,}
index ec52529394ad27c7f04f1a5a6b0868bd17c1ca6f..40cf9e5cb9e2b90a6bbfe812580df8d8bf35e8f3 100644 (file)
@@ -63,7 +63,7 @@ MODULE_VERSION(ATL2_DRV_VERSION);
 /*
  * atl2_pci_tbl - PCI Device ID Table
  */
-static struct pci_device_id atl2_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(atl2_pci_tbl) = {
        {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATTANSIC_L2)},
        /* required last entry */
        {0,}
index 4869adb695865a3f7dc4ff3bacd1ee5a260b296d..44b66be38134b34fec5c000f06080967260d8e89 100644 (file)
@@ -102,7 +102,7 @@ MODULE_PARM_DESC(b44_debug, "B44 bitmapped debugging message enable value");
 
 
 #ifdef CONFIG_B44_PCI
-static const struct pci_device_id b44_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(b44_pci_tbl) = {
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401) },
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401B0) },
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401B1) },
index fee6eee7ae5ba583bf345a79a4be188fbdd2345d..3227b11131c470dd00f7a5a7fb47054f9165007b 100644 (file)
@@ -1607,3 +1607,33 @@ err:
        spin_unlock_bh(&adapter->mcc_lock);
        return status;
 }
+
+extern int be_cmd_get_seeprom_data(struct be_adapter *adapter,
+                               struct be_dma_mem *nonemb_cmd)
+{
+       struct be_mcc_wrb *wrb;
+       struct be_cmd_req_seeprom_read *req;
+       struct be_sge *sge;
+       int status;
+
+       spin_lock_bh(&adapter->mcc_lock);
+
+       wrb = wrb_from_mccq(adapter);
+       req = nonemb_cmd->va;
+       sge = nonembedded_sgl(wrb);
+
+       be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1,
+                       OPCODE_COMMON_SEEPROM_READ);
+
+       be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+                       OPCODE_COMMON_SEEPROM_READ, sizeof(*req));
+
+       sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma));
+       sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF);
+       sge->len = cpu_to_le32(nonemb_cmd->size);
+
+       status = be_mcc_notify_wait(adapter);
+
+       spin_unlock_bh(&adapter->mcc_lock);
+       return status;
+}
index 13b33c841083ae9e446fa35cd4a2cd8e777a1c85..c622a968c37956fbaa8ceb92044dd2caeb557f60 100644 (file)
@@ -124,6 +124,7 @@ struct be_mcc_mailbox {
 #define OPCODE_COMMON_CQ_CREATE                                12
 #define OPCODE_COMMON_EQ_CREATE                                13
 #define OPCODE_COMMON_MCC_CREATE                       21
+#define OPCODE_COMMON_SEEPROM_READ                     30
 #define OPCODE_COMMON_NTWK_RX_FILTER                   34
 #define OPCODE_COMMON_GET_FW_VERSION                   35
 #define OPCODE_COMMON_SET_FLOW_CONTROL                 36
@@ -855,6 +856,19 @@ struct be_cmd_resp_ddrdma_test {
        u8  rcv_buff[4096];
 };
 
+/*********************** SEEPROM Read ***********************/
+
+#define BE_READ_SEEPROM_LEN 1024
+struct be_cmd_req_seeprom_read {
+       struct be_cmd_req_hdr hdr;
+       u8 rsvd0[BE_READ_SEEPROM_LEN];
+};
+
+struct be_cmd_resp_seeprom_read {
+       struct be_cmd_req_hdr hdr;
+       u8 seeprom_data[BE_READ_SEEPROM_LEN];
+};
+
 extern int be_pci_fnum_get(struct be_adapter *adapter);
 extern int be_cmd_POST(struct be_adapter *adapter);
 extern int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr,
@@ -927,5 +941,8 @@ extern int be_cmd_loopback_test(struct be_adapter *adapter, u32 port_num,
                                u32 num_pkts, u64 pattern);
 extern int be_cmd_ddr_dma_test(struct be_adapter *adapter, u64 pattern,
                        u32 byte_cnt, struct be_dma_mem *cmd);
+extern int be_cmd_get_seeprom_data(struct be_adapter *adapter,
+                               struct be_dma_mem *nonemb_cmd);
 extern int be_cmd_set_loopback(struct be_adapter *adapter, u8 port_num,
                                u8 loopback_type, u8 enable);
+
index 5d001c4deac1d3b8684c91261cb0c15769c96cfa..09d8899b2de93c3382daf374e74742bc42fabf3c 100644 (file)
@@ -112,6 +112,7 @@ static const char et_self_tests[][ETH_GSTRING_LEN] = {
        "PHY Loopback test",
        "External Loopback test",
        "DDR DMA test"
+       "Link test"
 };
 
 #define ETHTOOL_TESTS_NUM ARRAY_SIZE(et_self_tests)
@@ -529,6 +530,9 @@ static void
 be_self_test(struct net_device *netdev, struct ethtool_test *test, u64 *data)
 {
        struct be_adapter *adapter = netdev_priv(netdev);
+       bool link_up;
+       u8 mac_speed = 0;
+       u16 qos_link_speed = 0;
 
        memset(data, 0, sizeof(u64) * ETHTOOL_TESTS_NUM);
 
@@ -545,12 +549,20 @@ be_self_test(struct net_device *netdev, struct ethtool_test *test, u64 *data)
                                                &data[2]) != 0) {
                        test->flags |= ETH_TEST_FL_FAILED;
                }
+       }
 
-               data[3] = be_test_ddr_dma(adapter);
-               if (data[3] != 0)
-                       test->flags |= ETH_TEST_FL_FAILED;
+       if (be_test_ddr_dma(adapter) != 0) {
+               data[3] = 1;
+               test->flags |= ETH_TEST_FL_FAILED;
        }
 
+       if (be_cmd_link_status_query(adapter, &link_up, &mac_speed,
+                               &qos_link_speed) != 0) {
+               test->flags |= ETH_TEST_FL_FAILED;
+               data[4] = -1;
+       } else if (mac_speed) {
+               data[4] = 1;
+       }
 }
 
 static int
@@ -567,12 +579,57 @@ be_do_flash(struct net_device *netdev, struct ethtool_flash *efl)
        return be_load_fw(adapter, file_name);
 }
 
+static int
+be_get_eeprom_len(struct net_device *netdev)
+{
+       return BE_READ_SEEPROM_LEN;
+}
+
+static int
+be_read_eeprom(struct net_device *netdev, struct ethtool_eeprom *eeprom,
+                       uint8_t *data)
+{
+       struct be_adapter *adapter = netdev_priv(netdev);
+       struct be_dma_mem eeprom_cmd;
+       struct be_cmd_resp_seeprom_read *resp;
+       int status;
+
+       if (!eeprom->len)
+               return -EINVAL;
+
+       eeprom->magic = BE_VENDOR_ID | (adapter->pdev->device<<16);
+
+       memset(&eeprom_cmd, 0, sizeof(struct be_dma_mem));
+       eeprom_cmd.size = sizeof(struct be_cmd_req_seeprom_read);
+       eeprom_cmd.va = pci_alloc_consistent(adapter->pdev, eeprom_cmd.size,
+                               &eeprom_cmd.dma);
+
+       if (!eeprom_cmd.va) {
+               dev_err(&adapter->pdev->dev,
+                       "Memory allocation failure. Could not read eeprom\n");
+               return -ENOMEM;
+       }
+
+       status = be_cmd_get_seeprom_data(adapter, &eeprom_cmd);
+
+       if (!status) {
+               resp = (struct be_cmd_resp_seeprom_read *) eeprom_cmd.va;
+               memcpy(data, resp->seeprom_data, eeprom->len);
+       }
+       pci_free_consistent(adapter->pdev, eeprom_cmd.size, eeprom_cmd.va,
+                       eeprom_cmd.dma);
+
+       return status;
+}
+
 const struct ethtool_ops be_ethtool_ops = {
        .get_settings = be_get_settings,
        .get_drvinfo = be_get_drvinfo,
        .get_wol = be_get_wol,
        .set_wol = be_set_wol,
        .get_link = ethtool_op_get_link,
+       .get_eeprom_len = be_get_eeprom_len,
+       .get_eeprom = be_read_eeprom,
        .get_coalesce = be_get_coalesce,
        .set_coalesce = be_set_coalesce,
        .get_ringparam = be_get_ringparam,
index 65df1de447e4d8db176ee14ea8605b4ccac09be4..5917b941aca26fb4a60fa9cd9f030751069985f2 100644 (file)
@@ -48,7 +48,6 @@
 #include <linux/cache.h>
 #include <linux/firmware.h>
 #include <linux/log2.h>
-#include <linux/list.h>
 
 #if defined(CONFIG_CNIC) || defined(CONFIG_CNIC_MODULE)
 #define BCM_CNIC 1
@@ -3579,14 +3578,14 @@ bnx2_set_rx_mode(struct net_device *dev)
                sort_mode |= BNX2_RPM_SORT_USER0_MC_HSH_EN;
        }
 
-       if (dev->uc.count > BNX2_MAX_UNICAST_ADDRESSES) {
+       if (netdev_uc_count(dev) > BNX2_MAX_UNICAST_ADDRESSES) {
                rx_mode |= BNX2_EMAC_RX_MODE_PROMISCUOUS;
                sort_mode |= BNX2_RPM_SORT_USER0_PROM_EN |
                             BNX2_RPM_SORT_USER0_PROM_VLAN;
        } else if (!(dev->flags & IFF_PROMISC)) {
                /* Add all entries into to the match filter list */
                i = 0;
-               list_for_each_entry(ha, &dev->uc.list, list) {
+               netdev_for_each_uc_addr(ha, dev) {
                        bnx2_set_mac_addr(bp, ha->addr,
                                          i + BNX2_START_UNICAST_ADDRESS_INDEX);
                        sort_mode |= (1 <<
@@ -6145,6 +6144,10 @@ bnx2_enable_msix(struct bnx2 *bp, int msix_vecs)
        REG_WR(bp, BNX2_PCI_MSIX_TBL_OFF_BIR, BNX2_PCI_GRC_WINDOW2_BASE);
        REG_WR(bp, BNX2_PCI_MSIX_PBA_OFF_BIT, BNX2_PCI_GRC_WINDOW3_BASE);
 
+       /*  Need to flush the previous three writes to ensure MSI-X
+        *  is setup properly */
+       REG_RD(bp, BNX2_PCI_MSIX_CONTROL);
+
        for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) {
                msix_ent[i].entry = i;
                msix_ent[i].vector = 0;
@@ -6227,6 +6230,8 @@ bnx2_open(struct net_device *dev)
 
        atomic_set(&bp->intr_sem, 0);
 
+       memset(bp->temp_stats_blk, 0, sizeof(struct statistics_block));
+
        bnx2_enable_int(bp);
 
        if (bp->flags & BNX2_FLAG_USING_MSI) {
@@ -6538,92 +6543,121 @@ bnx2_close(struct net_device *dev)
        return 0;
 }
 
-#define GET_NET_STATS64(ctr)                                   \
+static void
+bnx2_save_stats(struct bnx2 *bp)
+{
+       u32 *hw_stats = (u32 *) bp->stats_blk;
+       u32 *temp_stats = (u32 *) bp->temp_stats_blk;
+       int i;
+
+       /* The 1st 10 counters are 64-bit counters */
+       for (i = 0; i < 20; i += 2) {
+               u32 hi;
+               u64 lo;
+
+               hi = *(temp_stats + i) + *(hw_stats + i);
+               lo = *(temp_stats + i + 1) + *(hw_stats + i + 1);
+               if (lo > 0xffffffff)
+                       hi++;
+               *(temp_stats + i) = hi;
+               *(temp_stats + i + 1) = lo & 0xffffffff;
+       }
+
+       for ( ; i < sizeof(struct statistics_block) / 4; i++)
+               *(temp_stats + i) = *(temp_stats + i) + *(hw_stats + i);
+}
+
+#define GET_64BIT_NET_STATS64(ctr)                             \
        (unsigned long) ((unsigned long) (ctr##_hi) << 32) +    \
        (unsigned long) (ctr##_lo)
 
-#define GET_NET_STATS32(ctr)           \
+#define GET_64BIT_NET_STATS32(ctr)                             \
        (ctr##_lo)
 
 #if (BITS_PER_LONG == 64)
-#define GET_NET_STATS  GET_NET_STATS64
+#define GET_64BIT_NET_STATS(ctr)                               \
+       GET_64BIT_NET_STATS64(bp->stats_blk->ctr) +             \
+       GET_64BIT_NET_STATS64(bp->temp_stats_blk->ctr)
 #else
-#define GET_NET_STATS  GET_NET_STATS32
+#define GET_64BIT_NET_STATS(ctr)                               \
+       GET_64BIT_NET_STATS32(bp->stats_blk->ctr) +             \
+       GET_64BIT_NET_STATS32(bp->temp_stats_blk->ctr)
 #endif
 
+#define GET_32BIT_NET_STATS(ctr)                               \
+       (unsigned long) (bp->stats_blk->ctr +                   \
+                        bp->temp_stats_blk->ctr)
+
 static struct net_device_stats *
 bnx2_get_stats(struct net_device *dev)
 {
        struct bnx2 *bp = netdev_priv(dev);
-       struct statistics_block *stats_blk = bp->stats_blk;
        struct net_device_stats *net_stats = &dev->stats;
 
        if (bp->stats_blk == NULL) {
                return net_stats;
        }
        net_stats->rx_packets =
-               GET_NET_STATS(stats_blk->stat_IfHCInUcastPkts) +
-               GET_NET_STATS(stats_blk->stat_IfHCInMulticastPkts) +
-               GET_NET_STATS(stats_blk->stat_IfHCInBroadcastPkts);
+               GET_64BIT_NET_STATS(stat_IfHCInUcastPkts) +
+               GET_64BIT_NET_STATS(stat_IfHCInMulticastPkts) +
+               GET_64BIT_NET_STATS(stat_IfHCInBroadcastPkts);
 
        net_stats->tx_packets =
-               GET_NET_STATS(stats_blk->stat_IfHCOutUcastPkts) +
-               GET_NET_STATS(stats_blk->stat_IfHCOutMulticastPkts) +
-               GET_NET_STATS(stats_blk->stat_IfHCOutBroadcastPkts);
+               GET_64BIT_NET_STATS(stat_IfHCOutUcastPkts) +
+               GET_64BIT_NET_STATS(stat_IfHCOutMulticastPkts) +
+               GET_64BIT_NET_STATS(stat_IfHCOutBroadcastPkts);
 
        net_stats->rx_bytes =
-               GET_NET_STATS(stats_blk->stat_IfHCInOctets);
+               GET_64BIT_NET_STATS(stat_IfHCInOctets);
 
        net_stats->tx_bytes =
-               GET_NET_STATS(stats_blk->stat_IfHCOutOctets);
+               GET_64BIT_NET_STATS(stat_IfHCOutOctets);
 
        net_stats->multicast =
-               GET_NET_STATS(stats_blk->stat_IfHCOutMulticastPkts);
+               GET_64BIT_NET_STATS(stat_IfHCOutMulticastPkts);
 
        net_stats->collisions =
-               (unsigned long) stats_blk->stat_EtherStatsCollisions;
+               GET_32BIT_NET_STATS(stat_EtherStatsCollisions);
 
        net_stats->rx_length_errors =
-               (unsigned long) (stats_blk->stat_EtherStatsUndersizePkts +
-               stats_blk->stat_EtherStatsOverrsizePkts);
+               GET_32BIT_NET_STATS(stat_EtherStatsUndersizePkts) +
+               GET_32BIT_NET_STATS(stat_EtherStatsOverrsizePkts);
 
        net_stats->rx_over_errors =
-               (unsigned long) (stats_blk->stat_IfInFTQDiscards +
-               stats_blk->stat_IfInMBUFDiscards);
+               GET_32BIT_NET_STATS(stat_IfInFTQDiscards) +
+               GET_32BIT_NET_STATS(stat_IfInMBUFDiscards);
 
        net_stats->rx_frame_errors =
-               (unsigned long) stats_blk->stat_Dot3StatsAlignmentErrors;
+               GET_32BIT_NET_STATS(stat_Dot3StatsAlignmentErrors);
 
        net_stats->rx_crc_errors =
-               (unsigned long) stats_blk->stat_Dot3StatsFCSErrors;
+               GET_32BIT_NET_STATS(stat_Dot3StatsFCSErrors);
 
        net_stats->rx_errors = net_stats->rx_length_errors +
                net_stats->rx_over_errors + net_stats->rx_frame_errors +
                net_stats->rx_crc_errors;
 
        net_stats->tx_aborted_errors =
-               (unsigned long) (stats_blk->stat_Dot3StatsExcessiveCollisions +
-               stats_blk->stat_Dot3StatsLateCollisions);
+               GET_32BIT_NET_STATS(stat_Dot3StatsExcessiveCollisions) +
+               GET_32BIT_NET_STATS(stat_Dot3StatsLateCollisions);
 
        if ((CHIP_NUM(bp) == CHIP_NUM_5706) ||
            (CHIP_ID(bp) == CHIP_ID_5708_A0))
                net_stats->tx_carrier_errors = 0;
        else {
                net_stats->tx_carrier_errors =
-                       (unsigned long)
-                       stats_blk->stat_Dot3StatsCarrierSenseErrors;
+                       GET_32BIT_NET_STATS(stat_Dot3StatsCarrierSenseErrors);
        }
 
        net_stats->tx_errors =
-               (unsigned long)
-               stats_blk->stat_emac_tx_stat_dot3statsinternalmactransmiterrors
-               +
+               GET_32BIT_NET_STATS(stat_emac_tx_stat_dot3statsinternalmactransmiterrors) +
                net_stats->tx_aborted_errors +
                net_stats->tx_carrier_errors;
 
        net_stats->rx_missed_errors =
-               (unsigned long) (stats_blk->stat_IfInFTQDiscards +
-               stats_blk->stat_IfInMBUFDiscards + stats_blk->stat_FwRxDrop);
+               GET_32BIT_NET_STATS(stat_IfInFTQDiscards) +
+               GET_32BIT_NET_STATS(stat_IfInMBUFDiscards) +
+               GET_32BIT_NET_STATS(stat_FwRxDrop);
 
        return net_stats;
 }
@@ -7083,6 +7117,9 @@ static int
 bnx2_change_ring_size(struct bnx2 *bp, u32 rx, u32 tx)
 {
        if (netif_running(bp->dev)) {
+               /* Reset will erase chipset stats; save them */
+               bnx2_save_stats(bp);
+
                bnx2_netif_stop(bp);
                bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_RESET);
                bnx2_free_skbs(bp);
@@ -7427,6 +7464,7 @@ bnx2_get_ethtool_stats(struct net_device *dev,
        struct bnx2 *bp = netdev_priv(dev);
        int i;
        u32 *hw_stats = (u32 *) bp->stats_blk;
+       u32 *temp_stats = (u32 *) bp->temp_stats_blk;
        u8 *stats_len_arr = NULL;
 
        if (hw_stats == NULL) {
@@ -7443,21 +7481,26 @@ bnx2_get_ethtool_stats(struct net_device *dev,
                stats_len_arr = bnx2_5708_stats_len_arr;
 
        for (i = 0; i < BNX2_NUM_STATS; i++) {
+               unsigned long offset;
+
                if (stats_len_arr[i] == 0) {
                        /* skip this counter */
                        buf[i] = 0;
                        continue;
                }
+
+               offset = bnx2_stats_offset_arr[i];
                if (stats_len_arr[i] == 4) {
                        /* 4-byte counter */
-                       buf[i] = (u64)
-                               *(hw_stats + bnx2_stats_offset_arr[i]);
+                       buf[i] = (u64) *(hw_stats + offset) +
+                                *(temp_stats + offset);
                        continue;
                }
                /* 8-byte counter */
-               buf[i] = (((u64) *(hw_stats +
-                                       bnx2_stats_offset_arr[i])) << 32) +
-                               *(hw_stats + bnx2_stats_offset_arr[i] + 1);
+               buf[i] = (((u64) *(hw_stats + offset)) << 32) +
+                        *(hw_stats + offset + 1) +
+                        (((u64) *(temp_stats + offset)) << 32) +
+                        *(temp_stats + offset + 1);
        }
 }
 
@@ -7625,7 +7668,7 @@ bnx2_change_mtu(struct net_device *dev, int new_mtu)
        return (bnx2_change_ring_size(bp, bp->rx_ring_size, bp->tx_ring_size));
 }
 
-#if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER)
+#ifdef CONFIG_NET_POLL_CONTROLLER
 static void
 poll_bnx2(struct net_device *dev)
 {
@@ -7825,6 +7868,14 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
        bp->flags = 0;
        bp->phy_flags = 0;
 
+       bp->temp_stats_blk =
+               kzalloc(sizeof(struct statistics_block), GFP_KERNEL);
+
+       if (bp->temp_stats_blk == NULL) {
+               rc = -ENOMEM;
+               goto err_out;
+       }
+
        /* enable device (incl. PCI PM wakeup), and bus-mastering */
        rc = pci_enable_device(pdev);
        if (rc) {
@@ -8229,7 +8280,7 @@ static const struct net_device_ops bnx2_netdev_ops = {
 #ifdef BCM_VLAN
        .ndo_vlan_rx_register   = bnx2_vlan_rx_register,
 #endif
-#if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER)
+#ifdef CONFIG_NET_POLL_CONTROLLER
        .ndo_poll_controller    = poll_bnx2,
 #endif
 };
@@ -8346,6 +8397,8 @@ bnx2_remove_one(struct pci_dev *pdev)
        if (bp->regview)
                iounmap(bp->regview);
 
+       kfree(bp->temp_stats_blk);
+
        free_netdev(dev);
        pci_release_regions(pdev);
        pci_disable_device(pdev);
index 939dc44d50a0e5b4c18ba53e6b937131f53c825b..b860fbbff355bbc86371cf393ef93d55d43d2969 100644 (file)
@@ -6851,6 +6851,7 @@ struct bnx2 {
        dma_addr_t              status_blk_mapping;
 
        struct statistics_block *stats_blk;
+       struct statistics_block *temp_stats_blk;
        dma_addr_t              stats_blk_mapping;
 
        int                     ctx_pages;
index 306c2b8165e242c8400d6b416de9cc201540484a..ffc7381969aeaacfaa21451db2105b6fa11f3032 100644 (file)
@@ -140,7 +140,7 @@ static struct {
 };
 
 
-static const struct pci_device_id bnx2x_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(bnx2x_pci_tbl) = {
        { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57710), BCM57710 },
        { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57711), BCM57711 },
        { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57711E), BCM57711E },
@@ -11731,7 +11731,7 @@ static void bnx2x_vlan_rx_register(struct net_device *dev,
 
 #endif
 
-#if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER)
+#ifdef CONFIG_NET_POLL_CONTROLLER
 static void poll_bnx2x(struct net_device *dev)
 {
        struct bnx2x *bp = netdev_priv(dev);
@@ -11755,7 +11755,7 @@ static const struct net_device_ops bnx2x_netdev_ops = {
 #ifdef BCM_VLAN
        .ndo_vlan_rx_register   = bnx2x_vlan_rx_register,
 #endif
-#if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER)
+#ifdef CONFIG_NET_POLL_CONTROLLER
        .ndo_poll_controller    = poll_bnx2x,
 #endif
 };
index efa0e41bf3ec2e141dbf36f72187db8aa41975b9..6221936e957a0803d4272c773793026823b59e61 100644 (file)
@@ -2615,6 +2615,17 @@ static int bond_arp_rcv(struct sk_buff *skb, struct net_device *dev, struct pack
        unsigned char *arp_ptr;
        __be32 sip, tip;
 
+       if (dev->priv_flags & IFF_802_1Q_VLAN) {
+               /*
+                * When using VLANS and bonding, dev and oriv_dev may be
+                * incorrect if the physical interface supports VLAN
+                * acceleration.  With this change ARP validation now
+                * works for hosts only reachable on the VLAN interface.
+                */
+               dev = vlan_dev_real_dev(dev);
+               orig_dev = dev_get_by_index_rcu(dev_net(skb->dev),skb->skb_iif);
+       }
+
        if (!(dev->priv_flags & IFF_BONDING) || !(dev->flags & IFF_MASTER))
                goto out;
 
@@ -3296,7 +3307,7 @@ static void bond_remove_proc_entry(struct bonding *bond)
 /* Create the bonding directory under /proc/net, if doesn't exist yet.
  * Caller must hold rtnl_lock.
  */
-static void bond_create_proc_dir(struct bond_net *bn)
+static void __net_init bond_create_proc_dir(struct bond_net *bn)
 {
        if (!bn->proc_dir) {
                bn->proc_dir = proc_mkdir(DRV_NAME, bn->net->proc_net);
@@ -3309,7 +3320,7 @@ static void bond_create_proc_dir(struct bond_net *bn)
 /* Destroy the bonding directory under /proc/net, if empty.
  * Caller must hold rtnl_lock.
  */
-static void bond_destroy_proc_dir(struct bond_net *bn)
+static void __net_exit bond_destroy_proc_dir(struct bond_net *bn)
 {
        if (bn->proc_dir) {
                remove_proc_entry(DRV_NAME, bn->net->proc_net);
@@ -3327,11 +3338,11 @@ static void bond_remove_proc_entry(struct bonding *bond)
 {
 }
 
-static void bond_create_proc_dir(struct bond_net *bn)
+static inline void bond_create_proc_dir(struct bond_net *bn)
 {
 }
 
-static void bond_destroy_proc_dir(struct bond_net *bn)
+static inline void bond_destroy_proc_dir(struct bond_net *bn)
 {
 }
 
@@ -4944,7 +4955,7 @@ out_netdev:
        goto out;
 }
 
-static int bond_net_init(struct net *net)
+static int __net_init bond_net_init(struct net *net)
 {
        struct bond_net *bn = net_generic(net, bond_net_id);
 
@@ -4956,7 +4967,7 @@ static int bond_net_init(struct net *net)
        return 0;
 }
 
-static void bond_net_exit(struct net *net)
+static void __net_exit bond_net_exit(struct net *net)
 {
        struct bond_net *bn = net_generic(net, bond_net_id);
 
index 166cc7e579c0a8c1eaadc9193dffdfedac0a6b82..a2f29a38798a4de2fe9ae631749afa81279ce449 100644 (file)
@@ -342,6 +342,9 @@ static netdev_tx_t at91_start_xmit(struct sk_buff *skb, struct net_device *dev)
        unsigned int mb, prio;
        u32 reg_mid, reg_mcr;
 
+       if (can_dropped_invalid_skb(dev, skb))
+               return NETDEV_TX_OK;
+
        mb = get_tx_next_mb(priv);
        prio = get_tx_next_prio(priv);
 
@@ -1070,6 +1073,7 @@ static int __init at91_can_probe(struct platform_device *pdev)
        priv->can.bittiming_const = &at91_bittiming_const;
        priv->can.do_set_bittiming = at91_set_bittiming;
        priv->can.do_set_mode = at91_set_mode;
+       priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES;
        priv->reg_base = addr;
        priv->dev = dev;
        priv->clk = clk;
index 0ec1524523ccaa939988d3d0c1f55bcd3450114f..bf7f9ba2d903a34c439c953a659a7d31e5d89815 100644 (file)
@@ -318,6 +318,9 @@ static int bfin_can_start_xmit(struct sk_buff *skb, struct net_device *dev)
        u16 val;
        int i;
 
+       if (can_dropped_invalid_skb(dev, skb))
+               return NETDEV_TX_OK;
+
        netif_stop_queue(dev);
 
        /* fill id */
@@ -600,6 +603,7 @@ struct net_device *alloc_bfin_candev(void)
        priv->can.bittiming_const = &bfin_can_bittiming_const;
        priv->can.do_set_bittiming = bfin_can_set_bittiming;
        priv->can.do_set_mode = bfin_can_set_mode;
+       priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES;
 
        return dev;
 }
index c1bb29f0322b388193fa5d874fdabea87206cb75..f08f1202ff003cbe4f1854e2e2ebea44779118dd 100644 (file)
@@ -592,6 +592,8 @@ static int can_changelink(struct net_device *dev,
                if (dev->flags & IFF_UP)
                        return -EBUSY;
                cm = nla_data(data[IFLA_CAN_CTRLMODE]);
+               if (cm->flags & ~priv->ctrlmode_supported)
+                       return -EOPNOTSUPP;
                priv->ctrlmode &= ~cm->mask;
                priv->ctrlmode |= cm->flags;
        }
index 1a72ca066a17fa013a3453dcaacf694a32431fed..bbe186b5a0ed76ab5c4b5dcd36224a18dcde5846 100644 (file)
@@ -494,12 +494,8 @@ static netdev_tx_t mcp251x_hard_start_xmit(struct sk_buff *skb,
                return NETDEV_TX_BUSY;
        }
 
-       if (skb->len != sizeof(struct can_frame)) {
-               dev_err(&spi->dev, "dropping packet - bad length\n");
-               dev_kfree_skb(skb);
-               net->stats.tx_dropped++;
+       if (can_dropped_invalid_skb(net, skb))
                return NETDEV_TX_OK;
-       }
 
        netif_stop_queue(net);
        priv->tx_skb = skb;
@@ -543,9 +539,14 @@ static void mcp251x_set_normal_mode(struct spi_device *spi)
        if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) {
                /* Put device into loopback mode */
                mcp251x_write_reg(spi, CANCTRL, CANCTRL_REQOP_LOOPBACK);
+       } else if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) {
+               /* Put device into listen-only mode */
+               mcp251x_write_reg(spi, CANCTRL, CANCTRL_REQOP_LISTEN_ONLY);
        } else {
                /* Put device into normal mode */
-               mcp251x_write_reg(spi, CANCTRL, CANCTRL_REQOP_NORMAL);
+               mcp251x_write_reg(spi, CANCTRL, CANCTRL_REQOP_NORMAL |
+                                 (priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT ?
+                                  CANCTRL_OSM : 0));
 
                /* Wait for the device to enter normal mode */
                timeout = jiffies + HZ;
@@ -952,6 +953,10 @@ static int __devinit mcp251x_can_probe(struct spi_device *spi)
        priv->can.bittiming_const = &mcp251x_bittiming_const;
        priv->can.do_set_mode = mcp251x_do_set_mode;
        priv->can.clock.freq = pdata->oscillator_frequency / 2;
+       priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES |
+               CAN_CTRLMODE_LOOPBACK | CAN_CTRLMODE_LISTENONLY;
+       if (pdata->model == CAN_MCP251X_MCP2515)
+               priv->can.ctrlmode_supported |= CAN_CTRLMODE_ONE_SHOT;
        priv->net = net;
        dev_set_drvdata(&spi->dev, priv);
 
index cd0f2d6f375d3e42e2384290251831c43308cb28..27d1d398e25e54c47c5f8ef4843575c43c338075 100644 (file)
@@ -11,12 +11,13 @@ if CAN_MSCAN
 
 config CAN_MPC5XXX
        tristate "Freescale MPC5xxx onboard CAN controller"
-       depends on PPC_MPC52xx
+       depends on (PPC_MPC52xx || PPC_MPC512x)
        ---help---
          If you say yes here you get support for Freescale's MPC5xxx
-         onboard CAN controller.
+         onboard CAN controller. Currently, the MPC5200, MPC5200B and
+         MPC5121 (Rev. 2 and later) are supported.
 
-         This driver can also be built as a module.  If so, the module
+         This driver can also be built as a module. If so, the module
          will be called mscan-mpc5xxx.ko.
 
 endif
index 1de6f6349b16c914c9ad01dcbe05fa99f5562872..03e7c48465a212bd8b5ca17f248ff27e2f58051f 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/can/dev.h>
 #include <linux/of_platform.h>
 #include <sysdev/fsl_soc.h>
+#include <linux/clk.h>
 #include <linux/io.h>
 #include <asm/mpc52xx.h>
 
 
 #define DRV_NAME "mpc5xxx_can"
 
-static struct of_device_id mpc52xx_cdm_ids[] __devinitdata = {
+struct mpc5xxx_can_data {
+       unsigned int type;
+       u32 (*get_clock)(struct of_device *ofdev, const char *clock_name,
+                        int *mscan_clksrc);
+};
+
+#ifdef CONFIG_PPC_MPC52xx
+static struct of_device_id __devinitdata mpc52xx_cdm_ids[] = {
        { .compatible = "fsl,mpc5200-cdm", },
        {}
 };
 
-/*
- * Get frequency of the MSCAN clock source
- *
- * Either the oscillator clock (SYS_XTAL_IN) or the IP bus clock (IP_CLK)
- * can be selected. According to the MPC5200 user's manual, the oscillator
- * clock is the better choice as it has less jitter but due to a hardware
- * bug, it can not be selected for the old MPC5200 Rev. A chips.
- */
-
-static unsigned int  __devinit mpc52xx_can_clock_freq(struct of_device *of,
-                                                     int clock_src)
+static u32 __devinit mpc52xx_can_get_clock(struct of_device *ofdev,
+                                          const char *clock_name,
+                                          int *mscan_clksrc)
 {
        unsigned int pvr;
        struct mpc52xx_cdm  __iomem *cdm;
@@ -61,21 +61,33 @@ static unsigned int  __devinit mpc52xx_can_clock_freq(struct of_device *of,
 
        pvr = mfspr(SPRN_PVR);
 
-       freq = mpc5xxx_get_bus_frequency(of->node);
+       /*
+        * Either the oscillator clock (SYS_XTAL_IN) or the IP bus clock
+        * (IP_CLK) can be selected as MSCAN clock source. According to
+        * the MPC5200 user's manual, the oscillator clock is the better
+        * choice as it has less jitter. For this reason, it is selected
+        * by default. Unfortunately, it can not be selected for the old
+        * MPC5200 Rev. A chips due to a hardware bug (check errata).
+        */
+       if (clock_name && strcmp(clock_name, "ip") == 0)
+               *mscan_clksrc = MSCAN_CLKSRC_BUS;
+       else
+               *mscan_clksrc = MSCAN_CLKSRC_XTAL;
+
+       freq = mpc5xxx_get_bus_frequency(ofdev->node);
        if (!freq)
                return 0;
 
-       if (clock_src == MSCAN_CLKSRC_BUS || pvr == 0x80822011)
+       if (*mscan_clksrc == MSCAN_CLKSRC_BUS || pvr == 0x80822011)
                return freq;
 
        /* Determine SYS_XTAL_IN frequency from the clock domain settings */
        np_cdm = of_find_matching_node(NULL, mpc52xx_cdm_ids);
        if (!np_cdm) {
-               dev_err(&of->dev, "can't get clock node!\n");
+               dev_err(&ofdev->dev, "can't get clock node!\n");
                return 0;
        }
        cdm = of_iomap(np_cdm, 0);
-       of_node_put(np_cdm);
 
        if (in_8(&cdm->ipb_clk_sel) & 0x1)
                freq *= 2;
@@ -84,26 +96,174 @@ static unsigned int  __devinit mpc52xx_can_clock_freq(struct of_device *of,
        freq *= (val & (1 << 5)) ? 8 : 4;
        freq /= (val & (1 << 6)) ? 12 : 16;
 
+       of_node_put(np_cdm);
        iounmap(cdm);
 
        return freq;
 }
+#else /* !CONFIG_PPC_MPC52xx */
+static u32 __devinit mpc52xx_can_get_clock(struct of_device *ofdev,
+                                          const char *clock_name,
+                                          int *mscan_clksrc)
+{
+       return 0;
+}
+#endif /* CONFIG_PPC_MPC52xx */
+
+#ifdef CONFIG_PPC_MPC512x
+struct mpc512x_clockctl {
+       u32 spmr;               /* System PLL Mode Reg */
+       u32 sccr[2];            /* System Clk Ctrl Reg 1 & 2 */
+       u32 scfr1;              /* System Clk Freq Reg 1 */
+       u32 scfr2;              /* System Clk Freq Reg 2 */
+       u32 reserved;
+       u32 bcr;                /* Bread Crumb Reg */
+       u32 pccr[12];           /* PSC Clk Ctrl Reg 0-11 */
+       u32 spccr;              /* SPDIF Clk Ctrl Reg */
+       u32 cccr;               /* CFM Clk Ctrl Reg */
+       u32 dccr;               /* DIU Clk Cnfg Reg */
+       u32 mccr[4];            /* MSCAN Clk Ctrl Reg 1-3 */
+};
+
+static struct of_device_id __devinitdata mpc512x_clock_ids[] = {
+       { .compatible = "fsl,mpc5121-clock", },
+       {}
+};
+
+static u32 __devinit mpc512x_can_get_clock(struct of_device *ofdev,
+                                          const char *clock_name,
+                                          int *mscan_clksrc)
+{
+       struct mpc512x_clockctl __iomem *clockctl;
+       struct device_node *np_clock;
+       struct clk *sys_clk, *ref_clk;
+       int plen, clockidx, clocksrc = -1;
+       u32 sys_freq, val, clockdiv = 1, freq = 0;
+       const u32 *pval;
+
+       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;
+       }
+       clockctl = of_iomap(np_clock, 0);
+       if (!clockctl) {
+               dev_err(&ofdev->dev, "couldn't map clock registers\n");
+               return 0;
+       }
+
+       /* Determine the MSCAN device index from the physical address */
+       pval = of_get_property(ofdev->node, "reg", &plen);
+       BUG_ON(!pval || plen < sizeof(*pval));
+       clockidx = (*pval & 0x80) ? 1 : 0;
+       if (*pval & 0x2000)
+               clockidx += 2;
+
+       /*
+        * Clock source and divider selection: 3 different clock sources
+        * can be selected: "ip", "ref" or "sys". For the latter two, a
+        * clock divider can be defined as well. If the clock source is
+        * not specified by the device tree, we first try to find an
+        * optimal CAN source clock based on the system clock. If that
+        * is not posslible, the reference clock will be used.
+        */
+       if (clock_name && !strcmp(clock_name, "ip")) {
+               *mscan_clksrc = MSCAN_CLKSRC_IPS;
+               freq = mpc5xxx_get_bus_frequency(ofdev->node);
+       } else {
+               *mscan_clksrc = MSCAN_CLKSRC_BUS;
+
+               pval = of_get_property(ofdev->node,
+                                      "fsl,mscan-clock-divider", &plen);
+               if (pval && plen == sizeof(*pval))
+                       clockdiv = *pval;
+               if (!clockdiv)
+                       clockdiv = 1;
+
+               if (!clock_name || !strcmp(clock_name, "sys")) {
+                       sys_clk = clk_get(&ofdev->dev, "sys_clk");
+                       if (!sys_clk) {
+                               dev_err(&ofdev->dev, "couldn't get sys_clk\n");
+                               goto exit_unmap;
+                       }
+                       /* Get and round up/down sys clock rate */
+                       sys_freq = 1000000 *
+                               ((clk_get_rate(sys_clk) + 499999) / 1000000);
+
+                       if (!clock_name) {
+                               /* A multiple of 16 MHz would be optimal */
+                               if ((sys_freq % 16000000) == 0) {
+                                       clocksrc = 0;
+                                       clockdiv = sys_freq / 16000000;
+                                       freq = sys_freq / clockdiv;
+                               }
+                       } else {
+                               clocksrc = 0;
+                               freq = sys_freq / clockdiv;
+                       }
+               }
+
+               if (clocksrc < 0) {
+                       ref_clk = clk_get(&ofdev->dev, "ref_clk");
+                       if (!ref_clk) {
+                               dev_err(&ofdev->dev, "couldn't get ref_clk\n");
+                               goto exit_unmap;
+                       }
+                       clocksrc = 1;
+                       freq = clk_get_rate(ref_clk) / clockdiv;
+               }
+       }
+
+       /* Disable clock */
+       out_be32(&clockctl->mccr[clockidx], 0x0);
+       if (clocksrc >= 0) {
+               /* Set source and divider */
+               val = (clocksrc << 14) | ((clockdiv - 1) << 17);
+               out_be32(&clockctl->mccr[clockidx], val);
+               /* Enable clock */
+               out_be32(&clockctl->mccr[clockidx], val | 0x10000);
+       }
+
+       /* Enable MSCAN clock domain */
+       val = in_be32(&clockctl->sccr[1]);
+       if (!(val & (1 << 25)))
+               out_be32(&clockctl->sccr[1], val | (1 << 25));
+
+       dev_dbg(&ofdev->dev, "using '%s' with frequency divider %d\n",
+               *mscan_clksrc == MSCAN_CLKSRC_IPS ? "ips_clk" :
+               clocksrc == 1 ? "ref_clk" : "sys_clk", clockdiv);
+
+exit_unmap:
+       of_node_put(np_clock);
+       iounmap(clockctl);
+
+       return freq;
+}
+#else /* !CONFIG_PPC_MPC512x */
+static u32 __devinit mpc512x_can_get_clock(struct of_device *ofdev,
+                                          const char *clock_name,
+                                          int *mscan_clksrc)
+{
+       return 0;
+}
+#endif /* CONFIG_PPC_MPC512x */
 
 static int __devinit mpc5xxx_can_probe(struct of_device *ofdev,
                                       const struct of_device_id *id)
 {
+       struct mpc5xxx_can_data *data = (struct mpc5xxx_can_data *)id->data;
        struct device_node *np = ofdev->node;
        struct net_device *dev;
        struct mscan_priv *priv;
        void __iomem *base;
-       const char *clk_src;
-       int err, irq, clock_src;
+       const char *clock_name = NULL;
+       int irq, mscan_clksrc = 0;
+       int err = -ENOMEM;
 
-       base = of_iomap(ofdev->node, 0);
+       base = of_iomap(np, 0);
        if (!base) {
                dev_err(&ofdev->dev, "couldn't ioremap\n");
-               err = -ENOMEM;
-               goto exit_release_mem;
+               return err;
        }
 
        irq = irq_of_parse_and_map(np, 0);
@@ -114,37 +274,27 @@ static int __devinit mpc5xxx_can_probe(struct of_device *ofdev,
        }
 
        dev = alloc_mscandev();
-       if (!dev) {
-               err = -ENOMEM;
+       if (!dev)
                goto exit_dispose_irq;
-       }
 
        priv = netdev_priv(dev);
        priv->reg_base = base;
        dev->irq = irq;
 
-       /*
-        * Either the oscillator clock (SYS_XTAL_IN) or the IP bus clock
-        * (IP_CLK) can be selected as MSCAN clock source. According to
-        * the MPC5200 user's manual, the oscillator clock is the better
-        * choice as it has less jitter. For this reason, it is selected
-        * by default.
-        */
-       clk_src = of_get_property(np, "fsl,mscan-clock-source", NULL);
-       if (clk_src && strcmp(clk_src, "ip") == 0)
-               clock_src = MSCAN_CLKSRC_BUS;
-       else
-               clock_src = MSCAN_CLKSRC_XTAL;
-       priv->can.clock.freq = mpc52xx_can_clock_freq(ofdev, clock_src);
+       clock_name = of_get_property(np, "fsl,mscan-clock-source", NULL);
+
+       BUG_ON(!data);
+       priv->type = data->type;
+       priv->can.clock.freq = data->get_clock(ofdev, clock_name,
+                                              &mscan_clksrc);
        if (!priv->can.clock.freq) {
-               dev_err(&ofdev->dev, "couldn't get MSCAN clock frequency\n");
-               err = -ENODEV;
+               dev_err(&ofdev->dev, "couldn't get MSCAN clock properties\n");
                goto exit_free_mscan;
        }
 
        SET_NETDEV_DEV(dev, &ofdev->dev);
 
-       err = register_mscandev(dev, clock_src);
+       err = register_mscandev(dev, mscan_clksrc);
        if (err) {
                dev_err(&ofdev->dev, "registering %s failed (err=%d)\n",
                        DRV_NAME, err);
@@ -164,7 +314,7 @@ exit_dispose_irq:
        irq_dispose_mapping(irq);
 exit_unmap_mem:
        iounmap(base);
-exit_release_mem:
+
        return err;
 }
 
@@ -225,8 +375,20 @@ static int mpc5xxx_can_resume(struct of_device *ofdev)
 }
 #endif
 
+static struct mpc5xxx_can_data __devinitdata mpc5200_can_data = {
+       .type = MSCAN_TYPE_MPC5200,
+       .get_clock = mpc52xx_can_get_clock,
+};
+
+static struct mpc5xxx_can_data __devinitdata mpc5121_can_data = {
+       .type = MSCAN_TYPE_MPC5121,
+       .get_clock = mpc512x_can_get_clock,
+};
+
 static struct of_device_id __devinitdata mpc5xxx_can_table[] = {
-       {.compatible = "fsl,mpc5200-mscan"},
+       { .compatible = "fsl,mpc5200-mscan", .data = &mpc5200_can_data, },
+       /* Note that only MPC5121 Rev. 2 (and later) is supported */
+       { .compatible = "fsl,mpc5121-mscan", .data = &mpc5121_can_data, },
        {},
 };
 
@@ -255,5 +417,5 @@ static void __exit mpc5xxx_can_exit(void)
 module_exit(mpc5xxx_can_exit);
 
 MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>");
-MODULE_DESCRIPTION("Freescale MPC5200 CAN driver");
+MODULE_DESCRIPTION("Freescale MPC5xxx CAN driver");
 MODULE_LICENSE("GPL v2");
index 07346f880ca680e49668f7dc783bf734b5dbd157..6b7dd578d417b55c65e5eeb47439b5c604e76500 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (C) 2005-2006 Andrey Volkov <avolkov@varma-el.com>,
  *                         Varma Electronics Oy
  * Copyright (C) 2008-2009 Wolfgang Grandegger <wg@grandegger.com>
- * Copytight (C) 2008-2009 Pengutronix <kernel@pengutronix.de>
+ * Copyright (C) 2008-2009 Pengutronix <kernel@pengutronix.de>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the version 2 of the GNU General Public License
@@ -152,6 +152,12 @@ static int mscan_start(struct net_device *dev)
        priv->shadow_canrier = 0;
        priv->flags = 0;
 
+       if (priv->type == MSCAN_TYPE_MPC5121) {
+               /* Clear pending bus-off condition */
+               if (in_8(&regs->canmisc) & MSCAN_BOHOLD)
+                       out_8(&regs->canmisc, MSCAN_BOHOLD);
+       }
+
        err = mscan_set_mode(dev, MSCAN_NORMAL_MODE);
        if (err)
                return err;
@@ -163,8 +169,29 @@ static int mscan_start(struct net_device *dev)
        out_8(&regs->cantier, 0);
 
        /* Enable receive interrupts. */
-       out_8(&regs->canrier, MSCAN_OVRIE | MSCAN_RXFIE | MSCAN_CSCIE |
-             MSCAN_RSTATE1 | MSCAN_RSTATE0 | MSCAN_TSTATE1 | MSCAN_TSTATE0);
+       out_8(&regs->canrier, MSCAN_RX_INTS_ENABLE);
+
+       return 0;
+}
+
+static int mscan_restart(struct net_device *dev)
+{
+       struct mscan_priv *priv = netdev_priv(dev);
+
+       if (priv->type == MSCAN_TYPE_MPC5121) {
+               struct mscan_regs *regs = (struct mscan_regs *)priv->reg_base;
+
+               priv->can.state = CAN_STATE_ERROR_ACTIVE;
+               WARN(!(in_8(&regs->canmisc) & MSCAN_BOHOLD),
+                    "bus-off state expected");
+               out_8(&regs->canmisc, MSCAN_BOHOLD);
+               /* Re-enable receive interrupts. */
+               out_8(&regs->canrier, MSCAN_RX_INTS_ENABLE);
+       } else {
+               if (priv->can.state <= CAN_STATE_BUS_OFF)
+                       mscan_set_mode(dev, MSCAN_INIT_MODE);
+               return mscan_start(dev);
+       }
 
        return 0;
 }
@@ -177,8 +204,8 @@ static netdev_tx_t mscan_start_xmit(struct sk_buff *skb, struct net_device *dev)
        int i, rtr, buf_id;
        u32 can_id;
 
-       if (frame->can_dlc > 8)
-               return -EINVAL;
+       if (can_dropped_invalid_skb(dev, skb))
+               return NETDEV_TX_OK;
 
        out_8(&regs->cantier, 0);
 
@@ -359,9 +386,12 @@ static void mscan_get_err_frame(struct net_device *dev, struct can_frame *frame,
                         * automatically. To avoid that we stop the chip doing
                         * a light-weight stop (we are in irq-context).
                         */
-                       out_8(&regs->cantier, 0);
-                       out_8(&regs->canrier, 0);
-                       setbits8(&regs->canctl0, MSCAN_SLPRQ | MSCAN_INITRQ);
+                       if (priv->type != MSCAN_TYPE_MPC5121) {
+                               out_8(&regs->cantier, 0);
+                               out_8(&regs->canrier, 0);
+                               setbits8(&regs->canctl0,
+                                        MSCAN_SLPRQ | MSCAN_INITRQ);
+                       }
                        can_bus_off(dev);
                        break;
                default:
@@ -491,9 +521,7 @@ static int mscan_do_set_mode(struct net_device *dev, enum can_mode mode)
 
        switch (mode) {
        case CAN_MODE_START:
-               if (priv->can.state <= CAN_STATE_BUS_OFF)
-                       mscan_set_mode(dev, MSCAN_INIT_MODE);
-               ret = mscan_start(dev);
+               ret = mscan_restart(dev);
                if (ret)
                        break;
                if (netif_queue_stopped(dev))
@@ -592,18 +620,21 @@ static const struct net_device_ops mscan_netdev_ops = {
        .ndo_start_xmit         = mscan_start_xmit,
 };
 
-int register_mscandev(struct net_device *dev, int clock_src)
+int register_mscandev(struct net_device *dev, int mscan_clksrc)
 {
        struct mscan_priv *priv = netdev_priv(dev);
        struct mscan_regs *regs = (struct mscan_regs *)priv->reg_base;
        u8 ctl1;
 
        ctl1 = in_8(&regs->canctl1);
-       if (clock_src)
+       if (mscan_clksrc)
                ctl1 |= MSCAN_CLKSRC;
        else
                ctl1 &= ~MSCAN_CLKSRC;
 
+       if (priv->type == MSCAN_TYPE_MPC5121)
+               ctl1 |= MSCAN_BORM; /* bus-off recovery upon request */
+
        ctl1 |= MSCAN_CANE;
        out_8(&regs->canctl1, ctl1);
        udelay(100);
@@ -655,6 +686,7 @@ struct net_device *alloc_mscandev(void)
        priv->can.bittiming_const = &mscan_bittiming_const;
        priv->can.do_set_bittiming = mscan_do_set_bittiming;
        priv->can.do_set_mode = mscan_do_set_mode;
+       priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES;
 
        for (i = 0; i < TX_QUEUE_SIZE; i++) {
                priv->tx_queue[i].id = i;
index 00fc4aaf1ed8ca04533203813322914f8832202f..4ff966473bc9596477431637923a8fa5c2e8c2ab 100644 (file)
 #define MSCAN_CLKSRC           0x40
 #define MSCAN_LOOPB            0x20
 #define MSCAN_LISTEN           0x10
+#define MSCAN_BORM             0x08
 #define MSCAN_WUPM             0x04
 #define MSCAN_SLPAK            0x02
 #define MSCAN_INITAK           0x01
 
-/* Use the MPC5200 MSCAN variant? */
+/* Use the MPC5XXX MSCAN variant? */
 #ifdef CONFIG_PPC
-#define MSCAN_FOR_MPC5200
+#define MSCAN_FOR_MPC5XXX
 #endif
 
-#ifdef MSCAN_FOR_MPC5200
+#ifdef MSCAN_FOR_MPC5XXX
 #define MSCAN_CLKSRC_BUS       0
 #define MSCAN_CLKSRC_XTAL      MSCAN_CLKSRC
+#define MSCAN_CLKSRC_IPS       MSCAN_CLKSRC
 #else
 #define MSCAN_CLKSRC_BUS       MSCAN_CLKSRC
 #define MSCAN_CLKSRC_XTAL      0
 #define MSCAN_EFF_RTR_SHIFT    0
 #define MSCAN_EFF_FLAGS                0x18    /* IDE + SRR */
 
-#ifdef MSCAN_FOR_MPC5200
+#ifdef MSCAN_FOR_MPC5XXX
 #define _MSCAN_RESERVED_(n, num) u8 _res##n[num]
 #define _MSCAN_RESERVED_DSR_SIZE       2
 #else
@@ -165,67 +167,66 @@ struct mscan_regs {
        u8 cantbsel;                            /* + 0x14     0x0a */
        u8 canidac;                             /* + 0x15     0x0b */
        u8 reserved;                            /* + 0x16     0x0c */
-       _MSCAN_RESERVED_(6, 5);                 /* + 0x17          */
-#ifndef MSCAN_FOR_MPC5200
-       u8 canmisc;                             /*            0x0d */
-#endif
+       _MSCAN_RESERVED_(6, 2);                 /* + 0x17          */
+       u8 canmisc;                             /* + 0x19     0x0d */
+       _MSCAN_RESERVED_(7, 2);                 /* + 0x1a          */
        u8 canrxerr;                            /* + 0x1c     0x0e */
        u8 cantxerr;                            /* + 0x1d     0x0f */
-       _MSCAN_RESERVED_(7, 2);                 /* + 0x1e          */
+       _MSCAN_RESERVED_(8, 2);                 /* + 0x1e          */
        u16 canidar1_0;                         /* + 0x20     0x10 */
-       _MSCAN_RESERVED_(8, 2);                 /* + 0x22          */
+       _MSCAN_RESERVED_(9, 2);                 /* + 0x22          */
        u16 canidar3_2;                         /* + 0x24     0x12 */
-       _MSCAN_RESERVED_(9, 2);                 /* + 0x26          */
+       _MSCAN_RESERVED_(10, 2);                /* + 0x26          */
        u16 canidmr1_0;                         /* + 0x28     0x14 */
-       _MSCAN_RESERVED_(10, 2);                /* + 0x2a          */
+       _MSCAN_RESERVED_(11, 2);                /* + 0x2a          */
        u16 canidmr3_2;                         /* + 0x2c     0x16 */
-       _MSCAN_RESERVED_(11, 2);                /* + 0x2e          */
+       _MSCAN_RESERVED_(12, 2);                /* + 0x2e          */
        u16 canidar5_4;                         /* + 0x30     0x18 */
-       _MSCAN_RESERVED_(12, 2);                /* + 0x32          */
+       _MSCAN_RESERVED_(13, 2);                /* + 0x32          */
        u16 canidar7_6;                         /* + 0x34     0x1a */
-       _MSCAN_RESERVED_(13, 2);                /* + 0x36          */
+       _MSCAN_RESERVED_(14, 2);                /* + 0x36          */
        u16 canidmr5_4;                         /* + 0x38     0x1c */
-       _MSCAN_RESERVED_(14, 2);                /* + 0x3a          */
+       _MSCAN_RESERVED_(15, 2);                /* + 0x3a          */
        u16 canidmr7_6;                         /* + 0x3c     0x1e */
-       _MSCAN_RESERVED_(15, 2);                /* + 0x3e          */
+       _MSCAN_RESERVED_(16, 2);                /* + 0x3e          */
        struct {
                u16 idr1_0;                     /* + 0x40     0x20 */
-                _MSCAN_RESERVED_(16, 2);       /* + 0x42          */
+               _MSCAN_RESERVED_(17, 2);        /* + 0x42          */
                u16 idr3_2;                     /* + 0x44     0x22 */
-                _MSCAN_RESERVED_(17, 2);       /* + 0x46          */
+               _MSCAN_RESERVED_(18, 2);        /* + 0x46          */
                u16 dsr1_0;                     /* + 0x48     0x24 */
-                _MSCAN_RESERVED_(18, 2);       /* + 0x4a          */
+               _MSCAN_RESERVED_(19, 2);        /* + 0x4a          */
                u16 dsr3_2;                     /* + 0x4c     0x26 */
-                _MSCAN_RESERVED_(19, 2);       /* + 0x4e          */
+               _MSCAN_RESERVED_(20, 2);        /* + 0x4e          */
                u16 dsr5_4;                     /* + 0x50     0x28 */
-                _MSCAN_RESERVED_(20, 2);       /* + 0x52          */
+               _MSCAN_RESERVED_(21, 2);        /* + 0x52          */
                u16 dsr7_6;                     /* + 0x54     0x2a */
-                _MSCAN_RESERVED_(21, 2);       /* + 0x56          */
+               _MSCAN_RESERVED_(22, 2);        /* + 0x56          */
                u8 dlr;                         /* + 0x58     0x2c */
-                u8:8;                          /* + 0x59     0x2d */
-                _MSCAN_RESERVED_(22, 2);       /* + 0x5a          */
+               u8 reserved;                    /* + 0x59     0x2d */
+               _MSCAN_RESERVED_(23, 2);        /* + 0x5a          */
                u16 time;                       /* + 0x5c     0x2e */
        } rx;
-        _MSCAN_RESERVED_(23, 2);               /* + 0x5e          */
+       _MSCAN_RESERVED_(24, 2);                /* + 0x5e          */
        struct {
                u16 idr1_0;                     /* + 0x60     0x30 */
-                _MSCAN_RESERVED_(24, 2);       /* + 0x62          */
+               _MSCAN_RESERVED_(25, 2);        /* + 0x62          */
                u16 idr3_2;                     /* + 0x64     0x32 */
-                _MSCAN_RESERVED_(25, 2);       /* + 0x66          */
+               _MSCAN_RESERVED_(26, 2);        /* + 0x66          */
                u16 dsr1_0;                     /* + 0x68     0x34 */
-                _MSCAN_RESERVED_(26, 2);       /* + 0x6a          */
+               _MSCAN_RESERVED_(27, 2);        /* + 0x6a          */
                u16 dsr3_2;                     /* + 0x6c     0x36 */
-                _MSCAN_RESERVED_(27, 2);       /* + 0x6e          */
+               _MSCAN_RESERVED_(28, 2);        /* + 0x6e          */
                u16 dsr5_4;                     /* + 0x70     0x38 */
-                _MSCAN_RESERVED_(28, 2);       /* + 0x72          */
+               _MSCAN_RESERVED_(29, 2);        /* + 0x72          */
                u16 dsr7_6;                     /* + 0x74     0x3a */
-                _MSCAN_RESERVED_(29, 2);       /* + 0x76          */
+               _MSCAN_RESERVED_(30, 2);        /* + 0x76          */
                u8 dlr;                         /* + 0x78     0x3c */
                u8 tbpr;                        /* + 0x79     0x3d */
-                _MSCAN_RESERVED_(30, 2);       /* + 0x7a          */
+               _MSCAN_RESERVED_(31, 2);        /* + 0x7a          */
                u16 time;                       /* + 0x7c     0x3e */
        } tx;
-        _MSCAN_RESERVED_(31, 2);               /* + 0x7e          */
+       _MSCAN_RESERVED_(32, 2);                /* + 0x7e          */
 } __attribute__ ((packed));
 
 #undef _MSCAN_RESERVED_
@@ -237,6 +238,15 @@ struct mscan_regs {
 #define MSCAN_POWEROFF_MODE    (MSCAN_CSWAI | MSCAN_SLPRQ)
 #define MSCAN_SET_MODE_RETRIES 255
 #define MSCAN_ECHO_SKB_MAX     3
+#define MSCAN_RX_INTS_ENABLE   (MSCAN_OVRIE | MSCAN_RXFIE | MSCAN_CSCIE | \
+                                MSCAN_RSTATE1 | MSCAN_RSTATE0 | \
+                                MSCAN_TSTATE1 | MSCAN_TSTATE0)
+
+/* MSCAN type variants */
+enum {
+       MSCAN_TYPE_MPC5200,
+       MSCAN_TYPE_MPC5121
+};
 
 #define BTR0_BRP_MASK          0x3f
 #define BTR0_SJW_SHIFT         6
@@ -270,6 +280,7 @@ struct tx_queue_entry {
 
 struct mscan_priv {
        struct can_priv can;    /* must be the first member */
+       unsigned int type;      /* MSCAN type variants */
        long open_time;
        unsigned long flags;
        void __iomem *reg_base; /* ioremap'ed address to registers */
@@ -285,12 +296,7 @@ struct mscan_priv {
 };
 
 extern struct net_device *alloc_mscandev(void);
-/*
- * clock_src:
- *     1 = The MSCAN clock source is the onchip Bus Clock.
- *     0 = The MSCAN clock source is the chip Oscillator Clock.
- */
-extern int register_mscandev(struct net_device *dev, int clock_src);
+extern int register_mscandev(struct net_device *dev, int mscan_clksrc);
 extern void unregister_mscandev(struct net_device *dev);
 
 #endif /* __MSCAN_H__ */
index 4c674927f2475da1c3109c59d796e81ce334f279..9e277d64a3183e1232b5ce604b80d7bdde635a79 100644 (file)
@@ -44,4 +44,16 @@ config CAN_KVASER_PCI
          This driver is for the the PCIcanx and PCIcan cards (1, 2 or
          4 channel) from Kvaser (http://www.kvaser.com).
 
+config CAN_PLX_PCI
+       tristate "PLX90xx PCI-bridge based Cards"
+       depends on PCI
+       ---help---
+         This driver is for CAN interface cards based on
+         the PLX90xx PCI bridge.
+         Driver supports now:
+          - Adlink PCI-7841/cPCI-7841 card (http://www.adlinktech.com/)
+          - Adlink PCI-7841/cPCI-7841 SE card
+          - Marathon CAN-bus-PCI card (http://www.marathon.ru/)
+          - TEWS TECHNOLOGIES TPMC810 card (http://www.tews.com/)
+
 endif
index 9d245ac0396571a6a838dca3eb7c68ee6cfa0d17..ce924553995d5d850c73f4e865a189f685795b18 100644 (file)
@@ -8,5 +8,6 @@ obj-$(CONFIG_CAN_SJA1000_PLATFORM) += sja1000_platform.o
 obj-$(CONFIG_CAN_SJA1000_OF_PLATFORM) += sja1000_of_platform.o
 obj-$(CONFIG_CAN_EMS_PCI) += ems_pci.o
 obj-$(CONFIG_CAN_KVASER_PCI) += kvaser_pci.o
+obj-$(CONFIG_CAN_PLX_PCI) += plx_pci.o
 
 ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
index fd04789d33707a8db769d88a099374deff3089ca..87300606abb9db79bb683ca4b92deb3206d456b7 100644 (file)
@@ -102,7 +102,7 @@ struct ems_pci_card {
 
 #define EMS_PCI_BASE_SIZE  4096 /* size of controller area */
 
-static struct pci_device_id ems_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(ems_pci_tbl) = {
        /* CPC-PCI v1 */
        {PCI_VENDOR_ID_SIEMENS, 0x2104, PCI_ANY_ID, PCI_ANY_ID,},
        /* CPC-PCI v2 */
index 7dd7769b9713c74233fff614822778aa52526a21..441e776a7f59f51cedb91671e83f80e66436bde9 100644 (file)
@@ -109,7 +109,7 @@ struct kvaser_pci {
 #define KVASER_PCI_VENDOR_ID2     0x1a07    /* the PCI device and vendor IDs */
 #define KVASER_PCI_DEVICE_ID2     0x0008
 
-static struct pci_device_id kvaser_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(kvaser_pci_tbl) = {
        {KVASER_PCI_VENDOR_ID1, KVASER_PCI_DEVICE_ID1, PCI_ANY_ID, PCI_ANY_ID,},
        {KVASER_PCI_VENDOR_ID2, KVASER_PCI_DEVICE_ID2, PCI_ANY_ID, PCI_ANY_ID,},
        { 0,}
diff --git a/drivers/net/can/sja1000/plx_pci.c b/drivers/net/can/sja1000/plx_pci.c
new file mode 100644 (file)
index 0000000..6b46a63
--- /dev/null
@@ -0,0 +1,472 @@
+/*
+ * Copyright (C) 2008-2010 Pavel Cheblakov <P.B.Cheblakov@inp.nsk.su>
+ *
+ * Derived from the ems_pci.c driver:
+ *     Copyright (C) 2007 Wolfgang Grandegger <wg@grandegger.com>
+ *     Copyright (C) 2008 Markus Plessing <plessing@ems-wuensche.com>
+ *     Copyright (C) 2008 Sebastian Haas <haas@ems-wuensche.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/netdevice.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/can.h>
+#include <linux/can/dev.h>
+#include <linux/io.h>
+
+#include "sja1000.h"
+
+#define DRV_NAME  "sja1000_plx_pci"
+
+MODULE_AUTHOR("Pavel Cheblakov <P.B.Cheblakov@inp.nsk.su>");
+MODULE_DESCRIPTION("Socket-CAN driver for PLX90xx PCI-bridge cards with "
+                  "the SJA1000 chips");
+MODULE_SUPPORTED_DEVICE("Adlink PCI-7841/cPCI-7841, "
+                       "Adlink PCI-7841/cPCI-7841 SE, "
+                       "Marathon CAN-bus-PCI, "
+                       "TEWS TECHNOLOGIES TPMC810");
+MODULE_LICENSE("GPL v2");
+
+#define PLX_PCI_MAX_CHAN 2
+
+struct plx_pci_card {
+       int channels;                   /* detected channels count */
+       struct net_device *net_dev[PLX_PCI_MAX_CHAN];
+       void __iomem *conf_addr;
+};
+
+#define PLX_PCI_CAN_CLOCK (16000000 / 2)
+
+/* PLX90xx registers */
+#define PLX_INTCSR     0x4c            /* Interrupt Control/Status */
+#define PLX_CNTRL      0x50            /* User I/O, Direct Slave Response,
+                                        * Serial EEPROM, and Initialization
+                                        * Control register
+                                        */
+
+#define PLX_LINT1_EN   0x1             /* Local interrupt 1 enable */
+#define PLX_LINT2_EN   (1 << 3)        /* Local interrupt 2 enable */
+#define PLX_PCI_INT_EN (1 << 6)        /* PCI Interrupt Enable */
+#define PLX_PCI_RESET  (1 << 30)       /* PCI Adapter Software Reset */
+
+/*
+ * The board configuration is probably following:
+ * RX1 is connected to ground.
+ * TX1 is not connected.
+ * CLKO is not connected.
+ * Setting the OCR register to 0xDA is a good idea.
+ * This means normal output mode, push-pull and the correct polarity.
+ */
+#define PLX_PCI_OCR    (OCR_TX0_PUSHPULL | OCR_TX1_PUSHPULL)
+
+/*
+ * In the CDR register, you should set CBP to 1.
+ * You will probably also want to set the clock divider value to 7
+ * (meaning direct oscillator output) because the second SJA1000 chip
+ * is driven by the first one CLKOUT output.
+ */
+#define PLX_PCI_CDR                    (CDR_CBP | CDR_CLKOUT_MASK)
+
+/* SJA1000 Control Register in the BasicCAN Mode */
+#define REG_CR                         0x00
+
+/* States of some SJA1000 registers after hardware reset in the BasicCAN mode*/
+#define REG_CR_BASICCAN_INITIAL                0x21
+#define REG_CR_BASICCAN_INITIAL_MASK   0xa1
+#define REG_SR_BASICCAN_INITIAL                0x0c
+#define REG_IR_BASICCAN_INITIAL                0xe0
+
+/* States of some SJA1000 registers after hardware reset in the PeliCAN mode*/
+#define REG_MOD_PELICAN_INITIAL                0x01
+#define REG_SR_PELICAN_INITIAL         0x3c
+#define REG_IR_PELICAN_INITIAL         0x00
+
+#define ADLINK_PCI_VENDOR_ID           0x144A
+#define ADLINK_PCI_DEVICE_ID           0x7841
+
+#define MARATHON_PCI_DEVICE_ID         0x2715
+
+#define TEWS_PCI_VENDOR_ID             0x1498
+#define TEWS_PCI_DEVICE_ID_TMPC810     0x032A
+
+static void plx_pci_reset_common(struct pci_dev *pdev);
+static void plx_pci_reset_marathon(struct pci_dev *pdev);
+
+struct plx_pci_channel_map {
+       u32 bar;
+       u32 offset;
+       u32 size;               /* 0x00 - auto, e.g. length of entire bar */
+};
+
+struct plx_pci_card_info {
+       const char *name;
+       int channel_count;
+       u32 can_clock;
+       u8 ocr;                 /* output control register */
+       u8 cdr;                 /* clock divider register */
+
+       /* Parameters for mapping local configuration space */
+       struct plx_pci_channel_map conf_map;
+
+       /* Parameters for mapping the SJA1000 chips */
+       struct plx_pci_channel_map chan_map_tbl[PLX_PCI_MAX_CHAN];
+
+       /* Pointer to device-dependent reset function */
+       void (*reset_func)(struct pci_dev *pdev);
+};
+
+static struct plx_pci_card_info plx_pci_card_info_adlink __devinitdata = {
+       "Adlink PCI-7841/cPCI-7841", 2,
+       PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR,
+       {1, 0x00, 0x00}, { {2, 0x00, 0x80}, {2, 0x80, 0x80} },
+       &plx_pci_reset_common
+       /* based on PLX9052 */
+};
+
+static struct plx_pci_card_info plx_pci_card_info_adlink_se __devinitdata = {
+       "Adlink PCI-7841/cPCI-7841 SE", 2,
+       PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR,
+       {0, 0x00, 0x00}, { {2, 0x00, 0x80}, {2, 0x80, 0x80} },
+       &plx_pci_reset_common
+       /* based on PLX9052 */
+};
+
+static struct plx_pci_card_info plx_pci_card_info_marathon __devinitdata = {
+       "Marathon CAN-bus-PCI", 2,
+       PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR,
+       {0, 0x00, 0x00}, { {2, 0x00, 0x00}, {4, 0x00, 0x00} },
+       &plx_pci_reset_marathon
+       /* based on PLX9052 */
+};
+
+static struct plx_pci_card_info plx_pci_card_info_tews __devinitdata = {
+       "TEWS TECHNOLOGIES TPMC810", 2,
+       PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR,
+       {0, 0x00, 0x00}, { {2, 0x000, 0x80}, {2, 0x100, 0x80} },
+       &plx_pci_reset_common
+       /* based on PLX9030 */
+};
+
+static DEFINE_PCI_DEVICE_TABLE(plx_pci_tbl) = {
+       {
+               /* Adlink PCI-7841/cPCI-7841 */
+               ADLINK_PCI_VENDOR_ID, ADLINK_PCI_DEVICE_ID,
+               PCI_ANY_ID, PCI_ANY_ID,
+               PCI_CLASS_NETWORK_OTHER << 8, ~0,
+               (kernel_ulong_t)&plx_pci_card_info_adlink
+       },
+       {
+               /* Adlink PCI-7841/cPCI-7841 SE */
+               ADLINK_PCI_VENDOR_ID, ADLINK_PCI_DEVICE_ID,
+               PCI_ANY_ID, PCI_ANY_ID,
+               PCI_CLASS_COMMUNICATION_OTHER << 8, ~0,
+               (kernel_ulong_t)&plx_pci_card_info_adlink_se
+       },
+       {
+               /* Marathon CAN-bus-PCI card */
+               PCI_VENDOR_ID_PLX, MARATHON_PCI_DEVICE_ID,
+               PCI_ANY_ID, PCI_ANY_ID,
+               0, 0,
+               (kernel_ulong_t)&plx_pci_card_info_marathon
+       },
+       {
+               /* TEWS TECHNOLOGIES TPMC810 card */
+               TEWS_PCI_VENDOR_ID, TEWS_PCI_DEVICE_ID_TMPC810,
+               PCI_ANY_ID, PCI_ANY_ID,
+               0, 0,
+               (kernel_ulong_t)&plx_pci_card_info_tews
+       },
+       { 0,}
+};
+MODULE_DEVICE_TABLE(pci, plx_pci_tbl);
+
+static u8 plx_pci_read_reg(const struct sja1000_priv *priv, int port)
+{
+       return ioread8(priv->reg_base + port);
+}
+
+static void plx_pci_write_reg(const struct sja1000_priv *priv, int port, u8 val)
+{
+       iowrite8(val, priv->reg_base + port);
+}
+
+/*
+ * Check if a CAN controller is present at the specified location
+ * by trying to switch 'em from the Basic mode into the PeliCAN mode.
+ * Also check states of some registers in reset mode.
+ */
+static inline int plx_pci_check_sja1000(const struct sja1000_priv *priv)
+{
+       int flag = 0;
+
+       /*
+        * Check registers after hardware reset (the Basic mode)
+        * See states on p. 10 of the Datasheet.
+        */
+       if ((priv->read_reg(priv, REG_CR) & REG_CR_BASICCAN_INITIAL_MASK) ==
+           REG_CR_BASICCAN_INITIAL &&
+           (priv->read_reg(priv, REG_SR) == REG_SR_BASICCAN_INITIAL) &&
+           (priv->read_reg(priv, REG_IR) == REG_IR_BASICCAN_INITIAL))
+               flag = 1;
+
+       /* Bring the SJA1000 into the PeliCAN mode*/
+       priv->write_reg(priv, REG_CDR, CDR_PELICAN);
+
+       /*
+        * Check registers after reset in the PeliCAN mode.
+        * See states on p. 23 of the Datasheet.
+        */
+       if (priv->read_reg(priv, REG_MOD) == REG_MOD_PELICAN_INITIAL &&
+           priv->read_reg(priv, REG_SR) == REG_SR_PELICAN_INITIAL &&
+           priv->read_reg(priv, REG_IR) == REG_IR_PELICAN_INITIAL)
+               return flag;
+
+       return 0;
+}
+
+/*
+ * PLX90xx software reset
+ * Also LRESET# asserts and brings to reset device on the Local Bus (if wired).
+ * For most cards it's enough for reset the SJA1000 chips.
+ */
+static void plx_pci_reset_common(struct pci_dev *pdev)
+{
+       struct plx_pci_card *card = pci_get_drvdata(pdev);
+       u32 cntrl;
+
+       cntrl = ioread32(card->conf_addr + PLX_CNTRL);
+       cntrl |= PLX_PCI_RESET;
+       iowrite32(cntrl, card->conf_addr + PLX_CNTRL);
+       udelay(100);
+       cntrl ^= PLX_PCI_RESET;
+       iowrite32(cntrl, card->conf_addr + PLX_CNTRL);
+};
+
+/* Special reset function for Marathon card */
+static void plx_pci_reset_marathon(struct pci_dev *pdev)
+{
+       void __iomem *reset_addr;
+       int i;
+       int reset_bar[2] = {3, 5};
+
+       plx_pci_reset_common(pdev);
+
+       for (i = 0; i < 2; i++) {
+               reset_addr = pci_iomap(pdev, reset_bar[i], 0);
+               if (!reset_addr) {
+                       dev_err(&pdev->dev, "Failed to remap reset "
+                               "space %d (BAR%d)\n", i, reset_bar[i]);
+               } else {
+                       /* reset the SJA1000 chip */
+                       iowrite8(0x1, reset_addr);
+                       udelay(100);
+                       pci_iounmap(pdev, reset_addr);
+               }
+       }
+}
+
+static void plx_pci_del_card(struct pci_dev *pdev)
+{
+       struct plx_pci_card *card = pci_get_drvdata(pdev);
+       struct net_device *dev;
+       struct sja1000_priv *priv;
+       int i = 0;
+
+       for (i = 0; i < card->channels; i++) {
+               dev = card->net_dev[i];
+               if (!dev)
+                       continue;
+
+               dev_info(&pdev->dev, "Removing %s\n", dev->name);
+               unregister_sja1000dev(dev);
+               priv = netdev_priv(dev);
+               if (priv->reg_base)
+                       pci_iounmap(pdev, priv->reg_base);
+               free_sja1000dev(dev);
+       }
+
+       plx_pci_reset_common(pdev);
+
+       /*
+        * Disable interrupts from PCI-card (PLX90xx) and disable Local_1,
+        * Local_2 interrupts
+        */
+       iowrite32(0x0, card->conf_addr + PLX_INTCSR);
+
+       if (card->conf_addr)
+               pci_iounmap(pdev, card->conf_addr);
+
+       kfree(card);
+
+       pci_disable_device(pdev);
+       pci_set_drvdata(pdev, NULL);
+}
+
+/*
+ * Probe PLX90xx based device for the SJA1000 chips and register each
+ * available CAN channel to SJA1000 Socket-CAN subsystem.
+ */
+static int __devinit plx_pci_add_card(struct pci_dev *pdev,
+                                     const struct pci_device_id *ent)
+{
+       struct sja1000_priv *priv;
+       struct net_device *dev;
+       struct plx_pci_card *card;
+       struct plx_pci_card_info *ci;
+       int err, i;
+       u32 val;
+       void __iomem *addr;
+
+       ci = (struct plx_pci_card_info *)ent->driver_data;
+
+       if (pci_enable_device(pdev) < 0) {
+               dev_err(&pdev->dev, "Failed to enable PCI device\n");
+               return -ENODEV;
+       }
+
+       dev_info(&pdev->dev, "Detected \"%s\" card at slot #%i\n",
+                ci->name, PCI_SLOT(pdev->devfn));
+
+       /* Allocate card structures to hold addresses, ... */
+       card = kzalloc(sizeof(*card), GFP_KERNEL);
+       if (!card) {
+               dev_err(&pdev->dev, "Unable to allocate memory\n");
+               pci_disable_device(pdev);
+               return -ENOMEM;
+       }
+
+       pci_set_drvdata(pdev, card);
+
+       card->channels = 0;
+
+       /* Remap PLX90xx configuration space */
+       addr = pci_iomap(pdev, ci->conf_map.bar, ci->conf_map.size);
+       if (!addr) {
+               err = -ENOMEM;
+               dev_err(&pdev->dev, "Failed to remap configuration space "
+                       "(BAR%d)\n", ci->conf_map.bar);
+               goto failure_cleanup;
+       }
+       card->conf_addr = addr + ci->conf_map.offset;
+
+       ci->reset_func(pdev);
+
+       /* Detect available channels */
+       for (i = 0; i < ci->channel_count; i++) {
+               struct plx_pci_channel_map *cm = &ci->chan_map_tbl[i];
+
+               dev = alloc_sja1000dev(0);
+               if (!dev) {
+                       err = -ENOMEM;
+                       goto failure_cleanup;
+               }
+
+               card->net_dev[i] = dev;
+               priv = netdev_priv(dev);
+               priv->priv = card;
+               priv->irq_flags = IRQF_SHARED;
+
+               dev->irq = pdev->irq;
+
+               /*
+                * Remap IO space of the SJA1000 chips
+                * This is device-dependent mapping
+                */
+               addr = pci_iomap(pdev, cm->bar, cm->size);
+               if (!addr) {
+                       err = -ENOMEM;
+                       dev_err(&pdev->dev, "Failed to remap BAR%d\n", cm->bar);
+                       goto failure_cleanup;
+               }
+
+               priv->reg_base = addr + cm->offset;
+               priv->read_reg = plx_pci_read_reg;
+               priv->write_reg = plx_pci_write_reg;
+
+               /* Check if channel is present */
+               if (plx_pci_check_sja1000(priv)) {
+                       priv->can.clock.freq = ci->can_clock;
+                       priv->ocr = ci->ocr;
+                       priv->cdr = ci->cdr;
+
+                       SET_NETDEV_DEV(dev, &pdev->dev);
+
+                       /* Register SJA1000 device */
+                       err = register_sja1000dev(dev);
+                       if (err) {
+                               dev_err(&pdev->dev, "Registering device failed "
+                                       "(err=%d)\n", err);
+                               free_sja1000dev(dev);
+                               goto failure_cleanup;
+                       }
+
+                       card->channels++;
+
+                       dev_info(&pdev->dev, "Channel #%d at 0x%p, irq %d "
+                                "registered as %s\n", i + 1, priv->reg_base,
+                                dev->irq, dev->name);
+               } else {
+                       dev_err(&pdev->dev, "Channel #%d not detected\n",
+                               i + 1);
+                       free_sja1000dev(dev);
+               }
+       }
+
+       if (!card->channels) {
+               err = -ENODEV;
+               goto failure_cleanup;
+       }
+
+       /*
+        * Enable interrupts from PCI-card (PLX90xx) and enable Local_1,
+        * Local_2 interrupts from the SJA1000 chips
+        */
+       val = ioread32(card->conf_addr + PLX_INTCSR);
+       val |= PLX_LINT1_EN | PLX_LINT2_EN | PLX_PCI_INT_EN;
+       iowrite32(val, card->conf_addr + PLX_INTCSR);
+
+       return 0;
+
+failure_cleanup:
+       dev_err(&pdev->dev, "Error: %d. Cleaning Up.\n", err);
+
+       plx_pci_del_card(pdev);
+
+       return err;
+}
+
+static struct pci_driver plx_pci_driver = {
+       .name = DRV_NAME,
+       .id_table = plx_pci_tbl,
+       .probe = plx_pci_add_card,
+       .remove = plx_pci_del_card,
+};
+
+static int __init plx_pci_init(void)
+{
+       return pci_register_driver(&plx_pci_driver);
+}
+
+static void __exit plx_pci_exit(void)
+{
+       pci_unregister_driver(&plx_pci_driver);
+}
+
+module_init(plx_pci_init);
+module_exit(plx_pci_exit);
index 542a4f7255b4f5db367ef755abb623aed752c9b1..ace103a44833378aef5d8b5027bb4a1db79ce19f 100644 (file)
@@ -249,6 +249,9 @@ static netdev_tx_t sja1000_start_xmit(struct sk_buff *skb,
        uint8_t dreg;
        int i;
 
+       if (can_dropped_invalid_skb(dev, skb))
+               return NETDEV_TX_OK;
+
        netif_stop_queue(dev);
 
        fi = dlc = cf->can_dlc;
@@ -564,6 +567,7 @@ struct net_device *alloc_sja1000dev(int sizeof_priv)
        priv->can.bittiming_const = &sja1000_bittiming_const;
        priv->can.do_set_bittiming = sja1000_set_bittiming;
        priv->can.do_set_mode = sja1000_set_mode;
+       priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES;
 
        if (sizeof_priv)
                priv->priv = (void *)priv + sizeof(struct sja1000_priv);
index 5c993c2da5281b24c74434ad54ccb0862fa9bc72..8332e242b0bedaaf9543de780649d38f0db184f3 100644 (file)
@@ -477,6 +477,9 @@ static netdev_tx_t ti_hecc_xmit(struct sk_buff *skb, struct net_device *ndev)
        u32 mbxno, mbx_mask, data;
        unsigned long flags;
 
+       if (can_dropped_invalid_skb(ndev, skb))
+               return NETDEV_TX_OK;
+
        mbxno = get_tx_head_mb(priv);
        mbx_mask = BIT(mbxno);
        spin_lock_irqsave(&priv->mbx_lock, flags);
@@ -491,7 +494,6 @@ static netdev_tx_t ti_hecc_xmit(struct sk_buff *skb, struct net_device *ndev)
        spin_unlock_irqrestore(&priv->mbx_lock, flags);
 
        /* Prepare mailbox for transmission */
-       data = min_t(u8, cf->can_dlc, 8);
        if (cf->can_id & CAN_RTR_FLAG) /* Remote transmission request */
                data |= HECC_CANMCF_RTR;
        data |= get_tx_head_prio(priv) << 8;
@@ -907,6 +909,7 @@ static int ti_hecc_probe(struct platform_device *pdev)
        priv->can.bittiming_const = &ti_hecc_bittiming_const;
        priv->can.do_set_mode = ti_hecc_do_set_mode;
        priv->can.do_get_state = ti_hecc_get_state;
+       priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES;
 
        ndev->irq = irq->start;
        ndev->flags |= IFF_ECHO;
index efbb05c71bf47fdde6af69fb13d1a38fdd80f032..bfab283ba9b18ebe8459ce247aa9a485a72a5f48 100644 (file)
@@ -767,6 +767,9 @@ static netdev_tx_t ems_usb_start_xmit(struct sk_buff *skb, struct net_device *ne
        size_t size = CPC_HEADER_SIZE + CPC_MSG_HEADER_LEN
                        + sizeof(struct cpc_can_msg);
 
+       if (can_dropped_invalid_skb(netdev, skb))
+               return NETDEV_TX_OK;
+
        /* create a URB, and a buffer for it, and copy the data to the URB */
        urb = usb_alloc_urb(0, GFP_ATOMIC);
        if (!urb) {
@@ -1019,6 +1022,7 @@ static int ems_usb_probe(struct usb_interface *intf,
        dev->can.bittiming_const = &ems_usb_bittiming_const;
        dev->can.do_set_bittiming = ems_usb_set_bittiming;
        dev->can.do_set_mode = ems_usb_set_mode;
+       dev->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES;
 
        netdev->flags |= IFF_ECHO; /* we support local echo */
 
index 80ac56313981983063340adb95150fe40d76bea9..d124d837ae58c4c1c5de7ce1d6a90d3fc86c5d52 100644 (file)
@@ -47,6 +47,7 @@
 #include <linux/if_arp.h>
 #include <linux/if_ether.h>
 #include <linux/can.h>
+#include <linux/can/dev.h>
 #include <net/rtnetlink.h>
 
 static __initdata const char banner[] =
@@ -70,10 +71,11 @@ MODULE_PARM_DESC(echo, "Echo sent frames (for testing). Default: 0 (Off)");
 
 static void vcan_rx(struct sk_buff *skb, struct net_device *dev)
 {
+       struct can_frame *cf = (struct can_frame *)skb->data;
        struct net_device_stats *stats = &dev->stats;
 
        stats->rx_packets++;
-       stats->rx_bytes += skb->len;
+       stats->rx_bytes += cf->can_dlc;
 
        skb->protocol  = htons(ETH_P_CAN);
        skb->pkt_type  = PACKET_BROADCAST;
@@ -85,11 +87,15 @@ static void vcan_rx(struct sk_buff *skb, struct net_device *dev)
 
 static netdev_tx_t vcan_tx(struct sk_buff *skb, struct net_device *dev)
 {
+       struct can_frame *cf = (struct can_frame *)skb->data;
        struct net_device_stats *stats = &dev->stats;
        int loop;
 
+       if (can_dropped_invalid_skb(dev, skb))
+               return NETDEV_TX_OK;
+
        stats->tx_packets++;
-       stats->tx_bytes += skb->len;
+       stats->tx_bytes += cf->can_dlc;
 
        /* set flag whether this packet has to be looped back */
        loop = skb->pkt_type == PACKET_LOOPBACK;
@@ -103,7 +109,7 @@ static netdev_tx_t vcan_tx(struct sk_buff *skb, struct net_device *dev)
                         * CAN core already did the echo for us
                         */
                        stats->rx_packets++;
-                       stats->rx_bytes += skb->len;
+                       stats->rx_bytes += cf->can_dlc;
                }
                kfree_skb(skb);
                return NETDEV_TX_OK;
index f857afe8e4883c8310778ceb6ba8568f0ae886f3..ad47e5126fdea010e2de1c0547efa90b528c332e 100644 (file)
 #define cas_page_unmap(x)    kunmap_atomic((x), KM_SKB_DATA_SOFTIRQ)
 #define CAS_NCPUS            num_online_cpus()
 
-#if defined(CONFIG_CASSINI_NAPI) && defined(HAVE_NETDEV_POLL)
+#ifdef CONFIG_CASSINI_NAPI
 #define USE_NAPI
 #define cas_skb_release(x)  netif_receive_skb(x)
 #else
@@ -236,7 +236,7 @@ static u16 link_modes[] __devinitdata = {
        CAS_BMCR_SPEED1000|BMCR_FULLDPLX /* 5 : 1000bt full duplex */
 };
 
-static struct pci_device_id cas_pci_tbl[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(cas_pci_tbl) = {
        { PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_CASSINI,
          PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
        { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SATURN,
index 699d22c5fe094f03919aefd7e2672a412955ab19..f6462b54f823fabffd42d247c584d2ae5528937f 100644 (file)
@@ -334,7 +334,7 @@ static inline int t1_is_asic(const adapter_t *adapter)
        return adapter->params.is_asic;
 }
 
-extern struct pci_device_id t1_pci_tbl[];
+extern const struct pci_device_id t1_pci_tbl[];
 
 static inline int adapter_matches_type(const adapter_t *adapter,
                                       int version, int revision)
index 17720c6e5bfe028b8a5dbfd927f52a0af6c8929b..2402d372c886fbec10ec38ce868b74bfa1390835 100644 (file)
@@ -528,7 +528,7 @@ static const struct board_info t1_board[] = {
 
 };
 
-struct pci_device_id t1_pci_tbl[] = {
+DEFINE_PCI_DEVICE_TABLE(t1_pci_tbl) = {
        CH_DEVICE(8, 0, CH_BRD_T110_1CU),
        CH_DEVICE(8, 1, CH_BRD_T110_1CU),
        CH_DEVICE(7, 0, CH_BRD_N110_1F),
index 89bec9c3c141a86517f7113d223bcf541a81c3db..73622f5312cb66b8b5b9b007dd7a0a9d917e4721 100644 (file)
@@ -80,7 +80,7 @@ enum {
 #define CH_DEVICE(devid, idx) \
        { PCI_VENDOR_ID_CHELSIO, devid, PCI_ANY_ID, PCI_ANY_ID, 0, 0, idx }
 
-static const struct pci_device_id cxgb3_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(cxgb3_pci_tbl) = {
        CH_DEVICE(0x20, 0),     /* PE9000 */
        CH_DEVICE(0x21, 1),     /* T302E */
        CH_DEVICE(0x22, 2),     /* T310E */
index 75064eea1d87eea36acb36b5351f7f5a16855adb..9498361119d6747dfdd7190a90982bcc9c8b87f5 100644 (file)
@@ -1252,7 +1252,7 @@ int cxgb3_offload_activate(struct adapter *adapter)
        struct mtutab mtutab;
        unsigned int l2t_capacity;
 
-       t = kcalloc(1, sizeof(*t), GFP_KERNEL);
+       t = kzalloc(sizeof(*t), GFP_KERNEL);
        if (!t)
                return -ENOMEM;
 
index bdbd14727e4b232987632fb19f114510e6068837..4cf9b7962afa99ccf70a4153f638f5dcdaf40779 100644 (file)
@@ -480,6 +480,7 @@ static inline void ring_fl_db(struct adapter *adap, struct sge_fl *q)
 {
        if (q->pend_cred >= q->credits / 4) {
                q->pend_cred = 0;
+               wmb();
                t3_write_reg(adap, A_SG_KDOORBELL, V_EGRCNTX(q->cntxt_id));
        }
 }
@@ -2282,11 +2283,14 @@ static int process_responses(struct adapter *adap, struct sge_qset *qs,
        while (likely(budget_left && is_new_response(r, q))) {
                int packet_complete, eth, ethpad = 2, lro = qs->lro_enabled;
                struct sk_buff *skb = NULL;
-               u32 len, flags = ntohl(r->flags);
-               __be32 rss_hi = *(const __be32 *)r,
-                      rss_lo = r->rss_hdr.rss_hash_val;
+               u32 len, flags;
+               __be32 rss_hi, rss_lo;
 
+               rmb();
                eth = r->rss_hdr.opcode == CPL_RX_PKT;
+               rss_hi = *(const __be32 *)r;
+               rss_lo = r->rss_hdr.rss_hash_val;
+               flags = ntohl(r->flags);
 
                if (unlikely(flags & F_RSPD_ASYNC_NOTIF)) {
                        skb = alloc_skb(AN_PKT_SIZE, GFP_ATOMIC);
@@ -2497,7 +2501,10 @@ static int process_pure_responses(struct adapter *adap, struct sge_qset *qs,
                        refill_rspq(adap, q, q->credits);
                        q->credits = 0;
                }
-       } while (is_new_response(r, q) && is_pure_response(r));
+               if (!is_new_response(r, q))
+                       break;
+               rmb();
+       } while (is_pure_response(r));
 
        if (sleeping)
                check_ring_db(adap, qs, sleeping);
@@ -2531,6 +2538,7 @@ static inline int handle_responses(struct adapter *adap, struct sge_rspq *q)
 
        if (!is_new_response(r, q))
                return -1;
+       rmb();
        if (is_pure_response(r) && process_pure_responses(adap, qs, r) == 0) {
                t3_write_reg(adap, A_SG_GTS, V_RSPQ(q->cntxt_id) |
                             V_NEWTIMER(q->holdoff_tmr) | V_NEWINDEX(q->cidx));
index 6a6ea038d7a31df972cf0ff839888a4679e9c7b7..98da085445e61c3a886245b9ec654b8fa67e466c 100644 (file)
@@ -1052,12 +1052,9 @@ static int __devinit dfx_driver_init(struct net_device *dev,
                board_name = "DEFEA";
        if (dfx_bus_pci)
                board_name = "DEFPA";
-       pr_info("%s: %s at %saddr = 0x%llx, IRQ = %d, "
-               "Hardware addr = %02X-%02X-%02X-%02X-%02X-%02X\n",
+       pr_info("%s: %s at %saddr = 0x%llx, IRQ = %d, Hardware addr = %pMF\n",
                print_name, board_name, dfx_use_mmio ? "" : "I/O ",
-               (long long)bar_start, dev->irq,
-               dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
-               dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+               (long long)bar_start, dev->irq, dev->dev_addr);
 
        /*
         * Get memory for descriptor block, consumer block, and other buffers
@@ -3631,7 +3628,7 @@ static int __devinit dfx_pci_register(struct pci_dev *,
                                      const struct pci_device_id *);
 static void __devexit dfx_pci_unregister(struct pci_dev *);
 
-static struct pci_device_id dfx_pci_table[] = {
+static DEFINE_PCI_DEVICE_TABLE(dfx_pci_table) = {
        { PCI_DEVICE(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_FDDI) },
        { }
 };
index 266ec8777ca81797f0dfd92b22875229644e5584..7caab3d26a9eee8ae6761a2d9f188b8efe33ff14 100644 (file)
@@ -537,7 +537,7 @@ struct netdev_private {
         driver_data             Data private to the driver.
 */
 
-static const struct pci_device_id rio_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(rio_pci_tbl) = {
        {0x1186, 0x4000, PCI_ANY_ID, PCI_ANY_ID, },
        {0x13f0, 0x1021, PCI_ANY_ID, PCI_ANY_ID, },
        { }
index 839fb2b136d37bd9993cbfe42d44ddcffec90e2c..5c7a155e849a67374440b64184624704774b24ac 100644 (file)
@@ -208,7 +208,7 @@ MODULE_PARM_DESC(use_io, "Force use of i/o access mode");
 #define INTEL_8255X_ETHERNET_DEVICE(device_id, ich) {\
        PCI_VENDOR_ID_INTEL, device_id, PCI_ANY_ID, PCI_ANY_ID, \
        PCI_CLASS_NETWORK_ETHERNET << 8, 0xFFFF00, ich }
-static struct pci_device_id e100_id_table[] = {
+static DEFINE_PCI_DEVICE_TABLE(e100_id_table) = {
        INTEL_8255X_ETHERNET_DEVICE(0x1029, 0),
        INTEL_8255X_ETHERNET_DEVICE(0x1030, 0),
        INTEL_8255X_ETHERNET_DEVICE(0x1031, 3),
index d29bb532eccf15349f8792fbb0f5b803beda29db..b608528f26fc962527104963ce90ec3799dca14c 100644 (file)
@@ -42,7 +42,7 @@ static const char e1000_copyright[] = "Copyright (c) 1999-2006 Intel Corporation
  * Macro expands to...
  *   {PCI_DEVICE(PCI_VENDOR_ID_INTEL, device_id)}
  */
-static struct pci_device_id e1000_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(e1000_pci_tbl) = {
        INTEL_E1000_ETHERNET_DEVICE(0x1000),
        INTEL_E1000_ETHERNET_DEVICE(0x1001),
        INTEL_E1000_ETHERNET_DEVICE(0x1004),
@@ -2127,7 +2127,7 @@ static void e1000_set_rx_mode(struct net_device *netdev)
                        rctl |= E1000_RCTL_VFE;
        }
 
-       if (netdev->uc.count > rar_entries - 1) {
+       if (netdev_uc_count(netdev) > rar_entries - 1) {
                rctl |= E1000_RCTL_UPE;
        } else if (!(netdev->flags & IFF_PROMISC)) {
                rctl &= ~E1000_RCTL_UPE;
@@ -2150,7 +2150,7 @@ static void e1000_set_rx_mode(struct net_device *netdev)
         */
        i = 1;
        if (use_uc)
-               list_for_each_entry(ha, &netdev->uc.list, list) {
+               netdev_for_each_uc_addr(ha, netdev) {
                        if (i == rar_entries)
                                break;
                        e1000_rar_set(hw, ha->addr, i++);
index 02d67d047d963854c1c5d8210d14c46d4bbcdf0d..3c95acb3a87d0eb641ec7146111bd5a88a516ea9 100644 (file)
@@ -267,8 +267,14 @@ static s32 e1000_init_mac_params_82571(struct e1000_adapter *adapter)
        }
 
        switch (hw->mac.type) {
+       case e1000_82573:
+               func->set_lan_id = e1000_set_lan_id_single_port;
+               func->check_mng_mode = e1000e_check_mng_mode_generic;
+               func->led_on = e1000e_led_on_generic;
+               break;
        case e1000_82574:
        case e1000_82583:
+               func->set_lan_id = e1000_set_lan_id_single_port;
                func->check_mng_mode = e1000_check_mng_mode_82574;
                func->led_on = e1000_led_on_82574;
                break;
@@ -922,9 +928,12 @@ static s32 e1000_reset_hw_82571(struct e1000_hw *hw)
        ew32(IMC, 0xffffffff);
        icr = er32(ICR);
 
-       if (hw->mac.type == e1000_82571 &&
-               hw->dev_spec.e82571.alt_mac_addr_is_present)
-                       e1000e_set_laa_state_82571(hw, true);
+       /* Install any alternate MAC address into RAR0 */
+       ret_val = e1000_check_alt_mac_addr_generic(hw);
+       if (ret_val)
+               return ret_val;
+
+       e1000e_set_laa_state_82571(hw, true);
 
        /* Reinitialize the 82571 serdes link state machine */
        if (hw->phy.media_type == e1000_media_type_internal_serdes)
@@ -1224,32 +1233,6 @@ static s32 e1000_led_on_82574(struct e1000_hw *hw)
        return 0;
 }
 
-/**
- *  e1000_update_mc_addr_list_82571 - Update Multicast addresses
- *  @hw: pointer to the HW structure
- *  @mc_addr_list: array of multicast addresses to program
- *  @mc_addr_count: number of multicast addresses to program
- *  @rar_used_count: the first RAR register free to program
- *  @rar_count: total number of supported Receive Address Registers
- *
- *  Updates the Receive Address Registers and Multicast Table Array.
- *  The caller must have a packed mc_addr_list of multicast addresses.
- *  The parameter rar_count will usually be hw->mac.rar_entry_count
- *  unless there are workarounds that change this.
- **/
-static void e1000_update_mc_addr_list_82571(struct e1000_hw *hw,
-                                           u8 *mc_addr_list,
-                                           u32 mc_addr_count,
-                                           u32 rar_used_count,
-                                           u32 rar_count)
-{
-       if (e1000e_get_laa_state_82571(hw))
-               rar_count--;
-
-       e1000e_update_mc_addr_list_generic(hw, mc_addr_list, mc_addr_count,
-                                          rar_used_count, rar_count);
-}
-
 /**
  *  e1000_setup_link_82571 - Setup flow control and link settings
  *  @hw: pointer to the HW structure
@@ -1620,6 +1603,29 @@ static s32 e1000_fix_nvm_checksum_82571(struct e1000_hw *hw)
        return 0;
 }
 
+/**
+ *  e1000_read_mac_addr_82571 - Read device MAC address
+ *  @hw: pointer to the HW structure
+ **/
+static s32 e1000_read_mac_addr_82571(struct e1000_hw *hw)
+{
+       s32 ret_val = 0;
+
+       /*
+        * If there's an alternate MAC address place it in RAR0
+        * so that it will override the Si installed default perm
+        * address.
+        */
+       ret_val = e1000_check_alt_mac_addr_generic(hw);
+       if (ret_val)
+               goto out;
+
+       ret_val = e1000_read_mac_addr_generic(hw);
+
+out:
+       return ret_val;
+}
+
 /**
  * e1000_power_down_phy_copper_82571 - Remove link during PHY power down
  * @hw: pointer to the HW structure
@@ -1695,10 +1701,11 @@ static struct e1000_mac_operations e82571_mac_ops = {
        .cleanup_led            = e1000e_cleanup_led_generic,
        .clear_hw_cntrs         = e1000_clear_hw_cntrs_82571,
        .get_bus_info           = e1000e_get_bus_info_pcie,
+       .set_lan_id             = e1000_set_lan_id_multi_port_pcie,
        /* .get_link_up_info: media type dependent */
        /* .led_on: mac type dependent */
        .led_off                = e1000e_led_off_generic,
-       .update_mc_addr_list    = e1000_update_mc_addr_list_82571,
+       .update_mc_addr_list    = e1000e_update_mc_addr_list_generic,
        .write_vfta             = e1000_write_vfta_generic,
        .clear_vfta             = e1000_clear_vfta_82571,
        .reset_hw               = e1000_reset_hw_82571,
@@ -1706,6 +1713,7 @@ static struct e1000_mac_operations e82571_mac_ops = {
        .setup_link             = e1000_setup_link_82571,
        /* .setup_physical_interface: media type dependent */
        .setup_led              = e1000e_setup_led_generic,
+       .read_mac_addr          = e1000_read_mac_addr_82571,
 };
 
 static struct e1000_phy_operations e82_phy_ops_igp = {
index e02e38221ed47c9ab428a7aec033c16ac97e2584..db05ec35574931538e136e40db65988a43df45b4 100644 (file)
  */
 #define E1000_RAR_ENTRIES     15
 #define E1000_RAH_AV  0x80000000        /* Receive descriptor valid */
+#define E1000_RAL_MAC_ADDR_LEN 4
+#define E1000_RAH_MAC_ADDR_LEN 2
 
 /* Error Codes */
 #define E1000_ERR_NVM      1
index d236efaf74781d68fd41c34d591c066ee063909b..318bdb28a7cd92504700e2aff0e682c9c643b8bb 100644 (file)
@@ -503,6 +503,8 @@ extern s32 e1000e_cleanup_led_generic(struct e1000_hw *hw);
 extern s32 e1000e_led_on_generic(struct e1000_hw *hw);
 extern s32 e1000e_led_off_generic(struct e1000_hw *hw);
 extern s32 e1000e_get_bus_info_pcie(struct e1000_hw *hw);
+extern void e1000_set_lan_id_multi_port_pcie(struct e1000_hw *hw);
+extern void e1000_set_lan_id_single_port(struct e1000_hw *hw);
 extern s32 e1000e_get_speed_and_duplex_copper(struct e1000_hw *hw, u16 *speed, u16 *duplex);
 extern s32 e1000e_get_speed_and_duplex_fiber_serdes(struct e1000_hw *hw, u16 *speed, u16 *duplex);
 extern s32 e1000e_disable_pcie_master(struct e1000_hw *hw);
@@ -517,9 +519,7 @@ extern void e1000_clear_vfta_generic(struct e1000_hw *hw);
 extern void e1000e_init_rx_addrs(struct e1000_hw *hw, u16 rar_count);
 extern void e1000e_update_mc_addr_list_generic(struct e1000_hw *hw,
                                               u8 *mc_addr_list,
-                                              u32 mc_addr_count,
-                                              u32 rar_used_count,
-                                              u32 rar_count);
+                                              u32 mc_addr_count);
 extern void e1000e_rar_set(struct e1000_hw *hw, u8 *addr, u32 index);
 extern s32 e1000e_set_fc_watermarks(struct e1000_hw *hw);
 extern void e1000e_set_pcie_no_snoop(struct e1000_hw *hw, u32 no_snoop);
@@ -530,6 +530,7 @@ extern s32 e1000e_config_fc_after_link_up(struct e1000_hw *hw);
 extern s32 e1000e_force_mac_fc(struct e1000_hw *hw);
 extern s32 e1000e_blink_led(struct e1000_hw *hw);
 extern void e1000_write_vfta_generic(struct e1000_hw *hw, u32 offset, u32 value);
+extern s32 e1000_check_alt_mac_addr_generic(struct e1000_hw *hw);
 extern void e1000e_reset_adaptive(struct e1000_hw *hw);
 extern void e1000e_update_adaptive(struct e1000_hw *hw);
 
@@ -629,7 +630,15 @@ extern s32 e1000e_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words, u16
 extern s32 e1000e_validate_nvm_checksum_generic(struct e1000_hw *hw);
 extern void e1000e_release_nvm(struct e1000_hw *hw);
 extern void e1000e_reload_nvm(struct e1000_hw *hw);
-extern s32 e1000e_read_mac_addr(struct e1000_hw *hw);
+extern s32 e1000_read_mac_addr_generic(struct e1000_hw *hw);
+
+static inline s32 e1000e_read_mac_addr(struct e1000_hw *hw)
+{
+       if (hw->mac.ops.read_mac_addr)
+               return hw->mac.ops.read_mac_addr(hw);
+
+       return e1000_read_mac_addr_generic(hw);
+}
 
 static inline s32 e1000_validate_nvm_checksum(struct e1000_hw *hw)
 {
index e2aa3b7885642375f49ff88c5977647f7f72f399..27d21589a69afa128e7a6f0be459703a6e917053 100644 (file)
@@ -246,6 +246,9 @@ static s32 e1000_init_mac_params_80003es2lan(struct e1000_adapter *adapter)
                break;
        }
 
+       /* set lan id for port to determine which phy lock to use */
+       hw->mac.ops.set_lan_id(hw);
+
        return 0;
 }
 
@@ -814,7 +817,9 @@ static s32 e1000_reset_hw_80003es2lan(struct e1000_hw *hw)
        ew32(IMC, 0xffffffff);
        icr = er32(ICR);
 
-       return 0;
+       ret_val = e1000_check_alt_mac_addr_generic(hw);
+
+       return ret_val;
 }
 
 /**
@@ -1339,6 +1344,29 @@ static s32 e1000_write_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset,
        return ret_val;
 }
 
+/**
+ *  e1000_read_mac_addr_80003es2lan - Read device MAC address
+ *  @hw: pointer to the HW structure
+ **/
+static s32 e1000_read_mac_addr_80003es2lan(struct e1000_hw *hw)
+{
+       s32 ret_val = 0;
+
+       /*
+        * If there's an alternate MAC address place it in RAR0
+        * so that it will override the Si installed default perm
+        * address.
+        */
+       ret_val = e1000_check_alt_mac_addr_generic(hw);
+       if (ret_val)
+               goto out;
+
+       ret_val = e1000_read_mac_addr_generic(hw);
+
+out:
+       return ret_val;
+}
+
 /**
  * e1000_power_down_phy_copper_80003es2lan - Remove link during PHY power down
  * @hw: pointer to the HW structure
@@ -1403,12 +1431,14 @@ static void e1000_clear_hw_cntrs_80003es2lan(struct e1000_hw *hw)
 }
 
 static struct e1000_mac_operations es2_mac_ops = {
+       .read_mac_addr          = e1000_read_mac_addr_80003es2lan,
        .id_led_init            = e1000e_id_led_init,
        .check_mng_mode         = e1000e_check_mng_mode_generic,
        /* check_for_link dependent on media type */
        .cleanup_led            = e1000e_cleanup_led_generic,
        .clear_hw_cntrs         = e1000_clear_hw_cntrs_80003es2lan,
        .get_bus_info           = e1000e_get_bus_info_pcie,
+       .set_lan_id             = e1000_set_lan_id_multi_port_pcie,
        .get_link_up_info       = e1000_get_link_up_info_80003es2lan,
        .led_on                 = e1000e_led_on_generic,
        .led_off                = e1000e_led_off_generic,
index eccf29b75c41ed062551249f6552cdfc373a3d85..8bdcd5f24eff1b4c3d99e3ca7cb99b7ef2c9ecbd 100644 (file)
@@ -389,6 +389,9 @@ enum e1e_registers {
 
 #define E1000_FUNC_1 1
 
+#define E1000_ALT_MAC_ADDRESS_OFFSET_LAN0   0
+#define E1000_ALT_MAC_ADDRESS_OFFSET_LAN1   3
+
 enum e1000_mac_type {
        e1000_82571,
        e1000_82572,
@@ -746,16 +749,18 @@ struct e1000_mac_operations {
        void (*clear_hw_cntrs)(struct e1000_hw *);
        void (*clear_vfta)(struct e1000_hw *);
        s32  (*get_bus_info)(struct e1000_hw *);
+       void (*set_lan_id)(struct e1000_hw *);
        s32  (*get_link_up_info)(struct e1000_hw *, u16 *, u16 *);
        s32  (*led_on)(struct e1000_hw *);
        s32  (*led_off)(struct e1000_hw *);
-       void (*update_mc_addr_list)(struct e1000_hw *, u8 *, u32, u32, u32);
+       void (*update_mc_addr_list)(struct e1000_hw *, u8 *, u32);
        s32  (*reset_hw)(struct e1000_hw *);
        s32  (*init_hw)(struct e1000_hw *);
        s32  (*setup_link)(struct e1000_hw *);
        s32  (*setup_physical_interface)(struct e1000_hw *);
        s32  (*setup_led)(struct e1000_hw *);
        void (*write_vfta)(struct e1000_hw *, u32, u32);
+       s32  (*read_mac_addr)(struct e1000_hw *);
 };
 
 /* Function pointers for the PHY. */
@@ -814,6 +819,10 @@ struct e1000_mac_info {
        u16 ifs_ratio;
        u16 ifs_step_size;
        u16 mta_reg_count;
+
+       /* Maximum size of the MTA register table in all supported adapters */
+       #define MAX_MTA_REG 128
+       u32 mta_shadow[MAX_MTA_REG];
        u16 rar_entry_count;
 
        u8  forced_speed_duplex;
@@ -897,7 +906,6 @@ struct e1000_fc_info {
 
 struct e1000_dev_spec_82571 {
        bool laa_is_present;
-       bool alt_mac_addr_is_present;
        u32 smb_counter;
 };
 
index 8b6ecd127889e6d19ed155c725dcd4f594d73666..54d03a0ce3ce268e256d23e5f12e638777a91481 100644 (file)
@@ -3368,6 +3368,7 @@ static struct e1000_mac_operations ich8_mac_ops = {
        /* cleanup_led dependent on mac type */
        .clear_hw_cntrs         = e1000_clear_hw_cntrs_ich8lan,
        .get_bus_info           = e1000_get_bus_info_ich8lan,
+       .set_lan_id             = e1000_set_lan_id_single_port,
        .get_link_up_info       = e1000_get_link_up_info_ich8lan,
        /* led_on dependent on mac type */
        /* led_off dependent on mac type */
index 2fa9b36a2c5ae3d289e7923751bd7b396076a103..2425ed11d5cccae2b71e6646a0c75cd381524930 100644 (file)
@@ -51,10 +51,10 @@ enum e1000_mng_mode {
  **/
 s32 e1000e_get_bus_info_pcie(struct e1000_hw *hw)
 {
+       struct e1000_mac_info *mac = &hw->mac;
        struct e1000_bus_info *bus = &hw->bus;
        struct e1000_adapter *adapter = hw->adapter;
-       u32 status;
-       u16 pcie_link_status, pci_header_type, cap_offset;
+       u16 pcie_link_status, cap_offset;
 
        cap_offset = pci_find_capability(adapter->pdev, PCI_CAP_ID_EXP);
        if (!cap_offset) {
@@ -68,19 +68,45 @@ s32 e1000e_get_bus_info_pcie(struct e1000_hw *hw)
                                                    PCIE_LINK_WIDTH_SHIFT);
        }
 
-       pci_read_config_word(adapter->pdev, PCI_HEADER_TYPE_REGISTER,
-                            &pci_header_type);
-       if (pci_header_type & PCI_HEADER_TYPE_MULTIFUNC) {
-               status = er32(STATUS);
-               bus->func = (status & E1000_STATUS_FUNC_MASK)
-                           >> E1000_STATUS_FUNC_SHIFT;
-       } else {
-               bus->func = 0;
-       }
+       mac->ops.set_lan_id(hw);
 
        return 0;
 }
 
+/**
+ *  e1000_set_lan_id_multi_port_pcie - Set LAN id for PCIe multiple port devices
+ *
+ *  @hw: pointer to the HW structure
+ *
+ *  Determines the LAN function id by reading memory-mapped registers
+ *  and swaps the port value if requested.
+ **/
+void e1000_set_lan_id_multi_port_pcie(struct e1000_hw *hw)
+{
+       struct e1000_bus_info *bus = &hw->bus;
+       u32 reg;
+
+       /*
+        * The status register reports the correct function number
+        * for the device regardless of function swap state.
+        */
+       reg = er32(STATUS);
+       bus->func = (reg & E1000_STATUS_FUNC_MASK) >> E1000_STATUS_FUNC_SHIFT;
+}
+
+/**
+ *  e1000_set_lan_id_single_port - Set LAN id for a single port device
+ *  @hw: pointer to the HW structure
+ *
+ *  Sets the LAN function id to zero for a single port device.
+ **/
+void e1000_set_lan_id_single_port(struct e1000_hw *hw)
+{
+       struct e1000_bus_info *bus = &hw->bus;
+
+       bus->func = 0;
+}
+
 /**
  *  e1000_clear_vfta_generic - Clear VLAN filter table
  *  @hw: pointer to the HW structure
@@ -138,6 +164,68 @@ void e1000e_init_rx_addrs(struct e1000_hw *hw, u16 rar_count)
                e1000e_rar_set(hw, mac_addr, i);
 }
 
+/**
+ *  e1000_check_alt_mac_addr_generic - Check for alternate MAC addr
+ *  @hw: pointer to the HW structure
+ *
+ *  Checks the nvm for an alternate MAC address.  An alternate MAC address
+ *  can be setup by pre-boot software and must be treated like a permanent
+ *  address and must override the actual permanent MAC address. If an
+ *  alternate MAC address is found it is programmed into RAR0, replacing
+ *  the permanent address that was installed into RAR0 by the Si on reset.
+ *  This function will return SUCCESS unless it encounters an error while
+ *  reading the EEPROM.
+ **/
+s32 e1000_check_alt_mac_addr_generic(struct e1000_hw *hw)
+{
+       u32 i;
+       s32 ret_val = 0;
+       u16 offset, nvm_alt_mac_addr_offset, nvm_data;
+       u8 alt_mac_addr[ETH_ALEN];
+
+       ret_val = e1000_read_nvm(hw, NVM_ALT_MAC_ADDR_PTR, 1,
+                                &nvm_alt_mac_addr_offset);
+       if (ret_val) {
+               e_dbg("NVM Read Error\n");
+               goto out;
+       }
+
+       if (nvm_alt_mac_addr_offset == 0xFFFF) {
+               /* There is no Alternate MAC Address */
+               goto out;
+       }
+
+       if (hw->bus.func == E1000_FUNC_1)
+               nvm_alt_mac_addr_offset += E1000_ALT_MAC_ADDRESS_OFFSET_LAN1;
+       for (i = 0; i < ETH_ALEN; i += 2) {
+               offset = nvm_alt_mac_addr_offset + (i >> 1);
+               ret_val = e1000_read_nvm(hw, offset, 1, &nvm_data);
+               if (ret_val) {
+                       e_dbg("NVM Read Error\n");
+                       goto out;
+               }
+
+               alt_mac_addr[i] = (u8)(nvm_data & 0xFF);
+               alt_mac_addr[i + 1] = (u8)(nvm_data >> 8);
+       }
+
+       /* if multicast bit is set, the alternate address will not be used */
+       if (alt_mac_addr[0] & 0x01) {
+               e_dbg("Ignoring Alternate Mac Address with MC bit set\n");
+               goto out;
+       }
+
+       /*
+        * We have a valid alternate MAC address, and we want to treat it the
+        * same as the normal permanent MAC address stored by the HW into the
+        * RAR. Do this by mapping this address into RAR0.
+        */
+       e1000e_rar_set(hw, alt_mac_addr, 0);
+
+out:
+       return ret_val;
+}
+
 /**
  *  e1000e_rar_set - Set receive address register
  *  @hw: pointer to the HW structure
@@ -252,62 +340,34 @@ static u32 e1000_hash_mc_addr(struct e1000_hw *hw, u8 *mc_addr)
  *  @hw: pointer to the HW structure
  *  @mc_addr_list: array of multicast addresses to program
  *  @mc_addr_count: number of multicast addresses to program
- *  @rar_used_count: the first RAR register free to program
- *  @rar_count: total number of supported Receive Address Registers
  *
- *  Updates the Receive Address Registers and Multicast Table Array.
+ *  Updates entire Multicast Table Array.
  *  The caller must have a packed mc_addr_list of multicast addresses.
- *  The parameter rar_count will usually be hw->mac.rar_entry_count
- *  unless there are workarounds that change this.
  **/
 void e1000e_update_mc_addr_list_generic(struct e1000_hw *hw,
-                                       u8 *mc_addr_list, u32 mc_addr_count,
-                                       u32 rar_used_count, u32 rar_count)
+                                       u8 *mc_addr_list, u32 mc_addr_count)
 {
-       u32 i;
-       u32 *mcarray = kzalloc(hw->mac.mta_reg_count * sizeof(u32), GFP_ATOMIC);
+       u32 hash_value, hash_bit, hash_reg;
+       int i;
 
-       if (!mcarray) {
-               printk(KERN_ERR "multicast array memory allocation failed\n");
-               return;
-       }
+       /* clear mta_shadow */
+       memset(&hw->mac.mta_shadow, 0, sizeof(hw->mac.mta_shadow));
 
-       /*
-        * Load the first set of multicast addresses into the exact
-        * filters (RAR).  If there are not enough to fill the RAR
-        * array, clear the filters.
-        */
-       for (i = rar_used_count; i < rar_count; i++) {
-               if (mc_addr_count) {
-                       e1000e_rar_set(hw, mc_addr_list, i);
-                       mc_addr_count--;
-                       mc_addr_list += ETH_ALEN;
-               } else {
-                       E1000_WRITE_REG_ARRAY(hw, E1000_RA, i << 1, 0);
-                       e1e_flush();
-                       E1000_WRITE_REG_ARRAY(hw, E1000_RA, (i << 1) + 1, 0);
-                       e1e_flush();
-               }
-       }
-
-       /* Load any remaining multicast addresses into the hash table. */
-       for (; mc_addr_count > 0; mc_addr_count--) {
-               u32 hash_value, hash_reg, hash_bit, mta;
+       /* update mta_shadow from mc_addr_list */
+       for (i = 0; (u32) i < mc_addr_count; i++) {
                hash_value = e1000_hash_mc_addr(hw, mc_addr_list);
-               e_dbg("Hash value = 0x%03X\n", hash_value);
+
                hash_reg = (hash_value >> 5) & (hw->mac.mta_reg_count - 1);
                hash_bit = hash_value & 0x1F;
-               mta = (1 << hash_bit);
-               mcarray[hash_reg] |= mta;
-               mc_addr_list += ETH_ALEN;
-       }
 
-       /* write the hash table completely */
-       for (i = 0; i < hw->mac.mta_reg_count; i++)
-               E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, mcarray[i]);
+               hw->mac.mta_shadow[hash_reg] |= (1 << hash_bit);
+               mc_addr_list += (ETH_ALEN);
+       }
 
+       /* replace the entire MTA table */
+       for (i = hw->mac.mta_reg_count - 1; i >= 0; i--)
+               E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, hw->mac.mta_shadow[i]);
        e1e_flush();
-       kfree(mcarray);
 }
 
 /**
@@ -2072,67 +2132,27 @@ s32 e1000e_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
 }
 
 /**
- *  e1000e_read_mac_addr - Read device MAC address
+ *  e1000_read_mac_addr_generic - Read device MAC address
  *  @hw: pointer to the HW structure
  *
  *  Reads the device MAC address from the EEPROM and stores the value.
  *  Since devices with two ports use the same EEPROM, we increment the
  *  last bit in the MAC address for the second port.
  **/
-s32 e1000e_read_mac_addr(struct e1000_hw *hw)
+s32 e1000_read_mac_addr_generic(struct e1000_hw *hw)
 {
-       s32 ret_val;
-       u16 offset, nvm_data, i;
-       u16 mac_addr_offset = 0;
-
-       if (hw->mac.type == e1000_82571) {
-               /* Check for an alternate MAC address.  An alternate MAC
-                * address can be setup by pre-boot software and must be
-                * treated like a permanent address and must override the
-                * actual permanent MAC address.*/
-               ret_val = e1000_read_nvm(hw, NVM_ALT_MAC_ADDR_PTR, 1,
-                                        &mac_addr_offset);
-               if (ret_val) {
-                       e_dbg("NVM Read Error\n");
-                       return ret_val;
-               }
-               if (mac_addr_offset == 0xFFFF)
-                       mac_addr_offset = 0;
-
-               if (mac_addr_offset) {
-                       if (hw->bus.func == E1000_FUNC_1)
-                               mac_addr_offset += ETH_ALEN/sizeof(u16);
-
-                       /* make sure we have a valid mac address here
-                       * before using it */
-                       ret_val = e1000_read_nvm(hw, mac_addr_offset, 1,
-                                                &nvm_data);
-                       if (ret_val) {
-                               e_dbg("NVM Read Error\n");
-                               return ret_val;
-                       }
-                       if (nvm_data & 0x0001)
-                               mac_addr_offset = 0;
-               }
+       u32 rar_high;
+       u32 rar_low;
+       u16 i;
 
-               if (mac_addr_offset)
-               hw->dev_spec.e82571.alt_mac_addr_is_present = 1;
-       }
+       rar_high = er32(RAH(0));
+       rar_low = er32(RAL(0));
 
-       for (i = 0; i < ETH_ALEN; i += 2) {
-               offset = mac_addr_offset + (i >> 1);
-               ret_val = e1000_read_nvm(hw, offset, 1, &nvm_data);
-               if (ret_val) {
-                       e_dbg("NVM Read Error\n");
-                       return ret_val;
-               }
-               hw->mac.perm_addr[i] = (u8)(nvm_data & 0xFF);
-               hw->mac.perm_addr[i+1] = (u8)(nvm_data >> 8);
-       }
+       for (i = 0; i < E1000_RAL_MAC_ADDR_LEN; i++)
+               hw->mac.perm_addr[i] = (u8)(rar_low >> (i*8));
 
-       /* Flip last bit of mac address if we're on second port */
-       if (!mac_addr_offset && hw->bus.func == E1000_FUNC_1)
-               hw->mac.perm_addr[5] ^= 1;
+       for (i = 0; i < E1000_RAH_MAC_ADDR_LEN; i++)
+               hw->mac.perm_addr[i+4] = (u8)(rar_high >> (i*8));
 
        for (i = 0; i < ETH_ALEN; i++)
                hw->mac.addr[i] = hw->mac.perm_addr[i];
index 57f149b75fbe9d07f4b5e05e3e14c919d4987461..14a80f8f61183717d7005a48caad89902d8ddd04 100644 (file)
@@ -2541,22 +2541,14 @@ static void e1000_configure_rx(struct e1000_adapter *adapter)
  *  @hw: pointer to the HW structure
  *  @mc_addr_list: array of multicast addresses to program
  *  @mc_addr_count: number of multicast addresses to program
- *  @rar_used_count: the first RAR register free to program
- *  @rar_count: total number of supported Receive Address Registers
  *
- *  Updates the Receive Address Registers and Multicast Table Array.
+ *  Updates the Multicast Table Array.
  *  The caller must have a packed mc_addr_list of multicast addresses.
- *  The parameter rar_count will usually be hw->mac.rar_entry_count
- *  unless there are workarounds that change this.  Currently no func pointer
- *  exists and all implementations are handled in the generic version of this
- *  function.
  **/
 static void e1000_update_mc_addr_list(struct e1000_hw *hw, u8 *mc_addr_list,
-                                     u32 mc_addr_count, u32 rar_used_count,
-                                     u32 rar_count)
+                                     u32 mc_addr_count)
 {
-       hw->mac.ops.update_mc_addr_list(hw, mc_addr_list, mc_addr_count,
-                                       rar_used_count, rar_count);
+       hw->mac.ops.update_mc_addr_list(hw, mc_addr_list, mc_addr_count);
 }
 
 /**
@@ -2572,7 +2564,6 @@ static void e1000_set_multi(struct net_device *netdev)
 {
        struct e1000_adapter *adapter = netdev_priv(netdev);
        struct e1000_hw *hw = &adapter->hw;
-       struct e1000_mac_info *mac = &hw->mac;
        struct dev_mc_list *mc_ptr;
        u8  *mta_list;
        u32 rctl;
@@ -2614,15 +2605,14 @@ static void e1000_set_multi(struct net_device *netdev)
                        mc_ptr = mc_ptr->next;
                }
 
-               e1000_update_mc_addr_list(hw, mta_list, i, 1,
-                                         mac->rar_entry_count);
+               e1000_update_mc_addr_list(hw, mta_list, i);
                kfree(mta_list);
        } else {
                /*
                 * if we're called from probe, we might not have
                 * anything to do here, so clear out the list
                 */
-               e1000_update_mc_addr_list(hw, NULL, 0, 1, mac->rar_entry_count);
+               e1000_update_mc_addr_list(hw, NULL, 0);
        }
 }
 
@@ -5134,7 +5124,7 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
 
        e1000_eeprom_checks(adapter);
 
-       /* copy the MAC address out of the NVM */
+       /* copy the MAC address */
        if (e1000e_read_mac_addr(&adapter->hw))
                e_err("NVM Read Error while reading MAC address\n");
 
@@ -5326,7 +5316,7 @@ static struct pci_error_handlers e1000_err_handler = {
        .resume = e1000_io_resume,
 };
 
-static struct pci_device_id e1000_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(e1000_pci_tbl) = {
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_COPPER), board_82571 },
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_FIBER), board_82571 },
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_QUAD_COPPER), board_82571 },
index e1c2076228ba5a652005127b3ba0695ef0917e4b..ee01f5a6d0d4c540f4bfd49f097d2a8ac7445676 100644 (file)
@@ -34,7 +34,7 @@
 
 #define DRV_NAME               "enic"
 #define DRV_DESCRIPTION                "Cisco 10G Ethernet Driver"
-#define DRV_VERSION            "1.1.0.100"
+#define DRV_VERSION            "1.1.0.241a"
 #define DRV_COPYRIGHT          "Copyright 2008-2009 Cisco Systems, Inc"
 #define PFX                    DRV_NAME ": "
 
@@ -89,9 +89,12 @@ struct enic {
        spinlock_t devcmd_lock;
        u8 mac_addr[ETH_ALEN];
        u8 mc_addr[ENIC_MULTICAST_PERFECT_FILTERS][ETH_ALEN];
+       unsigned int flags;
        unsigned int mc_count;
        int csum_rx_enabled;
        u32 port_mtu;
+       u32 rx_coalesce_usecs;
+       u32 tx_coalesce_usecs;
 
        /* work queue cache line section */
        ____cacheline_aligned struct vnic_wq wq[ENIC_WQ_MAX];
index f875751af15e59547988f49358aea3160197f678..c81bc4b1816f44a59d5fcd8048eaba5b451722ed 100644 (file)
@@ -51,7 +51,7 @@
 #define PCI_DEVICE_ID_CISCO_VIC_ENET         0x0043  /* ethernet vnic */
 
 /* Supported devices */
-static struct pci_device_id enic_id_table[] = {
+static DEFINE_PCI_DEVICE_TABLE(enic_id_table) = {
        { PCI_VDEVICE(CISCO, PCI_DEVICE_ID_CISCO_VIC_ENET) },
        { 0, }  /* end of table */
 };
@@ -261,6 +261,62 @@ static void enic_set_msglevel(struct net_device *netdev, u32 value)
        enic->msg_enable = value;
 }
 
+static int enic_get_coalesce(struct net_device *netdev,
+       struct ethtool_coalesce *ecmd)
+{
+       struct enic *enic = netdev_priv(netdev);
+
+       ecmd->tx_coalesce_usecs = enic->tx_coalesce_usecs;
+       ecmd->rx_coalesce_usecs = enic->rx_coalesce_usecs;
+
+       return 0;
+}
+
+static int enic_set_coalesce(struct net_device *netdev,
+       struct ethtool_coalesce *ecmd)
+{
+       struct enic *enic = netdev_priv(netdev);
+       u32 tx_coalesce_usecs;
+       u32 rx_coalesce_usecs;
+
+       tx_coalesce_usecs = min_t(u32,
+               INTR_COALESCE_HW_TO_USEC(VNIC_INTR_TIMER_MAX),
+               ecmd->tx_coalesce_usecs);
+       rx_coalesce_usecs = min_t(u32,
+               INTR_COALESCE_HW_TO_USEC(VNIC_INTR_TIMER_MAX),
+               ecmd->rx_coalesce_usecs);
+
+       switch (vnic_dev_get_intr_mode(enic->vdev)) {
+       case VNIC_DEV_INTR_MODE_INTX:
+               if (tx_coalesce_usecs != rx_coalesce_usecs)
+                       return -EINVAL;
+
+               vnic_intr_coalescing_timer_set(&enic->intr[ENIC_INTX_WQ_RQ],
+                       INTR_COALESCE_USEC_TO_HW(tx_coalesce_usecs));
+               break;
+       case VNIC_DEV_INTR_MODE_MSI:
+               if (tx_coalesce_usecs != rx_coalesce_usecs)
+                       return -EINVAL;
+
+               vnic_intr_coalescing_timer_set(&enic->intr[0],
+                       INTR_COALESCE_USEC_TO_HW(tx_coalesce_usecs));
+               break;
+       case VNIC_DEV_INTR_MODE_MSIX:
+               vnic_intr_coalescing_timer_set(&enic->intr[ENIC_MSIX_WQ],
+                       INTR_COALESCE_USEC_TO_HW(tx_coalesce_usecs));
+               vnic_intr_coalescing_timer_set(&enic->intr[ENIC_MSIX_RQ],
+                       INTR_COALESCE_USEC_TO_HW(rx_coalesce_usecs));
+               break;
+       default:
+               break;
+       }
+
+       enic->tx_coalesce_usecs = tx_coalesce_usecs;
+       enic->rx_coalesce_usecs = rx_coalesce_usecs;
+
+       return 0;
+}
+
 static const struct ethtool_ops enic_ethtool_ops = {
        .get_settings = enic_get_settings,
        .get_drvinfo = enic_get_drvinfo,
@@ -278,6 +334,8 @@ static const struct ethtool_ops enic_ethtool_ops = {
        .set_sg = ethtool_op_set_sg,
        .get_tso = ethtool_op_get_tso,
        .set_tso = enic_set_tso,
+       .get_coalesce = enic_get_coalesce,
+       .set_coalesce = enic_set_coalesce,
        .get_flags = ethtool_op_get_flags,
        .set_flags = ethtool_op_set_flags,
 };
@@ -363,12 +421,12 @@ static void enic_mtu_check(struct enic *enic)
        u32 mtu = vnic_dev_mtu(enic->vdev);
 
        if (mtu && mtu != enic->port_mtu) {
+               enic->port_mtu = mtu;
                if (mtu < enic->netdev->mtu)
                        printk(KERN_WARNING PFX
                                "%s: interface MTU (%d) set higher "
                                "than switch port MTU (%d)\n",
                                enic->netdev->name, enic->netdev->mtu, mtu);
-               enic->port_mtu = mtu;
        }
 }
 
@@ -673,7 +731,7 @@ static inline void enic_queue_wq_skb(struct enic *enic,
 
 /* netif_tx_lock held, process context with BHs disabled, or BH */
 static netdev_tx_t enic_hard_start_xmit(struct sk_buff *skb,
-                                             struct net_device *netdev)
+       struct net_device *netdev)
 {
        struct enic *enic = netdev_priv(netdev);
        struct vnic_wq *wq = &enic->wq[0];
@@ -771,6 +829,7 @@ static void enic_set_multicast_list(struct net_device *netdev)
        int promisc = (netdev->flags & IFF_PROMISC) ? 1 : 0;
        int allmulti = (netdev->flags & IFF_ALLMULTI) ||
            (netdev->mc_count > ENIC_MULTICAST_PERFECT_FILTERS);
+       unsigned int flags = netdev->flags | (allmulti ? IFF_ALLMULTI : 0);
        u8 mc_addr[ENIC_MULTICAST_PERFECT_FILTERS][ETH_ALEN];
        unsigned int mc_count = netdev->mc_count;
        unsigned int i, j;
@@ -780,8 +839,11 @@ static void enic_set_multicast_list(struct net_device *netdev)
 
        spin_lock(&enic->devcmd_lock);
 
-       vnic_dev_packet_filter(enic->vdev, directed,
-               multicast, broadcast, promisc, allmulti);
+       if (enic->flags != flags) {
+               enic->flags = flags;
+               vnic_dev_packet_filter(enic->vdev, directed,
+                       multicast, broadcast, promisc, allmulti);
+       }
 
        /* Is there an easier way?  Trying to minimize to
         * calls to add/del multicast addrs.  We keep the
@@ -1084,34 +1146,6 @@ static int enic_rq_service(struct vnic_dev *vdev, struct cq_desc *cq_desc,
        return 0;
 }
 
-static void enic_rq_drop_buf(struct vnic_rq *rq,
-       struct cq_desc *cq_desc, struct vnic_rq_buf *buf,
-       int skipped, void *opaque)
-{
-       struct enic *enic = vnic_dev_priv(rq->vdev);
-       struct sk_buff *skb = buf->os_buf;
-
-       if (skipped)
-               return;
-
-       pci_unmap_single(enic->pdev, buf->dma_addr,
-               buf->len, PCI_DMA_FROMDEVICE);
-
-       dev_kfree_skb_any(skb);
-}
-
-static int enic_rq_service_drop(struct vnic_dev *vdev, struct cq_desc *cq_desc,
-       u8 type, u16 q_number, u16 completed_index, void *opaque)
-{
-       struct enic *enic = vnic_dev_priv(vdev);
-
-       vnic_rq_service(&enic->rq[q_number], cq_desc,
-               completed_index, VNIC_RQ_RETURN_DESC,
-               enic_rq_drop_buf, opaque);
-
-       return 0;
-}
-
 static int enic_poll(struct napi_struct *napi, int budget)
 {
        struct enic *enic = container_of(napi, struct enic, napi);
@@ -1119,6 +1153,7 @@ static int enic_poll(struct napi_struct *napi, int budget)
        unsigned int rq_work_to_do = budget;
        unsigned int wq_work_to_do = -1; /* no limit */
        unsigned int  work_done, rq_work_done, wq_work_done;
+       int err;
 
        /* Service RQ (first) and WQ
         */
@@ -1142,16 +1177,19 @@ static int enic_poll(struct napi_struct *napi, int budget)
                        0 /* don't unmask intr */,
                        0 /* don't reset intr timer */);
 
-       if (rq_work_done > 0) {
+       err = vnic_rq_fill(&enic->rq[0], enic->rq_alloc_buf);
 
-               /* Replenish RQ
-                */
+       /* Buffer allocation failed. Stay in polling
+        * mode so we can try to fill the ring again.
+        */
 
-               vnic_rq_fill(&enic->rq[0], enic->rq_alloc_buf);
+       if (err)
+               rq_work_done = rq_work_to_do;
 
-       } else {
+       if (rq_work_done < rq_work_to_do) {
 
-               /* If no work done, flush all LROs and exit polling
+               /* Some work done, but not enough to stay in polling,
+                * flush all LROs and exit polling
                 */
 
                if (netdev->features & NETIF_F_LRO)
@@ -1170,6 +1208,7 @@ static int enic_poll_msix(struct napi_struct *napi, int budget)
        struct net_device *netdev = enic->netdev;
        unsigned int work_to_do = budget;
        unsigned int work_done;
+       int err;
 
        /* Service RQ
         */
@@ -1177,25 +1216,30 @@ static int enic_poll_msix(struct napi_struct *napi, int budget)
        work_done = vnic_cq_service(&enic->cq[ENIC_CQ_RQ],
                work_to_do, enic_rq_service, NULL);
 
-       if (work_done > 0) {
-
-               /* Replenish RQ
-                */
-
-               vnic_rq_fill(&enic->rq[0], enic->rq_alloc_buf);
-
-               /* Return intr event credits for this polling
-                * cycle.  An intr event is the completion of a
-                * RQ packet.
-                */
+       /* Return intr event credits for this polling
+        * cycle.  An intr event is the completion of a
+        * RQ packet.
+        */
 
+       if (work_done > 0)
                vnic_intr_return_credits(&enic->intr[ENIC_MSIX_RQ],
                        work_done,
                        0 /* don't unmask intr */,
                        0 /* don't reset intr timer */);
-       } else {
 
-               /* If no work done, flush all LROs and exit polling
+       err = vnic_rq_fill(&enic->rq[0], enic->rq_alloc_buf);
+
+       /* Buffer allocation failed. Stay in polling mode
+        * so we can try to fill the ring again.
+        */
+
+       if (err)
+               work_done = work_to_do;
+
+       if (work_done < work_to_do) {
+
+               /* Some work done, but not enough to stay in polling,
+                * flush all LROs and exit polling
                 */
 
                if (netdev->features & NETIF_F_LRO)
@@ -1304,6 +1348,24 @@ static int enic_request_intr(struct enic *enic)
        return err;
 }
 
+static void enic_synchronize_irqs(struct enic *enic)
+{
+       unsigned int i;
+
+       switch (vnic_dev_get_intr_mode(enic->vdev)) {
+       case VNIC_DEV_INTR_MODE_INTX:
+       case VNIC_DEV_INTR_MODE_MSI:
+               synchronize_irq(enic->pdev->irq);
+               break;
+       case VNIC_DEV_INTR_MODE_MSIX:
+               for (i = 0; i < enic->intr_count; i++)
+                       synchronize_irq(enic->msix_entry[i].vector);
+               break;
+       default:
+               break;
+       }
+}
+
 static int enic_notify_set(struct enic *enic)
 {
        int err;
@@ -1360,11 +1422,13 @@ static int enic_open(struct net_device *netdev)
        }
 
        for (i = 0; i < enic->rq_count; i++) {
-               err = vnic_rq_fill(&enic->rq[i], enic->rq_alloc_buf);
-               if (err) {
+               vnic_rq_fill(&enic->rq[i], enic->rq_alloc_buf);
+               /* Need at least one buffer on ring to get going */
+               if (vnic_rq_desc_used(&enic->rq[i]) == 0) {
                        printk(KERN_ERR PFX
                                "%s: Unable to alloc receive buffers.\n",
                                netdev->name);
+                       err = -ENOMEM;
                        goto err_out_notify_unset;
                }
        }
@@ -1409,16 +1473,19 @@ static int enic_stop(struct net_device *netdev)
        unsigned int i;
        int err;
 
+       for (i = 0; i < enic->intr_count; i++)
+               vnic_intr_mask(&enic->intr[i]);
+
+       enic_synchronize_irqs(enic);
+
        del_timer_sync(&enic->notify_timer);
 
        spin_lock(&enic->devcmd_lock);
        vnic_dev_disable(enic->vdev);
        spin_unlock(&enic->devcmd_lock);
        napi_disable(&enic->napi);
-       netif_stop_queue(netdev);
-
-       for (i = 0; i < enic->intr_count; i++)
-               vnic_intr_mask(&enic->intr[i]);
+       netif_carrier_off(netdev);
+       netif_tx_disable(netdev);
 
        for (i = 0; i < enic->wq_count; i++) {
                err = vnic_wq_disable(&enic->wq[i]);
@@ -1436,11 +1503,6 @@ static int enic_stop(struct net_device *netdev)
        spin_unlock(&enic->devcmd_lock);
        enic_free_intr(enic);
 
-       (void)vnic_cq_service(&enic->cq[ENIC_CQ_RQ],
-               -1, enic_rq_service_drop, NULL);
-       (void)vnic_cq_service(&enic->cq[ENIC_CQ_WQ],
-               -1, enic_wq_service, NULL);
-
        for (i = 0; i < enic->wq_count; i++)
                vnic_wq_clean(&enic->wq[i], enic_free_wq_buf);
        for (i = 0; i < enic->rq_count; i++)
@@ -1762,7 +1824,8 @@ int enic_dev_init(struct enic *enic)
        err = enic_set_intr_mode(enic);
        if (err) {
                printk(KERN_ERR PFX
-                       "Failed to set intr mode, aborting.\n");
+                       "Failed to set intr mode based on resource "
+                       "counts and system capabilities, aborting.\n");
                return err;
        }
 
@@ -1986,6 +2049,9 @@ static int __devinit enic_probe(struct pci_dev *pdev,
                goto err_out_dev_deinit;
        }
 
+       enic->tx_coalesce_usecs = enic->config.intr_timer_usec;
+       enic->rx_coalesce_usecs = enic->tx_coalesce_usecs;
+
        netdev->netdev_ops = &enic_netdev_ops;
        netdev->watchdog_timeo = 2 * HZ;
        netdev->ethtool_ops = &enic_ethtool_ops;
index 32111144efc9bdb0727320a7745c038e09d2ff9b..02839bf0fe8bde44a215ff558a0a0669aca1a399 100644 (file)
@@ -66,21 +66,21 @@ int enic_get_vnic_config(struct enic *enic)
        GET_CONFIG(wq_desc_count);
        GET_CONFIG(rq_desc_count);
        GET_CONFIG(mtu);
-       GET_CONFIG(intr_timer);
        GET_CONFIG(intr_timer_type);
        GET_CONFIG(intr_mode);
+       GET_CONFIG(intr_timer_usec);
 
        c->wq_desc_count =
                min_t(u32, ENIC_MAX_WQ_DESCS,
                max_t(u32, ENIC_MIN_WQ_DESCS,
                c->wq_desc_count));
-       c->wq_desc_count &= 0xfffffff0; /* must be aligned to groups of 16 */
+       c->wq_desc_count &= 0xffffffe0; /* must be aligned to groups of 32 */
 
        c->rq_desc_count =
                min_t(u32, ENIC_MAX_RQ_DESCS,
                max_t(u32, ENIC_MIN_RQ_DESCS,
                c->rq_desc_count));
-       c->rq_desc_count &= 0xfffffff0; /* must be aligned to groups of 16 */
+       c->rq_desc_count &= 0xffffffe0; /* must be aligned to groups of 32 */
 
        if (c->mtu == 0)
                c->mtu = 1500;
@@ -88,15 +88,17 @@ int enic_get_vnic_config(struct enic *enic)
                max_t(u16, ENIC_MIN_MTU,
                c->mtu));
 
-       c->intr_timer = min_t(u16, VNIC_INTR_TIMER_MAX, c->intr_timer);
+       c->intr_timer_usec = min_t(u32,
+               INTR_COALESCE_HW_TO_USEC(VNIC_INTR_TIMER_MAX),
+               c->intr_timer_usec);
 
        printk(KERN_INFO PFX "vNIC MAC addr %pM wq/rq %d/%d\n",
                enic->mac_addr, c->wq_desc_count, c->rq_desc_count);
        printk(KERN_INFO PFX "vNIC mtu %d csum tx/rx %d/%d tso/lro %d/%d "
-               "intr timer %d\n",
+               "intr timer %d usec\n",
                c->mtu, ENIC_SETTING(enic, TXCSUM),
                ENIC_SETTING(enic, RXCSUM), ENIC_SETTING(enic, TSO),
-               ENIC_SETTING(enic, LRO), c->intr_timer);
+               ENIC_SETTING(enic, LRO), c->intr_timer_usec);
 
        return 0;
 }
@@ -303,7 +305,7 @@ void enic_init_vnic_resources(struct enic *enic)
 
        for (i = 0; i < enic->intr_count; i++) {
                vnic_intr_init(&enic->intr[i],
-                       enic->config.intr_timer,
+                       INTR_COALESCE_USEC_TO_HW(enic->config.intr_timer_usec),
                        enic->config.intr_timer_type,
                        mask_on_assertion);
        }
index 29a48e8b59d379799e1447a39e4c08aec74ab6f8..69b9b70c7da08c441f5cfa77c45a4ab1e3ab9745 100644 (file)
@@ -36,7 +36,6 @@ struct vnic_res {
 };
 
 #define VNIC_DEV_CAP_INIT      0x0001
-#define VNIC_DEV_CAP_PERBI     0x0002
 
 struct vnic_dev {
        void *priv;
index 6332ac9391b89d4eaec6423a914f9995b321547b..8eeb6758491bcb3e065839ccb3b8f4ea7100e77b 100644 (file)
 #ifndef _VNIC_ENIC_H_
 #define _VNIC_ENIC_H_
 
+/* Hardware intr coalesce timer is in units of 1.5us */
+#define INTR_COALESCE_USEC_TO_HW(usec) ((usec) * 2/3)
+#define INTR_COALESCE_HW_TO_USEC(usec) ((usec) * 3/2)
+
 /* Device-specific region: enet configuration */
 struct vnic_enet_config {
        u32 flags;
@@ -30,6 +34,7 @@ struct vnic_enet_config {
        u8 intr_timer_type;
        u8 intr_mode;
        char devname[16];
+       u32 intr_timer_usec;
 };
 
 #define VENETF_TSO             0x1     /* TSO enabled */
index 1f8786d7195e1e01bde8d6b16a4b25ab3771bef6..3934309a9498b69527f8c33068831b123c5efa78 100644 (file)
@@ -50,12 +50,18 @@ int vnic_intr_alloc(struct vnic_dev *vdev, struct vnic_intr *intr,
 void vnic_intr_init(struct vnic_intr *intr, unsigned int coalescing_timer,
        unsigned int coalescing_type, unsigned int mask_on_assertion)
 {
-       iowrite32(coalescing_timer, &intr->ctrl->coalescing_timer);
+       vnic_intr_coalescing_timer_set(intr, coalescing_timer);
        iowrite32(coalescing_type, &intr->ctrl->coalescing_type);
        iowrite32(mask_on_assertion, &intr->ctrl->mask_on_assertion);
        iowrite32(0, &intr->ctrl->int_credits);
 }
 
+void vnic_intr_coalescing_timer_set(struct vnic_intr *intr,
+       unsigned int coalescing_timer)
+{
+       iowrite32(coalescing_timer, &intr->ctrl->coalescing_timer);
+}
+
 void vnic_intr_clean(struct vnic_intr *intr)
 {
        iowrite32(0, &intr->ctrl->int_credits);
index 9a53604edce69ca9dfb19eeb241b63f634627a6b..2fe6c6339e3c58a54eb9f205ac34ba6d625f4199 100644 (file)
@@ -61,6 +61,7 @@ static inline void vnic_intr_unmask(struct vnic_intr *intr)
 static inline void vnic_intr_mask(struct vnic_intr *intr)
 {
        iowrite32(1, &intr->ctrl->mask);
+       (void)ioread32(&intr->ctrl->mask);
 }
 
 static inline void vnic_intr_return_credits(struct vnic_intr *intr,
@@ -101,6 +102,8 @@ int vnic_intr_alloc(struct vnic_dev *vdev, struct vnic_intr *intr,
        unsigned int index);
 void vnic_intr_init(struct vnic_intr *intr, unsigned int coalescing_timer,
        unsigned int coalescing_type, unsigned int mask_on_assertion);
+void vnic_intr_coalescing_timer_set(struct vnic_intr *intr,
+       unsigned int coalescing_timer);
 void vnic_intr_clean(struct vnic_intr *intr);
 
 #endif /* _VNIC_INTR_H_ */
index eeaf329945d8d12ff0ef53cdd67c6e1331204bb3..cf80ab46d582ac73a94ff59766c6fdf0a379cdef 100644 (file)
 #define NIC_CFG_IG_VLAN_STRIP_EN_MASK_FIELD    1UL
 #define NIC_CFG_IG_VLAN_STRIP_EN_SHIFT         24
 
-#define NIC_CFG_RSS_HASH_TYPE_IPV4             (1 << 0)
-#define NIC_CFG_RSS_HASH_TYPE_TCP_IPV4         (1 << 1)
-#define NIC_CFG_RSS_HASH_TYPE_IPV6             (1 << 2)
-#define NIC_CFG_RSS_HASH_TYPE_TCP_IPV6         (1 << 3)
-#define NIC_CFG_RSS_HASH_TYPE_IPV6_EX          (1 << 4)
-#define NIC_CFG_RSS_HASH_TYPE_TCP_IPV6_EX      (1 << 5)
+#define NIC_CFG_RSS_HASH_TYPE_IPV4             (1 << 1)
+#define NIC_CFG_RSS_HASH_TYPE_TCP_IPV4         (1 << 2)
+#define NIC_CFG_RSS_HASH_TYPE_IPV6             (1 << 3)
+#define NIC_CFG_RSS_HASH_TYPE_TCP_IPV6         (1 << 4)
+#define NIC_CFG_RSS_HASH_TYPE_IPV6_EX          (1 << 5)
+#define NIC_CFG_RSS_HASH_TYPE_TCP_IPV6_EX      (1 << 6)
 
 static inline void vnic_set_nic_cfg(u32 *nic_cfg,
        u8 rss_default_cpu, u8 rss_hash_type,
index 41494f7b2ec8d3f147e1b67d7a1a54d60460fde4..1f8b11449fad22a80126aee82a0286266744ae62 100644 (file)
@@ -167,7 +167,7 @@ static const struct epic_chip_info pci_id_tbl[] = {
 };
 
 
-static struct pci_device_id epic_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(epic_pci_tbl) = {
        { 0x10B8, 0x0005, 0x1092, 0x0AB4, 0, 0, SMSC_83C170_0 },
        { 0x10B8, 0x0005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SMSC_83C170 },
        { 0x10B8, 0x0006, PCI_ANY_ID, PCI_ANY_ID,
index bd1db92aec1beaa801463446fb425e1582fd9968..f9d5ca078743f37a181b38fa060bc176e36bbde2 100644 (file)
@@ -904,7 +904,7 @@ static int ethoc_probe(struct platform_device *pdev)
        }
 
        mmio = devm_request_mem_region(&pdev->dev, res->start,
-                       res->end - res->start + 1, res->name);
+                       resource_size(res), res->name);
        if (!mmio) {
                dev_err(&pdev->dev, "cannot request I/O memory space\n");
                ret = -ENXIO;
@@ -917,7 +917,7 @@ static int ethoc_probe(struct platform_device *pdev)
        res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
        if (res) {
                mem = devm_request_mem_region(&pdev->dev, res->start,
-                       res->end - res->start + 1, res->name);
+                       resource_size(res), res->name);
                if (!mem) {
                        dev_err(&pdev->dev, "cannot request memory space\n");
                        ret = -ENXIO;
@@ -945,7 +945,7 @@ static int ethoc_probe(struct platform_device *pdev)
        priv->dma_alloc = 0;
 
        priv->iobase = devm_ioremap_nocache(&pdev->dev, netdev->base_addr,
-                       mmio->end - mmio->start + 1);
+                       resource_size(mmio));
        if (!priv->iobase) {
                dev_err(&pdev->dev, "cannot remap I/O memory space\n");
                ret = -ENXIO;
@@ -954,7 +954,7 @@ static int ethoc_probe(struct platform_device *pdev)
 
        if (netdev->mem_end) {
                priv->membase = devm_ioremap_nocache(&pdev->dev,
-                       netdev->mem_start, mem->end - mem->start + 1);
+                       netdev->mem_start, resource_size(mem));
                if (!priv->membase) {
                        dev_err(&pdev->dev, "cannot remap memory space\n");
                        ret = -ENXIO;
index dac4e595589e35dd486c7e3f06c5baff5afbdc4d..e6a98129d7876b30a862a91e9f68006cb2fd013e 100644 (file)
@@ -1941,7 +1941,7 @@ static int netdev_close(struct net_device *dev)
        return 0;
 }
 
-static struct pci_device_id fealnx_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(fealnx_pci_tbl) = {
        {0x1516, 0x0800, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
        {0x1516, 0x0803, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
        {0x1516, 0x0891, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
index 3c340489804a9bc6f3b8cc65826795033efcbf12..3eb713b014f9e56d37b11c303dc2c396875e7d51 100644 (file)
@@ -6198,7 +6198,7 @@ static void nv_shutdown(struct pci_dev *pdev)
 #define nv_resume NULL
 #endif /* CONFIG_PM */
 
-static struct pci_device_id pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(pci_tbl) = {
        {       /* nForce Ethernet Controller */
                PCI_DEVICE(0x10DE, 0x01C3),
                .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
index ea85075a89a223b7a3dbb88d870de301555c9317..dd72c5025e6aa661eff27ac3e5aacd4b0b1f51d0 100644 (file)
@@ -1990,7 +1990,7 @@ static void __devexit hamachi_remove_one (struct pci_dev *pdev)
        }
 }
 
-static struct pci_device_id hamachi_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(hamachi_pci_tbl) = {
        { 0x1318, 0x0911, PCI_ANY_ID, PCI_ANY_ID, },
        { 0, }
 };
index 90f890e7c5e113b7c817b3fb61e02eccc704885d..0c2f2e8b1c4782628eb29fc9c7c51004dba22cc1 100644 (file)
@@ -210,7 +210,7 @@ MODULE_DEVICE_TABLE(eisa, hp100_eisa_tbl);
 #endif
 
 #ifdef CONFIG_PCI
-static struct pci_device_id hp100_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(hp100_pci_tbl) = {
        {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585A, PCI_ANY_ID, PCI_ANY_ID,},
        {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585B, PCI_ANY_ID, PCI_ANY_ID,},
        {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2970A, PCI_ANY_ID, PCI_ANY_ID,},
index 997124d2992a38e7817bc2ed7a97815e5fd7fe25..0a064ce3eb4525140398521ac4db0a7921358cd3 100644 (file)
@@ -60,7 +60,7 @@ static const struct e1000_info *igb_info_tbl[] = {
        [board_82575] = &e1000_82575_info,
 };
 
-static struct pci_device_id igb_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(igb_pci_tbl) = {
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_COPPER), board_82575 },
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_FIBER), board_82575 },
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_SERDES), board_82575 },
@@ -2905,12 +2905,13 @@ static int igb_write_uc_addr_list(struct net_device *netdev)
        int count = 0;
 
        /* return ENOMEM indicating insufficient memory for addresses */
-       if (netdev->uc.count > rar_entries)
+       if (netdev_uc_count(netdev) > rar_entries)
                return -ENOMEM;
 
-       if (netdev->uc.count && rar_entries) {
+       if (!netdev_uc_empty(netdev) && rar_entries) {
                struct netdev_hw_addr *ha;
-               list_for_each_entry(ha, &netdev->uc.list, list) {
+
+               netdev_for_each_uc_addr(ha, netdev) {
                        if (!rar_entries)
                                break;
                        igb_rar_set_qsel(adapter, ha->addr,
@@ -4105,6 +4106,9 @@ static irqreturn_t igb_msix_other(int irq, void *data)
        u32 icr = rd32(E1000_ICR);
        /* reading ICR causes bit 31 of EICR to be cleared */
 
+       if (icr & E1000_ICR_DRSTA)
+               schedule_work(&adapter->reset_task);
+
        if (icr & E1000_ICR_DOUTSYNC) {
                /* HW is reporting DMA is out of sync */
                adapter->stats.doosync++;
@@ -4728,6 +4732,9 @@ static irqreturn_t igb_intr_msi(int irq, void *data)
 
        igb_write_itr(q_vector);
 
+       if (icr & E1000_ICR_DRSTA)
+               schedule_work(&adapter->reset_task);
+
        if (icr & E1000_ICR_DOUTSYNC) {
                /* HW is reporting DMA is out of sync */
                adapter->stats.doosync++;
@@ -4767,6 +4774,9 @@ static irqreturn_t igb_intr(int irq, void *data)
        if (!(icr & E1000_ICR_INT_ASSERTED))
                return IRQ_NONE;
 
+       if (icr & E1000_ICR_DRSTA)
+               schedule_work(&adapter->reset_task);
+
        if (icr & E1000_ICR_DOUTSYNC) {
                /* HW is reporting DMA is out of sync */
                adapter->stats.doosync++;
index 2aa71a766c35ae8d5ee9d75f6b21f04c6e82235c..23ce07d3de0890c9d1927ca7c1f12268371c7ef0 100644 (file)
@@ -2609,11 +2609,7 @@ static void igbvf_print_device_info(struct igbvf_adapter *adapter)
        struct pci_dev *pdev = adapter->pdev;
 
        dev_info(&pdev->dev, "Intel(R) 82576 Virtual Function\n");
-       dev_info(&pdev->dev, "Address: %02x:%02x:%02x:%02x:%02x:%02x\n",
-                /* MAC address */
-                netdev->dev_addr[0], netdev->dev_addr[1],
-                netdev->dev_addr[2], netdev->dev_addr[3],
-                netdev->dev_addr[4], netdev->dev_addr[5]);
+       dev_info(&pdev->dev, "Address: %pM\n", netdev->dev_addr);
        dev_info(&pdev->dev, "MAC: %d\n", hw->mac.type);
 }
 
@@ -2779,11 +2775,8 @@ static int __devinit igbvf_probe(struct pci_dev *pdev,
        memcpy(netdev->perm_addr, adapter->hw.mac.addr, netdev->addr_len);
 
        if (!is_valid_ether_addr(netdev->perm_addr)) {
-               dev_err(&pdev->dev, "Invalid MAC Address: "
-                       "%02x:%02x:%02x:%02x:%02x:%02x\n",
-                       netdev->dev_addr[0], netdev->dev_addr[1],
-                       netdev->dev_addr[2], netdev->dev_addr[3],
-                       netdev->dev_addr[4], netdev->dev_addr[5]);
+               dev_err(&pdev->dev, "Invalid MAC Address: %pM\n",
+                       netdev->dev_addr);
                err = -EIO;
                goto err_hw_init;
        }
@@ -2885,7 +2878,7 @@ static struct pci_error_handlers igbvf_err_handler = {
        .resume = igbvf_io_resume,
 };
 
-static struct pci_device_id igbvf_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(igbvf_pci_tbl) = {
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_VF), board_vf },
        { } /* terminate list */
 };
index 8ec15ab8c8c24fd09c0ae5b023d8471114047736..81a4c5d30733dea07254ada6f7e4d5a25eca22fd 100644 (file)
@@ -1383,7 +1383,7 @@ static void __devexit ioc3_remove_one (struct pci_dev *pdev)
         */
 }
 
-static struct pci_device_id ioc3_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(ioc3_pci_tbl) = {
        { PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3, PCI_ANY_ID, PCI_ANY_ID },
        { 0 }
 };
index ba8d246d05a09d310267ee44ac3caff1e38fbef1..49f35e2ed19f79585e68ce1f3c69be8081d43725 100644 (file)
@@ -92,7 +92,7 @@ static const char *ipg_brand_name[] = {
        "D-Link NIC IP1000A"
 };
 
-static struct pci_device_id ipg_pci_tbl[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(ipg_pci_tbl) = {
        { PCI_VDEVICE(SUNDANCE, 0x1023), 0 },
        { PCI_VDEVICE(SUNDANCE, 0x2021), 1 },
        { PCI_VDEVICE(SUNDANCE, 0x1021), 2 },
index f76384221422ce1ef32005b20d379c0b7b4f8a1f..af10e97345ced34a19c86bc3d28b39e7fdb37fcb 100644 (file)
@@ -64,6 +64,16 @@ endchoice
 
 comment "Dongle support"
 
+config SH_SIR
+       tristate "SuperH SIR on UART"
+       depends on IRDA && SUPERH && \
+               (CPU_SUBTYPE_SH7722 || CPU_SUBTYPE_SH7723 || \
+                CPU_SUBTYPE_SH7724)
+       default n
+       help
+         Say Y here if your want to enable SIR function on SuperH UART
+         devices.
+
 config DONGLE
        bool "Serial dongle support"
        depends on IRTTY_SIR
index d82e1e3bd8c8f401471f995ab3da4873b2b7b88a..e030d47e27932a44e0472238ab54016bea0b32d5 100644 (file)
@@ -22,6 +22,7 @@ obj-$(CONFIG_AU1000_FIR)      += au1k_ir.o
 # SIR drivers
 obj-$(CONFIG_IRTTY_SIR)                += irtty-sir.o  sir-dev.o
 obj-$(CONFIG_BFIN_SIR)         += bfin_sir.o
+obj-$(CONFIG_SH_SIR)           += sh_sir.o
 # dongle drivers for SIR drivers
 obj-$(CONFIG_ESI_DONGLE)       += esi-sir.o
 obj-$(CONFIG_TEKRAM_DONGLE)    += tekram-sir.o
index 2d7b5c1d55720290ffdac4d34a0de2cd1085c70b..b7e6625ca75e35a34b1f2907ed040de0eb0591ce 100644 (file)
 #define CONFIG0H_DMA_ON_NORX CONFIG0H_DMA_OFF| OBOE_CONFIG0H_ENDMAC
 #define CONFIG0H_DMA_ON CONFIG0H_DMA_ON_NORX | OBOE_CONFIG0H_ENRX
 
-static struct pci_device_id toshoboe_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(toshoboe_pci_tbl) = {
        { PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_FIR701, PCI_ANY_ID, PCI_ANY_ID, },
        { PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_FIRD01, PCI_ANY_ID, PCI_ANY_ID, },
        { }                     /* Terminating entry */
diff --git a/drivers/net/irda/sh_sir.c b/drivers/net/irda/sh_sir.c
new file mode 100644 (file)
index 0000000..d7c983d
--- /dev/null
@@ -0,0 +1,823 @@
+/*
+ * SuperH IrDA Driver
+ *
+ * Copyright (C) 2009 Renesas Solutions Corp.
+ * Kuninori Morimoto <morimoto.kuninori@renesas.com>
+ *
+ * Based on bfin_sir.c
+ * Copyright 2006-2009 Analog Devices Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <net/irda/wrapper.h>
+#include <net/irda/irda_device.h>
+#include <asm/clock.h>
+
+#define DRIVER_NAME "sh_sir"
+
+#define RX_PHASE       (1 << 0)
+#define TX_PHASE       (1 << 1)
+#define TX_COMP_PHASE  (1 << 2) /* tx complete */
+#define NONE_PHASE     (1 << 31)
+
+#define IRIF_RINTCLR   0x0016 /* DMA rx interrupt source clear */
+#define IRIF_TINTCLR   0x0018 /* DMA tx interrupt source clear */
+#define IRIF_SIR0      0x0020 /* IrDA-SIR10 control */
+#define IRIF_SIR1      0x0022 /* IrDA-SIR10 baudrate error correction */
+#define IRIF_SIR2      0x0024 /* IrDA-SIR10 baudrate count */
+#define IRIF_SIR3      0x0026 /* IrDA-SIR10 status */
+#define IRIF_SIR_FRM   0x0028 /* Hardware frame processing set */
+#define IRIF_SIR_EOF   0x002A /* EOF value */
+#define IRIF_SIR_FLG   0x002C /* Flag clear */
+#define IRIF_UART_STS2 0x002E /* UART status 2 */
+#define IRIF_UART0     0x0030 /* UART control */
+#define IRIF_UART1     0x0032 /* UART status */
+#define IRIF_UART2     0x0034 /* UART mode */
+#define IRIF_UART3     0x0036 /* UART transmit data */
+#define IRIF_UART4     0x0038 /* UART receive data */
+#define IRIF_UART5     0x003A /* UART interrupt mask */
+#define IRIF_UART6     0x003C /* UART baud rate error correction */
+#define IRIF_UART7     0x003E /* UART baud rate count set */
+#define IRIF_CRC0      0x0040 /* CRC engine control */
+#define IRIF_CRC1      0x0042 /* CRC engine input data */
+#define IRIF_CRC2      0x0044 /* CRC engine calculation */
+#define IRIF_CRC3      0x0046 /* CRC engine output data 1 */
+#define IRIF_CRC4      0x0048 /* CRC engine output data 2 */
+
+/* IRIF_SIR0 */
+#define IRTPW          (1 << 1) /* transmit pulse width select */
+#define IRERRC         (1 << 0) /* Clear receive pulse width error */
+
+/* IRIF_SIR3 */
+#define IRERR          (1 << 0) /* received pulse width Error */
+
+/* IRIF_SIR_FRM */
+#define EOFD           (1 << 9) /* EOF detection flag */
+#define FRER           (1 << 8) /* Frame Error bit */
+#define FRP            (1 << 0) /* Frame processing set */
+
+/* IRIF_UART_STS2 */
+#define IRSME          (1 << 6) /* Receive Sum     Error flag */
+#define IROVE          (1 << 5) /* Receive Overrun Error flag */
+#define IRFRE          (1 << 4) /* Receive Framing Error flag */
+#define IRPRE          (1 << 3) /* Receive Parity  Error flag */
+
+/* IRIF_UART0_*/
+#define TBEC           (1 << 2) /* Transmit Data Clear */
+#define RIE            (1 << 1) /* Receive Enable */
+#define TIE            (1 << 0) /* Transmit Enable */
+
+/* IRIF_UART1 */
+#define URSME          (1 << 6) /* Receive Sum Error Flag */
+#define UROVE          (1 << 5) /* Receive Overrun Error Flag */
+#define URFRE          (1 << 4) /* Receive Framing Error Flag */
+#define URPRE          (1 << 3) /* Receive Parity Error Flag */
+#define RBF            (1 << 2) /* Receive Buffer Full Flag */
+#define TSBE           (1 << 1) /* Transmit Shift Buffer Empty Flag */
+#define TBE            (1 << 0) /* Transmit Buffer Empty flag */
+#define TBCOMP         (TSBE | TBE)
+
+/* IRIF_UART5 */
+#define RSEIM          (1 << 6) /* Receive Sum Error Flag IRQ Mask */
+#define RBFIM          (1 << 2) /* Receive Buffer Full Flag IRQ Mask */
+#define TSBEIM         (1 << 1) /* Transmit Shift Buffer Empty Flag IRQ Mask */
+#define TBEIM          (1 << 0) /* Transmit Buffer Empty Flag IRQ Mask */
+#define RX_MASK                (RSEIM  | RBFIM)
+
+/* IRIF_CRC0 */
+#define CRC_RST                (1 << 15) /* CRC Engine Reset */
+#define CRC_CT_MASK    0x0FFF
+
+/************************************************************************
+
+
+                       structure
+
+
+************************************************************************/
+struct sh_sir_self {
+       void __iomem            *membase;
+       unsigned int             irq;
+       struct clk              *clk;
+
+       struct net_device       *ndev;
+
+       struct irlap_cb         *irlap;
+       struct qos_info         qos;
+
+       iobuff_t                tx_buff;
+       iobuff_t                rx_buff;
+};
+
+/************************************************************************
+
+
+                       common function
+
+
+************************************************************************/
+static void sh_sir_write(struct sh_sir_self *self, u32 offset, u16 data)
+{
+       iowrite16(data, self->membase + offset);
+}
+
+static u16 sh_sir_read(struct sh_sir_self *self, u32 offset)
+{
+       return ioread16(self->membase + offset);
+}
+
+static void sh_sir_update_bits(struct sh_sir_self *self, u32 offset,
+                              u16 mask, u16 data)
+{
+       u16 old, new;
+
+       old = sh_sir_read(self, offset);
+       new = (old & ~mask) | data;
+       if (old != new)
+               sh_sir_write(self, offset, new);
+}
+
+/************************************************************************
+
+
+                       CRC function
+
+
+************************************************************************/
+static void sh_sir_crc_reset(struct sh_sir_self *self)
+{
+       sh_sir_write(self, IRIF_CRC0, CRC_RST);
+}
+
+static void sh_sir_crc_add(struct sh_sir_self *self, u8 data)
+{
+       sh_sir_write(self, IRIF_CRC1, (u16)data);
+}
+
+static u16 sh_sir_crc_cnt(struct sh_sir_self *self)
+{
+       return CRC_CT_MASK & sh_sir_read(self, IRIF_CRC0);
+}
+
+static u16 sh_sir_crc_out(struct sh_sir_self *self)
+{
+       return sh_sir_read(self, IRIF_CRC4);
+}
+
+static int sh_sir_crc_init(struct sh_sir_self *self)
+{
+       struct device *dev = &self->ndev->dev;
+       int ret = -EIO;
+       u16 val;
+
+       sh_sir_crc_reset(self);
+
+       sh_sir_crc_add(self, 0xCC);
+       sh_sir_crc_add(self, 0xF5);
+       sh_sir_crc_add(self, 0xF1);
+       sh_sir_crc_add(self, 0xA7);
+
+       val = sh_sir_crc_cnt(self);
+       if (4 != val) {
+               dev_err(dev, "CRC count error %x\n", val);
+               goto crc_init_out;
+       }
+
+       val = sh_sir_crc_out(self);
+       if (0x51DF != val) {
+               dev_err(dev, "CRC result error%x\n", val);
+               goto crc_init_out;
+       }
+
+       ret = 0;
+
+crc_init_out:
+
+       sh_sir_crc_reset(self);
+       return ret;
+}
+
+/************************************************************************
+
+
+                       baud rate functions
+
+
+************************************************************************/
+#define SCLK_BASE 1843200 /* 1.8432MHz */
+
+static u32 sh_sir_find_sclk(struct clk *irda_clk)
+{
+       struct cpufreq_frequency_table *freq_table = irda_clk->freq_table;
+       struct clk *pclk = clk_get(NULL, "peripheral_clk");
+       u32 limit, min = 0xffffffff, tmp;
+       int i, index = 0;
+
+       limit = clk_get_rate(pclk);
+       clk_put(pclk);
+
+       /* IrDA can not set over peripheral_clk */
+       for (i = 0;
+            freq_table[i].frequency != CPUFREQ_TABLE_END;
+            i++) {
+               u32 freq = freq_table[i].frequency;
+
+               if (freq == CPUFREQ_ENTRY_INVALID)
+                       continue;
+
+               /* IrDA should not over peripheral_clk */
+               if (freq > limit)
+                       continue;
+
+               tmp = freq % SCLK_BASE;
+               if (tmp < min) {
+                       min = tmp;
+                       index = i;
+               }
+       }
+
+       return freq_table[index].frequency;
+}
+
+#define ERR_ROUNDING(a) ((a + 5000) / 10000)
+static int sh_sir_set_baudrate(struct sh_sir_self *self, u32 baudrate)
+{
+       struct clk *clk;
+       struct device *dev = &self->ndev->dev;
+       u32 rate;
+       u16 uabca, uabc;
+       u16 irbca, irbc;
+       u32 min, rerr, tmp;
+       int i;
+
+       /* Baud Rate Error Correction x 10000 */
+       u32 rate_err_array[] = {
+               0000, 0625, 1250, 1875,
+               2500, 3125, 3750, 4375,
+               5000, 5625, 6250, 6875,
+               7500, 8125, 8750, 9375,
+       };
+
+       /*
+        * FIXME
+        *
+        * it support 9600 only now
+        */
+       switch (baudrate) {
+       case 9600:
+               break;
+       default:
+               dev_err(dev, "un-supported baudrate %d\n", baudrate);
+               return -EIO;
+       }
+
+       clk = clk_get(NULL, "irda_clk");
+       if (!clk) {
+               dev_err(dev, "can not get irda_clk\n");
+               return -EIO;
+       }
+
+       clk_set_rate(clk, sh_sir_find_sclk(clk));
+       rate = clk_get_rate(clk);
+       clk_put(clk);
+
+       dev_dbg(dev, "selected sclk = %d\n", rate);
+
+       /*
+        * CALCULATION
+        *
+        * 1843200 = system rate / (irbca + (irbc + 1))
+        */
+
+       irbc = rate / SCLK_BASE;
+
+       tmp = rate - (SCLK_BASE * irbc);
+       tmp *= 10000;
+
+       rerr = tmp / SCLK_BASE;
+
+       min = 0xffffffff;
+       irbca = 0;
+       for (i = 0; i < ARRAY_SIZE(rate_err_array); i++) {
+               tmp = abs(rate_err_array[i] - rerr);
+               if (min > tmp) {
+                       min = tmp;
+                       irbca = i;
+               }
+       }
+
+       tmp = rate / (irbc + ERR_ROUNDING(rate_err_array[irbca]));
+       if ((SCLK_BASE / 100) < abs(tmp - SCLK_BASE))
+               dev_warn(dev, "IrDA freq error margin over %d\n", tmp);
+
+       dev_dbg(dev, "target = %d, result = %d, infrared = %d.%d\n",
+              SCLK_BASE, tmp, irbc, rate_err_array[irbca]);
+
+       irbca = (irbca & 0xF) << 4;
+       irbc  = (irbc - 1) & 0xF;
+
+       if (!irbc) {
+               dev_err(dev, "sh_sir can not set 0 in IRIF_SIR2\n");
+               return -EIO;
+       }
+
+       sh_sir_write(self, IRIF_SIR0, IRTPW | IRERRC);
+       sh_sir_write(self, IRIF_SIR1, irbca);
+       sh_sir_write(self, IRIF_SIR2, irbc);
+
+       /*
+        * CALCULATION
+        *
+        * BaudRate[bps] = system rate / (uabca + (uabc + 1) x 16)
+        */
+
+       uabc = rate / baudrate;
+       uabc = (uabc / 16) - 1;
+       uabc = (uabc + 1) * 16;
+
+       tmp = rate - (uabc * baudrate);
+       tmp *= 10000;
+
+       rerr = tmp / baudrate;
+
+       min = 0xffffffff;
+       uabca = 0;
+       for (i = 0; i < ARRAY_SIZE(rate_err_array); i++) {
+               tmp = abs(rate_err_array[i] - rerr);
+               if (min > tmp) {
+                       min = tmp;
+                       uabca = i;
+               }
+       }
+
+       tmp = rate / (uabc + ERR_ROUNDING(rate_err_array[uabca]));
+       if ((baudrate / 100) < abs(tmp - baudrate))
+               dev_warn(dev, "UART freq error margin over %d\n", tmp);
+
+       dev_dbg(dev, "target = %d, result = %d, uart = %d.%d\n",
+              baudrate, tmp,
+              uabc, rate_err_array[uabca]);
+
+       uabca = (uabca & 0xF) << 4;
+       uabc  = (uabc / 16) - 1;
+
+       sh_sir_write(self, IRIF_UART6, uabca);
+       sh_sir_write(self, IRIF_UART7, uabc);
+
+       return 0;
+}
+
+/************************************************************************
+
+
+                       iobuf function
+
+
+************************************************************************/
+static int __sh_sir_init_iobuf(iobuff_t *io, int size)
+{
+       io->head = kmalloc(size, GFP_KERNEL);
+       if (!io->head)
+               return -ENOMEM;
+
+       io->truesize    = size;
+       io->in_frame    = FALSE;
+       io->state       = OUTSIDE_FRAME;
+       io->data        = io->head;
+
+       return 0;
+}
+
+static void sh_sir_remove_iobuf(struct sh_sir_self *self)
+{
+       kfree(self->rx_buff.head);
+       kfree(self->tx_buff.head);
+
+       self->rx_buff.head = NULL;
+       self->tx_buff.head = NULL;
+}
+
+static int sh_sir_init_iobuf(struct sh_sir_self *self, int rxsize, int txsize)
+{
+       int err = -ENOMEM;
+
+       if (self->rx_buff.head ||
+           self->tx_buff.head) {
+               dev_err(&self->ndev->dev, "iobuff has already existed.");
+               return err;
+       }
+
+       err = __sh_sir_init_iobuf(&self->rx_buff, rxsize);
+       if (err)
+               goto iobuf_err;
+
+       err = __sh_sir_init_iobuf(&self->tx_buff, txsize);
+
+iobuf_err:
+       if (err)
+               sh_sir_remove_iobuf(self);
+
+       return err;
+}
+
+/************************************************************************
+
+
+                       status function
+
+
+************************************************************************/
+static void sh_sir_clear_all_err(struct sh_sir_self *self)
+{
+       /* Clear error flag for receive pulse width */
+       sh_sir_update_bits(self, IRIF_SIR0, IRERRC, IRERRC);
+
+       /* Clear frame / EOF error flag */
+       sh_sir_write(self, IRIF_SIR_FLG, 0xffff);
+
+       /* Clear all status error */
+       sh_sir_write(self, IRIF_UART_STS2, 0);
+}
+
+static void sh_sir_set_phase(struct sh_sir_self *self, int phase)
+{
+       u16 uart5 = 0;
+       u16 uart0 = 0;
+
+       switch (phase) {
+       case TX_PHASE:
+               uart5 = TBEIM;
+               uart0 = TBEC | TIE;
+               break;
+       case TX_COMP_PHASE:
+               uart5 = TSBEIM;
+               uart0 = TIE;
+               break;
+       case RX_PHASE:
+               uart5 = RX_MASK;
+               uart0 = RIE;
+               break;
+       default:
+               break;
+       }
+
+       sh_sir_write(self, IRIF_UART5, uart5);
+       sh_sir_write(self, IRIF_UART0, uart0);
+}
+
+static int sh_sir_is_which_phase(struct sh_sir_self *self)
+{
+       u16 val = sh_sir_read(self, IRIF_UART5);
+
+       if (val & TBEIM)
+               return TX_PHASE;
+
+       if (val & TSBEIM)
+               return TX_COMP_PHASE;
+
+       if (val & RX_MASK)
+               return RX_PHASE;
+
+       return NONE_PHASE;
+}
+
+static void sh_sir_tx(struct sh_sir_self *self, int phase)
+{
+       switch (phase) {
+       case TX_PHASE:
+               if (0 >= self->tx_buff.len) {
+                       sh_sir_set_phase(self, TX_COMP_PHASE);
+               } else {
+                       sh_sir_write(self, IRIF_UART3, self->tx_buff.data[0]);
+                       self->tx_buff.len--;
+                       self->tx_buff.data++;
+               }
+               break;
+       case TX_COMP_PHASE:
+               sh_sir_set_phase(self, RX_PHASE);
+               netif_wake_queue(self->ndev);
+               break;
+       default:
+               dev_err(&self->ndev->dev, "should not happen\n");
+               break;
+       }
+}
+
+static int sh_sir_read_data(struct sh_sir_self *self)
+{
+       u16 val;
+       int timeout = 1024;
+
+       while (timeout--) {
+               val = sh_sir_read(self, IRIF_UART1);
+
+               /* data get */
+               if (val & RBF) {
+                       if (val & (URSME | UROVE | URFRE | URPRE))
+                               break;
+
+                       return (int)sh_sir_read(self, IRIF_UART4);
+               }
+
+               udelay(1);
+       }
+
+       dev_err(&self->ndev->dev, "UART1 %04x : STATUS %04x\n",
+               val, sh_sir_read(self, IRIF_UART_STS2));
+
+       /* read data register for clear error */
+       sh_sir_read(self, IRIF_UART4);
+
+       return -1;
+}
+
+static void sh_sir_rx(struct sh_sir_self *self)
+{
+       int timeout = 1024;
+       int data;
+
+       while (timeout--) {
+               data = sh_sir_read_data(self);
+               if (data < 0)
+                       break;
+
+               async_unwrap_char(self->ndev, &self->ndev->stats,
+                                 &self->rx_buff, (u8)data);
+               self->ndev->last_rx = jiffies;
+
+               if (EOFD & sh_sir_read(self, IRIF_SIR_FRM))
+                       continue;
+
+               break;
+       }
+}
+
+static irqreturn_t sh_sir_irq(int irq, void *dev_id)
+{
+       struct sh_sir_self *self = dev_id;
+       struct device *dev = &self->ndev->dev;
+       int phase = sh_sir_is_which_phase(self);
+
+       switch (phase) {
+       case TX_COMP_PHASE:
+       case TX_PHASE:
+               sh_sir_tx(self, phase);
+               break;
+       case RX_PHASE:
+               if (sh_sir_read(self, IRIF_SIR3))
+                       dev_err(dev, "rcv pulse width error occurred\n");
+
+               sh_sir_rx(self);
+               sh_sir_clear_all_err(self);
+               break;
+       default:
+               dev_err(dev, "unknown interrupt\n");
+       }
+
+        return IRQ_HANDLED;
+}
+
+/************************************************************************
+
+
+                       net_device_ops function
+
+
+************************************************************************/
+static int sh_sir_hard_xmit(struct sk_buff *skb, struct net_device *ndev)
+{
+       struct sh_sir_self *self = netdev_priv(ndev);
+       int speed = irda_get_next_speed(skb);
+
+       if ((0 < speed) &&
+           (9600 != speed)) {
+               dev_err(&ndev->dev, "support 9600 only (%d)\n", speed);
+               return -EIO;
+       }
+
+       netif_stop_queue(ndev);
+
+       self->tx_buff.data = self->tx_buff.head;
+       self->tx_buff.len = 0;
+       if (skb->len)
+               self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data,
+                                                  self->tx_buff.truesize);
+
+       sh_sir_set_phase(self, TX_PHASE);
+       dev_kfree_skb(skb);
+
+       return 0;
+}
+
+static int sh_sir_ioctl(struct net_device *ndev, struct ifreq *ifreq, int cmd)
+{
+       /*
+        * FIXME
+        *
+        * This function is needed for irda framework.
+        * But nothing to do now
+        */
+       return 0;
+}
+
+static struct net_device_stats *sh_sir_stats(struct net_device *ndev)
+{
+       struct sh_sir_self *self = netdev_priv(ndev);
+
+       return &self->ndev->stats;
+}
+
+static int sh_sir_open(struct net_device *ndev)
+{
+       struct sh_sir_self *self = netdev_priv(ndev);
+       int err;
+
+       clk_enable(self->clk);
+       err = sh_sir_crc_init(self);
+       if (err)
+               goto open_err;
+
+       sh_sir_set_baudrate(self, 9600);
+
+       self->irlap = irlap_open(ndev, &self->qos, DRIVER_NAME);
+       if (!self->irlap)
+               goto open_err;
+
+       /*
+        * Now enable the interrupt then start the queue
+        */
+       sh_sir_update_bits(self, IRIF_SIR_FRM, FRP, FRP);
+       sh_sir_read(self, IRIF_UART1); /* flag clear */
+       sh_sir_read(self, IRIF_UART4); /* flag clear */
+       sh_sir_set_phase(self, RX_PHASE);
+
+       netif_start_queue(ndev);
+
+       dev_info(&self->ndev->dev, "opened\n");
+
+       return 0;
+
+open_err:
+       clk_disable(self->clk);
+
+       return err;
+}
+
+static int sh_sir_stop(struct net_device *ndev)
+{
+       struct sh_sir_self *self = netdev_priv(ndev);
+
+       /* Stop IrLAP */
+       if (self->irlap) {
+               irlap_close(self->irlap);
+               self->irlap = NULL;
+       }
+
+       netif_stop_queue(ndev);
+
+       dev_info(&ndev->dev, "stoped\n");
+
+       return 0;
+}
+
+static const struct net_device_ops sh_sir_ndo = {
+       .ndo_open               = sh_sir_open,
+       .ndo_stop               = sh_sir_stop,
+       .ndo_start_xmit         = sh_sir_hard_xmit,
+       .ndo_do_ioctl           = sh_sir_ioctl,
+       .ndo_get_stats          = sh_sir_stats,
+};
+
+/************************************************************************
+
+
+                       platform_driver function
+
+
+************************************************************************/
+static int __devinit sh_sir_probe(struct platform_device *pdev)
+{
+       struct net_device *ndev;
+       struct sh_sir_self *self;
+       struct resource *res;
+       char clk_name[8];
+       void __iomem *base;
+       unsigned int irq;
+       int err = -ENOMEM;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       irq = platform_get_irq(pdev, 0);
+       if (!res || irq < 0) {
+               dev_err(&pdev->dev, "Not enough platform resources.\n");
+               goto exit;
+       }
+
+       ndev = alloc_irdadev(sizeof(*self));
+       if (!ndev)
+               goto exit;
+
+       base = ioremap_nocache(res->start, resource_size(res));
+       if (!base) {
+               err = -ENXIO;
+               dev_err(&pdev->dev, "Unable to ioremap.\n");
+               goto err_mem_1;
+       }
+
+       self = netdev_priv(ndev);
+       err = sh_sir_init_iobuf(self, IRDA_SKB_MAX_MTU, IRDA_SIR_MAX_FRAME);
+       if (err)
+               goto err_mem_2;
+
+       snprintf(clk_name, sizeof(clk_name), "irda%d", pdev->id);
+       self->clk = clk_get(&pdev->dev, clk_name);
+       if (IS_ERR(self->clk)) {
+               dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name);
+               goto err_mem_3;
+       }
+
+       irda_init_max_qos_capabilies(&self->qos);
+
+       ndev->netdev_ops        = &sh_sir_ndo;
+       ndev->irq               = irq;
+
+       self->membase                   = base;
+       self->ndev                      = ndev;
+       self->qos.baud_rate.bits        &= IR_9600; /* FIXME */
+       self->qos.min_turn_time.bits    = 1; /* 10 ms or more */
+
+       irda_qos_bits_to_value(&self->qos);
+
+       err = register_netdev(ndev);
+       if (err)
+               goto err_mem_4;
+
+       platform_set_drvdata(pdev, ndev);
+
+       if (request_irq(irq, sh_sir_irq, IRQF_DISABLED, "sh_sir", self)) {
+               dev_warn(&pdev->dev, "Unable to attach sh_sir interrupt\n");
+               goto err_mem_4;
+       }
+
+       dev_info(&pdev->dev, "SuperH IrDA probed\n");
+
+       goto exit;
+
+err_mem_4:
+       clk_put(self->clk);
+err_mem_3:
+       sh_sir_remove_iobuf(self);
+err_mem_2:
+       iounmap(self->membase);
+err_mem_1:
+       free_netdev(ndev);
+exit:
+       return err;
+}
+
+static int __devexit sh_sir_remove(struct platform_device *pdev)
+{
+       struct net_device *ndev = platform_get_drvdata(pdev);
+       struct sh_sir_self *self = netdev_priv(ndev);
+
+       if (!self)
+               return 0;
+
+       unregister_netdev(ndev);
+       clk_put(self->clk);
+       sh_sir_remove_iobuf(self);
+       iounmap(self->membase);
+       free_netdev(ndev);
+       platform_set_drvdata(pdev, NULL);
+
+       return 0;
+}
+
+static struct platform_driver sh_sir_driver = {
+       .probe   = sh_sir_probe,
+       .remove  = __devexit_p(sh_sir_remove),
+       .driver  = {
+               .name = DRIVER_NAME,
+       },
+};
+
+static int __init sh_sir_init(void)
+{
+       return platform_driver_register(&sh_sir_driver);
+}
+
+static void __exit sh_sir_exit(void)
+{
+       platform_driver_unregister(&sh_sir_driver);
+}
+
+module_init(sh_sir_init);
+module_exit(sh_sir_exit);
+
+MODULE_AUTHOR("Kuninori Morimoto <morimoto.kuninori@renesas.com>");
+MODULE_DESCRIPTION("SuperH IrDA driver");
+MODULE_LICENSE("GPL");
index fddb4efd545383debb70cd80c1ce3de68960674a..6533c010cf5c494f1e574da6ca43d64b507e9e53 100644 (file)
@@ -121,7 +121,7 @@ static void iodelay(int udelay)
        }
 }
 
-static struct pci_device_id via_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(via_pci_tbl) = {
        { PCI_VENDOR_ID_VIA, 0x8231, PCI_ANY_ID, PCI_ANY_ID,0,0,0 },
        { PCI_VENDOR_ID_VIA, 0x3109, PCI_ANY_ID, PCI_ANY_ID,0,0,1 },
        { PCI_VENDOR_ID_VIA, 0x3074, PCI_ANY_ID, PCI_ANY_ID,0,0,2 },
index bd3c6b5ee76a61f56f92fe14d96b12087d3c3aef..209d4bcfaced6d7e4288c3d5d90927b4493d7e1d 100644 (file)
@@ -59,7 +59,7 @@ MODULE_LICENSE("GPL");
 
 static /* const */ char drivername[] = DRIVER_NAME;
 
-static struct pci_device_id vlsi_irda_table [] = {
+static DEFINE_PCI_DEVICE_TABLE(vlsi_irda_table) = {
        {
                .class =        PCI_CLASS_WIRELESS_IRDA << 8,
                .class_mask =   PCI_CLASS_SUBCLASS_MASK << 8, 
index 593d1a4f217c0fccbf439156825f2556316c624d..c56ea69762cdd9c233ad9846a6895b5f4f7f5a43 100644 (file)
@@ -50,7 +50,7 @@ MODULE_PARM_DESC(copybreak,
  * { Vendor ID, Device ID, SubVendor ID, SubDevice ID,
  *   Class, Class Mask, private data (not used) }
  */
-static struct pci_device_id ixgb_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(ixgb_pci_tbl) = {
        {INTEL_VENDOR_ID, IXGB_DEVICE_ID_82597EX,
         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
        {INTEL_VENDOR_ID, IXGB_DEVICE_ID_82597EX_CX4,
index bfef0ebcba9ab343b36e4a7493cb36f42467b11c..8f81efb49169f150e3e45510117a904e6a7a7c82 100644 (file)
@@ -33,7 +33,8 @@
 obj-$(CONFIG_IXGBE) += ixgbe.o
 
 ixgbe-objs := ixgbe_main.o ixgbe_common.o ixgbe_ethtool.o \
-              ixgbe_82599.o ixgbe_82598.o ixgbe_phy.o
+              ixgbe_82599.o ixgbe_82598.o ixgbe_phy.o ixgbe_sriov.o \
+              ixgbe_mbx.o
 
 ixgbe-$(CONFIG_IXGBE_DCB) +=  ixgbe_dcb.o ixgbe_dcb_82598.o \
                               ixgbe_dcb_82599.o ixgbe_dcb_nl.o
index 303e7bd39b672fe4dbceff62ea91e96782e4211b..e576fb4740bc9799231a9a29cd9299ae2724a155 100644 (file)
 
 #define IXGBE_MAX_RSC_INT_RATE          162760
 
+#define IXGBE_MAX_VF_MC_ENTRIES         30
+#define IXGBE_MAX_VF_FUNCTIONS          64
+#define IXGBE_MAX_VFTA_ENTRIES          128
+#define MAX_EMULATION_MAC_ADDRS         16
+#define VMDQ_P(p)   ((p) + adapter->num_vfs)
+
+struct vf_data_storage {
+       unsigned char vf_mac_addresses[ETH_ALEN];
+       u16 vf_mc_hashes[IXGBE_MAX_VF_MC_ENTRIES];
+       u16 num_vf_mc_hashes;
+       u16 default_vf_vlan_id;
+       u16 vlans_enabled;
+       bool clear_to_send;
+       int rar;
+};
+
 /* wrapper around a pointer to a socket buffer,
  * so a DMA handle can be stored along with the buffer */
 struct ixgbe_tx_buffer {
@@ -171,7 +187,7 @@ struct ixgbe_ring {
 enum ixgbe_ring_f_enum {
        RING_F_NONE = 0,
        RING_F_DCB,
-       RING_F_VMDQ,
+       RING_F_VMDQ,  /* SR-IOV uses the same ring feature */
        RING_F_RSS,
        RING_F_FDIR,
 #ifdef IXGBE_FCOE
@@ -183,7 +199,7 @@ enum ixgbe_ring_f_enum {
 
 #define IXGBE_MAX_DCB_INDICES   8
 #define IXGBE_MAX_RSS_INDICES  16
-#define IXGBE_MAX_VMDQ_INDICES 16
+#define IXGBE_MAX_VMDQ_INDICES 64
 #define IXGBE_MAX_FDIR_INDICES 64
 #ifdef IXGBE_FCOE
 #define IXGBE_MAX_FCOE_INDICES  8
@@ -288,6 +304,8 @@ struct ixgbe_adapter {
        /* RX */
        struct ixgbe_ring *rx_ring ____cacheline_aligned_in_smp; /* One per active queue */
        int num_rx_queues;
+       int num_rx_pools;               /* == num_rx_queues in 82598 */
+       int num_rx_queues_per_pool;     /* 1 if 82598, can be many if 82599 */
        u64 hw_csum_rx_error;
        u64 hw_rx_no_dma_resources;
        u64 non_eop_descs;
@@ -330,6 +348,8 @@ struct ixgbe_adapter {
 #define IXGBE_FLAG_FDIR_PERFECT_CAPABLE         (u32)(1 << 27)
 #define IXGBE_FLAG_FCOE_CAPABLE                 (u32)(1 << 28)
 #define IXGBE_FLAG_FCOE_ENABLED                 (u32)(1 << 29)
+#define IXGBE_FLAG_SRIOV_CAPABLE                (u32)(1 << 30)
+#define IXGBE_FLAG_SRIOV_ENABLED                (u32)(1 << 31)
 
        u32 flags2;
 #define IXGBE_FLAG2_RSC_CAPABLE                 (u32)(1)
@@ -379,6 +399,11 @@ struct ixgbe_adapter {
        u64 rsc_total_flush;
        u32 wol;
        u16 eeprom_version;
+
+       /* SR-IOV */
+       DECLARE_BITMAP(active_vfs, IXGBE_MAX_VF_FUNCTIONS);
+       unsigned int num_vfs;
+       struct vf_data_storage *vfinfo;
 };
 
 enum ixbge_state_t {
@@ -440,6 +465,7 @@ extern s32 ixgbe_atr_set_flex_byte_82599(struct ixgbe_atr_input *input,
                                          u16 flex_byte);
 extern s32 ixgbe_atr_set_l4type_82599(struct ixgbe_atr_input *input,
                                       u8 l4type);
+extern void ixgbe_set_rx_mode(struct net_device *netdev);
 #ifdef IXGBE_FCOE
 extern void ixgbe_configure_fcoe(struct ixgbe_adapter *adapter);
 extern int ixgbe_fso(struct ixgbe_adapter *adapter,
index b49bd6b9feb724f7c5b93c69647d86e69a9a8ab0..d4ed6adb7975256d10561c60b34e5661d65bd9f6 100644 (file)
@@ -31,6 +31,7 @@
 
 #include "ixgbe.h"
 #include "ixgbe_phy.h"
+#include "ixgbe_mbx.h"
 
 #define IXGBE_82599_MAX_TX_QUEUES 128
 #define IXGBE_82599_MAX_RX_QUEUES 128
@@ -889,7 +890,7 @@ static s32 ixgbe_setup_copper_link_82599(struct ixgbe_hw *hw,
 static s32 ixgbe_reset_hw_82599(struct ixgbe_hw *hw)
 {
        s32 status = 0;
-       u32 ctrl, ctrl_ext;
+       u32 ctrl;
        u32 i;
        u32 autoc;
        u32 autoc2;
@@ -944,15 +945,9 @@ static s32 ixgbe_reset_hw_82599(struct ixgbe_hw *hw)
                status = IXGBE_ERR_RESET_FAILED;
                hw_dbg(hw, "Reset polling failed to complete.\n");
        }
-       /* Clear PF Reset Done bit so PF/VF Mail Ops can work */
-       ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT);
-       ctrl_ext |= IXGBE_CTRL_EXT_PFRSTD;
-       IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext);
 
        msleep(50);
 
-
-
        /*
         * Store the original AUTOC/AUTOC2 values if they have not been
         * stored off yet.  Otherwise restore the stored original
@@ -1095,9 +1090,11 @@ static s32 ixgbe_set_vfta_82599(struct ixgbe_hw *hw, u32 vlan, u32 vind,
                                 bool vlan_on)
 {
        u32 regindex;
+       u32 vlvf_index;
        u32 bitindex;
        u32 bits;
        u32 first_empty_slot;
+       u32 vt_ctl;
 
        if (vlan > 4095)
                return IXGBE_ERR_PARAM;
@@ -1124,76 +1121,84 @@ static s32 ixgbe_set_vfta_82599(struct ixgbe_hw *hw, u32 vlan, u32 vind,
 
 
        /* Part 2
-        * If the vind is set
+        * If VT mode is set
         *   Either vlan_on
         *     make sure the vlan is in VLVF
         *     set the vind bit in the matching VLVFB
         *   Or !vlan_on
         *     clear the pool bit and possibly the vind
         */
-       if (vind) {
-               /* find the vlanid or the first empty slot */
-               first_empty_slot = 0;
-
-               for (regindex = 1; regindex < IXGBE_VLVF_ENTRIES; regindex++) {
-                       bits = IXGBE_READ_REG(hw, IXGBE_VLVF(regindex));
-                       if (!bits && !first_empty_slot)
-                               first_empty_slot = regindex;
-                       else if ((bits & 0x0FFF) == vlan)
-                               break;
-               }
+       vt_ctl = IXGBE_READ_REG(hw, IXGBE_VT_CTL);
+       if (!(vt_ctl & IXGBE_VT_CTL_VT_ENABLE))
+               goto out;
 
-               if (regindex >= IXGBE_VLVF_ENTRIES) {
-                       if (first_empty_slot)
-                               regindex = first_empty_slot;
-                       else {
-                               hw_dbg(hw, "No space in VLVF.\n");
-                               goto out;
-                       }
+       /* find the vlanid or the first empty slot */
+       first_empty_slot = 0;
+
+       for (vlvf_index = 1; vlvf_index < IXGBE_VLVF_ENTRIES; vlvf_index++) {
+               bits = IXGBE_READ_REG(hw, IXGBE_VLVF(vlvf_index));
+               if (!bits && !first_empty_slot)
+                       first_empty_slot = vlvf_index;
+               else if ((bits & 0x0FFF) == vlan)
+                       break;
+       }
+
+       if (vlvf_index >= IXGBE_VLVF_ENTRIES) {
+               if (first_empty_slot)
+                       vlvf_index = first_empty_slot;
+               else {
+                       hw_dbg(hw, "No space in VLVF.\n");
+                       goto out;
                }
+       }
 
-               if (vlan_on) {
-                       /* set the pool bit */
-                       if (vind < 32) {
-                               bits = IXGBE_READ_REG(hw,
-                                                   IXGBE_VLVFB(regindex * 2));
-                               bits |= (1 << vind);
-                               IXGBE_WRITE_REG(hw,
-                                             IXGBE_VLVFB(regindex * 2), bits);
-                       } else {
-                               bits = IXGBE_READ_REG(hw,
-                                             IXGBE_VLVFB((regindex * 2) + 1));
-                               bits |= (1 << vind);
-                               IXGBE_WRITE_REG(hw,
-                                       IXGBE_VLVFB((regindex * 2) + 1), bits);
-                       }
+       if (vlan_on) {
+               /* set the pool bit */
+               if (vind < 32) {
+                       bits = IXGBE_READ_REG(hw,
+                                             IXGBE_VLVFB(vlvf_index * 2));
+                       bits |= (1 << vind);
+                       IXGBE_WRITE_REG(hw,
+                                       IXGBE_VLVFB(vlvf_index * 2), bits);
                } else {
-                       /* clear the pool bit */
-                       if (vind < 32) {
-                               bits = IXGBE_READ_REG(hw,
-                                    IXGBE_VLVFB(regindex * 2));
+                       bits = IXGBE_READ_REG(hw,
+                               IXGBE_VLVFB((vlvf_index * 2) + 1));
+                       bits |= (1 << (vind - 32));
+                       IXGBE_WRITE_REG(hw,
+                               IXGBE_VLVFB((vlvf_index * 2) + 1), bits);
+               }
+       } else {
+               /* clear the pool bit */
+               if (vind < 32) {
+                       bits = IXGBE_READ_REG(hw,
+                                             IXGBE_VLVFB(vlvf_index * 2));
                        bits &= ~(1 << vind);
-                               IXGBE_WRITE_REG(hw,
-                                             IXGBE_VLVFB(regindex * 2), bits);
-                               bits |= IXGBE_READ_REG(hw,
-                                             IXGBE_VLVFB((regindex * 2) + 1));
-                       } else {
-                               bits = IXGBE_READ_REG(hw,
-                                             IXGBE_VLVFB((regindex * 2) + 1));
-                               bits &= ~(1 << vind);
-                               IXGBE_WRITE_REG(hw,
-                                       IXGBE_VLVFB((regindex * 2) + 1), bits);
-                               bits |= IXGBE_READ_REG(hw,
-                                                   IXGBE_VLVFB(regindex * 2));
-                       }
+                       IXGBE_WRITE_REG(hw,
+                                       IXGBE_VLVFB(vlvf_index * 2), bits);
+                       bits |= IXGBE_READ_REG(hw,
+                                       IXGBE_VLVFB((vlvf_index * 2) + 1));
+               } else {
+                       bits = IXGBE_READ_REG(hw,
+                               IXGBE_VLVFB((vlvf_index * 2) + 1));
+                       bits &= ~(1 << (vind - 32));
+                       IXGBE_WRITE_REG(hw,
+                               IXGBE_VLVFB((vlvf_index * 2) + 1), bits);
+                       bits |= IXGBE_READ_REG(hw,
+                                              IXGBE_VLVFB(vlvf_index * 2));
                }
+       }
 
-               if (bits)
-                       IXGBE_WRITE_REG(hw, IXGBE_VLVF(regindex),
-                                       (IXGBE_VLVF_VIEN | vlan));
-               else
-                       IXGBE_WRITE_REG(hw, IXGBE_VLVF(regindex), 0);
+       if (bits) {
+               IXGBE_WRITE_REG(hw, IXGBE_VLVF(vlvf_index),
+                               (IXGBE_VLVF_VIEN | vlan));
+               /* if bits is non-zero then some pools/VFs are still
+                * using this VLAN ID.  Force the VFTA entry to on */
+               bits = IXGBE_READ_REG(hw, IXGBE_VFTA(regindex));
+               bits |= (1 << bitindex);
+               IXGBE_WRITE_REG(hw, IXGBE_VFTA(regindex), bits);
        }
+       else
+               IXGBE_WRITE_REG(hw, IXGBE_VLVF(vlvf_index), 0);
 
 out:
        return 0;
@@ -2655,4 +2660,5 @@ struct ixgbe_info ixgbe_82599_info = {
        .mac_ops                = &mac_ops_82599,
        .eeprom_ops             = &eeprom_ops_82599,
        .phy_ops                = &phy_ops_82599,
+       .mbx_ops                = &mbx_ops_82599,
 };
index 21f158f79dd01b10110866f1b1b0f2e80d236e36..eb49020903c12a019335d9ef27ca421721d35166 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/sched.h>
-#include <linux/list.h>
 #include <linux/netdevice.h>
 
 #include "ixgbe.h"
@@ -1278,19 +1277,11 @@ s32 ixgbe_init_rx_addrs_generic(struct ixgbe_hw *hw)
                /* Get the MAC address from the RAR0 for later reference */
                hw->mac.ops.get_mac_addr(hw, hw->mac.addr);
 
-               hw_dbg(hw, " Keeping Current RAR0 Addr =%.2X %.2X %.2X ",
-                      hw->mac.addr[0], hw->mac.addr[1],
-                      hw->mac.addr[2]);
-               hw_dbg(hw, "%.2X %.2X %.2X\n", hw->mac.addr[3],
-                      hw->mac.addr[4], hw->mac.addr[5]);
+               hw_dbg(hw, " Keeping Current RAR0 Addr =%pM\n", hw->mac.addr);
        } else {
                /* Setup the receive address. */
                hw_dbg(hw, "Overriding MAC Address in RAR[0]\n");
-               hw_dbg(hw, " New MAC Addr =%.2X %.2X %.2X ",
-                      hw->mac.addr[0], hw->mac.addr[1],
-                      hw->mac.addr[2]);
-               hw_dbg(hw, "%.2X %.2X %.2X\n", hw->mac.addr[3],
-                      hw->mac.addr[4], hw->mac.addr[5]);
+               hw_dbg(hw, " New MAC Addr =%pM\n", hw->mac.addr);
 
                hw->mac.ops.set_rar(hw, 0, hw->mac.addr, 0, IXGBE_RAH_AV);
        }
@@ -1355,7 +1346,7 @@ static void ixgbe_add_uc_addr(struct ixgbe_hw *hw, u8 *addr, u32 vmdq)
 /**
  *  ixgbe_update_uc_addr_list_generic - Updates MAC list of secondary addresses
  *  @hw: pointer to hardware structure
- *  @uc_list: the list of new addresses
+ *  @netdev: pointer to net device structure
  *
  *  The given list replaces any existing list.  Clears the secondary addrs from
  *  receive address registers.  Uses unused receive address registers for the
@@ -1365,7 +1356,7 @@ static void ixgbe_add_uc_addr(struct ixgbe_hw *hw, u8 *addr, u32 vmdq)
  *  manually putting the device into promiscuous mode.
  **/
 s32 ixgbe_update_uc_addr_list_generic(struct ixgbe_hw *hw,
-                                     struct list_head *uc_list)
+                                     struct net_device *netdev)
 {
        u32 i;
        u32 old_promisc_setting = hw->addr_ctrl.overflow_promisc;
@@ -1389,7 +1380,7 @@ s32 ixgbe_update_uc_addr_list_generic(struct ixgbe_hw *hw,
        }
 
        /* Add the new addresses */
-       list_for_each_entry(ha, uc_list, list) {
+       netdev_for_each_uc_addr(ha, netdev) {
                hw_dbg(hw, " Adding the secondary addresses:\n");
                ixgbe_add_uc_addr(hw, ha->addr, 0);
        }
index dfff0ffaa502df9737e126caba7ff31f30935fa7..13606d4809c90b8050b9087a2deb51dc0f43d7a6 100644 (file)
@@ -60,7 +60,7 @@ s32 ixgbe_update_mc_addr_list_generic(struct ixgbe_hw *hw, u8 *mc_addr_list,
                                       u32 mc_addr_count,
                                       ixgbe_mc_addr_itr func);
 s32 ixgbe_update_uc_addr_list_generic(struct ixgbe_hw *hw,
-                                     struct list_head *uc_list);
+                                     struct net_device *netdev);
 s32 ixgbe_enable_mc_generic(struct ixgbe_hw *hw);
 s32 ixgbe_disable_mc_generic(struct ixgbe_hw *hw);
 s32 ixgbe_enable_rx_dma_generic(struct ixgbe_hw *hw, u32 regval);
index d77961fc75f90c8eda86139f6885b5384fe47f56..1525c86cbccf15bfd874174840dc9bc770a4aa7f 100644 (file)
@@ -1867,11 +1867,22 @@ static void ixgbe_diag_test(struct net_device *netdev,
                if (ixgbe_intr_test(adapter, &data[2]))
                        eth_test->flags |= ETH_TEST_FL_FAILED;
 
+               /* If SRIOV or VMDq is enabled then skip MAC
+                * loopback diagnostic. */
+               if (adapter->flags & (IXGBE_FLAG_SRIOV_ENABLED |
+                                     IXGBE_FLAG_VMDQ_ENABLED)) {
+                       DPRINTK(HW, INFO, "Skip MAC loopback diagnostic in VT "
+                               "mode\n");
+                       data[3] = 0;
+                       goto skip_loopback;
+               }
+
                ixgbe_reset(adapter);
                DPRINTK(HW, INFO, "loopback testing starting\n");
                if (ixgbe_loopback_test(adapter, &data[3]))
                        eth_test->flags |= ETH_TEST_FL_FAILED;
 
+skip_loopback:
                ixgbe_reset(adapter);
 
                clear_bit(__IXGBE_TESTING, &adapter->state);
index 7b7c8486c0bf8dee604ea17949a1d945abeabf9c..f098816d4199815fd4acd0b046ecac1c03981d74 100644 (file)
@@ -45,6 +45,7 @@
 #include "ixgbe.h"
 #include "ixgbe_common.h"
 #include "ixgbe_dcb_82599.h"
+#include "ixgbe_sriov.h"
 
 char ixgbe_driver_name[] = "ixgbe";
 static const char ixgbe_driver_string[] =
@@ -67,7 +68,7 @@ static const struct ixgbe_info *ixgbe_info_tbl[] = {
  * { Vendor ID, Device ID, SubVendor ID, SubDevice ID,
  *   Class, Class Mask, private data (not used) }
  */
-static struct pci_device_id ixgbe_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(ixgbe_pci_tbl) = {
        {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598),
         board_82598 },
        {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598AF_DUAL_PORT),
@@ -124,6 +125,13 @@ static struct notifier_block dca_notifier = {
 };
 #endif
 
+#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");
+#endif /* CONFIG_PCI_IOV */
+
 MODULE_AUTHOR("Intel Corporation, <linux.nics@intel.com>");
 MODULE_DESCRIPTION("Intel(R) 10 Gigabit PCI Express Network Driver");
 MODULE_LICENSE("GPL");
@@ -131,6 +139,41 @@ MODULE_VERSION(DRV_VERSION);
 
 #define DEFAULT_DEBUG_LEVEL_SHIFT 3
 
+static inline void ixgbe_disable_sriov(struct ixgbe_adapter *adapter)
+{
+       struct ixgbe_hw *hw = &adapter->hw;
+       u32 gcr;
+       u32 gpie;
+       u32 vmdctl;
+
+#ifdef CONFIG_PCI_IOV
+       /* disable iov and allow time for transactions to clear */
+       pci_disable_sriov(adapter->pdev);
+#endif
+
+       /* turn off device IOV mode */
+       gcr = IXGBE_READ_REG(hw, IXGBE_GCR_EXT);
+       gcr &= ~(IXGBE_GCR_EXT_SRIOV);
+       IXGBE_WRITE_REG(hw, IXGBE_GCR_EXT, gcr);
+       gpie = IXGBE_READ_REG(hw, IXGBE_GPIE);
+       gpie &= ~IXGBE_GPIE_VTMODE_MASK;
+       IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie);
+
+       /* set default pool back to 0 */
+       vmdctl = IXGBE_READ_REG(hw, IXGBE_VT_CTL);
+       vmdctl &= ~IXGBE_VT_CTL_POOL_MASK;
+       IXGBE_WRITE_REG(hw, IXGBE_VT_CTL, vmdctl);
+
+       /* take a breather then clean up driver data */
+       msleep(100);
+       if (adapter->vfinfo)
+               kfree(adapter->vfinfo);
+       adapter->vfinfo = NULL;
+
+       adapter->num_vfs = 0;
+       adapter->flags &= ~IXGBE_FLAG_SRIOV_ENABLED;
+}
+
 static void ixgbe_release_hw_control(struct ixgbe_adapter *adapter)
 {
        u32 ctrl_ext;
@@ -1025,7 +1068,12 @@ static void ixgbe_configure_msix(struct ixgbe_adapter *adapter)
 
        /* set up to autoclear timer, and the vectors */
        mask = IXGBE_EIMS_ENABLE_MASK;
-       mask &= ~(IXGBE_EIMS_OTHER | IXGBE_EIMS_LSC);
+       if (adapter->num_vfs)
+               mask &= ~(IXGBE_EIMS_OTHER |
+                         IXGBE_EIMS_MAILBOX |
+                         IXGBE_EIMS_LSC);
+       else
+               mask &= ~(IXGBE_EIMS_OTHER | IXGBE_EIMS_LSC);
        IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIAC, mask);
 }
 
@@ -1254,6 +1302,9 @@ static irqreturn_t ixgbe_msix_lsc(int irq, void *data)
        if (eicr & IXGBE_EICR_LSC)
                ixgbe_check_lsc(adapter);
 
+       if (eicr & IXGBE_EICR_MAILBOX)
+               ixgbe_msg_task(adapter);
+
        if (hw->mac.type == ixgbe_mac_82598EB)
                ixgbe_check_fan_failure(adapter, eicr);
 
@@ -1768,6 +1819,8 @@ static inline void ixgbe_irq_enable(struct ixgbe_adapter *adapter)
                mask |= IXGBE_EIMS_ECC;
                mask |= IXGBE_EIMS_GPI_SDP1;
                mask |= IXGBE_EIMS_GPI_SDP2;
+               if (adapter->num_vfs)
+                       mask |= IXGBE_EIMS_MAILBOX;
        }
        if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE ||
            adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE)
@@ -1776,6 +1829,11 @@ static inline void ixgbe_irq_enable(struct ixgbe_adapter *adapter)
        IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, mask);
        ixgbe_irq_enable_queues(adapter, ~0);
        IXGBE_WRITE_FLUSH(&adapter->hw);
+
+       if (adapter->num_vfs > 32) {
+               u32 eitrsel = (1 << (adapter->num_vfs - 32)) - 1;
+               IXGBE_WRITE_REG(&adapter->hw, IXGBE_EITRSEL, eitrsel);
+       }
 }
 
 /**
@@ -1905,6 +1963,8 @@ static inline void ixgbe_irq_disable(struct ixgbe_adapter *adapter)
                IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, 0xFFFF0000);
                IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(0), ~0);
                IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(1), ~0);
+               if (adapter->num_vfs > 32)
+                       IXGBE_WRITE_REG(&adapter->hw, IXGBE_EITRSEL, 0);
        }
        IXGBE_WRITE_FLUSH(&adapter->hw);
        if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) {
@@ -1989,18 +2049,32 @@ static void ixgbe_configure_tx(struct ixgbe_adapter *adapter)
 
        if (hw->mac.type == ixgbe_mac_82599EB) {
                u32 rttdcs;
+               u32 mask;
 
                /* disable the arbiter while setting MTQC */
                rttdcs = IXGBE_READ_REG(hw, IXGBE_RTTDCS);
                rttdcs |= IXGBE_RTTDCS_ARBDIS;
                IXGBE_WRITE_REG(hw, IXGBE_RTTDCS, rttdcs);
 
-               /* We enable 8 traffic classes, DCB only */
-               if (adapter->flags & IXGBE_FLAG_DCB_ENABLED)
-                       IXGBE_WRITE_REG(hw, IXGBE_MTQC, (IXGBE_MTQC_RT_ENA |
-                                       IXGBE_MTQC_8TC_8TQ));
-               else
+               /* 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-eable the arbiter */
                rttdcs &= ~IXGBE_RTTDCS_ARBDIS;
@@ -2059,12 +2133,16 @@ static u32 ixgbe_setup_mrqc(struct ixgbe_adapter *adapter)
 #ifdef CONFIG_IXGBE_DCB
                                 | IXGBE_FLAG_DCB_ENABLED
 #endif
+                                | IXGBE_FLAG_SRIOV_ENABLED
                                );
 
        switch (mask) {
        case (IXGBE_FLAG_RSS_ENABLED):
                mrqc = IXGBE_MRQC_RSSEN;
                break;
+       case (IXGBE_FLAG_SRIOV_ENABLED):
+               mrqc = IXGBE_MRQC_VMDQEN;
+               break;
 #ifdef CONFIG_IXGBE_DCB
        case (IXGBE_FLAG_DCB_ENABLED):
                mrqc = IXGBE_MRQC_RT8TCEN;
@@ -2145,7 +2223,9 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter)
        int rx_buf_len;
 
        /* Decide whether to use packet split mode or not */
-       adapter->flags |= IXGBE_FLAG_RX_PS_ENABLED;
+       /* Do not use packet split if we're in SR-IOV Mode */
+       if (!adapter->num_vfs)
+               adapter->flags |= IXGBE_FLAG_RX_PS_ENABLED;
 
        /* Set the RX buffer length according to the mode */
        if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) {
@@ -2157,7 +2237,9 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter)
                                      IXGBE_PSRTYPE_IPV4HDR |
                                      IXGBE_PSRTYPE_IPV6HDR |
                                      IXGBE_PSRTYPE_L2HDR;
-                       IXGBE_WRITE_REG(hw, IXGBE_PSRTYPE(0), psrtype);
+                       IXGBE_WRITE_REG(hw,
+                                       IXGBE_PSRTYPE(adapter->num_vfs),
+                                       psrtype);
                }
        } else {
                if (!(adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED) &&
@@ -2243,6 +2325,30 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter)
                IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, rdrxctl);
        }
 
+       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);
+       }
+
        /* Program MRQC for the distribution of queues */
        mrqc = ixgbe_setup_mrqc(adapter);
 
@@ -2274,6 +2380,20 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter)
        }
        IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc);
 
+       if (adapter->num_vfs) {
+               u32 reg;
+
+               /* 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.
+                * 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);
+       }
+
        rxcsum = IXGBE_READ_REG(hw, IXGBE_RXCSUM);
 
        if (adapter->flags & IXGBE_FLAG_RSS_ENABLED ||
@@ -2312,15 +2432,17 @@ static void ixgbe_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
 {
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
        struct ixgbe_hw *hw = &adapter->hw;
+       int pool_ndx = adapter->num_vfs;
 
        /* add VID to filter table */
-       hw->mac.ops.set_vfta(&adapter->hw, vid, 0, true);
+       hw->mac.ops.set_vfta(&adapter->hw, vid, pool_ndx, true);
 }
 
 static void ixgbe_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
 {
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
        struct ixgbe_hw *hw = &adapter->hw;
+       int pool_ndx = adapter->num_vfs;
 
        if (!test_bit(__IXGBE_DOWN, &adapter->state))
                ixgbe_irq_disable(adapter);
@@ -2331,7 +2453,7 @@ static void ixgbe_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
                ixgbe_irq_enable(adapter);
 
        /* remove VID from filter table */
-       hw->mac.ops.set_vfta(&adapter->hw, vid, 0, false);
+       hw->mac.ops.set_vfta(&adapter->hw, vid, pool_ndx, false);
 }
 
 static void ixgbe_vlan_rx_register(struct net_device *netdev,
@@ -2414,7 +2536,7 @@ static u8 *ixgbe_addr_list_itr(struct ixgbe_hw *hw, u8 **mc_addr_ptr, u32 *vmdq)
  * responsible for configuring the hardware for proper unicast, multicast and
  * promiscuous mode.
  **/
-static void ixgbe_set_rx_mode(struct net_device *netdev)
+void ixgbe_set_rx_mode(struct net_device *netdev)
 {
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
        struct ixgbe_hw *hw = &adapter->hw;
@@ -2446,7 +2568,7 @@ static void ixgbe_set_rx_mode(struct net_device *netdev)
        IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, vlnctrl);
 
        /* reprogram secondary unicast list */
-       hw->mac.ops.update_uc_addr_list(hw, &netdev->uc.list);
+       hw->mac.ops.update_uc_addr_list(hw, netdev);
 
        /* reprogram multicast list */
        addr_count = netdev->mc_count;
@@ -2454,6 +2576,8 @@ static void ixgbe_set_rx_mode(struct net_device *netdev)
                addr_list = netdev->mc_list->dmi_addr;
        hw->mac.ops.update_mc_addr_list(hw, addr_list, addr_count,
                                        ixgbe_addr_list_itr);
+       if (adapter->num_vfs)
+               ixgbe_restore_vf_multicasts(adapter);
 }
 
 static void ixgbe_napi_enable_all(struct ixgbe_adapter *adapter)
@@ -2702,6 +2826,7 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
        u32 txdctl, rxdctl, mhadd;
        u32 dmatxctl;
        u32 gpie;
+       u32 ctrl_ext;
 
        ixgbe_get_hw_control(adapter);
 
@@ -2714,6 +2839,10 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
                        /* 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);
@@ -2788,6 +2917,18 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
                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)
+                               DPRINTK(DRV, ERR, "Could not enable "
+                                       "Tx Queue %d\n", j);
+               }
        }
 
        for (i = 0; i < num_rx_rings; i++) {
@@ -2875,6 +3016,12 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
        adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE;
        adapter->link_check_timeout = jiffies;
        mod_timer(&adapter->watchdog_timer, jiffies);
+
+       /* Set PF Reset Done bit so PF/VF Mail Ops can work */
+       ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT);
+       ctrl_ext |= IXGBE_CTRL_EXT_PFRSTD;
+       IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext);
+
        return 0;
 }
 
@@ -2923,7 +3070,8 @@ void ixgbe_reset(struct ixgbe_adapter *adapter)
        }
 
        /* reprogram the RAR[0] in case user changed it. */
-       hw->mac.ops.set_rar(hw, 0, hw->mac.addr, 0, IXGBE_RAH_AV);
+       hw->mac.ops.set_rar(hw, 0, hw->mac.addr, adapter->num_vfs,
+                           IXGBE_RAH_AV);
 }
 
 /**
@@ -3055,6 +3203,17 @@ void ixgbe_down(struct ixgbe_adapter *adapter)
        /* signal that we are down to the interrupt handler */
        set_bit(__IXGBE_DOWN, &adapter->state);
 
+       /* disable receive for all VFs and wait one second */
+       if (adapter->num_vfs) {
+               for (i = 0 ; i < adapter->num_vfs; i++)
+                       adapter->vfinfo[i].clear_to_send = 0;
+
+               /* ping all the active vfs to let them know we are going down */
+               ixgbe_ping_all_vfs(adapter);
+               /* Disable all VFTE/VFRE TX/RX */
+               ixgbe_disable_tx_rx(adapter);
+       }
+
        /* disable receives */
        rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
        IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, rxctrl & ~IXGBE_RXCTRL_RXEN);
@@ -3291,6 +3450,19 @@ static inline bool ixgbe_set_fcoe_queues(struct ixgbe_adapter *adapter)
 }
 
 #endif /* IXGBE_FCOE */
+/**
+ * ixgbe_set_sriov_queues: Allocate queues for IOV use
+ * @adapter: board private structure to initialize
+ *
+ * IOV doesn't actually use anything, so just NAK the
+ * request for now and let the other queue routines
+ * figure out what to do.
+ */
+static inline bool ixgbe_set_sriov_queues(struct ixgbe_adapter *adapter)
+{
+       return false;
+}
+
 /*
  * ixgbe_set_num_queues: Allocate queues for device, feature dependant
  * @adapter: board private structure to initialize
@@ -3304,6 +3476,15 @@ static inline bool ixgbe_set_fcoe_queues(struct ixgbe_adapter *adapter)
  **/
 static void ixgbe_set_num_queues(struct ixgbe_adapter *adapter)
 {
+       /* Start with base case */
+       adapter->num_rx_queues = 1;
+       adapter->num_tx_queues = 1;
+       adapter->num_rx_pools = adapter->num_rx_queues;
+       adapter->num_rx_queues_per_pool = 1;
+
+       if (ixgbe_set_sriov_queues(adapter))
+               return;
+
 #ifdef IXGBE_FCOE
        if (ixgbe_set_fcoe_queues(adapter))
                goto done;
@@ -3574,6 +3755,24 @@ static inline bool ixgbe_cache_ring_fcoe(struct ixgbe_adapter *adapter)
 }
 
 #endif /* IXGBE_FCOE */
+/**
+ * ixgbe_cache_ring_sriov - Descriptor ring to register mapping for sriov
+ * @adapter: board private structure to initialize
+ *
+ * SR-IOV doesn't use any descriptor rings but changes the default if
+ * no other mapping is used.
+ *
+ */
+static inline bool ixgbe_cache_ring_sriov(struct ixgbe_adapter *adapter)
+{
+       adapter->rx_ring[0].reg_idx = adapter->num_vfs * 2;
+       adapter->tx_ring[0].reg_idx = adapter->num_vfs * 2;
+       if (adapter->num_vfs)
+               return true;
+       else
+               return false;
+}
+
 /**
  * ixgbe_cache_ring_register - Descriptor ring to register mapping
  * @adapter: board private structure to initialize
@@ -3591,6 +3790,9 @@ static void ixgbe_cache_ring_register(struct ixgbe_adapter *adapter)
        adapter->rx_ring[0].reg_idx = 0;
        adapter->tx_ring[0].reg_idx = 0;
 
+       if (ixgbe_cache_ring_sriov(adapter))
+               return;
+
 #ifdef IXGBE_FCOE
        if (ixgbe_cache_ring_fcoe(adapter))
                return;
@@ -3700,6 +3902,9 @@ static int ixgbe_set_interrupt_capability(struct ixgbe_adapter *adapter)
        adapter->flags &= ~IXGBE_FLAG_FDIR_HASH_CAPABLE;
        adapter->flags &= ~IXGBE_FLAG_FDIR_PERFECT_CAPABLE;
        adapter->atr_sample_rate = 0;
+       if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED)
+               ixgbe_disable_sriov(adapter);
+
        ixgbe_set_num_queues(adapter);
 
        err = pci_enable_msi(adapter->pdev);
@@ -5487,7 +5692,8 @@ static int ixgbe_set_mac(struct net_device *netdev, void *p)
        memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
        memcpy(hw->mac.addr, addr->sa_data, netdev->addr_len);
 
-       hw->mac.ops.set_rar(hw, 0, hw->mac.addr, 0, IXGBE_RAH_AV);
+       hw->mac.ops.set_rar(hw, 0, hw->mac.addr, adapter->num_vfs,
+                           IXGBE_RAH_AV);
 
        return 0;
 }
@@ -5624,6 +5830,61 @@ static const struct net_device_ops ixgbe_netdev_ops = {
 #endif /* IXGBE_FCOE */
 };
 
+static void __devinit ixgbe_probe_vf(struct ixgbe_adapter *adapter,
+                          const struct ixgbe_info *ii)
+{
+#ifdef CONFIG_PCI_IOV
+       struct ixgbe_hw *hw = &adapter->hw;
+       int err;
+
+       if (hw->mac.type != ixgbe_mac_82599EB || !max_vfs)
+               return;
+
+       /* The 82599 supports up to 64 VFs per physical function
+        * but this implementation limits allocation to 63 so that
+        * basic networking resources are still available to the
+        * physical function
+        */
+       adapter->num_vfs = (max_vfs > 63) ? 63 : max_vfs;
+       adapter->flags |= IXGBE_FLAG_SRIOV_ENABLED;
+       err = pci_enable_sriov(adapter->pdev, adapter->num_vfs);
+       if (err) {
+               DPRINTK(PROBE, ERR,
+                       "Failed to enable PCI sriov: %d\n", err);
+               goto err_novfs;
+       }
+       /* If call to enable VFs succeeded then allocate memory
+        * for per VF control structures.
+        */
+       adapter->vfinfo =
+               kcalloc(adapter->num_vfs,
+                       sizeof(struct vf_data_storage), GFP_KERNEL);
+       if (adapter->vfinfo) {
+               /* Now that we're sure SR-IOV is enabled
+                * and memory allocated set up the mailbox parameters
+                */
+               ixgbe_init_mbx_params_pf(hw);
+               memcpy(&hw->mbx.ops, ii->mbx_ops,
+                      sizeof(hw->mbx.ops));
+
+               /* Disable RSC when in SR-IOV mode */
+               adapter->flags2 &= ~(IXGBE_FLAG2_RSC_CAPABLE |
+                                    IXGBE_FLAG2_RSC_ENABLED);
+               return;
+       }
+
+       /* Oh oh */
+       DPRINTK(PROBE, ERR,
+               "Unable to allocate memory for VF "
+               "Data Storage - SRIOV disabled\n");
+       pci_disable_sriov(adapter->pdev);
+
+err_novfs:
+       adapter->flags &= ~IXGBE_FLAG_SRIOV_ENABLED;
+       adapter->num_vfs = 0;
+#endif /* CONFIG_PCI_IOV */
+}
+
 /**
  * ixgbe_probe - Device Initialization Routine
  * @pdev: PCI device information struct
@@ -5798,6 +6059,8 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
                goto err_sw_init;
        }
 
+       ixgbe_probe_vf(adapter, ii);
+
        netdev->features = NETIF_F_SG |
                           NETIF_F_IP_CSUM |
                           NETIF_F_HW_VLAN_TX |
@@ -5818,6 +6081,9 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
        netdev->vlan_features |= NETIF_F_IPV6_CSUM;
        netdev->vlan_features |= NETIF_F_SG;
 
+       if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED)
+               adapter->flags &= ~(IXGBE_FLAG_RSS_ENABLED |
+                                   IXGBE_FLAG_DCB_ENABLED);
        if (adapter->flags & IXGBE_FLAG_DCB_ENABLED)
                adapter->flags &= ~IXGBE_FLAG_RSS_ENABLED;
 
@@ -5944,6 +6210,13 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
                ixgbe_setup_dca(adapter);
        }
 #endif
+       if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED) {
+               DPRINTK(PROBE, INFO, "IOV is enabled with %d VFs\n",
+                       adapter->num_vfs);
+               for (i = 0; i < adapter->num_vfs; i++)
+                       ixgbe_vf_configuration(pdev, (i | 0x10000000));
+       }
+
        /* add san mac addr to netdev */
        ixgbe_add_sanmac_netdev(netdev);
 
@@ -5956,6 +6229,8 @@ err_register:
        ixgbe_clear_interrupt_scheme(adapter);
 err_sw_init:
 err_eeprom:
+       if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED)
+               ixgbe_disable_sriov(adapter);
        clear_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state);
        del_timer_sync(&adapter->sfp_timer);
        cancel_work_sync(&adapter->sfp_task);
@@ -6024,6 +6299,9 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev)
        if (netdev->reg_state == NETREG_REGISTERED)
                unregister_netdev(netdev);
 
+       if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED)
+               ixgbe_disable_sriov(adapter);
+
        ixgbe_clear_interrupt_scheme(adapter);
 
        ixgbe_release_hw_control(adapter);
diff --git a/drivers/net/ixgbe/ixgbe_mbx.c b/drivers/net/ixgbe/ixgbe_mbx.c
new file mode 100644 (file)
index 0000000..d75f914
--- /dev/null
@@ -0,0 +1,479 @@
+/*******************************************************************************
+
+  Intel 10 Gigabit PCI Express Linux driver
+  Copyright(c) 1999 - 2009 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include "ixgbe_type.h"
+#include "ixgbe_common.h"
+#include "ixgbe_mbx.h"
+
+/**
+ *  ixgbe_read_mbx - Reads a message from the mailbox
+ *  @hw: pointer to the HW structure
+ *  @msg: The message buffer
+ *  @size: Length of buffer
+ *  @mbx_id: id of mailbox to read
+ *
+ *  returns SUCCESS if it successfuly read message from buffer
+ **/
+s32 ixgbe_read_mbx(struct ixgbe_hw *hw, u32 *msg, u16 size, u16 mbx_id)
+{
+       struct ixgbe_mbx_info *mbx = &hw->mbx;
+       s32 ret_val = IXGBE_ERR_MBX;
+
+       /* limit read to size of mailbox */
+       if (size > mbx->size)
+               size = mbx->size;
+
+       if (mbx->ops.read)
+               ret_val = mbx->ops.read(hw, msg, size, mbx_id);
+
+       return ret_val;
+}
+
+/**
+ *  ixgbe_write_mbx - Write a message to the mailbox
+ *  @hw: pointer to the HW structure
+ *  @msg: The message buffer
+ *  @size: Length of buffer
+ *  @mbx_id: id of mailbox to write
+ *
+ *  returns SUCCESS if it successfully copied message into the buffer
+ **/
+s32 ixgbe_write_mbx(struct ixgbe_hw *hw, u32 *msg, u16 size, u16 mbx_id)
+{
+       struct ixgbe_mbx_info *mbx = &hw->mbx;
+       s32 ret_val = 0;
+
+       if (size > mbx->size)
+               ret_val = IXGBE_ERR_MBX;
+
+       else if (mbx->ops.write)
+               ret_val = mbx->ops.write(hw, msg, size, mbx_id);
+
+       return ret_val;
+}
+
+/**
+ *  ixgbe_check_for_msg - checks to see if someone sent us mail
+ *  @hw: pointer to the HW structure
+ *  @mbx_id: id of mailbox to check
+ *
+ *  returns SUCCESS if the Status bit was found or else ERR_MBX
+ **/
+s32 ixgbe_check_for_msg(struct ixgbe_hw *hw, u16 mbx_id)
+{
+       struct ixgbe_mbx_info *mbx = &hw->mbx;
+       s32 ret_val = IXGBE_ERR_MBX;
+
+       if (mbx->ops.check_for_msg)
+               ret_val = mbx->ops.check_for_msg(hw, mbx_id);
+
+       return ret_val;
+}
+
+/**
+ *  ixgbe_check_for_ack - checks to see if someone sent us ACK
+ *  @hw: pointer to the HW structure
+ *  @mbx_id: id of mailbox to check
+ *
+ *  returns SUCCESS if the Status bit was found or else ERR_MBX
+ **/
+s32 ixgbe_check_for_ack(struct ixgbe_hw *hw, u16 mbx_id)
+{
+       struct ixgbe_mbx_info *mbx = &hw->mbx;
+       s32 ret_val = IXGBE_ERR_MBX;
+
+       if (mbx->ops.check_for_ack)
+               ret_val = mbx->ops.check_for_ack(hw, mbx_id);
+
+       return ret_val;
+}
+
+/**
+ *  ixgbe_check_for_rst - checks to see if other side has reset
+ *  @hw: pointer to the HW structure
+ *  @mbx_id: id of mailbox to check
+ *
+ *  returns SUCCESS if the Status bit was found or else ERR_MBX
+ **/
+s32 ixgbe_check_for_rst(struct ixgbe_hw *hw, u16 mbx_id)
+{
+       struct ixgbe_mbx_info *mbx = &hw->mbx;
+       s32 ret_val = IXGBE_ERR_MBX;
+
+       if (mbx->ops.check_for_rst)
+               ret_val = mbx->ops.check_for_rst(hw, mbx_id);
+
+       return ret_val;
+}
+
+/**
+ *  ixgbe_poll_for_msg - Wait for message notification
+ *  @hw: pointer to the HW structure
+ *  @mbx_id: id of mailbox to write
+ *
+ *  returns SUCCESS if it successfully received a message notification
+ **/
+static s32 ixgbe_poll_for_msg(struct ixgbe_hw *hw, u16 mbx_id)
+{
+       struct ixgbe_mbx_info *mbx = &hw->mbx;
+       int countdown = mbx->timeout;
+
+       if (!countdown || !mbx->ops.check_for_msg)
+               goto out;
+
+       while (countdown && mbx->ops.check_for_msg(hw, mbx_id)) {
+               countdown--;
+               if (!countdown)
+                       break;
+               udelay(mbx->usec_delay);
+       }
+
+       /* if we failed, all future posted messages fail until reset */
+       if (!countdown)
+               mbx->timeout = 0;
+out:
+       return countdown ? 0 : IXGBE_ERR_MBX;
+}
+
+/**
+ *  ixgbe_poll_for_ack - Wait for message acknowledgement
+ *  @hw: pointer to the HW structure
+ *  @mbx_id: id of mailbox to write
+ *
+ *  returns SUCCESS if it successfully received a message acknowledgement
+ **/
+static s32 ixgbe_poll_for_ack(struct ixgbe_hw *hw, u16 mbx_id)
+{
+       struct ixgbe_mbx_info *mbx = &hw->mbx;
+       int countdown = mbx->timeout;
+
+       if (!countdown || !mbx->ops.check_for_ack)
+               goto out;
+
+       while (countdown && mbx->ops.check_for_ack(hw, mbx_id)) {
+               countdown--;
+               if (!countdown)
+                       break;
+               udelay(mbx->usec_delay);
+       }
+
+       /* if we failed, all future posted messages fail until reset */
+       if (!countdown)
+               mbx->timeout = 0;
+out:
+       return countdown ? 0 : IXGBE_ERR_MBX;
+}
+
+/**
+ *  ixgbe_read_posted_mbx - Wait for message notification and receive message
+ *  @hw: pointer to the HW structure
+ *  @msg: The message buffer
+ *  @size: Length of buffer
+ *  @mbx_id: id of mailbox to write
+ *
+ *  returns SUCCESS if it successfully received a message notification and
+ *  copied it into the receive buffer.
+ **/
+s32 ixgbe_read_posted_mbx(struct ixgbe_hw *hw, u32 *msg, u16 size, u16 mbx_id)
+{
+       struct ixgbe_mbx_info *mbx = &hw->mbx;
+       s32 ret_val = IXGBE_ERR_MBX;
+
+       if (!mbx->ops.read)
+               goto out;
+
+       ret_val = ixgbe_poll_for_msg(hw, mbx_id);
+
+       /* if ack received read message, otherwise we timed out */
+       if (!ret_val)
+               ret_val = mbx->ops.read(hw, msg, size, mbx_id);
+out:
+       return ret_val;
+}
+
+/**
+ *  ixgbe_write_posted_mbx - Write a message to the mailbox, wait for ack
+ *  @hw: pointer to the HW structure
+ *  @msg: The message buffer
+ *  @size: Length of buffer
+ *  @mbx_id: id of mailbox to write
+ *
+ *  returns SUCCESS if it successfully copied message into the buffer and
+ *  received an ack to that message within delay * timeout period
+ **/
+s32 ixgbe_write_posted_mbx(struct ixgbe_hw *hw, u32 *msg, u16 size,
+                           u16 mbx_id)
+{
+       struct ixgbe_mbx_info *mbx = &hw->mbx;
+       s32 ret_val = IXGBE_ERR_MBX;
+
+       /* exit if either we can't write or there isn't a defined timeout */
+       if (!mbx->ops.write || !mbx->timeout)
+               goto out;
+
+       /* send msg */
+       ret_val = mbx->ops.write(hw, msg, size, mbx_id);
+
+       /* if msg sent wait until we receive an ack */
+       if (!ret_val)
+               ret_val = ixgbe_poll_for_ack(hw, mbx_id);
+out:
+       return ret_val;
+}
+
+/**
+ *  ixgbe_init_mbx_ops_generic - Initialize MB function pointers
+ *  @hw: pointer to the HW structure
+ *
+ *  Setup the mailbox read and write message function pointers
+ **/
+void ixgbe_init_mbx_ops_generic(struct ixgbe_hw *hw)
+{
+       struct ixgbe_mbx_info *mbx = &hw->mbx;
+
+       mbx->ops.read_posted = ixgbe_read_posted_mbx;
+       mbx->ops.write_posted = ixgbe_write_posted_mbx;
+}
+
+static s32 ixgbe_check_for_bit_pf(struct ixgbe_hw *hw, u32 mask, s32 index)
+{
+       u32 mbvficr = IXGBE_READ_REG(hw, IXGBE_MBVFICR(index));
+       s32 ret_val = IXGBE_ERR_MBX;
+
+       if (mbvficr & mask) {
+               ret_val = 0;
+               IXGBE_WRITE_REG(hw, IXGBE_MBVFICR(index), mask);
+       }
+
+       return ret_val;
+}
+
+/**
+ *  ixgbe_check_for_msg_pf - checks to see if the VF has sent mail
+ *  @hw: pointer to the HW structure
+ *  @vf_number: the VF index
+ *
+ *  returns SUCCESS if the VF has set the Status bit or else ERR_MBX
+ **/
+static s32 ixgbe_check_for_msg_pf(struct ixgbe_hw *hw, u16 vf_number)
+{
+       s32 ret_val = IXGBE_ERR_MBX;
+       s32 index = IXGBE_MBVFICR_INDEX(vf_number);
+       u32 vf_bit = vf_number % 16;
+
+       if (!ixgbe_check_for_bit_pf(hw, IXGBE_MBVFICR_VFREQ_VF1 << vf_bit,
+                                   index)) {
+               ret_val = 0;
+               hw->mbx.stats.reqs++;
+       }
+
+       return ret_val;
+}
+
+/**
+ *  ixgbe_check_for_ack_pf - checks to see if the VF has ACKed
+ *  @hw: pointer to the HW structure
+ *  @vf_number: the VF index
+ *
+ *  returns SUCCESS if the VF has set the Status bit or else ERR_MBX
+ **/
+static s32 ixgbe_check_for_ack_pf(struct ixgbe_hw *hw, u16 vf_number)
+{
+       s32 ret_val = IXGBE_ERR_MBX;
+       s32 index = IXGBE_MBVFICR_INDEX(vf_number);
+       u32 vf_bit = vf_number % 16;
+
+       if (!ixgbe_check_for_bit_pf(hw, IXGBE_MBVFICR_VFACK_VF1 << vf_bit,
+                                   index)) {
+               ret_val = 0;
+               hw->mbx.stats.acks++;
+       }
+
+       return ret_val;
+}
+
+/**
+ *  ixgbe_check_for_rst_pf - checks to see if the VF has reset
+ *  @hw: pointer to the HW structure
+ *  @vf_number: the VF index
+ *
+ *  returns SUCCESS if the VF has set the Status bit or else ERR_MBX
+ **/
+static s32 ixgbe_check_for_rst_pf(struct ixgbe_hw *hw, u16 vf_number)
+{
+       u32 reg_offset = (vf_number < 32) ? 0 : 1;
+       u32 vf_shift = vf_number % 32;
+       u32 vflre = 0;
+       s32 ret_val = IXGBE_ERR_MBX;
+
+       if (hw->mac.type == ixgbe_mac_82599EB)
+               vflre = IXGBE_READ_REG(hw, IXGBE_VFLRE(reg_offset));
+
+       if (vflre & (1 << vf_shift)) {
+               ret_val = 0;
+               IXGBE_WRITE_REG(hw, IXGBE_VFLREC(reg_offset), (1 << vf_shift));
+               hw->mbx.stats.rsts++;
+       }
+
+       return ret_val;
+}
+
+/**
+ *  ixgbe_obtain_mbx_lock_pf - obtain mailbox lock
+ *  @hw: pointer to the HW structure
+ *  @vf_number: the VF index
+ *
+ *  return SUCCESS if we obtained the mailbox lock
+ **/
+static s32 ixgbe_obtain_mbx_lock_pf(struct ixgbe_hw *hw, u16 vf_number)
+{
+       s32 ret_val = IXGBE_ERR_MBX;
+       u32 p2v_mailbox;
+
+       /* Take ownership of the buffer */
+       IXGBE_WRITE_REG(hw, IXGBE_PFMAILBOX(vf_number), IXGBE_PFMAILBOX_PFU);
+
+       /* reserve mailbox for vf use */
+       p2v_mailbox = IXGBE_READ_REG(hw, IXGBE_PFMAILBOX(vf_number));
+       if (p2v_mailbox & IXGBE_PFMAILBOX_PFU)
+               ret_val = 0;
+
+       return ret_val;
+}
+
+/**
+ *  ixgbe_write_mbx_pf - Places a message in the mailbox
+ *  @hw: pointer to the HW structure
+ *  @msg: The message buffer
+ *  @size: Length of buffer
+ *  @vf_number: the VF index
+ *
+ *  returns SUCCESS if it successfully copied message into the buffer
+ **/
+static s32 ixgbe_write_mbx_pf(struct ixgbe_hw *hw, u32 *msg, u16 size,
+                              u16 vf_number)
+{
+       s32 ret_val;
+       u16 i;
+
+       /* lock the mailbox to prevent pf/vf race condition */
+       ret_val = ixgbe_obtain_mbx_lock_pf(hw, vf_number);
+       if (ret_val)
+               goto out_no_write;
+
+       /* flush msg and acks as we are overwriting the message buffer */
+       ixgbe_check_for_msg_pf(hw, vf_number);
+       ixgbe_check_for_ack_pf(hw, vf_number);
+
+       /* copy the caller specified message to the mailbox memory buffer */
+       for (i = 0; i < size; i++)
+               IXGBE_WRITE_REG_ARRAY(hw, IXGBE_PFMBMEM(vf_number), i, msg[i]);
+
+       /* Interrupt VF to tell it a message has been sent and release buffer*/
+       IXGBE_WRITE_REG(hw, IXGBE_PFMAILBOX(vf_number), IXGBE_PFMAILBOX_STS);
+
+       /* update stats */
+       hw->mbx.stats.msgs_tx++;
+
+out_no_write:
+       return ret_val;
+
+}
+
+/**
+ *  ixgbe_read_mbx_pf - Read a message from the mailbox
+ *  @hw: pointer to the HW structure
+ *  @msg: The message buffer
+ *  @size: Length of buffer
+ *  @vf_number: the VF index
+ *
+ *  This function copies a message from the mailbox buffer to the caller's
+ *  memory buffer.  The presumption is that the caller knows that there was
+ *  a message due to a VF request so no polling for message is needed.
+ **/
+static s32 ixgbe_read_mbx_pf(struct ixgbe_hw *hw, u32 *msg, u16 size,
+                             u16 vf_number)
+{
+       s32 ret_val;
+       u16 i;
+
+       /* lock the mailbox to prevent pf/vf race condition */
+       ret_val = ixgbe_obtain_mbx_lock_pf(hw, vf_number);
+       if (ret_val)
+               goto out_no_read;
+
+       /* copy the message to the mailbox memory buffer */
+       for (i = 0; i < size; i++)
+               msg[i] = IXGBE_READ_REG_ARRAY(hw, IXGBE_PFMBMEM(vf_number), i);
+
+       /* Acknowledge the message and release buffer */
+       IXGBE_WRITE_REG(hw, IXGBE_PFMAILBOX(vf_number), IXGBE_PFMAILBOX_ACK);
+
+       /* update stats */
+       hw->mbx.stats.msgs_rx++;
+
+out_no_read:
+       return ret_val;
+}
+
+/**
+ *  ixgbe_init_mbx_params_pf - set initial values for pf mailbox
+ *  @hw: pointer to the HW structure
+ *
+ *  Initializes the hw->mbx struct to correct values for pf mailbox
+ */
+void ixgbe_init_mbx_params_pf(struct ixgbe_hw *hw)
+{
+       struct ixgbe_mbx_info *mbx = &hw->mbx;
+
+       if (hw->mac.type != ixgbe_mac_82599EB)
+               return;
+
+       mbx->timeout = 0;
+       mbx->usec_delay = 0;
+
+       mbx->size = IXGBE_VFMAILBOX_SIZE;
+
+       mbx->stats.msgs_tx = 0;
+       mbx->stats.msgs_rx = 0;
+       mbx->stats.reqs = 0;
+       mbx->stats.acks = 0;
+       mbx->stats.rsts = 0;
+}
+
+struct ixgbe_mbx_operations mbx_ops_82599 = {
+       .read                   = ixgbe_read_mbx_pf,
+       .write                  = ixgbe_write_mbx_pf,
+       .read_posted            = ixgbe_read_posted_mbx,
+       .write_posted           = ixgbe_write_posted_mbx,
+       .check_for_msg          = ixgbe_check_for_msg_pf,
+       .check_for_ack          = ixgbe_check_for_ack_pf,
+       .check_for_rst          = ixgbe_check_for_rst_pf,
+};
+
diff --git a/drivers/net/ixgbe/ixgbe_mbx.h b/drivers/net/ixgbe/ixgbe_mbx.h
new file mode 100644 (file)
index 0000000..be7ab33
--- /dev/null
@@ -0,0 +1,96 @@
+/*******************************************************************************
+
+  Intel 10 Gigabit PCI Express Linux driver
+  Copyright(c) 1999 - 2009 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _IXGBE_MBX_H_
+#define _IXGBE_MBX_H_
+
+#include "ixgbe_type.h"
+
+#define IXGBE_VFMAILBOX_SIZE        16 /* 16 32 bit words - 64 bytes */
+#define IXGBE_ERR_MBX               -100
+
+#define IXGBE_VFMAILBOX             0x002FC
+#define IXGBE_VFMBMEM               0x00200
+
+#define IXGBE_PFMAILBOX(x)          (0x04B00 + (4 * x))
+#define IXGBE_PFMBMEM(vfn)          (0x13000 + (64 * vfn))
+
+#define IXGBE_PFMAILBOX_STS   0x00000001 /* Initiate message send to VF */
+#define IXGBE_PFMAILBOX_ACK   0x00000002 /* Ack message recv'd from VF */
+#define IXGBE_PFMAILBOX_VFU   0x00000004 /* VF owns the mailbox buffer */
+#define IXGBE_PFMAILBOX_PFU   0x00000008 /* PF owns the mailbox buffer */
+#define IXGBE_PFMAILBOX_RVFU  0x00000010 /* Reset VFU - used when VF stuck */
+
+#define IXGBE_MBVFICR_VFREQ_MASK 0x0000FFFF /* bits for VF messages */
+#define IXGBE_MBVFICR_VFREQ_VF1  0x00000001 /* bit for VF 1 message */
+#define IXGBE_MBVFICR_VFACK_MASK 0xFFFF0000 /* bits for VF acks */
+#define IXGBE_MBVFICR_VFACK_VF1  0x00010000 /* bit for VF 1 ack */
+
+
+/* If it's a IXGBE_VF_* msg then it originates in the VF and is sent to the
+ * PF.  The reverse is true if it is IXGBE_PF_*.
+ * Message ACK's are the value or'd with 0xF0000000
+ */
+#define IXGBE_VT_MSGTYPE_ACK      0x80000000  /* Messages below or'd with
+                                               * this are the ACK */
+#define IXGBE_VT_MSGTYPE_NACK     0x40000000  /* Messages below or'd with
+                                               * this are the NACK */
+#define IXGBE_VT_MSGTYPE_CTS      0x20000000  /* Indicates that VF is still
+                                                 clear to send requests */
+#define IXGBE_VT_MSGINFO_SHIFT    16
+/* bits 23:16 are used for exra info for certain messages */
+#define IXGBE_VT_MSGINFO_MASK     (0xFF << IXGBE_VT_MSGINFO_SHIFT)
+
+#define IXGBE_VF_RESET            0x01 /* VF requests reset */
+#define IXGBE_VF_SET_MAC_ADDR     0x02 /* VF requests PF to set MAC addr */
+#define IXGBE_VF_SET_MULTICAST    0x03 /* VF requests PF to set MC addr */
+#define IXGBE_VF_SET_VLAN         0x04 /* VF requests PF to set VLAN */
+#define IXGBE_VF_SET_LPE          0x05 /* VF requests PF to set VMOLR.LPE */
+
+/* length of permanent address message returned from PF */
+#define IXGBE_VF_PERMADDR_MSG_LEN 4
+/* word in permanent address message with the current multicast type */
+#define IXGBE_VF_MC_TYPE_WORD     3
+
+#define IXGBE_PF_CONTROL_MSG      0x0100 /* PF control message */
+
+#define IXGBE_VF_MBX_INIT_TIMEOUT 2000 /* number of retries on mailbox */
+#define IXGBE_VF_MBX_INIT_DELAY   500  /* microseconds between retries */
+
+s32 ixgbe_read_mbx(struct ixgbe_hw *, u32 *, u16, u16);
+s32 ixgbe_write_mbx(struct ixgbe_hw *, u32 *, u16, u16);
+s32 ixgbe_read_posted_mbx(struct ixgbe_hw *, u32 *, u16, u16);
+s32 ixgbe_write_posted_mbx(struct ixgbe_hw *, u32 *, u16, u16);
+s32 ixgbe_check_for_msg(struct ixgbe_hw *, u16);
+s32 ixgbe_check_for_ack(struct ixgbe_hw *, u16);
+s32 ixgbe_check_for_rst(struct ixgbe_hw *, u16);
+void ixgbe_init_mbx_ops_generic(struct ixgbe_hw *hw);
+void ixgbe_init_mbx_params_pf(struct ixgbe_hw *);
+
+extern struct ixgbe_mbx_operations mbx_ops_82599;
+
+#endif /* _IXGBE_MBX_H_ */
diff --git a/drivers/net/ixgbe/ixgbe_sriov.c b/drivers/net/ixgbe/ixgbe_sriov.c
new file mode 100644 (file)
index 0000000..d4cd20f
--- /dev/null
@@ -0,0 +1,362 @@
+/*******************************************************************************
+
+  Intel 10 Gigabit PCI Express Linux driver
+  Copyright(c) 1999 - 2009 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/vmalloc.h>
+#include <linux/string.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/ipv6.h>
+#ifdef NETIF_F_HW_VLAN_TX
+#include <linux/if_vlan.h>
+#endif
+
+#include "ixgbe.h"
+
+#include "ixgbe_sriov.h"
+
+int ixgbe_set_vf_multicasts(struct ixgbe_adapter *adapter,
+                           int entries, u16 *hash_list, u32 vf)
+{
+       struct vf_data_storage *vfinfo = &adapter->vfinfo[vf];
+       int i;
+
+       /* only so many hash values supported */
+       entries = min(entries, IXGBE_MAX_VF_MC_ENTRIES);
+
+       /*
+        * salt away the number of multi cast addresses assigned
+        * to this VF for later use to restore when the PF multi cast
+        * list changes
+        */
+       vfinfo->num_vf_mc_hashes = entries;
+
+       /*
+        * VFs are limited to using the MTA hash table for their multicast
+        * addresses
+        */
+       for (i = 0; i < entries; i++) {
+               vfinfo->vf_mc_hashes[i] = hash_list[i];;
+       }
+
+       /* Flush and reset the mta with the new values */
+       ixgbe_set_rx_mode(adapter->netdev);
+
+       return 0;
+}
+
+void ixgbe_restore_vf_multicasts(struct ixgbe_adapter *adapter)
+{
+       struct ixgbe_hw *hw = &adapter->hw;
+       struct vf_data_storage *vfinfo;
+       int i, j;
+       u32 vector_bit;
+       u32 vector_reg;
+       u32 mta_reg;
+
+       for (i = 0; i < adapter->num_vfs; i++) {
+               vfinfo = &adapter->vfinfo[i];
+               for (j = 0; j < vfinfo->num_vf_mc_hashes; j++) {
+                       hw->addr_ctrl.mta_in_use++;
+                       vector_reg = (vfinfo->vf_mc_hashes[j] >> 5) & 0x7F;
+                       vector_bit = vfinfo->vf_mc_hashes[j] & 0x1F;
+                       mta_reg = IXGBE_READ_REG(hw, IXGBE_MTA(vector_reg));
+                       mta_reg |= (1 << vector_bit);
+                       IXGBE_WRITE_REG(hw, IXGBE_MTA(vector_reg), mta_reg);
+               }
+       }
+}
+
+int ixgbe_set_vf_vlan(struct ixgbe_adapter *adapter, int add, int vid, u32 vf)
+{
+       u32 ctrl;
+
+       /* Check if global VLAN already set, if not set it */
+       ctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_VLNCTRL);
+       if (!(ctrl & IXGBE_VLNCTRL_VFE)) {
+               /* enable VLAN tag insert/strip */
+               ctrl |= IXGBE_VLNCTRL_VFE;
+               ctrl &= ~IXGBE_VLNCTRL_CFIEN;
+               IXGBE_WRITE_REG(&adapter->hw, IXGBE_VLNCTRL, ctrl);
+       }
+
+       return adapter->hw.mac.ops.set_vfta(&adapter->hw, vid, vf, (bool)add);
+}
+
+
+void ixgbe_set_vmolr(struct ixgbe_hw *hw, u32 vf)
+{
+       u32 vmolr = IXGBE_READ_REG(hw, IXGBE_VMOLR(vf));
+       vmolr |= (IXGBE_VMOLR_AUPE |
+                 IXGBE_VMOLR_ROMPE |
+                 IXGBE_VMOLR_ROPE |
+                 IXGBE_VMOLR_BAM);
+       IXGBE_WRITE_REG(hw, IXGBE_VMOLR(vf), vmolr);
+}
+
+inline void ixgbe_vf_reset_event(struct ixgbe_adapter *adapter, u32 vf)
+{
+       struct ixgbe_hw *hw = &adapter->hw;
+
+       /* reset offloads to defaults */
+       ixgbe_set_vmolr(hw, vf);
+
+
+       /* reset multicast table array for vf */
+       adapter->vfinfo[vf].num_vf_mc_hashes = 0;
+
+       /* Flush and reset the mta with the new values */
+       ixgbe_set_rx_mode(adapter->netdev);
+
+       if (adapter->vfinfo[vf].rar > 0) {
+               adapter->hw.mac.ops.clear_rar(&adapter->hw,
+                                             adapter->vfinfo[vf].rar);
+               adapter->vfinfo[vf].rar = -1;
+       }
+}
+
+int ixgbe_set_vf_mac(struct ixgbe_adapter *adapter,
+                          int vf, unsigned char *mac_addr)
+{
+       struct ixgbe_hw *hw = &adapter->hw;
+
+       adapter->vfinfo[vf].rar = hw->mac.ops.set_rar(hw, vf + 1, mac_addr,
+                                                     vf, IXGBE_RAH_AV);
+       if (adapter->vfinfo[vf].rar < 0) {
+               DPRINTK(DRV, ERR, "Could not set MAC Filter for VF %d\n", vf);
+               return -1;
+       }
+
+       memcpy(adapter->vfinfo[vf].vf_mac_addresses, mac_addr, 6);
+
+       return 0;
+}
+
+int ixgbe_vf_configuration(struct pci_dev *pdev, unsigned int event_mask)
+{
+       unsigned char vf_mac_addr[6];
+       struct net_device *netdev = pci_get_drvdata(pdev);
+       struct ixgbe_adapter *adapter = netdev_priv(netdev);
+       unsigned int vfn = (event_mask & 0x3f);
+
+       bool enable = ((event_mask & 0x10000000U) != 0);
+
+       if (enable) {
+               random_ether_addr(vf_mac_addr);
+               DPRINTK(PROBE, INFO, "IOV: VF %d is enabled "
+                      "mac %02X:%02X:%02X:%02X:%02X:%02X\n",
+                      vfn,
+                      vf_mac_addr[0], vf_mac_addr[1], vf_mac_addr[2],
+                      vf_mac_addr[3], vf_mac_addr[4], vf_mac_addr[5]);
+               /*
+                * Store away the VF "permananet" MAC address, it will ask
+                * for it later.
+                */
+               memcpy(adapter->vfinfo[vfn].vf_mac_addresses, vf_mac_addr, 6);
+       }
+
+       return 0;
+}
+
+inline void ixgbe_vf_reset_msg(struct ixgbe_adapter *adapter, u32 vf)
+{
+       struct ixgbe_hw *hw = &adapter->hw;
+       u32 reg;
+       u32 reg_offset, vf_shift;
+
+       vf_shift = vf % 32;
+       reg_offset = vf / 32;
+
+       /* enable transmit and receive for vf */
+       reg = IXGBE_READ_REG(hw, IXGBE_VFTE(reg_offset));
+       reg |= (reg | (1 << vf_shift));
+       IXGBE_WRITE_REG(hw, IXGBE_VFTE(reg_offset), reg);
+
+       reg = IXGBE_READ_REG(hw, IXGBE_VFRE(reg_offset));
+       reg |= (reg | (1 << vf_shift));
+       IXGBE_WRITE_REG(hw, IXGBE_VFRE(reg_offset), reg);
+
+       ixgbe_vf_reset_event(adapter, vf);
+}
+
+static int ixgbe_rcv_msg_from_vf(struct ixgbe_adapter *adapter, u32 vf)
+{
+       u32 mbx_size = IXGBE_VFMAILBOX_SIZE;
+       u32 msgbuf[mbx_size];
+       struct ixgbe_hw *hw = &adapter->hw;
+       s32 retval;
+       int entries;
+       u16 *hash_list;
+       int add, vid;
+
+       retval = ixgbe_read_mbx(hw, msgbuf, mbx_size, vf);
+
+       if (retval)
+               printk(KERN_ERR "Error receiving message from VF\n");
+
+       /* this is a message we already processed, do nothing */
+       if (msgbuf[0] & (IXGBE_VT_MSGTYPE_ACK | IXGBE_VT_MSGTYPE_NACK))
+               return retval;
+
+       /*
+        * until the vf completes a virtual function reset it should not be
+        * allowed to start any configuration.
+        */
+
+       if (msgbuf[0] == IXGBE_VF_RESET) {
+               unsigned char *vf_mac = adapter->vfinfo[vf].vf_mac_addresses;
+               u8 *addr = (u8 *)(&msgbuf[1]);
+               DPRINTK(PROBE, INFO, "VF Reset msg received from vf %d\n", vf);
+               adapter->vfinfo[vf].clear_to_send = false;
+               ixgbe_vf_reset_msg(adapter, vf);
+               adapter->vfinfo[vf].clear_to_send = true;
+
+               /* reply to reset with ack and vf mac address */
+               msgbuf[0] = IXGBE_VF_RESET | IXGBE_VT_MSGTYPE_ACK;
+               memcpy(addr, vf_mac, IXGBE_ETH_LENGTH_OF_ADDRESS);
+               /*
+                * Piggyback the multicast filter type so VF can compute the
+                * correct vectors
+                */
+               msgbuf[3] = hw->mac.mc_filter_type;
+               ixgbe_write_mbx(hw, msgbuf, IXGBE_VF_PERMADDR_MSG_LEN, vf);
+
+               return retval;
+       }
+
+       if (!adapter->vfinfo[vf].clear_to_send) {
+               msgbuf[0] |= IXGBE_VT_MSGTYPE_NACK;
+               ixgbe_write_mbx(hw, msgbuf, 1, vf);
+               return retval;
+       }
+
+       switch ((msgbuf[0] & 0xFFFF)) {
+       case IXGBE_VF_SET_MAC_ADDR:
+               {
+                       u8 *new_mac = ((u8 *)(&msgbuf[1]));
+                       if (is_valid_ether_addr(new_mac))
+                               ixgbe_set_vf_mac(adapter, vf, new_mac);
+                       else
+                               retval = -1;
+               }
+               break;
+       case IXGBE_VF_SET_MULTICAST:
+               entries = (msgbuf[0] & IXGBE_VT_MSGINFO_MASK)
+                         >> IXGBE_VT_MSGINFO_SHIFT;
+               hash_list = (u16 *)&msgbuf[1];
+               retval = ixgbe_set_vf_multicasts(adapter, entries,
+                                                hash_list, vf);
+               break;
+       case IXGBE_VF_SET_LPE:
+               WARN_ON((msgbuf[0] & 0xFFFF) == IXGBE_VF_SET_LPE);
+               break;
+       case IXGBE_VF_SET_VLAN:
+               add = (msgbuf[0] & IXGBE_VT_MSGINFO_MASK)
+                     >> IXGBE_VT_MSGINFO_SHIFT;
+               vid = (msgbuf[1] & IXGBE_VLVF_VLANID_MASK);
+               retval = ixgbe_set_vf_vlan(adapter, add, vid, vf);
+               break;
+       default:
+               DPRINTK(DRV, ERR, "Unhandled Msg %8.8x\n", msgbuf[0]);
+               retval = IXGBE_ERR_MBX;
+               break;
+       }
+
+       /* notify the VF of the results of what it sent us */
+       if (retval)
+               msgbuf[0] |= IXGBE_VT_MSGTYPE_NACK;
+       else
+               msgbuf[0] |= IXGBE_VT_MSGTYPE_ACK;
+
+       msgbuf[0] |= IXGBE_VT_MSGTYPE_CTS;
+
+       ixgbe_write_mbx(hw, msgbuf, 1, vf);
+
+       return retval;
+}
+
+static void ixgbe_rcv_ack_from_vf(struct ixgbe_adapter *adapter, u32 vf)
+{
+       struct ixgbe_hw *hw = &adapter->hw;
+       u32 msg = IXGBE_VT_MSGTYPE_NACK;
+
+       /* if device isn't clear to send it shouldn't be reading either */
+       if (!adapter->vfinfo[vf].clear_to_send)
+               ixgbe_write_mbx(hw, &msg, 1, vf);
+}
+
+void ixgbe_msg_task(struct ixgbe_adapter *adapter)
+{
+       struct ixgbe_hw *hw = &adapter->hw;
+       u32 vf;
+
+       for (vf = 0; vf < adapter->num_vfs; vf++) {
+               /* process any reset requests */
+               if (!ixgbe_check_for_rst(hw, vf))
+                       ixgbe_vf_reset_event(adapter, vf);
+
+               /* process any messages pending */
+               if (!ixgbe_check_for_msg(hw, vf))
+                       ixgbe_rcv_msg_from_vf(adapter, vf);
+
+               /* process any acks */
+               if (!ixgbe_check_for_ack(hw, vf))
+                       ixgbe_rcv_ack_from_vf(adapter, vf);
+       }
+}
+
+void ixgbe_disable_tx_rx(struct ixgbe_adapter *adapter)
+{
+       struct ixgbe_hw *hw = &adapter->hw;
+
+       /* disable transmit and receive for all vfs */
+       IXGBE_WRITE_REG(hw, IXGBE_VFTE(0), 0);
+       IXGBE_WRITE_REG(hw, IXGBE_VFTE(1), 0);
+
+       IXGBE_WRITE_REG(hw, IXGBE_VFRE(0), 0);
+       IXGBE_WRITE_REG(hw, IXGBE_VFRE(1), 0);
+}
+
+void ixgbe_ping_all_vfs(struct ixgbe_adapter *adapter)
+{
+       struct ixgbe_hw *hw = &adapter->hw;
+       u32 ping;
+       int i;
+
+       for (i = 0 ; i < adapter->num_vfs; i++) {
+               ping = IXGBE_PF_CONTROL_MSG;
+               if (adapter->vfinfo[i].clear_to_send)
+                       ping |= IXGBE_VT_MSGTYPE_CTS;
+               ixgbe_write_mbx(hw, &ping, 1, i);
+       }
+}
+
diff --git a/drivers/net/ixgbe/ixgbe_sriov.h b/drivers/net/ixgbe/ixgbe_sriov.h
new file mode 100644 (file)
index 0000000..51d1106
--- /dev/null
@@ -0,0 +1,47 @@
+/*******************************************************************************
+
+  Intel 10 Gigabit PCI Express Linux driver
+  Copyright(c) 1999 - 2009 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _IXGBE_SRIOV_H_
+#define _IXGBE_SRIOV_H_
+
+int ixgbe_set_vf_multicasts(struct ixgbe_adapter *adapter,
+                            int entries, u16 *hash_list, u32 vf);
+void ixgbe_restore_vf_multicasts(struct ixgbe_adapter *adapter);
+int ixgbe_set_vf_vlan(struct ixgbe_adapter *adapter, int add, int vid, u32 vf);
+void ixgbe_set_vmolr(struct ixgbe_hw *hw, u32 vf);
+void ixgbe_vf_reset_event(struct ixgbe_adapter *adapter, u32 vf);
+void ixgbe_vf_reset_msg(struct ixgbe_adapter *adapter, u32 vf);
+void ixgbe_msg_task(struct ixgbe_adapter *adapter);
+int ixgbe_set_vf_mac(struct ixgbe_adapter *adapter,
+                     int vf, unsigned char *mac_addr);
+int ixgbe_vf_configuration(struct pci_dev *pdev, unsigned int event_mask);
+void ixgbe_disable_tx_rx(struct ixgbe_adapter *adapter);
+void ixgbe_ping_all_vfs(struct ixgbe_adapter *adapter);
+void ixgbe_dump_registers(struct ixgbe_adapter *adapter);
+
+#endif /* _IXGBE_SRIOV_H_ */
+
index 9eafddfa1b97f82810e735ef40f4c8c3d9d46f62..0db67c19b2c458d6926ece5641a4b44c6161cdca 100644 (file)
@@ -30,7 +30,7 @@
 
 #include <linux/types.h>
 #include <linux/mdio.h>
-#include <linux/list.h>
+#include <linux/netdevice.h>
 
 /* Vendor ID */
 #define IXGBE_INTEL_VENDOR_ID   0x8086
 #define IXGBE_DTXCTL    0x07E00
 
 #define IXGBE_DMATXCTL  0x04A80
+#define IXGBE_PFDTXGSWC     0x08220
 #define IXGBE_DTXMXSZRQ     0x08100
 #define IXGBE_DTXTCPFLGL    0x04A88
 #define IXGBE_DTXTCPFLGH    0x04A8C
 #define IXGBE_DMATXCTL_NS       0x2 /* No Snoop LSO hdr buffer */
 #define IXGBE_DMATXCTL_GDV      0x8 /* Global Double VLAN */
 #define IXGBE_DMATXCTL_VT_SHIFT 16  /* VLAN EtherType */
+
+#define IXGBE_PFDTXGSWC_VT_LBEN 0x1 /* Local L2 VT switch enable */
 #define IXGBE_DCA_TXCTRL(_i)    (0x07200 + ((_i) * 4)) /* 16 of these (0-15) */
 /* Tx DCA Control register : 128 of these (0-127) */
 #define IXGBE_DCA_TXCTRL_82599(_i)  (0x0600C + ((_i) * 0x40))
 /* DCB registers */
 #define IXGBE_RTRPCS      0x02430
 #define IXGBE_RTTDCS      0x04900
+#define IXGBE_RTTDCS_ARBDIS     0x00000040 /* DCB arbiter disable */
 #define IXGBE_RTTPCS      0x0CD00
 #define IXGBE_RTRUP2TC    0x03020
 #define IXGBE_RTTUP2TC    0x0C800
 #define IXGBE_GCR_CMPL_TMOUT_RESEND     0x00010000
 #define IXGBE_GCR_CAP_VER2              0x00040000
 
+#define IXGBE_GCR_EXT_MSIX_EN           0x80000000
+#define IXGBE_GCR_EXT_VT_MODE_16        0x00000001
+#define IXGBE_GCR_EXT_VT_MODE_32        0x00000002
+#define IXGBE_GCR_EXT_VT_MODE_64        0x00000003
+#define IXGBE_GCR_EXT_SRIOV             (IXGBE_GCR_EXT_MSIX_EN | \
+                                         IXGBE_GCR_EXT_VT_MODE_64)
+
 /* Time Sync Registers */
 #define IXGBE_TSYNCRXCTL 0x05188 /* Rx Time Sync Control register - RW */
 #define IXGBE_TSYNCTXCTL 0x08C00 /* Tx Time Sync Control register - RW */
 /* VFRE bitmask */
 #define IXGBE_VFRE_ENABLE_ALL   0xFFFFFFFF
 
+#define IXGBE_VF_INIT_TIMEOUT   200 /* Number of retries to clear RSTI */
+
 /* RDHMPN and TDHMPN bitmasks */
 #define IXGBE_RDHMPN_RDICADDR       0x007FF800
 #define IXGBE_RDHMPN_RDICRDREQ      0x00800000
 /* VLAN pool filtering masks */
 #define IXGBE_VLVF_VIEN         0x80000000  /* filter is valid */
 #define IXGBE_VLVF_ENTRIES      64
+#define IXGBE_VLVF_VLANID_MASK  0x00000FFF
 
 #define IXGBE_ETHERNET_IEEE_VLAN_TYPE 0x8100  /* 802.1q protocol */
 
 #define IXGBE_RX_DESC_SPECIAL_PRI_SHIFT  0x000D /* Priority in upper 3 of 16 */
 #define IXGBE_TX_DESC_SPECIAL_PRI_SHIFT  IXGBE_RX_DESC_SPECIAL_PRI_SHIFT
 
+/* SR-IOV specific macros */
+#define IXGBE_MBVFICR_INDEX(vf_number)   (vf_number >> 4)
+#define IXGBE_MBVFICR(_i)                (0x00710 + (_i * 4))
+#define IXGBE_VFLRE(_i)                  (((_i & 1) ? 0x001C0 : 0x00600))
+#define IXGBE_VFLREC(_i)                 (0x00700 + (_i * 4))
+
 /* Little Endian defines */
 #ifndef __le32
 #define __le32  u32
@@ -2385,7 +2405,7 @@ struct ixgbe_mac_operations {
        s32 (*set_vmdq)(struct ixgbe_hw *, u32, u32);
        s32 (*clear_vmdq)(struct ixgbe_hw *, u32, u32);
        s32 (*init_rx_addrs)(struct ixgbe_hw *);
-       s32 (*update_uc_addr_list)(struct ixgbe_hw *, struct list_head *);
+       s32 (*update_uc_addr_list)(struct ixgbe_hw *, struct net_device *);
        s32 (*update_mc_addr_list)(struct ixgbe_hw *, u8 *, u32,
                                   ixgbe_mc_addr_itr);
        s32 (*enable_mc)(struct ixgbe_hw *);
@@ -2463,6 +2483,37 @@ struct ixgbe_phy_info {
        bool                            multispeed_fiber;
 };
 
+#include "ixgbe_mbx.h"
+
+struct ixgbe_mbx_operations {
+       s32 (*init_params)(struct ixgbe_hw *hw);
+       s32 (*read)(struct ixgbe_hw *, u32 *, u16,  u16);
+       s32 (*write)(struct ixgbe_hw *, u32 *, u16, u16);
+       s32 (*read_posted)(struct ixgbe_hw *, u32 *, u16,  u16);
+       s32 (*write_posted)(struct ixgbe_hw *, u32 *, u16, u16);
+       s32 (*check_for_msg)(struct ixgbe_hw *, u16);
+       s32 (*check_for_ack)(struct ixgbe_hw *, u16);
+       s32 (*check_for_rst)(struct ixgbe_hw *, u16);
+};
+
+struct ixgbe_mbx_stats {
+       u32 msgs_tx;
+       u32 msgs_rx;
+
+       u32 acks;
+       u32 reqs;
+       u32 rsts;
+};
+
+struct ixgbe_mbx_info {
+       struct ixgbe_mbx_operations ops;
+       struct ixgbe_mbx_stats stats;
+       u32 timeout;
+       u32 usec_delay;
+       u32 v2p_mailbox;
+       u16 size;
+};
+
 struct ixgbe_hw {
        u8 __iomem                      *hw_addr;
        void                            *back;
@@ -2472,6 +2523,7 @@ struct ixgbe_hw {
        struct ixgbe_phy_info           phy;
        struct ixgbe_eeprom_info        eeprom;
        struct ixgbe_bus_info           bus;
+       struct ixgbe_mbx_info           mbx;
        u16                             device_id;
        u16                             vendor_id;
        u16                             subsystem_device_id;
@@ -2486,6 +2538,7 @@ struct ixgbe_info {
        struct ixgbe_mac_operations     *mac_ops;
        struct ixgbe_eeprom_operations  *eeprom_ops;
        struct ixgbe_phy_operations     *phy_ops;
+       struct ixgbe_mbx_operations     *mbx_ops;
 };
 
 
diff --git a/drivers/net/ixgbevf/Makefile b/drivers/net/ixgbevf/Makefile
new file mode 100644 (file)
index 0000000..dd4e0d2
--- /dev/null
@@ -0,0 +1,38 @@
+################################################################################
+#
+# Intel 82599 Virtual Function driver
+# Copyright(c) 1999 - 2009 Intel Corporation.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms and conditions of the GNU General Public License,
+# version 2, as published by the Free Software Foundation.
+#
+# This program is distributed in the hope it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+# more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# The full GNU General Public License is included in this distribution in
+# the file called "COPYING".
+#
+# Contact Information:
+# e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+# Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+#
+################################################################################
+
+#
+# Makefile for the Intel(R) 82599 VF ethernet driver
+#
+
+obj-$(CONFIG_IXGBEVF) += ixgbevf.o
+
+ixgbevf-objs := vf.o \
+                mbx.o \
+                ethtool.o \
+                ixgbevf_main.o
+
diff --git a/drivers/net/ixgbevf/defines.h b/drivers/net/ixgbevf/defines.h
new file mode 100644 (file)
index 0000000..c44fdb0
--- /dev/null
@@ -0,0 +1,292 @@
+/*******************************************************************************
+
+  Intel 82599 Virtual Function driver
+  Copyright(c) 1999 - 2009 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _IXGBEVF_DEFINES_H_
+#define _IXGBEVF_DEFINES_H_
+
+/* Device IDs */
+#define IXGBE_DEV_ID_82599_VF           0x10ED
+
+#define IXGBE_VF_IRQ_CLEAR_MASK         7
+#define IXGBE_VF_MAX_TX_QUEUES          1
+#define IXGBE_VF_MAX_RX_QUEUES          1
+#define IXGBE_ETH_LENGTH_OF_ADDRESS     6
+
+/* Link speed */
+typedef u32 ixgbe_link_speed;
+#define IXGBE_LINK_SPEED_1GB_FULL       0x0020
+#define IXGBE_LINK_SPEED_10GB_FULL      0x0080
+
+#define IXGBE_CTRL_RST          0x04000000 /* Reset (SW) */
+#define IXGBE_RXDCTL_ENABLE     0x02000000 /* Enable specific Rx Queue */
+#define IXGBE_TXDCTL_ENABLE     0x02000000 /* Enable specific Tx Queue */
+#define IXGBE_LINKS_UP          0x40000000
+#define IXGBE_LINKS_SPEED       0x20000000
+
+/* Number of Transmit and Receive Descriptors must be a multiple of 8 */
+#define IXGBE_REQ_TX_DESCRIPTOR_MULTIPLE  8
+#define IXGBE_REQ_RX_DESCRIPTOR_MULTIPLE  8
+#define IXGBE_REQ_TX_BUFFER_GRANULARITY   1024
+
+/* Interrupt Vector Allocation Registers */
+#define IXGBE_IVAR_ALLOC_VAL    0x80 /* Interrupt Allocation valid */
+
+#define IXGBE_VF_INIT_TIMEOUT   200 /* Number of retries to clear RSTI */
+
+/* Receive Config masks */
+#define IXGBE_RXCTRL_RXEN       0x00000001  /* Enable Receiver */
+#define IXGBE_RXCTRL_DMBYPS     0x00000002  /* Descriptor Monitor Bypass */
+#define IXGBE_RXDCTL_ENABLE     0x02000000  /* Enable specific Rx Queue */
+#define IXGBE_RXDCTL_VME        0x40000000  /* VLAN mode enable */
+
+/* DCA Control */
+#define IXGBE_DCA_TXCTRL_TX_WB_RO_EN (1 << 11) /* Tx Desc writeback RO bit */
+
+/* PSRTYPE bit definitions */
+#define IXGBE_PSRTYPE_TCPHDR    0x00000010
+#define IXGBE_PSRTYPE_UDPHDR    0x00000020
+#define IXGBE_PSRTYPE_IPV4HDR   0x00000100
+#define IXGBE_PSRTYPE_IPV6HDR   0x00000200
+#define IXGBE_PSRTYPE_L2HDR     0x00001000
+
+/* SRRCTL bit definitions */
+#define IXGBE_SRRCTL_BSIZEPKT_SHIFT     10     /* so many KBs */
+#define IXGBE_SRRCTL_RDMTS_SHIFT        22
+#define IXGBE_SRRCTL_RDMTS_MASK         0x01C00000
+#define IXGBE_SRRCTL_DROP_EN            0x10000000
+#define IXGBE_SRRCTL_BSIZEPKT_MASK      0x0000007F
+#define IXGBE_SRRCTL_BSIZEHDR_MASK      0x00003F00
+#define IXGBE_SRRCTL_DESCTYPE_LEGACY    0x00000000
+#define IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF 0x02000000
+#define IXGBE_SRRCTL_DESCTYPE_HDR_SPLIT  0x04000000
+#define IXGBE_SRRCTL_DESCTYPE_HDR_REPLICATION_LARGE_PKT 0x08000000
+#define IXGBE_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS 0x0A000000
+#define IXGBE_SRRCTL_DESCTYPE_MASK      0x0E000000
+
+/* Receive Descriptor bit definitions */
+#define IXGBE_RXD_STAT_DD         0x01    /* Descriptor Done */
+#define IXGBE_RXD_STAT_EOP        0x02    /* End of Packet */
+#define IXGBE_RXD_STAT_FLM        0x04    /* FDir Match */
+#define IXGBE_RXD_STAT_VP         0x08    /* IEEE VLAN Packet */
+#define IXGBE_RXDADV_NEXTP_MASK   0x000FFFF0 /* Next Descriptor Index */
+#define IXGBE_RXDADV_NEXTP_SHIFT  0x00000004
+#define IXGBE_RXD_STAT_UDPCS      0x10    /* UDP xsum calculated */
+#define IXGBE_RXD_STAT_L4CS       0x20    /* L4 xsum calculated */
+#define IXGBE_RXD_STAT_IPCS       0x40    /* IP xsum calculated */
+#define IXGBE_RXD_STAT_PIF        0x80    /* passed in-exact filter */
+#define IXGBE_RXD_STAT_CRCV       0x100   /* Speculative CRC Valid */
+#define IXGBE_RXD_STAT_VEXT       0x200   /* 1st VLAN found */
+#define IXGBE_RXD_STAT_UDPV       0x400   /* Valid UDP checksum */
+#define IXGBE_RXD_STAT_DYNINT     0x800   /* Pkt caused INT via DYNINT */
+#define IXGBE_RXD_STAT_TS         0x10000 /* Time Stamp */
+#define IXGBE_RXD_STAT_SECP       0x20000 /* Security Processing */
+#define IXGBE_RXD_STAT_LB         0x40000 /* Loopback Status */
+#define IXGBE_RXD_STAT_ACK        0x8000  /* ACK Packet indication */
+#define IXGBE_RXD_ERR_CE          0x01    /* CRC Error */
+#define IXGBE_RXD_ERR_LE          0x02    /* Length Error */
+#define IXGBE_RXD_ERR_PE          0x08    /* Packet Error */
+#define IXGBE_RXD_ERR_OSE         0x10    /* Oversize Error */
+#define IXGBE_RXD_ERR_USE         0x20    /* Undersize Error */
+#define IXGBE_RXD_ERR_TCPE        0x40    /* TCP/UDP Checksum Error */
+#define IXGBE_RXD_ERR_IPE         0x80    /* IP Checksum Error */
+#define IXGBE_RXDADV_ERR_MASK     0xFFF00000 /* RDESC.ERRORS mask */
+#define IXGBE_RXDADV_ERR_SHIFT    20         /* RDESC.ERRORS shift */
+#define IXGBE_RXDADV_ERR_HBO      0x00800000 /*Header Buffer Overflow */
+#define IXGBE_RXDADV_ERR_CE       0x01000000 /* CRC Error */
+#define IXGBE_RXDADV_ERR_LE       0x02000000 /* Length Error */
+#define IXGBE_RXDADV_ERR_PE       0x08000000 /* Packet Error */
+#define IXGBE_RXDADV_ERR_OSE      0x10000000 /* Oversize Error */
+#define IXGBE_RXDADV_ERR_USE      0x20000000 /* Undersize Error */
+#define IXGBE_RXDADV_ERR_TCPE     0x40000000 /* TCP/UDP Checksum Error */
+#define IXGBE_RXDADV_ERR_IPE      0x80000000 /* IP Checksum Error */
+#define IXGBE_RXD_VLAN_ID_MASK    0x0FFF  /* VLAN ID is in lower 12 bits */
+#define IXGBE_RXD_PRI_MASK        0xE000  /* Priority is in upper 3 bits */
+#define IXGBE_RXD_PRI_SHIFT       13
+#define IXGBE_RXD_CFI_MASK        0x1000  /* CFI is bit 12 */
+#define IXGBE_RXD_CFI_SHIFT       12
+
+#define IXGBE_RXDADV_STAT_DD            IXGBE_RXD_STAT_DD  /* Done */
+#define IXGBE_RXDADV_STAT_EOP           IXGBE_RXD_STAT_EOP /* End of Packet */
+#define IXGBE_RXDADV_STAT_FLM           IXGBE_RXD_STAT_FLM /* FDir Match */
+#define IXGBE_RXDADV_STAT_VP            IXGBE_RXD_STAT_VP  /* IEEE VLAN Pkt */
+#define IXGBE_RXDADV_STAT_MASK          0x000FFFFF /* Stat/NEXTP: bit 0-19 */
+#define IXGBE_RXDADV_STAT_FCEOFS        0x00000040 /* FCoE EOF/SOF Stat */
+#define IXGBE_RXDADV_STAT_FCSTAT        0x00000030 /* FCoE Pkt Stat */
+#define IXGBE_RXDADV_STAT_FCSTAT_NOMTCH 0x00000000 /* 00: No Ctxt Match */
+#define IXGBE_RXDADV_STAT_FCSTAT_NODDP  0x00000010 /* 01: Ctxt w/o DDP */
+#define IXGBE_RXDADV_STAT_FCSTAT_FCPRSP 0x00000020 /* 10: Recv. FCP_RSP */
+#define IXGBE_RXDADV_STAT_FCSTAT_DDP    0x00000030 /* 11: Ctxt w/ DDP */
+
+#define IXGBE_RXDADV_RSSTYPE_MASK       0x0000000F
+#define IXGBE_RXDADV_PKTTYPE_MASK       0x0000FFF0
+#define IXGBE_RXDADV_PKTTYPE_MASK_EX    0x0001FFF0
+#define IXGBE_RXDADV_HDRBUFLEN_MASK     0x00007FE0
+#define IXGBE_RXDADV_RSCCNT_MASK        0x001E0000
+#define IXGBE_RXDADV_RSCCNT_SHIFT       17
+#define IXGBE_RXDADV_HDRBUFLEN_SHIFT    5
+#define IXGBE_RXDADV_SPLITHEADER_EN     0x00001000
+#define IXGBE_RXDADV_SPH                0x8000
+
+#define IXGBE_RXD_ERR_FRAME_ERR_MASK ( \
+                                     IXGBE_RXD_ERR_CE |  \
+                                     IXGBE_RXD_ERR_LE |  \
+                                     IXGBE_RXD_ERR_PE |  \
+                                     IXGBE_RXD_ERR_OSE | \
+                                     IXGBE_RXD_ERR_USE)
+
+#define IXGBE_RXDADV_ERR_FRAME_ERR_MASK ( \
+                                        IXGBE_RXDADV_ERR_CE |  \
+                                        IXGBE_RXDADV_ERR_LE |  \
+                                        IXGBE_RXDADV_ERR_PE |  \
+                                        IXGBE_RXDADV_ERR_OSE | \
+                                        IXGBE_RXDADV_ERR_USE)
+
+#define IXGBE_TXD_POPTS_IXSM 0x01       /* Insert IP checksum */
+#define IXGBE_TXD_POPTS_TXSM 0x02       /* Insert TCP/UDP checksum */
+#define IXGBE_TXD_CMD_EOP    0x01000000 /* End of Packet */
+#define IXGBE_TXD_CMD_IFCS   0x02000000 /* Insert FCS (Ethernet CRC) */
+#define IXGBE_TXD_CMD_IC     0x04000000 /* Insert Checksum */
+#define IXGBE_TXD_CMD_RS     0x08000000 /* Report Status */
+#define IXGBE_TXD_CMD_DEXT   0x20000000 /* Descriptor extension (0 = legacy) */
+#define IXGBE_TXD_CMD_VLE    0x40000000 /* Add VLAN tag */
+#define IXGBE_TXD_STAT_DD    0x00000001 /* Descriptor Done */
+
+/* Transmit Descriptor - Advanced */
+union ixgbe_adv_tx_desc {
+       struct {
+               __le64 buffer_addr;      /* Address of descriptor's data buf */
+               __le32 cmd_type_len;
+               __le32 olinfo_status;
+       } read;
+       struct {
+               __le64 rsvd;       /* Reserved */
+               __le32 nxtseq_seed;
+               __le32 status;
+       } wb;
+};
+
+/* Receive Descriptor - Advanced */
+union ixgbe_adv_rx_desc {
+       struct {
+               __le64 pkt_addr; /* Packet buffer address */
+               __le64 hdr_addr; /* Header buffer address */
+       } read;
+       struct {
+               struct {
+                       union {
+                               __le32 data;
+                               struct {
+                                       __le16 pkt_info; /* RSS, Pkt type */
+                                       __le16 hdr_info; /* Splithdr, hdrlen */
+                               } hs_rss;
+                       } lo_dword;
+                       union {
+                               __le32 rss; /* RSS Hash */
+                               struct {
+                                       __le16 ip_id; /* IP id */
+                                       __le16 csum; /* Packet Checksum */
+                               } csum_ip;
+                       } hi_dword;
+               } lower;
+               struct {
+                       __le32 status_error; /* ext status/error */
+                       __le16 length; /* Packet length */
+                       __le16 vlan; /* VLAN tag */
+               } upper;
+       } wb;  /* writeback */
+};
+
+/* Context descriptors */
+struct ixgbe_adv_tx_context_desc {
+       __le32 vlan_macip_lens;
+       __le32 seqnum_seed;
+       __le32 type_tucmd_mlhl;
+       __le32 mss_l4len_idx;
+};
+
+/* Adv Transmit Descriptor Config Masks */
+#define IXGBE_ADVTXD_DTYP_MASK  0x00F00000 /* DTYP mask */
+#define IXGBE_ADVTXD_DTYP_CTXT  0x00200000 /* Advanced Context Desc */
+#define IXGBE_ADVTXD_DTYP_DATA  0x00300000 /* Advanced Data Descriptor */
+#define IXGBE_ADVTXD_DCMD_EOP   IXGBE_TXD_CMD_EOP  /* End of Packet */
+#define IXGBE_ADVTXD_DCMD_IFCS  IXGBE_TXD_CMD_IFCS /* Insert FCS */
+#define IXGBE_ADVTXD_DCMD_RS    IXGBE_TXD_CMD_RS   /* Report Status */
+#define IXGBE_ADVTXD_DCMD_DEXT  IXGBE_TXD_CMD_DEXT /* Desc ext (1=Adv) */
+#define IXGBE_ADVTXD_DCMD_VLE   IXGBE_TXD_CMD_VLE  /* VLAN pkt enable */
+#define IXGBE_ADVTXD_DCMD_TSE   0x80000000 /* TCP Seg enable */
+#define IXGBE_ADVTXD_STAT_DD    IXGBE_TXD_STAT_DD  /* Descriptor Done */
+#define IXGBE_ADVTXD_TUCMD_IPV4      0x00000400  /* IP Packet Type: 1=IPv4 */
+#define IXGBE_ADVTXD_TUCMD_IPV6      0x00000000  /* IP Packet Type: 0=IPv6 */
+#define IXGBE_ADVTXD_TUCMD_L4T_UDP   0x00000000  /* L4 Packet TYPE of UDP */
+#define IXGBE_ADVTXD_TUCMD_L4T_TCP   0x00000800  /* L4 Packet TYPE of TCP */
+#define IXGBE_ADVTXD_TUCMD_L4T_SCTP  0x00001000  /* L4 Packet TYPE of SCTP */
+#define IXGBE_ADVTXD_IDX_SHIFT  4 /* Adv desc Index shift */
+#define IXGBE_ADVTXD_POPTS_SHIFT      8  /* Adv desc POPTS shift */
+#define IXGBE_ADVTXD_POPTS_IXSM (IXGBE_TXD_POPTS_IXSM << \
+                                IXGBE_ADVTXD_POPTS_SHIFT)
+#define IXGBE_ADVTXD_POPTS_TXSM (IXGBE_TXD_POPTS_TXSM << \
+                                IXGBE_ADVTXD_POPTS_SHIFT)
+#define IXGBE_ADVTXD_PAYLEN_SHIFT    14 /* Adv desc PAYLEN shift */
+#define IXGBE_ADVTXD_MACLEN_SHIFT    9  /* Adv ctxt desc mac len shift */
+#define IXGBE_ADVTXD_VLAN_SHIFT      16  /* Adv ctxt vlan tag shift */
+#define IXGBE_ADVTXD_L4LEN_SHIFT     8  /* Adv ctxt L4LEN shift */
+#define IXGBE_ADVTXD_MSS_SHIFT       16  /* Adv ctxt MSS shift */
+
+/* Interrupt register bitmasks */
+
+/* Extended Interrupt Cause Read */
+#define IXGBE_EICR_RTX_QUEUE    0x0000FFFF /* RTx Queue Interrupt */
+#define IXGBE_EICR_MAILBOX      0x00080000 /* VF to PF Mailbox Interrupt */
+#define IXGBE_EICR_OTHER        0x80000000 /* Interrupt Cause Active */
+
+/* Extended Interrupt Cause Set */
+#define IXGBE_EICS_RTX_QUEUE    IXGBE_EICR_RTX_QUEUE /* RTx Queue Interrupt */
+#define IXGBE_EICS_MAILBOX      IXGBE_EICR_MAILBOX   /* VF to PF Mailbox Int */
+#define IXGBE_EICS_OTHER        IXGBE_EICR_OTHER     /* INT Cause Active */
+
+/* Extended Interrupt Mask Set */
+#define IXGBE_EIMS_RTX_QUEUE    IXGBE_EICR_RTX_QUEUE /* RTx Queue Interrupt */
+#define IXGBE_EIMS_MAILBOX      IXGBE_EICR_MAILBOX   /* VF to PF Mailbox Int */
+#define IXGBE_EIMS_OTHER        IXGBE_EICR_OTHER     /* INT Cause Active */
+
+/* Extended Interrupt Mask Clear */
+#define IXGBE_EIMC_RTX_QUEUE    IXGBE_EICR_RTX_QUEUE /* RTx Queue Interrupt */
+#define IXGBE_EIMC_MAILBOX      IXGBE_EICR_MAILBOX   /* VF to PF Mailbox Int */
+#define IXGBE_EIMC_OTHER        IXGBE_EICR_OTHER     /* INT Cause Active */
+
+#define IXGBE_EIMS_ENABLE_MASK ( \
+                               IXGBE_EIMS_RTX_QUEUE       | \
+                               IXGBE_EIMS_MAILBOX         | \
+                               IXGBE_EIMS_OTHER)
+
+#define IXGBE_EITR_CNT_WDIS     0x80000000
+
+/* Error Codes */
+#define IXGBE_ERR_INVALID_MAC_ADDR              -1
+#define IXGBE_ERR_RESET_FAILED                  -2
+
+#endif /* _IXGBEVF_DEFINES_H_ */
diff --git a/drivers/net/ixgbevf/ethtool.c b/drivers/net/ixgbevf/ethtool.c
new file mode 100644 (file)
index 0000000..399be0c
--- /dev/null
@@ -0,0 +1,716 @@
+/*******************************************************************************
+
+  Intel 82599 Virtual Function driver
+  Copyright(c) 1999 - 2009 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+/* ethtool support for ixgbevf */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/ethtool.h>
+#include <linux/vmalloc.h>
+#include <linux/if_vlan.h>
+#include <linux/uaccess.h>
+
+#include "ixgbevf.h"
+
+#define IXGBE_ALL_RAR_ENTRIES 16
+
+#ifdef ETHTOOL_GSTATS
+struct ixgbe_stats {
+       char stat_string[ETH_GSTRING_LEN];
+       int sizeof_stat;
+       int stat_offset;
+       int base_stat_offset;
+};
+
+#define IXGBEVF_STAT(m, b)  sizeof(((struct ixgbevf_adapter *)0)->m), \
+                           offsetof(struct ixgbevf_adapter, m),      \
+                           offsetof(struct ixgbevf_adapter, b)
+static struct ixgbe_stats ixgbe_gstrings_stats[] = {
+       {"rx_packets", IXGBEVF_STAT(stats.vfgprc, stats.base_vfgprc)},
+       {"tx_packets", IXGBEVF_STAT(stats.vfgptc, stats.base_vfgptc)},
+       {"rx_bytes", IXGBEVF_STAT(stats.vfgorc, stats.base_vfgorc)},
+       {"tx_bytes", IXGBEVF_STAT(stats.vfgotc, stats.base_vfgotc)},
+       {"tx_busy", IXGBEVF_STAT(tx_busy, zero_base)},
+       {"multicast", IXGBEVF_STAT(stats.vfmprc, stats.base_vfmprc)},
+       {"rx_csum_offload_good", IXGBEVF_STAT(hw_csum_rx_good, zero_base)},
+       {"rx_csum_offload_errors", IXGBEVF_STAT(hw_csum_rx_error, zero_base)},
+       {"tx_csum_offload_ctxt", IXGBEVF_STAT(hw_csum_tx_good, zero_base)},
+       {"rx_header_split", IXGBEVF_STAT(rx_hdr_split, zero_base)},
+};
+
+#define IXGBE_QUEUE_STATS_LEN 0
+#define IXGBE_GLOBAL_STATS_LEN ARRAY_SIZE(ixgbe_gstrings_stats)
+
+#define IXGBEVF_STATS_LEN (IXGBE_GLOBAL_STATS_LEN + IXGBE_QUEUE_STATS_LEN)
+#endif /* ETHTOOL_GSTATS */
+#ifdef ETHTOOL_TEST
+static const char ixgbe_gstrings_test[][ETH_GSTRING_LEN] = {
+       "Register test  (offline)",
+       "Link test   (on/offline)"
+};
+#define IXGBE_TEST_LEN (sizeof(ixgbe_gstrings_test) / ETH_GSTRING_LEN)
+#endif /* ETHTOOL_TEST */
+
+static int ixgbevf_get_settings(struct net_device *netdev,
+                               struct ethtool_cmd *ecmd)
+{
+       struct ixgbevf_adapter *adapter = netdev_priv(netdev);
+       struct ixgbe_hw *hw = &adapter->hw;
+       u32 link_speed = 0;
+       bool link_up;
+
+       ecmd->supported = SUPPORTED_10000baseT_Full;
+       ecmd->autoneg = AUTONEG_DISABLE;
+       ecmd->transceiver = XCVR_DUMMY1;
+       ecmd->port = -1;
+
+       hw->mac.ops.check_link(hw, &link_speed, &link_up, false);
+
+       if (link_up) {
+               ecmd->speed = (link_speed == IXGBE_LINK_SPEED_10GB_FULL) ?
+                              SPEED_10000 : SPEED_1000;
+               ecmd->duplex = DUPLEX_FULL;
+       } else {
+               ecmd->speed = -1;
+               ecmd->duplex = -1;
+       }
+
+       return 0;
+}
+
+static u32 ixgbevf_get_rx_csum(struct net_device *netdev)
+{
+       struct ixgbevf_adapter *adapter = netdev_priv(netdev);
+       return adapter->flags & IXGBE_FLAG_RX_CSUM_ENABLED;
+}
+
+static int ixgbevf_set_rx_csum(struct net_device *netdev, u32 data)
+{
+       struct ixgbevf_adapter *adapter = netdev_priv(netdev);
+       if (data)
+               adapter->flags |= IXGBE_FLAG_RX_CSUM_ENABLED;
+       else
+               adapter->flags &= ~IXGBE_FLAG_RX_CSUM_ENABLED;
+
+       if (netif_running(netdev)) {
+               if (!adapter->dev_closed)
+                       ixgbevf_reinit_locked(adapter);
+       } else {
+               ixgbevf_reset(adapter);
+       }
+
+       return 0;
+}
+
+static int ixgbevf_set_tso(struct net_device *netdev, u32 data)
+{
+       if (data) {
+               netdev->features |= NETIF_F_TSO;
+               netdev->features |= NETIF_F_TSO6;
+       } else {
+               netif_tx_stop_all_queues(netdev);
+               netdev->features &= ~NETIF_F_TSO;
+               netdev->features &= ~NETIF_F_TSO6;
+               netif_tx_start_all_queues(netdev);
+       }
+       return 0;
+}
+
+static u32 ixgbevf_get_msglevel(struct net_device *netdev)
+{
+       struct ixgbevf_adapter *adapter = netdev_priv(netdev);
+       return adapter->msg_enable;
+}
+
+static void ixgbevf_set_msglevel(struct net_device *netdev, u32 data)
+{
+       struct ixgbevf_adapter *adapter = netdev_priv(netdev);
+       adapter->msg_enable = data;
+}
+
+#define IXGBE_GET_STAT(_A_, _R_) (_A_->stats._R_)
+
+static char *ixgbevf_reg_names[] = {
+       "IXGBE_VFCTRL",
+       "IXGBE_VFSTATUS",
+       "IXGBE_VFLINKS",
+       "IXGBE_VFRXMEMWRAP",
+       "IXGBE_VFRTIMER",
+       "IXGBE_VTEICR",
+       "IXGBE_VTEICS",
+       "IXGBE_VTEIMS",
+       "IXGBE_VTEIMC",
+       "IXGBE_VTEIAC",
+       "IXGBE_VTEIAM",
+       "IXGBE_VTEITR",
+       "IXGBE_VTIVAR",
+       "IXGBE_VTIVAR_MISC",
+       "IXGBE_VFRDBAL0",
+       "IXGBE_VFRDBAL1",
+       "IXGBE_VFRDBAH0",
+       "IXGBE_VFRDBAH1",
+       "IXGBE_VFRDLEN0",
+       "IXGBE_VFRDLEN1",
+       "IXGBE_VFRDH0",
+       "IXGBE_VFRDH1",
+       "IXGBE_VFRDT0",
+       "IXGBE_VFRDT1",
+       "IXGBE_VFRXDCTL0",
+       "IXGBE_VFRXDCTL1",
+       "IXGBE_VFSRRCTL0",
+       "IXGBE_VFSRRCTL1",
+       "IXGBE_VFPSRTYPE",
+       "IXGBE_VFTDBAL0",
+       "IXGBE_VFTDBAL1",
+       "IXGBE_VFTDBAH0",
+       "IXGBE_VFTDBAH1",
+       "IXGBE_VFTDLEN0",
+       "IXGBE_VFTDLEN1",
+       "IXGBE_VFTDH0",
+       "IXGBE_VFTDH1",
+       "IXGBE_VFTDT0",
+       "IXGBE_VFTDT1",
+       "IXGBE_VFTXDCTL0",
+       "IXGBE_VFTXDCTL1",
+       "IXGBE_VFTDWBAL0",
+       "IXGBE_VFTDWBAL1",
+       "IXGBE_VFTDWBAH0",
+       "IXGBE_VFTDWBAH1"
+};
+
+
+static int ixgbevf_get_regs_len(struct net_device *netdev)
+{
+       return (ARRAY_SIZE(ixgbevf_reg_names)) * sizeof(u32);
+}
+
+static void ixgbevf_get_regs(struct net_device *netdev,
+                            struct ethtool_regs *regs,
+                            void *p)
+{
+       struct ixgbevf_adapter *adapter = netdev_priv(netdev);
+       struct ixgbe_hw *hw = &adapter->hw;
+       u32 *regs_buff = p;
+       u32 regs_len = ixgbevf_get_regs_len(netdev);
+       u8 i;
+
+       memset(p, 0, regs_len);
+
+       regs->version = (1 << 24) | hw->revision_id << 16 | hw->device_id;
+
+       /* General Registers */
+       regs_buff[0] = IXGBE_READ_REG(hw, IXGBE_VFCTRL);
+       regs_buff[1] = IXGBE_READ_REG(hw, IXGBE_VFSTATUS);
+       regs_buff[2] = IXGBE_READ_REG(hw, IXGBE_VFLINKS);
+       regs_buff[3] = IXGBE_READ_REG(hw, IXGBE_VFRXMEMWRAP);
+       regs_buff[4] = IXGBE_READ_REG(hw, IXGBE_VFRTIMER);
+
+       /* Interrupt */
+       /* don't read EICR because it can clear interrupt causes, instead
+        * read EICS which is a shadow but doesn't clear EICR */
+       regs_buff[5] = IXGBE_READ_REG(hw, IXGBE_VTEICS);
+       regs_buff[6] = IXGBE_READ_REG(hw, IXGBE_VTEICS);
+       regs_buff[7] = IXGBE_READ_REG(hw, IXGBE_VTEIMS);
+       regs_buff[8] = IXGBE_READ_REG(hw, IXGBE_VTEIMC);
+       regs_buff[9] = IXGBE_READ_REG(hw, IXGBE_VTEIAC);
+       regs_buff[10] = IXGBE_READ_REG(hw, IXGBE_VTEIAM);
+       regs_buff[11] = IXGBE_READ_REG(hw, IXGBE_VTEITR(0));
+       regs_buff[12] = IXGBE_READ_REG(hw, IXGBE_VTIVAR(0));
+       regs_buff[13] = IXGBE_READ_REG(hw, IXGBE_VTIVAR_MISC);
+
+       /* Receive DMA */
+       for (i = 0; i < 2; i++)
+               regs_buff[14 + i] = IXGBE_READ_REG(hw, IXGBE_VFRDBAL(i));
+       for (i = 0; i < 2; i++)
+               regs_buff[16 + i] = IXGBE_READ_REG(hw, IXGBE_VFRDBAH(i));
+       for (i = 0; i < 2; i++)
+               regs_buff[18 + i] = IXGBE_READ_REG(hw, IXGBE_VFRDLEN(i));
+       for (i = 0; i < 2; i++)
+               regs_buff[20 + i] = IXGBE_READ_REG(hw, IXGBE_VFRDH(i));
+       for (i = 0; i < 2; i++)
+               regs_buff[22 + i] = IXGBE_READ_REG(hw, IXGBE_VFRDT(i));
+       for (i = 0; i < 2; i++)
+               regs_buff[24 + i] = IXGBE_READ_REG(hw, IXGBE_VFRXDCTL(i));
+       for (i = 0; i < 2; i++)
+               regs_buff[26 + i] = IXGBE_READ_REG(hw, IXGBE_VFSRRCTL(i));
+
+       /* Receive */
+       regs_buff[28] = IXGBE_READ_REG(hw, IXGBE_VFPSRTYPE);
+
+       /* Transmit */
+       for (i = 0; i < 2; i++)
+               regs_buff[29 + i] = IXGBE_READ_REG(hw, IXGBE_VFTDBAL(i));
+       for (i = 0; i < 2; i++)
+               regs_buff[31 + i] = IXGBE_READ_REG(hw, IXGBE_VFTDBAH(i));
+       for (i = 0; i < 2; i++)
+               regs_buff[33 + i] = IXGBE_READ_REG(hw, IXGBE_VFTDLEN(i));
+       for (i = 0; i < 2; i++)
+               regs_buff[35 + i] = IXGBE_READ_REG(hw, IXGBE_VFTDH(i));
+       for (i = 0; i < 2; i++)
+               regs_buff[37 + i] = IXGBE_READ_REG(hw, IXGBE_VFTDT(i));
+       for (i = 0; i < 2; i++)
+               regs_buff[39 + i] = IXGBE_READ_REG(hw, IXGBE_VFTXDCTL(i));
+       for (i = 0; i < 2; i++)
+               regs_buff[41 + i] = IXGBE_READ_REG(hw, IXGBE_VFTDWBAL(i));
+       for (i = 0; i < 2; i++)
+               regs_buff[43 + i] = IXGBE_READ_REG(hw, IXGBE_VFTDWBAH(i));
+
+       for (i = 0; i < ARRAY_SIZE(ixgbevf_reg_names); i++)
+               hw_dbg(hw, "%s\t%8.8x\n", ixgbevf_reg_names[i], regs_buff[i]);
+}
+
+static void ixgbevf_get_drvinfo(struct net_device *netdev,
+                               struct ethtool_drvinfo *drvinfo)
+{
+       struct ixgbevf_adapter *adapter = netdev_priv(netdev);
+
+       strlcpy(drvinfo->driver, ixgbevf_driver_name, 32);
+       strlcpy(drvinfo->version, ixgbevf_driver_version, 32);
+
+       strlcpy(drvinfo->fw_version, "N/A", 4);
+       strlcpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
+}
+
+static void ixgbevf_get_ringparam(struct net_device *netdev,
+                                 struct ethtool_ringparam *ring)
+{
+       struct ixgbevf_adapter *adapter = netdev_priv(netdev);
+       struct ixgbevf_ring *tx_ring = adapter->tx_ring;
+       struct ixgbevf_ring *rx_ring = adapter->rx_ring;
+
+       ring->rx_max_pending = IXGBEVF_MAX_RXD;
+       ring->tx_max_pending = IXGBEVF_MAX_TXD;
+       ring->rx_mini_max_pending = 0;
+       ring->rx_jumbo_max_pending = 0;
+       ring->rx_pending = rx_ring->count;
+       ring->tx_pending = tx_ring->count;
+       ring->rx_mini_pending = 0;
+       ring->rx_jumbo_pending = 0;
+}
+
+static int ixgbevf_set_ringparam(struct net_device *netdev,
+                                struct ethtool_ringparam *ring)
+{
+       struct ixgbevf_adapter *adapter = netdev_priv(netdev);
+       struct ixgbevf_ring *tx_ring = NULL, *rx_ring = NULL;
+       int i, err;
+       u32 new_rx_count, new_tx_count;
+       bool need_tx_update = false;
+       bool need_rx_update = false;
+
+       if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
+               return -EINVAL;
+
+       new_rx_count = max(ring->rx_pending, (u32)IXGBEVF_MIN_RXD);
+       new_rx_count = min(new_rx_count, (u32)IXGBEVF_MAX_RXD);
+       new_rx_count = ALIGN(new_rx_count, IXGBE_REQ_RX_DESCRIPTOR_MULTIPLE);
+
+       new_tx_count = max(ring->tx_pending, (u32)IXGBEVF_MIN_TXD);
+       new_tx_count = min(new_tx_count, (u32)IXGBEVF_MAX_TXD);
+       new_tx_count = ALIGN(new_tx_count, IXGBE_REQ_TX_DESCRIPTOR_MULTIPLE);
+
+       if ((new_tx_count == adapter->tx_ring->count) &&
+           (new_rx_count == adapter->rx_ring->count)) {
+               /* nothing to do */
+               return 0;
+       }
+
+       while (test_and_set_bit(__IXGBEVF_RESETTING, &adapter->state))
+               msleep(1);
+
+       if (new_tx_count != adapter->tx_ring_count) {
+               tx_ring = kcalloc(adapter->num_tx_queues,
+                                 sizeof(struct ixgbevf_ring), GFP_KERNEL);
+               if (!tx_ring) {
+                       err = -ENOMEM;
+                       goto err_setup;
+               }
+               memcpy(tx_ring, adapter->tx_ring,
+                      adapter->num_tx_queues * sizeof(struct ixgbevf_ring));
+               for (i = 0; i < adapter->num_tx_queues; i++) {
+                       tx_ring[i].count = new_tx_count;
+                       err = ixgbevf_setup_tx_resources(adapter,
+                                                        &tx_ring[i]);
+                       if (err) {
+                               while (i) {
+                                       i--;
+                                       ixgbevf_free_tx_resources(adapter,
+                                                                 &tx_ring[i]);
+                               }
+                               kfree(tx_ring);
+                               goto err_setup;
+                       }
+                       tx_ring[i].v_idx = adapter->tx_ring[i].v_idx;
+               }
+               need_tx_update = true;
+       }
+
+       if (new_rx_count != adapter->rx_ring_count) {
+               rx_ring = kcalloc(adapter->num_rx_queues,
+                                 sizeof(struct ixgbevf_ring), GFP_KERNEL);
+               if ((!rx_ring) && (need_tx_update)) {
+                       err = -ENOMEM;
+                       goto err_rx_setup;
+               }
+               memcpy(rx_ring, adapter->rx_ring,
+                      adapter->num_rx_queues * sizeof(struct ixgbevf_ring));
+               for (i = 0; i < adapter->num_rx_queues; i++) {
+                       rx_ring[i].count = new_rx_count;
+                       err = ixgbevf_setup_rx_resources(adapter,
+                                                        &rx_ring[i]);
+                       if (err) {
+                               while (i) {
+                                       i--;
+                                       ixgbevf_free_rx_resources(adapter,
+                                                                 &rx_ring[i]);
+                               }
+                               kfree(rx_ring);
+                               goto err_rx_setup;
+                       }
+                       rx_ring[i].v_idx = adapter->rx_ring[i].v_idx;
+               }
+               need_rx_update = true;
+       }
+
+err_rx_setup:
+       /* if rings need to be updated, here's the place to do it in one shot */
+       if (need_tx_update || need_rx_update) {
+               if (netif_running(netdev))
+                       ixgbevf_down(adapter);
+       }
+
+       /* tx */
+       if (need_tx_update) {
+               kfree(adapter->tx_ring);
+               adapter->tx_ring = tx_ring;
+               tx_ring = NULL;
+               adapter->tx_ring_count = new_tx_count;
+       }
+
+       /* rx */
+       if (need_rx_update) {
+               kfree(adapter->rx_ring);
+               adapter->rx_ring = rx_ring;
+               rx_ring = NULL;
+               adapter->rx_ring_count = new_rx_count;
+       }
+
+       /* success! */
+       err = 0;
+       if (netif_running(netdev))
+               ixgbevf_up(adapter);
+
+err_setup:
+       clear_bit(__IXGBEVF_RESETTING, &adapter->state);
+       return err;
+}
+
+static int ixgbevf_get_sset_count(struct net_device *dev, int stringset)
+{
+       switch (stringset) {
+       case ETH_SS_TEST:
+              return IXGBE_TEST_LEN;
+       case ETH_SS_STATS:
+              return IXGBE_GLOBAL_STATS_LEN;
+       default:
+              return -EINVAL;
+       }
+}
+
+static void ixgbevf_get_ethtool_stats(struct net_device *netdev,
+                                     struct ethtool_stats *stats, u64 *data)
+{
+       struct ixgbevf_adapter *adapter = netdev_priv(netdev);
+       int i;
+
+       ixgbevf_update_stats(adapter);
+       for (i = 0; i < IXGBE_GLOBAL_STATS_LEN; i++) {
+               char *p = (char *)adapter +
+                       ixgbe_gstrings_stats[i].stat_offset;
+               char *b = (char *)adapter +
+                       ixgbe_gstrings_stats[i].base_stat_offset;
+               data[i] = ((ixgbe_gstrings_stats[i].sizeof_stat ==
+                           sizeof(u64)) ? *(u64 *)p : *(u32 *)p) -
+                         ((ixgbe_gstrings_stats[i].sizeof_stat ==
+                           sizeof(u64)) ? *(u64 *)b : *(u32 *)b);
+       }
+}
+
+static void ixgbevf_get_strings(struct net_device *netdev, u32 stringset,
+                               u8 *data)
+{
+       char *p = (char *)data;
+       int i;
+
+       switch (stringset) {
+       case ETH_SS_TEST:
+               memcpy(data, *ixgbe_gstrings_test,
+                      IXGBE_TEST_LEN * ETH_GSTRING_LEN);
+               break;
+       case ETH_SS_STATS:
+               for (i = 0; i < IXGBE_GLOBAL_STATS_LEN; i++) {
+                       memcpy(p, ixgbe_gstrings_stats[i].stat_string,
+                              ETH_GSTRING_LEN);
+                       p += ETH_GSTRING_LEN;
+               }
+               break;
+       }
+}
+
+static int ixgbevf_link_test(struct ixgbevf_adapter *adapter, u64 *data)
+{
+       struct ixgbe_hw *hw = &adapter->hw;
+       bool link_up;
+       u32 link_speed = 0;
+       *data = 0;
+
+       hw->mac.ops.check_link(hw, &link_speed, &link_up, true);
+       if (!link_up)
+               *data = 1;
+
+       return *data;
+}
+
+/* ethtool register test data */
+struct ixgbevf_reg_test {
+       u16 reg;
+       u8  array_len;
+       u8  test_type;
+       u32 mask;
+       u32 write;
+};
+
+/* In the hardware, registers are laid out either singly, in arrays
+ * spaced 0x40 bytes apart, or in contiguous tables.  We assume
+ * most tests take place on arrays or single registers (handled
+ * as a single-element array) and special-case the tables.
+ * Table tests are always pattern tests.
+ *
+ * We also make provision for some required setup steps by specifying
+ * registers to be written without any read-back testing.
+ */
+
+#define PATTERN_TEST   1
+#define SET_READ_TEST  2
+#define WRITE_NO_TEST  3
+#define TABLE32_TEST   4
+#define TABLE64_TEST_LO        5
+#define TABLE64_TEST_HI        6
+
+/* default VF register test */
+static struct ixgbevf_reg_test reg_test_vf[] = {
+       { IXGBE_VFRDBAL(0), 2, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFF80 },
+       { IXGBE_VFRDBAH(0), 2, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
+       { IXGBE_VFRDLEN(0), 2, PATTERN_TEST, 0x000FFF80, 0x000FFFFF },
+       { IXGBE_VFRXDCTL(0), 2, WRITE_NO_TEST, 0, IXGBE_RXDCTL_ENABLE },
+       { IXGBE_VFRDT(0), 2, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF },
+       { IXGBE_VFRXDCTL(0), 2, WRITE_NO_TEST, 0, 0 },
+       { IXGBE_VFTDBAL(0), 2, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF },
+       { IXGBE_VFTDBAH(0), 2, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
+       { IXGBE_VFTDLEN(0), 2, PATTERN_TEST, 0x000FFF80, 0x000FFF80 },
+       { 0, 0, 0, 0 }
+};
+
+#define REG_PATTERN_TEST(R, M, W)                                             \
+{                                                                             \
+       u32 pat, val, before;                                                 \
+       const u32 _test[] = {0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF}; \
+       for (pat = 0; pat < ARRAY_SIZE(_test); pat++) {                       \
+               before = readl(adapter->hw.hw_addr + R);                      \
+               writel((_test[pat] & W), (adapter->hw.hw_addr + R));          \
+               val = readl(adapter->hw.hw_addr + R);                         \
+               if (val != (_test[pat] & W & M)) {                            \
+                       hw_dbg(&adapter->hw,                                  \
+                       "pattern test reg %04X failed: got "                  \
+                       "0x%08X expected 0x%08X\n",                           \
+                       R, val, (_test[pat] & W & M));                        \
+                       *data = R;                                            \
+                       writel(before, adapter->hw.hw_addr + R);              \
+                       return 1;                                             \
+               }                                                             \
+               writel(before, adapter->hw.hw_addr + R);                      \
+       }                                                                     \
+}
+
+#define REG_SET_AND_CHECK(R, M, W)                                            \
+{                                                                             \
+       u32 val, before;                                                      \
+       before = readl(adapter->hw.hw_addr + R);                              \
+       writel((W & M), (adapter->hw.hw_addr + R));                           \
+       val = readl(adapter->hw.hw_addr + R);                                 \
+       if ((W & M) != (val & M)) {                                           \
+               printk(KERN_ERR "set/check reg %04X test failed: got 0x%08X " \
+                                "expected 0x%08X\n", R, (val & M), (W & M)); \
+               *data = R;                                                    \
+               writel(before, (adapter->hw.hw_addr + R));                    \
+               return 1;                                                     \
+       }                                                                     \
+       writel(before, (adapter->hw.hw_addr + R));                            \
+}
+
+static int ixgbevf_reg_test(struct ixgbevf_adapter *adapter, u64 *data)
+{
+       struct ixgbevf_reg_test *test;
+       u32 i;
+
+       test = reg_test_vf;
+
+       /*
+        * Perform the register test, looping through the test table
+        * until we either fail or reach the null entry.
+        */
+       while (test->reg) {
+               for (i = 0; i < test->array_len; i++) {
+                       switch (test->test_type) {
+                       case PATTERN_TEST:
+                               REG_PATTERN_TEST(test->reg + (i * 0x40),
+                                               test->mask,
+                                               test->write);
+                               break;
+                       case SET_READ_TEST:
+                               REG_SET_AND_CHECK(test->reg + (i * 0x40),
+                                               test->mask,
+                                               test->write);
+                               break;
+                       case WRITE_NO_TEST:
+                               writel(test->write,
+                                      (adapter->hw.hw_addr + test->reg)
+                                      + (i * 0x40));
+                               break;
+                       case TABLE32_TEST:
+                               REG_PATTERN_TEST(test->reg + (i * 4),
+                                               test->mask,
+                                               test->write);
+                               break;
+                       case TABLE64_TEST_LO:
+                               REG_PATTERN_TEST(test->reg + (i * 8),
+                                               test->mask,
+                                               test->write);
+                               break;
+                       case TABLE64_TEST_HI:
+                               REG_PATTERN_TEST((test->reg + 4) + (i * 8),
+                                               test->mask,
+                                               test->write);
+                               break;
+                       }
+               }
+               test++;
+       }
+
+       *data = 0;
+       return *data;
+}
+
+static void ixgbevf_diag_test(struct net_device *netdev,
+                             struct ethtool_test *eth_test, u64 *data)
+{
+       struct ixgbevf_adapter *adapter = netdev_priv(netdev);
+       bool if_running = netif_running(netdev);
+
+       set_bit(__IXGBEVF_TESTING, &adapter->state);
+       if (eth_test->flags == ETH_TEST_FL_OFFLINE) {
+               /* Offline tests */
+
+               hw_dbg(&adapter->hw, "offline testing starting\n");
+
+               /* Link test performed before hardware reset so autoneg doesn't
+                * interfere with test result */
+               if (ixgbevf_link_test(adapter, &data[1]))
+                       eth_test->flags |= ETH_TEST_FL_FAILED;
+
+               if (if_running)
+                       /* indicate we're in test mode */
+                       dev_close(netdev);
+               else
+                       ixgbevf_reset(adapter);
+
+               hw_dbg(&adapter->hw, "register testing starting\n");
+               if (ixgbevf_reg_test(adapter, &data[0]))
+                       eth_test->flags |= ETH_TEST_FL_FAILED;
+
+               ixgbevf_reset(adapter);
+
+               clear_bit(__IXGBEVF_TESTING, &adapter->state);
+               if (if_running)
+                       dev_open(netdev);
+       } else {
+               hw_dbg(&adapter->hw, "online testing starting\n");
+               /* Online tests */
+               if (ixgbevf_link_test(adapter, &data[1]))
+                       eth_test->flags |= ETH_TEST_FL_FAILED;
+
+               /* Online tests aren't run; pass by default */
+               data[0] = 0;
+
+               clear_bit(__IXGBEVF_TESTING, &adapter->state);
+       }
+       msleep_interruptible(4 * 1000);
+}
+
+static int ixgbevf_nway_reset(struct net_device *netdev)
+{
+       struct ixgbevf_adapter *adapter = netdev_priv(netdev);
+
+       if (netif_running(netdev)) {
+               if (!adapter->dev_closed)
+                       ixgbevf_reinit_locked(adapter);
+       }
+
+       return 0;
+}
+
+static struct ethtool_ops ixgbevf_ethtool_ops = {
+       .get_settings           = ixgbevf_get_settings,
+       .get_drvinfo            = ixgbevf_get_drvinfo,
+       .get_regs_len           = ixgbevf_get_regs_len,
+       .get_regs               = ixgbevf_get_regs,
+       .nway_reset             = ixgbevf_nway_reset,
+       .get_link               = ethtool_op_get_link,
+       .get_ringparam          = ixgbevf_get_ringparam,
+       .set_ringparam          = ixgbevf_set_ringparam,
+       .get_rx_csum            = ixgbevf_get_rx_csum,
+       .set_rx_csum            = ixgbevf_set_rx_csum,
+       .get_tx_csum            = ethtool_op_get_tx_csum,
+       .set_tx_csum            = ethtool_op_set_tx_ipv6_csum,
+       .get_sg                 = ethtool_op_get_sg,
+       .set_sg                 = ethtool_op_set_sg,
+       .get_msglevel           = ixgbevf_get_msglevel,
+       .set_msglevel           = ixgbevf_set_msglevel,
+       .get_tso                = ethtool_op_get_tso,
+       .set_tso                = ixgbevf_set_tso,
+       .self_test              = ixgbevf_diag_test,
+       .get_sset_count         = ixgbevf_get_sset_count,
+       .get_strings            = ixgbevf_get_strings,
+       .get_ethtool_stats      = ixgbevf_get_ethtool_stats,
+};
+
+void ixgbevf_set_ethtool_ops(struct net_device *netdev)
+{
+       SET_ETHTOOL_OPS(netdev, &ixgbevf_ethtool_ops);
+}
diff --git a/drivers/net/ixgbevf/ixgbevf.h b/drivers/net/ixgbevf/ixgbevf.h
new file mode 100644 (file)
index 0000000..f7015ef
--- /dev/null
@@ -0,0 +1,318 @@
+/*******************************************************************************
+
+  Intel 82599 Virtual Function driver
+  Copyright(c) 1999 - 2009 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _IXGBEVF_H_
+#define _IXGBEVF_H_
+
+#include <linux/types.h>
+#include <linux/timer.h>
+#include <linux/io.h>
+#include <linux/netdevice.h>
+
+#include "vf.h"
+
+/* wrapper around a pointer to a socket buffer,
+ * so a DMA handle can be stored along with the buffer */
+struct ixgbevf_tx_buffer {
+       struct sk_buff *skb;
+       dma_addr_t dma;
+       unsigned long time_stamp;
+       u16 length;
+       u16 next_to_watch;
+       u16 mapped_as_page;
+};
+
+struct ixgbevf_rx_buffer {
+       struct sk_buff *skb;
+       dma_addr_t dma;
+       struct page *page;
+       dma_addr_t page_dma;
+       unsigned int page_offset;
+};
+
+struct ixgbevf_ring {
+       struct ixgbevf_adapter *adapter;  /* backlink */
+       void *desc;                     /* descriptor ring memory */
+       dma_addr_t dma;                 /* phys. address of descriptor ring */
+       unsigned int size;              /* length in bytes */
+       unsigned int count;             /* amount of descriptors */
+       unsigned int next_to_use;
+       unsigned int next_to_clean;
+
+       int queue_index; /* needed for multiqueue queue management */
+       union {
+               struct ixgbevf_tx_buffer *tx_buffer_info;
+               struct ixgbevf_rx_buffer *rx_buffer_info;
+       };
+
+       u16 head;
+       u16 tail;
+
+       unsigned int total_bytes;
+       unsigned int total_packets;
+
+       u16 reg_idx; /* holds the special value that gets the hardware register
+                     * offset associated with this ring, which is different
+                     * for DCB and RSS modes */
+
+#if defined(CONFIG_DCA) || defined(CONFIG_DCA_MODULE)
+       /* cpu for tx queue */
+       int cpu;
+#endif
+
+       u64 v_idx; /* maps directly to the index for this ring in the hardware
+                   * vector array, can also be used for finding the bit in EICR
+                   * and friends that represents the vector for this ring */
+
+       u16 work_limit;                /* max work per interrupt */
+       u16 rx_buf_len;
+};
+
+enum ixgbevf_ring_f_enum {
+       RING_F_NONE = 0,
+       RING_F_ARRAY_SIZE      /* must be last in enum set */
+};
+
+struct ixgbevf_ring_feature {
+       int indices;
+       int mask;
+};
+
+/* How many Rx Buffers do we bundle into one write to the hardware ? */
+#define IXGBEVF_RX_BUFFER_WRITE        16      /* Must be power of 2 */
+
+#define MAX_RX_QUEUES 1
+#define MAX_TX_QUEUES 1
+
+#define IXGBEVF_DEFAULT_TXD   1024
+#define IXGBEVF_DEFAULT_RXD   512
+#define IXGBEVF_MAX_TXD       4096
+#define IXGBEVF_MIN_TXD       64
+#define IXGBEVF_MAX_RXD       4096
+#define IXGBEVF_MIN_RXD       64
+
+/* Supported Rx Buffer Sizes */
+#define IXGBEVF_RXBUFFER_64    64     /* Used for packet split */
+#define IXGBEVF_RXBUFFER_128   128    /* Used for packet split */
+#define IXGBEVF_RXBUFFER_256   256    /* Used for packet split */
+#define IXGBEVF_RXBUFFER_2048  2048
+#define IXGBEVF_MAX_RXBUFFER   16384  /* largest size for single descriptor */
+
+#define IXGBEVF_RX_HDR_SIZE IXGBEVF_RXBUFFER_256
+
+#define MAXIMUM_ETHERNET_VLAN_SIZE (VLAN_ETH_FRAME_LEN + ETH_FCS_LEN)
+
+#define IXGBE_TX_FLAGS_CSUM            (u32)(1)
+#define IXGBE_TX_FLAGS_VLAN            (u32)(1 << 1)
+#define IXGBE_TX_FLAGS_TSO             (u32)(1 << 2)
+#define IXGBE_TX_FLAGS_IPV4            (u32)(1 << 3)
+#define IXGBE_TX_FLAGS_FCOE            (u32)(1 << 4)
+#define IXGBE_TX_FLAGS_FSO             (u32)(1 << 5)
+#define IXGBE_TX_FLAGS_VLAN_MASK       0xffff0000
+#define IXGBE_TX_FLAGS_VLAN_PRIO_MASK  0x0000e000
+#define IXGBE_TX_FLAGS_VLAN_SHIFT      16
+
+/* MAX_MSIX_Q_VECTORS of these are allocated,
+ * but we only use one per queue-specific vector.
+ */
+struct ixgbevf_q_vector {
+       struct ixgbevf_adapter *adapter;
+       struct napi_struct napi;
+       DECLARE_BITMAP(rxr_idx, MAX_RX_QUEUES); /* Rx ring indices */
+       DECLARE_BITMAP(txr_idx, MAX_TX_QUEUES); /* Tx ring indices */
+       u8 rxr_count;     /* Rx ring count assigned to this vector */
+       u8 txr_count;     /* Tx ring count assigned to this vector */
+       u8 tx_itr;
+       u8 rx_itr;
+       u32 eitr;
+       int v_idx;        /* vector index in list */
+};
+
+/* Helper macros to switch between ints/sec and what the register uses.
+ * And yes, it's the same math going both ways.  The lowest value
+ * supported by all of the ixgbe hardware is 8.
+ */
+#define EITR_INTS_PER_SEC_TO_REG(_eitr) \
+       ((_eitr) ? (1000000000 / ((_eitr) * 256)) : 8)
+#define EITR_REG_TO_INTS_PER_SEC EITR_INTS_PER_SEC_TO_REG
+
+#define IXGBE_DESC_UNUSED(R) \
+       ((((R)->next_to_clean > (R)->next_to_use) ? 0 : (R)->count) + \
+       (R)->next_to_clean - (R)->next_to_use - 1)
+
+#define IXGBE_RX_DESC_ADV(R, i)            \
+       (&(((union ixgbe_adv_rx_desc *)((R).desc))[i]))
+#define IXGBE_TX_DESC_ADV(R, 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]))
+
+#define IXGBE_MAX_JUMBO_FRAME_SIZE        16128
+
+#define OTHER_VECTOR 1
+#define NON_Q_VECTORS (OTHER_VECTOR)
+
+#define MAX_MSIX_Q_VECTORS 2
+#define MAX_MSIX_COUNT 2
+
+#define MIN_MSIX_Q_VECTORS 2
+#define MIN_MSIX_COUNT (MIN_MSIX_Q_VECTORS + NON_Q_VECTORS)
+
+/* board specific private data structure */
+struct ixgbevf_adapter {
+       struct timer_list watchdog_timer;
+#ifdef NETIF_F_HW_VLAN_TX
+       struct vlan_group *vlgrp;
+#endif
+       u16 bd_number;
+       struct work_struct reset_task;
+       struct ixgbevf_q_vector *q_vector[MAX_MSIX_Q_VECTORS];
+       char name[MAX_MSIX_COUNT][IFNAMSIZ + 9];
+
+       /* Interrupt Throttle Rate */
+       u32 itr_setting;
+       u16 eitr_low;
+       u16 eitr_high;
+
+       /* TX */
+       struct ixgbevf_ring *tx_ring;   /* One per active queue */
+       int num_tx_queues;
+       u64 restart_queue;
+       u64 hw_csum_tx_good;
+       u64 lsc_int;
+       u64 hw_tso_ctxt;
+       u64 hw_tso6_ctxt;
+       u32 tx_timeout_count;
+       bool detect_tx_hung;
+
+       /* RX */
+       struct ixgbevf_ring *rx_ring;   /* One per active queue */
+       int num_rx_queues;
+       int num_rx_pools;               /* == num_rx_queues in 82598 */
+       int num_rx_queues_per_pool;     /* 1 if 82598, can be many if 82599 */
+       u64 hw_csum_rx_error;
+       u64 hw_rx_no_dma_resources;
+       u64 hw_csum_rx_good;
+       u64 non_eop_descs;
+       int num_msix_vectors;
+       int max_msix_q_vectors;         /* true count of q_vectors for device */
+       struct ixgbevf_ring_feature ring_feature[RING_F_ARRAY_SIZE];
+       struct msix_entry *msix_entries;
+
+       u64 rx_hdr_split;
+       u32 alloc_rx_page_failed;
+       u32 alloc_rx_buff_failed;
+
+       /* Some features need tri-state capability,
+        * thus the additional *_CAPABLE flags.
+        */
+       u32 flags;
+#define IXGBE_FLAG_RX_CSUM_ENABLED              (u32)(1)
+#define IXGBE_FLAG_RX_1BUF_CAPABLE              (u32)(1 << 1)
+#define IXGBE_FLAG_RX_PS_CAPABLE                (u32)(1 << 2)
+#define IXGBE_FLAG_RX_PS_ENABLED                (u32)(1 << 3)
+#define IXGBE_FLAG_IN_NETPOLL                   (u32)(1 << 4)
+#define IXGBE_FLAG_IMIR_ENABLED                 (u32)(1 << 5)
+#define IXGBE_FLAG_MQ_CAPABLE                   (u32)(1 << 6)
+#define IXGBE_FLAG_NEED_LINK_UPDATE             (u32)(1 << 7)
+#define IXGBE_FLAG_IN_WATCHDOG_TASK             (u32)(1 << 8)
+       /* 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;
+       u16 msg_enable;
+       struct ixgbevf_hw_stats stats;
+       u64 zero_base;
+       /* Interrupt Throttle Rate */
+       u32 eitr_param;
+
+       unsigned long state;
+       u32 *config_space;
+       u64 tx_busy;
+       unsigned int tx_ring_count;
+       unsigned int rx_ring_count;
+
+       u32 link_speed;
+       bool link_up;
+       unsigned long link_check_timeout;
+
+       struct work_struct watchdog_task;
+       bool netdev_registered;
+       bool dev_closed;
+};
+
+enum ixbgevf_state_t {
+       __IXGBEVF_TESTING,
+       __IXGBEVF_RESETTING,
+       __IXGBEVF_DOWN
+};
+
+enum ixgbevf_boards {
+       board_82599_vf,
+};
+
+extern struct ixgbevf_info ixgbevf_vf_info;
+extern struct ixgbe_mac_operations ixgbevf_mbx_ops;
+
+/* needed by ethtool.c */
+extern char ixgbevf_driver_name[];
+extern const char ixgbevf_driver_version[];
+
+extern int ixgbevf_up(struct ixgbevf_adapter *adapter);
+extern void ixgbevf_down(struct ixgbevf_adapter *adapter);
+extern void ixgbevf_reinit_locked(struct ixgbevf_adapter *adapter);
+extern void ixgbevf_reset(struct ixgbevf_adapter *adapter);
+extern void ixgbevf_set_ethtool_ops(struct net_device *netdev);
+extern int ixgbevf_setup_rx_resources(struct ixgbevf_adapter *,
+                                     struct ixgbevf_ring *);
+extern int ixgbevf_setup_tx_resources(struct ixgbevf_adapter *,
+                                     struct ixgbevf_ring *);
+extern void ixgbevf_free_rx_resources(struct ixgbevf_adapter *,
+                                     struct ixgbevf_ring *);
+extern void ixgbevf_free_tx_resources(struct ixgbevf_adapter *,
+                                     struct ixgbevf_ring *);
+extern void ixgbevf_update_stats(struct ixgbevf_adapter *adapter);
+
+#ifdef ETHTOOL_OPS_COMPAT
+extern int ethtool_ioctl(struct ifreq *ifr);
+
+#endif
+extern void ixgbe_napi_add_all(struct ixgbevf_adapter *adapter);
+extern void ixgbe_napi_del_all(struct ixgbevf_adapter *adapter);
+
+#ifdef DEBUG
+extern char *ixgbevf_get_hw_dev_name(struct ixgbe_hw *hw);
+#define hw_dbg(hw, format, arg...) \
+       printk(KERN_DEBUG "%s: " format, ixgbevf_get_hw_dev_name(hw), ##arg)
+#else
+#define hw_dbg(hw, format, arg...) do {} while (0)
+#endif
+
+#endif /* _IXGBEVF_H_ */
diff --git a/drivers/net/ixgbevf/ixgbevf_main.c b/drivers/net/ixgbevf/ixgbevf_main.c
new file mode 100644 (file)
index 0000000..b9f10d0
--- /dev/null
@@ -0,0 +1,3578 @@
+/*******************************************************************************
+
+  Intel 82599 Virtual Function driver
+  Copyright(c) 1999 - 2009 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+
+/******************************************************************************
+ Copyright (c)2006 - 2007 Myricom, Inc. for some LRO specific code
+******************************************************************************/
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/vmalloc.h>
+#include <linux/string.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/ipv6.h>
+#include <net/checksum.h>
+#include <net/ip6_checksum.h>
+#include <linux/ethtool.h>
+#include <linux/if_vlan.h>
+
+#include "ixgbevf.h"
+
+char ixgbevf_driver_name[] = "ixgbevf";
+static const char ixgbevf_driver_string[] =
+       "Intel(R) 82599 Virtual Function";
+
+#define DRV_VERSION "1.0.0-k0"
+const char ixgbevf_driver_version[] = DRV_VERSION;
+static char ixgbevf_copyright[] = "Copyright (c) 2009 Intel Corporation.";
+
+static const struct ixgbevf_info *ixgbevf_info_tbl[] = {
+       [board_82599_vf] = &ixgbevf_vf_info,
+};
+
+/* ixgbevf_pci_tbl - PCI Device ID Table
+ *
+ * Wildcard entries (PCI_ANY_ID) should come last
+ * Last entry must be all 0s
+ *
+ * { Vendor ID, Device ID, SubVendor ID, SubDevice ID,
+ *   Class, Class Mask, private data (not used) }
+ */
+static struct pci_device_id ixgbevf_pci_tbl[] = {
+       {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_VF),
+       board_82599_vf},
+
+       /* required last entry */
+       {0, }
+};
+MODULE_DEVICE_TABLE(pci, ixgbevf_pci_tbl);
+
+MODULE_AUTHOR("Intel Corporation, <linux.nics@intel.com>");
+MODULE_DESCRIPTION("Intel(R) 82599 Virtual Function Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
+#define DEFAULT_DEBUG_LEVEL_SHIFT 3
+
+/* forward decls */
+static void ixgbevf_set_itr_msix(struct ixgbevf_q_vector *q_vector);
+static void ixgbevf_write_eitr(struct ixgbevf_adapter *adapter, int v_idx,
+                              u32 itr_reg);
+
+static inline void ixgbevf_release_rx_desc(struct ixgbe_hw *hw,
+                                          struct ixgbevf_ring *rx_ring,
+                                          u32 val)
+{
+       /*
+        * Force memory writes to complete before letting h/w
+        * know there are new descriptors to fetch.  (Only
+        * applicable for weak-ordered memory model archs,
+        * such as IA-64).
+        */
+       wmb();
+       IXGBE_WRITE_REG(hw, IXGBE_VFRDT(rx_ring->reg_idx), val);
+}
+
+/*
+ * ixgbe_set_ivar - set the IVAR registers, mapping interrupt causes to vectors
+ * @adapter: pointer to adapter struct
+ * @direction: 0 for Rx, 1 for Tx, -1 for other causes
+ * @queue: queue to map the corresponding interrupt to
+ * @msix_vector: the vector to map to the corresponding queue
+ *
+ */
+static void ixgbevf_set_ivar(struct ixgbevf_adapter *adapter, s8 direction,
+                            u8 queue, u8 msix_vector)
+{
+       u32 ivar, index;
+       struct ixgbe_hw *hw = &adapter->hw;
+       if (direction == -1) {
+               /* other causes */
+               msix_vector |= IXGBE_IVAR_ALLOC_VAL;
+               ivar = IXGBE_READ_REG(hw, IXGBE_VTIVAR_MISC);
+               ivar &= ~0xFF;
+               ivar |= msix_vector;
+               IXGBE_WRITE_REG(hw, IXGBE_VTIVAR_MISC, ivar);
+       } else {
+               /* tx or rx causes */
+               msix_vector |= IXGBE_IVAR_ALLOC_VAL;
+               index = ((16 * (queue & 1)) + (8 * direction));
+               ivar = IXGBE_READ_REG(hw, IXGBE_VTIVAR(queue >> 1));
+               ivar &= ~(0xFF << index);
+               ivar |= (msix_vector << index);
+               IXGBE_WRITE_REG(hw, IXGBE_VTIVAR(queue >> 1), ivar);
+       }
+}
+
+static void ixgbevf_unmap_and_free_tx_resource(struct ixgbevf_adapter *adapter,
+                                              struct ixgbevf_tx_buffer
+                                              *tx_buffer_info)
+{
+       if (tx_buffer_info->dma) {
+               if (tx_buffer_info->mapped_as_page)
+                       pci_unmap_page(adapter->pdev,
+                                      tx_buffer_info->dma,
+                                      tx_buffer_info->length,
+                                      PCI_DMA_TODEVICE);
+               else
+                       pci_unmap_single(adapter->pdev,
+                                        tx_buffer_info->dma,
+                                        tx_buffer_info->length,
+                                        PCI_DMA_TODEVICE);
+               tx_buffer_info->dma = 0;
+       }
+       if (tx_buffer_info->skb) {
+               dev_kfree_skb_any(tx_buffer_info->skb);
+               tx_buffer_info->skb = NULL;
+       }
+       tx_buffer_info->time_stamp = 0;
+       /* tx_buffer_info must be completely set up in the transmit path */
+}
+
+static inline bool ixgbevf_check_tx_hang(struct ixgbevf_adapter *adapter,
+                                        struct ixgbevf_ring *tx_ring,
+                                        unsigned int eop)
+{
+       struct ixgbe_hw *hw = &adapter->hw;
+       u32 head, tail;
+
+       /* Detect a transmit hang in hardware, this serializes the
+        * check with the clearing of time_stamp and movement of eop */
+       head = readl(hw->hw_addr + tx_ring->head);
+       tail = readl(hw->hw_addr + tx_ring->tail);
+       adapter->detect_tx_hung = false;
+       if ((head != tail) &&
+           tx_ring->tx_buffer_info[eop].time_stamp &&
+           time_after(jiffies, tx_ring->tx_buffer_info[eop].time_stamp + HZ)) {
+               /* detected Tx unit hang */
+               union ixgbe_adv_tx_desc *tx_desc;
+               tx_desc = IXGBE_TX_DESC_ADV(*tx_ring, eop);
+               printk(KERN_ERR "Detected Tx Unit Hang\n"
+                      "  Tx Queue             <%d>\n"
+                      "  TDH, TDT             <%x>, <%x>\n"
+                      "  next_to_use          <%x>\n"
+                      "  next_to_clean        <%x>\n"
+                      "tx_buffer_info[next_to_clean]\n"
+                      "  time_stamp           <%lx>\n"
+                      "  jiffies              <%lx>\n",
+                      tx_ring->queue_index,
+                      head, tail,
+                      tx_ring->next_to_use, eop,
+                      tx_ring->tx_buffer_info[eop].time_stamp, jiffies);
+               return true;
+       }
+
+       return false;
+}
+
+#define IXGBE_MAX_TXD_PWR      14
+#define IXGBE_MAX_DATA_PER_TXD (1 << IXGBE_MAX_TXD_PWR)
+
+/* Tx Descriptors needed, worst case */
+#define TXD_USE_COUNT(S) (((S) >> IXGBE_MAX_TXD_PWR) + \
+                        (((S) & (IXGBE_MAX_DATA_PER_TXD - 1)) ? 1 : 0))
+#ifdef MAX_SKB_FRAGS
+#define DESC_NEEDED (TXD_USE_COUNT(IXGBE_MAX_DATA_PER_TXD) /* skb->data */ + \
+       MAX_SKB_FRAGS * TXD_USE_COUNT(PAGE_SIZE) + 1)      /* for context */
+#else
+#define DESC_NEEDED TXD_USE_COUNT(IXGBE_MAX_DATA_PER_TXD)
+#endif
+
+static void ixgbevf_tx_timeout(struct net_device *netdev);
+
+/**
+ * ixgbevf_clean_tx_irq - Reclaim resources after transmit completes
+ * @adapter: board private structure
+ * @tx_ring: tx ring to clean
+ **/
+static bool ixgbevf_clean_tx_irq(struct ixgbevf_adapter *adapter,
+                                struct ixgbevf_ring *tx_ring)
+{
+       struct net_device *netdev = adapter->netdev;
+       struct ixgbe_hw *hw = &adapter->hw;
+       union ixgbe_adv_tx_desc *tx_desc, *eop_desc;
+       struct ixgbevf_tx_buffer *tx_buffer_info;
+       unsigned int i, eop, count = 0;
+       unsigned int total_bytes = 0, total_packets = 0;
+
+       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);
+
+       while ((eop_desc->wb.status & cpu_to_le32(IXGBE_TXD_STAT_DD)) &&
+              (count < tx_ring->work_limit)) {
+               bool cleaned = false;
+               for ( ; !cleaned; count++) {
+                       struct sk_buff *skb;
+                       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;
+
+                       if (cleaned && skb) {
+                               unsigned int segs, bytecount;
+
+                               /* gso_segs is currently only valid for tcp */
+                               segs = skb_shinfo(skb)->gso_segs ?: 1;
+                               /* multiply data chunks by size of headers */
+                               bytecount = ((segs - 1) * skb_headlen(skb)) +
+                                           skb->len;
+                               total_packets += segs;
+                               total_bytes += bytecount;
+                       }
+
+                       ixgbevf_unmap_and_free_tx_resource(adapter,
+                                                          tx_buffer_info);
+
+                       tx_desc->wb.status = 0;
+
+                       i++;
+                       if (i == tx_ring->count)
+                               i = 0;
+               }
+
+               eop = tx_ring->tx_buffer_info[i].next_to_watch;
+               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))) {
+               /* Make sure that anybody stopping the queue after this
+                * sees the new next_to_clean.
+                */
+               smp_mb();
+#ifdef HAVE_TX_MQ
+               if (__netif_subqueue_stopped(netdev, tx_ring->queue_index) &&
+                   !test_bit(__IXGBEVF_DOWN, &adapter->state)) {
+                       netif_wake_subqueue(netdev, tx_ring->queue_index);
+                       ++adapter->restart_queue;
+               }
+#else
+               if (netif_queue_stopped(netdev) &&
+                   !test_bit(__IXGBEVF_DOWN, &adapter->state)) {
+                       netif_wake_queue(netdev);
+                       ++adapter->restart_queue;
+               }
+#endif
+       }
+
+       if (adapter->detect_tx_hung) {
+               if (ixgbevf_check_tx_hang(adapter, tx_ring, i)) {
+                       /* schedule immediate reset if we believe we hung */
+                       printk(KERN_INFO
+                              "tx hang %d detected, resetting adapter\n",
+                              adapter->tx_timeout_count + 1);
+                       ixgbevf_tx_timeout(adapter->netdev);
+               }
+       }
+
+       /* re-arm the interrupt */
+       if ((count >= tx_ring->work_limit) &&
+           (!test_bit(__IXGBEVF_DOWN, &adapter->state))) {
+               IXGBE_WRITE_REG(hw, IXGBE_VTEICS, tx_ring->v_idx);
+       }
+
+       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;
+
+       return (count < tx_ring->work_limit);
+}
+
+/**
+ * ixgbevf_receive_skb - Send a completed packet up the stack
+ * @q_vector: structure containing interrupt and ring information
+ * @skb: packet to send up
+ * @status: hardware indication of status of receive
+ * @rx_ring: rx descriptor ring (for a specific queue) to setup
+ * @rx_desc: rx descriptor
+ **/
+static void ixgbevf_receive_skb(struct ixgbevf_q_vector *q_vector,
+                               struct sk_buff *skb, u8 status,
+                               struct ixgbevf_ring *ring,
+                               union ixgbe_adv_rx_desc *rx_desc)
+{
+       struct ixgbevf_adapter *adapter = q_vector->adapter;
+       bool is_vlan = (status & IXGBE_RXD_STAT_VP);
+       u16 tag = le16_to_cpu(rx_desc->wb.upper.vlan);
+       int ret;
+
+       if (!(adapter->flags & IXGBE_FLAG_IN_NETPOLL)) {
+               if (adapter->vlgrp && is_vlan)
+                       vlan_gro_receive(&q_vector->napi,
+                                        adapter->vlgrp,
+                                        tag, skb);
+               else
+                       napi_gro_receive(&q_vector->napi, skb);
+       } else {
+               if (adapter->vlgrp && is_vlan)
+                       ret = vlan_hwaccel_rx(skb, adapter->vlgrp, tag);
+               else
+                       ret = netif_rx(skb);
+       }
+}
+
+/**
+ * ixgbevf_rx_checksum - indicate in skb if hw indicated a good cksum
+ * @adapter: address of board private structure
+ * @status_err: hardware indication of status of receive
+ * @skb: skb currently being received and modified
+ **/
+static inline void ixgbevf_rx_checksum(struct ixgbevf_adapter *adapter,
+                                      u32 status_err, struct sk_buff *skb)
+{
+       skb->ip_summed = CHECKSUM_NONE;
+
+       /* Rx csum disabled */
+       if (!(adapter->flags & IXGBE_FLAG_RX_CSUM_ENABLED))
+               return;
+
+       /* if IP and error */
+       if ((status_err & IXGBE_RXD_STAT_IPCS) &&
+           (status_err & IXGBE_RXDADV_ERR_IPE)) {
+               adapter->hw_csum_rx_error++;
+               return;
+       }
+
+       if (!(status_err & IXGBE_RXD_STAT_L4CS))
+               return;
+
+       if (status_err & IXGBE_RXDADV_ERR_TCPE) {
+               adapter->hw_csum_rx_error++;
+               return;
+       }
+
+       /* It must be a TCP or UDP packet with a valid checksum */
+       skb->ip_summed = CHECKSUM_UNNECESSARY;
+       adapter->hw_csum_rx_good++;
+}
+
+/**
+ * ixgbevf_alloc_rx_buffers - Replace used receive buffers; packet split
+ * @adapter: address of board private structure
+ **/
+static void ixgbevf_alloc_rx_buffers(struct ixgbevf_adapter *adapter,
+                                    struct ixgbevf_ring *rx_ring,
+                                    int cleaned_count)
+{
+       struct pci_dev *pdev = adapter->pdev;
+       union ixgbe_adv_rx_desc *rx_desc;
+       struct ixgbevf_rx_buffer *bi;
+       struct sk_buff *skb;
+       unsigned int i;
+       unsigned int bufsz = rx_ring->rx_buf_len + NET_IP_ALIGN;
+
+       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);
+
+               if (!bi->page_dma &&
+                   (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED)) {
+                       if (!bi->page) {
+                               bi->page = netdev_alloc_page(adapter->netdev);
+                               if (!bi->page) {
+                                       adapter->alloc_rx_page_failed++;
+                                       goto no_buffers;
+                               }
+                               bi->page_offset = 0;
+                       } else {
+                               /* use a half page if we're re-using */
+                               bi->page_offset ^= (PAGE_SIZE / 2);
+                       }
+
+                       bi->page_dma = pci_map_page(pdev, bi->page,
+                                                   bi->page_offset,
+                                                   (PAGE_SIZE / 2),
+                                                   PCI_DMA_FROMDEVICE);
+               }
+
+               skb = bi->skb;
+               if (!skb) {
+                       skb = netdev_alloc_skb(adapter->netdev,
+                                                              bufsz);
+
+                       if (!skb) {
+                               adapter->alloc_rx_buff_failed++;
+                               goto no_buffers;
+                       }
+
+                       /*
+                        * Make buffer alignment 2 beyond a 16 byte boundary
+                        * this will result in a 16 byte aligned IP header after
+                        * the 14 byte MAC header is removed
+                        */
+                       skb_reserve(skb, NET_IP_ALIGN);
+
+                       bi->skb = skb;
+               }
+               if (!bi->dma) {
+                       bi->dma = pci_map_single(pdev, skb->data,
+                                                rx_ring->rx_buf_len,
+                                                PCI_DMA_FROMDEVICE);
+               }
+               /* Refresh the desc even if buffer_addrs didn't change because
+                * each write-back erases this info. */
+               if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) {
+                       rx_desc->read.pkt_addr = cpu_to_le64(bi->page_dma);
+                       rx_desc->read.hdr_addr = cpu_to_le64(bi->dma);
+               } else {
+                       rx_desc->read.pkt_addr = cpu_to_le64(bi->dma);
+               }
+
+               i++;
+               if (i == rx_ring->count)
+                       i = 0;
+               bi = &rx_ring->rx_buffer_info[i];
+       }
+
+no_buffers:
+       if (rx_ring->next_to_use != i) {
+               rx_ring->next_to_use = i;
+               if (i-- == 0)
+                       i = (rx_ring->count - 1);
+
+               ixgbevf_release_rx_desc(&adapter->hw, rx_ring, i);
+       }
+}
+
+static inline void ixgbevf_irq_enable_queues(struct ixgbevf_adapter *adapter,
+                                            u64 qmask)
+{
+       u32 mask;
+       struct ixgbe_hw *hw = &adapter->hw;
+
+       mask = (qmask & 0xFFFFFFFF);
+       IXGBE_WRITE_REG(hw, IXGBE_VTEIMS, mask);
+}
+
+static inline u16 ixgbevf_get_hdr_info(union ixgbe_adv_rx_desc *rx_desc)
+{
+       return rx_desc->wb.lower.lo_dword.hs_rss.hdr_info;
+}
+
+static inline u16 ixgbevf_get_pkt_info(union ixgbe_adv_rx_desc *rx_desc)
+{
+       return rx_desc->wb.lower.lo_dword.hs_rss.pkt_info;
+}
+
+static bool ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
+                                struct ixgbevf_ring *rx_ring,
+                                int *work_done, int work_to_do)
+{
+       struct ixgbevf_adapter *adapter = q_vector->adapter;
+       struct pci_dev *pdev = adapter->pdev;
+       union ixgbe_adv_rx_desc *rx_desc, *next_rxd;
+       struct ixgbevf_rx_buffer *rx_buffer_info, *next_buffer;
+       struct sk_buff *skb;
+       unsigned int i;
+       u32 len, staterr;
+       u16 hdr_info;
+       bool cleaned = false;
+       int cleaned_count = 0;
+       unsigned int total_rx_bytes = 0, total_rx_packets = 0;
+
+       i = rx_ring->next_to_clean;
+       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];
+
+       while (staterr & IXGBE_RXD_STAT_DD) {
+               u32 upper_len = 0;
+               if (*work_done >= work_to_do)
+                       break;
+               (*work_done)++;
+
+               if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) {
+                       hdr_info = le16_to_cpu(ixgbevf_get_hdr_info(rx_desc));
+                       len = (hdr_info & IXGBE_RXDADV_HDRBUFLEN_MASK) >>
+                              IXGBE_RXDADV_HDRBUFLEN_SHIFT;
+                       if (hdr_info & IXGBE_RXDADV_SPH)
+                               adapter->rx_hdr_split++;
+                       if (len > IXGBEVF_RX_HDR_SIZE)
+                               len = IXGBEVF_RX_HDR_SIZE;
+                       upper_len = le16_to_cpu(rx_desc->wb.upper.length);
+               } else {
+                       len = le16_to_cpu(rx_desc->wb.upper.length);
+               }
+               cleaned = true;
+               skb = rx_buffer_info->skb;
+               prefetch(skb->data - NET_IP_ALIGN);
+               rx_buffer_info->skb = NULL;
+
+               if (rx_buffer_info->dma) {
+                       pci_unmap_single(pdev, rx_buffer_info->dma,
+                                        rx_ring->rx_buf_len,
+                                        PCI_DMA_FROMDEVICE);
+                       rx_buffer_info->dma = 0;
+                       skb_put(skb, len);
+               }
+
+               if (upper_len) {
+                       pci_unmap_page(pdev, rx_buffer_info->page_dma,
+                                      PAGE_SIZE / 2, PCI_DMA_FROMDEVICE);
+                       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);
+
+                       if ((rx_ring->rx_buf_len > (PAGE_SIZE / 2)) ||
+                           (page_count(rx_buffer_info->page) != 1))
+                               rx_buffer_info->page = NULL;
+                       else
+                               get_page(rx_buffer_info->page);
+
+                       skb->len += upper_len;
+                       skb->data_len += upper_len;
+                       skb->truesize += upper_len;
+               }
+
+               i++;
+               if (i == rx_ring->count)
+                       i = 0;
+
+               next_rxd = IXGBE_RX_DESC_ADV(*rx_ring, i);
+               prefetch(next_rxd);
+               cleaned_count++;
+
+               next_buffer = &rx_ring->rx_buffer_info[i];
+
+               if (!(staterr & IXGBE_RXD_STAT_EOP)) {
+                       if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) {
+                               rx_buffer_info->skb = next_buffer->skb;
+                               rx_buffer_info->dma = next_buffer->dma;
+                               next_buffer->skb = skb;
+                               next_buffer->dma = 0;
+                       } else {
+                               skb->next = next_buffer->skb;
+                               skb->next->prev = skb;
+                       }
+                       adapter->non_eop_descs++;
+                       goto next_desc;
+               }
+
+               /* ERR_MASK will only have valid bits if EOP set */
+               if (unlikely(staterr & IXGBE_RXDADV_ERR_FRAME_ERR_MASK)) {
+                       dev_kfree_skb_irq(skb);
+                       goto next_desc;
+               }
+
+               ixgbevf_rx_checksum(adapter, staterr, skb);
+
+               /* probably a little skewed due to removing CRC */
+               total_rx_bytes += skb->len;
+               total_rx_packets++;
+
+               /*
+                * Work around issue of some types of VM to VM loop back
+                * packets not getting split correctly
+                */
+               if (staterr & IXGBE_RXD_STAT_LB) {
+                       u32 header_fixup_len = skb->len - skb->data_len;
+                       if (header_fixup_len < 14)
+                               skb_push(skb, header_fixup_len);
+               }
+               skb->protocol = eth_type_trans(skb, adapter->netdev);
+
+               ixgbevf_receive_skb(q_vector, skb, staterr, rx_ring, rx_desc);
+               adapter->netdev->last_rx = jiffies;
+
+next_desc:
+               rx_desc->wb.upper.status_error = 0;
+
+               /* return some buffers to hardware, one at a time is too slow */
+               if (cleaned_count >= IXGBEVF_RX_BUFFER_WRITE) {
+                       ixgbevf_alloc_rx_buffers(adapter, rx_ring,
+                                                cleaned_count);
+                       cleaned_count = 0;
+               }
+
+               /* use prefetched values */
+               rx_desc = next_rxd;
+               rx_buffer_info = &rx_ring->rx_buffer_info[i];
+
+               staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
+       }
+
+       rx_ring->next_to_clean = i;
+       cleaned_count = IXGBE_DESC_UNUSED(rx_ring);
+
+       if (cleaned_count)
+               ixgbevf_alloc_rx_buffers(adapter, rx_ring, cleaned_count);
+
+       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;
+
+       return cleaned;
+}
+
+/**
+ * ixgbevf_clean_rxonly - msix (aka one shot) rx clean routine
+ * @napi: napi struct with our devices info in it
+ * @budget: amount of work driver is allowed to do this pass, in packets
+ *
+ * This function is optimized for cleaning one queue only on a single
+ * q_vector!!!
+ **/
+static int ixgbevf_clean_rxonly(struct napi_struct *napi, int budget)
+{
+       struct ixgbevf_q_vector *q_vector =
+               container_of(napi, struct ixgbevf_q_vector, napi);
+       struct ixgbevf_adapter *adapter = q_vector->adapter;
+       struct ixgbevf_ring *rx_ring = NULL;
+       int work_done = 0;
+       long r_idx;
+
+       r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues);
+       rx_ring = &(adapter->rx_ring[r_idx]);
+
+       ixgbevf_clean_rx_irq(q_vector, rx_ring, &work_done, budget);
+
+       /* If all Rx work done, exit the polling mode */
+       if (work_done < budget) {
+               napi_complete(napi);
+               if (adapter->itr_setting & 1)
+                       ixgbevf_set_itr_msix(q_vector);
+               if (!test_bit(__IXGBEVF_DOWN, &adapter->state))
+                       ixgbevf_irq_enable_queues(adapter, rx_ring->v_idx);
+       }
+
+       return work_done;
+}
+
+/**
+ * ixgbevf_clean_rxonly_many - msix (aka one shot) rx clean routine
+ * @napi: napi struct with our devices info in it
+ * @budget: amount of work driver is allowed to do this pass, in packets
+ *
+ * This function will clean more than one rx queue associated with a
+ * q_vector.
+ **/
+static int ixgbevf_clean_rxonly_many(struct napi_struct *napi, int budget)
+{
+       struct ixgbevf_q_vector *q_vector =
+               container_of(napi, struct ixgbevf_q_vector, napi);
+       struct ixgbevf_adapter *adapter = q_vector->adapter;
+       struct ixgbevf_ring *rx_ring = NULL;
+       int work_done = 0, i;
+       long r_idx;
+       u64 enable_mask = 0;
+
+       /* attempt to distribute budget to each queue fairly, but don't allow
+        * the budget to go below 1 because we'll exit polling */
+       budget /= (q_vector->rxr_count ?: 1);
+       budget = max(budget, 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]);
+               ixgbevf_clean_rx_irq(q_vector, rx_ring, &work_done, budget);
+               enable_mask |= rx_ring->v_idx;
+               r_idx = find_next_bit(q_vector->rxr_idx, adapter->num_rx_queues,
+                                     r_idx + 1);
+       }
+
+#ifndef HAVE_NETDEV_NAPI_LIST
+       if (!netif_running(adapter->netdev))
+               work_done = 0;
+
+#endif
+       r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues);
+       rx_ring = &(adapter->rx_ring[r_idx]);
+
+       /* If all Rx work done, exit the polling mode */
+       if (work_done < budget) {
+               napi_complete(napi);
+               if (adapter->itr_setting & 1)
+                       ixgbevf_set_itr_msix(q_vector);
+               if (!test_bit(__IXGBEVF_DOWN, &adapter->state))
+                       ixgbevf_irq_enable_queues(adapter, enable_mask);
+       }
+
+       return work_done;
+}
+
+
+/**
+ * ixgbevf_configure_msix - Configure MSI-X hardware
+ * @adapter: board private structure
+ *
+ * ixgbevf_configure_msix sets up the hardware to properly generate MSI-X
+ * interrupts.
+ **/
+static void ixgbevf_configure_msix(struct ixgbevf_adapter *adapter)
+{
+       struct ixgbevf_q_vector *q_vector;
+       struct ixgbe_hw *hw = &adapter->hw;
+       int i, j, q_vectors, v_idx, r_idx;
+       u32 mask;
+
+       q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS;
+
+       /*
+        * Populate the IVAR table and set the ITR values to the
+        * corresponding register.
+        */
+       for (v_idx = 0; v_idx < q_vectors; v_idx++) {
+               q_vector = adapter->q_vector[v_idx];
+               /* XXX for_each_bit(...) */
+               r_idx = find_first_bit(q_vector->rxr_idx,
+                                      adapter->num_rx_queues);
+
+               for (i = 0; i < q_vector->rxr_count; i++) {
+                       j = adapter->rx_ring[r_idx].reg_idx;
+                       ixgbevf_set_ivar(adapter, 0, j, v_idx);
+                       r_idx = find_next_bit(q_vector->rxr_idx,
+                                             adapter->num_rx_queues,
+                                             r_idx + 1);
+               }
+               r_idx = find_first_bit(q_vector->txr_idx,
+                                      adapter->num_tx_queues);
+
+               for (i = 0; i < q_vector->txr_count; i++) {
+                       j = adapter->tx_ring[r_idx].reg_idx;
+                       ixgbevf_set_ivar(adapter, 1, j, v_idx);
+                       r_idx = find_next_bit(q_vector->txr_idx,
+                                             adapter->num_tx_queues,
+                                             r_idx + 1);
+               }
+
+               /* if this is a tx only vector halve the interrupt rate */
+               if (q_vector->txr_count && !q_vector->rxr_count)
+                       q_vector->eitr = (adapter->eitr_param >> 1);
+               else if (q_vector->rxr_count)
+                       /* rx only */
+                       q_vector->eitr = adapter->eitr_param;
+
+               ixgbevf_write_eitr(adapter, v_idx, q_vector->eitr);
+       }
+
+       ixgbevf_set_ivar(adapter, -1, 1, v_idx);
+
+       /* set up to autoclear timer, and the vectors */
+       mask = IXGBE_EIMS_ENABLE_MASK;
+       mask &= ~IXGBE_EIMS_OTHER;
+       IXGBE_WRITE_REG(hw, IXGBE_VTEIAC, mask);
+}
+
+enum latency_range {
+       lowest_latency = 0,
+       low_latency = 1,
+       bulk_latency = 2,
+       latency_invalid = 255
+};
+
+/**
+ * ixgbevf_update_itr - update the dynamic ITR value based on statistics
+ * @adapter: pointer to adapter
+ * @eitr: eitr setting (ints per sec) to give last timeslice
+ * @itr_setting: current throttle rate in ints/second
+ * @packets: the number of packets during this measurement interval
+ * @bytes: the number of bytes during this measurement interval
+ *
+ *      Stores a new ITR value based on packets and byte
+ *      counts during the last interrupt.  The advantage of per interrupt
+ *      computation is faster updates and more accurate ITR for the current
+ *      traffic pattern.  Constants in this function were computed
+ *      based on theoretical maximum wire speed and thresholds were set based
+ *      on testing data as well as attempting to minimize response time
+ *      while increasing bulk throughput.
+ **/
+static u8 ixgbevf_update_itr(struct ixgbevf_adapter *adapter,
+                            u32 eitr, u8 itr_setting,
+                            int packets, int bytes)
+{
+       unsigned int retval = itr_setting;
+       u32 timepassed_us;
+       u64 bytes_perint;
+
+       if (packets == 0)
+               goto update_itr_done;
+
+
+       /* simple throttlerate management
+        *    0-20MB/s lowest (100000 ints/s)
+        *   20-100MB/s low   (20000 ints/s)
+        *  100-1249MB/s bulk (8000 ints/s)
+        */
+       /* what was last interrupt timeslice? */
+       timepassed_us = 1000000/eitr;
+       bytes_perint = bytes / timepassed_us; /* bytes/usec */
+
+       switch (itr_setting) {
+       case lowest_latency:
+               if (bytes_perint > adapter->eitr_low)
+                       retval = low_latency;
+               break;
+       case low_latency:
+               if (bytes_perint > adapter->eitr_high)
+                       retval = bulk_latency;
+               else if (bytes_perint <= adapter->eitr_low)
+                       retval = lowest_latency;
+               break;
+       case bulk_latency:
+               if (bytes_perint <= adapter->eitr_high)
+                       retval = low_latency;
+               break;
+       }
+
+update_itr_done:
+       return retval;
+}
+
+/**
+ * ixgbevf_write_eitr - write VTEITR register in hardware specific way
+ * @adapter: pointer to adapter struct
+ * @v_idx: vector index into q_vector array
+ * @itr_reg: new value to be written in *register* format, not ints/s
+ *
+ * This function is made to be called by ethtool and by the driver
+ * when it needs to update VTEITR registers at runtime.  Hardware
+ * specific quirks/differences are taken care of here.
+ */
+static void ixgbevf_write_eitr(struct ixgbevf_adapter *adapter, int v_idx,
+                              u32 itr_reg)
+{
+       struct ixgbe_hw *hw = &adapter->hw;
+
+       itr_reg = EITR_INTS_PER_SEC_TO_REG(itr_reg);
+
+       /*
+        * set the WDIS bit to not clear the timer bits and cause an
+        * immediate assertion of the interrupt
+        */
+       itr_reg |= IXGBE_EITR_CNT_WDIS;
+
+       IXGBE_WRITE_REG(hw, IXGBE_VTEITR(v_idx), itr_reg);
+}
+
+static void ixgbevf_set_itr_msix(struct ixgbevf_q_vector *q_vector)
+{
+       struct ixgbevf_adapter *adapter = q_vector->adapter;
+       u32 new_itr;
+       u8 current_itr, ret_itr;
+       int i, r_idx, v_idx = q_vector->v_idx;
+       struct ixgbevf_ring *rx_ring, *tx_ring;
+
+       r_idx = find_first_bit(q_vector->txr_idx, adapter->num_tx_queues);
+       for (i = 0; i < q_vector->txr_count; i++) {
+               tx_ring = &(adapter->tx_ring[r_idx]);
+               ret_itr = ixgbevf_update_itr(adapter, q_vector->eitr,
+                                            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);
+               r_idx = find_next_bit(q_vector->txr_idx, adapter->num_tx_queues,
+                                     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 = ixgbevf_update_itr(adapter, q_vector->eitr,
+                                            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);
+               r_idx = find_next_bit(q_vector->rxr_idx, adapter->num_rx_queues,
+                                     r_idx + 1);
+       }
+
+       current_itr = max(q_vector->rx_itr, q_vector->tx_itr);
+
+       switch (current_itr) {
+       /* counts and packets in update_itr are dependent on these numbers */
+       case lowest_latency:
+               new_itr = 100000;
+               break;
+       case low_latency:
+               new_itr = 20000; /* aka hwitr = ~200 */
+               break;
+       case bulk_latency:
+       default:
+               new_itr = 8000;
+               break;
+       }
+
+       if (new_itr != q_vector->eitr) {
+               u32 itr_reg;
+
+               /* save the algorithm value here, not the smoothed one */
+               q_vector->eitr = new_itr;
+               /* do an exponential smoothing */
+               new_itr = ((q_vector->eitr * 90)/100) + ((new_itr * 10)/100);
+               itr_reg = EITR_INTS_PER_SEC_TO_REG(new_itr);
+               ixgbevf_write_eitr(adapter, v_idx, itr_reg);
+       }
+
+       return;
+}
+
+static irqreturn_t ixgbevf_msix_mbx(int irq, void *data)
+{
+       struct net_device *netdev = data;
+       struct ixgbevf_adapter *adapter = netdev_priv(netdev);
+       struct ixgbe_hw *hw = &adapter->hw;
+       u32 eicr;
+       u32 msg;
+
+       eicr = IXGBE_READ_REG(hw, IXGBE_VTEICS);
+       IXGBE_WRITE_REG(hw, IXGBE_VTEICR, eicr);
+
+       hw->mbx.ops.read(hw, &msg, 1);
+
+       if ((msg & IXGBE_MBVFICR_VFREQ_MASK) == IXGBE_PF_CONTROL_MSG)
+               mod_timer(&adapter->watchdog_timer,
+                         round_jiffies(jiffies + 10));
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t ixgbevf_msix_clean_tx(int irq, void *data)
+{
+       struct ixgbevf_q_vector *q_vector = data;
+       struct ixgbevf_adapter  *adapter = q_vector->adapter;
+       struct ixgbevf_ring     *tx_ring;
+       int i, r_idx;
+
+       if (!q_vector->txr_count)
+               return IRQ_HANDLED;
+
+       r_idx = find_first_bit(q_vector->txr_idx, adapter->num_tx_queues);
+       for (i = 0; i < q_vector->txr_count; i++) {
+               tx_ring = &(adapter->tx_ring[r_idx]);
+               tx_ring->total_bytes = 0;
+               tx_ring->total_packets = 0;
+               ixgbevf_clean_tx_irq(adapter, tx_ring);
+               r_idx = find_next_bit(q_vector->txr_idx, adapter->num_tx_queues,
+                                     r_idx + 1);
+       }
+
+       if (adapter->itr_setting & 1)
+               ixgbevf_set_itr_msix(q_vector);
+
+       return IRQ_HANDLED;
+}
+
+/**
+ * ixgbe_msix_clean_rx - single unshared vector rx clean (all queues)
+ * @irq: unused
+ * @data: pointer to our q_vector struct for this interrupt vector
+ **/
+static irqreturn_t ixgbevf_msix_clean_rx(int irq, void *data)
+{
+       struct ixgbevf_q_vector *q_vector = data;
+       struct ixgbevf_adapter  *adapter = q_vector->adapter;
+       struct ixgbe_hw *hw = &adapter->hw;
+       struct ixgbevf_ring  *rx_ring;
+       int r_idx;
+       int i;
+
+       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]);
+               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);
+       }
+
+       if (!q_vector->rxr_count)
+               return IRQ_HANDLED;
+
+       r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues);
+       rx_ring = &(adapter->rx_ring[r_idx]);
+       /* disable interrupts on this vector only */
+       IXGBE_WRITE_REG(hw, IXGBE_VTEIMC, rx_ring->v_idx);
+       napi_schedule(&q_vector->napi);
+
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t ixgbevf_msix_clean_many(int irq, void *data)
+{
+       ixgbevf_msix_clean_rx(irq, data);
+       ixgbevf_msix_clean_tx(irq, data);
+
+       return IRQ_HANDLED;
+}
+
+static inline void map_vector_to_rxq(struct ixgbevf_adapter *a, int v_idx,
+                                    int r_idx)
+{
+       struct ixgbevf_q_vector *q_vector = a->q_vector[v_idx];
+
+       set_bit(r_idx, q_vector->rxr_idx);
+       q_vector->rxr_count++;
+       a->rx_ring[r_idx].v_idx = 1 << v_idx;
+}
+
+static inline void map_vector_to_txq(struct ixgbevf_adapter *a, int v_idx,
+                                    int t_idx)
+{
+       struct ixgbevf_q_vector *q_vector = a->q_vector[v_idx];
+
+       set_bit(t_idx, q_vector->txr_idx);
+       q_vector->txr_count++;
+       a->tx_ring[t_idx].v_idx = 1 << v_idx;
+}
+
+/**
+ * ixgbevf_map_rings_to_vectors - Maps descriptor rings to vectors
+ * @adapter: board private structure to initialize
+ *
+ * This function maps descriptor rings to the queue-specific vectors
+ * we were allotted through the MSI-X enabling code.  Ideally, we'd have
+ * one vector per ring/queue, but on a constrained vector budget, we
+ * group the rings as "efficiently" as possible.  You would add new
+ * mapping configurations in here.
+ **/
+static int ixgbevf_map_rings_to_vectors(struct ixgbevf_adapter *adapter)
+{
+       int q_vectors;
+       int v_start = 0;
+       int rxr_idx = 0, txr_idx = 0;
+       int rxr_remaining = adapter->num_rx_queues;
+       int txr_remaining = adapter->num_tx_queues;
+       int i, j;
+       int rqpv, tqpv;
+       int err = 0;
+
+       q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS;
+
+       /*
+        * The ideal configuration...
+        * We have enough vectors to map one per queue.
+        */
+       if (q_vectors == adapter->num_rx_queues + adapter->num_tx_queues) {
+               for (; rxr_idx < rxr_remaining; v_start++, rxr_idx++)
+                       map_vector_to_rxq(adapter, v_start, rxr_idx);
+
+               for (; txr_idx < txr_remaining; v_start++, txr_idx++)
+                       map_vector_to_txq(adapter, v_start, txr_idx);
+               goto out;
+       }
+
+       /*
+        * If we don't have enough vectors for a 1-to-1
+        * mapping, we'll have to group them so there are
+        * multiple queues per vector.
+        */
+       /* Re-adjusting *qpv takes care of the remainder. */
+       for (i = v_start; i < q_vectors; i++) {
+               rqpv = DIV_ROUND_UP(rxr_remaining, q_vectors - i);
+               for (j = 0; j < rqpv; j++) {
+                       map_vector_to_rxq(adapter, i, rxr_idx);
+                       rxr_idx++;
+                       rxr_remaining--;
+               }
+       }
+       for (i = v_start; i < q_vectors; i++) {
+               tqpv = DIV_ROUND_UP(txr_remaining, q_vectors - i);
+               for (j = 0; j < tqpv; j++) {
+                       map_vector_to_txq(adapter, i, txr_idx);
+                       txr_idx++;
+                       txr_remaining--;
+               }
+       }
+
+out:
+       return err;
+}
+
+/**
+ * ixgbevf_request_msix_irqs - Initialize MSI-X interrupts
+ * @adapter: board private structure
+ *
+ * ixgbevf_request_msix_irqs allocates MSI-X vectors and requests
+ * interrupts from the kernel.
+ **/
+static int ixgbevf_request_msix_irqs(struct ixgbevf_adapter *adapter)
+{
+       struct net_device *netdev = adapter->netdev;
+       irqreturn_t (*handler)(int, void *);
+       int i, vector, q_vectors, err;
+       int ri = 0, ti = 0;
+
+       /* Decrement for Other and TCP Timer vectors */
+       q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS;
+
+#define SET_HANDLER(_v) (((_v)->rxr_count && (_v)->txr_count)          \
+                                         ? &ixgbevf_msix_clean_many : \
+                         (_v)->rxr_count ? &ixgbevf_msix_clean_rx   : \
+                         (_v)->txr_count ? &ixgbevf_msix_clean_tx   : \
+                         NULL)
+       for (vector = 0; vector < q_vectors; vector++) {
+               handler = SET_HANDLER(adapter->q_vector[vector]);
+
+               if (handler == &ixgbevf_msix_clean_rx) {
+                       sprintf(adapter->name[vector], "%s-%s-%d",
+                               netdev->name, "rx", ri++);
+               } else if (handler == &ixgbevf_msix_clean_tx) {
+                       sprintf(adapter->name[vector], "%s-%s-%d",
+                               netdev->name, "tx", ti++);
+               } else if (handler == &ixgbevf_msix_clean_many) {
+                       sprintf(adapter->name[vector], "%s-%s-%d",
+                               netdev->name, "TxRx", vector);
+               } else {
+                       /* skip this unused q_vector */
+                       continue;
+               }
+               err = request_irq(adapter->msix_entries[vector].vector,
+                                 handler, 0, adapter->name[vector],
+                                 adapter->q_vector[vector]);
+               if (err) {
+                       hw_dbg(&adapter->hw,
+                              "request_irq failed for MSIX interrupt "
+                              "Error: %d\n", err);
+                       goto free_queue_irqs;
+               }
+       }
+
+       sprintf(adapter->name[vector], "%s:mbx", netdev->name);
+       err = request_irq(adapter->msix_entries[vector].vector,
+                         &ixgbevf_msix_mbx, 0, adapter->name[vector], netdev);
+       if (err) {
+               hw_dbg(&adapter->hw,
+                      "request_irq for msix_mbx failed: %d\n", err);
+               goto free_queue_irqs;
+       }
+
+       return 0;
+
+free_queue_irqs:
+       for (i = vector - 1; i >= 0; i--)
+               free_irq(adapter->msix_entries[--vector].vector,
+                        &(adapter->q_vector[i]));
+       pci_disable_msix(adapter->pdev);
+       kfree(adapter->msix_entries);
+       adapter->msix_entries = NULL;
+       return err;
+}
+
+static inline void ixgbevf_reset_q_vectors(struct ixgbevf_adapter *adapter)
+{
+       int i, q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS;
+
+       for (i = 0; i < q_vectors; i++) {
+               struct ixgbevf_q_vector *q_vector = adapter->q_vector[i];
+               bitmap_zero(q_vector->rxr_idx, MAX_RX_QUEUES);
+               bitmap_zero(q_vector->txr_idx, MAX_TX_QUEUES);
+               q_vector->rxr_count = 0;
+               q_vector->txr_count = 0;
+               q_vector->eitr = adapter->eitr_param;
+       }
+}
+
+/**
+ * ixgbevf_request_irq - initialize interrupts
+ * @adapter: board private structure
+ *
+ * Attempts to configure interrupts using the best available
+ * capabilities of the hardware and kernel.
+ **/
+static int ixgbevf_request_irq(struct ixgbevf_adapter *adapter)
+{
+       int err = 0;
+
+       err = ixgbevf_request_msix_irqs(adapter);
+
+       if (err)
+               hw_dbg(&adapter->hw,
+                      "request_irq failed, Error %d\n", err);
+
+       return err;
+}
+
+static void ixgbevf_free_irq(struct ixgbevf_adapter *adapter)
+{
+       struct net_device *netdev = adapter->netdev;
+       int i, q_vectors;
+
+       q_vectors = adapter->num_msix_vectors;
+
+       i = q_vectors - 1;
+
+       free_irq(adapter->msix_entries[i].vector, netdev);
+       i--;
+
+       for (; i >= 0; i--) {
+               free_irq(adapter->msix_entries[i].vector,
+                        adapter->q_vector[i]);
+       }
+
+       ixgbevf_reset_q_vectors(adapter);
+}
+
+/**
+ * ixgbevf_irq_disable - Mask off interrupt generation on the NIC
+ * @adapter: board private structure
+ **/
+static inline void ixgbevf_irq_disable(struct ixgbevf_adapter *adapter)
+{
+       int i;
+       struct ixgbe_hw *hw = &adapter->hw;
+
+       IXGBE_WRITE_REG(hw, IXGBE_VTEIMC, ~0);
+
+       IXGBE_WRITE_FLUSH(hw);
+
+       for (i = 0; i < adapter->num_msix_vectors; i++)
+               synchronize_irq(adapter->msix_entries[i].vector);
+}
+
+/**
+ * ixgbevf_irq_enable - Enable default interrupt generation settings
+ * @adapter: board private structure
+ **/
+static inline void ixgbevf_irq_enable(struct ixgbevf_adapter *adapter,
+                                     bool queues, bool flush)
+{
+       struct ixgbe_hw *hw = &adapter->hw;
+       u32 mask;
+       u64 qmask;
+
+       mask = (IXGBE_EIMS_ENABLE_MASK & ~IXGBE_EIMS_RTX_QUEUE);
+       qmask = ~0;
+
+       IXGBE_WRITE_REG(hw, IXGBE_VTEIMS, mask);
+
+       if (queues)
+               ixgbevf_irq_enable_queues(adapter, qmask);
+
+       if (flush)
+               IXGBE_WRITE_FLUSH(hw);
+}
+
+/**
+ * ixgbevf_configure_tx - Configure 82599 VF Transmit Unit after Reset
+ * @adapter: board private structure
+ *
+ * Configure the Tx unit of the MAC after a reset.
+ **/
+static void ixgbevf_configure_tx(struct ixgbevf_adapter *adapter)
+{
+       u64 tdba;
+       struct ixgbe_hw *hw = &adapter->hw;
+       u32 i, j, tdlen, txctrl;
+
+       /* Setup the HW Tx Head and Tail descriptor pointers */
+       for (i = 0; i < adapter->num_tx_queues; i++) {
+               struct ixgbevf_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_VFTDBAL(j),
+                               (tdba & DMA_BIT_MASK(32)));
+               IXGBE_WRITE_REG(hw, IXGBE_VFTDBAH(j), (tdba >> 32));
+               IXGBE_WRITE_REG(hw, IXGBE_VFTDLEN(j), tdlen);
+               IXGBE_WRITE_REG(hw, IXGBE_VFTDH(j), 0);
+               IXGBE_WRITE_REG(hw, IXGBE_VFTDT(j), 0);
+               adapter->tx_ring[i].head = IXGBE_VFTDH(j);
+               adapter->tx_ring[i].tail = IXGBE_VFTDT(j);
+               /* Disable Tx Head Writeback RO bit, since this hoses
+                * bookkeeping if things aren't delivered in order.
+                */
+               txctrl = IXGBE_READ_REG(hw, IXGBE_VFDCA_TXCTRL(j));
+               txctrl &= ~IXGBE_DCA_TXCTRL_TX_WB_RO_EN;
+               IXGBE_WRITE_REG(hw, IXGBE_VFDCA_TXCTRL(j), txctrl);
+       }
+}
+
+#define IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT        2
+
+static void ixgbevf_configure_srrctl(struct ixgbevf_adapter *adapter, int index)
+{
+       struct ixgbevf_ring *rx_ring;
+       struct ixgbe_hw *hw = &adapter->hw;
+       u32 srrctl;
+
+       rx_ring = &adapter->rx_ring[index];
+
+       srrctl = IXGBE_SRRCTL_DROP_EN;
+
+       if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) {
+               u16 bufsz = IXGBEVF_RXBUFFER_2048;
+               /* grow the amount we can receive on large page machines */
+               if (bufsz < (PAGE_SIZE / 2))
+                       bufsz = (PAGE_SIZE / 2);
+               /* cap the bufsz at our largest descriptor size */
+               bufsz = min((u16)IXGBEVF_MAX_RXBUFFER, bufsz);
+
+               srrctl |= bufsz >> IXGBE_SRRCTL_BSIZEPKT_SHIFT;
+               srrctl |= IXGBE_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS;
+               srrctl |= ((IXGBEVF_RX_HDR_SIZE <<
+                          IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT) &
+                          IXGBE_SRRCTL_BSIZEHDR_MASK);
+       } else {
+               srrctl |= IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF;
+
+               if (rx_ring->rx_buf_len == MAXIMUM_ETHERNET_VLAN_SIZE)
+                       srrctl |= IXGBEVF_RXBUFFER_2048 >>
+                               IXGBE_SRRCTL_BSIZEPKT_SHIFT;
+               else
+                       srrctl |= rx_ring->rx_buf_len >>
+                               IXGBE_SRRCTL_BSIZEPKT_SHIFT;
+       }
+       IXGBE_WRITE_REG(hw, IXGBE_VFSRRCTL(index), srrctl);
+}
+
+/**
+ * ixgbevf_configure_rx - Configure 82599 VF Receive Unit after Reset
+ * @adapter: board private structure
+ *
+ * Configure the Rx unit of the MAC after a reset.
+ **/
+static void ixgbevf_configure_rx(struct ixgbevf_adapter *adapter)
+{
+       u64 rdba;
+       struct ixgbe_hw *hw = &adapter->hw;
+       struct net_device *netdev = adapter->netdev;
+       int max_frame = netdev->mtu + ETH_HLEN + ETH_FCS_LEN;
+       int i, j;
+       u32 rdlen;
+       int rx_buf_len;
+
+       /* Decide whether to use packet split mode or not */
+       if (netdev->mtu > ETH_DATA_LEN) {
+               if (adapter->flags & IXGBE_FLAG_RX_PS_CAPABLE)
+                       adapter->flags |= IXGBE_FLAG_RX_PS_ENABLED;
+               else
+                       adapter->flags &= ~IXGBE_FLAG_RX_PS_ENABLED;
+       } else {
+               if (adapter->flags & IXGBE_FLAG_RX_1BUF_CAPABLE)
+                       adapter->flags &= ~IXGBE_FLAG_RX_PS_ENABLED;
+               else
+                       adapter->flags |= IXGBE_FLAG_RX_PS_ENABLED;
+       }
+
+       /* Set the RX buffer length according to the mode */
+       if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) {
+               /* 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_VFPSRTYPE, psrtype);
+               rx_buf_len = IXGBEVF_RX_HDR_SIZE;
+       } else {
+               IXGBE_WRITE_REG(hw, IXGBE_VFPSRTYPE, 0);
+               if (netdev->mtu <= ETH_DATA_LEN)
+                       rx_buf_len = MAXIMUM_ETHERNET_VLAN_SIZE;
+               else
+                       rx_buf_len = ALIGN(max_frame, 1024);
+       }
+
+       rdlen = adapter->rx_ring[0].count * sizeof(union ixgbe_adv_rx_desc);
+       /* 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++) {
+               rdba = adapter->rx_ring[i].dma;
+               j = adapter->rx_ring[i].reg_idx;
+               IXGBE_WRITE_REG(hw, IXGBE_VFRDBAL(j),
+                               (rdba & DMA_BIT_MASK(32)));
+               IXGBE_WRITE_REG(hw, IXGBE_VFRDBAH(j), (rdba >> 32));
+               IXGBE_WRITE_REG(hw, IXGBE_VFRDLEN(j), rdlen);
+               IXGBE_WRITE_REG(hw, IXGBE_VFRDH(j), 0);
+               IXGBE_WRITE_REG(hw, IXGBE_VFRDT(j), 0);
+               adapter->rx_ring[i].head = IXGBE_VFRDH(j);
+               adapter->rx_ring[i].tail = IXGBE_VFRDT(j);
+               adapter->rx_ring[i].rx_buf_len = rx_buf_len;
+
+               ixgbevf_configure_srrctl(adapter, j);
+       }
+}
+
+static void ixgbevf_vlan_rx_register(struct net_device *netdev,
+                                    struct vlan_group *grp)
+{
+       struct ixgbevf_adapter *adapter = netdev_priv(netdev);
+       struct ixgbe_hw *hw = &adapter->hw;
+       int i, j;
+       u32 ctrl;
+
+       adapter->vlgrp = grp;
+
+       for (i = 0; i < adapter->num_rx_queues; i++) {
+               j = adapter->rx_ring[i].reg_idx;
+               ctrl = IXGBE_READ_REG(hw, IXGBE_VFRXDCTL(j));
+               ctrl |= IXGBE_RXDCTL_VME;
+               IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(j), ctrl);
+       }
+}
+
+static void ixgbevf_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
+{
+       struct ixgbevf_adapter *adapter = netdev_priv(netdev);
+       struct ixgbe_hw *hw = &adapter->hw;
+       struct net_device *v_netdev;
+
+       /* add VID to filter table */
+       if (hw->mac.ops.set_vfta)
+               hw->mac.ops.set_vfta(hw, vid, 0, true);
+       /*
+        * Copy feature flags from netdev to the vlan netdev for this vid.
+        * This allows things like TSO to bubble down to our vlan device.
+        */
+       v_netdev = vlan_group_get_device(adapter->vlgrp, vid);
+       v_netdev->features |= adapter->netdev->features;
+       vlan_group_set_device(adapter->vlgrp, vid, v_netdev);
+}
+
+static void ixgbevf_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
+{
+       struct ixgbevf_adapter *adapter = netdev_priv(netdev);
+       struct ixgbe_hw *hw = &adapter->hw;
+
+       if (!test_bit(__IXGBEVF_DOWN, &adapter->state))
+               ixgbevf_irq_disable(adapter);
+
+       vlan_group_set_device(adapter->vlgrp, vid, NULL);
+
+       if (!test_bit(__IXGBEVF_DOWN, &adapter->state))
+               ixgbevf_irq_enable(adapter, true, true);
+
+       /* remove VID from filter table */
+       if (hw->mac.ops.set_vfta)
+               hw->mac.ops.set_vfta(hw, vid, 0, false);
+}
+
+static void ixgbevf_restore_vlan(struct ixgbevf_adapter *adapter)
+{
+       ixgbevf_vlan_rx_register(adapter->netdev, adapter->vlgrp);
+
+       if (adapter->vlgrp) {
+               u16 vid;
+               for (vid = 0; vid < VLAN_GROUP_ARRAY_LEN; vid++) {
+                       if (!vlan_group_get_device(adapter->vlgrp, vid))
+                               continue;
+                       ixgbevf_vlan_rx_add_vid(adapter->netdev, vid);
+               }
+       }
+}
+
+static u8 *ixgbevf_addr_list_itr(struct ixgbe_hw *hw, u8 **mc_addr_ptr,
+                                u32 *vmdq)
+{
+       struct dev_mc_list *mc_ptr;
+       u8 *addr = *mc_addr_ptr;
+       *vmdq = 0;
+
+       mc_ptr = container_of(addr, struct dev_mc_list, dmi_addr[0]);
+       if (mc_ptr->next)
+               *mc_addr_ptr = mc_ptr->next->dmi_addr;
+       else
+               *mc_addr_ptr = NULL;
+
+       return addr;
+}
+
+/**
+ * ixgbevf_set_rx_mode - Multicast set
+ * @netdev: network interface device structure
+ *
+ * The set_rx_method entry point is called whenever the multicast address
+ * list or the network interface flags are updated.  This routine is
+ * responsible for configuring the hardware for proper multicast mode.
+ **/
+static void ixgbevf_set_rx_mode(struct net_device *netdev)
+{
+       struct ixgbevf_adapter *adapter = netdev_priv(netdev);
+       struct ixgbe_hw *hw = &adapter->hw;
+       u8 *addr_list = NULL;
+       int addr_count = 0;
+
+       /* reprogram multicast list */
+       addr_count = netdev->mc_count;
+       if (addr_count)
+               addr_list = netdev->mc_list->dmi_addr;
+       if (hw->mac.ops.update_mc_addr_list)
+               hw->mac.ops.update_mc_addr_list(hw, addr_list, addr_count,
+                                               ixgbevf_addr_list_itr);
+}
+
+static void ixgbevf_napi_enable_all(struct ixgbevf_adapter *adapter)
+{
+       int q_idx;
+       struct ixgbevf_q_vector *q_vector;
+       int q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS;
+
+       for (q_idx = 0; q_idx < q_vectors; q_idx++) {
+               struct napi_struct *napi;
+               q_vector = adapter->q_vector[q_idx];
+               if (!q_vector->rxr_count)
+                       continue;
+               napi = &q_vector->napi;
+               if (q_vector->rxr_count > 1)
+                       napi->poll = &ixgbevf_clean_rxonly_many;
+
+               napi_enable(napi);
+       }
+}
+
+static void ixgbevf_napi_disable_all(struct ixgbevf_adapter *adapter)
+{
+       int q_idx;
+       struct ixgbevf_q_vector *q_vector;
+       int q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS;
+
+       for (q_idx = 0; q_idx < q_vectors; q_idx++) {
+               q_vector = adapter->q_vector[q_idx];
+               if (!q_vector->rxr_count)
+                       continue;
+               napi_disable(&q_vector->napi);
+       }
+}
+
+static void ixgbevf_configure(struct ixgbevf_adapter *adapter)
+{
+       struct net_device *netdev = adapter->netdev;
+       int i;
+
+       ixgbevf_set_rx_mode(netdev);
+
+       ixgbevf_restore_vlan(adapter);
+
+       ixgbevf_configure_tx(adapter);
+       ixgbevf_configure_rx(adapter);
+       for (i = 0; i < adapter->num_rx_queues; i++) {
+               struct ixgbevf_ring *ring = &adapter->rx_ring[i];
+               ixgbevf_alloc_rx_buffers(adapter, ring, ring->count);
+               ring->next_to_use = ring->count - 1;
+               writel(ring->next_to_use, adapter->hw.hw_addr + ring->tail);
+       }
+}
+
+#define IXGBE_MAX_RX_DESC_POLL 10
+static inline void ixgbevf_rx_desc_queue_enable(struct ixgbevf_adapter *adapter,
+                                               int rxr)
+{
+       struct ixgbe_hw *hw = &adapter->hw;
+       int j = adapter->rx_ring[rxr].reg_idx;
+       int k;
+
+       for (k = 0; k < IXGBE_MAX_RX_DESC_POLL; k++) {
+               if (IXGBE_READ_REG(hw, IXGBE_VFRXDCTL(j)) & IXGBE_RXDCTL_ENABLE)
+                       break;
+               else
+                       msleep(1);
+       }
+       if (k >= IXGBE_MAX_RX_DESC_POLL) {
+               hw_dbg(hw, "RXDCTL.ENABLE on Rx queue %d "
+                      "not set within the polling period\n", rxr);
+       }
+
+       ixgbevf_release_rx_desc(&adapter->hw, &adapter->rx_ring[rxr],
+                               (adapter->rx_ring[rxr].count - 1));
+}
+
+static int ixgbevf_up_complete(struct ixgbevf_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;
+       u32 txdctl, rxdctl;
+
+       for (i = 0; i < adapter->num_tx_queues; i++) {
+               j = adapter->tx_ring[i].reg_idx;
+               txdctl = IXGBE_READ_REG(hw, IXGBE_VFTXDCTL(j));
+               /* enable WTHRESH=8 descriptors, to encourage burst writeback */
+               txdctl |= (8 << 16);
+               IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(j), txdctl);
+       }
+
+       for (i = 0; i < adapter->num_tx_queues; i++) {
+               j = adapter->tx_ring[i].reg_idx;
+               txdctl = IXGBE_READ_REG(hw, IXGBE_VFTXDCTL(j));
+               txdctl |= IXGBE_TXDCTL_ENABLE;
+               IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(j), txdctl);
+       }
+
+       for (i = 0; i < num_rx_rings; i++) {
+               j = adapter->rx_ring[i].reg_idx;
+               rxdctl = IXGBE_READ_REG(hw, IXGBE_VFRXDCTL(j));
+               rxdctl |= IXGBE_RXDCTL_ENABLE;
+               IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(j), rxdctl);
+               ixgbevf_rx_desc_queue_enable(adapter, i);
+       }
+
+       ixgbevf_configure_msix(adapter);
+
+       if (hw->mac.ops.set_rar) {
+               if (is_valid_ether_addr(hw->mac.addr))
+                       hw->mac.ops.set_rar(hw, 0, hw->mac.addr, 0);
+               else
+                       hw->mac.ops.set_rar(hw, 0, hw->mac.perm_addr, 0);
+       }
+
+       clear_bit(__IXGBEVF_DOWN, &adapter->state);
+       ixgbevf_napi_enable_all(adapter);
+
+       /* enable transmits */
+       netif_tx_start_all_queues(netdev);
+
+       /* bring the link up in the watchdog, this could race with our first
+        * link up interrupt but shouldn't be a problem */
+       adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE;
+       adapter->link_check_timeout = jiffies;
+       mod_timer(&adapter->watchdog_timer, jiffies);
+       return 0;
+}
+
+int ixgbevf_up(struct ixgbevf_adapter *adapter)
+{
+       int err;
+       struct ixgbe_hw *hw = &adapter->hw;
+
+       ixgbevf_configure(adapter);
+
+       err = ixgbevf_up_complete(adapter);
+
+       /* clear any pending interrupts, may auto mask */
+       IXGBE_READ_REG(hw, IXGBE_VTEICR);
+
+       ixgbevf_irq_enable(adapter, true, true);
+
+       return err;
+}
+
+/**
+ * ixgbevf_clean_rx_ring - Free Rx Buffers per Queue
+ * @adapter: board private structure
+ * @rx_ring: ring to free buffers from
+ **/
+static void ixgbevf_clean_rx_ring(struct ixgbevf_adapter *adapter,
+                                 struct ixgbevf_ring *rx_ring)
+{
+       struct pci_dev *pdev = adapter->pdev;
+       unsigned long size;
+       unsigned int i;
+
+       if (!rx_ring->rx_buffer_info)
+               return;
+
+       /* Free all the Rx ring sk_buffs */
+       for (i = 0; i < rx_ring->count; i++) {
+               struct ixgbevf_rx_buffer *rx_buffer_info;
+
+               rx_buffer_info = &rx_ring->rx_buffer_info[i];
+               if (rx_buffer_info->dma) {
+                       pci_unmap_single(pdev, rx_buffer_info->dma,
+                                        rx_ring->rx_buf_len,
+                                        PCI_DMA_FROMDEVICE);
+                       rx_buffer_info->dma = 0;
+               }
+               if (rx_buffer_info->skb) {
+                       struct sk_buff *skb = rx_buffer_info->skb;
+                       rx_buffer_info->skb = NULL;
+                       do {
+                               struct sk_buff *this = skb;
+                               skb = skb->prev;
+                               dev_kfree_skb(this);
+                       } while (skb);
+               }
+               if (!rx_buffer_info->page)
+                       continue;
+               pci_unmap_page(pdev, rx_buffer_info->page_dma, PAGE_SIZE / 2,
+                              PCI_DMA_FROMDEVICE);
+               rx_buffer_info->page_dma = 0;
+               put_page(rx_buffer_info->page);
+               rx_buffer_info->page = NULL;
+               rx_buffer_info->page_offset = 0;
+       }
+
+       size = sizeof(struct ixgbevf_rx_buffer) * rx_ring->count;
+       memset(rx_ring->rx_buffer_info, 0, size);
+
+       /* Zero out the descriptor ring */
+       memset(rx_ring->desc, 0, rx_ring->size);
+
+       rx_ring->next_to_clean = 0;
+       rx_ring->next_to_use = 0;
+
+       if (rx_ring->head)
+               writel(0, adapter->hw.hw_addr + rx_ring->head);
+       if (rx_ring->tail)
+               writel(0, adapter->hw.hw_addr + rx_ring->tail);
+}
+
+/**
+ * ixgbevf_clean_tx_ring - Free Tx Buffers
+ * @adapter: board private structure
+ * @tx_ring: ring to be cleaned
+ **/
+static void ixgbevf_clean_tx_ring(struct ixgbevf_adapter *adapter,
+                                 struct ixgbevf_ring *tx_ring)
+{
+       struct ixgbevf_tx_buffer *tx_buffer_info;
+       unsigned long size;
+       unsigned int i;
+
+       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];
+               ixgbevf_unmap_and_free_tx_resource(adapter, tx_buffer_info);
+       }
+
+       size = sizeof(struct ixgbevf_tx_buffer) * tx_ring->count;
+       memset(tx_ring->tx_buffer_info, 0, size);
+
+       memset(tx_ring->desc, 0, tx_ring->size);
+
+       tx_ring->next_to_use = 0;
+       tx_ring->next_to_clean = 0;
+
+       if (tx_ring->head)
+               writel(0, adapter->hw.hw_addr + tx_ring->head);
+       if (tx_ring->tail)
+               writel(0, adapter->hw.hw_addr + tx_ring->tail);
+}
+
+/**
+ * ixgbevf_clean_all_rx_rings - Free Rx Buffers for all queues
+ * @adapter: board private structure
+ **/
+static void ixgbevf_clean_all_rx_rings(struct ixgbevf_adapter *adapter)
+{
+       int i;
+
+       for (i = 0; i < adapter->num_rx_queues; i++)
+               ixgbevf_clean_rx_ring(adapter, &adapter->rx_ring[i]);
+}
+
+/**
+ * ixgbevf_clean_all_tx_rings - Free Tx Buffers for all queues
+ * @adapter: board private structure
+ **/
+static void ixgbevf_clean_all_tx_rings(struct ixgbevf_adapter *adapter)
+{
+       int i;
+
+       for (i = 0; i < adapter->num_tx_queues; i++)
+               ixgbevf_clean_tx_ring(adapter, &adapter->tx_ring[i]);
+}
+
+void ixgbevf_down(struct ixgbevf_adapter *adapter)
+{
+       struct net_device *netdev = adapter->netdev;
+       struct ixgbe_hw *hw = &adapter->hw;
+       u32 txdctl;
+       int i, j;
+
+       /* signal that we are down to the interrupt handler */
+       set_bit(__IXGBEVF_DOWN, &adapter->state);
+       /* disable receives */
+
+       netif_tx_disable(netdev);
+
+       msleep(10);
+
+       netif_tx_stop_all_queues(netdev);
+
+       ixgbevf_irq_disable(adapter);
+
+       ixgbevf_napi_disable_all(adapter);
+
+       del_timer_sync(&adapter->watchdog_timer);
+       /* can't call flush scheduled work here because it can deadlock
+        * if linkwatch_event tries to acquire the rtnl_lock which we are
+        * holding */
+       while (adapter->flags & IXGBE_FLAG_IN_WATCHDOG_TASK)
+               msleep(1);
+
+       /* disable transmits in the hardware now that interrupts are off */
+       for (i = 0; i < adapter->num_tx_queues; i++) {
+               j = adapter->tx_ring[i].reg_idx;
+               txdctl = IXGBE_READ_REG(hw, IXGBE_VFTXDCTL(j));
+               IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(j),
+                               (txdctl & ~IXGBE_TXDCTL_ENABLE));
+       }
+
+       netif_carrier_off(netdev);
+
+       if (!pci_channel_offline(adapter->pdev))
+               ixgbevf_reset(adapter);
+
+       ixgbevf_clean_all_tx_rings(adapter);
+       ixgbevf_clean_all_rx_rings(adapter);
+}
+
+void ixgbevf_reinit_locked(struct ixgbevf_adapter *adapter)
+{
+       struct ixgbe_hw *hw = &adapter->hw;
+
+       WARN_ON(in_interrupt());
+
+       while (test_and_set_bit(__IXGBEVF_RESETTING, &adapter->state))
+               msleep(1);
+
+       /*
+        * Check if PF is up before re-init.  If not then skip until
+        * later when the PF is up and ready to service requests from
+        * the VF via mailbox.  If the VF is up and running then the
+        * watchdog task will continue to schedule reset tasks until
+        * the PF is up and running.
+        */
+       if (!hw->mac.ops.reset_hw(hw)) {
+               ixgbevf_down(adapter);
+               ixgbevf_up(adapter);
+       }
+
+       clear_bit(__IXGBEVF_RESETTING, &adapter->state);
+}
+
+void ixgbevf_reset(struct ixgbevf_adapter *adapter)
+{
+       struct ixgbe_hw *hw = &adapter->hw;
+       struct net_device *netdev = adapter->netdev;
+
+       if (hw->mac.ops.reset_hw(hw))
+               hw_dbg(hw, "PF still resetting\n");
+       else
+               hw->mac.ops.init_hw(hw);
+
+       if (is_valid_ether_addr(adapter->hw.mac.addr)) {
+               memcpy(netdev->dev_addr, adapter->hw.mac.addr,
+                      netdev->addr_len);
+               memcpy(netdev->perm_addr, adapter->hw.mac.addr,
+                      netdev->addr_len);
+       }
+}
+
+static void ixgbevf_acquire_msix_vectors(struct ixgbevf_adapter *adapter,
+                                        int vectors)
+{
+       int err, vector_threshold;
+
+       /* We'll want at least 3 (vector_threshold):
+        * 1) TxQ[0] Cleanup
+        * 2) RxQ[0] Cleanup
+        * 3) Other (Link Status Change, etc.)
+        */
+       vector_threshold = MIN_MSIX_COUNT;
+
+       /* The more we get, the more we will assign to Tx/Rx Cleanup
+        * for the separate queues...where Rx Cleanup >= Tx Cleanup.
+        * Right now, we simply care about how many we'll get; we'll
+        * set them up later while requesting irq's.
+        */
+       while (vectors >= vector_threshold) {
+               err = pci_enable_msix(adapter->pdev, adapter->msix_entries,
+                                     vectors);
+               if (!err) /* Success in acquiring all requested vectors. */
+                       break;
+               else if (err < 0)
+                       vectors = 0; /* Nasty failure, quit now */
+               else /* err == number of vectors we should try again with */
+                       vectors = err;
+       }
+
+       if (vectors < vector_threshold) {
+               /* Can't allocate enough MSI-X interrupts?  Oh well.
+                * This just means we'll go with either a single MSI
+                * vector or fall back to legacy interrupts.
+                */
+               hw_dbg(&adapter->hw,
+                      "Unable to allocate MSI-X interrupts\n");
+               kfree(adapter->msix_entries);
+               adapter->msix_entries = NULL;
+       } else {
+               /*
+                * Adjust for only the vectors we'll use, which is minimum
+                * of max_msix_q_vectors + NON_Q_VECTORS, or the number of
+                * vectors we were allocated.
+                */
+               adapter->num_msix_vectors = vectors;
+       }
+}
+
+/*
+ * ixgbe_set_num_queues: Allocate queues for device, feature dependant
+ * @adapter: board private structure to initialize
+ *
+ * This is the top level queue allocation routine.  The order here is very
+ * important, starting with the "most" number of features turned on at once,
+ * and ending with the smallest set of features.  This way large combinations
+ * can be allocated if they're turned on, and smaller combinations are the
+ * fallthrough conditions.
+ *
+ **/
+static void ixgbevf_set_num_queues(struct ixgbevf_adapter *adapter)
+{
+       /* Start with base case */
+       adapter->num_rx_queues = 1;
+       adapter->num_tx_queues = 1;
+       adapter->num_rx_pools = adapter->num_rx_queues;
+       adapter->num_rx_queues_per_pool = 1;
+}
+
+/**
+ * ixgbevf_alloc_queues - Allocate memory for all rings
+ * @adapter: board private structure to initialize
+ *
+ * We allocate one ring per queue at run-time since we don't know the
+ * number of queues at compile-time.  The polling_netdev array is
+ * intended for Multiqueue, but should work fine with a single queue.
+ **/
+static int ixgbevf_alloc_queues(struct ixgbevf_adapter *adapter)
+{
+       int i;
+
+       adapter->tx_ring = kcalloc(adapter->num_tx_queues,
+                                  sizeof(struct ixgbevf_ring), GFP_KERNEL);
+       if (!adapter->tx_ring)
+               goto err_tx_ring_allocation;
+
+       adapter->rx_ring = kcalloc(adapter->num_rx_queues,
+                                  sizeof(struct ixgbevf_ring), GFP_KERNEL);
+       if (!adapter->rx_ring)
+               goto err_rx_ring_allocation;
+
+       for (i = 0; i < adapter->num_tx_queues; i++) {
+               adapter->tx_ring[i].count = adapter->tx_ring_count;
+               adapter->tx_ring[i].queue_index = i;
+               adapter->tx_ring[i].reg_idx = i;
+       }
+
+       for (i = 0; i < adapter->num_rx_queues; i++) {
+               adapter->rx_ring[i].count = adapter->rx_ring_count;
+               adapter->rx_ring[i].queue_index = i;
+               adapter->rx_ring[i].reg_idx = i;
+       }
+
+       return 0;
+
+err_rx_ring_allocation:
+       kfree(adapter->tx_ring);
+err_tx_ring_allocation:
+       return -ENOMEM;
+}
+
+/**
+ * ixgbevf_set_interrupt_capability - set MSI-X or FAIL if not supported
+ * @adapter: board private structure to initialize
+ *
+ * Attempt to configure the interrupts using the best available
+ * capabilities of the hardware and the kernel.
+ **/
+static int ixgbevf_set_interrupt_capability(struct ixgbevf_adapter *adapter)
+{
+       int err = 0;
+       int vector, v_budget;
+
+       /*
+        * It's easy to be greedy for MSI-X vectors, but it really
+        * doesn't do us much good if we have a lot more vectors
+        * than CPU's.  So let's be conservative and only ask for
+        * (roughly) twice the number of vectors as there are CPU's.
+        */
+       v_budget = min(adapter->num_rx_queues + adapter->num_tx_queues,
+                      (int)(num_online_cpus() * 2)) + NON_Q_VECTORS;
+
+       /* 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);
+       if (!adapter->msix_entries) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       for (vector = 0; vector < v_budget; vector++)
+               adapter->msix_entries[vector].entry = vector;
+
+       ixgbevf_acquire_msix_vectors(adapter, v_budget);
+
+out:
+       return err;
+}
+
+/**
+ * ixgbevf_alloc_q_vectors - Allocate memory for interrupt vectors
+ * @adapter: board private structure to initialize
+ *
+ * We allocate one q_vector per queue interrupt.  If allocation fails we
+ * return -ENOMEM.
+ **/
+static int ixgbevf_alloc_q_vectors(struct ixgbevf_adapter *adapter)
+{
+       int q_idx, num_q_vectors;
+       struct ixgbevf_q_vector *q_vector;
+       int napi_vectors;
+       int (*poll)(struct napi_struct *, int);
+
+       num_q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS;
+       napi_vectors = adapter->num_rx_queues;
+       poll = &ixgbevf_clean_rxonly;
+
+       for (q_idx = 0; q_idx < num_q_vectors; q_idx++) {
+               q_vector = kzalloc(sizeof(struct ixgbevf_q_vector), GFP_KERNEL);
+               if (!q_vector)
+                       goto err_out;
+               q_vector->adapter = adapter;
+               q_vector->v_idx = q_idx;
+               q_vector->eitr = adapter->eitr_param;
+               if (q_idx < napi_vectors)
+                       netif_napi_add(adapter->netdev, &q_vector->napi,
+                                      (*poll), 64);
+               adapter->q_vector[q_idx] = q_vector;
+       }
+
+       return 0;
+
+err_out:
+       while (q_idx) {
+               q_idx--;
+               q_vector = adapter->q_vector[q_idx];
+               netif_napi_del(&q_vector->napi);
+               kfree(q_vector);
+               adapter->q_vector[q_idx] = NULL;
+       }
+       return -ENOMEM;
+}
+
+/**
+ * ixgbevf_free_q_vectors - Free memory allocated for interrupt vectors
+ * @adapter: board private structure to initialize
+ *
+ * This function frees the memory allocated to the q_vectors.  In addition if
+ * NAPI is enabled it will delete any references to the NAPI struct prior
+ * to freeing the q_vector.
+ **/
+static void ixgbevf_free_q_vectors(struct ixgbevf_adapter *adapter)
+{
+       int q_idx, num_q_vectors;
+       int napi_vectors;
+
+       num_q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS;
+       napi_vectors = adapter->num_rx_queues;
+
+       for (q_idx = 0; q_idx < num_q_vectors; q_idx++) {
+               struct ixgbevf_q_vector *q_vector = adapter->q_vector[q_idx];
+
+               adapter->q_vector[q_idx] = NULL;
+               if (q_idx < napi_vectors)
+                       netif_napi_del(&q_vector->napi);
+               kfree(q_vector);
+       }
+}
+
+/**
+ * ixgbevf_reset_interrupt_capability - Reset MSIX setup
+ * @adapter: board private structure
+ *
+ **/
+static void ixgbevf_reset_interrupt_capability(struct ixgbevf_adapter *adapter)
+{
+       pci_disable_msix(adapter->pdev);
+       kfree(adapter->msix_entries);
+       adapter->msix_entries = NULL;
+
+       return;
+}
+
+/**
+ * ixgbevf_init_interrupt_scheme - Determine if MSIX is supported and init
+ * @adapter: board private structure to initialize
+ *
+ **/
+static int ixgbevf_init_interrupt_scheme(struct ixgbevf_adapter *adapter)
+{
+       int err;
+
+       /* Number of supported queues */
+       ixgbevf_set_num_queues(adapter);
+
+       err = ixgbevf_set_interrupt_capability(adapter);
+       if (err) {
+               hw_dbg(&adapter->hw,
+                      "Unable to setup interrupt capabilities\n");
+               goto err_set_interrupt;
+       }
+
+       err = ixgbevf_alloc_q_vectors(adapter);
+       if (err) {
+               hw_dbg(&adapter->hw, "Unable to allocate memory for queue "
+                      "vectors\n");
+               goto err_alloc_q_vectors;
+       }
+
+       err = ixgbevf_alloc_queues(adapter);
+       if (err) {
+               printk(KERN_ERR "Unable to allocate memory for queues\n");
+               goto err_alloc_queues;
+       }
+
+       hw_dbg(&adapter->hw, "Multiqueue %s: Rx Queue count = %u, "
+              "Tx Queue count = %u\n",
+              (adapter->num_rx_queues > 1) ? "Enabled" :
+              "Disabled", adapter->num_rx_queues, adapter->num_tx_queues);
+
+       set_bit(__IXGBEVF_DOWN, &adapter->state);
+
+       return 0;
+err_alloc_queues:
+       ixgbevf_free_q_vectors(adapter);
+err_alloc_q_vectors:
+       ixgbevf_reset_interrupt_capability(adapter);
+err_set_interrupt:
+       return err;
+}
+
+/**
+ * ixgbevf_sw_init - Initialize general software structures
+ * (struct ixgbevf_adapter)
+ * @adapter: board private structure to initialize
+ *
+ * ixgbevf_sw_init initializes the Adapter private data structure.
+ * Fields are initialized based on PCI device information and
+ * OS network device settings (MTU size).
+ **/
+static int __devinit ixgbevf_sw_init(struct ixgbevf_adapter *adapter)
+{
+       struct ixgbe_hw *hw = &adapter->hw;
+       struct pci_dev *pdev = adapter->pdev;
+       int err;
+
+       /* PCI config space info */
+
+       hw->vendor_id = pdev->vendor;
+       hw->device_id = pdev->device;
+       pci_read_config_byte(pdev, PCI_REVISION_ID, &hw->revision_id);
+       hw->subsystem_vendor_id = pdev->subsystem_vendor;
+       hw->subsystem_device_id = pdev->subsystem_device;
+
+       hw->mbx.ops.init_params(hw);
+       hw->mac.max_tx_queues = MAX_TX_QUEUES;
+       hw->mac.max_rx_queues = MAX_RX_QUEUES;
+       err = hw->mac.ops.reset_hw(hw);
+       if (err) {
+               dev_info(&pdev->dev,
+                        "PF still in reset state, assigning new address\n");
+               random_ether_addr(hw->mac.addr);
+       } else {
+               err = hw->mac.ops.init_hw(hw);
+               if (err) {
+                       printk(KERN_ERR "init_shared_code failed: %d\n", err);
+                       goto out;
+               }
+       }
+
+       /* Enable dynamic interrupt throttling rates */
+       adapter->eitr_param = 20000;
+       adapter->itr_setting = 1;
+
+       /* set defaults for eitr in MegaBytes */
+       adapter->eitr_low = 10;
+       adapter->eitr_high = 20;
+
+       /* set default ring sizes */
+       adapter->tx_ring_count = IXGBEVF_DEFAULT_TXD;
+       adapter->rx_ring_count = IXGBEVF_DEFAULT_RXD;
+
+       /* enable rx csum by default */
+       adapter->flags |= IXGBE_FLAG_RX_CSUM_ENABLED;
+
+       set_bit(__IXGBEVF_DOWN, &adapter->state);
+
+out:
+       return err;
+}
+
+static void ixgbevf_init_last_counter_stats(struct ixgbevf_adapter *adapter)
+{
+       struct ixgbe_hw *hw = &adapter->hw;
+
+       adapter->stats.last_vfgprc = IXGBE_READ_REG(hw, IXGBE_VFGPRC);
+       adapter->stats.last_vfgorc = IXGBE_READ_REG(hw, IXGBE_VFGORC_LSB);
+       adapter->stats.last_vfgorc |=
+               (((u64)(IXGBE_READ_REG(hw, IXGBE_VFGORC_MSB))) << 32);
+       adapter->stats.last_vfgptc = IXGBE_READ_REG(hw, IXGBE_VFGPTC);
+       adapter->stats.last_vfgotc = IXGBE_READ_REG(hw, IXGBE_VFGOTC_LSB);
+       adapter->stats.last_vfgotc |=
+               (((u64)(IXGBE_READ_REG(hw, IXGBE_VFGOTC_MSB))) << 32);
+       adapter->stats.last_vfmprc = IXGBE_READ_REG(hw, IXGBE_VFMPRC);
+
+       adapter->stats.base_vfgprc = adapter->stats.last_vfgprc;
+       adapter->stats.base_vfgorc = adapter->stats.last_vfgorc;
+       adapter->stats.base_vfgptc = adapter->stats.last_vfgptc;
+       adapter->stats.base_vfgotc = adapter->stats.last_vfgotc;
+       adapter->stats.base_vfmprc = adapter->stats.last_vfmprc;
+}
+
+#define UPDATE_VF_COUNTER_32bit(reg, last_counter, counter)    \
+       {                                                       \
+               u32 current_counter = IXGBE_READ_REG(hw, reg);  \
+               if (current_counter < last_counter)             \
+                       counter += 0x100000000LL;               \
+               last_counter = current_counter;                 \
+               counter &= 0xFFFFFFFF00000000LL;                \
+               counter |= current_counter;                     \
+       }
+
+#define UPDATE_VF_COUNTER_36bit(reg_lsb, reg_msb, last_counter, counter) \
+       {                                                                \
+               u64 current_counter_lsb = IXGBE_READ_REG(hw, reg_lsb);   \
+               u64 current_counter_msb = IXGBE_READ_REG(hw, reg_msb);   \
+               u64 current_counter = (current_counter_msb << 32) |      \
+                       current_counter_lsb;                             \
+               if (current_counter < last_counter)                      \
+                       counter += 0x1000000000LL;                       \
+               last_counter = current_counter;                          \
+               counter &= 0xFFFFFFF000000000LL;                         \
+               counter |= current_counter;                              \
+       }
+/**
+ * ixgbevf_update_stats - Update the board statistics counters.
+ * @adapter: board private structure
+ **/
+void ixgbevf_update_stats(struct ixgbevf_adapter *adapter)
+{
+       struct ixgbe_hw *hw = &adapter->hw;
+
+       UPDATE_VF_COUNTER_32bit(IXGBE_VFGPRC, adapter->stats.last_vfgprc,
+                               adapter->stats.vfgprc);
+       UPDATE_VF_COUNTER_32bit(IXGBE_VFGPTC, adapter->stats.last_vfgptc,
+                               adapter->stats.vfgptc);
+       UPDATE_VF_COUNTER_36bit(IXGBE_VFGORC_LSB, IXGBE_VFGORC_MSB,
+                               adapter->stats.last_vfgorc,
+                               adapter->stats.vfgorc);
+       UPDATE_VF_COUNTER_36bit(IXGBE_VFGOTC_LSB, IXGBE_VFGOTC_MSB,
+                               adapter->stats.last_vfgotc,
+                               adapter->stats.vfgotc);
+       UPDATE_VF_COUNTER_32bit(IXGBE_VFMPRC, adapter->stats.last_vfmprc,
+                               adapter->stats.vfmprc);
+
+       /* Fill out the OS statistics structure */
+       adapter->net_stats.multicast = adapter->stats.vfmprc -
+               adapter->stats.base_vfmprc;
+}
+
+/**
+ * ixgbevf_watchdog - Timer Call-back
+ * @data: pointer to adapter cast into an unsigned long
+ **/
+static void ixgbevf_watchdog(unsigned long data)
+{
+       struct ixgbevf_adapter *adapter = (struct ixgbevf_adapter *)data;
+       struct ixgbe_hw *hw = &adapter->hw;
+       u64 eics = 0;
+       int i;
+
+       /*
+        * Do the watchdog outside of interrupt context due to the lovely
+        * delays that some of the newer hardware requires
+        */
+
+       if (test_bit(__IXGBEVF_DOWN, &adapter->state))
+               goto watchdog_short_circuit;
+
+       /* get one bit for every active tx/rx interrupt vector */
+       for (i = 0; i < adapter->num_msix_vectors - NON_Q_VECTORS; i++) {
+               struct ixgbevf_q_vector *qv = adapter->q_vector[i];
+               if (qv->rxr_count || qv->txr_count)
+                       eics |= (1 << i);
+       }
+
+       IXGBE_WRITE_REG(hw, IXGBE_VTEICS, (u32)eics);
+
+watchdog_short_circuit:
+       schedule_work(&adapter->watchdog_task);
+}
+
+/**
+ * ixgbevf_tx_timeout - Respond to a Tx Hang
+ * @netdev: network interface device structure
+ **/
+static void ixgbevf_tx_timeout(struct net_device *netdev)
+{
+       struct ixgbevf_adapter *adapter = netdev_priv(netdev);
+
+       /* Do the reset outside of interrupt context */
+       schedule_work(&adapter->reset_task);
+}
+
+static void ixgbevf_reset_task(struct work_struct *work)
+{
+       struct ixgbevf_adapter *adapter;
+       adapter = container_of(work, struct ixgbevf_adapter, reset_task);
+
+       /* If we're already down or resetting, just bail */
+       if (test_bit(__IXGBEVF_DOWN, &adapter->state) ||
+           test_bit(__IXGBEVF_RESETTING, &adapter->state))
+               return;
+
+       adapter->tx_timeout_count++;
+
+       ixgbevf_reinit_locked(adapter);
+}
+
+/**
+ * ixgbevf_watchdog_task - worker thread to bring link up
+ * @work: pointer to work_struct containing our data
+ **/
+static void ixgbevf_watchdog_task(struct work_struct *work)
+{
+       struct ixgbevf_adapter *adapter = container_of(work,
+                                                      struct ixgbevf_adapter,
+                                                      watchdog_task);
+       struct net_device *netdev = adapter->netdev;
+       struct ixgbe_hw *hw = &adapter->hw;
+       u32 link_speed = adapter->link_speed;
+       bool link_up = adapter->link_up;
+
+       adapter->flags |= IXGBE_FLAG_IN_WATCHDOG_TASK;
+
+       /*
+        * Always check the link on the watchdog because we have
+        * no LSC interrupt
+        */
+       if (hw->mac.ops.check_link) {
+               if ((hw->mac.ops.check_link(hw, &link_speed,
+                                           &link_up, false)) != 0) {
+                       adapter->link_up = link_up;
+                       adapter->link_speed = link_speed;
+                       netif_carrier_off(netdev);
+                       netif_tx_stop_all_queues(netdev);
+                       schedule_work(&adapter->reset_task);
+                       goto pf_has_reset;
+               }
+       } else {
+               /* always assume link is up, if no check link
+                * function */
+               link_speed = IXGBE_LINK_SPEED_10GB_FULL;
+               link_up = true;
+       }
+       adapter->link_up = link_up;
+       adapter->link_speed = link_speed;
+
+       if (link_up) {
+               if (!netif_carrier_ok(netdev)) {
+                       hw_dbg(&adapter->hw, "NIC Link is Up %s, ",
+                              ((link_speed == IXGBE_LINK_SPEED_10GB_FULL) ?
+                               "10 Gbps" : "1 Gbps"));
+                       netif_carrier_on(netdev);
+                       netif_tx_wake_all_queues(netdev);
+               } else {
+                       /* Force detection of hung controller */
+                       adapter->detect_tx_hung = true;
+               }
+       } else {
+               adapter->link_up = false;
+               adapter->link_speed = 0;
+               if (netif_carrier_ok(netdev)) {
+                       hw_dbg(&adapter->hw, "NIC Link is Down\n");
+                       netif_carrier_off(netdev);
+                       netif_tx_stop_all_queues(netdev);
+               }
+       }
+
+pf_has_reset:
+       ixgbevf_update_stats(adapter);
+
+       /* Force detection of hung controller every watchdog period */
+       adapter->detect_tx_hung = true;
+
+       /* Reset the timer */
+       if (!test_bit(__IXGBEVF_DOWN, &adapter->state))
+               mod_timer(&adapter->watchdog_timer,
+                         round_jiffies(jiffies + (2 * HZ)));
+
+       adapter->flags &= ~IXGBE_FLAG_IN_WATCHDOG_TASK;
+}
+
+/**
+ * ixgbevf_free_tx_resources - Free Tx Resources per Queue
+ * @adapter: board private structure
+ * @tx_ring: Tx descriptor ring for a specific queue
+ *
+ * Free all transmit software resources
+ **/
+void ixgbevf_free_tx_resources(struct ixgbevf_adapter *adapter,
+                              struct ixgbevf_ring *tx_ring)
+{
+       struct pci_dev *pdev = adapter->pdev;
+
+       ixgbevf_clean_tx_ring(adapter, tx_ring);
+
+       vfree(tx_ring->tx_buffer_info);
+       tx_ring->tx_buffer_info = NULL;
+
+       pci_free_consistent(pdev, tx_ring->size, tx_ring->desc, tx_ring->dma);
+
+       tx_ring->desc = NULL;
+}
+
+/**
+ * ixgbevf_free_all_tx_resources - Free Tx Resources for All Queues
+ * @adapter: board private structure
+ *
+ * Free all transmit software resources
+ **/
+static void ixgbevf_free_all_tx_resources(struct ixgbevf_adapter *adapter)
+{
+       int i;
+
+       for (i = 0; i < adapter->num_tx_queues; i++)
+               if (adapter->tx_ring[i].desc)
+                       ixgbevf_free_tx_resources(adapter,
+                                                 &adapter->tx_ring[i]);
+
+}
+
+/**
+ * ixgbevf_setup_tx_resources - allocate Tx resources (Descriptors)
+ * @adapter: board private structure
+ * @tx_ring:    tx descriptor ring (for a specific queue) to setup
+ *
+ * Return 0 on success, negative on failure
+ **/
+int ixgbevf_setup_tx_resources(struct ixgbevf_adapter *adapter,
+                              struct ixgbevf_ring *tx_ring)
+{
+       struct pci_dev *pdev = adapter->pdev;
+       int size;
+
+       size = sizeof(struct ixgbevf_tx_buffer) * tx_ring->count;
+       tx_ring->tx_buffer_info = vmalloc(size);
+       if (!tx_ring->tx_buffer_info)
+               goto err;
+       memset(tx_ring->tx_buffer_info, 0, size);
+
+       /* round up to nearest 4K */
+       tx_ring->size = tx_ring->count * sizeof(union ixgbe_adv_tx_desc);
+       tx_ring->size = ALIGN(tx_ring->size, 4096);
+
+       tx_ring->desc = pci_alloc_consistent(pdev, tx_ring->size,
+                                            &tx_ring->dma);
+       if (!tx_ring->desc)
+               goto err;
+
+       tx_ring->next_to_use = 0;
+       tx_ring->next_to_clean = 0;
+       tx_ring->work_limit = tx_ring->count;
+       return 0;
+
+err:
+       vfree(tx_ring->tx_buffer_info);
+       tx_ring->tx_buffer_info = NULL;
+       hw_dbg(&adapter->hw, "Unable to allocate memory for the transmit "
+              "descriptor ring\n");
+       return -ENOMEM;
+}
+
+/**
+ * ixgbevf_setup_all_tx_resources - allocate all queues Tx resources
+ * @adapter: board private structure
+ *
+ * If this function returns with an error, then it's possible one or
+ * more of the rings is populated (while the rest are not).  It is the
+ * callers duty to clean those orphaned rings.
+ *
+ * Return 0 on success, negative on failure
+ **/
+static int ixgbevf_setup_all_tx_resources(struct ixgbevf_adapter *adapter)
+{
+       int i, err = 0;
+
+       for (i = 0; i < adapter->num_tx_queues; i++) {
+               err = ixgbevf_setup_tx_resources(adapter, &adapter->tx_ring[i]);
+               if (!err)
+                       continue;
+               hw_dbg(&adapter->hw,
+                      "Allocation for Tx Queue %u failed\n", i);
+               break;
+       }
+
+       return err;
+}
+
+/**
+ * ixgbevf_setup_rx_resources - allocate Rx resources (Descriptors)
+ * @adapter: board private structure
+ * @rx_ring:    rx descriptor ring (for a specific queue) to setup
+ *
+ * Returns 0 on success, negative on failure
+ **/
+int ixgbevf_setup_rx_resources(struct ixgbevf_adapter *adapter,
+                              struct ixgbevf_ring *rx_ring)
+{
+       struct pci_dev *pdev = adapter->pdev;
+       int size;
+
+       size = sizeof(struct ixgbevf_rx_buffer) * rx_ring->count;
+       rx_ring->rx_buffer_info = vmalloc(size);
+       if (!rx_ring->rx_buffer_info) {
+               hw_dbg(&adapter->hw,
+                      "Unable to vmalloc buffer memory for "
+                      "the receive descriptor ring\n");
+               goto alloc_failed;
+       }
+       memset(rx_ring->rx_buffer_info, 0, size);
+
+       /* Round up to nearest 4K */
+       rx_ring->size = rx_ring->count * sizeof(union ixgbe_adv_rx_desc);
+       rx_ring->size = ALIGN(rx_ring->size, 4096);
+
+       rx_ring->desc = pci_alloc_consistent(pdev, rx_ring->size,
+                                            &rx_ring->dma);
+
+       if (!rx_ring->desc) {
+               hw_dbg(&adapter->hw,
+                      "Unable to allocate memory for "
+                      "the receive descriptor ring\n");
+               vfree(rx_ring->rx_buffer_info);
+               rx_ring->rx_buffer_info = NULL;
+               goto alloc_failed;
+       }
+
+       rx_ring->next_to_clean = 0;
+       rx_ring->next_to_use = 0;
+
+       return 0;
+alloc_failed:
+       return -ENOMEM;
+}
+
+/**
+ * ixgbevf_setup_all_rx_resources - allocate all queues Rx resources
+ * @adapter: board private structure
+ *
+ * If this function returns with an error, then it's possible one or
+ * more of the rings is populated (while the rest are not).  It is the
+ * callers duty to clean those orphaned rings.
+ *
+ * Return 0 on success, negative on failure
+ **/
+static int ixgbevf_setup_all_rx_resources(struct ixgbevf_adapter *adapter)
+{
+       int i, err = 0;
+
+       for (i = 0; i < adapter->num_rx_queues; i++) {
+               err = ixgbevf_setup_rx_resources(adapter, &adapter->rx_ring[i]);
+               if (!err)
+                       continue;
+               hw_dbg(&adapter->hw,
+                      "Allocation for Rx Queue %u failed\n", i);
+               break;
+       }
+       return err;
+}
+
+/**
+ * ixgbevf_free_rx_resources - Free Rx Resources
+ * @adapter: board private structure
+ * @rx_ring: ring to clean the resources from
+ *
+ * Free all receive software resources
+ **/
+void ixgbevf_free_rx_resources(struct ixgbevf_adapter *adapter,
+                              struct ixgbevf_ring *rx_ring)
+{
+       struct pci_dev *pdev = adapter->pdev;
+
+       ixgbevf_clean_rx_ring(adapter, rx_ring);
+
+       vfree(rx_ring->rx_buffer_info);
+       rx_ring->rx_buffer_info = NULL;
+
+       pci_free_consistent(pdev, rx_ring->size, rx_ring->desc, rx_ring->dma);
+
+       rx_ring->desc = NULL;
+}
+
+/**
+ * ixgbevf_free_all_rx_resources - Free Rx Resources for All Queues
+ * @adapter: board private structure
+ *
+ * Free all receive software resources
+ **/
+static void ixgbevf_free_all_rx_resources(struct ixgbevf_adapter *adapter)
+{
+       int i;
+
+       for (i = 0; i < adapter->num_rx_queues; i++)
+               if (adapter->rx_ring[i].desc)
+                       ixgbevf_free_rx_resources(adapter,
+                                                 &adapter->rx_ring[i]);
+}
+
+/**
+ * ixgbevf_open - Called when a network interface is made active
+ * @netdev: network interface device structure
+ *
+ * Returns 0 on success, negative value on failure
+ *
+ * The open entry point is called when a network interface is made
+ * active by the system (IFF_UP).  At this point all resources needed
+ * for transmit and receive operations are allocated, the interrupt
+ * handler is registered with the OS, the watchdog timer is started,
+ * and the stack is notified that the interface is ready.
+ **/
+static int ixgbevf_open(struct net_device *netdev)
+{
+       struct ixgbevf_adapter *adapter = netdev_priv(netdev);
+       struct ixgbe_hw *hw = &adapter->hw;
+       int err;
+
+       /* disallow open during test */
+       if (test_bit(__IXGBEVF_TESTING, &adapter->state))
+               return -EBUSY;
+
+       if (hw->adapter_stopped) {
+               ixgbevf_reset(adapter);
+               /* if adapter is still stopped then PF isn't up and
+                * the vf can't start. */
+               if (hw->adapter_stopped) {
+                       err = IXGBE_ERR_MBX;
+                       printk(KERN_ERR "Unable to start - perhaps the PF"
+                              "Driver isn't up yet\n");
+                       goto err_setup_reset;
+               }
+       }
+
+       /* allocate transmit descriptors */
+       err = ixgbevf_setup_all_tx_resources(adapter);
+       if (err)
+               goto err_setup_tx;
+
+       /* allocate receive descriptors */
+       err = ixgbevf_setup_all_rx_resources(adapter);
+       if (err)
+               goto err_setup_rx;
+
+       ixgbevf_configure(adapter);
+
+       /*
+        * Map the Tx/Rx rings to the vectors we were allotted.
+        * if request_irq will be called in this function map_rings
+        * must be called *before* up_complete
+        */
+       ixgbevf_map_rings_to_vectors(adapter);
+
+       err = ixgbevf_up_complete(adapter);
+       if (err)
+               goto err_up;
+
+       /* clear any pending interrupts, may auto mask */
+       IXGBE_READ_REG(hw, IXGBE_VTEICR);
+       err = ixgbevf_request_irq(adapter);
+       if (err)
+               goto err_req_irq;
+
+       ixgbevf_irq_enable(adapter, true, true);
+
+       return 0;
+
+err_req_irq:
+       ixgbevf_down(adapter);
+err_up:
+       ixgbevf_free_irq(adapter);
+err_setup_rx:
+       ixgbevf_free_all_rx_resources(adapter);
+err_setup_tx:
+       ixgbevf_free_all_tx_resources(adapter);
+       ixgbevf_reset(adapter);
+
+err_setup_reset:
+
+       return err;
+}
+
+/**
+ * ixgbevf_close - Disables a network interface
+ * @netdev: network interface device structure
+ *
+ * Returns 0, this is not allowed to fail
+ *
+ * The close entry point is called when an interface is de-activated
+ * by the OS.  The hardware is still under the drivers control, but
+ * needs to be disabled.  A global MAC reset is issued to stop the
+ * hardware, and all transmit and receive resources are freed.
+ **/
+static int ixgbevf_close(struct net_device *netdev)
+{
+       struct ixgbevf_adapter *adapter = netdev_priv(netdev);
+
+       ixgbevf_down(adapter);
+       ixgbevf_free_irq(adapter);
+
+       ixgbevf_free_all_tx_resources(adapter);
+       ixgbevf_free_all_rx_resources(adapter);
+
+       return 0;
+}
+
+static int ixgbevf_tso(struct ixgbevf_adapter *adapter,
+                      struct ixgbevf_ring *tx_ring,
+                      struct sk_buff *skb, u32 tx_flags, u8 *hdr_len)
+{
+       struct ixgbe_adv_tx_context_desc *context_desc;
+       unsigned int i;
+       int err;
+       struct ixgbevf_tx_buffer *tx_buffer_info;
+       u32 vlan_macip_lens = 0, type_tucmd_mlhl;
+       u32 mss_l4len_idx, l4len;
+
+       if (skb_is_gso(skb)) {
+               if (skb_header_cloned(skb)) {
+                       err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
+                       if (err)
+                               return err;
+               }
+               l4len = tcp_hdrlen(skb);
+               *hdr_len += l4len;
+
+               if (skb->protocol == htons(ETH_P_IP)) {
+                       struct iphdr *iph = ip_hdr(skb);
+                       iph->tot_len = 0;
+                       iph->check = 0;
+                       tcp_hdr(skb)->check = ~csum_tcpudp_magic(iph->saddr,
+                                                                iph->daddr, 0,
+                                                                IPPROTO_TCP,
+                                                                0);
+                       adapter->hw_tso_ctxt++;
+               } 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);
+                       adapter->hw_tso6_ctxt++;
+               }
+
+               i = tx_ring->next_to_use;
+
+               tx_buffer_info = &tx_ring->tx_buffer_info[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);
+               *hdr_len += skb_network_offset(skb);
+               vlan_macip_lens |=
+                       (skb_transport_header(skb) - skb_network_header(skb));
+               *hdr_len +=
+                       (skb_transport_header(skb) - skb_network_header(skb));
+               context_desc->vlan_macip_lens = cpu_to_le32(vlan_macip_lens);
+               context_desc->seqnum_seed = 0;
+
+               /* ADV DTYP TUCMD MKRLOC/ISCSIHEDLEN */
+               type_tucmd_mlhl = (IXGBE_TXD_CMD_DEXT |
+                                   IXGBE_ADVTXD_DTYP_CTXT);
+
+               if (skb->protocol == htons(ETH_P_IP))
+                       type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_IPV4;
+               type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_L4T_TCP;
+               context_desc->type_tucmd_mlhl = cpu_to_le32(type_tucmd_mlhl);
+
+               /* MSS L4LEN IDX */
+               mss_l4len_idx =
+                       (skb_shinfo(skb)->gso_size << IXGBE_ADVTXD_MSS_SHIFT);
+               mss_l4len_idx |= (l4len << IXGBE_ADVTXD_L4LEN_SHIFT);
+               /* use index 1 for TSO */
+               mss_l4len_idx |= (1 << IXGBE_ADVTXD_IDX_SHIFT);
+               context_desc->mss_l4len_idx = cpu_to_le32(mss_l4len_idx);
+
+               tx_buffer_info->time_stamp = jiffies;
+               tx_buffer_info->next_to_watch = i;
+
+               i++;
+               if (i == tx_ring->count)
+                       i = 0;
+               tx_ring->next_to_use = i;
+
+               return true;
+       }
+
+       return false;
+}
+
+static bool ixgbevf_tx_csum(struct ixgbevf_adapter *adapter,
+                           struct ixgbevf_ring *tx_ring,
+                           struct sk_buff *skb, u32 tx_flags)
+{
+       struct ixgbe_adv_tx_context_desc *context_desc;
+       unsigned int i;
+       struct ixgbevf_tx_buffer *tx_buffer_info;
+       u32 vlan_macip_lens = 0, type_tucmd_mlhl = 0;
+
+       if (skb->ip_summed == CHECKSUM_PARTIAL ||
+           (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);
+
+               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);
+               if (skb->ip_summed == CHECKSUM_PARTIAL)
+                       vlan_macip_lens |= (skb_transport_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) {
+                       switch (skb->protocol) {
+                       case __constant_htons(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;
+                               break;
+                       case __constant_htons(ETH_P_IPV6):
+                               /* XXX what about other V6 headers?? */
+                               if (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP)
+                                       type_tucmd_mlhl |=
+                                               IXGBE_ADVTXD_TUCMD_L4T_TCP;
+                               break;
+                       default:
+                               if (unlikely(net_ratelimit())) {
+                                       printk(KERN_WARNING
+                                              "partial checksum but "
+                                              "proto=%x!\n",
+                                              skb->protocol);
+                               }
+                               break;
+                       }
+               }
+
+               context_desc->type_tucmd_mlhl = cpu_to_le32(type_tucmd_mlhl);
+               /* use index zero for tx checksum offload */
+               context_desc->mss_l4len_idx = 0;
+
+               tx_buffer_info->time_stamp = jiffies;
+               tx_buffer_info->next_to_watch = i;
+
+               adapter->hw_csum_tx_good++;
+               i++;
+               if (i == tx_ring->count)
+                       i = 0;
+               tx_ring->next_to_use = i;
+
+               return true;
+       }
+
+       return false;
+}
+
+static int ixgbevf_tx_map(struct ixgbevf_adapter *adapter,
+                         struct ixgbevf_ring *tx_ring,
+                         struct sk_buff *skb, u32 tx_flags,
+                         unsigned int first)
+{
+       struct pci_dev *pdev = adapter->pdev;
+       struct ixgbevf_tx_buffer *tx_buffer_info;
+       unsigned int len;
+       unsigned int total = skb->len;
+       unsigned int offset = 0, size, count = 0, i;
+       unsigned int nr_frags = skb_shinfo(skb)->nr_frags;
+       unsigned int f;
+
+       i = tx_ring->next_to_use;
+
+       len = min(skb_headlen(skb), total);
+       while (len) {
+               tx_buffer_info = &tx_ring->tx_buffer_info[i];
+               size = min(len, (unsigned int)IXGBE_MAX_DATA_PER_TXD);
+
+               tx_buffer_info->length = size;
+               tx_buffer_info->mapped_as_page = false;
+               tx_buffer_info->dma = pci_map_single(adapter->pdev,
+                                                    skb->data + offset,
+                                                    size, PCI_DMA_TODEVICE);
+               if (pci_dma_mapping_error(pdev, tx_buffer_info->dma))
+                       goto dma_error;
+               tx_buffer_info->time_stamp = jiffies;
+               tx_buffer_info->next_to_watch = i;
+
+               len -= size;
+               total -= size;
+               offset += size;
+               count++;
+               i++;
+               if (i == tx_ring->count)
+                       i = 0;
+       }
+
+       for (f = 0; f < nr_frags; f++) {
+               struct skb_frag_struct *frag;
+
+               frag = &skb_shinfo(skb)->frags[f];
+               len = min((unsigned int)frag->size, total);
+               offset = frag->page_offset;
+
+               while (len) {
+                       tx_buffer_info = &tx_ring->tx_buffer_info[i];
+                       size = min(len, (unsigned int)IXGBE_MAX_DATA_PER_TXD);
+
+                       tx_buffer_info->length = size;
+                       tx_buffer_info->dma = pci_map_page(adapter->pdev,
+                                                          frag->page,
+                                                          offset,
+                                                          size,
+                                                          PCI_DMA_TODEVICE);
+                       tx_buffer_info->mapped_as_page = true;
+                       if (pci_dma_mapping_error(pdev, tx_buffer_info->dma))
+                               goto dma_error;
+                       tx_buffer_info->time_stamp = jiffies;
+                       tx_buffer_info->next_to_watch = i;
+
+                       len -= size;
+                       total -= size;
+                       offset += size;
+                       count++;
+                       i++;
+                       if (i == tx_ring->count)
+                               i = 0;
+               }
+               if (total == 0)
+                       break;
+       }
+
+       if (i == 0)
+               i = tx_ring->count - 1;
+       else
+               i = i - 1;
+       tx_ring->tx_buffer_info[i].skb = skb;
+       tx_ring->tx_buffer_info[first].next_to_watch = i;
+
+       return count;
+
+dma_error:
+       dev_err(&pdev->dev, "TX DMA map failed\n");
+
+       /* clear timestamp and dma mappings for failed tx_buffer_info map */
+       tx_buffer_info->dma = 0;
+       tx_buffer_info->time_stamp = 0;
+       tx_buffer_info->next_to_watch = 0;
+       count--;
+
+       /* clear timestamp and dma mappings for remaining portion of packet */
+       while (count >= 0) {
+               count--;
+               i--;
+               if (i < 0)
+                       i += tx_ring->count;
+               tx_buffer_info = &tx_ring->tx_buffer_info[i];
+               ixgbevf_unmap_and_free_tx_resource(adapter, tx_buffer_info);
+       }
+
+       return count;
+}
+
+static void ixgbevf_tx_queue(struct ixgbevf_adapter *adapter,
+                            struct ixgbevf_ring *tx_ring, int tx_flags,
+                            int count, u32 paylen, u8 hdr_len)
+{
+       union ixgbe_adv_tx_desc *tx_desc = NULL;
+       struct ixgbevf_tx_buffer *tx_buffer_info;
+       u32 olinfo_status = 0, cmd_type_len = 0;
+       unsigned int i;
+
+       u32 txd_cmd = IXGBE_TXD_CMD_EOP | IXGBE_TXD_CMD_RS | IXGBE_TXD_CMD_IFCS;
+
+       cmd_type_len |= IXGBE_ADVTXD_DTYP_DATA;
+
+       cmd_type_len |= IXGBE_ADVTXD_DCMD_IFCS | IXGBE_ADVTXD_DCMD_DEXT;
+
+       if (tx_flags & IXGBE_TX_FLAGS_VLAN)
+               cmd_type_len |= IXGBE_ADVTXD_DCMD_VLE;
+
+       if (tx_flags & IXGBE_TX_FLAGS_TSO) {
+               cmd_type_len |= IXGBE_ADVTXD_DCMD_TSE;
+
+               olinfo_status |= IXGBE_TXD_POPTS_TXSM <<
+                       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;
+
+       } else if (tx_flags & IXGBE_TX_FLAGS_CSUM)
+               olinfo_status |= IXGBE_TXD_POPTS_TXSM <<
+                       IXGBE_ADVTXD_POPTS_SHIFT;
+
+       olinfo_status |= ((paylen - hdr_len) << IXGBE_ADVTXD_PAYLEN_SHIFT);
+
+       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->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);
+               tx_desc->read.olinfo_status = cpu_to_le32(olinfo_status);
+               i++;
+               if (i == tx_ring->count)
+                       i = 0;
+       }
+
+       tx_desc->read.cmd_type_len |= cpu_to_le32(txd_cmd);
+
+       /*
+        * Force memory writes to complete before letting h/w
+        * know there are new descriptors to fetch.  (Only
+        * applicable for weak-ordered memory model archs,
+        * such as IA-64).
+        */
+       wmb();
+
+       tx_ring->next_to_use = i;
+       writel(i, adapter->hw.hw_addr + tx_ring->tail);
+}
+
+static int __ixgbevf_maybe_stop_tx(struct net_device *netdev,
+                                  struct ixgbevf_ring *tx_ring, int size)
+{
+       struct ixgbevf_adapter *adapter = netdev_priv(netdev);
+
+       netif_stop_subqueue(netdev, tx_ring->queue_index);
+       /* Herbert's original patch had:
+        *  smp_mb__after_netif_stop_queue();
+        * but since that doesn't exist yet, just open code it. */
+       smp_mb();
+
+       /* We need to check again in a case another CPU has just
+        * made room available. */
+       if (likely(IXGBE_DESC_UNUSED(tx_ring) < size))
+               return -EBUSY;
+
+       /* A reprieve! - use start_queue because it doesn't call schedule */
+       netif_start_subqueue(netdev, tx_ring->queue_index);
+       ++adapter->restart_queue;
+       return 0;
+}
+
+static int ixgbevf_maybe_stop_tx(struct net_device *netdev,
+                                struct ixgbevf_ring *tx_ring, int size)
+{
+       if (likely(IXGBE_DESC_UNUSED(tx_ring) >= size))
+               return 0;
+       return __ixgbevf_maybe_stop_tx(netdev, tx_ring, size);
+}
+
+static int ixgbevf_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
+{
+       struct ixgbevf_adapter *adapter = netdev_priv(netdev);
+       struct ixgbevf_ring *tx_ring;
+       unsigned int first;
+       unsigned int tx_flags = 0;
+       u8 hdr_len = 0;
+       int r_idx = 0, tso;
+       int count = 0;
+
+       unsigned int f;
+
+       tx_ring = &adapter->tx_ring[r_idx];
+
+       if (adapter->vlgrp && vlan_tx_tag_present(skb)) {
+               tx_flags |= vlan_tx_tag_get(skb);
+               tx_flags <<= IXGBE_TX_FLAGS_VLAN_SHIFT;
+               tx_flags |= IXGBE_TX_FLAGS_VLAN;
+       }
+
+       /* four things can cause us to need a context descriptor */
+       if (skb_is_gso(skb) ||
+           (skb->ip_summed == CHECKSUM_PARTIAL) ||
+           (tx_flags & IXGBE_TX_FLAGS_VLAN))
+               count++;
+
+       count += TXD_USE_COUNT(skb_headlen(skb));
+       for (f = 0; f < skb_shinfo(skb)->nr_frags; f++)
+               count += TXD_USE_COUNT(skb_shinfo(skb)->frags[f].size);
+
+       if (ixgbevf_maybe_stop_tx(netdev, tx_ring, count)) {
+               adapter->tx_busy++;
+               return NETDEV_TX_BUSY;
+       }
+
+       first = tx_ring->next_to_use;
+
+       if (skb->protocol == htons(ETH_P_IP))
+               tx_flags |= IXGBE_TX_FLAGS_IPV4;
+       tso = ixgbevf_tso(adapter, tx_ring, skb, tx_flags, &hdr_len);
+       if (tso < 0) {
+               dev_kfree_skb_any(skb);
+               return NETDEV_TX_OK;
+       }
+
+       if (tso)
+               tx_flags |= IXGBE_TX_FLAGS_TSO;
+       else if (ixgbevf_tx_csum(adapter, tx_ring, skb, tx_flags) &&
+                (skb->ip_summed == CHECKSUM_PARTIAL))
+               tx_flags |= IXGBE_TX_FLAGS_CSUM;
+
+       ixgbevf_tx_queue(adapter, tx_ring, tx_flags,
+                        ixgbevf_tx_map(adapter, tx_ring, skb, tx_flags, first),
+                        skb->len, hdr_len);
+
+       netdev->trans_start = jiffies;
+
+       ixgbevf_maybe_stop_tx(netdev, tx_ring, DESC_NEEDED);
+
+       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
+ * @p: pointer to an address structure
+ *
+ * Returns 0 on success, negative on failure
+ **/
+static int ixgbevf_set_mac(struct net_device *netdev, void *p)
+{
+       struct ixgbevf_adapter *adapter = netdev_priv(netdev);
+       struct ixgbe_hw *hw = &adapter->hw;
+       struct sockaddr *addr = p;
+
+       if (!is_valid_ether_addr(addr->sa_data))
+               return -EADDRNOTAVAIL;
+
+       memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
+       memcpy(hw->mac.addr, addr->sa_data, netdev->addr_len);
+
+       if (hw->mac.ops.set_rar)
+               hw->mac.ops.set_rar(hw, 0, hw->mac.addr, 0);
+
+       return 0;
+}
+
+/**
+ * ixgbevf_change_mtu - Change the Maximum Transfer Unit
+ * @netdev: network interface device structure
+ * @new_mtu: new value for maximum frame size
+ *
+ * Returns 0 on success, negative on failure
+ **/
+static int ixgbevf_change_mtu(struct net_device *netdev, int new_mtu)
+{
+       struct ixgbevf_adapter *adapter = netdev_priv(netdev);
+       int max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN;
+
+       /* MTU < 68 is an error and causes problems on some kernels */
+       if ((new_mtu < 68) || (max_frame > MAXIMUM_ETHERNET_VLAN_SIZE))
+               return -EINVAL;
+
+       hw_dbg(&adapter->hw, "changing MTU from %d to %d\n",
+              netdev->mtu, new_mtu);
+       /* must set new MTU before calling down or up */
+       netdev->mtu = new_mtu;
+
+       if (netif_running(netdev))
+               ixgbevf_reinit_locked(adapter);
+
+       return 0;
+}
+
+static void ixgbevf_shutdown(struct pci_dev *pdev)
+{
+       struct net_device *netdev = pci_get_drvdata(pdev);
+       struct ixgbevf_adapter *adapter = netdev_priv(netdev);
+
+       netif_device_detach(netdev);
+
+       if (netif_running(netdev)) {
+               ixgbevf_down(adapter);
+               ixgbevf_free_irq(adapter);
+               ixgbevf_free_all_tx_resources(adapter);
+               ixgbevf_free_all_rx_resources(adapter);
+       }
+
+#ifdef CONFIG_PM
+       pci_save_state(pdev);
+#endif
+
+       pci_disable_device(pdev);
+}
+
+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,
+       .ndo_set_mac_address    = &ixgbevf_set_mac,
+       .ndo_change_mtu         = &ixgbevf_change_mtu,
+       .ndo_tx_timeout         = &ixgbevf_tx_timeout,
+       .ndo_vlan_rx_register   = &ixgbevf_vlan_rx_register,
+       .ndo_vlan_rx_add_vid    = &ixgbevf_vlan_rx_add_vid,
+       .ndo_vlan_rx_kill_vid   = &ixgbevf_vlan_rx_kill_vid,
+};
+
+static void ixgbevf_assign_netdev_ops(struct net_device *dev)
+{
+       struct ixgbevf_adapter *adapter;
+       adapter = netdev_priv(dev);
+       dev->netdev_ops = &ixgbe_netdev_ops;
+       ixgbevf_set_ethtool_ops(dev);
+       dev->watchdog_timeo = 5 * HZ;
+}
+
+/**
+ * ixgbevf_probe - Device Initialization Routine
+ * @pdev: PCI device information struct
+ * @ent: entry in ixgbevf_pci_tbl
+ *
+ * Returns 0 on success, negative on failure
+ *
+ * ixgbevf_probe initializes an adapter identified by a pci_dev structure.
+ * The OS initialization, configuring of the adapter private structure,
+ * and a hardware reset occur.
+ **/
+static int __devinit ixgbevf_probe(struct pci_dev *pdev,
+                                  const struct pci_device_id *ent)
+{
+       struct net_device *netdev;
+       struct ixgbevf_adapter *adapter = NULL;
+       struct ixgbe_hw *hw = NULL;
+       const struct ixgbevf_info *ii = ixgbevf_info_tbl[ent->driver_data];
+       static int cards_found;
+       int err, pci_using_dac;
+
+       err = pci_enable_device(pdev);
+       if (err)
+               return err;
+
+       if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) &&
+           !pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) {
+               pci_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) {
+                               dev_err(&pdev->dev, "No usable DMA "
+                                       "configuration, aborting\n");
+                               goto err_dma;
+                       }
+               }
+               pci_using_dac = 0;
+       }
+
+       err = pci_request_regions(pdev, ixgbevf_driver_name);
+       if (err) {
+               dev_err(&pdev->dev, "pci_request_regions failed 0x%x\n", err);
+               goto err_pci_reg;
+       }
+
+       pci_set_master(pdev);
+
+#ifdef HAVE_TX_MQ
+       netdev = alloc_etherdev_mq(sizeof(struct ixgbevf_adapter),
+                                  MAX_TX_QUEUES);
+#else
+       netdev = alloc_etherdev(sizeof(struct ixgbevf_adapter));
+#endif
+       if (!netdev) {
+               err = -ENOMEM;
+               goto err_alloc_etherdev;
+       }
+
+       SET_NETDEV_DEV(netdev, &pdev->dev);
+
+       pci_set_drvdata(pdev, netdev);
+       adapter = netdev_priv(netdev);
+
+       adapter->netdev = netdev;
+       adapter->pdev = pdev;
+       hw = &adapter->hw;
+       hw->back = adapter;
+       adapter->msg_enable = (1 << DEFAULT_DEBUG_LEVEL_SHIFT) - 1;
+
+       /*
+        * call save state here in standalone driver because it relies on
+        * adapter struct to exist, and needs to call netdev_priv
+        */
+       pci_save_state(pdev);
+
+       hw->hw_addr = ioremap(pci_resource_start(pdev, 0),
+                             pci_resource_len(pdev, 0));
+       if (!hw->hw_addr) {
+               err = -EIO;
+               goto err_ioremap;
+       }
+
+       ixgbevf_assign_netdev_ops(netdev);
+
+       adapter->bd_number = cards_found;
+
+       /* Setup hw api */
+       memcpy(&hw->mac.ops, ii->mac_ops, sizeof(hw->mac.ops));
+       hw->mac.type  = ii->mac;
+
+       memcpy(&hw->mbx.ops, &ixgbevf_mbx_ops,
+              sizeof(struct ixgbe_mac_operations));
+
+       adapter->flags &= ~IXGBE_FLAG_RX_PS_CAPABLE;
+       adapter->flags &= ~IXGBE_FLAG_RX_PS_ENABLED;
+       adapter->flags |= IXGBE_FLAG_RX_1BUF_CAPABLE;
+
+       /* setup the private structure */
+       err = ixgbevf_sw_init(adapter);
+
+       ixgbevf_init_last_counter_stats(adapter);
+
+#ifdef MAX_SKB_FRAGS
+       netdev->features = NETIF_F_SG |
+                          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;
+       netdev->features |= NETIF_F_TSO6;
+       netdev->vlan_features |= NETIF_F_TSO;
+       netdev->vlan_features |= NETIF_F_TSO6;
+       netdev->vlan_features |= NETIF_F_IP_CSUM;
+       netdev->vlan_features |= NETIF_F_SG;
+
+       if (pci_using_dac)
+               netdev->features |= NETIF_F_HIGHDMA;
+
+#endif /* MAX_SKB_FRAGS */
+
+       /* The HW MAC address was set and/or determined in sw_init */
+       memcpy(netdev->dev_addr, adapter->hw.mac.addr, netdev->addr_len);
+       memcpy(netdev->perm_addr, adapter->hw.mac.addr, netdev->addr_len);
+
+       if (!is_valid_ether_addr(netdev->dev_addr)) {
+               printk(KERN_ERR "invalid MAC address\n");
+               err = -EIO;
+               goto err_sw_init;
+       }
+
+       init_timer(&adapter->watchdog_timer);
+       adapter->watchdog_timer.function = &ixgbevf_watchdog;
+       adapter->watchdog_timer.data = (unsigned long)adapter;
+
+       INIT_WORK(&adapter->reset_task, ixgbevf_reset_task);
+       INIT_WORK(&adapter->watchdog_task, ixgbevf_watchdog_task);
+
+       err = ixgbevf_init_interrupt_scheme(adapter);
+       if (err)
+               goto err_sw_init;
+
+       /* pick up the PCI bus settings for reporting later */
+       if (hw->mac.ops.get_bus_info)
+               hw->mac.ops.get_bus_info(hw);
+
+
+       netif_carrier_off(netdev);
+       netif_tx_stop_all_queues(netdev);
+
+       strcpy(netdev->name, "eth%d");
+
+       err = register_netdev(netdev);
+       if (err)
+               goto err_register;
+
+       adapter->netdev_registered = true;
+
+       /* print the MAC address */
+       hw_dbg(hw, "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n",
+              netdev->dev_addr[0],
+              netdev->dev_addr[1],
+              netdev->dev_addr[2],
+              netdev->dev_addr[3],
+              netdev->dev_addr[4],
+              netdev->dev_addr[5]);
+
+       hw_dbg(hw, "MAC: %d\n", hw->mac.type);
+
+       hw_dbg(hw, "LRO is disabled \n");
+
+       hw_dbg(hw, "Intel(R) 82599 Virtual Function\n");
+       cards_found++;
+       return 0;
+
+err_register:
+err_sw_init:
+       ixgbevf_reset_interrupt_capability(adapter);
+       iounmap(hw->hw_addr);
+err_ioremap:
+       free_netdev(netdev);
+err_alloc_etherdev:
+       pci_release_regions(pdev);
+err_pci_reg:
+err_dma:
+       pci_disable_device(pdev);
+       return err;
+}
+
+/**
+ * ixgbevf_remove - Device Removal Routine
+ * @pdev: PCI device information struct
+ *
+ * ixgbevf_remove is called by the PCI subsystem to alert the driver
+ * that it should release a PCI device.  The could be caused by a
+ * Hot-Plug event, or because the driver is going to be removed from
+ * memory.
+ **/
+static void __devexit ixgbevf_remove(struct pci_dev *pdev)
+{
+       struct net_device *netdev = pci_get_drvdata(pdev);
+       struct ixgbevf_adapter *adapter = netdev_priv(netdev);
+
+       set_bit(__IXGBEVF_DOWN, &adapter->state);
+
+       del_timer_sync(&adapter->watchdog_timer);
+
+       cancel_work_sync(&adapter->watchdog_task);
+
+       flush_scheduled_work();
+
+       if (adapter->netdev_registered) {
+               unregister_netdev(netdev);
+               adapter->netdev_registered = false;
+       }
+
+       ixgbevf_reset_interrupt_capability(adapter);
+
+       iounmap(adapter->hw.hw_addr);
+       pci_release_regions(pdev);
+
+       hw_dbg(&adapter->hw, "Remove complete\n");
+
+       kfree(adapter->tx_ring);
+       kfree(adapter->rx_ring);
+
+       free_netdev(netdev);
+
+       pci_disable_device(pdev);
+}
+
+static struct pci_driver ixgbevf_driver = {
+       .name     = ixgbevf_driver_name,
+       .id_table = ixgbevf_pci_tbl,
+       .probe    = ixgbevf_probe,
+       .remove   = __devexit_p(ixgbevf_remove),
+       .shutdown = ixgbevf_shutdown,
+};
+
+/**
+ * ixgbe_init_module - Driver Registration Routine
+ *
+ * ixgbe_init_module is the first routine called when the driver is
+ * loaded. All it does is register with the PCI subsystem.
+ **/
+static int __init ixgbevf_init_module(void)
+{
+       int ret;
+       printk(KERN_INFO "ixgbevf: %s - version %s\n", ixgbevf_driver_string,
+              ixgbevf_driver_version);
+
+       printk(KERN_INFO "%s\n", ixgbevf_copyright);
+
+       ret = pci_register_driver(&ixgbevf_driver);
+       return ret;
+}
+
+module_init(ixgbevf_init_module);
+
+/**
+ * ixgbe_exit_module - Driver Exit Cleanup Routine
+ *
+ * ixgbe_exit_module is called just before the driver is removed
+ * from memory.
+ **/
+static void __exit ixgbevf_exit_module(void)
+{
+       pci_unregister_driver(&ixgbevf_driver);
+}
+
+#ifdef DEBUG
+/**
+ * ixgbe_get_hw_dev_name - return device name string
+ * used by hardware layer to print debugging information
+ **/
+char *ixgbevf_get_hw_dev_name(struct ixgbe_hw *hw)
+{
+       struct ixgbevf_adapter *adapter = hw->back;
+       return adapter->netdev->name;
+}
+
+#endif
+module_exit(ixgbevf_exit_module);
+
+/* ixgbevf_main.c */
diff --git a/drivers/net/ixgbevf/mbx.c b/drivers/net/ixgbevf/mbx.c
new file mode 100644 (file)
index 0000000..b814350
--- /dev/null
@@ -0,0 +1,341 @@
+/*******************************************************************************
+
+  Intel 82599 Virtual Function driver
+  Copyright(c) 1999 - 2009 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#include "mbx.h"
+
+/**
+ *  ixgbevf_poll_for_msg - Wait for message notification
+ *  @hw: pointer to the HW structure
+ *
+ *  returns 0 if it successfully received a message notification
+ **/
+static s32 ixgbevf_poll_for_msg(struct ixgbe_hw *hw)
+{
+       struct ixgbe_mbx_info *mbx = &hw->mbx;
+       int countdown = mbx->timeout;
+
+       while (countdown && mbx->ops.check_for_msg(hw)) {
+               countdown--;
+               udelay(mbx->udelay);
+       }
+
+       /* if we failed, all future posted messages fail until reset */
+       if (!countdown)
+               mbx->timeout = 0;
+
+       return countdown ? 0 : IXGBE_ERR_MBX;
+}
+
+/**
+ *  ixgbevf_poll_for_ack - Wait for message acknowledgement
+ *  @hw: pointer to the HW structure
+ *
+ *  returns 0 if it successfully received a message acknowledgement
+ **/
+static s32 ixgbevf_poll_for_ack(struct ixgbe_hw *hw)
+{
+       struct ixgbe_mbx_info *mbx = &hw->mbx;
+       int countdown = mbx->timeout;
+
+       while (countdown && mbx->ops.check_for_ack(hw)) {
+               countdown--;
+               udelay(mbx->udelay);
+       }
+
+       /* if we failed, all future posted messages fail until reset */
+       if (!countdown)
+               mbx->timeout = 0;
+
+       return countdown ? 0 : IXGBE_ERR_MBX;
+}
+
+/**
+ *  ixgbevf_read_posted_mbx - Wait for message notification and receive message
+ *  @hw: pointer to the HW structure
+ *  @msg: The message buffer
+ *  @size: Length of buffer
+ *
+ *  returns 0 if it successfully received a message notification and
+ *  copied it into the receive buffer.
+ **/
+static s32 ixgbevf_read_posted_mbx(struct ixgbe_hw *hw, u32 *msg, u16 size)
+{
+       struct ixgbe_mbx_info *mbx = &hw->mbx;
+       s32 ret_val = IXGBE_ERR_MBX;
+
+       ret_val = ixgbevf_poll_for_msg(hw);
+
+       /* if ack received read message, otherwise we timed out */
+       if (!ret_val)
+               ret_val = mbx->ops.read(hw, msg, size);
+
+       return ret_val;
+}
+
+/**
+ *  ixgbevf_write_posted_mbx - Write a message to the mailbox, wait for ack
+ *  @hw: pointer to the HW structure
+ *  @msg: The message buffer
+ *  @size: Length of buffer
+ *
+ *  returns 0 if it successfully copied message into the buffer and
+ *  received an ack to that message within delay * timeout period
+ **/
+static s32 ixgbevf_write_posted_mbx(struct ixgbe_hw *hw, u32 *msg, u16 size)
+{
+       struct ixgbe_mbx_info *mbx = &hw->mbx;
+       s32 ret_val;
+
+       /* send msg */
+       ret_val = mbx->ops.write(hw, msg, size);
+
+       /* if msg sent wait until we receive an ack */
+       if (!ret_val)
+               ret_val = ixgbevf_poll_for_ack(hw);
+
+       return ret_val;
+}
+
+/**
+ *  ixgbevf_read_v2p_mailbox - read v2p mailbox
+ *  @hw: pointer to the HW structure
+ *
+ *  This function is used to read the v2p mailbox without losing the read to
+ *  clear status bits.
+ **/
+static u32 ixgbevf_read_v2p_mailbox(struct ixgbe_hw *hw)
+{
+       u32 v2p_mailbox = IXGBE_READ_REG(hw, IXGBE_VFMAILBOX);
+
+       v2p_mailbox |= hw->mbx.v2p_mailbox;
+       hw->mbx.v2p_mailbox |= v2p_mailbox & IXGBE_VFMAILBOX_R2C_BITS;
+
+       return v2p_mailbox;
+}
+
+/**
+ *  ixgbevf_check_for_bit_vf - Determine if a status bit was set
+ *  @hw: pointer to the HW structure
+ *  @mask: bitmask for bits to be tested and cleared
+ *
+ *  This function is used to check for the read to clear bits within
+ *  the V2P mailbox.
+ **/
+static s32 ixgbevf_check_for_bit_vf(struct ixgbe_hw *hw, u32 mask)
+{
+       u32 v2p_mailbox = ixgbevf_read_v2p_mailbox(hw);
+       s32 ret_val = IXGBE_ERR_MBX;
+
+       if (v2p_mailbox & mask)
+               ret_val = 0;
+
+       hw->mbx.v2p_mailbox &= ~mask;
+
+       return ret_val;
+}
+
+/**
+ *  ixgbevf_check_for_msg_vf - checks to see if the PF has sent mail
+ *  @hw: pointer to the HW structure
+ *
+ *  returns 0 if the PF has set the Status bit or else ERR_MBX
+ **/
+static s32 ixgbevf_check_for_msg_vf(struct ixgbe_hw *hw)
+{
+       s32 ret_val = IXGBE_ERR_MBX;
+
+       if (!ixgbevf_check_for_bit_vf(hw, IXGBE_VFMAILBOX_PFSTS)) {
+               ret_val = 0;
+               hw->mbx.stats.reqs++;
+       }
+
+       return ret_val;
+}
+
+/**
+ *  ixgbevf_check_for_ack_vf - checks to see if the PF has ACK'd
+ *  @hw: pointer to the HW structure
+ *
+ *  returns 0 if the PF has set the ACK bit or else ERR_MBX
+ **/
+static s32 ixgbevf_check_for_ack_vf(struct ixgbe_hw *hw)
+{
+       s32 ret_val = IXGBE_ERR_MBX;
+
+       if (!ixgbevf_check_for_bit_vf(hw, IXGBE_VFMAILBOX_PFACK)) {
+               ret_val = 0;
+               hw->mbx.stats.acks++;
+       }
+
+       return ret_val;
+}
+
+/**
+ *  ixgbevf_check_for_rst_vf - checks to see if the PF has reset
+ *  @hw: pointer to the HW structure
+ *
+ *  returns true if the PF has set the reset done bit or else false
+ **/
+static s32 ixgbevf_check_for_rst_vf(struct ixgbe_hw *hw)
+{
+       s32 ret_val = IXGBE_ERR_MBX;
+
+       if (!ixgbevf_check_for_bit_vf(hw, (IXGBE_VFMAILBOX_RSTD |
+                                        IXGBE_VFMAILBOX_RSTI))) {
+               ret_val = 0;
+               hw->mbx.stats.rsts++;
+       }
+
+       return ret_val;
+}
+
+/**
+ *  ixgbevf_obtain_mbx_lock_vf - obtain mailbox lock
+ *  @hw: pointer to the HW structure
+ *
+ *  return 0 if we obtained the mailbox lock
+ **/
+static s32 ixgbevf_obtain_mbx_lock_vf(struct ixgbe_hw *hw)
+{
+       s32 ret_val = IXGBE_ERR_MBX;
+
+       /* Take ownership of the buffer */
+       IXGBE_WRITE_REG(hw, IXGBE_VFMAILBOX, IXGBE_VFMAILBOX_VFU);
+
+       /* reserve mailbox for vf use */
+       if (ixgbevf_read_v2p_mailbox(hw) & IXGBE_VFMAILBOX_VFU)
+               ret_val = 0;
+
+       return ret_val;
+}
+
+/**
+ *  ixgbevf_write_mbx_vf - Write a message to the mailbox
+ *  @hw: pointer to the HW structure
+ *  @msg: The message buffer
+ *  @size: Length of buffer
+ *
+ *  returns 0 if it successfully copied message into the buffer
+ **/
+static s32 ixgbevf_write_mbx_vf(struct ixgbe_hw *hw, u32 *msg, u16 size)
+{
+       s32 ret_val;
+       u16 i;
+
+
+       /* lock the mailbox to prevent pf/vf race condition */
+       ret_val = ixgbevf_obtain_mbx_lock_vf(hw);
+       if (ret_val)
+               goto out_no_write;
+
+       /* flush msg and acks as we are overwriting the message buffer */
+       ixgbevf_check_for_msg_vf(hw);
+       ixgbevf_check_for_ack_vf(hw);
+
+       /* copy the caller specified message to the mailbox memory buffer */
+       for (i = 0; i < size; i++)
+               IXGBE_WRITE_REG_ARRAY(hw, IXGBE_VFMBMEM, i, msg[i]);
+
+       /* update stats */
+       hw->mbx.stats.msgs_tx++;
+
+       /* Drop VFU and interrupt the PF to tell it a message has been sent */
+       IXGBE_WRITE_REG(hw, IXGBE_VFMAILBOX, IXGBE_VFMAILBOX_REQ);
+
+out_no_write:
+       return ret_val;
+}
+
+/**
+ *  ixgbevf_read_mbx_vf - Reads a message from the inbox intended for vf
+ *  @hw: pointer to the HW structure
+ *  @msg: The message buffer
+ *  @size: Length of buffer
+ *
+ *  returns 0 if it successfuly read message from buffer
+ **/
+static s32 ixgbevf_read_mbx_vf(struct ixgbe_hw *hw, u32 *msg, u16 size)
+{
+       s32 ret_val = 0;
+       u16 i;
+
+       /* lock the mailbox to prevent pf/vf race condition */
+       ret_val = ixgbevf_obtain_mbx_lock_vf(hw);
+       if (ret_val)
+               goto out_no_read;
+
+       /* copy the message from the mailbox memory buffer */
+       for (i = 0; i < size; i++)
+               msg[i] = IXGBE_READ_REG_ARRAY(hw, IXGBE_VFMBMEM, i);
+
+       /* Acknowledge receipt and release mailbox, then we're done */
+       IXGBE_WRITE_REG(hw, IXGBE_VFMAILBOX, IXGBE_VFMAILBOX_ACK);
+
+       /* update stats */
+       hw->mbx.stats.msgs_rx++;
+
+out_no_read:
+       return ret_val;
+}
+
+/**
+ *  ixgbevf_init_mbx_params_vf - set initial values for vf mailbox
+ *  @hw: pointer to the HW structure
+ *
+ *  Initializes the hw->mbx struct to correct values for vf mailbox
+ */
+s32 ixgbevf_init_mbx_params_vf(struct ixgbe_hw *hw)
+{
+       struct ixgbe_mbx_info *mbx = &hw->mbx;
+
+       /* start mailbox as timed out and let the reset_hw call set the timeout
+        * value to begin communications */
+       mbx->timeout = 0;
+       mbx->udelay = IXGBE_VF_MBX_INIT_DELAY;
+
+       mbx->size = IXGBE_VFMAILBOX_SIZE;
+
+       mbx->stats.msgs_tx = 0;
+       mbx->stats.msgs_rx = 0;
+       mbx->stats.reqs = 0;
+       mbx->stats.acks = 0;
+       mbx->stats.rsts = 0;
+
+       return 0;
+}
+
+struct ixgbe_mbx_operations ixgbevf_mbx_ops = {
+       .init_params   = ixgbevf_init_mbx_params_vf,
+       .read          = ixgbevf_read_mbx_vf,
+       .write         = ixgbevf_write_mbx_vf,
+       .read_posted   = ixgbevf_read_posted_mbx,
+       .write_posted  = ixgbevf_write_posted_mbx,
+       .check_for_msg = ixgbevf_check_for_msg_vf,
+       .check_for_ack = ixgbevf_check_for_ack_vf,
+       .check_for_rst = ixgbevf_check_for_rst_vf,
+};
+
diff --git a/drivers/net/ixgbevf/mbx.h b/drivers/net/ixgbevf/mbx.h
new file mode 100644 (file)
index 0000000..1b0e0bf
--- /dev/null
@@ -0,0 +1,100 @@
+/*******************************************************************************
+
+  Intel 82599 Virtual Function driver
+  Copyright(c) 1999 - 2009 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _IXGBE_MBX_H_
+#define _IXGBE_MBX_H_
+
+#include "vf.h"
+
+#define IXGBE_VFMAILBOX_SIZE        16 /* 16 32 bit words - 64 bytes */
+#define IXGBE_ERR_MBX               -100
+
+#define IXGBE_VFMAILBOX             0x002FC
+#define IXGBE_VFMBMEM               0x00200
+
+/* Define mailbox register bits */
+#define IXGBE_VFMAILBOX_REQ      0x00000001 /* Request for PF Ready bit */
+#define IXGBE_VFMAILBOX_ACK      0x00000002 /* Ack PF message received */
+#define IXGBE_VFMAILBOX_VFU      0x00000004 /* VF owns the mailbox buffer */
+#define IXGBE_VFMAILBOX_PFU      0x00000008 /* PF owns the mailbox buffer */
+#define IXGBE_VFMAILBOX_PFSTS    0x00000010 /* PF wrote a message in the MB */
+#define IXGBE_VFMAILBOX_PFACK    0x00000020 /* PF ack the previous VF msg */
+#define IXGBE_VFMAILBOX_RSTI     0x00000040 /* PF has reset indication */
+#define IXGBE_VFMAILBOX_RSTD     0x00000080 /* PF has indicated reset done */
+#define IXGBE_VFMAILBOX_R2C_BITS 0x000000B0 /* All read to clear bits */
+
+#define IXGBE_PFMAILBOX(x)          (0x04B00 + (4 * x))
+#define IXGBE_PFMBMEM(vfn)          (0x13000 + (64 * vfn))
+
+#define IXGBE_PFMAILBOX_STS   0x00000001 /* Initiate message send to VF */
+#define IXGBE_PFMAILBOX_ACK   0x00000002 /* Ack message recv'd from VF */
+#define IXGBE_PFMAILBOX_VFU   0x00000004 /* VF owns the mailbox buffer */
+#define IXGBE_PFMAILBOX_PFU   0x00000008 /* PF owns the mailbox buffer */
+#define IXGBE_PFMAILBOX_RVFU  0x00000010 /* Reset VFU - used when VF stuck */
+
+#define IXGBE_MBVFICR_VFREQ_MASK 0x0000FFFF /* bits for VF messages */
+#define IXGBE_MBVFICR_VFREQ_VF1  0x00000001 /* bit for VF 1 message */
+#define IXGBE_MBVFICR_VFACK_MASK 0xFFFF0000 /* bits for VF acks */
+#define IXGBE_MBVFICR_VFACK_VF1  0x00010000 /* bit for VF 1 ack */
+
+
+/* If it's a IXGBE_VF_* msg then it originates in the VF and is sent to the
+ * PF.  The reverse is true if it is IXGBE_PF_*.
+ * Message ACK's are the value or'd with 0xF0000000
+ */
+#define IXGBE_VT_MSGTYPE_ACK      0x80000000  /* Messages below or'd with
+                                              * this are the ACK */
+#define IXGBE_VT_MSGTYPE_NACK     0x40000000  /* Messages below or'd with
+                                              * this are the NACK */
+#define IXGBE_VT_MSGTYPE_CTS      0x20000000  /* Indicates that VF is still
+                                              *  clear to send requests */
+#define IXGBE_VT_MSGINFO_SHIFT    16
+/* bits 23:16 are used for exra info for certain messages */
+#define IXGBE_VT_MSGINFO_MASK     (0xFF << IXGBE_VT_MSGINFO_SHIFT)
+
+#define IXGBE_VF_RESET            0x01 /* VF requests reset */
+#define IXGBE_VF_SET_MAC_ADDR     0x02 /* VF requests PF to set MAC addr */
+#define IXGBE_VF_SET_MULTICAST    0x03 /* VF requests PF to set MC addr */
+#define IXGBE_VF_SET_VLAN         0x04 /* VF requests PF to set VLAN */
+#define IXGBE_VF_SET_LPE          0x05 /* VF requests PF to set VMOLR.LPE */
+
+/* length of permanent address message returned from PF */
+#define IXGBE_VF_PERMADDR_MSG_LEN 4
+/* word in permanent address message with the current multicast type */
+#define IXGBE_VF_MC_TYPE_WORD     3
+
+#define IXGBE_PF_CONTROL_MSG      0x0100 /* PF control message */
+
+#define IXGBE_VF_MBX_INIT_TIMEOUT 2000 /* number of retries on mailbox */
+#define IXGBE_VF_MBX_INIT_DELAY   500  /* microseconds between retries */
+
+/* forward declaration of the HW struct */
+struct ixgbe_hw;
+
+s32 ixgbevf_init_mbx_params_vf(struct ixgbe_hw *);
+
+#endif /* _IXGBE_MBX_H_ */
diff --git a/drivers/net/ixgbevf/regs.h b/drivers/net/ixgbevf/regs.h
new file mode 100644 (file)
index 0000000..12f7596
--- /dev/null
@@ -0,0 +1,85 @@
+/*******************************************************************************
+
+  Intel 82599 Virtual Function driver
+  Copyright(c) 1999 - 2009 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _IXGBEVF_REGS_H_
+#define _IXGBEVF_REGS_H_
+
+#define IXGBE_VFCTRL           0x00000
+#define IXGBE_VFSTATUS         0x00008
+#define IXGBE_VFLINKS          0x00010
+#define IXGBE_VFRTIMER         0x00048
+#define IXGBE_VFRXMEMWRAP      0x03190
+#define IXGBE_VTEICR           0x00100
+#define IXGBE_VTEICS           0x00104
+#define IXGBE_VTEIMS           0x00108
+#define IXGBE_VTEIMC           0x0010C
+#define IXGBE_VTEIAC           0x00110
+#define IXGBE_VTEIAM           0x00114
+#define IXGBE_VTEITR(x)        (0x00820 + (4 * x))
+#define IXGBE_VTIVAR(x)        (0x00120 + (4 * x))
+#define IXGBE_VTIVAR_MISC      0x00140
+#define IXGBE_VTRSCINT(x)      (0x00180 + (4 * x))
+#define IXGBE_VFRDBAL(x)       (0x01000 + (0x40 * x))
+#define IXGBE_VFRDBAH(x)       (0x01004 + (0x40 * x))
+#define IXGBE_VFRDLEN(x)       (0x01008 + (0x40 * x))
+#define IXGBE_VFRDH(x)         (0x01010 + (0x40 * x))
+#define IXGBE_VFRDT(x)         (0x01018 + (0x40 * x))
+#define IXGBE_VFRXDCTL(x)      (0x01028 + (0x40 * x))
+#define IXGBE_VFSRRCTL(x)      (0x01014 + (0x40 * x))
+#define IXGBE_VFRSCCTL(x)      (0x0102C + (0x40 * x))
+#define IXGBE_VFPSRTYPE        0x00300
+#define IXGBE_VFTDBAL(x)       (0x02000 + (0x40 * x))
+#define IXGBE_VFTDBAH(x)       (0x02004 + (0x40 * x))
+#define IXGBE_VFTDLEN(x)       (0x02008 + (0x40 * x))
+#define IXGBE_VFTDH(x)         (0x02010 + (0x40 * x))
+#define IXGBE_VFTDT(x)         (0x02018 + (0x40 * x))
+#define IXGBE_VFTXDCTL(x)      (0x02028 + (0x40 * x))
+#define IXGBE_VFTDWBAL(x)      (0x02038 + (0x40 * x))
+#define IXGBE_VFTDWBAH(x)      (0x0203C + (0x40 * x))
+#define IXGBE_VFDCA_RXCTRL(x)  (0x0100C + (0x40 * x))
+#define IXGBE_VFDCA_TXCTRL(x)  (0x0200c + (0x40 * x))
+#define IXGBE_VFGPRC           0x0101C
+#define IXGBE_VFGPTC           0x0201C
+#define IXGBE_VFGORC_LSB       0x01020
+#define IXGBE_VFGORC_MSB       0x01024
+#define IXGBE_VFGOTC_LSB       0x02020
+#define IXGBE_VFGOTC_MSB       0x02024
+#define IXGBE_VFMPRC           0x01034
+
+#define IXGBE_WRITE_REG(a, reg, value) writel((value), ((a)->hw_addr + (reg)))
+
+#define IXGBE_READ_REG(a, reg) readl((a)->hw_addr + (reg))
+
+#define IXGBE_WRITE_REG_ARRAY(a, reg, offset, value) ( \
+    writel((value), ((a)->hw_addr + (reg) + ((offset) << 2))))
+
+#define IXGBE_READ_REG_ARRAY(a, reg, offset) ( \
+    readl((a)->hw_addr + (reg) + ((offset) << 2)))
+
+#define IXGBE_WRITE_FLUSH(a) (IXGBE_READ_REG(a, IXGBE_VFSTATUS))
+
+#endif /* _IXGBEVF_REGS_H_ */
diff --git a/drivers/net/ixgbevf/vf.c b/drivers/net/ixgbevf/vf.c
new file mode 100644 (file)
index 0000000..4b5dec0
--- /dev/null
@@ -0,0 +1,387 @@
+/*******************************************************************************
+
+  Intel 82599 Virtual Function driver
+  Copyright(c) 1999 - 2009 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#include "vf.h"
+
+/**
+ *  ixgbevf_start_hw_vf - Prepare hardware for Tx/Rx
+ *  @hw: pointer to hardware structure
+ *
+ *  Starts the hardware by filling the bus info structure and media type, clears
+ *  all on chip counters, initializes receive address registers, multicast
+ *  table, VLAN filter table, calls routine to set up link and flow control
+ *  settings, and leaves transmit and receive units disabled and uninitialized
+ **/
+static s32 ixgbevf_start_hw_vf(struct ixgbe_hw *hw)
+{
+       /* Clear adapter stopped flag */
+       hw->adapter_stopped = false;
+
+       return 0;
+}
+
+/**
+ *  ixgbevf_init_hw_vf - virtual function hardware initialization
+ *  @hw: pointer to hardware structure
+ *
+ *  Initialize the hardware by resetting the hardware and then starting
+ *  the hardware
+ **/
+static s32 ixgbevf_init_hw_vf(struct ixgbe_hw *hw)
+{
+       s32 status = hw->mac.ops.start_hw(hw);
+
+       hw->mac.ops.get_mac_addr(hw, hw->mac.addr);
+
+       return status;
+}
+
+/**
+ *  ixgbevf_reset_hw_vf - Performs hardware reset
+ *  @hw: pointer to hardware structure
+ *
+ *  Resets the hardware by reseting the transmit and receive units, masks and
+ *  clears all interrupts.
+ **/
+static s32 ixgbevf_reset_hw_vf(struct ixgbe_hw *hw)
+{
+       struct ixgbe_mbx_info *mbx = &hw->mbx;
+       u32 timeout = IXGBE_VF_INIT_TIMEOUT;
+       s32 ret_val = IXGBE_ERR_INVALID_MAC_ADDR;
+       u32 msgbuf[IXGBE_VF_PERMADDR_MSG_LEN];
+       u8 *addr = (u8 *)(&msgbuf[1]);
+
+       /* Call adapter stop to disable tx/rx and clear interrupts */
+       hw->mac.ops.stop_adapter(hw);
+
+       IXGBE_WRITE_REG(hw, IXGBE_VFCTRL, IXGBE_CTRL_RST);
+       IXGBE_WRITE_FLUSH(hw);
+
+       /* we cannot reset while the RSTI / RSTD bits are asserted */
+       while (!mbx->ops.check_for_rst(hw) && timeout) {
+               timeout--;
+               udelay(5);
+       }
+
+       if (!timeout)
+               return IXGBE_ERR_RESET_FAILED;
+
+       /* mailbox timeout can now become active */
+       mbx->timeout = IXGBE_VF_MBX_INIT_TIMEOUT;
+
+       msgbuf[0] = IXGBE_VF_RESET;
+       mbx->ops.write_posted(hw, msgbuf, 1);
+
+       msleep(10);
+
+       /* set our "perm_addr" based on info provided by PF */
+       /* also set up the mc_filter_type which is piggy backed
+        * on the mac address in word 3 */
+       ret_val = mbx->ops.read_posted(hw, msgbuf, IXGBE_VF_PERMADDR_MSG_LEN);
+       if (ret_val)
+               return ret_val;
+
+       if (msgbuf[0] != (IXGBE_VF_RESET | IXGBE_VT_MSGTYPE_ACK))
+               return IXGBE_ERR_INVALID_MAC_ADDR;
+
+       memcpy(hw->mac.perm_addr, addr, IXGBE_ETH_LENGTH_OF_ADDRESS);
+       hw->mac.mc_filter_type = msgbuf[IXGBE_VF_MC_TYPE_WORD];
+
+       return 0;
+}
+
+/**
+ *  ixgbevf_stop_hw_vf - Generic stop Tx/Rx units
+ *  @hw: pointer to hardware structure
+ *
+ *  Sets the adapter_stopped flag within ixgbe_hw struct. Clears interrupts,
+ *  disables transmit and receive units. The adapter_stopped flag is used by
+ *  the shared code and drivers to determine if the adapter is in a stopped
+ *  state and should not touch the hardware.
+ **/
+static s32 ixgbevf_stop_hw_vf(struct ixgbe_hw *hw)
+{
+       u32 number_of_queues;
+       u32 reg_val;
+       u16 i;
+
+       /*
+        * Set the adapter_stopped flag so other driver functions stop touching
+        * the hardware
+        */
+       hw->adapter_stopped = true;
+
+       /* Disable the receive unit by stopped each queue */
+       number_of_queues = hw->mac.max_rx_queues;
+       for (i = 0; i < number_of_queues; i++) {
+               reg_val = IXGBE_READ_REG(hw, IXGBE_VFRXDCTL(i));
+               if (reg_val & IXGBE_RXDCTL_ENABLE) {
+                       reg_val &= ~IXGBE_RXDCTL_ENABLE;
+                       IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(i), reg_val);
+               }
+       }
+
+       IXGBE_WRITE_FLUSH(hw);
+
+       /* Clear interrupt mask to stop from interrupts being generated */
+       IXGBE_WRITE_REG(hw, IXGBE_VTEIMC, IXGBE_VF_IRQ_CLEAR_MASK);
+
+       /* Clear any pending interrupts */
+       IXGBE_READ_REG(hw, IXGBE_VTEICR);
+
+       /* Disable the transmit unit.  Each queue must be disabled. */
+       number_of_queues = hw->mac.max_tx_queues;
+       for (i = 0; i < number_of_queues; i++) {
+               reg_val = IXGBE_READ_REG(hw, IXGBE_VFTXDCTL(i));
+               if (reg_val & IXGBE_TXDCTL_ENABLE) {
+                       reg_val &= ~IXGBE_TXDCTL_ENABLE;
+                       IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(i), reg_val);
+               }
+       }
+
+       return 0;
+}
+
+/**
+ *  ixgbevf_mta_vector - Determines bit-vector in multicast table to set
+ *  @hw: pointer to hardware structure
+ *  @mc_addr: the multicast address
+ *
+ *  Extracts the 12 bits, from a multicast address, to determine which
+ *  bit-vector to set in the multicast table. The hardware uses 12 bits, from
+ *  incoming rx multicast addresses, to determine the bit-vector to check in
+ *  the MTA. Which of the 4 combination, of 12-bits, the hardware uses is set
+ *  by the MO field of the MCSTCTRL. The MO field is set during initialization
+ *  to mc_filter_type.
+ **/
+static s32 ixgbevf_mta_vector(struct ixgbe_hw *hw, u8 *mc_addr)
+{
+       u32 vector = 0;
+
+       switch (hw->mac.mc_filter_type) {
+       case 0:   /* use bits [47:36] of the address */
+               vector = ((mc_addr[4] >> 4) | (((u16)mc_addr[5]) << 4));
+               break;
+       case 1:   /* use bits [46:35] of the address */
+               vector = ((mc_addr[4] >> 3) | (((u16)mc_addr[5]) << 5));
+               break;
+       case 2:   /* use bits [45:34] of the address */
+               vector = ((mc_addr[4] >> 2) | (((u16)mc_addr[5]) << 6));
+               break;
+       case 3:   /* use bits [43:32] of the address */
+               vector = ((mc_addr[4]) | (((u16)mc_addr[5]) << 8));
+               break;
+       default:  /* Invalid mc_filter_type */
+               break;
+       }
+
+       /* vector can only be 12-bits or boundary will be exceeded */
+       vector &= 0xFFF;
+       return vector;
+}
+
+/**
+ *  ixgbevf_get_mac_addr_vf - Read device MAC address
+ *  @hw: pointer to the HW structure
+ *  @mac_addr: pointer to storage for retrieved MAC address
+ **/
+static s32 ixgbevf_get_mac_addr_vf(struct ixgbe_hw *hw, u8 *mac_addr)
+{
+       memcpy(mac_addr, hw->mac.perm_addr, IXGBE_ETH_LENGTH_OF_ADDRESS);
+
+       return 0;
+}
+
+/**
+ *  ixgbevf_set_rar_vf - set device MAC address
+ *  @hw: pointer to hardware structure
+ *  @index: Receive address register to write
+ *  @addr: Address to put into receive address register
+ *  @vmdq: Unused in this implementation
+ **/
+static s32 ixgbevf_set_rar_vf(struct ixgbe_hw *hw, u32 index, u8 *addr,
+                             u32 vmdq)
+{
+       struct ixgbe_mbx_info *mbx = &hw->mbx;
+       u32 msgbuf[3];
+       u8 *msg_addr = (u8 *)(&msgbuf[1]);
+       s32 ret_val;
+
+       memset(msgbuf, 0, sizeof(msgbuf));
+       msgbuf[0] = IXGBE_VF_SET_MAC_ADDR;
+       memcpy(msg_addr, addr, 6);
+       ret_val = mbx->ops.write_posted(hw, msgbuf, 3);
+
+       if (!ret_val)
+               ret_val = mbx->ops.read_posted(hw, msgbuf, 3);
+
+       msgbuf[0] &= ~IXGBE_VT_MSGTYPE_CTS;
+
+       /* if nacked the address was rejected, use "perm_addr" */
+       if (!ret_val &&
+           (msgbuf[0] == (IXGBE_VF_SET_MAC_ADDR | IXGBE_VT_MSGTYPE_NACK)))
+               ixgbevf_get_mac_addr_vf(hw, hw->mac.addr);
+
+       return ret_val;
+}
+
+/**
+ *  ixgbevf_update_mc_addr_list_vf - Update Multicast addresses
+ *  @hw: pointer to the HW structure
+ *  @mc_addr_list: array of multicast addresses to program
+ *  @mc_addr_count: number of multicast addresses to program
+ *  @next: caller supplied function to return next address in list
+ *
+ *  Updates the Multicast Table Array.
+ **/
+static s32 ixgbevf_update_mc_addr_list_vf(struct ixgbe_hw *hw, u8 *mc_addr_list,
+                                       u32 mc_addr_count,
+                                       ixgbe_mc_addr_itr next)
+{
+       struct ixgbe_mbx_info *mbx = &hw->mbx;
+       u32 msgbuf[IXGBE_VFMAILBOX_SIZE];
+       u16 *vector_list = (u16 *)&msgbuf[1];
+       u32 vector;
+       u32 cnt, i;
+       u32 vmdq;
+
+       /* Each entry in the list uses 1 16 bit word.  We have 30
+        * 16 bit words available in our HW msg buffer (minus 1 for the
+        * msg type).  That's 30 hash values if we pack 'em right.  If
+        * there are more than 30 MC addresses to add then punt the
+        * extras for now and then add code to handle more than 30 later.
+        * It would be unusual for a server to request that many multi-cast
+        * addresses except for in large enterprise network environments.
+        */
+
+       cnt = (mc_addr_count > 30) ? 30 : mc_addr_count;
+       msgbuf[0] = IXGBE_VF_SET_MULTICAST;
+       msgbuf[0] |= cnt << IXGBE_VT_MSGINFO_SHIFT;
+
+       for (i = 0; i < cnt; i++) {
+               vector = ixgbevf_mta_vector(hw, next(hw, &mc_addr_list, &vmdq));
+               vector_list[i] = vector;
+       }
+
+       mbx->ops.write_posted(hw, msgbuf, IXGBE_VFMAILBOX_SIZE);
+
+       return 0;
+}
+
+/**
+ *  ixgbevf_set_vfta_vf - Set/Unset vlan filter table address
+ *  @hw: pointer to the HW structure
+ *  @vlan: 12 bit VLAN ID
+ *  @vind: unused by VF drivers
+ *  @vlan_on: if true then set bit, else clear bit
+ **/
+static s32 ixgbevf_set_vfta_vf(struct ixgbe_hw *hw, u32 vlan, u32 vind,
+                              bool vlan_on)
+{
+       struct ixgbe_mbx_info *mbx = &hw->mbx;
+       u32 msgbuf[2];
+
+       msgbuf[0] = IXGBE_VF_SET_VLAN;
+       msgbuf[1] = vlan;
+       /* Setting the 8 bit field MSG INFO to TRUE indicates "add" */
+       msgbuf[0] |= vlan_on << IXGBE_VT_MSGINFO_SHIFT;
+
+       return mbx->ops.write_posted(hw, msgbuf, 2);
+}
+
+/**
+ *  ixgbevf_setup_mac_link_vf - Setup MAC link settings
+ *  @hw: pointer to hardware structure
+ *  @speed: Unused in this implementation
+ *  @autoneg: Unused in this implementation
+ *  @autoneg_wait_to_complete: Unused in this implementation
+ *
+ *  Do nothing and return success.  VF drivers are not allowed to change
+ *  global settings.  Maintained for driver compatibility.
+ **/
+static s32 ixgbevf_setup_mac_link_vf(struct ixgbe_hw *hw,
+                                    ixgbe_link_speed speed, bool autoneg,
+                                    bool autoneg_wait_to_complete)
+{
+       return 0;
+}
+
+/**
+ *  ixgbevf_check_mac_link_vf - Get link/speed status
+ *  @hw: pointer to hardware structure
+ *  @speed: pointer to link speed
+ *  @link_up: true is link is up, false otherwise
+ *  @autoneg_wait_to_complete: true when waiting for completion is needed
+ *
+ *  Reads the links register to determine if link is up and the current speed
+ **/
+static s32 ixgbevf_check_mac_link_vf(struct ixgbe_hw *hw,
+                                    ixgbe_link_speed *speed,
+                                    bool *link_up,
+                                    bool autoneg_wait_to_complete)
+{
+       u32 links_reg;
+
+       if (!(hw->mbx.ops.check_for_rst(hw))) {
+               *link_up = false;
+               *speed = 0;
+               return -1;
+       }
+
+       links_reg = IXGBE_READ_REG(hw, IXGBE_VFLINKS);
+
+       if (links_reg & IXGBE_LINKS_UP)
+               *link_up = true;
+       else
+               *link_up = false;
+
+       if (links_reg & IXGBE_LINKS_SPEED)
+               *speed = IXGBE_LINK_SPEED_10GB_FULL;
+       else
+               *speed = IXGBE_LINK_SPEED_1GB_FULL;
+
+       return 0;
+}
+
+struct ixgbe_mac_operations ixgbevf_mac_ops = {
+       .init_hw             = ixgbevf_init_hw_vf,
+       .reset_hw            = ixgbevf_reset_hw_vf,
+       .start_hw            = ixgbevf_start_hw_vf,
+       .get_mac_addr        = ixgbevf_get_mac_addr_vf,
+       .stop_adapter        = ixgbevf_stop_hw_vf,
+       .setup_link          = ixgbevf_setup_mac_link_vf,
+       .check_link          = ixgbevf_check_mac_link_vf,
+       .set_rar             = ixgbevf_set_rar_vf,
+       .update_mc_addr_list = ixgbevf_update_mc_addr_list_vf,
+       .set_vfta            = ixgbevf_set_vfta_vf,
+};
+
+struct ixgbevf_info ixgbevf_vf_info = {
+       .mac = ixgbe_mac_82599_vf,
+       .mac_ops = &ixgbevf_mac_ops,
+};
+
diff --git a/drivers/net/ixgbevf/vf.h b/drivers/net/ixgbevf/vf.h
new file mode 100644 (file)
index 0000000..799600e
--- /dev/null
@@ -0,0 +1,168 @@
+/*******************************************************************************
+
+  Intel 82599 Virtual Function driver
+  Copyright(c) 1999 - 2009 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef __IXGBE_VF_H__
+#define __IXGBE_VF_H__
+
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/if_ether.h>
+
+#include "defines.h"
+#include "regs.h"
+#include "mbx.h"
+
+struct ixgbe_hw;
+
+/* iterator type for walking multicast address lists */
+typedef u8* (*ixgbe_mc_addr_itr) (struct ixgbe_hw *hw, u8 **mc_addr_ptr,
+                                 u32 *vmdq);
+struct ixgbe_mac_operations {
+       s32 (*init_hw)(struct ixgbe_hw *);
+       s32 (*reset_hw)(struct ixgbe_hw *);
+       s32 (*start_hw)(struct ixgbe_hw *);
+       s32 (*clear_hw_cntrs)(struct ixgbe_hw *);
+       enum ixgbe_media_type (*get_media_type)(struct ixgbe_hw *);
+       u32 (*get_supported_physical_layer)(struct ixgbe_hw *);
+       s32 (*get_mac_addr)(struct ixgbe_hw *, u8 *);
+       s32 (*stop_adapter)(struct ixgbe_hw *);
+       s32 (*get_bus_info)(struct ixgbe_hw *);
+
+       /* Link */
+       s32 (*setup_link)(struct ixgbe_hw *, ixgbe_link_speed, bool, bool);
+       s32 (*check_link)(struct ixgbe_hw *, ixgbe_link_speed *, bool *, bool);
+       s32 (*get_link_capabilities)(struct ixgbe_hw *, ixgbe_link_speed *,
+                                    bool *);
+
+       /* RAR, Multicast, VLAN */
+       s32 (*set_rar)(struct ixgbe_hw *, u32, u8 *, u32);
+       s32 (*init_rx_addrs)(struct ixgbe_hw *);
+       s32 (*update_mc_addr_list)(struct ixgbe_hw *, u8 *, u32,
+                                  ixgbe_mc_addr_itr);
+       s32 (*enable_mc)(struct ixgbe_hw *);
+       s32 (*disable_mc)(struct ixgbe_hw *);
+       s32 (*clear_vfta)(struct ixgbe_hw *);
+       s32 (*set_vfta)(struct ixgbe_hw *, u32, u32, bool);
+};
+
+enum ixgbe_mac_type {
+       ixgbe_mac_unknown = 0,
+       ixgbe_mac_82599_vf,
+       ixgbe_num_macs
+};
+
+struct ixgbe_mac_info {
+       struct ixgbe_mac_operations ops;
+       u8 addr[6];
+       u8 perm_addr[6];
+
+       enum ixgbe_mac_type type;
+
+       s32  mc_filter_type;
+
+       bool get_link_status;
+       u32  max_tx_queues;
+       u32  max_rx_queues;
+       u32  max_msix_vectors;
+};
+
+struct ixgbe_mbx_operations {
+       s32 (*init_params)(struct ixgbe_hw *hw);
+       s32 (*read)(struct ixgbe_hw *, u32 *, u16);
+       s32 (*write)(struct ixgbe_hw *, u32 *, u16);
+       s32 (*read_posted)(struct ixgbe_hw *, u32 *, u16);
+       s32 (*write_posted)(struct ixgbe_hw *, u32 *, u16);
+       s32 (*check_for_msg)(struct ixgbe_hw *);
+       s32 (*check_for_ack)(struct ixgbe_hw *);
+       s32 (*check_for_rst)(struct ixgbe_hw *);
+};
+
+struct ixgbe_mbx_stats {
+       u32 msgs_tx;
+       u32 msgs_rx;
+
+       u32 acks;
+       u32 reqs;
+       u32 rsts;
+};
+
+struct ixgbe_mbx_info {
+       struct ixgbe_mbx_operations ops;
+       struct ixgbe_mbx_stats stats;
+       u32 timeout;
+       u32 udelay;
+       u32 v2p_mailbox;
+       u16 size;
+};
+
+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;
+
+       u16 device_id;
+       u16 subsystem_vendor_id;
+       u16 subsystem_device_id;
+       u16 vendor_id;
+
+       u8  revision_id;
+       bool adapter_stopped;
+};
+
+struct ixgbevf_hw_stats {
+       u64 base_vfgprc;
+       u64 base_vfgptc;
+       u64 base_vfgorc;
+       u64 base_vfgotc;
+       u64 base_vfmprc;
+
+       u64 last_vfgprc;
+       u64 last_vfgptc;
+       u64 last_vfgorc;
+       u64 last_vfgotc;
+       u64 last_vfmprc;
+
+       u64 vfgprc;
+       u64 vfgptc;
+       u64 vfgorc;
+       u64 vfgotc;
+       u64 vfmprc;
+};
+
+struct ixgbevf_info {
+       enum ixgbe_mac_type             mac;
+       struct ixgbe_mac_operations     *mac_ops;
+};
+
+#endif /* __IXGBE_VF_H__ */
+
index 792b88fc35748a5423996708f97cdfa1759711b8..26eed49d32084d789d97076abac4a6fbf80bdf09 100644 (file)
@@ -2994,7 +2994,7 @@ jme_resume(struct pci_dev *pdev)
 }
 #endif
 
-static struct pci_device_id jme_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(jme_pci_tbl) = {
        { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMC250) },
        { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMC260) },
        { }
index b117f7f8b194ad1cfb43045726cbd8d84bb9f785..b60efd4bd017d722ea57d7df7b56dee2ccae07c1 100644 (file)
@@ -1094,11 +1094,9 @@ static int __devinit i82596_probe(struct net_device *dev)
                return i;
        };
 
-       DEB(DEB_PROBE, printk(KERN_INFO "%s: 82596 at %#3lx,",
-                             dev->name, dev->base_addr));
-       for (i = 0; i < 6; i++)
-               DEB(DEB_PROBE, printk(" %2.2X", dev->dev_addr[i]));
-       DEB(DEB_PROBE, printk(" IRQ %d.\n", dev->irq));
+       DEB(DEB_PROBE, printk(KERN_INFO "%s: 82596 at %#3lx, %pM IRQ %d.\n",
+                             dev->name, dev->base_addr, dev->dev_addr,
+                             dev->irq));
        DEB(DEB_INIT, printk(KERN_INFO
                             "%s: dma at 0x%p (%d bytes), lp->scb at 0x%p\n",
                             dev->name, dma, (int)sizeof(struct i596_dma),
index f8fa0c3f0f6408d5761f17f402372f0e9a49a8ee..a8768672dc5aece9741081e3cde63835b5d80c01 100644 (file)
@@ -17,6 +17,8 @@
 /* 2002-12-30: Try to support more cards, some clues from NetBSD driver */
 /* 2003-12-26: Make sure Asante cards always work. */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/bitops.h>
+#include <linux/io.h>
 
 #include <asm/system.h>
-#include <asm/io.h>
 #include <asm/dma.h>
 #include <asm/hwtest.h>
 #include <asm/macints.h>
 
 static char version[] =
-       "mac8390.c: v0.4 2001-05-15 David Huggins-Daines <dhd@debian.org> and others\n";
+       "v0.4 2001-05-15 David Huggins-Daines <dhd@debian.org> and others\n";
 
 #define EI_SHIFT(x)    (ei_local->reg_offset[x])
-#define ei_inb(port)   in_8(port)
-#define ei_outb(val,port)  out_8(port,val)
-#define ei_inb_p(port)   in_8(port)
-#define ei_outb_p(val,port)  out_8(port,val)
+#define ei_inb(port)   in_8(port)
+#define ei_outb(val, port)     out_8(port, val)
+#define ei_inb_p(port) in_8(port)
+#define ei_outb_p(val, port)   out_8(port, val)
 
 #include "lib8390.c"
 
 #define WD_START_PG                    0x00    /* First page of TX buffer */
 #define CABLETRON_RX_START_PG          0x00    /* First page of RX buffer */
 #define CABLETRON_RX_STOP_PG           0x30    /* Last page +1 of RX ring */
-#define CABLETRON_TX_START_PG          CABLETRON_RX_STOP_PG  /* First page of TX buffer */
+#define CABLETRON_TX_START_PG          CABLETRON_RX_STOP_PG
+                                               /* First page of TX buffer */
 
-/* Unfortunately it seems we have to hardcode these for the moment */
-/* Shouldn't the card know about this? Does anyone know where to read it off the card? Do we trust the data provided by the card? */
+/*
+ * Unfortunately it seems we have to hardcode these for the moment
+ * Shouldn't the card know about this?
+ * Does anyone know where to read it off the card?
+ * Do we trust the data provided by the card?
+ */
 
 #define DAYNA_8390_BASE                0x80000
 #define DAYNA_8390_MEM         0x00000
@@ -80,7 +87,7 @@ enum mac8390_type {
        MAC8390_KINETICS,
 };
 
-static const char * cardname[] = {
+static const char *cardname[] = {
        "apple",
        "asante",
        "farallon",
@@ -90,7 +97,7 @@ static const char * cardname[] = {
        "kinetics",
 };
 
-static int word16[] = {
+static const int word16[] = {
        1, /* apple */
        1, /* asante */
        1, /* farallon */
@@ -101,7 +108,7 @@ static int word16[] = {
 };
 
 /* on which cards do we use NuBus resources? */
-static int useresources[] = {
+static const int useresources[] = {
        1, /* apple */
        1, /* asante */
        1, /* farallon */
@@ -117,22 +124,22 @@ enum mac8390_access {
        ACCESS_16,
 };
 
-extern int mac8390_memtest(struct net_device * dev);
-static int mac8390_initdev(struct net_device * dev, struct nubus_dev * ndev,
+extern int mac8390_memtest(struct net_device *dev);
+static int mac8390_initdev(struct net_device *dev, struct nubus_dev *ndev,
                           enum mac8390_type type);
 
-static int mac8390_open(struct net_device * dev);
-static int mac8390_close(struct net_device * dev);
+static int mac8390_open(struct net_device *dev);
+static int mac8390_close(struct net_device *dev);
 static void mac8390_no_reset(struct net_device *dev);
 static void interlan_reset(struct net_device *dev);
 
 /* Sane (32-bit chunk memory read/write) - Some Farallon and Apple do this*/
 static void sane_get_8390_hdr(struct net_device *dev,
                              struct e8390_pkt_hdr *hdr, int ring_page);
-static void sane_block_input(struct net_device * dev, int count,
-                            struct sk_buff * skb, int ring_offset);
-static void sane_block_output(struct net_device * dev, int count,
-                             const unsigned char * buf, const int start_page);
+static void sane_block_input(struct net_device *dev, int count,
+                            struct sk_buff *skb, int ring_offset);
+static void sane_block_output(struct net_device *dev, int count,
+                             const unsigned char *buf, const int start_page);
 
 /* dayna_memcpy to and from card */
 static void dayna_memcpy_fromcard(struct net_device *dev, void *to,
@@ -148,8 +155,8 @@ static void dayna_block_input(struct net_device *dev, int count,
 static void dayna_block_output(struct net_device *dev, int count,
                               const unsigned char *buf, int start_page);
 
-#define memcpy_fromio(a,b,c)   memcpy((a),(void *)(b),(c))
-#define memcpy_toio(a,b,c)     memcpy((void *)(a),(b),(c))
+#define memcpy_fromio(a, b, c) memcpy((a), (void *)(b), (c))
+#define memcpy_toio(a, b, c)   memcpy((void *)(a), (b), (c))
 
 /* Slow Sane (16-bit chunk memory read/write) Cabletron uses this */
 static void slow_sane_get_8390_hdr(struct net_device *dev,
@@ -164,70 +171,72 @@ static void word_memcpy_fromcard(void *tp, const void *fp, int count);
 static enum mac8390_type __init mac8390_ident(struct nubus_dev *dev)
 {
        switch (dev->dr_sw) {
-               case NUBUS_DRSW_3COM:
-                       switch (dev->dr_hw) {
-                               case NUBUS_DRHW_APPLE_SONIC_NB:
-                               case NUBUS_DRHW_APPLE_SONIC_LC:
-                               case NUBUS_DRHW_SONNET:
-                                       return MAC8390_NONE;
-                                       break;
-                               default:
-                                       return MAC8390_APPLE;
-                                       break;
-                       }
+       case NUBUS_DRSW_3COM:
+               switch (dev->dr_hw) {
+               case NUBUS_DRHW_APPLE_SONIC_NB:
+               case NUBUS_DRHW_APPLE_SONIC_LC:
+               case NUBUS_DRHW_SONNET:
+                       return MAC8390_NONE;
                        break;
-
-               case NUBUS_DRSW_APPLE:
-                       switch (dev->dr_hw) {
-                               case NUBUS_DRHW_ASANTE_LC:
-                                       return MAC8390_NONE;
-                                       break;
-                               case NUBUS_DRHW_CABLETRON:
-                                       return MAC8390_CABLETRON;
-                                       break;
-                               default:
-                                       return MAC8390_APPLE;
-                                       break;
-                       }
+               default:
+                       return MAC8390_APPLE;
                        break;
+               }
+               break;
 
-               case NUBUS_DRSW_ASANTE:
-                       return MAC8390_ASANTE;
+       case NUBUS_DRSW_APPLE:
+               switch (dev->dr_hw) {
+               case NUBUS_DRHW_ASANTE_LC:
+                       return MAC8390_NONE;
                        break;
-
-               case NUBUS_DRSW_TECHWORKS:
-               case NUBUS_DRSW_DAYNA2:
-               case NUBUS_DRSW_DAYNA_LC:
-                       if (dev->dr_hw == NUBUS_DRHW_CABLETRON)
-                               return MAC8390_CABLETRON;
-                       else
-                               return MAC8390_APPLE;
+               case NUBUS_DRHW_CABLETRON:
+                       return MAC8390_CABLETRON;
                        break;
-
-               case NUBUS_DRSW_FARALLON:
-                       return MAC8390_FARALLON;
+               default:
+                       return MAC8390_APPLE;
                        break;
+               }
+               break;
 
-               case NUBUS_DRSW_KINETICS:
-                       switch (dev->dr_hw) {
-                               case NUBUS_DRHW_INTERLAN:
-                                       return MAC8390_INTERLAN;
-                                       break;
-                               default:
-                                       return MAC8390_KINETICS;
-                                       break;
-                       }
-                       break;
+       case NUBUS_DRSW_ASANTE:
+               return MAC8390_ASANTE;
+               break;
 
-               case NUBUS_DRSW_DAYNA:
-                       // These correspond to Dayna Sonic cards
-                       // which use the macsonic driver
-                       if (dev->dr_hw == NUBUS_DRHW_SMC9194 ||
-                               dev->dr_hw == NUBUS_DRHW_INTERLAN )
-                               return MAC8390_NONE;
-                       else
-                               return MAC8390_DAYNA;
+       case NUBUS_DRSW_TECHWORKS:
+       case NUBUS_DRSW_DAYNA2:
+       case NUBUS_DRSW_DAYNA_LC:
+               if (dev->dr_hw == NUBUS_DRHW_CABLETRON)
+                       return MAC8390_CABLETRON;
+               else
+                       return MAC8390_APPLE;
+               break;
+
+       case NUBUS_DRSW_FARALLON:
+               return MAC8390_FARALLON;
+               break;
+
+       case NUBUS_DRSW_KINETICS:
+               switch (dev->dr_hw) {
+               case NUBUS_DRHW_INTERLAN:
+                       return MAC8390_INTERLAN;
+                       break;
+               default:
+                       return MAC8390_KINETICS;
                        break;
+               }
+               break;
+
+       case NUBUS_DRSW_DAYNA:
+               /*
+                * These correspond to Dayna Sonic cards
+                * which use the macsonic driver
+                */
+               if (dev->dr_hw == NUBUS_DRHW_SMC9194 ||
+                   dev->dr_hw == NUBUS_DRHW_INTERLAN)
+                       return MAC8390_NONE;
+               else
+                       return MAC8390_DAYNA;
+               break;
        }
        return MAC8390_NONE;
 }
@@ -237,14 +246,14 @@ static enum mac8390_access __init mac8390_testio(volatile unsigned long membase)
        unsigned long outdata = 0xA5A0B5B0;
        unsigned long indata =  0x00000000;
        /* Try writing 32 bits */
-       memcpy((char *)membase, (char *)&outdata, 4);
+       memcpy(membase, &outdata, 4);
        /* Now compare them */
        if (memcmp((char *)&outdata, (char *)membase, 4) == 0)
                return ACCESS_32;
        /* Write 16 bit output */
-       word_memcpy_tocard((char *)membase, (char *)&outdata, 4);
+       word_memcpy_tocard(membase, &outdata, 4);
        /* Now read it back */
-       word_memcpy_fromcard((char *)&indata, (char *)membase, 4);
+       word_memcpy_fromcard(&indata, membase, 4);
        if (outdata == indata)
                return ACCESS_16;
        return ACCESS_UNKNOWN;
@@ -258,7 +267,7 @@ static int __init mac8390_memsize(unsigned long membase)
        local_irq_save(flags);
        /* Check up to 32K in 4K increments */
        for (i = 0; i < 8; i++) {
-               volatile unsigned short *m = (unsigned short *) (membase + (i * 0x1000));
+               volatile unsigned short *m = (unsigned short *)(membase + (i * 0x1000));
 
                /* Unwriteable - we have a fully decoded card and the
                   RAM end located */
@@ -273,28 +282,127 @@ static int __init mac8390_memsize(unsigned long membase)
 
                /* check for partial decode and wrap */
                for (j = 0; j < i; j++) {
-                       volatile unsigned short *p = (unsigned short *) (membase + (j * 0x1000));
+                       volatile unsigned short *p = (unsigned short *)(membase + (j * 0x1000));
                        if (*p != (0xA5A0 | j))
                                break;
-               }
-       }
+               }
+       }
        local_irq_restore(flags);
-       /* in any case, we stopped once we tried one block too many,
-           or once we reached 32K */
-       return i * 0x1000;
+       /*
+        * in any case, we stopped once we tried one block too many,
+        * or once we reached 32K
+        */
+       return i * 0x1000;
+}
+
+static bool __init mac8390_init(struct net_device *dev, struct nubus_dev *ndev,
+                               enum mac8390_type cardtype)
+{
+       struct nubus_dir dir;
+       struct nubus_dirent ent;
+       int offset;
+       volatile unsigned short *i;
+
+       printk_once(KERN_INFO pr_fmt("%s"), version);
+
+       dev->irq = SLOT2IRQ(ndev->board->slot);
+       /* This is getting to be a habit */
+       dev->base_addr = (ndev->board->slot_addr |
+                         ((ndev->board->slot & 0xf) << 20));
+
+       /*
+        * Get some Nubus info - we will trust the card's idea
+        * of where its memory and registers are.
+        */
+
+       if (nubus_get_func_dir(ndev, &dir) == -1) {
+               pr_err("%s: Unable to get Nubus functional directory for slot %X!\n",
+                      dev->name, ndev->board->slot);
+               return false;
+       }
+
+       /* Get the MAC address */
+       if (nubus_find_rsrc(&dir, NUBUS_RESID_MAC_ADDRESS, &ent) == -1) {
+               pr_info("%s: Couldn't get MAC address!\n", dev->name);
+               return false;
+       }
+
+       nubus_get_rsrc_mem(dev->dev_addr, &ent, 6);
+
+       if (useresources[cardtype] == 1) {
+               nubus_rewinddir(&dir);
+               if (nubus_find_rsrc(&dir, NUBUS_RESID_MINOR_BASEOS,
+                                   &ent) == -1) {
+                       pr_err("%s: Memory offset resource for slot %X not found!\n",
+                              dev->name, ndev->board->slot);
+                       return false;
+               }
+               nubus_get_rsrc_mem(&offset, &ent, 4);
+               dev->mem_start = dev->base_addr + offset;
+               /* yes, this is how the Apple driver does it */
+               dev->base_addr = dev->mem_start + 0x10000;
+               nubus_rewinddir(&dir);
+               if (nubus_find_rsrc(&dir, NUBUS_RESID_MINOR_LENGTH,
+                                   &ent) == -1) {
+                       pr_info("%s: Memory length resource for slot %X not found, probing\n",
+                               dev->name, ndev->board->slot);
+                       offset = mac8390_memsize(dev->mem_start);
+               } else {
+                       nubus_get_rsrc_mem(&offset, &ent, 4);
+               }
+               dev->mem_end = dev->mem_start + offset;
+       } else {
+               switch (cardtype) {
+               case MAC8390_KINETICS:
+               case MAC8390_DAYNA: /* it's the same */
+                       dev->base_addr = (int)(ndev->board->slot_addr +
+                                              DAYNA_8390_BASE);
+                       dev->mem_start = (int)(ndev->board->slot_addr +
+                                              DAYNA_8390_MEM);
+                       dev->mem_end = dev->mem_start +
+                                      mac8390_memsize(dev->mem_start);
+                       break;
+               case MAC8390_INTERLAN:
+                       dev->base_addr = (int)(ndev->board->slot_addr +
+                                              INTERLAN_8390_BASE);
+                       dev->mem_start = (int)(ndev->board->slot_addr +
+                                              INTERLAN_8390_MEM);
+                       dev->mem_end = dev->mem_start +
+                                      mac8390_memsize(dev->mem_start);
+                       break;
+               case MAC8390_CABLETRON:
+                       dev->base_addr = (int)(ndev->board->slot_addr +
+                                              CABLETRON_8390_BASE);
+                       dev->mem_start = (int)(ndev->board->slot_addr +
+                                              CABLETRON_8390_MEM);
+                       /* The base address is unreadable if 0x00
+                        * has been written to the command register
+                        * Reset the chip by writing E8390_NODMA +
+                        *   E8390_PAGE0 + E8390_STOP just to be
+                        *   sure
+                        */
+                       i = (void *)dev->base_addr;
+                       *i = 0x21;
+                       dev->mem_end = dev->mem_start +
+                                      mac8390_memsize(dev->mem_start);
+                       break;
+
+               default:
+                       pr_err("Card type %s is unsupported, sorry\n",
+                              ndev->board->name);
+                       return false;
+               }
+       }
+
+       return true;
 }
 
 struct net_device * __init mac8390_probe(int unit)
 {
        struct net_device *dev;
-       volatile unsigned short *i;
-       int version_disp = 0;
-       struct nubus_dev * ndev = NULL;
+       struct nubus_dev *ndev = NULL;
        int err = -ENODEV;
 
-       struct nubus_dir dir;
-       struct nubus_dirent ent;
-       int offset;
        static unsigned int slots;
 
        enum mac8390_type cardtype;
@@ -311,118 +419,19 @@ struct net_device * __init mac8390_probe(int unit)
        if (unit >= 0)
                sprintf(dev->name, "eth%d", unit);
 
-       while ((ndev = nubus_find_type(NUBUS_CAT_NETWORK, NUBUS_TYPE_ETHERNET, ndev))) {
+       while ((ndev = nubus_find_type(NUBUS_CAT_NETWORK, NUBUS_TYPE_ETHERNET,
+                                      ndev))) {
                /* Have we seen it already? */
-               if (slots & (1<<ndev->board->slot))
+               if (slots & (1 << ndev->board->slot))
                        continue;
-               slots |= 1<<ndev->board->slot;
+               slots |= 1 << ndev->board->slot;
 
-               if ((cardtype = mac8390_ident(ndev)) == MAC8390_NONE)
+               cardtype = mac8390_ident(ndev);
+               if (cardtype == MAC8390_NONE)
                        continue;
 
-               if (version_disp == 0) {
-                       version_disp = 1;
-                       printk(version);
-               }
-
-               dev->irq = SLOT2IRQ(ndev->board->slot);
-               /* This is getting to be a habit */
-               dev->base_addr = ndev->board->slot_addr | ((ndev->board->slot&0xf) << 20);
-
-               /* Get some Nubus info - we will trust the card's idea
-                  of where its memory and registers are. */
-
-               if (nubus_get_func_dir(ndev, &dir) == -1) {
-                       printk(KERN_ERR "%s: Unable to get Nubus functional"
-                                       " directory for slot %X!\n",
-                              dev->name, ndev->board->slot);
+               if (!mac8390_init(dev, ndev, cardtype))
                        continue;
-               }
-
-               /* Get the MAC address */
-               if ((nubus_find_rsrc(&dir, NUBUS_RESID_MAC_ADDRESS, &ent)) == -1) {
-                       printk(KERN_INFO "%s: Couldn't get MAC address!\n",
-                                       dev->name);
-                       continue;
-               } else {
-                       nubus_get_rsrc_mem(dev->dev_addr, &ent, 6);
-               }
-
-               if (useresources[cardtype] == 1) {
-                       nubus_rewinddir(&dir);
-                       if (nubus_find_rsrc(&dir, NUBUS_RESID_MINOR_BASEOS, &ent) == -1) {
-                               printk(KERN_ERR "%s: Memory offset resource"
-                                               " for slot %X not found!\n",
-                                      dev->name, ndev->board->slot);
-                               continue;
-                       }
-                       nubus_get_rsrc_mem(&offset, &ent, 4);
-                       dev->mem_start = dev->base_addr + offset;
-                       /* yes, this is how the Apple driver does it */
-                       dev->base_addr = dev->mem_start + 0x10000;
-                       nubus_rewinddir(&dir);
-                       if (nubus_find_rsrc(&dir, NUBUS_RESID_MINOR_LENGTH, &ent) == -1) {
-                               printk(KERN_INFO "%s: Memory length resource"
-                                                " for slot %X not found"
-                                                ", probing\n",
-                                      dev->name, ndev->board->slot);
-                               offset = mac8390_memsize(dev->mem_start);
-                               } else {
-                                       nubus_get_rsrc_mem(&offset, &ent, 4);
-                               }
-                       dev->mem_end = dev->mem_start + offset;
-               } else {
-                       switch (cardtype) {
-                               case MAC8390_KINETICS:
-                               case MAC8390_DAYNA: /* it's the same */
-                                       dev->base_addr =
-                                               (int)(ndev->board->slot_addr +
-                                               DAYNA_8390_BASE);
-                                       dev->mem_start =
-                                               (int)(ndev->board->slot_addr +
-                                               DAYNA_8390_MEM);
-                                       dev->mem_end =
-                                               dev->mem_start +
-                                               mac8390_memsize(dev->mem_start);
-                                       break;
-                               case MAC8390_INTERLAN:
-                                       dev->base_addr =
-                                               (int)(ndev->board->slot_addr +
-                                               INTERLAN_8390_BASE);
-                                       dev->mem_start =
-                                               (int)(ndev->board->slot_addr +
-                                               INTERLAN_8390_MEM);
-                                       dev->mem_end =
-                                               dev->mem_start +
-                                               mac8390_memsize(dev->mem_start);
-                                       break;
-                               case MAC8390_CABLETRON:
-                                       dev->base_addr =
-                                               (int)(ndev->board->slot_addr +
-                                               CABLETRON_8390_BASE);
-                                       dev->mem_start =
-                                               (int)(ndev->board->slot_addr +
-                                               CABLETRON_8390_MEM);
-                                       /* The base address is unreadable if 0x00
-                                        * has been written to the command register
-                                        * Reset the chip by writing E8390_NODMA +
-                                        *   E8390_PAGE0 + E8390_STOP just to be
-                                        *   sure
-                                        */
-                                       i = (void *)dev->base_addr;
-                                       *i = 0x21;
-                                       dev->mem_end =
-                                               dev->mem_start +
-                                               mac8390_memsize(dev->mem_start);
-                                       break;
-
-                               default:
-                                       printk(KERN_ERR "Card type %s is"
-                                              " unsupported, sorry\n",
-                                              ndev->board->name);
-                                       continue;
-                       }
-               }
 
                /* Do the nasty 8390 stuff */
                if (!mac8390_initdev(dev, ndev, cardtype))
@@ -458,7 +467,7 @@ int init_module(void)
                dev_mac890[i] = dev;
        }
        if (!i) {
-               printk(KERN_NOTICE "mac8390.c: No useable cards found, driver NOT installed.\n");
+               pr_notice("No useable cards found, driver NOT installed.\n");
                return -ENODEV;
        }
        return 0;
@@ -493,22 +502,23 @@ static const struct net_device_ops mac8390_netdev_ops = {
 #endif
 };
 
-static int __init mac8390_initdev(struct net_device * dev, struct nubus_dev * ndev,
-                           enum mac8390_type type)
+static int __init mac8390_initdev(struct net_device *dev,
+                                 struct nubus_dev *ndev,
+                                 enum mac8390_type type)
 {
-       static u32 fwrd4_offsets[16]={
+       static u32 fwrd4_offsets[16] = {
                0,      4,      8,      12,
                16,     20,     24,     28,
                32,     36,     40,     44,
                48,     52,     56,     60
        };
-       static u32 back4_offsets[16]={
+       static u32 back4_offsets[16] = {
                60,     56,     52,     48,
                44,     40,     36,     32,
                28,     24,     20,     16,
                12,     8,      4,      0
        };
-       static u32 fwrd2_offsets[16]={
+       static u32 fwrd2_offsets[16] = {
                0,      2,      4,      6,
                8,     10,     12,     14,
                16,    18,     20,     22,
@@ -526,47 +536,47 @@ static int __init mac8390_initdev(struct net_device * dev, struct nubus_dev * nd
 
        /* Cabletron's TX/RX buffers are backwards */
        if (type == MAC8390_CABLETRON) {
-               ei_status.tx_start_page = CABLETRON_TX_START_PG;
-               ei_status.rx_start_page = CABLETRON_RX_START_PG;
-               ei_status.stop_page = CABLETRON_RX_STOP_PG;
-               ei_status.rmem_start = dev->mem_start;
-               ei_status.rmem_end = dev->mem_start + CABLETRON_RX_STOP_PG*256;
+               ei_status.tx_start_page = CABLETRON_TX_START_PG;
+               ei_status.rx_start_page = CABLETRON_RX_START_PG;
+               ei_status.stop_page = CABLETRON_RX_STOP_PG;
+               ei_status.rmem_start = dev->mem_start;
+               ei_status.rmem_end = dev->mem_start + CABLETRON_RX_STOP_PG*256;
        } else {
-               ei_status.tx_start_page = WD_START_PG;
-               ei_status.rx_start_page = WD_START_PG + TX_PAGES;
-               ei_status.stop_page = (dev->mem_end - dev->mem_start)/256;
-               ei_status.rmem_start = dev->mem_start + TX_PAGES*256;
-               ei_status.rmem_end = dev->mem_end;
+               ei_status.tx_start_page = WD_START_PG;
+               ei_status.rx_start_page = WD_START_PG + TX_PAGES;
+               ei_status.stop_page = (dev->mem_end - dev->mem_start)/256;
+               ei_status.rmem_start = dev->mem_start + TX_PAGES*256;
+               ei_status.rmem_end = dev->mem_end;
        }
 
        /* Fill in model-specific information and functions */
-       switch(type) {
+       switch (type) {
        case MAC8390_FARALLON:
        case MAC8390_APPLE:
-               switch(mac8390_testio(dev->mem_start)) {
-                       case ACCESS_UNKNOWN:
-                               printk("Don't know how to access card memory!\n");
-                               return -ENODEV;
-                               break;
+               switch (mac8390_testio(dev->mem_start)) {
+               case ACCESS_UNKNOWN:
+                       pr_info("Don't know how to access card memory!\n");
+                       return -ENODEV;
+                       break;
 
-                       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.reg_offset = back4_offsets;
-                               break;
+               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.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.reg_offset = back4_offsets;
-                               access_bitmode = 1;
-                               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.reg_offset = back4_offsets;
+                       access_bitmode = 1;
+                       break;
                }
                break;
 
@@ -608,24 +618,25 @@ static int __init mac8390_initdev(struct net_device * dev, struct nubus_dev * nd
                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;
+               ei_status.reg_offset = fwrd4_offsets;
+               break;
 
        default:
-               printk(KERN_ERR "Card type %s is unsupported, sorry\n", ndev->board->name);
+               pr_err("Card type %s is unsupported, sorry\n",
+                      ndev->board->name);
                return -ENODEV;
        }
 
        __NS8390_init(dev, 0);
 
        /* Good, done, now spit out some messages */
-       printk(KERN_INFO "%s: %s in slot %X (type %s)\n",
-              dev->name, ndev->board->name, ndev->board->slot, cardname[type]);
-       printk(KERN_INFO
-              "MAC %pM IRQ %d, %d KB shared memory at %#lx, %d-bit access.\n",
-              dev->dev_addr, dev->irq,
-              (unsigned int)(dev->mem_end - dev->mem_start) >> 10,
-              dev->mem_start, access_bitmode ? 32 : 16);
+       pr_info("%s: %s in slot %X (type %s)\n",
+               dev->name, ndev->board->name, ndev->board->slot,
+               cardname[type]);
+       pr_info("MAC %pM IRQ %d, %d KB shared memory at %#lx, %d-bit access.\n",
+               dev->dev_addr, dev->irq,
+               (unsigned int)(dev->mem_end - dev->mem_start) >> 10,
+               dev->mem_start, access_bitmode ? 32 : 16);
        return 0;
 }
 
@@ -633,7 +644,7 @@ static int mac8390_open(struct net_device *dev)
 {
        __ei_open(dev);
        if (request_irq(dev->irq, __ei_interrupt, 0, "8390 Ethernet", dev)) {
-               printk ("%s: unable to get IRQ %d.\n", dev->name, dev->irq);
+               pr_info("%s: unable to get IRQ %d.\n", dev->name, dev->irq);
                return -EAGAIN;
        }
        return 0;
@@ -650,72 +661,71 @@ static void mac8390_no_reset(struct net_device *dev)
 {
        ei_status.txing = 0;
        if (ei_debug > 1)
-               printk("reset not supported\n");
+               pr_info("reset not supported\n");
        return;
 }
 
 static void interlan_reset(struct net_device *dev)
 {
-       unsigned char *target=nubus_slot_addr(IRQ2SLOT(dev->irq));
+       unsigned char *target = nubus_slot_addr(IRQ2SLOT(dev->irq));
        if (ei_debug > 1)
-               printk("Need to reset the NS8390 t=%lu...", jiffies);
+               pr_info("Need to reset the NS8390 t=%lu...", jiffies);
        ei_status.txing = 0;
        target[0xC0000] = 0;
        if (ei_debug > 1)
-               printk("reset complete\n");
+               pr_cont("reset complete\n");
        return;
 }
 
 /* dayna_memcpy_fromio/dayna_memcpy_toio */
 /* directly from daynaport.c by Alan Cox */
-static void dayna_memcpy_fromcard(struct net_device *dev, void *to, int from, int count)
+static void dayna_memcpy_fromcard(struct net_device *dev, void *to, int from,
+                                 int count)
 {
        volatile unsigned char *ptr;
-       unsigned char *target=to;
-       from<<=1;       /* word, skip overhead */
-       ptr=(unsigned char *)(dev->mem_start+from);
+       unsigned char *target = to;
+       from <<= 1;     /* word, skip overhead */
+       ptr = (unsigned char *)(dev->mem_start+from);
        /* Leading byte? */
-       if (from&2) {
+       if (from & 2) {
                *target++ = ptr[-1];
                ptr += 2;
                count--;
        }
-       while(count>=2)
-       {
+       while (count >= 2) {
                *(unsigned short *)target = *(unsigned short volatile *)ptr;
                ptr += 4;                       /* skip cruft */
                target += 2;
-               count-=2;
+               count -= 2;
        }
        /* Trailing byte? */
-       if(count)
+       if (count)
                *target = *ptr;
 }
 
-static void dayna_memcpy_tocard(struct net_device *dev, int to, const void *from, int count)
+static void dayna_memcpy_tocard(struct net_device *dev, int to,
+                               const void *from, int count)
 {
        volatile unsigned short *ptr;
-       const unsigned char *src=from;
-       to<<=1; /* word, skip overhead */
-       ptr=(unsigned short *)(dev->mem_start+to);
+       const unsigned char *src = from;
+       to <<= 1;       /* word, skip overhead */
+       ptr = (unsigned short *)(dev->mem_start+to);
        /* Leading byte? */
-       if (to&2) { /* avoid a byte write (stomps on other data) */
+       if (to & 2) {           /* avoid a byte write (stomps on other data) */
                ptr[-1] = (ptr[-1]&0xFF00)|*src++;
                ptr++;
                count--;
        }
-       while(count>=2)
-       {
-               *ptr++=*(unsigned short *)src;          /* Copy and */
+       while (count >= 2) {
+               *ptr++ = *(unsigned short *)src;        /* Copy and */
                ptr++;                  /* skip cruft */
                src += 2;
-               count-=2;
+               count -= 2;
        }
        /* Trailing byte? */
-       if(count)
-       {
+       if (count) {
                /* card doesn't like byte writes */
-               *ptr=(*ptr&0x00FF)|(*src << 8);
+               *ptr = (*ptr & 0x00FF) | (*src << 8);
        }
 }
 
@@ -738,11 +748,14 @@ static void sane_block_input(struct net_device *dev, int count,
        if (xfer_start + count > ei_status.rmem_end) {
                /* We must wrap the input move. */
                int semi_count = ei_status.rmem_end - xfer_start;
-               memcpy_fromio(skb->data, (char *)dev->mem_start + xfer_base, semi_count);
+               memcpy_fromio(skb->data, (char *)dev->mem_start + xfer_base,
+                             semi_count);
                count -= semi_count;
-               memcpy_toio(skb->data + semi_count, (char *)ei_status.rmem_start, count);
+               memcpy_toio(skb->data + semi_count,
+                           (char *)ei_status.rmem_start, count);
        } else {
-               memcpy_fromio(skb->data, (char *)dev->mem_start + xfer_base, count);
+               memcpy_fromio(skb->data, (char *)dev->mem_start + xfer_base,
+                             count);
        }
 }
 
@@ -755,16 +768,18 @@ static void sane_block_output(struct net_device *dev, int count,
 }
 
 /* dayna block input/output */
-static void dayna_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
+static void dayna_get_8390_hdr(struct net_device *dev,
+                              struct e8390_pkt_hdr *hdr, int ring_page)
 {
        unsigned long hdr_start = (ring_page - WD_START_PG)<<8;
 
-       dayna_memcpy_fromcard(dev, (void *)hdr, hdr_start, 4);
+       dayna_memcpy_fromcard(dev, hdr, hdr_start, 4);
        /* Fix endianness */
-       hdr->count=(hdr->count&0xFF)<<8|(hdr->count>>8);
+       hdr->count = (hdr->count & 0xFF) << 8 | (hdr->count >> 8);
 }
 
-static void dayna_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
+static void dayna_block_input(struct net_device *dev, int count,
+                             struct sk_buff *skb, int ring_offset)
 {
        unsigned long xfer_base = ring_offset - (WD_START_PG<<8);
        unsigned long xfer_start = xfer_base+dev->mem_start;
@@ -772,8 +787,7 @@ static void dayna_block_input(struct net_device *dev, int count, struct sk_buff
        /* Note the offset math is done in card memory space which is word
           per long onto our space. */
 
-       if (xfer_start + count > ei_status.rmem_end)
-       {
+       if (xfer_start + count > ei_status.rmem_end) {
                /* We must wrap the input move. */
                int semi_count = ei_status.rmem_end - xfer_start;
                dayna_memcpy_fromcard(dev, skb->data, xfer_base, semi_count);
@@ -781,15 +795,14 @@ static void dayna_block_input(struct net_device *dev, int count, struct sk_buff
                dayna_memcpy_fromcard(dev, skb->data + semi_count,
                                      ei_status.rmem_start - dev->mem_start,
                                      count);
-       }
-       else
-       {
+       } else {
                dayna_memcpy_fromcard(dev, skb->data, xfer_base, count);
        }
 }
 
-static void dayna_block_output(struct net_device *dev, int count, const unsigned char *buf,
-                               int start_page)
+static void dayna_block_output(struct net_device *dev, int count,
+                              const unsigned char *buf,
+                              int start_page)
 {
        long shmem = (start_page - WD_START_PG)<<8;
 
@@ -797,40 +810,39 @@ static void dayna_block_output(struct net_device *dev, int count, const unsigned
 }
 
 /* Cabletron block I/O */
-static void slow_sane_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
-       int ring_page)
+static void slow_sane_get_8390_hdr(struct net_device *dev,
+                                  struct e8390_pkt_hdr *hdr,
+                                  int ring_page)
 {
        unsigned long hdr_start = (ring_page - WD_START_PG)<<8;
-       word_memcpy_fromcard((void *)hdr, (char *)dev->mem_start+hdr_start, 4);
+       word_memcpy_fromcard(hdr, (char *)dev->mem_start + hdr_start, 4);
        /* Register endianism - fix here rather than 8390.c */
        hdr->count = (hdr->count&0xFF)<<8|(hdr->count>>8);
 }
 
-static void slow_sane_block_input(struct net_device *dev, int count, struct sk_buff *skb,
-       int ring_offset)
+static void slow_sane_block_input(struct net_device *dev, int count,
+                                 struct sk_buff *skb, int ring_offset)
 {
        unsigned long xfer_base = ring_offset - (WD_START_PG<<8);
        unsigned long xfer_start = xfer_base+dev->mem_start;
 
-       if (xfer_start + count > ei_status.rmem_end)
-       {
+       if (xfer_start + count > ei_status.rmem_end) {
                /* We must wrap the input move. */
                int semi_count = ei_status.rmem_end - xfer_start;
-               word_memcpy_fromcard(skb->data, (char *)dev->mem_start +
-                       xfer_base, semi_count);
+               word_memcpy_fromcard(skb->data,
+                                    (char *)dev->mem_start + xfer_base,
+                                    semi_count);
                count -= semi_count;
                word_memcpy_fromcard(skb->data + semi_count,
                                     (char *)ei_status.rmem_start, count);
-       }
-       else
-       {
-               word_memcpy_fromcard(skb->data, (char *)dev->mem_start +
-                       xfer_base, count);
+       } else {
+               word_memcpy_fromcard(skb->data,
+                                    (char *)dev->mem_start + xfer_base, count);
        }
 }
 
-static void slow_sane_block_output(struct net_device *dev, int count, const unsigned char *buf,
-       int start_page)
+static void slow_sane_block_output(struct net_device *dev, int count,
+                                  const unsigned char *buf, int start_page)
 {
        long shmem = (start_page - WD_START_PG)<<8;
 
@@ -843,10 +855,10 @@ static void word_memcpy_tocard(void *tp, const void *fp, int count)
        const unsigned short *from = fp;
 
        count++;
-       count/=2;
+       count /= 2;
 
-       while(count--)
-               *to++=*from++;
+       while (count--)
+               *to++ = *from++;
 }
 
 static void word_memcpy_fromcard(void *tp, const void *fp, int count)
@@ -855,10 +867,10 @@ static void word_memcpy_fromcard(void *tp, const void *fp, int count)
        const volatile unsigned short *from = fp;
 
        count++;
-       count/=2;
+       count /= 2;
 
-       while(count--)
-               *to++=*from++;
+       while (count--)
+               *to++ = *from++;
 }
 
 
index 21a9c9ab4b342d6eff468ea8ff4232426de57b49..fa0dc514dbaf635d583a773d608e2dff94f11a84 100644 (file)
@@ -418,7 +418,7 @@ static struct lock_class_key macvlan_netdev_addr_lock_key;
 #define MACVLAN_FEATURES \
        (NETIF_F_SG | NETIF_F_ALL_CSUM | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST | \
         NETIF_F_GSO | NETIF_F_TSO | NETIF_F_UFO | NETIF_F_GSO_ROBUST | \
-        NETIF_F_TSO_ECN | NETIF_F_TSO6)
+        NETIF_F_TSO_ECN | NETIF_F_TSO6 | NETIF_F_GRO)
 
 #define MACVLAN_STATE_MASK \
        ((1<<__LINK_STATE_NOCARRIER) | (1<<__LINK_STATE_DORMANT))
index 2af81735386b86066c30d7ebbf9d99da59e2236e..9f72cb45f4af65933b41b5ec5951032fd5ad6a09 100644 (file)
 
 static const char *meth_str="SGI O2 Fast Ethernet";
 
-#define HAVE_TX_TIMEOUT
 /* The maximum time waited (in jiffies) before assuming a Tx failed. (400ms) */
 #define TX_TIMEOUT (400*HZ/1000)
 
-#ifdef HAVE_TX_TIMEOUT
 static int timeout = TX_TIMEOUT;
 module_param(timeout, int, 0);
-#endif
 
 /*
  * This structure is private to each device. It is used to pass
index 3cf56d90d85924551c86252ac1343226173a3630..8f6e816a7395f78dadfa12c7a64269ce820d0b7d 100644 (file)
@@ -1271,7 +1271,7 @@ int mlx4_restart_one(struct pci_dev *pdev)
        return __mlx4_init_one(pdev, NULL);
 }
 
-static struct pci_device_id mlx4_pci_table[] = {
+static DEFINE_PCI_DEVICE_TABLE(mlx4_pci_table) = {
        { PCI_VDEVICE(MELLANOX, 0x6340) }, /* MT25408 "Hermon" SDR */
        { PCI_VDEVICE(MELLANOX, 0x634a) }, /* MT25408 "Hermon" DDR */
        { PCI_VDEVICE(MELLANOX, 0x6354) }, /* MT25408 "Hermon" QDR */
index af67af55efe7a4d5490273632d689e944f4aec90..e24072a9a979bf7021207b3c284decd0f89fc6fe 100644 (file)
@@ -55,7 +55,6 @@
 #include <linux/types.h>
 #include <linux/inet_lro.h>
 #include <asm/system.h>
-#include <linux/list.h>
 
 static char mv643xx_eth_driver_name[] = "mv643xx_eth";
 static char mv643xx_eth_driver_version[] = "1.4";
@@ -1697,7 +1696,7 @@ static u32 uc_addr_filter_mask(struct net_device *dev)
                return 0;
 
        nibbles = 1 << (dev->dev_addr[5] & 0x0f);
-       list_for_each_entry(ha, &dev->uc.list, list) {
+       netdev_for_each_uc_addr(ha, dev) {
                if (memcmp(dev->dev_addr, ha->addr, 5))
                        return 0;
                if ((dev->dev_addr[5] ^ ha->addr[5]) & 0xf0)
index 3fcb1c356e0d157de807fc1a729bf9b1af19b48e..c0884a9cba3ce78624b45b846791c68342e0fb54 100644 (file)
@@ -4085,7 +4085,7 @@ static void myri10ge_remove(struct pci_dev *pdev)
 #define PCI_DEVICE_ID_MYRICOM_MYRI10GE_Z8E     0x0008
 #define PCI_DEVICE_ID_MYRICOM_MYRI10GE_Z8E_9   0x0009
 
-static struct pci_device_id myri10ge_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(myri10ge_pci_tbl) = {
        {PCI_DEVICE(PCI_VENDOR_ID_MYRICOM, PCI_DEVICE_ID_MYRICOM_MYRI10GE_Z8E)},
        {PCI_DEVICE
         (PCI_VENDOR_ID_MYRICOM, PCI_DEVICE_ID_MYRICOM_MYRI10GE_Z8E_9)},
index b3513ad3b7037eb45b76190b32124b9f7a842dba..8b4313085359ce703f2f4bd6c91c815c43a2c030 100644 (file)
@@ -716,10 +716,10 @@ static int myri_header(struct sk_buff *skb, struct net_device *dev,
        pad[0] = MYRI_PAD_LEN;
        pad[1] = 0xab;
 
-       /* Set the protocol type. For a packet of type ETH_P_802_3 we put the length
-        * in here instead. It is up to the 802.2 layer to carry protocol information.
+       /* Set the protocol type. For a packet of type ETH_P_802_3/2 we put the
+        * length in here instead.
         */
-       if (type != ETH_P_802_3)
+       if (type != ETH_P_802_3 && type != ETH_P_802_2)
                eth->h_proto = htons(type);
        else
                eth->h_proto = htons(len);
index 797fe164ce272df12d7f6e84b84b0d300933e0e3..2d7b3bbfed012df5a53f23486034f3c059cb0e41 100644 (file)
@@ -247,7 +247,7 @@ static struct {
        { "NatSemi DP8381[56]", 0, 24 },
 };
 
-static struct pci_device_id natsemi_pci_tbl[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(natsemi_pci_tbl) = {
        { PCI_VENDOR_ID_NS, 0x0020, 0x12d9,     0x000c,     0, 0, 0 },
        { PCI_VENDOR_ID_NS, 0x0020, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 },
        { }     /* terminate list */
index 3fcebb70151c82fbbab06026f2dc636f3baff7d9..85aec4f1013184d47c110c0c22a5c91b2493ec19 100644 (file)
@@ -136,7 +136,7 @@ static struct {
 };
 
 
-static struct pci_device_id ne2k_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(ne2k_pci_tbl) = {
        { 0x10ec, 0x8029, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_RealTek_RTL_8029 },
        { 0x1050, 0x0940, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Winbond_89C940 },
        { 0x11f6, 0x1401, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Compex_RL2000 },
index 11d94e2434e46fd8b0049150fb4a2424dc6414a0..861a0590b1f4fd2bff47e25a0d84d9f69917c5f0 100644 (file)
@@ -18,7 +18,7 @@
 # MA  02111-1307, USA.
 # 
 # The full GNU General Public License is included in this distribution
-# in the file called LICENSE.
+# in the file called "COPYING".
 # 
 #
 
index 9bc5bd1d538a8b1b83ddf8e390631514ff35e365..144d2e8804225a16e20f3799eface6c1f8a6f165 100644 (file)
@@ -19,7 +19,7 @@
  * MA  02111-1307, USA.
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.
+ * in the file called "COPYING".
  *
  */
 
@@ -420,7 +420,7 @@ struct status_desc {
 } __attribute__ ((aligned(16)));
 
 /* UNIFIED ROMIMAGE *************************/
-#define NX_UNI_FW_MIN_SIZE             0x3eb000
+#define NX_UNI_FW_MIN_SIZE             0xc8000
 #define NX_UNI_DIR_SECT_PRODUCT_TBL    0x0
 #define NX_UNI_DIR_SECT_BOOTLD         0x6
 #define NX_UNI_DIR_SECT_FW             0x7
@@ -1427,8 +1427,8 @@ static inline u32 netxen_tx_avail(struct nx_host_tx_ring *tx_ring)
 
 }
 
-int netxen_get_flash_mac_addr(struct netxen_adapter *adapter, __le64 *mac);
-int netxen_p3_get_mac_addr(struct netxen_adapter *adapter, __le64 *mac);
+int netxen_get_flash_mac_addr(struct netxen_adapter *adapter, u64 *mac);
+int netxen_p3_get_mac_addr(struct netxen_adapter *adapter, u64 *mac);
 extern void netxen_change_ringparam(struct netxen_adapter *adapter);
 extern int netxen_rom_fast_read(struct netxen_adapter *adapter, int addr,
                                int *valp);
index 9cb8f68780470137e42a57b94b8bde904abbc2d9..2a8ef5fc9663b094bcfdfb5fc24c2f4adbff31be 100644 (file)
@@ -19,7 +19,7 @@
  * MA  02111-1307, USA.
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.
+ * in the file called "COPYING".
  *
  */
 
index 542f408333ff17633330f0b34f7aa6dcd3a1445a..f8499e56cbee4752b37938aa0f0a948663134bec 100644 (file)
@@ -19,7 +19,7 @@
  * MA  02111-1307, USA.
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.
+ * in the file called "COPYING".
  *
  */
 
index d138fc22927afee3281e0d7137d01c2b4eb59309..622e4c8be937c0c7b3c1c44db335954134235f39 100644 (file)
@@ -19,7 +19,7 @@
  * MA  02111-1307, USA.
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.
+ * in the file called "COPYING".
  *
  */
 
@@ -969,7 +969,8 @@ enum {
 #define NX_DEV_READY           3
 #define NX_DEV_NEED_RESET      4
 #define NX_DEV_NEED_QUISCENT   5
-#define NX_DEV_FAILED          6
+#define NX_DEV_NEED_AER        6
+#define NX_DEV_FAILED          7
 
 #define NX_RCODE_DRIVER_INFO           0x20000000
 #define NX_RCODE_DRIVER_CAN_RELOAD     0x40000000
index 85e28e60ecf1a43fe9f4b789877994deeaa1f716..dd45c7a9122e708af4957ee4a484364eb7c9fba0 100644 (file)
@@ -19,7 +19,7 @@
  * MA  02111-1307, USA.
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.
+ * in the file called "COPYING".
  *
  */
 
@@ -777,17 +777,20 @@ int netxen_p3_nic_set_mac_addr(struct netxen_adapter *adapter, u8 *addr)
 int netxen_config_intr_coalesce(struct netxen_adapter *adapter)
 {
        nx_nic_req_t req;
-       u64 word;
-       int rv;
+       u64 word[6];
+       int rv, i;
 
        memset(&req, 0, sizeof(nx_nic_req_t));
+       memset(word, 0, sizeof(word));
 
        req.qhdr = cpu_to_le64(NX_HOST_REQUEST << 23);
 
-       word = NETXEN_CONFIG_INTR_COALESCE | ((u64)adapter->portnum << 16);
-       req.req_hdr = cpu_to_le64(word);
+       word[0] = NETXEN_CONFIG_INTR_COALESCE | ((u64)adapter->portnum << 16);
+       req.req_hdr = cpu_to_le64(word[0]);
 
-       memcpy(&req.words[0], &adapter->coal, sizeof(adapter->coal));
+       memcpy(&word[0], &adapter->coal, sizeof(adapter->coal));
+       for (i = 0; i < 6; i++)
+               req.words[i] = cpu_to_le64(word[i]);
 
        rv = netxen_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
        if (rv != 0) {
@@ -1033,7 +1036,7 @@ static int netxen_get_flash_block(struct netxen_adapter *adapter, int base,
        return 0;
 }
 
-int netxen_get_flash_mac_addr(struct netxen_adapter *adapter, __le64 *mac)
+int netxen_get_flash_mac_addr(struct netxen_adapter *adapter, u64 *mac)
 {
        __le32 *pmac = (__le32 *) mac;
        u32 offset;
@@ -1058,7 +1061,7 @@ int netxen_get_flash_mac_addr(struct netxen_adapter *adapter, __le64 *mac)
        return 0;
 }
 
-int netxen_p3_get_mac_addr(struct netxen_adapter *adapter, __le64 *mac)
+int netxen_p3_get_mac_addr(struct netxen_adapter *adapter, u64 *mac)
 {
        uint32_t crbaddr, mac_hi, mac_lo;
        int pci_func = adapter->ahw.pci_func;
index 3fd1dcb3583a6276da1577620e7fabe7469ee1f7..e2c5b6f2df0361e54a6fcb2c8f9df41098610fd4 100644 (file)
@@ -19,7 +19,7 @@
  * MA  02111-1307, USA.
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.
+ * in the file called "COPYING".
  *
  */
 
index 64cff68d372c9573717a66888def79cfbf501a92..1c63610ead422a29b4628e525b7c1be37de300dd 100644 (file)
@@ -19,7 +19,7 @@
  * MA  02111-1307, USA.
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.
+ * in the file called "COPYING".
  *
  */
 
@@ -780,6 +780,9 @@ netxen_need_fw_reset(struct netxen_adapter *adapter)
        if (NX_IS_REVISION_P2(adapter->ahw.revision_id))
                return 1;
 
+       if (adapter->need_fw_reset)
+               return 1;
+
        /* last attempt had failed */
        if (NXRD32(adapter, CRB_CMDPEG_STATE) == PHAN_INITIALIZE_FAILED)
                return 1;
index 24279e6e55f5046711a938cfeab782624d11718b..08780ef1c1f885d56b38d9c4ff68b4f790711f58 100644 (file)
@@ -19,7 +19,7 @@
  * MA  02111-1307, USA.
  *
  * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.
+ * in the file called "COPYING".
  *
  */
 
@@ -35,6 +35,7 @@
 #include <linux/ipv6.h>
 #include <linux/inetdevice.h>
 #include <linux/sysfs.h>
+#include <linux/aer.h>
 
 MODULE_DESCRIPTION("QLogic/NetXen (1/10) GbE Converged Ethernet Driver");
 MODULE_LICENSE("GPL");
@@ -84,6 +85,7 @@ static void netxen_remove_sysfs_entries(struct netxen_adapter *adapter);
 static void netxen_create_diag_entries(struct netxen_adapter *adapter);
 static void netxen_remove_diag_entries(struct netxen_adapter *adapter);
 
+static int nx_dev_request_aer(struct netxen_adapter *adapter);
 static int nx_decr_dev_ref_cnt(struct netxen_adapter *adapter);
 static int netxen_can_start_firmware(struct netxen_adapter *adapter);
 
@@ -98,7 +100,7 @@ static void netxen_config_indev_addr(struct net_device *dev, unsigned long);
        {PCI_DEVICE(PCI_VENDOR_ID_NETXEN, (device)), \
        .class = PCI_CLASS_NETWORK_ETHERNET << 8, .class_mask = ~0}
 
-static struct pci_device_id netxen_pci_tbl[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(netxen_pci_tbl) = {
        ENTRY(PCI_DEVICE_ID_NX2031_10GXSR),
        ENTRY(PCI_DEVICE_ID_NX2031_10GCX4),
        ENTRY(PCI_DEVICE_ID_NX2031_4GCU),
@@ -430,7 +432,7 @@ netxen_read_mac_addr(struct netxen_adapter *adapter)
 {
        int i;
        unsigned char *p;
-       __le64 mac_addr;
+       u64 mac_addr;
        struct net_device *netdev = adapter->netdev;
        struct pci_dev *pdev = adapter->pdev;
 
@@ -1262,6 +1264,9 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        if ((err = pci_request_regions(pdev, netxen_nic_driver_name)))
                goto err_out_disable_pdev;
 
+       if (NX_IS_REVISION_P3(pdev->revision))
+               pci_enable_pcie_error_reporting(pdev);
+
        pci_set_master(pdev);
 
        netdev = alloc_etherdev(sizeof(struct netxen_adapter));
@@ -1409,17 +1414,19 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev)
 
        netxen_release_firmware(adapter);
 
+       if (NX_IS_REVISION_P3(pdev->revision))
+               pci_disable_pcie_error_reporting(pdev);
+
        pci_release_regions(pdev);
        pci_disable_device(pdev);
        pci_set_drvdata(pdev, NULL);
 
        free_netdev(netdev);
 }
-static int __netxen_nic_shutdown(struct pci_dev *pdev)
+
+static void netxen_nic_detach_func(struct netxen_adapter *adapter)
 {
-       struct netxen_adapter *adapter = pci_get_drvdata(pdev);
        struct net_device *netdev = adapter->netdev;
-       int retval;
 
        netif_device_detach(netdev);
 
@@ -1438,53 +1445,22 @@ static int __netxen_nic_shutdown(struct pci_dev *pdev)
        nx_decr_dev_ref_cnt(adapter);
 
        clear_bit(__NX_RESETTING, &adapter->state);
-
-       retval = pci_save_state(pdev);
-       if (retval)
-               return retval;
-
-       if (netxen_nic_wol_supported(adapter)) {
-               pci_enable_wake(pdev, PCI_D3cold, 1);
-               pci_enable_wake(pdev, PCI_D3hot, 1);
-       }
-
-       pci_disable_device(pdev);
-
-       return 0;
 }
-static void netxen_nic_shutdown(struct pci_dev *pdev)
-{
-       if (__netxen_nic_shutdown(pdev))
-               return;
-}
-#ifdef CONFIG_PM
-static int
-netxen_nic_suspend(struct pci_dev *pdev, pm_message_t state)
-{
-       int retval;
-
-       retval = __netxen_nic_shutdown(pdev);
-       if (retval)
-               return retval;
 
-       pci_set_power_state(pdev, pci_choose_state(pdev, state));
-       return 0;
-}
-
-static int
-netxen_nic_resume(struct pci_dev *pdev)
+static int netxen_nic_attach_func(struct pci_dev *pdev)
 {
        struct netxen_adapter *adapter = pci_get_drvdata(pdev);
        struct net_device *netdev = adapter->netdev;
        int err;
 
-       pci_set_power_state(pdev, PCI_D0);
-       pci_restore_state(pdev);
-
        err = pci_enable_device(pdev);
        if (err)
                return err;
 
+       pci_set_power_state(pdev, PCI_D0);
+       pci_set_master(pdev);
+       pci_restore_state(pdev);
+
        adapter->ahw.crb_win = -1;
        adapter->ahw.ocm_win = -1;
 
@@ -1503,11 +1479,10 @@ netxen_nic_resume(struct pci_dev *pdev)
                if (err)
                        goto err_out_detach;
 
-               netif_device_attach(netdev);
-
                netxen_config_indev_addr(netdev, NETDEV_UP);
        }
 
+       netif_device_attach(netdev);
        netxen_schedule_work(adapter, netxen_fw_poll_work, FW_POLL_DELAY);
        return 0;
 
@@ -1517,6 +1492,85 @@ err_out:
        nx_decr_dev_ref_cnt(adapter);
        return err;
 }
+
+static pci_ers_result_t netxen_io_error_detected(struct pci_dev *pdev,
+                                               pci_channel_state_t state)
+{
+       struct netxen_adapter *adapter = pci_get_drvdata(pdev);
+
+       if (state == pci_channel_io_perm_failure)
+               return PCI_ERS_RESULT_DISCONNECT;
+
+       if (nx_dev_request_aer(adapter))
+               return PCI_ERS_RESULT_RECOVERED;
+
+       netxen_nic_detach_func(adapter);
+
+       pci_disable_device(pdev);
+
+       return PCI_ERS_RESULT_NEED_RESET;
+}
+
+static pci_ers_result_t netxen_io_slot_reset(struct pci_dev *pdev)
+{
+       int err = 0;
+
+       err = netxen_nic_attach_func(pdev);
+
+       return err ? PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_RECOVERED;
+}
+
+static void netxen_io_resume(struct pci_dev *pdev)
+{
+       pci_cleanup_aer_uncorrect_error_status(pdev);
+}
+
+static void netxen_nic_shutdown(struct pci_dev *pdev)
+{
+       struct netxen_adapter *adapter = pci_get_drvdata(pdev);
+
+       netxen_nic_detach_func(adapter);
+
+       if (pci_save_state(pdev))
+               return;
+
+       if (netxen_nic_wol_supported(adapter)) {
+               pci_enable_wake(pdev, PCI_D3cold, 1);
+               pci_enable_wake(pdev, PCI_D3hot, 1);
+       }
+
+       pci_disable_device(pdev);
+}
+
+#ifdef CONFIG_PM
+static int
+netxen_nic_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+       struct netxen_adapter *adapter = pci_get_drvdata(pdev);
+       int retval;
+
+       netxen_nic_detach_func(adapter);
+
+       retval = pci_save_state(pdev);
+       if (retval)
+               return retval;
+
+       if (netxen_nic_wol_supported(adapter)) {
+               pci_enable_wake(pdev, PCI_D3cold, 1);
+               pci_enable_wake(pdev, PCI_D3hot, 1);
+       }
+
+       pci_disable_device(pdev);
+       pci_set_power_state(pdev, pci_choose_state(pdev, state));
+
+       return 0;
+}
+
+static int
+netxen_nic_resume(struct pci_dev *pdev)
+{
+       return netxen_nic_attach_func(pdev);
+}
 #endif
 
 static int netxen_nic_open(struct net_device *netdev)
@@ -2104,20 +2158,49 @@ nx_decr_dev_ref_cnt(struct netxen_adapter *adapter)
        return count;
 }
 
-static void
+static int
+nx_dev_request_aer(struct netxen_adapter *adapter)
+{
+       u32 state;
+       int ret = -EINVAL;
+
+       if (netxen_api_lock(adapter))
+               return ret;
+
+       state = NXRD32(adapter, NX_CRB_DEV_STATE);
+
+       if (state == NX_DEV_NEED_AER)
+               ret = 0;
+       else if (state == NX_DEV_READY) {
+               NXWR32(adapter, NX_CRB_DEV_STATE, NX_DEV_NEED_AER);
+               ret = 0;
+       }
+
+       netxen_api_unlock(adapter);
+       return ret;
+}
+
+static int
 nx_dev_request_reset(struct netxen_adapter *adapter)
 {
        u32 state;
+       int ret = -EINVAL;
 
        if (netxen_api_lock(adapter))
-               return;
+               return ret;
 
        state = NXRD32(adapter, NX_CRB_DEV_STATE);
 
-       if (state != NX_DEV_INITALIZING)
+       if (state == NX_DEV_NEED_RESET)
+               ret = 0;
+       else if (state != NX_DEV_INITALIZING && state != NX_DEV_NEED_AER) {
                NXWR32(adapter, NX_CRB_DEV_STATE, NX_DEV_NEED_RESET);
+               ret = 0;
+       }
 
        netxen_api_unlock(adapter);
+
+       return ret;
 }
 
 static int
@@ -2271,17 +2354,29 @@ netxen_check_health(struct netxen_adapter *adapter)
        u32 state, heartbit;
        struct net_device *netdev = adapter->netdev;
 
+       state = NXRD32(adapter, NX_CRB_DEV_STATE);
+       if (state == NX_DEV_NEED_AER)
+               return 0;
+
        if (netxen_nic_check_temp(adapter))
                goto detach;
 
        if (adapter->need_fw_reset) {
-               nx_dev_request_reset(adapter);
+               if (nx_dev_request_reset(adapter))
+                       return 0;
                goto detach;
        }
 
-       state = NXRD32(adapter, NX_CRB_DEV_STATE);
-       if (state == NX_DEV_NEED_RESET)
-               goto detach;
+       /* NX_DEV_NEED_RESET, this state can be marked in two cases
+        * 1. Tx timeout 2. Fw hang
+        * Send request to destroy context in case of tx timeout only
+        * and doesn't required in case of Fw hang
+        */
+       if (state == NX_DEV_NEED_RESET) {
+               adapter->need_fw_reset = 1;
+               if (NX_IS_REVISION_P2(adapter->ahw.revision_id))
+                       goto detach;
+       }
 
        if (NX_IS_REVISION_P2(adapter->ahw.revision_id))
                return 0;
@@ -2290,12 +2385,17 @@ netxen_check_health(struct netxen_adapter *adapter)
        if (heartbit != adapter->heartbit) {
                adapter->heartbit = heartbit;
                adapter->fw_fail_cnt = 0;
+               if (adapter->need_fw_reset)
+                       goto detach;
                return 0;
        }
 
        if (++adapter->fw_fail_cnt < FW_FAIL_THRESH)
                return 0;
 
+       if (nx_dev_request_reset(adapter))
+               return 0;
+
        clear_bit(__NX_FW_ATTACHED, &adapter->state);
 
        dev_info(&netdev->dev, "firmware hang detected\n");
@@ -2498,7 +2598,7 @@ netxen_sysfs_read_mem(struct kobject *kobj, struct bin_attribute *attr,
        return size;
 }
 
-ssize_t netxen_sysfs_write_mem(struct kobject *kobj,
+static ssize_t netxen_sysfs_write_mem(struct kobject *kobj,
                struct bin_attribute *attr, char *buf,
                loff_t offset, size_t size)
 {
@@ -2725,6 +2825,12 @@ netxen_config_indev_addr(struct net_device *dev, unsigned long event)
 { }
 #endif
 
+static struct pci_error_handlers netxen_err_handler = {
+       .error_detected = netxen_io_error_detected,
+       .slot_reset = netxen_io_slot_reset,
+       .resume = netxen_io_resume,
+};
+
 static struct pci_driver netxen_driver = {
        .name = netxen_nic_driver_name,
        .id_table = netxen_pci_tbl,
@@ -2734,7 +2840,8 @@ static struct pci_driver netxen_driver = {
        .suspend = netxen_nic_suspend,
        .resume = netxen_nic_resume,
 #endif
-       .shutdown = netxen_nic_shutdown
+       .shutdown = netxen_nic_shutdown,
+       .err_handler = &netxen_err_handler
 };
 
 static int __init netxen_init_module(void)
index 2aed2b382c409358bd5a72c42694ea1ea117da15..af9a8647c7e8ae8d7aa4cdb442b9e0a0fd2e55fe 100644 (file)
@@ -58,7 +58,7 @@ static void writeq(u64 val, void __iomem *reg)
 }
 #endif
 
-static struct pci_device_id niu_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(niu_pci_tbl) = {
        {PCI_DEVICE(PCI_VENDOR_ID_SUN, 0xabcd)},
        {}
 };
@@ -6372,7 +6372,7 @@ static void niu_set_rx_mode(struct net_device *dev)
        if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 0))
                np->flags |= NIU_FLAGS_MCAST;
 
-       alt_cnt = dev->uc.count;
+       alt_cnt = netdev_uc_count(dev);
        if (alt_cnt > niu_num_alt_addr(np)) {
                alt_cnt = 0;
                np->flags |= NIU_FLAGS_PROMISC;
@@ -6381,7 +6381,7 @@ static void niu_set_rx_mode(struct net_device *dev)
        if (alt_cnt) {
                int index = 0;
 
-               list_for_each_entry(ha, &dev->uc.list, list) {
+               netdev_for_each_uc_addr(ha, dev) {
                        err = niu_set_alt_mac(np, index, ha->addr);
                        if (err)
                                printk(KERN_WARNING PFX "%s: Error %d "
index 1f6327d4153699d7ed65aab16eddbf0004f3149a..a3b6aa0f375da037263eb1fa5d71b96da22d129f 100644 (file)
@@ -2292,7 +2292,7 @@ static void __devexit ns83820_remove_one(struct pci_dev *pci_dev)
        pci_set_drvdata(pci_dev, NULL);
 }
 
-static struct pci_device_id ns83820_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(ns83820_pci_tbl) = {
        { 0x100b, 0x0022, PCI_ANY_ID, PCI_ANY_ID, 0, .driver_data = 0, },
        { 0, },
 };
index 050538bf155a5b34bed529da415c10a908a648f8..6fd8789ef487bc71e992eb5ed119ec18c71bdd0a 100644 (file)
@@ -1119,11 +1119,8 @@ static int __init octeon_mgmt_probe(struct platform_device *pdev)
 
        if (p->port >= octeon_bootinfo->mac_addr_count)
                dev_err(&pdev->dev,
-                       "Error %s: Using MAC outside of the assigned range: "
-                       "%02x:%02x:%02x:%02x:%02x:%02x\n", netdev->name,
-                       netdev->dev_addr[0], netdev->dev_addr[1],
-                       netdev->dev_addr[2], netdev->dev_addr[3],
-                       netdev->dev_addr[4], netdev->dev_addr[5]);
+                       "Error %s: Using MAC outside of the assigned range: %pM\n",
+                       netdev->name, netdev->dev_addr);
 
        if (register_netdev(netdev))
                goto err;
index 1673eb045e1e650c8373eb20ec894ed010d787ae..d44d4a208bbf144ceecd4f7ba6dab36d16e6eb38 100644 (file)
@@ -1875,7 +1875,7 @@ static void __devexit pasemi_mac_remove(struct pci_dev *pdev)
        free_netdev(netdev);
 }
 
-static struct pci_device_id pasemi_mac_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(pasemi_mac_pci_tbl) = {
        { PCI_DEVICE(PCI_VENDOR_ID_PASEMI, 0xa005) },
        { PCI_DEVICE(PCI_VENDOR_ID_PASEMI, 0xa006) },
        { },
index 480af402affd5893c63d1c75dcd0021479474b63..20273832bfcedfd8e6ab94fce3cefa1b2a07f0cd 100644 (file)
@@ -211,7 +211,7 @@ static struct {
 };
 
 
-static struct pci_device_id netdrv_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(netdrv_pci_tbl) = {
        {0x10ec, 0x8139, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
        {0x10ec, 0x8138, PCI_ANY_ID, PCI_ANY_ID, 0, 0, NETDRV_CB },
        {0x1113, 0x1211, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SMC1211TX },
index d431b59e7d11bda7b203a96cec3217570344eade..2ee57bd52a019152323be86c76ae8bf6cefc44c1 100644 (file)
@@ -1065,14 +1065,11 @@ static netdev_tx_t axnet_start_xmit(struct sk_buff *skb,
           
        spin_lock_irqsave(&ei_local->page_lock, flags);
        outb_p(0x00, e8390_base + EN0_IMR);
-       spin_unlock_irqrestore(&ei_local->page_lock, flags);
        
        /*
         *      Slow phase with lock held.
         */
         
-       spin_lock_irqsave(&ei_local->page_lock, flags);
-       
        ei_local->irqlock = 1;
 
        send_length = max(length, ETH_ZLEN);
index e154677ff706834285ce6f4a7bd6f00d83118818..0dc7ff896eebc4b0a167c2598977f69cfe43babb 100644 (file)
@@ -59,7 +59,7 @@ static const char *const version =
 /*
  * PCI device identifiers for "new style" Linux PCI Device Drivers
  */
-static struct pci_device_id pcnet32_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(pcnet32_pci_tbl) = {
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE_HOME), },
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE), },
 
index 6f69b9ba0df8994736e9f1a0eaad78b0a52f497f..65ed385c2ceb430f091cf26ef0b1acfc87a6978a 100644 (file)
@@ -63,6 +63,7 @@
 #define MII_M1111_HWCFG_MODE_COPPER_RGMII      0xb
 #define MII_M1111_HWCFG_MODE_FIBER_RGMII       0x3
 #define MII_M1111_HWCFG_MODE_SGMII_NO_CLK      0x4
+#define MII_M1111_HWCFG_MODE_COPPER_RTBI       0x9
 #define MII_M1111_HWCFG_FIBER_COPPER_AUTO      0x8000
 #define MII_M1111_HWCFG_FIBER_COPPER_RES       0x2000
 
@@ -269,6 +270,43 @@ static int m88e1111_config_init(struct phy_device *phydev)
                        return err;
        }
 
+       if (phydev->interface == PHY_INTERFACE_MODE_RTBI) {
+               temp = phy_read(phydev, MII_M1111_PHY_EXT_CR);
+               if (temp < 0)
+                       return temp;
+               temp |= (MII_M1111_RX_DELAY | MII_M1111_TX_DELAY);
+               err = phy_write(phydev, MII_M1111_PHY_EXT_CR, temp);
+               if (err < 0)
+                       return err;
+
+               temp = phy_read(phydev, MII_M1111_PHY_EXT_SR);
+               if (temp < 0)
+                       return temp;
+               temp &= ~(MII_M1111_HWCFG_MODE_MASK | MII_M1111_HWCFG_FIBER_COPPER_RES);
+               temp |= 0x7 | MII_M1111_HWCFG_FIBER_COPPER_AUTO;
+               err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp);
+               if (err < 0)
+                       return err;
+
+               /* soft reset */
+               err = phy_write(phydev, MII_BMCR, BMCR_RESET);
+               if (err < 0)
+                       return err;
+               do
+                       temp = phy_read(phydev, MII_BMCR);
+               while (temp & BMCR_RESET);
+
+               temp = phy_read(phydev, MII_M1111_PHY_EXT_SR);
+               if (temp < 0)
+                       return temp;
+               temp &= ~(MII_M1111_HWCFG_MODE_MASK | MII_M1111_HWCFG_FIBER_COPPER_RES);
+               temp |= MII_M1111_HWCFG_MODE_COPPER_RTBI | MII_M1111_HWCFG_FIBER_COPPER_AUTO;
+               err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp);
+               if (err < 0)
+                       return err;
+       }
+
+
        err = phy_write(phydev, MII_BMCR, BMCR_RESET);
        if (err < 0)
                return err;
index 5123bb954dd751e198038fd3cbbc8f445b1208d2..ed2644a57500c0673b40709d574e87df06fc8533 100644 (file)
@@ -25,6 +25,7 @@
 
 #define MII_LAN83C185_ISF 29 /* Interrupt Source Flags */
 #define MII_LAN83C185_IM  30 /* Interrupt Mask */
+#define MII_LAN83C185_CTRL_STATUS 17 /* Mode/Status Register */
 
 #define MII_LAN83C185_ISF_INT1 (1<<1) /* Auto-Negotiation Page Received */
 #define MII_LAN83C185_ISF_INT2 (1<<2) /* Parallel Detection Fault */
 #define MII_LAN83C185_ISF_INT_ALL (0x0e)
 
 #define MII_LAN83C185_ISF_INT_PHYLIB_EVENTS \
-       (MII_LAN83C185_ISF_INT6 | MII_LAN83C185_ISF_INT4)
+       (MII_LAN83C185_ISF_INT6 | MII_LAN83C185_ISF_INT4 | \
+        MII_LAN83C185_ISF_INT7)
 
+#define MII_LAN83C185_EDPWRDOWN        (1 << 13) /* EDPWRDOWN */
 
 static int smsc_phy_config_intr(struct phy_device *phydev)
 {
@@ -59,9 +62,23 @@ static int smsc_phy_ack_interrupt(struct phy_device *phydev)
 
 static int smsc_phy_config_init(struct phy_device *phydev)
 {
+       int rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS);
+       if (rc < 0)
+               return rc;
+
+       /* Enable energy detect mode for this SMSC Transceivers */
+       rc = phy_write(phydev, MII_LAN83C185_CTRL_STATUS,
+                      rc | MII_LAN83C185_EDPWRDOWN);
+       if (rc < 0)
+               return rc;
+
        return smsc_phy_ack_interrupt (phydev);
 }
 
+static int lan911x_config_init(struct phy_device *phydev)
+{
+       return smsc_phy_ack_interrupt(phydev);
+}
 
 static struct phy_driver lan83c185_driver = {
        .phy_id         = 0x0007c0a0, /* OUI=0x00800f, Model#=0x0a */
@@ -147,7 +164,7 @@ static struct phy_driver lan911x_int_driver = {
        /* basic functions */
        .config_aneg    = genphy_config_aneg,
        .read_status    = genphy_read_status,
-       .config_init    = smsc_phy_config_init,
+       .config_init    = lan911x_config_init,
 
        /* IRQ related */
        .ack_interrupt  = smsc_phy_ack_interrupt,
index 2282e729edbe55742dba8632c0f48311dd00b9e0..6d61602208c1f1470409c34717e7641e038b86a5 100644 (file)
@@ -167,7 +167,7 @@ struct channel {
        u8              avail;          /* flag used in multilink stuff */
        u8              had_frag;       /* >= 1 fragments have been sent */
        u32             lastseq;        /* MP: last sequence # received */
-       int     speed;          /* speed of the corresponding ppp channel*/
+       int             speed;          /* speed of the corresponding ppp channel*/
 #endif /* CONFIG_PPP_MULTILINK */
 };
 
@@ -1293,13 +1293,13 @@ ppp_push(struct ppp *ppp)
  */
 static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb)
 {
-       int     len, totlen;
-       int     i, bits, hdrlen, mtu;
-       int     flen;
-       int     navail, nfree, nzero;
-       int     nbigger;
-       int     totspeed;
-       int     totfree;
+       int len, totlen;
+       int i, bits, hdrlen, mtu;
+       int flen;
+       int navail, nfree, nzero;
+       int nbigger;
+       int totspeed;
+       int totfree;
        unsigned char *p, *q;
        struct list_head *list;
        struct channel *pch;
@@ -1307,21 +1307,21 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb)
        struct ppp_channel *chan;
 
        totspeed = 0; /*total bitrate of the bundle*/
-       nfree = 0;      /* # channels which     have no packet already queued */
-       navail = 0;     /* total # of usable channels (not deregistered) */
-       nzero = 0; /* number of channels with zero speed associated*/
-       totfree = 0; /*total # of channels available and
+       nfree = 0; /* # channels which have no packet already queued */
+       navail = 0; /* total # of usable channels (not deregistered) */
+       nzero = 0; /* number of channels with zero speed associated*/
+       totfree = 0; /*total # of channels available and
                                  *having no queued packets before
                                  *starting the fragmentation*/
 
        hdrlen = (ppp->flags & SC_MP_XSHORTSEQ)? MPHDRLEN_SSN: MPHDRLEN;
-       i =     0;
-       list_for_each_entry(pch, &ppp->channels, clist) {
+       i = 0;
+       list_for_each_entry(pch, &ppp->channels, clist) {
                navail += pch->avail = (pch->chan != NULL);
                pch->speed = pch->chan->speed;
-               if (pch->avail) {
+               if (pch->avail) {
                        if (skb_queue_empty(&pch->file.xq) ||
-                               !pch->had_frag) {
+                               !pch->had_frag) {
                                        if (pch->speed == 0)
                                                nzero++;
                                        else
@@ -1331,60 +1331,60 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb)
                                        ++nfree;
                                        ++totfree;
                                }
-                       if (!pch->had_frag && i < ppp->nxchan)
-                               ppp->nxchan     = i;
+                       if (!pch->had_frag && i < ppp->nxchan)
+                               ppp->nxchan = i;
                }
                ++i;
        }
        /*
-        * Don't start sending this     packet unless at least half     of
-        * the channels are     free.  This     gives much better TCP
-        * performance if we have a     lot     of channels.
+        * Don't start sending this packet unless at least half of
+        * the channels are free.  This gives much better TCP
+        * performance if we have a lot of channels.
         */
-       if (nfree == 0 || nfree < navail / 2)
-               return 0; /* can't take now, leave it in xmit_pending   */
+       if (nfree == 0 || nfree < navail / 2)
+               return 0; /* can't take now, leave it in xmit_pending */
 
        /* Do protocol field compression (XXX this should be optional) */
-       p =     skb->data;
-       len     = skb->len;
+       p = skb->data;
+       len = skb->len;
        if (*p == 0) {
                ++p;
                --len;
        }
 
        totlen = len;
-       nbigger = len % nfree;
+       nbigger = len % nfree;
 
-       /* skip to the channel after the one we last used
-          and start at that one */
+       /* skip to the channel after the one we last used
+          and start at that one */
        list = &ppp->channels;
-       for     (i = 0; i <     ppp->nxchan; ++i) {
+       for (i = 0; i < ppp->nxchan; ++i) {
                list = list->next;
-               if (list ==     &ppp->channels) {
-                       i =     0;
+               if (list == &ppp->channels) {
+                       i = 0;
                        break;
                }
        }
 
-       /* create a     fragment for each channel */
+       /* create a fragment for each channel */
        bits = B;
-       while (len      > 0) {
+       while (len > 0) {
                list = list->next;
-               if (list ==     &ppp->channels) {
-                       i =     0;
+               if (list == &ppp->channels) {
+                       i = 0;
                        continue;
                }
-               pch     = list_entry(list, struct channel, clist);
+               pch = list_entry(list, struct channel, clist);
                ++i;
                if (!pch->avail)
                        continue;
 
                /*
-                * Skip this channel if it has a fragment pending already and
-                * we haven't given     a fragment to all of the free channels.
+                * Skip this channel if it has a fragment pending already and
+                * we haven't given a fragment to all of the free channels.
                 */
                if (pch->avail == 1) {
-                       if (nfree >     0)
+                       if (nfree > 0)
                                continue;
                } else {
                        pch->avail = 1;
@@ -1393,32 +1393,32 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb)
                /* check the channel's mtu and whether it is still attached. */
                spin_lock_bh(&pch->downl);
                if (pch->chan == NULL) {
-                       /* can't use this channel, it's being deregistered */
+                       /* can't use this channel, it's being deregistered */
                        if (pch->speed == 0)
                                nzero--;
                        else
-                               totspeed -=     pch->speed;
+                               totspeed -= pch->speed;
 
                        spin_unlock_bh(&pch->downl);
                        pch->avail = 0;
                        totlen = len;
                        totfree--;
                        nfree--;
-                       if (--navail == 0)
+                       if (--navail == 0)
                                break;
                        continue;
                }
 
                /*
                *if the channel speed is not set divide
-               *the packet     evenly among the free channels;
+               *the packet evenly among the free channels;
                *otherwise divide it according to the speed
                *of the channel we are going to transmit on
                */
                flen = len;
                if (nfree > 0) {
                        if (pch->speed == 0) {
-                               flen = totlen/nfree     ;
+                               flen = totlen/nfree;
                                if (nbigger > 0) {
                                        flen++;
                                        nbigger--;
@@ -1436,8 +1436,8 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb)
                }
 
                /*
-                *check if we are on the last channel or
-                *we exceded the lenght of the data     to
+                *check if we are on the last channel or
+                *we exceded the lenght of the data to
                 *fragment
                 */
                if ((nfree <= 0) || (flen > len))
@@ -1448,29 +1448,29 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb)
                 *above formula will be equal or less than zero.
                 *Skip the channel in this case
                 */
-               if (flen <=     0) {
+               if (flen <= 0) {
                        pch->avail = 2;
                        spin_unlock_bh(&pch->downl);
                        continue;
                }
 
-               mtu     = pch->chan->mtu - hdrlen;
-               if (mtu < 4)
-                       mtu     = 4;
+               mtu = pch->chan->mtu - hdrlen;
+               if (mtu < 4)
+                       mtu = 4;
                if (flen > mtu)
                        flen = mtu;
-               if (flen ==     len)
-                       bits |= E;
-               frag = alloc_skb(flen + hdrlen + (flen == 0), GFP_ATOMIC);
+               if (flen == len)
+                       bits |= E;
+               frag = alloc_skb(flen + hdrlen + (flen == 0), GFP_ATOMIC);
                if (!frag)
                        goto noskb;
-               q =     skb_put(frag, flen + hdrlen);
+               q = skb_put(frag, flen + hdrlen);
 
-               /* make the     MP header */
+               /* make the MP header */
                q[0] = PPP_MP >> 8;
                q[1] = PPP_MP;
                if (ppp->flags & SC_MP_XSHORTSEQ) {
-                       q[2] = bits     + ((ppp->nxseq >> 8) & 0xf);
+                       q[2] = bits + ((ppp->nxseq >> 8) & 0xf);
                        q[3] = ppp->nxseq;
                } else {
                        q[2] = bits;
@@ -1483,24 +1483,24 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb)
 
                /* try to send it down the channel */
                chan = pch->chan;
-               if (!skb_queue_empty(&pch->file.xq)     ||
+               if (!skb_queue_empty(&pch->file.xq) ||
                        !chan->ops->start_xmit(chan, frag))
                        skb_queue_tail(&pch->file.xq, frag);
-               pch->had_frag = 1;
+               pch->had_frag = 1;
                p += flen;
-               len     -= flen;
+               len -= flen;
                ++ppp->nxseq;
                bits = 0;
                spin_unlock_bh(&pch->downl);
        }
-       ppp->nxchan     = i;
+       ppp->nxchan = i;
 
        return 1;
 
  noskb:
        spin_unlock_bh(&pch->downl);
        if (ppp->debug & 1)
-               printk(KERN_ERR "PPP: no memory (fragment)\n");
+               printk(KERN_ERR "PPP: no memory (fragment)\n");
        ++ppp->dev->stats.tx_errors;
        ++ppp->nxseq;
        return 1;       /* abandon the frame */
index dd35066a7f8d17d8f131253b906e2501dfa86244..4ef0afbcbe1b1980081aa147330b2e0ec4674dad 100644 (file)
@@ -61,7 +61,7 @@ static int msi;
 module_param(msi, int, 0);
 MODULE_PARM_DESC(msi, "Turn on Message Signaled Interrupts.");
 
-static struct pci_device_id ql3xxx_pci_tbl[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(ql3xxx_pci_tbl) = {
        {PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QL3022_DEVICE_ID)},
        {PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QL3032_DEVICE_ID)},
        /* required last entry */
@@ -4087,7 +4087,6 @@ static void __devexit ql3xxx_remove(struct pci_dev *pdev)
        struct ql3_adapter *qdev = netdev_priv(ndev);
 
        unregister_netdev(ndev);
-       qdev = netdev_priv(ndev);
 
        ql_disable_interrupts(qdev);
 
diff --git a/drivers/net/qlcnic/Makefile b/drivers/net/qlcnic/Makefile
new file mode 100644 (file)
index 0000000..ddba83e
--- /dev/null
@@ -0,0 +1,8 @@
+#
+# Makefile for Qlogic 1G/10G Ethernet Driver for CNA devices
+#
+
+obj-$(CONFIG_QLCNIC) := qlcnic.o
+
+qlcnic-y := qlcnic_hw.o qlcnic_main.o qlcnic_init.o \
+       qlcnic_ethtool.o qlcnic_ctx.o
diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h
new file mode 100644 (file)
index 0000000..b40a851
--- /dev/null
@@ -0,0 +1,1126 @@
+/*
+ * Copyright (C) 2009 - QLogic Corporation.
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called "COPYING".
+ *
+ */
+
+#ifndef _QLCNIC_H_
+#define _QLCNIC_H_
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ip.h>
+#include <linux/in.h>
+#include <linux/tcp.h>
+#include <linux/skbuff.h>
+#include <linux/firmware.h>
+
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/timer.h>
+
+#include <linux/vmalloc.h>
+
+#include <linux/io.h>
+#include <asm/byteorder.h>
+
+#include "qlcnic_hdr.h"
+
+#define _QLCNIC_LINUX_MAJOR 5
+#define _QLCNIC_LINUX_MINOR 0
+#define _QLCNIC_LINUX_SUBVERSION 0
+#define QLCNIC_LINUX_VERSIONID  "5.0.0"
+
+#define QLCNIC_VERSION_CODE(a, b, c)   (((a) << 24) + ((b) << 16) + (c))
+#define _major(v)      (((v) >> 24) & 0xff)
+#define _minor(v)      (((v) >> 16) & 0xff)
+#define _build(v)      ((v) & 0xffff)
+
+/* version in image has weird encoding:
+ *  7:0  - major
+ * 15:8  - minor
+ * 31:16 - build (little endian)
+ */
+#define QLCNIC_DECODE_VERSION(v) \
+       QLCNIC_VERSION_CODE(((v) & 0xff), (((v) >> 8) & 0xff), ((v) >> 16))
+
+#define QLCNIC_NUM_FLASH_SECTORS (64)
+#define QLCNIC_FLASH_SECTOR_SIZE (64 * 1024)
+#define QLCNIC_FLASH_TOTAL_SIZE  (QLCNIC_NUM_FLASH_SECTORS \
+                                       * QLCNIC_FLASH_SECTOR_SIZE)
+
+#define RCV_DESC_RINGSIZE(rds_ring)    \
+       (sizeof(struct rcv_desc) * (rds_ring)->num_desc)
+#define RCV_BUFF_RINGSIZE(rds_ring)    \
+       (sizeof(struct qlcnic_rx_buffer) * rds_ring->num_desc)
+#define STATUS_DESC_RINGSIZE(sds_ring) \
+       (sizeof(struct status_desc) * (sds_ring)->num_desc)
+#define TX_BUFF_RINGSIZE(tx_ring)      \
+       (sizeof(struct qlcnic_cmd_buffer) * tx_ring->num_desc)
+#define TX_DESC_RINGSIZE(tx_ring)      \
+       (sizeof(struct cmd_desc_type0) * tx_ring->num_desc)
+
+#define QLCNIC_P3P_A0          0x50
+
+#define QLCNIC_IS_REVISION_P3P(REVISION)     (REVISION >= QLCNIC_P3P_A0)
+
+#define FIRST_PAGE_GROUP_START 0
+#define FIRST_PAGE_GROUP_END   0x100000
+
+#define P3_MAX_MTU                     (9600)
+#define QLCNIC_MAX_ETHERHDR                32 /* This contains some padding */
+
+#define QLCNIC_P3_RX_BUF_MAX_LEN         (QLCNIC_MAX_ETHERHDR + ETH_DATA_LEN)
+#define QLCNIC_P3_RX_JUMBO_BUF_MAX_LEN   (QLCNIC_MAX_ETHERHDR + P3_MAX_MTU)
+#define QLCNIC_CT_DEFAULT_RX_BUF_LEN   2048
+#define QLCNIC_LRO_BUFFER_EXTRA                2048
+
+#define QLCNIC_RX_LRO_BUFFER_LENGTH            (8060)
+
+/* Opcodes to be used with the commands */
+#define TX_ETHER_PKT   0x01
+#define TX_TCP_PKT     0x02
+#define TX_UDP_PKT     0x03
+#define TX_IP_PKT      0x04
+#define TX_TCP_LSO     0x05
+#define TX_TCP_LSO6    0x06
+#define TX_IPSEC       0x07
+#define TX_IPSEC_CMD   0x0a
+#define TX_TCPV6_PKT   0x0b
+#define TX_UDPV6_PKT   0x0c
+
+/* Tx defines */
+#define MAX_BUFFERS_PER_CMD    32
+#define TX_STOP_THRESH         ((MAX_SKB_FRAGS >> 2) + 4)
+#define QLCNIC_MAX_TX_TIMEOUTS 2
+
+/*
+ * Following are the states of the Phantom. Phantom will set them and
+ * Host will read to check if the fields are correct.
+ */
+#define PHAN_INITIALIZE_FAILED         0xffff
+#define PHAN_INITIALIZE_COMPLETE       0xff01
+
+/* Host writes the following to notify that it has done the init-handshake */
+#define PHAN_INITIALIZE_ACK            0xf00f
+#define PHAN_PEG_RCV_INITIALIZED       0xff01
+
+#define NUM_RCV_DESC_RINGS     3
+#define NUM_STS_DESC_RINGS     4
+
+#define RCV_RING_NORMAL 0
+#define RCV_RING_JUMBO 1
+#define RCV_RING_LRO   2
+
+#define MIN_CMD_DESCRIPTORS            64
+#define MIN_RCV_DESCRIPTORS            64
+#define MIN_JUMBO_DESCRIPTORS          32
+
+#define MAX_CMD_DESCRIPTORS            1024
+#define MAX_RCV_DESCRIPTORS_1G         4096
+#define MAX_RCV_DESCRIPTORS_10G        8192
+#define MAX_JUMBO_RCV_DESCRIPTORS_1G   512
+#define MAX_JUMBO_RCV_DESCRIPTORS_10G  1024
+#define MAX_LRO_RCV_DESCRIPTORS                8
+
+#define DEFAULT_RCV_DESCRIPTORS_1G     2048
+#define DEFAULT_RCV_DESCRIPTORS_10G    4096
+
+#define get_next_index(index, length)  \
+       (((index) + 1) & ((length) - 1))
+
+#define MPORT_MULTI_FUNCTION_MODE 0x2222
+
+/*
+ * Following data structures describe the descriptors that will be used.
+ * Added fileds of tcpHdrSize and ipHdrSize, The driver needs to do it only when
+ * we are doing LSO (above the 1500 size packet) only.
+ */
+
+#define FLAGS_VLAN_TAGGED      0x10
+#define FLAGS_VLAN_OOB         0x40
+
+#define qlcnic_set_tx_vlan_tci(cmd_desc, v)    \
+       (cmd_desc)->vlan_TCI = cpu_to_le16(v);
+#define qlcnic_set_cmd_desc_port(cmd_desc, var)        \
+       ((cmd_desc)->port_ctxid |= ((var) & 0x0F))
+#define qlcnic_set_cmd_desc_ctxid(cmd_desc, var)       \
+       ((cmd_desc)->port_ctxid |= ((var) << 4 & 0xF0))
+
+#define qlcnic_set_tx_port(_desc, _port) \
+       ((_desc)->port_ctxid = ((_port) & 0xf) | (((_port) << 4) & 0xf0))
+
+#define qlcnic_set_tx_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) \
+       ((_desc)->nfrags__length = \
+       cpu_to_le32(((_frags) & 0xff) | (((_len) & 0xffffff) << 8)))
+
+struct cmd_desc_type0 {
+       u8 tcp_hdr_offset;      /* For LSO only */
+       u8 ip_hdr_offset;       /* For LSO only */
+       __le16 flags_opcode;    /* 15:13 unused, 12:7 opcode, 6:0 flags */
+       __le32 nfrags__length;  /* 31:8 total len, 7:0 frag count */
+
+       __le64 addr_buffer2;
+
+       __le16 reference_handle;
+       __le16 mss;
+       u8 port_ctxid;          /* 7:4 ctxid 3:0 port */
+       u8 total_hdr_length;    /* LSO only : MAC+IP+TCP Hdr size */
+       __le16 conn_id;         /* IPSec offoad only */
+
+       __le64 addr_buffer3;
+       __le64 addr_buffer1;
+
+       __le16 buffer_length[4];
+
+       __le64 addr_buffer4;
+
+       __le32 reserved2;
+       __le16 reserved;
+       __le16 vlan_TCI;
+
+} __attribute__ ((aligned(64)));
+
+/* Note: sizeof(rcv_desc) should always be a mutliple of 2 */
+struct rcv_desc {
+       __le16 reference_handle;
+       __le16 reserved;
+       __le32 buffer_length;   /* allocated buffer length (usually 2K) */
+       __le64 addr_buffer;
+};
+
+/* opcode field in status_desc */
+#define QLCNIC_SYN_OFFLOAD     0x03
+#define QLCNIC_RXPKT_DESC      0x04
+#define QLCNIC_OLD_RXPKT_DESC  0x3f
+#define QLCNIC_RESPONSE_DESC   0x05
+#define QLCNIC_LRO_DESC        0x12
+
+/* for status field in status_desc */
+#define STATUS_CKSUM_OK                (2)
+
+/* owner bits of status_desc */
+#define STATUS_OWNER_HOST      (0x1ULL << 56)
+#define STATUS_OWNER_PHANTOM   (0x2ULL << 56)
+
+/* Status descriptor:
+   0-3 port, 4-7 status, 8-11 type, 12-27 total_length
+   28-43 reference_handle, 44-47 protocol, 48-52 pkt_offset
+   53-55 desc_cnt, 56-57 owner, 58-63 opcode
+ */
+#define qlcnic_get_sts_port(sts_data)  \
+       ((sts_data) & 0x0F)
+#define qlcnic_get_sts_status(sts_data)        \
+       (((sts_data) >> 4) & 0x0F)
+#define qlcnic_get_sts_type(sts_data)  \
+       (((sts_data) >> 8) & 0x0F)
+#define qlcnic_get_sts_totallength(sts_data)   \
+       (((sts_data) >> 12) & 0xFFFF)
+#define qlcnic_get_sts_refhandle(sts_data)     \
+       (((sts_data) >> 28) & 0xFFFF)
+#define qlcnic_get_sts_prot(sts_data)  \
+       (((sts_data) >> 44) & 0x0F)
+#define qlcnic_get_sts_pkt_offset(sts_data)    \
+       (((sts_data) >> 48) & 0x1F)
+#define qlcnic_get_sts_desc_cnt(sts_data)      \
+       (((sts_data) >> 53) & 0x7)
+#define qlcnic_get_sts_opcode(sts_data)        \
+       (((sts_data) >> 58) & 0x03F)
+
+#define qlcnic_get_lro_sts_refhandle(sts_data)         \
+       ((sts_data) & 0x0FFFF)
+#define qlcnic_get_lro_sts_length(sts_data)    \
+       (((sts_data) >> 16) & 0x0FFFF)
+#define qlcnic_get_lro_sts_l2_hdr_offset(sts_data)     \
+       (((sts_data) >> 32) & 0x0FF)
+#define qlcnic_get_lro_sts_l4_hdr_offset(sts_data)     \
+       (((sts_data) >> 40) & 0x0FF)
+#define qlcnic_get_lro_sts_timestamp(sts_data) \
+       (((sts_data) >> 48) & 0x1)
+#define qlcnic_get_lro_sts_type(sts_data)      \
+       (((sts_data) >> 49) & 0x7)
+#define qlcnic_get_lro_sts_push_flag(sts_data)         \
+       (((sts_data) >> 52) & 0x1)
+#define qlcnic_get_lro_sts_seq_number(sts_data)                \
+       ((sts_data) & 0x0FFFFFFFF)
+
+
+struct status_desc {
+       __le64 status_desc_data[2];
+} __attribute__ ((aligned(16)));
+
+/* UNIFIED ROMIMAGE */
+#define QLCNIC_UNI_FW_MIN_SIZE         0xc8000
+#define QLCNIC_UNI_DIR_SECT_PRODUCT_TBL        0x0
+#define QLCNIC_UNI_DIR_SECT_BOOTLD     0x6
+#define QLCNIC_UNI_DIR_SECT_FW         0x7
+
+/*Offsets */
+#define QLCNIC_UNI_CHIP_REV_OFF                10
+#define QLCNIC_UNI_FLAGS_OFF           11
+#define QLCNIC_UNI_BIOS_VERSION_OFF    12
+#define QLCNIC_UNI_BOOTLD_IDX_OFF      27
+#define QLCNIC_UNI_FIRMWARE_IDX_OFF    29
+
+struct uni_table_desc{
+       u32     findex;
+       u32     num_entries;
+       u32     entry_size;
+       u32     reserved[5];
+};
+
+struct uni_data_desc{
+       u32     findex;
+       u32     size;
+       u32     reserved[5];
+};
+
+/* Magic number to let user know flash is programmed */
+#define        QLCNIC_BDINFO_MAGIC 0x12345678
+
+#define QLCNIC_BRDTYPE_P3_REF_QG       0x0021
+#define QLCNIC_BRDTYPE_P3_HMEZ         0x0022
+#define QLCNIC_BRDTYPE_P3_10G_CX4_LP   0x0023
+#define QLCNIC_BRDTYPE_P3_4_GB         0x0024
+#define QLCNIC_BRDTYPE_P3_IMEZ         0x0025
+#define QLCNIC_BRDTYPE_P3_10G_SFP_PLUS 0x0026
+#define QLCNIC_BRDTYPE_P3_10000_BASE_T 0x0027
+#define QLCNIC_BRDTYPE_P3_XG_LOM       0x0028
+#define QLCNIC_BRDTYPE_P3_4_GB_MM      0x0029
+#define QLCNIC_BRDTYPE_P3_10G_SFP_CT   0x002a
+#define QLCNIC_BRDTYPE_P3_10G_SFP_QT   0x002b
+#define QLCNIC_BRDTYPE_P3_10G_CX4      0x0031
+#define QLCNIC_BRDTYPE_P3_10G_XFP      0x0032
+#define QLCNIC_BRDTYPE_P3_10G_TP       0x0080
+
+/* Flash memory map */
+#define QLCNIC_BRDCFG_START    0x4000          /* board config */
+#define QLCNIC_BOOTLD_START    0x10000         /* bootld */
+#define QLCNIC_IMAGE_START     0x43000         /* compressed image */
+#define QLCNIC_USER_START      0x3E8000        /* Firmare info */
+
+#define QLCNIC_FW_VERSION_OFFSET       (QLCNIC_USER_START+0x408)
+#define QLCNIC_FW_SIZE_OFFSET          (QLCNIC_USER_START+0x40c)
+#define QLCNIC_FW_SERIAL_NUM_OFFSET    (QLCNIC_USER_START+0x81c)
+#define QLCNIC_BIOS_VERSION_OFFSET     (QLCNIC_USER_START+0x83c)
+
+#define QLCNIC_BRDTYPE_OFFSET          (QLCNIC_BRDCFG_START+0x8)
+#define QLCNIC_FW_MAGIC_OFFSET         (QLCNIC_BRDCFG_START+0x128)
+
+#define QLCNIC_FW_MIN_SIZE             (0x3fffff)
+#define QLCNIC_UNIFIED_ROMIMAGE        0
+#define QLCNIC_FLASH_ROMIMAGE          1
+#define QLCNIC_UNKNOWN_ROMIMAGE                0xff
+
+#define QLCNIC_UNIFIED_ROMIMAGE_NAME   "phanfw.bin"
+#define QLCNIC_FLASH_ROMIMAGE_NAME     "flash"
+
+extern char qlcnic_driver_name[];
+
+/* Number of status descriptors to handle per interrupt */
+#define MAX_STATUS_HANDLE      (64)
+
+/*
+ * qlcnic_skb_frag{} is to contain mapping info for each SG list. This
+ * has to be freed when DMA is complete. This is part of qlcnic_tx_buffer{}.
+ */
+struct qlcnic_skb_frag {
+       u64 dma;
+       u64 length;
+};
+
+struct qlcnic_recv_crb {
+       u32 crb_rcv_producer[NUM_RCV_DESC_RINGS];
+       u32 crb_sts_consumer[NUM_STS_DESC_RINGS];
+       u32 sw_int_mask[NUM_STS_DESC_RINGS];
+};
+
+/*    Following defines are for the state of the buffers    */
+#define        QLCNIC_BUFFER_FREE      0
+#define        QLCNIC_BUFFER_BUSY      1
+
+/*
+ * There will be one qlcnic_buffer per skb packet.    These will be
+ * used to save the dma info for pci_unmap_page()
+ */
+struct qlcnic_cmd_buffer {
+       struct sk_buff *skb;
+       struct qlcnic_skb_frag frag_array[MAX_BUFFERS_PER_CMD + 1];
+       u32 frag_count;
+};
+
+/* In rx_buffer, we do not need multiple fragments as is a single buffer */
+struct qlcnic_rx_buffer {
+       struct list_head list;
+       struct sk_buff *skb;
+       u64 dma;
+       u16 ref_handle;
+       u16 state;
+};
+
+/* Board types */
+#define        QLCNIC_GBE      0x01
+#define        QLCNIC_XGBE     0x02
+
+/*
+ * One hardware_context{} per adapter
+ * contains interrupt info as well shared hardware info.
+ */
+struct qlcnic_hardware_context {
+       void __iomem *pci_base0;
+       void __iomem *ocm_win_crb;
+
+       unsigned long pci_len0;
+
+       u32 ocm_win;
+       u32 crb_win;
+
+       rwlock_t crb_lock;
+       struct mutex mem_lock;
+
+       u8 cut_through;
+       u8 revision_id;
+       u8 pci_func;
+       u8 linkup;
+       u16 port_type;
+       u16 board_type;
+};
+
+struct qlcnic_adapter_stats {
+       u64  xmitcalled;
+       u64  xmitfinished;
+       u64  rxdropped;
+       u64  txdropped;
+       u64  csummed;
+       u64  rx_pkts;
+       u64  lro_pkts;
+       u64  rxbytes;
+       u64  txbytes;
+};
+
+/*
+ * Rcv Descriptor Context. One such per Rcv Descriptor. There may
+ * be one Rcv Descriptor for normal packets, one for jumbo and may be others.
+ */
+struct qlcnic_host_rds_ring {
+       u32 producer;
+       u32 num_desc;
+       u32 dma_size;
+       u32 skb_size;
+       u32 flags;
+       void __iomem *crb_rcv_producer;
+       struct rcv_desc *desc_head;
+       struct qlcnic_rx_buffer *rx_buf_arr;
+       struct list_head free_list;
+       spinlock_t lock;
+       dma_addr_t phys_addr;
+};
+
+struct qlcnic_host_sds_ring {
+       u32 consumer;
+       u32 num_desc;
+       void __iomem *crb_sts_consumer;
+       void __iomem *crb_intr_mask;
+
+       struct status_desc *desc_head;
+       struct qlcnic_adapter *adapter;
+       struct napi_struct napi;
+       struct list_head free_list[NUM_RCV_DESC_RINGS];
+
+       int irq;
+
+       dma_addr_t phys_addr;
+       char name[IFNAMSIZ+4];
+};
+
+struct qlcnic_host_tx_ring {
+       u32 producer;
+       __le32 *hw_consumer;
+       u32 sw_consumer;
+       void __iomem *crb_cmd_producer;
+       u32 num_desc;
+
+       struct netdev_queue *txq;
+
+       struct qlcnic_cmd_buffer *cmd_buf_arr;
+       struct cmd_desc_type0 *desc_head;
+       dma_addr_t phys_addr;
+       dma_addr_t hw_cons_phys_addr;
+};
+
+/*
+ * Receive context. There is one such structure per instance of the
+ * receive processing. Any state information that is relevant to
+ * the receive, and is must be in this structure. The global data may be
+ * present elsewhere.
+ */
+struct qlcnic_recv_context {
+       u32 state;
+       u16 context_id;
+       u16 virt_port;
+
+       struct qlcnic_host_rds_ring *rds_rings;
+       struct qlcnic_host_sds_ring *sds_rings;
+};
+
+/* HW context creation */
+
+#define QLCNIC_OS_CRB_RETRY_COUNT      4000
+#define QLCNIC_CDRP_SIGNATURE_MAKE(pcifn, version) \
+       (((pcifn) & 0xff) | (((version) & 0xff) << 8) | (0xcafe << 16))
+
+#define QLCNIC_CDRP_CMD_BIT            0x80000000
+
+/*
+ * All responses must have the QLCNIC_CDRP_CMD_BIT cleared
+ * in the crb QLCNIC_CDRP_CRB_OFFSET.
+ */
+#define QLCNIC_CDRP_FORM_RSP(rsp)      (rsp)
+#define QLCNIC_CDRP_IS_RSP(rsp)        (((rsp) & QLCNIC_CDRP_CMD_BIT) == 0)
+
+#define QLCNIC_CDRP_RSP_OK             0x00000001
+#define QLCNIC_CDRP_RSP_FAIL           0x00000002
+#define QLCNIC_CDRP_RSP_TIMEOUT        0x00000003
+
+/*
+ * All commands must have the QLCNIC_CDRP_CMD_BIT set in
+ * the crb QLCNIC_CDRP_CRB_OFFSET.
+ */
+#define QLCNIC_CDRP_FORM_CMD(cmd)      (QLCNIC_CDRP_CMD_BIT | (cmd))
+#define QLCNIC_CDRP_IS_CMD(cmd)        (((cmd) & QLCNIC_CDRP_CMD_BIT) != 0)
+
+#define QLCNIC_CDRP_CMD_SUBMIT_CAPABILITIES     0x00000001
+#define QLCNIC_CDRP_CMD_READ_MAX_RDS_PER_CTX    0x00000002
+#define QLCNIC_CDRP_CMD_READ_MAX_SDS_PER_CTX    0x00000003
+#define QLCNIC_CDRP_CMD_READ_MAX_RULES_PER_CTX  0x00000004
+#define QLCNIC_CDRP_CMD_READ_MAX_RX_CTX         0x00000005
+#define QLCNIC_CDRP_CMD_READ_MAX_TX_CTX         0x00000006
+#define QLCNIC_CDRP_CMD_CREATE_RX_CTX           0x00000007
+#define QLCNIC_CDRP_CMD_DESTROY_RX_CTX          0x00000008
+#define QLCNIC_CDRP_CMD_CREATE_TX_CTX           0x00000009
+#define QLCNIC_CDRP_CMD_DESTROY_TX_CTX          0x0000000a
+#define QLCNIC_CDRP_CMD_SETUP_STATISTICS        0x0000000e
+#define QLCNIC_CDRP_CMD_GET_STATISTICS          0x0000000f
+#define QLCNIC_CDRP_CMD_DELETE_STATISTICS       0x00000010
+#define QLCNIC_CDRP_CMD_SET_MTU                 0x00000012
+#define QLCNIC_CDRP_CMD_READ_PHY               0x00000013
+#define QLCNIC_CDRP_CMD_WRITE_PHY              0x00000014
+#define QLCNIC_CDRP_CMD_READ_HW_REG            0x00000015
+#define QLCNIC_CDRP_CMD_GET_FLOW_CTL           0x00000016
+#define QLCNIC_CDRP_CMD_SET_FLOW_CTL           0x00000017
+#define QLCNIC_CDRP_CMD_READ_MAX_MTU           0x00000018
+#define QLCNIC_CDRP_CMD_READ_MAX_LRO           0x00000019
+#define QLCNIC_CDRP_CMD_CONFIGURE_TOE          0x0000001a
+#define QLCNIC_CDRP_CMD_FUNC_ATTRIB            0x0000001b
+#define QLCNIC_CDRP_CMD_READ_PEXQ_PARAMETERS   0x0000001c
+#define QLCNIC_CDRP_CMD_GET_LIC_CAPABILITIES   0x0000001d
+#define QLCNIC_CDRP_CMD_READ_MAX_LRO_PER_BOARD 0x0000001e
+#define QLCNIC_CDRP_CMD_MAX                    0x0000001f
+
+#define QLCNIC_RCODE_SUCCESS           0
+#define QLCNIC_RCODE_TIMEOUT           17
+#define QLCNIC_DESTROY_CTX_RESET       0
+
+/*
+ * Capabilities Announced
+ */
+#define QLCNIC_CAP0_LEGACY_CONTEXT     (1)
+#define QLCNIC_CAP0_LEGACY_MN          (1 << 2)
+#define QLCNIC_CAP0_LSO                (1 << 6)
+#define QLCNIC_CAP0_JUMBO_CONTIGUOUS   (1 << 7)
+#define QLCNIC_CAP0_LRO_CONTIGUOUS     (1 << 8)
+
+/*
+ * Context state
+ */
+#define QLCHAL_VERSION 1
+
+#define QLCNIC_HOST_CTX_STATE_ACTIVE   2
+
+/*
+ * Rx context
+ */
+
+struct qlcnic_hostrq_sds_ring {
+       __le64 host_phys_addr;  /* Ring base addr */
+       __le32 ring_size;               /* Ring entries */
+       __le16 msi_index;
+       __le16 rsvd;            /* Padding */
+};
+
+struct qlcnic_hostrq_rds_ring {
+       __le64 host_phys_addr;  /* Ring base addr */
+       __le64 buff_size;               /* Packet buffer size */
+       __le32 ring_size;               /* Ring entries */
+       __le32 ring_kind;               /* Class of ring */
+};
+
+struct qlcnic_hostrq_rx_ctx {
+       __le64 host_rsp_dma_addr;       /* Response dma'd here */
+       __le32 capabilities[4]; /* Flag bit vector */
+       __le32 host_int_crb_mode;       /* Interrupt crb usage */
+       __le32 host_rds_crb_mode;       /* RDS crb usage */
+       /* These ring offsets are relative to data[0] below */
+       __le32 rds_ring_offset; /* Offset to RDS config */
+       __le32 sds_ring_offset; /* Offset to SDS config */
+       __le16 num_rds_rings;   /* Count of RDS rings */
+       __le16 num_sds_rings;   /* Count of SDS rings */
+       __le16 rsvd1;           /* Padding */
+       __le16 rsvd2;           /* Padding */
+       u8  reserved[128];      /* reserve space for future expansion*/
+       /* MUST BE 64-bit aligned.
+          The following is packed:
+          - N hostrq_rds_rings
+          - N hostrq_sds_rings */
+       char data[0];
+};
+
+struct qlcnic_cardrsp_rds_ring{
+       __le32 host_producer_crb;       /* Crb to use */
+       __le32 rsvd1;           /* Padding */
+};
+
+struct qlcnic_cardrsp_sds_ring {
+       __le32 host_consumer_crb;       /* Crb to use */
+       __le32 interrupt_crb;   /* Crb to use */
+};
+
+struct qlcnic_cardrsp_rx_ctx {
+       /* These ring offsets are relative to data[0] below */
+       __le32 rds_ring_offset; /* Offset to RDS config */
+       __le32 sds_ring_offset; /* Offset to SDS config */
+       __le32 host_ctx_state;  /* Starting State */
+       __le32 num_fn_per_port; /* How many PCI fn share the port */
+       __le16 num_rds_rings;   /* Count of RDS rings */
+       __le16 num_sds_rings;   /* Count of SDS rings */
+       __le16 context_id;              /* Handle for context */
+       u8  phys_port;          /* Physical id of port */
+       u8  virt_port;          /* Virtual/Logical id of port */
+       u8  reserved[128];      /* save space for future expansion */
+       /*  MUST BE 64-bit aligned.
+          The following is packed:
+          - N cardrsp_rds_rings
+          - N cardrs_sds_rings */
+       char data[0];
+};
+
+#define SIZEOF_HOSTRQ_RX(HOSTRQ_RX, rds_rings, sds_rings)      \
+       (sizeof(HOSTRQ_RX) +                                    \
+       (rds_rings)*(sizeof(struct qlcnic_hostrq_rds_ring)) +           \
+       (sds_rings)*(sizeof(struct qlcnic_hostrq_sds_ring)))
+
+#define SIZEOF_CARDRSP_RX(CARDRSP_RX, rds_rings, sds_rings)    \
+       (sizeof(CARDRSP_RX) +                                   \
+       (rds_rings)*(sizeof(struct qlcnic_cardrsp_rds_ring)) +          \
+       (sds_rings)*(sizeof(struct qlcnic_cardrsp_sds_ring)))
+
+/*
+ * Tx context
+ */
+
+struct qlcnic_hostrq_cds_ring {
+       __le64 host_phys_addr;  /* Ring base addr */
+       __le32 ring_size;               /* Ring entries */
+       __le32 rsvd;            /* Padding */
+};
+
+struct qlcnic_hostrq_tx_ctx {
+       __le64 host_rsp_dma_addr;       /* Response dma'd here */
+       __le64 cmd_cons_dma_addr;       /*  */
+       __le64 dummy_dma_addr;  /*  */
+       __le32 capabilities[4]; /* Flag bit vector */
+       __le32 host_int_crb_mode;       /* Interrupt crb usage */
+       __le32 rsvd1;           /* Padding */
+       __le16 rsvd2;           /* Padding */
+       __le16 interrupt_ctl;
+       __le16 msi_index;
+       __le16 rsvd3;           /* Padding */
+       struct qlcnic_hostrq_cds_ring cds_ring; /* Desc of cds ring */
+       u8  reserved[128];      /* future expansion */
+};
+
+struct qlcnic_cardrsp_cds_ring {
+       __le32 host_producer_crb;       /* Crb to use */
+       __le32 interrupt_crb;   /* Crb to use */
+};
+
+struct qlcnic_cardrsp_tx_ctx {
+       __le32 host_ctx_state;  /* Starting state */
+       __le16 context_id;              /* Handle for context */
+       u8  phys_port;          /* Physical id of port */
+       u8  virt_port;          /* Virtual/Logical id of port */
+       struct qlcnic_cardrsp_cds_ring cds_ring;        /* Card cds settings */
+       u8  reserved[128];      /* future expansion */
+};
+
+#define SIZEOF_HOSTRQ_TX(HOSTRQ_TX)    (sizeof(HOSTRQ_TX))
+#define SIZEOF_CARDRSP_TX(CARDRSP_TX)  (sizeof(CARDRSP_TX))
+
+/* CRB */
+
+#define QLCNIC_HOST_RDS_CRB_MODE_UNIQUE        0
+#define QLCNIC_HOST_RDS_CRB_MODE_SHARED        1
+#define QLCNIC_HOST_RDS_CRB_MODE_CUSTOM        2
+#define QLCNIC_HOST_RDS_CRB_MODE_MAX   3
+
+#define QLCNIC_HOST_INT_CRB_MODE_UNIQUE        0
+#define QLCNIC_HOST_INT_CRB_MODE_SHARED        1
+#define QLCNIC_HOST_INT_CRB_MODE_NORX  2
+#define QLCNIC_HOST_INT_CRB_MODE_NOTX  3
+#define QLCNIC_HOST_INT_CRB_MODE_NORXTX        4
+
+
+/* MAC */
+
+#define MC_COUNT_P3    38
+
+#define QLCNIC_MAC_NOOP        0
+#define QLCNIC_MAC_ADD 1
+#define QLCNIC_MAC_DEL 2
+
+struct qlcnic_mac_list_s {
+       struct list_head list;
+       uint8_t mac_addr[ETH_ALEN+2];
+};
+
+/*
+ * Interrupt coalescing defaults. The defaults are for 1500 MTU. It is
+ * adjusted based on configured MTU.
+ */
+#define QLCNIC_DEFAULT_INTR_COALESCE_RX_TIME_US        3
+#define QLCNIC_DEFAULT_INTR_COALESCE_RX_PACKETS        256
+#define QLCNIC_DEFAULT_INTR_COALESCE_TX_PACKETS        64
+#define QLCNIC_DEFAULT_INTR_COALESCE_TX_TIME_US        4
+
+#define QLCNIC_INTR_DEFAULT                    0x04
+
+union qlcnic_nic_intr_coalesce_data {
+       struct {
+               u16     rx_packets;
+               u16     rx_time_us;
+               u16     tx_packets;
+               u16     tx_time_us;
+       } data;
+       u64             word;
+};
+
+struct qlcnic_nic_intr_coalesce {
+       u16             stats_time_us;
+       u16             rate_sample_time;
+       u16             flags;
+       u16             rsvd_1;
+       u32             low_threshold;
+       u32             high_threshold;
+       union qlcnic_nic_intr_coalesce_data     normal;
+       union qlcnic_nic_intr_coalesce_data     low;
+       union qlcnic_nic_intr_coalesce_data     high;
+       union qlcnic_nic_intr_coalesce_data     irq;
+};
+
+#define QLCNIC_HOST_REQUEST    0x13
+#define QLCNIC_REQUEST         0x14
+
+#define QLCNIC_MAC_EVENT       0x1
+
+#define QLCNIC_IP_UP           2
+#define QLCNIC_IP_DOWN         3
+
+/*
+ * Driver --> Firmware
+ */
+#define QLCNIC_H2C_OPCODE_START                        0
+#define QLCNIC_H2C_OPCODE_CONFIG_RSS                   1
+#define QLCNIC_H2C_OPCODE_CONFIG_RSS_TBL               2
+#define QLCNIC_H2C_OPCODE_CONFIG_INTR_COALESCE         3
+#define QLCNIC_H2C_OPCODE_CONFIG_LED                   4
+#define QLCNIC_H2C_OPCODE_CONFIG_PROMISCUOUS           5
+#define QLCNIC_H2C_OPCODE_CONFIG_L2_MAC                6
+#define QLCNIC_H2C_OPCODE_LRO_REQUEST                  7
+#define QLCNIC_H2C_OPCODE_GET_SNMP_STATS               8
+#define QLCNIC_H2C_OPCODE_PROXY_START_REQUEST          9
+#define QLCNIC_H2C_OPCODE_PROXY_STOP_REQUEST           10
+#define QLCNIC_H2C_OPCODE_PROXY_SET_MTU                11
+#define QLCNIC_H2C_OPCODE_PROXY_SET_VPORT_MISS_MODE    12
+#define QLCNIC_H2C_OPCODE_GET_FINGER_PRINT_REQUEST     13
+#define QLCNIC_H2C_OPCODE_INSTALL_LICENSE_REQUEST      14
+#define QLCNIC_H2C_OPCODE_GET_LICENSE_CAPABILITY_REQUEST       15
+#define QLCNIC_H2C_OPCODE_GET_NET_STATS                16
+#define QLCNIC_H2C_OPCODE_PROXY_UPDATE_P2V             17
+#define QLCNIC_H2C_OPCODE_CONFIG_IPADDR                18
+#define QLCNIC_H2C_OPCODE_CONFIG_LOOPBACK              19
+#define QLCNIC_H2C_OPCODE_PROXY_STOP_DONE              20
+#define QLCNIC_H2C_OPCODE_GET_LINKEVENT                21
+#define QLCNIC_C2C_OPCODE                              22
+#define QLCNIC_H2C_OPCODE_CONFIG_BRIDGING              23
+#define QLCNIC_H2C_OPCODE_CONFIG_HW_LRO                24
+#define QLCNIC_H2C_OPCODE_LAST                         25
+/*
+ * Firmware --> Driver
+ */
+
+#define QLCNIC_C2H_OPCODE_START                        128
+#define QLCNIC_C2H_OPCODE_CONFIG_RSS_RESPONSE          129
+#define QLCNIC_C2H_OPCODE_CONFIG_RSS_TBL_RESPONSE      130
+#define QLCNIC_C2H_OPCODE_CONFIG_MAC_RESPONSE          131
+#define QLCNIC_C2H_OPCODE_CONFIG_PROMISCUOUS_RESPONSE  132
+#define QLCNIC_C2H_OPCODE_CONFIG_L2_MAC_RESPONSE       133
+#define QLCNIC_C2H_OPCODE_LRO_DELETE_RESPONSE          134
+#define QLCNIC_C2H_OPCODE_LRO_ADD_FAILURE_RESPONSE     135
+#define QLCNIC_C2H_OPCODE_GET_SNMP_STATS               136
+#define QLCNIC_C2H_OPCODE_GET_FINGER_PRINT_REPLY       137
+#define QLCNIC_C2H_OPCODE_INSTALL_LICENSE_REPLY        138
+#define QLCNIC_C2H_OPCODE_GET_LICENSE_CAPABILITIES_REPLY 139
+#define QLCNIC_C2H_OPCODE_GET_NET_STATS_RESPONSE       140
+#define QLCNIC_C2H_OPCODE_GET_LINKEVENT_RESPONSE       141
+#define QLCNIC_C2H_OPCODE_LAST                         142
+
+#define VPORT_MISS_MODE_DROP           0 /* drop all unmatched */
+#define VPORT_MISS_MODE_ACCEPT_ALL     1 /* accept all packets */
+#define VPORT_MISS_MODE_ACCEPT_MULTI   2 /* accept unmatched multicast */
+
+#define QLCNIC_LRO_REQUEST_CLEANUP     4
+
+/* Capabilites received */
+#define QLCNIC_FW_CAPABILITY_BDG               (1 << 8)
+#define QLCNIC_FW_CAPABILITY_FVLANTX           (1 << 9)
+#define QLCNIC_FW_CAPABILITY_HW_LRO            (1 << 10)
+
+/* module types */
+#define LINKEVENT_MODULE_NOT_PRESENT                   1
+#define LINKEVENT_MODULE_OPTICAL_UNKNOWN               2
+#define LINKEVENT_MODULE_OPTICAL_SRLR                  3
+#define LINKEVENT_MODULE_OPTICAL_LRM                   4
+#define LINKEVENT_MODULE_OPTICAL_SFP_1G                5
+#define LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLE      6
+#define LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLELEN   7
+#define LINKEVENT_MODULE_TWINAX                        8
+
+#define LINKSPEED_10GBPS       10000
+#define LINKSPEED_1GBPS        1000
+#define LINKSPEED_100MBPS      100
+#define LINKSPEED_10MBPS       10
+
+#define LINKSPEED_ENCODED_10MBPS       0
+#define LINKSPEED_ENCODED_100MBPS      1
+#define LINKSPEED_ENCODED_1GBPS        2
+
+#define LINKEVENT_AUTONEG_DISABLED     0
+#define LINKEVENT_AUTONEG_ENABLED      1
+
+#define LINKEVENT_HALF_DUPLEX          0
+#define LINKEVENT_FULL_DUPLEX          1
+
+#define LINKEVENT_LINKSPEED_MBPS       0
+#define LINKEVENT_LINKSPEED_ENCODED    1
+
+#define AUTO_FW_RESET_ENABLED  0x01
+/* firmware response header:
+ *     63:58 - message type
+ *     57:56 - owner
+ *     55:53 - desc count
+ *     52:48 - reserved
+ *     47:40 - completion id
+ *     39:32 - opcode
+ *     31:16 - error code
+ *     15:00 - reserved
+ */
+#define qlcnic_get_nic_msg_opcode(msg_hdr)     \
+       ((msg_hdr >> 32) & 0xFF)
+
+struct qlcnic_fw_msg {
+       union {
+               struct {
+                       u64 hdr;
+                       u64 body[7];
+               };
+               u64 words[8];
+       };
+};
+
+struct qlcnic_nic_req {
+       __le64 qhdr;
+       __le64 req_hdr;
+       __le64 words[6];
+};
+
+struct qlcnic_mac_req {
+       u8 op;
+       u8 tag;
+       u8 mac_addr[6];
+};
+
+#define QLCNIC_MSI_ENABLED             0x02
+#define QLCNIC_MSIX_ENABLED            0x04
+#define QLCNIC_LRO_ENABLED             0x08
+#define QLCNIC_BRIDGE_ENABLED          0X10
+#define QLCNIC_DIAG_ENABLED            0x20
+#define QLCNIC_IS_MSI_FAMILY(adapter) \
+       ((adapter)->flags & (QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED))
+
+#define MSIX_ENTRIES_PER_ADAPTER       NUM_STS_DESC_RINGS
+#define QLCNIC_MSIX_TBL_SPACE          8192
+#define QLCNIC_PCI_REG_MSIX_TBL        0x44
+
+#define QLCNIC_NETDEV_WEIGHT   128
+#define QLCNIC_ADAPTER_UP_MAGIC 777
+
+#define __QLCNIC_FW_ATTACHED           0
+#define __QLCNIC_DEV_UP                1
+#define __QLCNIC_RESETTING             2
+#define __QLCNIC_START_FW              4
+
+#define QLCNIC_INTERRUPT_TEST          1
+#define QLCNIC_LOOPBACK_TEST           2
+
+struct qlcnic_adapter {
+       struct qlcnic_hardware_context ahw;
+
+       struct net_device *netdev;
+       struct pci_dev *pdev;
+       struct list_head mac_list;
+
+       spinlock_t tx_clean_lock;
+
+       u16 num_txd;
+       u16 num_rxd;
+       u16 num_jumbo_rxd;
+       u16 num_lro_rxd;
+
+       u8 max_rds_rings;
+       u8 max_sds_rings;
+       u8 driver_mismatch;
+       u8 msix_supported;
+       u8 rx_csum;
+       u8 pci_using_dac;
+       u8 portnum;
+       u8 physical_port;
+
+       u8 mc_enabled;
+       u8 max_mc_count;
+       u8 rss_supported;
+       u8 rsrvd1;
+       u8 fw_wait_cnt;
+       u8 fw_fail_cnt;
+       u8 tx_timeo_cnt;
+       u8 need_fw_reset;
+
+       u8 has_link_events;
+       u8 fw_type;
+       u16 tx_context_id;
+       u16 mtu;
+       u16 is_up;
+
+       u16 link_speed;
+       u16 link_duplex;
+       u16 link_autoneg;
+       u16 module_type;
+
+       u32 capabilities;
+       u32 flags;
+       u32 irq;
+       u32 temp;
+
+       u32 int_vec_bit;
+       u32 heartbit;
+
+       u8 dev_state;
+       u8 diag_test;
+       u8 diag_cnt;
+       u8 rsrd1;
+       u16 rsrd2;
+
+       u8 mac_addr[ETH_ALEN];
+
+       struct qlcnic_adapter_stats stats;
+
+       struct qlcnic_recv_context recv_ctx;
+       struct qlcnic_host_tx_ring *tx_ring;
+
+       void __iomem    *tgt_mask_reg;
+       void __iomem    *tgt_status_reg;
+       void __iomem    *crb_int_state_reg;
+       void __iomem    *isr_int_vec;
+
+       struct msix_entry msix_entries[MSIX_ENTRIES_PER_ADAPTER];
+
+       struct delayed_work fw_work;
+
+       struct work_struct  tx_timeout_task;
+
+       struct qlcnic_nic_intr_coalesce coal;
+
+       unsigned long state;
+       __le32 file_prd_off;    /*File fw product offset*/
+       u32 fw_version;
+       const struct firmware *fw;
+};
+
+int qlcnic_fw_cmd_query_phy(struct qlcnic_adapter *adapter, u32 reg, u32 *val);
+int qlcnic_fw_cmd_set_phy(struct qlcnic_adapter *adapter, u32 reg, u32 val);
+
+u32 qlcnic_hw_read_wx_2M(struct qlcnic_adapter *adapter, ulong off);
+int qlcnic_hw_write_wx_2M(struct qlcnic_adapter *, ulong off, u32 data);
+int qlcnic_pci_mem_write_2M(struct qlcnic_adapter *, u64 off, u64 data);
+int qlcnic_pci_mem_read_2M(struct qlcnic_adapter *, u64 off, u64 *data);
+
+#define QLCRD32(adapter, off) \
+       (qlcnic_hw_read_wx_2M(adapter, off))
+#define QLCWR32(adapter, off, val) \
+       (qlcnic_hw_write_wx_2M(adapter, off, val))
+
+int qlcnic_pcie_sem_lock(struct qlcnic_adapter *, int, u32);
+void qlcnic_pcie_sem_unlock(struct qlcnic_adapter *, int);
+
+#define qlcnic_rom_lock(a)     \
+       qlcnic_pcie_sem_lock((a), 2, QLCNIC_ROM_LOCK_ID)
+#define qlcnic_rom_unlock(a)   \
+       qlcnic_pcie_sem_unlock((a), 2)
+#define qlcnic_phy_lock(a)     \
+       qlcnic_pcie_sem_lock((a), 3, QLCNIC_PHY_LOCK_ID)
+#define qlcnic_phy_unlock(a)   \
+       qlcnic_pcie_sem_unlock((a), 3)
+#define qlcnic_api_lock(a)     \
+       qlcnic_pcie_sem_lock((a), 5, 0)
+#define qlcnic_api_unlock(a)   \
+       qlcnic_pcie_sem_unlock((a), 5)
+#define qlcnic_sw_lock(a)      \
+       qlcnic_pcie_sem_lock((a), 6, 0)
+#define qlcnic_sw_unlock(a)    \
+       qlcnic_pcie_sem_unlock((a), 6)
+#define crb_win_lock(a)        \
+       qlcnic_pcie_sem_lock((a), 7, QLCNIC_CRB_WIN_LOCK_ID)
+#define crb_win_unlock(a)      \
+       qlcnic_pcie_sem_unlock((a), 7)
+
+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);
+
+/* Functions from qlcnic_init.c */
+int qlcnic_phantom_init(struct qlcnic_adapter *adapter);
+int qlcnic_load_firmware(struct qlcnic_adapter *adapter);
+int qlcnic_need_fw_reset(struct qlcnic_adapter *adapter);
+void qlcnic_request_firmware(struct qlcnic_adapter *adapter);
+void qlcnic_release_firmware(struct qlcnic_adapter *adapter);
+int qlcnic_pinit_from_rom(struct qlcnic_adapter *adapter);
+
+int qlcnic_rom_fast_read(struct qlcnic_adapter *adapter, int addr, int *valp);
+int qlcnic_rom_fast_read_words(struct qlcnic_adapter *adapter, int addr,
+                               u8 *bytes, size_t size);
+int qlcnic_alloc_sw_resources(struct qlcnic_adapter *adapter);
+void qlcnic_free_sw_resources(struct qlcnic_adapter *adapter);
+
+void __iomem *qlcnic_get_ioaddr(struct qlcnic_adapter *, u32);
+
+int qlcnic_alloc_hw_resources(struct qlcnic_adapter *adapter);
+void qlcnic_free_hw_resources(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);
+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);
+int qlcnic_process_rcv_ring(struct qlcnic_host_sds_ring *sds_ring, int max);
+void qlcnic_set_multi(struct net_device *netdev);
+void qlcnic_free_mac_list(struct qlcnic_adapter *adapter);
+int qlcnic_nic_set_promisc(struct qlcnic_adapter *adapter, u32);
+int qlcnic_config_intr_coalesce(struct qlcnic_adapter *adapter);
+int qlcnic_config_rss(struct qlcnic_adapter *adapter, int enable);
+int qlcnic_config_ipaddr(struct qlcnic_adapter *adapter, u32 ip, int cmd);
+int qlcnic_linkevent_request(struct qlcnic_adapter *adapter, int enable);
+void qlcnic_advert_link_change(struct qlcnic_adapter *adapter, int linkup);
+
+int qlcnic_fw_cmd_set_mtu(struct qlcnic_adapter *adapter, int mtu);
+int qlcnic_change_mtu(struct net_device *netdev, int new_mtu);
+int qlcnic_config_hw_lro(struct qlcnic_adapter *adapter, int enable);
+int qlcnic_config_bridged_mode(struct qlcnic_adapter *adapter, int 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, u64 *mac);
+void qlcnic_clear_ilb_mode(struct qlcnic_adapter *adapter);
+int qlcnic_set_ilb_mode(struct qlcnic_adapter *adapter);
+
+/* Functions from qlcnic_main.c */
+int qlcnic_reset_context(struct qlcnic_adapter *);
+u32 qlcnic_issue_cmd(struct qlcnic_adapter *adapter,
+       u32 pci_fn, u32 version, u32 arg1, u32 arg2, u32 arg3, u32 cmd);
+void qlcnic_diag_free_res(struct net_device *netdev, int max_sds_rings);
+int qlcnic_diag_alloc_res(struct net_device *netdev, int test);
+int qlcnic_check_loopback_buff(unsigned char *data);
+netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev);
+void qlcnic_process_rcv_ring_diag(struct qlcnic_host_sds_ring *sds_ring);
+
+/*
+ * QLOGIC Board information
+ */
+
+#define QLCNIC_MAX_BOARD_NAME_LEN 100
+struct qlcnic_brdinfo {
+       unsigned short  vendor;
+       unsigned short  device;
+       unsigned short  sub_vendor;
+       unsigned short  sub_device;
+       char short_name[QLCNIC_MAX_BOARD_NAME_LEN];
+};
+
+static const struct qlcnic_brdinfo qlcnic_boards[] = {
+       {0x1077, 0x8020, 0x1077, 0x203,
+               "8200 Series Single Port 10GbE Converged Network Adapter \
+               (TCP/IP Networking)"},
+       {0x1077, 0x8020, 0x1077, 0x207,
+               "8200 Series Dual Port 10GbE Converged Network Adapter \
+               (TCP/IP Networking)"},
+       {0x1077, 0x8020, 0x1077, 0x20b,
+               "3200 Series Dual Port 10Gb Intelligent Ethernet Adapter"},
+       {0x1077, 0x8020, 0x1077, 0x20c,
+               "3200 Series Quad Port 1Gb Intelligent Ethernet Adapter"},
+       {0x1077, 0x8020, 0x1077, 0x20f,
+               "3200 Series Single Port 10Gb Intelligent Ethernet Adapter"},
+       {0x1077, 0x8020, 0x0, 0x0, "cLOM8214 1/10GbE Controller"},
+};
+
+#define NUM_SUPPORTED_BOARDS ARRAY_SIZE(qlcnic_boards)
+
+static inline u32 qlcnic_tx_avail(struct qlcnic_host_tx_ring *tx_ring)
+{
+       smp_mb();
+       if (tx_ring->producer < tx_ring->sw_consumer)
+               return tx_ring->sw_consumer - tx_ring->producer;
+       else
+               return tx_ring->sw_consumer + tx_ring->num_desc -
+                               tx_ring->producer;
+}
+
+extern const struct ethtool_ops qlcnic_ethtool_ops;
+
+#endif                         /* __QLCNIC_H_ */
diff --git a/drivers/net/qlcnic/qlcnic_ctx.c b/drivers/net/qlcnic/qlcnic_ctx.c
new file mode 100644 (file)
index 0000000..0a6a399
--- /dev/null
@@ -0,0 +1,534 @@
+/*
+ * Copyright (C) 2009 - QLogic Corporation.
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called "COPYING".
+ *
+ */
+
+#include "qlcnic.h"
+
+static u32
+qlcnic_poll_rsp(struct qlcnic_adapter *adapter)
+{
+       u32 rsp;
+       int timeout = 0;
+
+       do {
+               /* give atleast 1ms for firmware to respond */
+               msleep(1);
+
+               if (++timeout > QLCNIC_OS_CRB_RETRY_COUNT)
+                       return QLCNIC_CDRP_RSP_TIMEOUT;
+
+               rsp = QLCRD32(adapter, QLCNIC_CDRP_CRB_OFFSET);
+       } while (!QLCNIC_CDRP_IS_RSP(rsp));
+
+       return rsp;
+}
+
+u32
+qlcnic_issue_cmd(struct qlcnic_adapter *adapter,
+       u32 pci_fn, u32 version, u32 arg1, u32 arg2, u32 arg3, u32 cmd)
+{
+       u32 rsp;
+       u32 signature;
+       u32 rcode = QLCNIC_RCODE_SUCCESS;
+       struct pci_dev *pdev = adapter->pdev;
+
+       signature = QLCNIC_CDRP_SIGNATURE_MAKE(pci_fn, version);
+
+       /* Acquire semaphore before accessing CRB */
+       if (qlcnic_api_lock(adapter))
+               return QLCNIC_RCODE_TIMEOUT;
+
+       QLCWR32(adapter, QLCNIC_SIGN_CRB_OFFSET, signature);
+       QLCWR32(adapter, QLCNIC_ARG1_CRB_OFFSET, arg1);
+       QLCWR32(adapter, QLCNIC_ARG2_CRB_OFFSET, arg2);
+       QLCWR32(adapter, QLCNIC_ARG3_CRB_OFFSET, arg3);
+       QLCWR32(adapter, QLCNIC_CDRP_CRB_OFFSET, QLCNIC_CDRP_FORM_CMD(cmd));
+
+       rsp = qlcnic_poll_rsp(adapter);
+
+       if (rsp == QLCNIC_CDRP_RSP_TIMEOUT) {
+               dev_err(&pdev->dev, "card response timeout.\n");
+               rcode = QLCNIC_RCODE_TIMEOUT;
+       } else if (rsp == QLCNIC_CDRP_RSP_FAIL) {
+               rcode = QLCRD32(adapter, QLCNIC_ARG1_CRB_OFFSET);
+               dev_err(&pdev->dev, "failed card response code:0x%x\n",
+                               rcode);
+       }
+
+       /* Release semaphore */
+       qlcnic_api_unlock(adapter);
+
+       return rcode;
+}
+
+int
+qlcnic_fw_cmd_set_mtu(struct qlcnic_adapter *adapter, int mtu)
+{
+       struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
+
+       if (recv_ctx->state == QLCNIC_HOST_CTX_STATE_ACTIVE) {
+               if (qlcnic_issue_cmd(adapter,
+                               adapter->ahw.pci_func,
+                               QLCHAL_VERSION,
+                               recv_ctx->context_id,
+                               mtu,
+                               0,
+                               QLCNIC_CDRP_CMD_SET_MTU)) {
+
+                       dev_err(&adapter->pdev->dev, "Failed to set mtu\n");
+                       return -EIO;
+               }
+       }
+
+       return 0;
+}
+
+static int
+qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter)
+{
+       void *addr;
+       struct qlcnic_hostrq_rx_ctx *prq;
+       struct qlcnic_cardrsp_rx_ctx *prsp;
+       struct qlcnic_hostrq_rds_ring *prq_rds;
+       struct qlcnic_hostrq_sds_ring *prq_sds;
+       struct qlcnic_cardrsp_rds_ring *prsp_rds;
+       struct qlcnic_cardrsp_sds_ring *prsp_sds;
+       struct qlcnic_host_rds_ring *rds_ring;
+       struct qlcnic_host_sds_ring *sds_ring;
+
+       dma_addr_t hostrq_phys_addr, cardrsp_phys_addr;
+       u64 phys_addr;
+
+       int i, nrds_rings, nsds_rings;
+       size_t rq_size, rsp_size;
+       u32 cap, reg, val;
+       int err;
+
+       struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
+
+       nrds_rings = adapter->max_rds_rings;
+       nsds_rings = adapter->max_sds_rings;
+
+       rq_size =
+               SIZEOF_HOSTRQ_RX(struct qlcnic_hostrq_rx_ctx, nrds_rings,
+                                               nsds_rings);
+       rsp_size =
+               SIZEOF_CARDRSP_RX(struct qlcnic_cardrsp_rx_ctx, nrds_rings,
+                                               nsds_rings);
+
+       addr = pci_alloc_consistent(adapter->pdev,
+                               rq_size, &hostrq_phys_addr);
+       if (addr == NULL)
+               return -ENOMEM;
+       prq = (struct qlcnic_hostrq_rx_ctx *)addr;
+
+       addr = pci_alloc_consistent(adapter->pdev,
+                       rsp_size, &cardrsp_phys_addr);
+       if (addr == NULL) {
+               err = -ENOMEM;
+               goto out_free_rq;
+       }
+       prsp = (struct qlcnic_cardrsp_rx_ctx *)addr;
+
+       prq->host_rsp_dma_addr = cpu_to_le64(cardrsp_phys_addr);
+
+       cap = (QLCNIC_CAP0_LEGACY_CONTEXT | QLCNIC_CAP0_LEGACY_MN);
+       cap |= (QLCNIC_CAP0_JUMBO_CONTIGUOUS | QLCNIC_CAP0_LRO_CONTIGUOUS);
+
+       prq->capabilities[0] = cpu_to_le32(cap);
+       prq->host_int_crb_mode =
+               cpu_to_le32(QLCNIC_HOST_INT_CRB_MODE_SHARED);
+       prq->host_rds_crb_mode =
+               cpu_to_le32(QLCNIC_HOST_RDS_CRB_MODE_UNIQUE);
+
+       prq->num_rds_rings = cpu_to_le16(nrds_rings);
+       prq->num_sds_rings = cpu_to_le16(nsds_rings);
+       prq->rds_ring_offset = cpu_to_le32(0);
+
+       val = le32_to_cpu(prq->rds_ring_offset) +
+               (sizeof(struct qlcnic_hostrq_rds_ring) * nrds_rings);
+       prq->sds_ring_offset = cpu_to_le32(val);
+
+       prq_rds = (struct qlcnic_hostrq_rds_ring *)(prq->data +
+                       le32_to_cpu(prq->rds_ring_offset));
+
+       for (i = 0; i < nrds_rings; i++) {
+
+               rds_ring = &recv_ctx->rds_rings[i];
+
+               prq_rds[i].host_phys_addr = cpu_to_le64(rds_ring->phys_addr);
+               prq_rds[i].ring_size = cpu_to_le32(rds_ring->num_desc);
+               prq_rds[i].ring_kind = cpu_to_le32(i);
+               prq_rds[i].buff_size = cpu_to_le64(rds_ring->dma_size);
+       }
+
+       prq_sds = (struct qlcnic_hostrq_sds_ring *)(prq->data +
+                       le32_to_cpu(prq->sds_ring_offset));
+
+       for (i = 0; i < nsds_rings; i++) {
+
+               sds_ring = &recv_ctx->sds_rings[i];
+
+               prq_sds[i].host_phys_addr = cpu_to_le64(sds_ring->phys_addr);
+               prq_sds[i].ring_size = cpu_to_le32(sds_ring->num_desc);
+               prq_sds[i].msi_index = cpu_to_le16(i);
+       }
+
+       phys_addr = hostrq_phys_addr;
+       err = qlcnic_issue_cmd(adapter,
+                       adapter->ahw.pci_func,
+                       QLCHAL_VERSION,
+                       (u32)(phys_addr >> 32),
+                       (u32)(phys_addr & 0xffffffff),
+                       rq_size,
+                       QLCNIC_CDRP_CMD_CREATE_RX_CTX);
+       if (err) {
+               dev_err(&adapter->pdev->dev,
+                       "Failed to create rx ctx in firmware%d\n", err);
+               goto out_free_rsp;
+       }
+
+
+       prsp_rds = ((struct qlcnic_cardrsp_rds_ring *)
+                        &prsp->data[le32_to_cpu(prsp->rds_ring_offset)]);
+
+       for (i = 0; i < le16_to_cpu(prsp->num_rds_rings); i++) {
+               rds_ring = &recv_ctx->rds_rings[i];
+
+               reg = le32_to_cpu(prsp_rds[i].host_producer_crb);
+               rds_ring->crb_rcv_producer = qlcnic_get_ioaddr(adapter,
+                               QLCNIC_REG(reg - 0x200));
+       }
+
+       prsp_sds = ((struct qlcnic_cardrsp_sds_ring *)
+                       &prsp->data[le32_to_cpu(prsp->sds_ring_offset)]);
+
+       for (i = 0; i < le16_to_cpu(prsp->num_sds_rings); i++) {
+               sds_ring = &recv_ctx->sds_rings[i];
+
+               reg = le32_to_cpu(prsp_sds[i].host_consumer_crb);
+               sds_ring->crb_sts_consumer = qlcnic_get_ioaddr(adapter,
+                               QLCNIC_REG(reg - 0x200));
+
+               reg = le32_to_cpu(prsp_sds[i].interrupt_crb);
+               sds_ring->crb_intr_mask = qlcnic_get_ioaddr(adapter,
+                               QLCNIC_REG(reg - 0x200));
+       }
+
+       recv_ctx->state = le32_to_cpu(prsp->host_ctx_state);
+       recv_ctx->context_id = le16_to_cpu(prsp->context_id);
+       recv_ctx->virt_port = prsp->virt_port;
+
+out_free_rsp:
+       pci_free_consistent(adapter->pdev, rsp_size, prsp, cardrsp_phys_addr);
+out_free_rq:
+       pci_free_consistent(adapter->pdev, rq_size, prq, hostrq_phys_addr);
+       return err;
+}
+
+static void
+qlcnic_fw_cmd_destroy_rx_ctx(struct qlcnic_adapter *adapter)
+{
+       struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
+
+       if (qlcnic_issue_cmd(adapter,
+                       adapter->ahw.pci_func,
+                       QLCHAL_VERSION,
+                       recv_ctx->context_id,
+                       QLCNIC_DESTROY_CTX_RESET,
+                       0,
+                       QLCNIC_CDRP_CMD_DESTROY_RX_CTX)) {
+
+               dev_err(&adapter->pdev->dev,
+                       "Failed to destroy rx ctx in firmware\n");
+       }
+}
+
+static int
+qlcnic_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter)
+{
+       struct qlcnic_hostrq_tx_ctx     *prq;
+       struct qlcnic_hostrq_cds_ring   *prq_cds;
+       struct qlcnic_cardrsp_tx_ctx    *prsp;
+       void    *rq_addr, *rsp_addr;
+       size_t  rq_size, rsp_size;
+       u32     temp;
+       int     err;
+       u64     phys_addr;
+       dma_addr_t      rq_phys_addr, rsp_phys_addr;
+       struct qlcnic_host_tx_ring *tx_ring = adapter->tx_ring;
+
+       rq_size = SIZEOF_HOSTRQ_TX(struct qlcnic_hostrq_tx_ctx);
+       rq_addr = pci_alloc_consistent(adapter->pdev,
+               rq_size, &rq_phys_addr);
+       if (!rq_addr)
+               return -ENOMEM;
+
+       rsp_size = SIZEOF_CARDRSP_TX(struct qlcnic_cardrsp_tx_ctx);
+       rsp_addr = pci_alloc_consistent(adapter->pdev,
+               rsp_size, &rsp_phys_addr);
+       if (!rsp_addr) {
+               err = -ENOMEM;
+               goto out_free_rq;
+       }
+
+       memset(rq_addr, 0, rq_size);
+       prq = (struct qlcnic_hostrq_tx_ctx *)rq_addr;
+
+       memset(rsp_addr, 0, rsp_size);
+       prsp = (struct qlcnic_cardrsp_tx_ctx *)rsp_addr;
+
+       prq->host_rsp_dma_addr = cpu_to_le64(rsp_phys_addr);
+
+       temp = (QLCNIC_CAP0_LEGACY_CONTEXT | QLCNIC_CAP0_LEGACY_MN |
+                                       QLCNIC_CAP0_LSO);
+       prq->capabilities[0] = cpu_to_le32(temp);
+
+       prq->host_int_crb_mode =
+               cpu_to_le32(QLCNIC_HOST_INT_CRB_MODE_SHARED);
+
+       prq->interrupt_ctl = 0;
+       prq->msi_index = 0;
+       prq->cmd_cons_dma_addr = cpu_to_le64(tx_ring->hw_cons_phys_addr);
+
+       prq_cds = &prq->cds_ring;
+
+       prq_cds->host_phys_addr = cpu_to_le64(tx_ring->phys_addr);
+       prq_cds->ring_size = cpu_to_le32(tx_ring->num_desc);
+
+       phys_addr = rq_phys_addr;
+       err = qlcnic_issue_cmd(adapter,
+                       adapter->ahw.pci_func,
+                       QLCHAL_VERSION,
+                       (u32)(phys_addr >> 32),
+                       ((u32)phys_addr & 0xffffffff),
+                       rq_size,
+                       QLCNIC_CDRP_CMD_CREATE_TX_CTX);
+
+       if (err == QLCNIC_RCODE_SUCCESS) {
+               temp = le32_to_cpu(prsp->cds_ring.host_producer_crb);
+               tx_ring->crb_cmd_producer = qlcnic_get_ioaddr(adapter,
+                               QLCNIC_REG(temp - 0x200));
+
+               adapter->tx_context_id =
+                       le16_to_cpu(prsp->context_id);
+       } else {
+               dev_err(&adapter->pdev->dev,
+                       "Failed to create tx ctx in firmware%d\n", err);
+               err = -EIO;
+       }
+
+       pci_free_consistent(adapter->pdev, rsp_size, rsp_addr, rsp_phys_addr);
+
+out_free_rq:
+       pci_free_consistent(adapter->pdev, rq_size, rq_addr, rq_phys_addr);
+
+       return err;
+}
+
+static void
+qlcnic_fw_cmd_destroy_tx_ctx(struct qlcnic_adapter *adapter)
+{
+       if (qlcnic_issue_cmd(adapter,
+                       adapter->ahw.pci_func,
+                       QLCHAL_VERSION,
+                       adapter->tx_context_id,
+                       QLCNIC_DESTROY_CTX_RESET,
+                       0,
+                       QLCNIC_CDRP_CMD_DESTROY_TX_CTX)) {
+
+               dev_err(&adapter->pdev->dev,
+                       "Failed to destroy tx ctx in firmware\n");
+       }
+}
+
+int
+qlcnic_fw_cmd_query_phy(struct qlcnic_adapter *adapter, u32 reg, u32 *val)
+{
+
+       if (qlcnic_issue_cmd(adapter,
+                       adapter->ahw.pci_func,
+                       QLCHAL_VERSION,
+                       reg,
+                       0,
+                       0,
+                       QLCNIC_CDRP_CMD_READ_PHY)) {
+
+               return -EIO;
+       }
+
+       return QLCRD32(adapter, QLCNIC_ARG1_CRB_OFFSET);
+}
+
+int
+qlcnic_fw_cmd_set_phy(struct qlcnic_adapter *adapter, u32 reg, u32 val)
+{
+       return qlcnic_issue_cmd(adapter,
+                       adapter->ahw.pci_func,
+                       QLCHAL_VERSION,
+                       reg,
+                       val,
+                       0,
+                       QLCNIC_CDRP_CMD_WRITE_PHY);
+}
+
+int qlcnic_alloc_hw_resources(struct qlcnic_adapter *adapter)
+{
+       void *addr;
+       int err;
+       int ring;
+       struct qlcnic_recv_context *recv_ctx;
+       struct qlcnic_host_rds_ring *rds_ring;
+       struct qlcnic_host_sds_ring *sds_ring;
+       struct qlcnic_host_tx_ring *tx_ring;
+
+       struct pci_dev *pdev = adapter->pdev;
+
+       recv_ctx = &adapter->recv_ctx;
+       tx_ring = adapter->tx_ring;
+
+       tx_ring->hw_consumer = (__le32 *)pci_alloc_consistent(pdev, sizeof(u32),
+                                               &tx_ring->hw_cons_phys_addr);
+       if (tx_ring->hw_consumer == NULL) {
+               dev_err(&pdev->dev, "failed to allocate tx consumer\n");
+               return -ENOMEM;
+       }
+       *(tx_ring->hw_consumer) = 0;
+
+       /* cmd desc ring */
+       addr = pci_alloc_consistent(pdev, TX_DESC_RINGSIZE(tx_ring),
+                       &tx_ring->phys_addr);
+
+       if (addr == NULL) {
+               dev_err(&pdev->dev, "failed to allocate tx desc ring\n");
+               return -ENOMEM;
+       }
+
+       tx_ring->desc_head = (struct cmd_desc_type0 *)addr;
+
+       for (ring = 0; ring < adapter->max_rds_rings; ring++) {
+               rds_ring = &recv_ctx->rds_rings[ring];
+               addr = pci_alloc_consistent(adapter->pdev,
+                               RCV_DESC_RINGSIZE(rds_ring),
+                               &rds_ring->phys_addr);
+               if (addr == NULL) {
+                       dev_err(&pdev->dev,
+                               "failed to allocate rds ring [%d]\n", ring);
+                       err = -ENOMEM;
+                       goto err_out_free;
+               }
+               rds_ring->desc_head = (struct rcv_desc *)addr;
+
+       }
+
+       for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+               sds_ring = &recv_ctx->sds_rings[ring];
+
+               addr = pci_alloc_consistent(adapter->pdev,
+                               STATUS_DESC_RINGSIZE(sds_ring),
+                               &sds_ring->phys_addr);
+               if (addr == NULL) {
+                       dev_err(&pdev->dev,
+                               "failed to allocate sds ring [%d]\n", ring);
+                       err = -ENOMEM;
+                       goto err_out_free;
+               }
+               sds_ring->desc_head = (struct status_desc *)addr;
+       }
+
+
+       err = qlcnic_fw_cmd_create_rx_ctx(adapter);
+       if (err)
+               goto err_out_free;
+       err = qlcnic_fw_cmd_create_tx_ctx(adapter);
+       if (err)
+               goto err_out_free;
+
+       set_bit(__QLCNIC_FW_ATTACHED, &adapter->state);
+       return 0;
+
+err_out_free:
+       qlcnic_free_hw_resources(adapter);
+       return err;
+}
+
+void qlcnic_free_hw_resources(struct qlcnic_adapter *adapter)
+{
+       struct qlcnic_recv_context *recv_ctx;
+       struct qlcnic_host_rds_ring *rds_ring;
+       struct qlcnic_host_sds_ring *sds_ring;
+       struct qlcnic_host_tx_ring *tx_ring;
+       int ring;
+
+
+       if (test_and_clear_bit(__QLCNIC_FW_ATTACHED, &adapter->state)) {
+               qlcnic_fw_cmd_destroy_rx_ctx(adapter);
+               qlcnic_fw_cmd_destroy_tx_ctx(adapter);
+
+               /* Allow dma queues to drain after context reset */
+               msleep(20);
+       }
+
+       recv_ctx = &adapter->recv_ctx;
+
+       tx_ring = adapter->tx_ring;
+       if (tx_ring->hw_consumer != NULL) {
+               pci_free_consistent(adapter->pdev,
+                               sizeof(u32),
+                               tx_ring->hw_consumer,
+                               tx_ring->hw_cons_phys_addr);
+               tx_ring->hw_consumer = NULL;
+       }
+
+       if (tx_ring->desc_head != NULL) {
+               pci_free_consistent(adapter->pdev,
+                               TX_DESC_RINGSIZE(tx_ring),
+                               tx_ring->desc_head, tx_ring->phys_addr);
+               tx_ring->desc_head = NULL;
+       }
+
+       for (ring = 0; ring < adapter->max_rds_rings; ring++) {
+               rds_ring = &recv_ctx->rds_rings[ring];
+
+               if (rds_ring->desc_head != NULL) {
+                       pci_free_consistent(adapter->pdev,
+                                       RCV_DESC_RINGSIZE(rds_ring),
+                                       rds_ring->desc_head,
+                                       rds_ring->phys_addr);
+                       rds_ring->desc_head = NULL;
+               }
+       }
+
+       for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+               sds_ring = &recv_ctx->sds_rings[ring];
+
+               if (sds_ring->desc_head != NULL) {
+                       pci_free_consistent(adapter->pdev,
+                               STATUS_DESC_RINGSIZE(sds_ring),
+                               sds_ring->desc_head,
+                               sds_ring->phys_addr);
+                       sds_ring->desc_head = NULL;
+               }
+       }
+}
+
diff --git a/drivers/net/qlcnic/qlcnic_ethtool.c b/drivers/net/qlcnic/qlcnic_ethtool.c
new file mode 100644 (file)
index 0000000..8da6ec8
--- /dev/null
@@ -0,0 +1,1015 @@
+/*
+ * Copyright (C) 2009 - QLogic Corporation.
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called "COPYING".
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/io.h>
+#include <linux/netdevice.h>
+#include <linux/ethtool.h>
+
+#include "qlcnic.h"
+
+struct qlcnic_stats {
+       char stat_string[ETH_GSTRING_LEN];
+       int sizeof_stat;
+       int stat_offset;
+};
+
+#define QLC_SIZEOF(m) FIELD_SIZEOF(struct qlcnic_adapter, m)
+#define QLC_OFF(m) offsetof(struct qlcnic_adapter, m)
+
+static const struct qlcnic_stats qlcnic_gstrings_stats[] = {
+       {"xmit_called",
+               QLC_SIZEOF(stats.xmitcalled), QLC_OFF(stats.xmitcalled)},
+       {"xmit_finished",
+               QLC_SIZEOF(stats.xmitfinished), QLC_OFF(stats.xmitfinished)},
+       {"rx_dropped",
+               QLC_SIZEOF(stats.rxdropped), QLC_OFF(stats.rxdropped)},
+       {"tx_dropped",
+               QLC_SIZEOF(stats.txdropped), QLC_OFF(stats.txdropped)},
+       {"csummed",
+               QLC_SIZEOF(stats.csummed), QLC_OFF(stats.csummed)},
+       {"rx_pkts",
+               QLC_SIZEOF(stats.rx_pkts), QLC_OFF(stats.rx_pkts)},
+       {"lro_pkts",
+               QLC_SIZEOF(stats.lro_pkts), QLC_OFF(stats.lro_pkts)},
+       {"rx_bytes",
+               QLC_SIZEOF(stats.rxbytes), QLC_OFF(stats.rxbytes)},
+       {"tx_bytes",
+               QLC_SIZEOF(stats.txbytes), QLC_OFF(stats.txbytes)},
+};
+
+#define QLCNIC_STATS_LEN       ARRAY_SIZE(qlcnic_gstrings_stats)
+
+static const char qlcnic_gstrings_test[][ETH_GSTRING_LEN] = {
+       "Register_Test_on_offline",
+       "Link_Test_on_offline",
+       "Interrupt_Test_offline",
+       "Loopback_Test_offline"
+};
+
+#define QLCNIC_TEST_LEN        ARRAY_SIZE(qlcnic_gstrings_test)
+
+#define QLCNIC_RING_REGS_COUNT 20
+#define QLCNIC_RING_REGS_LEN   (QLCNIC_RING_REGS_COUNT * sizeof(u32))
+#define QLCNIC_MAX_EEPROM_LEN   1024
+
+static const u32 diag_registers[] = {
+       CRB_CMDPEG_STATE,
+       CRB_RCVPEG_STATE,
+       CRB_XG_STATE_P3,
+       CRB_FW_CAPABILITIES_1,
+       ISR_INT_STATE_REG,
+       QLCNIC_CRB_DEV_REF_COUNT,
+       QLCNIC_CRB_DEV_STATE,
+       QLCNIC_CRB_DRV_STATE,
+       QLCNIC_CRB_DRV_SCRATCH,
+       QLCNIC_CRB_DEV_PARTITION_INFO,
+       QLCNIC_CRB_DRV_IDC_VER,
+       QLCNIC_PEG_ALIVE_COUNTER,
+       QLCNIC_PEG_HALT_STATUS1,
+       QLCNIC_PEG_HALT_STATUS2,
+       QLCNIC_CRB_PEG_NET_0+0x3c,
+       QLCNIC_CRB_PEG_NET_1+0x3c,
+       QLCNIC_CRB_PEG_NET_2+0x3c,
+       QLCNIC_CRB_PEG_NET_4+0x3c,
+       -1
+};
+
+static int qlcnic_get_regs_len(struct net_device *dev)
+{
+       return sizeof(diag_registers) + QLCNIC_RING_REGS_LEN;
+}
+
+static int qlcnic_get_eeprom_len(struct net_device *dev)
+{
+       return QLCNIC_FLASH_TOTAL_SIZE;
+}
+
+static void
+qlcnic_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo)
+{
+       struct qlcnic_adapter *adapter = netdev_priv(dev);
+       u32 fw_major, fw_minor, fw_build;
+
+       fw_major = QLCRD32(adapter, QLCNIC_FW_VERSION_MAJOR);
+       fw_minor = QLCRD32(adapter, QLCNIC_FW_VERSION_MINOR);
+       fw_build = QLCRD32(adapter, QLCNIC_FW_VERSION_SUB);
+       sprintf(drvinfo->fw_version, "%d.%d.%d", fw_major, fw_minor, fw_build);
+
+       strlcpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
+       strlcpy(drvinfo->driver, qlcnic_driver_name, 32);
+       strlcpy(drvinfo->version, QLCNIC_LINUX_VERSIONID, 32);
+}
+
+static int
+qlcnic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+       struct qlcnic_adapter *adapter = netdev_priv(dev);
+       int check_sfp_module = 0;
+       u16 pcifn = adapter->ahw.pci_func;
+
+       /* read which mode */
+       if (adapter->ahw.port_type == QLCNIC_GBE) {
+               ecmd->supported = (SUPPORTED_10baseT_Half |
+                                  SUPPORTED_10baseT_Full |
+                                  SUPPORTED_100baseT_Half |
+                                  SUPPORTED_100baseT_Full |
+                                  SUPPORTED_1000baseT_Half |
+                                  SUPPORTED_1000baseT_Full);
+
+               ecmd->advertising = (ADVERTISED_100baseT_Half |
+                                    ADVERTISED_100baseT_Full |
+                                    ADVERTISED_1000baseT_Half |
+                                    ADVERTISED_1000baseT_Full);
+
+               ecmd->speed = adapter->link_speed;
+               ecmd->duplex = adapter->link_duplex;
+               ecmd->autoneg = adapter->link_autoneg;
+
+       } else if (adapter->ahw.port_type == QLCNIC_XGBE) {
+               u32 val;
+
+               val = QLCRD32(adapter, QLCNIC_PORT_MODE_ADDR);
+               if (val == QLCNIC_PORT_MODE_802_3_AP) {
+                       ecmd->supported = SUPPORTED_1000baseT_Full;
+                       ecmd->advertising = ADVERTISED_1000baseT_Full;
+               } else {
+                       ecmd->supported = SUPPORTED_10000baseT_Full;
+                       ecmd->advertising = ADVERTISED_10000baseT_Full;
+               }
+
+               if (netif_running(dev) && adapter->has_link_events) {
+                       ecmd->speed = adapter->link_speed;
+                       ecmd->autoneg = adapter->link_autoneg;
+                       ecmd->duplex = adapter->link_duplex;
+                       goto skip;
+               }
+
+               val = QLCRD32(adapter, P3_LINK_SPEED_REG(pcifn));
+               ecmd->speed = P3_LINK_SPEED_MHZ *
+                       P3_LINK_SPEED_VAL(pcifn, val);
+               ecmd->duplex = DUPLEX_FULL;
+               ecmd->autoneg = AUTONEG_DISABLE;
+       } else
+               return -EIO;
+
+skip:
+       ecmd->phy_address = adapter->physical_port;
+       ecmd->transceiver = XCVR_EXTERNAL;
+
+       switch (adapter->ahw.board_type) {
+       case QLCNIC_BRDTYPE_P3_REF_QG:
+       case QLCNIC_BRDTYPE_P3_4_GB:
+       case QLCNIC_BRDTYPE_P3_4_GB_MM:
+
+               ecmd->supported |= SUPPORTED_Autoneg;
+               ecmd->advertising |= ADVERTISED_Autoneg;
+       case QLCNIC_BRDTYPE_P3_10G_CX4:
+       case QLCNIC_BRDTYPE_P3_10G_CX4_LP:
+       case QLCNIC_BRDTYPE_P3_10000_BASE_T:
+               ecmd->supported |= SUPPORTED_TP;
+               ecmd->advertising |= ADVERTISED_TP;
+               ecmd->port = PORT_TP;
+               ecmd->autoneg =  adapter->link_autoneg;
+               break;
+       case QLCNIC_BRDTYPE_P3_IMEZ:
+       case QLCNIC_BRDTYPE_P3_XG_LOM:
+       case QLCNIC_BRDTYPE_P3_HMEZ:
+               ecmd->supported |= SUPPORTED_MII;
+               ecmd->advertising |= ADVERTISED_MII;
+               ecmd->port = PORT_MII;
+               ecmd->autoneg = AUTONEG_DISABLE;
+               break;
+       case QLCNIC_BRDTYPE_P3_10G_SFP_PLUS:
+       case QLCNIC_BRDTYPE_P3_10G_SFP_CT:
+       case QLCNIC_BRDTYPE_P3_10G_SFP_QT:
+               ecmd->advertising |= ADVERTISED_TP;
+               ecmd->supported |= SUPPORTED_TP;
+               check_sfp_module = netif_running(dev) &&
+                       adapter->has_link_events;
+       case QLCNIC_BRDTYPE_P3_10G_XFP:
+               ecmd->supported |= SUPPORTED_FIBRE;
+               ecmd->advertising |= ADVERTISED_FIBRE;
+               ecmd->port = PORT_FIBRE;
+               ecmd->autoneg = AUTONEG_DISABLE;
+               break;
+       case QLCNIC_BRDTYPE_P3_10G_TP:
+               if (adapter->ahw.port_type == QLCNIC_XGBE) {
+                       ecmd->autoneg = AUTONEG_DISABLE;
+                       ecmd->supported |= (SUPPORTED_FIBRE | SUPPORTED_TP);
+                       ecmd->advertising |=
+                               (ADVERTISED_FIBRE | ADVERTISED_TP);
+                       ecmd->port = PORT_FIBRE;
+                       check_sfp_module = netif_running(dev) &&
+                               adapter->has_link_events;
+               } else {
+                       ecmd->autoneg = AUTONEG_ENABLE;
+                       ecmd->supported |= (SUPPORTED_TP | SUPPORTED_Autoneg);
+                       ecmd->advertising |=
+                               (ADVERTISED_TP | ADVERTISED_Autoneg);
+                       ecmd->port = PORT_TP;
+               }
+               break;
+       default:
+               dev_err(&adapter->pdev->dev, "Unsupported board model %d\n",
+                       adapter->ahw.board_type);
+               return -EIO;
+       }
+
+       if (check_sfp_module) {
+               switch (adapter->module_type) {
+               case LINKEVENT_MODULE_OPTICAL_UNKNOWN:
+               case LINKEVENT_MODULE_OPTICAL_SRLR:
+               case LINKEVENT_MODULE_OPTICAL_LRM:
+               case LINKEVENT_MODULE_OPTICAL_SFP_1G:
+                       ecmd->port = PORT_FIBRE;
+                       break;
+               case LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLE:
+               case LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLELEN:
+               case LINKEVENT_MODULE_TWINAX:
+                       ecmd->port = PORT_TP;
+                       break;
+               default:
+                       ecmd->port = PORT_OTHER;
+               }
+       }
+
+       return 0;
+}
+
+static int
+qlcnic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+       struct qlcnic_adapter *adapter = netdev_priv(dev);
+       __u32 status;
+
+       /* read which mode */
+       if (adapter->ahw.port_type == QLCNIC_GBE) {
+               /* autonegotiation */
+               if (qlcnic_fw_cmd_set_phy(adapter,
+                              QLCNIC_NIU_GB_MII_MGMT_ADDR_AUTONEG,
+                              ecmd->autoneg) != 0)
+                       return -EIO;
+               else
+                       adapter->link_autoneg = ecmd->autoneg;
+
+               if (qlcnic_fw_cmd_query_phy(adapter,
+                             QLCNIC_NIU_GB_MII_MGMT_ADDR_PHY_STATUS,
+                             &status) != 0)
+                       return -EIO;
+
+               switch (ecmd->speed) {
+               case SPEED_10:
+                       qlcnic_set_phy_speed(status, 0);
+                       break;
+               case SPEED_100:
+                       qlcnic_set_phy_speed(status, 1);
+                       break;
+               case SPEED_1000:
+                       qlcnic_set_phy_speed(status, 2);
+                       break;
+               }
+
+               if (ecmd->duplex == DUPLEX_HALF)
+                       qlcnic_clear_phy_duplex(status);
+               if (ecmd->duplex == DUPLEX_FULL)
+                       qlcnic_set_phy_duplex(status);
+               if (qlcnic_fw_cmd_set_phy(adapter,
+                              QLCNIC_NIU_GB_MII_MGMT_ADDR_PHY_STATUS,
+                              *((int *)&status)) != 0)
+                       return -EIO;
+               else {
+                       adapter->link_speed = ecmd->speed;
+                       adapter->link_duplex = ecmd->duplex;
+               }
+       } else
+               return -EOPNOTSUPP;
+
+       if (!netif_running(dev))
+               return 0;
+
+       dev->netdev_ops->ndo_stop(dev);
+       return dev->netdev_ops->ndo_open(dev);
+}
+
+static void
+qlcnic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p)
+{
+       struct qlcnic_adapter *adapter = netdev_priv(dev);
+       struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
+       struct qlcnic_host_sds_ring *sds_ring;
+       u32 *regs_buff = 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;
+
+       for (i = 0; diag_registers[i] != -1; i++)
+               regs_buff[i] = QLCRD32(adapter, diag_registers[i]);
+
+       if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
+               return;
+
+       regs_buff[i++] = 0xFFEFCDAB; /* Marker btw regs and ring count*/
+
+       regs_buff[i++] = 1; /* No. of tx ring */
+       regs_buff[i++] = le32_to_cpu(*(adapter->tx_ring->hw_consumer));
+       regs_buff[i++] = readl(adapter->tx_ring->crb_cmd_producer);
+
+       regs_buff[i++] = 2; /* No. of rx ring */
+       regs_buff[i++] = readl(recv_ctx->rds_rings[0].crb_rcv_producer);
+       regs_buff[i++] = readl(recv_ctx->rds_rings[1].crb_rcv_producer);
+
+       regs_buff[i++] = adapter->max_sds_rings;
+
+       for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+               sds_ring = &(recv_ctx->sds_rings[ring]);
+               regs_buff[i++] = readl(sds_ring->crb_sts_consumer);
+       }
+}
+
+static u32 qlcnic_test_link(struct net_device *dev)
+{
+       struct qlcnic_adapter *adapter = netdev_priv(dev);
+       u32 val;
+
+       val = QLCRD32(adapter, CRB_XG_STATE_P3);
+       val = XG_LINK_STATE_P3(adapter->ahw.pci_func, val);
+       return (val == XG_LINK_UP_P3) ? 0 : 1;
+}
+
+static int
+qlcnic_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
+                     u8 *bytes)
+{
+       struct qlcnic_adapter *adapter = netdev_priv(dev);
+       int offset;
+       int ret;
+
+       if (eeprom->len == 0)
+               return -EINVAL;
+
+       eeprom->magic = (adapter->pdev)->vendor |
+                       ((adapter->pdev)->device << 16);
+       offset = eeprom->offset;
+
+       ret = qlcnic_rom_fast_read_words(adapter, offset, bytes,
+                                               eeprom->len);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static void
+qlcnic_get_ringparam(struct net_device *dev,
+               struct ethtool_ringparam *ring)
+{
+       struct qlcnic_adapter *adapter = netdev_priv(dev);
+
+       ring->rx_pending = adapter->num_rxd;
+       ring->rx_jumbo_pending = adapter->num_jumbo_rxd;
+       ring->rx_jumbo_pending += adapter->num_lro_rxd;
+       ring->tx_pending = adapter->num_txd;
+
+       if (adapter->ahw.port_type == QLCNIC_GBE) {
+               ring->rx_max_pending = MAX_RCV_DESCRIPTORS_1G;
+               ring->rx_jumbo_max_pending = MAX_JUMBO_RCV_DESCRIPTORS_1G;
+       } else {
+               ring->rx_max_pending = MAX_RCV_DESCRIPTORS_10G;
+               ring->rx_jumbo_max_pending = MAX_JUMBO_RCV_DESCRIPTORS_10G;
+       }
+
+       ring->tx_max_pending = MAX_CMD_DESCRIPTORS;
+
+       ring->rx_mini_max_pending = 0;
+       ring->rx_mini_pending = 0;
+}
+
+static u32
+qlcnic_validate_ringparam(u32 val, u32 min, u32 max, char *r_name)
+{
+       u32 num_desc;
+       num_desc = max(val, min);
+       num_desc = min(num_desc, max);
+       num_desc = roundup_pow_of_two(num_desc);
+
+       if (val != num_desc) {
+               printk(KERN_INFO "%s: setting %s ring size %d instead of %d\n",
+                      qlcnic_driver_name, r_name, num_desc, val);
+       }
+
+       return num_desc;
+}
+
+static int
+qlcnic_set_ringparam(struct net_device *dev,
+               struct ethtool_ringparam *ring)
+{
+       struct qlcnic_adapter *adapter = netdev_priv(dev);
+       u16 max_rcv_desc = MAX_RCV_DESCRIPTORS_10G;
+       u16 max_jumbo_desc = MAX_JUMBO_RCV_DESCRIPTORS_10G;
+       u16 num_rxd, num_jumbo_rxd, num_txd;
+
+
+       if (ring->rx_mini_pending)
+               return -EOPNOTSUPP;
+
+       if (adapter->ahw.port_type == QLCNIC_GBE) {
+               max_rcv_desc = MAX_RCV_DESCRIPTORS_1G;
+               max_jumbo_desc = MAX_JUMBO_RCV_DESCRIPTORS_10G;
+       }
+
+       num_rxd = qlcnic_validate_ringparam(ring->rx_pending,
+                       MIN_RCV_DESCRIPTORS, max_rcv_desc, "rx");
+
+       num_jumbo_rxd = qlcnic_validate_ringparam(ring->rx_jumbo_pending,
+                       MIN_JUMBO_DESCRIPTORS, max_jumbo_desc, "rx jumbo");
+
+       num_txd = qlcnic_validate_ringparam(ring->tx_pending,
+                       MIN_CMD_DESCRIPTORS, MAX_CMD_DESCRIPTORS, "tx");
+
+       if (num_rxd == adapter->num_rxd && num_txd == adapter->num_txd &&
+                       num_jumbo_rxd == adapter->num_jumbo_rxd)
+               return 0;
+
+       adapter->num_rxd = num_rxd;
+       adapter->num_jumbo_rxd = num_jumbo_rxd;
+       adapter->num_txd = num_txd;
+
+       return qlcnic_reset_context(adapter);
+}
+
+static void
+qlcnic_get_pauseparam(struct net_device *netdev,
+                         struct ethtool_pauseparam *pause)
+{
+       struct qlcnic_adapter *adapter = netdev_priv(netdev);
+       int port = adapter->physical_port;
+       __u32 val;
+
+       if (adapter->ahw.port_type == QLCNIC_GBE) {
+               if ((port < 0) || (port > QLCNIC_NIU_MAX_GBE_PORTS))
+                       return;
+               /* get flow control settings */
+               val = QLCRD32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port));
+               pause->rx_pause = qlcnic_gb_get_rx_flowctl(val);
+               val = QLCRD32(adapter, QLCNIC_NIU_GB_PAUSE_CTL);
+               switch (port) {
+               case 0:
+                       pause->tx_pause = !(qlcnic_gb_get_gb0_mask(val));
+                       break;
+               case 1:
+                       pause->tx_pause = !(qlcnic_gb_get_gb1_mask(val));
+                       break;
+               case 2:
+                       pause->tx_pause = !(qlcnic_gb_get_gb2_mask(val));
+                       break;
+               case 3:
+               default:
+                       pause->tx_pause = !(qlcnic_gb_get_gb3_mask(val));
+                       break;
+               }
+       } else if (adapter->ahw.port_type == QLCNIC_XGBE) {
+               if ((port < 0) || (port > QLCNIC_NIU_MAX_XG_PORTS))
+                       return;
+               pause->rx_pause = 1;
+               val = QLCRD32(adapter, QLCNIC_NIU_XG_PAUSE_CTL);
+               if (port == 0)
+                       pause->tx_pause = !(qlcnic_xg_get_xg0_mask(val));
+               else
+                       pause->tx_pause = !(qlcnic_xg_get_xg1_mask(val));
+       } else {
+               dev_err(&netdev->dev, "Unknown board type: %x\n",
+                                       adapter->ahw.port_type);
+       }
+}
+
+static int
+qlcnic_set_pauseparam(struct net_device *netdev,
+                         struct ethtool_pauseparam *pause)
+{
+       struct qlcnic_adapter *adapter = netdev_priv(netdev);
+       int port = adapter->physical_port;
+       __u32 val;
+
+       /* read mode */
+       if (adapter->ahw.port_type == QLCNIC_GBE) {
+               if ((port < 0) || (port > QLCNIC_NIU_MAX_GBE_PORTS))
+                       return -EIO;
+               /* set flow control */
+               val = QLCRD32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port));
+
+               if (pause->rx_pause)
+                       qlcnic_gb_rx_flowctl(val);
+               else
+                       qlcnic_gb_unset_rx_flowctl(val);
+
+               QLCWR32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port),
+                               val);
+               /* set autoneg */
+               val = QLCRD32(adapter, QLCNIC_NIU_GB_PAUSE_CTL);
+               switch (port) {
+               case 0:
+                       if (pause->tx_pause)
+                               qlcnic_gb_unset_gb0_mask(val);
+                       else
+                               qlcnic_gb_set_gb0_mask(val);
+                       break;
+               case 1:
+                       if (pause->tx_pause)
+                               qlcnic_gb_unset_gb1_mask(val);
+                       else
+                               qlcnic_gb_set_gb1_mask(val);
+                       break;
+               case 2:
+                       if (pause->tx_pause)
+                               qlcnic_gb_unset_gb2_mask(val);
+                       else
+                               qlcnic_gb_set_gb2_mask(val);
+                       break;
+               case 3:
+               default:
+                       if (pause->tx_pause)
+                               qlcnic_gb_unset_gb3_mask(val);
+                       else
+                               qlcnic_gb_set_gb3_mask(val);
+                       break;
+               }
+               QLCWR32(adapter, QLCNIC_NIU_GB_PAUSE_CTL, val);
+       } else if (adapter->ahw.port_type == QLCNIC_XGBE) {
+               if ((port < 0) || (port > QLCNIC_NIU_MAX_XG_PORTS))
+                       return -EIO;
+               val = QLCRD32(adapter, QLCNIC_NIU_XG_PAUSE_CTL);
+               if (port == 0) {
+                       if (pause->tx_pause)
+                               qlcnic_xg_unset_xg0_mask(val);
+                       else
+                               qlcnic_xg_set_xg0_mask(val);
+               } else {
+                       if (pause->tx_pause)
+                               qlcnic_xg_unset_xg1_mask(val);
+                       else
+                               qlcnic_xg_set_xg1_mask(val);
+               }
+               QLCWR32(adapter, QLCNIC_NIU_XG_PAUSE_CTL, val);
+       } else {
+               dev_err(&netdev->dev, "Unknown board type: %x\n",
+                               adapter->ahw.port_type);
+       }
+       return 0;
+}
+
+static int qlcnic_reg_test(struct net_device *dev)
+{
+       struct qlcnic_adapter *adapter = netdev_priv(dev);
+       u32 data_read, data_written;
+
+       data_read = QLCRD32(adapter, QLCNIC_PCIX_PH_REG(0));
+       if ((data_read & 0xffff) != adapter->pdev->vendor)
+               return 1;
+
+       data_written = (u32)0xa5a5a5a5;
+
+       QLCWR32(adapter, CRB_SCRATCHPAD_TEST, data_written);
+       data_read = QLCRD32(adapter, CRB_SCRATCHPAD_TEST);
+       if (data_written != data_read)
+               return 1;
+
+       return 0;
+}
+
+static int qlcnic_get_sset_count(struct net_device *dev, int sset)
+{
+       switch (sset) {
+       case ETH_SS_TEST:
+               return QLCNIC_TEST_LEN;
+       case ETH_SS_STATS:
+               return QLCNIC_STATS_LEN;
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
+#define QLC_ILB_PKT_SIZE 64
+
+static void qlcnic_create_loopback_buff(unsigned char *data)
+{
+       unsigned char random_data[] = {0xa8, 0x06, 0x45, 0x00};
+       memset(data, 0x4e, QLC_ILB_PKT_SIZE);
+       memset(data, 0xff, 12);
+       memcpy(data + 12, random_data, sizeof(random_data));
+}
+
+int qlcnic_check_loopback_buff(unsigned char *data)
+{
+       unsigned char buff[QLC_ILB_PKT_SIZE];
+       qlcnic_create_loopback_buff(buff);
+       return memcmp(data, buff, QLC_ILB_PKT_SIZE);
+}
+
+static int qlcnic_do_ilb_test(struct qlcnic_adapter *adapter)
+{
+       struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
+       struct qlcnic_host_sds_ring *sds_ring = &recv_ctx->sds_rings[0];
+       struct sk_buff *skb;
+       int i;
+
+       for (i = 0; i < 16; i++) {
+               skb = dev_alloc_skb(QLC_ILB_PKT_SIZE);
+               qlcnic_create_loopback_buff(skb->data);
+               skb_put(skb, QLC_ILB_PKT_SIZE);
+
+               adapter->diag_cnt = 0;
+
+               qlcnic_xmit_frame(skb, adapter->netdev);
+
+               msleep(5);
+
+               qlcnic_process_rcv_ring_diag(sds_ring);
+
+               dev_kfree_skb_any(skb);
+               if (!adapter->diag_cnt)
+                       return -1;
+       }
+       return 0;
+}
+
+static int qlcnic_loopback_test(struct net_device *netdev)
+{
+       struct qlcnic_adapter *adapter = netdev_priv(netdev);
+       int max_sds_rings = adapter->max_sds_rings;
+       int ret;
+
+       if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
+               return -EIO;
+
+       ret = qlcnic_diag_alloc_res(netdev, QLCNIC_LOOPBACK_TEST);
+       if (ret)
+               goto clear_it;
+
+       ret = qlcnic_set_ilb_mode(adapter);
+       if (ret)
+               goto done;
+
+       ret = qlcnic_do_ilb_test(adapter);
+
+       qlcnic_clear_ilb_mode(adapter);
+
+done:
+       qlcnic_diag_free_res(netdev, max_sds_rings);
+
+clear_it:
+       adapter->max_sds_rings = max_sds_rings;
+       clear_bit(__QLCNIC_RESETTING, &adapter->state);
+       return ret;
+}
+
+static int qlcnic_irq_test(struct net_device *netdev)
+{
+       struct qlcnic_adapter *adapter = netdev_priv(netdev);
+       int max_sds_rings = adapter->max_sds_rings;
+       int ret;
+
+       if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
+               return -EIO;
+
+       ret = qlcnic_diag_alloc_res(netdev, QLCNIC_INTERRUPT_TEST);
+       if (ret)
+               goto clear_it;
+
+       adapter->diag_cnt = 0;
+       ret = qlcnic_issue_cmd(adapter, adapter->ahw.pci_func,
+                       QLCHAL_VERSION, adapter->portnum, 0, 0, 0x00000011);
+       if (ret)
+               goto done;
+
+       msleep(10);
+
+       ret = !adapter->diag_cnt;
+
+done:
+       qlcnic_diag_free_res(netdev, max_sds_rings);
+
+clear_it:
+       adapter->max_sds_rings = max_sds_rings;
+       clear_bit(__QLCNIC_RESETTING, &adapter->state);
+       return ret;
+}
+
+static void
+qlcnic_diag_test(struct net_device *dev, struct ethtool_test *eth_test,
+                    u64 *data)
+{
+       memset(data, 0, sizeof(u64) * QLCNIC_TEST_LEN);
+
+       if (eth_test->flags == ETH_TEST_FL_OFFLINE) {
+               data[2] = qlcnic_irq_test(dev);
+               if (data[2])
+                       eth_test->flags |= ETH_TEST_FL_FAILED;
+
+               data[3] = qlcnic_loopback_test(dev);
+               if (data[3])
+                       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
+qlcnic_get_strings(struct net_device *dev, u32 stringset, u8 * data)
+{
+       int index;
+
+       switch (stringset) {
+       case ETH_SS_TEST:
+               memcpy(data, *qlcnic_gstrings_test,
+                      QLCNIC_TEST_LEN * ETH_GSTRING_LEN);
+               break;
+       case ETH_SS_STATS:
+               for (index = 0; index < QLCNIC_STATS_LEN; index++) {
+                       memcpy(data + index * ETH_GSTRING_LEN,
+                              qlcnic_gstrings_stats[index].stat_string,
+                              ETH_GSTRING_LEN);
+               }
+               break;
+       }
+}
+
+static void
+qlcnic_get_ethtool_stats(struct net_device *dev,
+                            struct ethtool_stats *stats, u64 * data)
+{
+       struct qlcnic_adapter *adapter = netdev_priv(dev);
+       int index;
+
+       for (index = 0; index < QLCNIC_STATS_LEN; index++) {
+               char *p =
+                   (char *)adapter +
+                   qlcnic_gstrings_stats[index].stat_offset;
+               data[index] =
+                   (qlcnic_gstrings_stats[index].sizeof_stat ==
+                    sizeof(u64)) ? *(u64 *)p:(*(u32 *)p);
+       }
+}
+
+static u32 qlcnic_get_rx_csum(struct net_device *dev)
+{
+       struct qlcnic_adapter *adapter = netdev_priv(dev);
+       return adapter->rx_csum;
+}
+
+static int qlcnic_set_rx_csum(struct net_device *dev, u32 data)
+{
+       struct qlcnic_adapter *adapter = netdev_priv(dev);
+       adapter->rx_csum = !!data;
+       return 0;
+}
+
+static u32 qlcnic_get_tso(struct net_device *dev)
+{
+       return (dev->features & (NETIF_F_TSO | NETIF_F_TSO6)) != 0;
+}
+
+static int qlcnic_set_tso(struct net_device *dev, u32 data)
+{
+       if (data)
+               dev->features |= (NETIF_F_TSO | NETIF_F_TSO6);
+       else
+               dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6);
+
+       return 0;
+}
+
+static int qlcnic_blink_led(struct net_device *dev, u32 val)
+{
+       struct qlcnic_adapter *adapter = netdev_priv(dev);
+       int ret;
+
+       ret = qlcnic_config_led(adapter, 1, 0xf);
+       if (ret) {
+               dev_err(&adapter->pdev->dev,
+                       "Failed to set LED blink state.\n");
+               return ret;
+       }
+
+       msleep_interruptible(val * 1000);
+
+       ret = qlcnic_config_led(adapter, 0, 0xf);
+       if (ret) {
+               dev_err(&adapter->pdev->dev,
+                       "Failed to reset LED blink state.\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static void
+qlcnic_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+       struct qlcnic_adapter *adapter = netdev_priv(dev);
+       u32 wol_cfg;
+
+       wol->supported = 0;
+       wol->wolopts = 0;
+
+       wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV);
+       if (wol_cfg & (1UL << adapter->portnum))
+               wol->supported |= WAKE_MAGIC;
+
+       wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG);
+       if (wol_cfg & (1UL << adapter->portnum))
+               wol->wolopts |= WAKE_MAGIC;
+}
+
+static int
+qlcnic_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+       struct qlcnic_adapter *adapter = netdev_priv(dev);
+       u32 wol_cfg;
+
+       if (wol->wolopts & ~WAKE_MAGIC)
+               return -EOPNOTSUPP;
+
+       wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV);
+       if (!(wol_cfg & (1 << adapter->portnum)))
+               return -EOPNOTSUPP;
+
+       wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG);
+       if (wol->wolopts & WAKE_MAGIC)
+               wol_cfg |= 1UL << adapter->portnum;
+       else
+               wol_cfg &= ~(1UL << adapter->portnum);
+
+       QLCWR32(adapter, QLCNIC_WOL_CONFIG, wol_cfg);
+
+       return 0;
+}
+
+/*
+ * Set the coalescing parameters. Currently only normal is supported.
+ * If rx_coalesce_usecs == 0 or rx_max_coalesced_frames == 0 then set the
+ * firmware coalescing to default.
+ */
+static int qlcnic_set_intr_coalesce(struct net_device *netdev,
+                       struct ethtool_coalesce *ethcoal)
+{
+       struct qlcnic_adapter *adapter = netdev_priv(netdev);
+
+       if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
+               return -EINVAL;
+
+       /*
+       * Return Error if unsupported values or
+       * unsupported parameters are set.
+       */
+       if (ethcoal->rx_coalesce_usecs > 0xffff ||
+               ethcoal->rx_max_coalesced_frames > 0xffff ||
+               ethcoal->tx_coalesce_usecs > 0xffff ||
+               ethcoal->tx_max_coalesced_frames > 0xffff ||
+               ethcoal->rx_coalesce_usecs_irq ||
+               ethcoal->rx_max_coalesced_frames_irq ||
+               ethcoal->tx_coalesce_usecs_irq ||
+               ethcoal->tx_max_coalesced_frames_irq ||
+               ethcoal->stats_block_coalesce_usecs ||
+               ethcoal->use_adaptive_rx_coalesce ||
+               ethcoal->use_adaptive_tx_coalesce ||
+               ethcoal->pkt_rate_low ||
+               ethcoal->rx_coalesce_usecs_low ||
+               ethcoal->rx_max_coalesced_frames_low ||
+               ethcoal->tx_coalesce_usecs_low ||
+               ethcoal->tx_max_coalesced_frames_low ||
+               ethcoal->pkt_rate_high ||
+               ethcoal->rx_coalesce_usecs_high ||
+               ethcoal->rx_max_coalesced_frames_high ||
+               ethcoal->tx_coalesce_usecs_high ||
+               ethcoal->tx_max_coalesced_frames_high)
+               return -EINVAL;
+
+       if (!ethcoal->rx_coalesce_usecs ||
+               !ethcoal->rx_max_coalesced_frames) {
+               adapter->coal.flags = QLCNIC_INTR_DEFAULT;
+               adapter->coal.normal.data.rx_time_us =
+                       QLCNIC_DEFAULT_INTR_COALESCE_RX_TIME_US;
+               adapter->coal.normal.data.rx_packets =
+                       QLCNIC_DEFAULT_INTR_COALESCE_RX_PACKETS;
+       } else {
+               adapter->coal.flags = 0;
+               adapter->coal.normal.data.rx_time_us =
+               ethcoal->rx_coalesce_usecs;
+               adapter->coal.normal.data.rx_packets =
+               ethcoal->rx_max_coalesced_frames;
+       }
+       adapter->coal.normal.data.tx_time_us = ethcoal->tx_coalesce_usecs;
+       adapter->coal.normal.data.tx_packets =
+       ethcoal->tx_max_coalesced_frames;
+
+       qlcnic_config_intr_coalesce(adapter);
+
+       return 0;
+}
+
+static int qlcnic_get_intr_coalesce(struct net_device *netdev,
+                       struct ethtool_coalesce *ethcoal)
+{
+       struct qlcnic_adapter *adapter = netdev_priv(netdev);
+
+       if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
+               return -EINVAL;
+
+       ethcoal->rx_coalesce_usecs = adapter->coal.normal.data.rx_time_us;
+       ethcoal->tx_coalesce_usecs = adapter->coal.normal.data.tx_time_us;
+       ethcoal->rx_max_coalesced_frames =
+               adapter->coal.normal.data.rx_packets;
+       ethcoal->tx_max_coalesced_frames =
+               adapter->coal.normal.data.tx_packets;
+
+       return 0;
+}
+
+static int qlcnic_set_flags(struct net_device *netdev, u32 data)
+{
+       struct qlcnic_adapter *adapter = netdev_priv(netdev);
+       int hw_lro;
+
+       if (!(adapter->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO))
+               return -EINVAL;
+
+       ethtool_op_set_flags(netdev, data);
+
+       hw_lro = (data & ETH_FLAG_LRO) ? QLCNIC_LRO_ENABLED : 0;
+
+       if (qlcnic_config_hw_lro(adapter, hw_lro))
+               return -EIO;
+
+       if ((hw_lro == 0) && qlcnic_send_lro_cleanup(adapter))
+               return -EIO;
+
+
+       return 0;
+}
+
+const struct ethtool_ops qlcnic_ethtool_ops = {
+       .get_settings = qlcnic_get_settings,
+       .set_settings = qlcnic_set_settings,
+       .get_drvinfo = qlcnic_get_drvinfo,
+       .get_regs_len = qlcnic_get_regs_len,
+       .get_regs = qlcnic_get_regs,
+       .get_link = ethtool_op_get_link,
+       .get_eeprom_len = qlcnic_get_eeprom_len,
+       .get_eeprom = qlcnic_get_eeprom,
+       .get_ringparam = qlcnic_get_ringparam,
+       .set_ringparam = qlcnic_set_ringparam,
+       .get_pauseparam = qlcnic_get_pauseparam,
+       .set_pauseparam = qlcnic_set_pauseparam,
+       .set_tx_csum = ethtool_op_set_tx_csum,
+       .set_sg = ethtool_op_set_sg,
+       .get_tso = qlcnic_get_tso,
+       .set_tso = qlcnic_set_tso,
+       .get_wol = qlcnic_get_wol,
+       .set_wol = qlcnic_set_wol,
+       .self_test = qlcnic_diag_test,
+       .get_strings = qlcnic_get_strings,
+       .get_ethtool_stats = qlcnic_get_ethtool_stats,
+       .get_sset_count = qlcnic_get_sset_count,
+       .get_rx_csum = qlcnic_get_rx_csum,
+       .set_rx_csum = qlcnic_set_rx_csum,
+       .get_coalesce = qlcnic_get_intr_coalesce,
+       .set_coalesce = qlcnic_set_intr_coalesce,
+       .get_flags = ethtool_op_get_flags,
+       .set_flags = qlcnic_set_flags,
+       .phys_id = qlcnic_blink_led,
+};
diff --git a/drivers/net/qlcnic/qlcnic_hdr.h b/drivers/net/qlcnic/qlcnic_hdr.h
new file mode 100644 (file)
index 0000000..0469f84
--- /dev/null
@@ -0,0 +1,937 @@
+/*
+ * Copyright (C) 2009 - QLogic Corporation.
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called "COPYING".
+ *
+ */
+
+#ifndef __QLCNIC_HDR_H_
+#define __QLCNIC_HDR_H_
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+
+/*
+ * The basic unit of access when reading/writing control registers.
+ */
+
+enum {
+       QLCNIC_HW_H0_CH_HUB_ADR = 0x05,
+       QLCNIC_HW_H1_CH_HUB_ADR = 0x0E,
+       QLCNIC_HW_H2_CH_HUB_ADR = 0x03,
+       QLCNIC_HW_H3_CH_HUB_ADR = 0x01,
+       QLCNIC_HW_H4_CH_HUB_ADR = 0x06,
+       QLCNIC_HW_H5_CH_HUB_ADR = 0x07,
+       QLCNIC_HW_H6_CH_HUB_ADR = 0x08
+};
+
+/*  Hub 0 */
+enum {
+       QLCNIC_HW_MN_CRB_AGT_ADR = 0x15,
+       QLCNIC_HW_MS_CRB_AGT_ADR = 0x25
+};
+
+/*  Hub 1 */
+enum {
+       QLCNIC_HW_PS_CRB_AGT_ADR = 0x73,
+       QLCNIC_HW_SS_CRB_AGT_ADR = 0x20,
+       QLCNIC_HW_RPMX3_CRB_AGT_ADR = 0x0b,
+       QLCNIC_HW_QMS_CRB_AGT_ADR = 0x00,
+       QLCNIC_HW_SQGS0_CRB_AGT_ADR = 0x01,
+       QLCNIC_HW_SQGS1_CRB_AGT_ADR = 0x02,
+       QLCNIC_HW_SQGS2_CRB_AGT_ADR = 0x03,
+       QLCNIC_HW_SQGS3_CRB_AGT_ADR = 0x04,
+       QLCNIC_HW_C2C0_CRB_AGT_ADR = 0x58,
+       QLCNIC_HW_C2C1_CRB_AGT_ADR = 0x59,
+       QLCNIC_HW_C2C2_CRB_AGT_ADR = 0x5a,
+       QLCNIC_HW_RPMX2_CRB_AGT_ADR = 0x0a,
+       QLCNIC_HW_RPMX4_CRB_AGT_ADR = 0x0c,
+       QLCNIC_HW_RPMX7_CRB_AGT_ADR = 0x0f,
+       QLCNIC_HW_RPMX9_CRB_AGT_ADR = 0x12,
+       QLCNIC_HW_SMB_CRB_AGT_ADR = 0x18
+};
+
+/*  Hub 2 */
+enum {
+       QLCNIC_HW_NIU_CRB_AGT_ADR = 0x31,
+       QLCNIC_HW_I2C0_CRB_AGT_ADR = 0x19,
+       QLCNIC_HW_I2C1_CRB_AGT_ADR = 0x29,
+
+       QLCNIC_HW_SN_CRB_AGT_ADR = 0x10,
+       QLCNIC_HW_I2Q_CRB_AGT_ADR = 0x20,
+       QLCNIC_HW_LPC_CRB_AGT_ADR = 0x22,
+       QLCNIC_HW_ROMUSB_CRB_AGT_ADR = 0x21,
+       QLCNIC_HW_QM_CRB_AGT_ADR = 0x66,
+       QLCNIC_HW_SQG0_CRB_AGT_ADR = 0x60,
+       QLCNIC_HW_SQG1_CRB_AGT_ADR = 0x61,
+       QLCNIC_HW_SQG2_CRB_AGT_ADR = 0x62,
+       QLCNIC_HW_SQG3_CRB_AGT_ADR = 0x63,
+       QLCNIC_HW_RPMX1_CRB_AGT_ADR = 0x09,
+       QLCNIC_HW_RPMX5_CRB_AGT_ADR = 0x0d,
+       QLCNIC_HW_RPMX6_CRB_AGT_ADR = 0x0e,
+       QLCNIC_HW_RPMX8_CRB_AGT_ADR = 0x11
+};
+
+/*  Hub 3 */
+enum {
+       QLCNIC_HW_PH_CRB_AGT_ADR = 0x1A,
+       QLCNIC_HW_SRE_CRB_AGT_ADR = 0x50,
+       QLCNIC_HW_EG_CRB_AGT_ADR = 0x51,
+       QLCNIC_HW_RPMX0_CRB_AGT_ADR = 0x08
+};
+
+/*  Hub 4 */
+enum {
+       QLCNIC_HW_PEGN0_CRB_AGT_ADR = 0x40,
+       QLCNIC_HW_PEGN1_CRB_AGT_ADR,
+       QLCNIC_HW_PEGN2_CRB_AGT_ADR,
+       QLCNIC_HW_PEGN3_CRB_AGT_ADR,
+       QLCNIC_HW_PEGNI_CRB_AGT_ADR,
+       QLCNIC_HW_PEGND_CRB_AGT_ADR,
+       QLCNIC_HW_PEGNC_CRB_AGT_ADR,
+       QLCNIC_HW_PEGR0_CRB_AGT_ADR,
+       QLCNIC_HW_PEGR1_CRB_AGT_ADR,
+       QLCNIC_HW_PEGR2_CRB_AGT_ADR,
+       QLCNIC_HW_PEGR3_CRB_AGT_ADR,
+       QLCNIC_HW_PEGN4_CRB_AGT_ADR
+};
+
+/*  Hub 5 */
+enum {
+       QLCNIC_HW_PEGS0_CRB_AGT_ADR = 0x40,
+       QLCNIC_HW_PEGS1_CRB_AGT_ADR,
+       QLCNIC_HW_PEGS2_CRB_AGT_ADR,
+       QLCNIC_HW_PEGS3_CRB_AGT_ADR,
+       QLCNIC_HW_PEGSI_CRB_AGT_ADR,
+       QLCNIC_HW_PEGSD_CRB_AGT_ADR,
+       QLCNIC_HW_PEGSC_CRB_AGT_ADR
+};
+
+/*  Hub 6 */
+enum {
+       QLCNIC_HW_CAS0_CRB_AGT_ADR = 0x46,
+       QLCNIC_HW_CAS1_CRB_AGT_ADR = 0x47,
+       QLCNIC_HW_CAS2_CRB_AGT_ADR = 0x48,
+       QLCNIC_HW_CAS3_CRB_AGT_ADR = 0x49,
+       QLCNIC_HW_NCM_CRB_AGT_ADR = 0x16,
+       QLCNIC_HW_TMR_CRB_AGT_ADR = 0x17,
+       QLCNIC_HW_XDMA_CRB_AGT_ADR = 0x05,
+       QLCNIC_HW_OCM0_CRB_AGT_ADR = 0x06,
+       QLCNIC_HW_OCM1_CRB_AGT_ADR = 0x07
+};
+
+/*  Floaters - non existent modules */
+#define QLCNIC_HW_EFC_RPMX0_CRB_AGT_ADR        0x67
+
+/*  This field defines PCI/X adr [25:20] of agents on the CRB */
+enum {
+       QLCNIC_HW_PX_MAP_CRB_PH = 0,
+       QLCNIC_HW_PX_MAP_CRB_PS,
+       QLCNIC_HW_PX_MAP_CRB_MN,
+       QLCNIC_HW_PX_MAP_CRB_MS,
+       QLCNIC_HW_PX_MAP_CRB_PGR1,
+       QLCNIC_HW_PX_MAP_CRB_SRE,
+       QLCNIC_HW_PX_MAP_CRB_NIU,
+       QLCNIC_HW_PX_MAP_CRB_QMN,
+       QLCNIC_HW_PX_MAP_CRB_SQN0,
+       QLCNIC_HW_PX_MAP_CRB_SQN1,
+       QLCNIC_HW_PX_MAP_CRB_SQN2,
+       QLCNIC_HW_PX_MAP_CRB_SQN3,
+       QLCNIC_HW_PX_MAP_CRB_QMS,
+       QLCNIC_HW_PX_MAP_CRB_SQS0,
+       QLCNIC_HW_PX_MAP_CRB_SQS1,
+       QLCNIC_HW_PX_MAP_CRB_SQS2,
+       QLCNIC_HW_PX_MAP_CRB_SQS3,
+       QLCNIC_HW_PX_MAP_CRB_PGN0,
+       QLCNIC_HW_PX_MAP_CRB_PGN1,
+       QLCNIC_HW_PX_MAP_CRB_PGN2,
+       QLCNIC_HW_PX_MAP_CRB_PGN3,
+       QLCNIC_HW_PX_MAP_CRB_PGND,
+       QLCNIC_HW_PX_MAP_CRB_PGNI,
+       QLCNIC_HW_PX_MAP_CRB_PGS0,
+       QLCNIC_HW_PX_MAP_CRB_PGS1,
+       QLCNIC_HW_PX_MAP_CRB_PGS2,
+       QLCNIC_HW_PX_MAP_CRB_PGS3,
+       QLCNIC_HW_PX_MAP_CRB_PGSD,
+       QLCNIC_HW_PX_MAP_CRB_PGSI,
+       QLCNIC_HW_PX_MAP_CRB_SN,
+       QLCNIC_HW_PX_MAP_CRB_PGR2,
+       QLCNIC_HW_PX_MAP_CRB_EG,
+       QLCNIC_HW_PX_MAP_CRB_PH2,
+       QLCNIC_HW_PX_MAP_CRB_PS2,
+       QLCNIC_HW_PX_MAP_CRB_CAM,
+       QLCNIC_HW_PX_MAP_CRB_CAS0,
+       QLCNIC_HW_PX_MAP_CRB_CAS1,
+       QLCNIC_HW_PX_MAP_CRB_CAS2,
+       QLCNIC_HW_PX_MAP_CRB_C2C0,
+       QLCNIC_HW_PX_MAP_CRB_C2C1,
+       QLCNIC_HW_PX_MAP_CRB_TIMR,
+       QLCNIC_HW_PX_MAP_CRB_PGR3,
+       QLCNIC_HW_PX_MAP_CRB_RPMX1,
+       QLCNIC_HW_PX_MAP_CRB_RPMX2,
+       QLCNIC_HW_PX_MAP_CRB_RPMX3,
+       QLCNIC_HW_PX_MAP_CRB_RPMX4,
+       QLCNIC_HW_PX_MAP_CRB_RPMX5,
+       QLCNIC_HW_PX_MAP_CRB_RPMX6,
+       QLCNIC_HW_PX_MAP_CRB_RPMX7,
+       QLCNIC_HW_PX_MAP_CRB_XDMA,
+       QLCNIC_HW_PX_MAP_CRB_I2Q,
+       QLCNIC_HW_PX_MAP_CRB_ROMUSB,
+       QLCNIC_HW_PX_MAP_CRB_CAS3,
+       QLCNIC_HW_PX_MAP_CRB_RPMX0,
+       QLCNIC_HW_PX_MAP_CRB_RPMX8,
+       QLCNIC_HW_PX_MAP_CRB_RPMX9,
+       QLCNIC_HW_PX_MAP_CRB_OCM0,
+       QLCNIC_HW_PX_MAP_CRB_OCM1,
+       QLCNIC_HW_PX_MAP_CRB_SMB,
+       QLCNIC_HW_PX_MAP_CRB_I2C0,
+       QLCNIC_HW_PX_MAP_CRB_I2C1,
+       QLCNIC_HW_PX_MAP_CRB_LPC,
+       QLCNIC_HW_PX_MAP_CRB_PGNC,
+       QLCNIC_HW_PX_MAP_CRB_PGR0
+};
+
+/*  This field defines CRB adr [31:20] of the agents */
+
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_MN   \
+       ((QLCNIC_HW_H0_CH_HUB_ADR << 7) | QLCNIC_HW_MN_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_PH   \
+       ((QLCNIC_HW_H0_CH_HUB_ADR << 7) | QLCNIC_HW_PH_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_MS   \
+       ((QLCNIC_HW_H0_CH_HUB_ADR << 7) | QLCNIC_HW_MS_CRB_AGT_ADR)
+
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_PS   \
+       ((QLCNIC_HW_H1_CH_HUB_ADR << 7) | QLCNIC_HW_PS_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_SS   \
+       ((QLCNIC_HW_H1_CH_HUB_ADR << 7) | QLCNIC_HW_SS_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX3        \
+       ((QLCNIC_HW_H1_CH_HUB_ADR << 7) | QLCNIC_HW_RPMX3_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_QMS  \
+       ((QLCNIC_HW_H1_CH_HUB_ADR << 7) | QLCNIC_HW_QMS_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_SQS0 \
+       ((QLCNIC_HW_H1_CH_HUB_ADR << 7) | QLCNIC_HW_SQGS0_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_SQS1 \
+       ((QLCNIC_HW_H1_CH_HUB_ADR << 7) | QLCNIC_HW_SQGS1_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_SQS2 \
+       ((QLCNIC_HW_H1_CH_HUB_ADR << 7) | QLCNIC_HW_SQGS2_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_SQS3 \
+       ((QLCNIC_HW_H1_CH_HUB_ADR << 7) | QLCNIC_HW_SQGS3_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_C2C0 \
+       ((QLCNIC_HW_H1_CH_HUB_ADR << 7) | QLCNIC_HW_C2C0_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_C2C1 \
+       ((QLCNIC_HW_H1_CH_HUB_ADR << 7) | QLCNIC_HW_C2C1_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX2        \
+       ((QLCNIC_HW_H1_CH_HUB_ADR << 7) | QLCNIC_HW_RPMX2_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX4        \
+       ((QLCNIC_HW_H1_CH_HUB_ADR << 7) | QLCNIC_HW_RPMX4_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX7        \
+       ((QLCNIC_HW_H1_CH_HUB_ADR << 7) | QLCNIC_HW_RPMX7_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX9        \
+       ((QLCNIC_HW_H1_CH_HUB_ADR << 7) | QLCNIC_HW_RPMX9_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_SMB  \
+       ((QLCNIC_HW_H1_CH_HUB_ADR << 7) | QLCNIC_HW_SMB_CRB_AGT_ADR)
+
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_NIU  \
+       ((QLCNIC_HW_H2_CH_HUB_ADR << 7) | QLCNIC_HW_NIU_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_I2C0 \
+       ((QLCNIC_HW_H2_CH_HUB_ADR << 7) | QLCNIC_HW_I2C0_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_I2C1 \
+       ((QLCNIC_HW_H2_CH_HUB_ADR << 7) | QLCNIC_HW_I2C1_CRB_AGT_ADR)
+
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_SRE  \
+       ((QLCNIC_HW_H3_CH_HUB_ADR << 7) | QLCNIC_HW_SRE_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_EG   \
+       ((QLCNIC_HW_H3_CH_HUB_ADR << 7) | QLCNIC_HW_EG_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX0        \
+       ((QLCNIC_HW_H3_CH_HUB_ADR << 7) | QLCNIC_HW_RPMX0_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_QMN  \
+       ((QLCNIC_HW_H3_CH_HUB_ADR << 7) | QLCNIC_HW_QM_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_SQN0 \
+       ((QLCNIC_HW_H3_CH_HUB_ADR << 7) | QLCNIC_HW_SQG0_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_SQN1 \
+       ((QLCNIC_HW_H3_CH_HUB_ADR << 7) | QLCNIC_HW_SQG1_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_SQN2 \
+       ((QLCNIC_HW_H3_CH_HUB_ADR << 7) | QLCNIC_HW_SQG2_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_SQN3 \
+       ((QLCNIC_HW_H3_CH_HUB_ADR << 7) | QLCNIC_HW_SQG3_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX1        \
+       ((QLCNIC_HW_H3_CH_HUB_ADR << 7) | QLCNIC_HW_RPMX1_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX5        \
+       ((QLCNIC_HW_H3_CH_HUB_ADR << 7) | QLCNIC_HW_RPMX5_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX6        \
+       ((QLCNIC_HW_H3_CH_HUB_ADR << 7) | QLCNIC_HW_RPMX6_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX8        \
+       ((QLCNIC_HW_H3_CH_HUB_ADR << 7) | QLCNIC_HW_RPMX8_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_CAS0 \
+       ((QLCNIC_HW_H3_CH_HUB_ADR << 7) | QLCNIC_HW_CAS0_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_CAS1 \
+       ((QLCNIC_HW_H3_CH_HUB_ADR << 7) | QLCNIC_HW_CAS1_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_CAS2 \
+       ((QLCNIC_HW_H3_CH_HUB_ADR << 7) | QLCNIC_HW_CAS2_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_CAS3 \
+       ((QLCNIC_HW_H3_CH_HUB_ADR << 7) | QLCNIC_HW_CAS3_CRB_AGT_ADR)
+
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGNI \
+       ((QLCNIC_HW_H4_CH_HUB_ADR << 7) | QLCNIC_HW_PEGNI_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGND \
+       ((QLCNIC_HW_H4_CH_HUB_ADR << 7) | QLCNIC_HW_PEGND_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGN0 \
+       ((QLCNIC_HW_H4_CH_HUB_ADR << 7) | QLCNIC_HW_PEGN0_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGN1 \
+       ((QLCNIC_HW_H4_CH_HUB_ADR << 7) | QLCNIC_HW_PEGN1_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGN2 \
+       ((QLCNIC_HW_H4_CH_HUB_ADR << 7) | QLCNIC_HW_PEGN2_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGN3 \
+       ((QLCNIC_HW_H4_CH_HUB_ADR << 7) | QLCNIC_HW_PEGN3_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGN4 \
+       ((QLCNIC_HW_H4_CH_HUB_ADR << 7) | QLCNIC_HW_PEGN4_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGNC \
+       ((QLCNIC_HW_H4_CH_HUB_ADR << 7) | QLCNIC_HW_PEGNC_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGR0 \
+       ((QLCNIC_HW_H4_CH_HUB_ADR << 7) | QLCNIC_HW_PEGR0_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGR1 \
+       ((QLCNIC_HW_H4_CH_HUB_ADR << 7) | QLCNIC_HW_PEGR1_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGR2 \
+       ((QLCNIC_HW_H4_CH_HUB_ADR << 7) | QLCNIC_HW_PEGR2_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGR3 \
+       ((QLCNIC_HW_H4_CH_HUB_ADR << 7) | QLCNIC_HW_PEGR3_CRB_AGT_ADR)
+
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGSI \
+       ((QLCNIC_HW_H5_CH_HUB_ADR << 7) | QLCNIC_HW_PEGSI_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGSD \
+       ((QLCNIC_HW_H5_CH_HUB_ADR << 7) | QLCNIC_HW_PEGSD_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGS0 \
+       ((QLCNIC_HW_H5_CH_HUB_ADR << 7) | QLCNIC_HW_PEGS0_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGS1 \
+       ((QLCNIC_HW_H5_CH_HUB_ADR << 7) | QLCNIC_HW_PEGS1_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGS2 \
+       ((QLCNIC_HW_H5_CH_HUB_ADR << 7) | QLCNIC_HW_PEGS2_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGS3 \
+       ((QLCNIC_HW_H5_CH_HUB_ADR << 7) | QLCNIC_HW_PEGS3_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_PGSC \
+       ((QLCNIC_HW_H5_CH_HUB_ADR << 7) | QLCNIC_HW_PEGSC_CRB_AGT_ADR)
+
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_CAM  \
+       ((QLCNIC_HW_H6_CH_HUB_ADR << 7) | QLCNIC_HW_NCM_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_TIMR \
+       ((QLCNIC_HW_H6_CH_HUB_ADR << 7) | QLCNIC_HW_TMR_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_XDMA \
+       ((QLCNIC_HW_H6_CH_HUB_ADR << 7) | QLCNIC_HW_XDMA_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_SN   \
+       ((QLCNIC_HW_H6_CH_HUB_ADR << 7) | QLCNIC_HW_SN_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_I2Q  \
+       ((QLCNIC_HW_H6_CH_HUB_ADR << 7) | QLCNIC_HW_I2Q_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_ROMUSB       \
+       ((QLCNIC_HW_H6_CH_HUB_ADR << 7) | QLCNIC_HW_ROMUSB_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_OCM0 \
+       ((QLCNIC_HW_H6_CH_HUB_ADR << 7) | QLCNIC_HW_OCM0_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_OCM1 \
+       ((QLCNIC_HW_H6_CH_HUB_ADR << 7) | QLCNIC_HW_OCM1_CRB_AGT_ADR)
+#define QLCNIC_HW_CRB_HUB_AGT_ADR_LPC  \
+       ((QLCNIC_HW_H6_CH_HUB_ADR << 7) | QLCNIC_HW_LPC_CRB_AGT_ADR)
+
+#define QLCNIC_SRE_MISC                (QLCNIC_CRB_SRE + 0x0002c)
+
+#define QLCNIC_I2Q_CLR_PCI_HI  (QLCNIC_CRB_I2Q + 0x00034)
+
+#define ROMUSB_GLB             (QLCNIC_CRB_ROMUSB + 0x00000)
+#define ROMUSB_ROM             (QLCNIC_CRB_ROMUSB + 0x10000)
+
+#define QLCNIC_ROMUSB_GLB_STATUS       (ROMUSB_GLB + 0x0004)
+#define QLCNIC_ROMUSB_GLB_SW_RESET     (ROMUSB_GLB + 0x0008)
+#define QLCNIC_ROMUSB_GLB_PAD_GPIO_I   (ROMUSB_GLB + 0x000c)
+#define QLCNIC_ROMUSB_GLB_CAS_RST      (ROMUSB_GLB + 0x0038)
+#define QLCNIC_ROMUSB_GLB_TEST_MUX_SEL (ROMUSB_GLB + 0x0044)
+#define QLCNIC_ROMUSB_GLB_PEGTUNE_DONE (ROMUSB_GLB + 0x005c)
+#define QLCNIC_ROMUSB_GLB_CHIP_CLK_CTRL        (ROMUSB_GLB + 0x00A8)
+
+#define QLCNIC_ROMUSB_GPIO(n)          (ROMUSB_GLB + 0x60 + (4 * (n)))
+
+#define QLCNIC_ROMUSB_ROM_INSTR_OPCODE (ROMUSB_ROM + 0x0004)
+#define QLCNIC_ROMUSB_ROM_ADDRESS      (ROMUSB_ROM + 0x0008)
+#define QLCNIC_ROMUSB_ROM_WDATA                (ROMUSB_ROM + 0x000c)
+#define QLCNIC_ROMUSB_ROM_ABYTE_CNT    (ROMUSB_ROM + 0x0010)
+#define QLCNIC_ROMUSB_ROM_DUMMY_BYTE_CNT (ROMUSB_ROM + 0x0014)
+#define QLCNIC_ROMUSB_ROM_RDATA                (ROMUSB_ROM + 0x0018)
+
+/* Lock IDs for ROM lock */
+#define ROM_LOCK_DRIVER        0x0d417340
+
+/******************************************************************************
+*
+*    Definitions specific to M25P flash
+*
+*******************************************************************************
+*/
+
+/* all are 1MB windows */
+
+#define QLCNIC_PCI_CRB_WINDOWSIZE      0x00100000
+#define QLCNIC_PCI_CRB_WINDOW(A)       \
+       (QLCNIC_PCI_CRBSPACE + (A)*QLCNIC_PCI_CRB_WINDOWSIZE)
+
+#define QLCNIC_CRB_NIU         QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_NIU)
+#define QLCNIC_CRB_SRE         QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_SRE)
+#define QLCNIC_CRB_ROMUSB      \
+       QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_ROMUSB)
+#define QLCNIC_CRB_I2Q         QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_I2Q)
+#define QLCNIC_CRB_I2C0        QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_I2C0)
+#define QLCNIC_CRB_SMB         QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_SMB)
+#define QLCNIC_CRB_MAX         QLCNIC_PCI_CRB_WINDOW(64)
+
+#define QLCNIC_CRB_PCIX_HOST   QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_PH)
+#define QLCNIC_CRB_PCIX_HOST2  QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_PH2)
+#define QLCNIC_CRB_PEG_NET_0   QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_PGN0)
+#define QLCNIC_CRB_PEG_NET_1   QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_PGN1)
+#define QLCNIC_CRB_PEG_NET_2   QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_PGN2)
+#define QLCNIC_CRB_PEG_NET_3   QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_PGN3)
+#define QLCNIC_CRB_PEG_NET_4   QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_SQS2)
+#define QLCNIC_CRB_PEG_NET_D   QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_PGND)
+#define QLCNIC_CRB_PEG_NET_I   QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_PGNI)
+#define QLCNIC_CRB_DDR_NET     QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_MN)
+#define QLCNIC_CRB_QDR_NET     QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_SN)
+
+#define QLCNIC_CRB_PCIX_MD     QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_PS)
+#define QLCNIC_CRB_PCIE        QLCNIC_CRB_PCIX_MD
+
+#define ISR_INT_VECTOR         (QLCNIC_PCIX_PS_REG(PCIX_INT_VECTOR))
+#define ISR_INT_MASK           (QLCNIC_PCIX_PS_REG(PCIX_INT_MASK))
+#define ISR_INT_MASK_SLOW      (QLCNIC_PCIX_PS_REG(PCIX_INT_MASK))
+#define ISR_INT_TARGET_STATUS  (QLCNIC_PCIX_PS_REG(PCIX_TARGET_STATUS))
+#define ISR_INT_TARGET_MASK    (QLCNIC_PCIX_PS_REG(PCIX_TARGET_MASK))
+#define ISR_INT_TARGET_STATUS_F1   (QLCNIC_PCIX_PS_REG(PCIX_TARGET_STATUS_F1))
+#define ISR_INT_TARGET_MASK_F1     (QLCNIC_PCIX_PS_REG(PCIX_TARGET_MASK_F1))
+#define ISR_INT_TARGET_STATUS_F2   (QLCNIC_PCIX_PS_REG(PCIX_TARGET_STATUS_F2))
+#define ISR_INT_TARGET_MASK_F2     (QLCNIC_PCIX_PS_REG(PCIX_TARGET_MASK_F2))
+#define ISR_INT_TARGET_STATUS_F3   (QLCNIC_PCIX_PS_REG(PCIX_TARGET_STATUS_F3))
+#define ISR_INT_TARGET_MASK_F3     (QLCNIC_PCIX_PS_REG(PCIX_TARGET_MASK_F3))
+#define ISR_INT_TARGET_STATUS_F4   (QLCNIC_PCIX_PS_REG(PCIX_TARGET_STATUS_F4))
+#define ISR_INT_TARGET_MASK_F4     (QLCNIC_PCIX_PS_REG(PCIX_TARGET_MASK_F4))
+#define ISR_INT_TARGET_STATUS_F5   (QLCNIC_PCIX_PS_REG(PCIX_TARGET_STATUS_F5))
+#define ISR_INT_TARGET_MASK_F5     (QLCNIC_PCIX_PS_REG(PCIX_TARGET_MASK_F5))
+#define ISR_INT_TARGET_STATUS_F6   (QLCNIC_PCIX_PS_REG(PCIX_TARGET_STATUS_F6))
+#define ISR_INT_TARGET_MASK_F6     (QLCNIC_PCIX_PS_REG(PCIX_TARGET_MASK_F6))
+#define ISR_INT_TARGET_STATUS_F7   (QLCNIC_PCIX_PS_REG(PCIX_TARGET_STATUS_F7))
+#define ISR_INT_TARGET_MASK_F7     (QLCNIC_PCIX_PS_REG(PCIX_TARGET_MASK_F7))
+
+#define QLCNIC_PCI_MN_2M       (0)
+#define QLCNIC_PCI_MS_2M       (0x80000)
+#define QLCNIC_PCI_OCM0_2M     (0x000c0000UL)
+#define QLCNIC_PCI_CRBSPACE    (0x06000000UL)
+#define QLCNIC_PCI_2MB_SIZE    (0x00200000UL)
+#define QLCNIC_PCI_CAMQM_2M_BASE       (0x000ff800UL)
+#define QLCNIC_PCI_CAMQM_2M_END        (0x04800800UL)
+
+#define QLCNIC_CRB_CAM QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_CAM)
+
+#define QLCNIC_ADDR_DDR_NET    (0x0000000000000000ULL)
+#define QLCNIC_ADDR_DDR_NET_MAX (0x000000000fffffffULL)
+#define QLCNIC_ADDR_OCM0       (0x0000000200000000ULL)
+#define QLCNIC_ADDR_OCM0_MAX   (0x00000002000fffffULL)
+#define QLCNIC_ADDR_OCM1       (0x0000000200400000ULL)
+#define QLCNIC_ADDR_OCM1_MAX   (0x00000002004fffffULL)
+#define QLCNIC_ADDR_QDR_NET    (0x0000000300000000ULL)
+#define QLCNIC_ADDR_QDR_NET_MAX_P3 (0x0000000303ffffffULL)
+
+/*
+ *   Register offsets for MN
+ */
+#define QLCNIC_MIU_CONTROL     (0x000)
+#define QLCNIC_MIU_MN_CONTROL  (QLCNIC_CRB_DDR_NET+QLCNIC_MIU_CONTROL)
+
+/* 200ms delay in each loop */
+#define QLCNIC_NIU_PHY_WAITLEN         200000
+/* 10 seconds before we give up */
+#define QLCNIC_NIU_PHY_WAITMAX         50
+#define QLCNIC_NIU_MAX_GBE_PORTS       4
+#define QLCNIC_NIU_MAX_XG_PORTS                2
+
+#define QLCNIC_NIU_MODE                        (QLCNIC_CRB_NIU + 0x00000)
+#define QLCNIC_NIU_GB_PAUSE_CTL                (QLCNIC_CRB_NIU + 0x0030c)
+#define QLCNIC_NIU_XG_PAUSE_CTL                (QLCNIC_CRB_NIU + 0x00098)
+
+#define QLCNIC_NIU_GB_MAC_CONFIG_0(I)          \
+               (QLCNIC_CRB_NIU + 0x30000 + (I)*0x10000)
+#define QLCNIC_NIU_GB_MAC_CONFIG_1(I)          \
+               (QLCNIC_CRB_NIU + 0x30004 + (I)*0x10000)
+
+
+#define TEST_AGT_CTRL  (0x00)
+
+#define TA_CTL_START   1
+#define TA_CTL_ENABLE  2
+#define TA_CTL_WRITE   4
+#define TA_CTL_BUSY    8
+
+/*
+ *   Register offsets for MN
+ */
+#define MIU_TEST_AGT_BASE              (0x90)
+
+#define MIU_TEST_AGT_ADDR_LO           (0x04)
+#define MIU_TEST_AGT_ADDR_HI           (0x08)
+#define MIU_TEST_AGT_WRDATA_LO         (0x10)
+#define MIU_TEST_AGT_WRDATA_HI         (0x14)
+#define MIU_TEST_AGT_WRDATA_UPPER_LO   (0x20)
+#define MIU_TEST_AGT_WRDATA_UPPER_HI   (0x24)
+#define MIU_TEST_AGT_WRDATA(i)         (0x10+(0x10*((i)>>1))+(4*((i)&1)))
+#define MIU_TEST_AGT_RDDATA_LO         (0x18)
+#define MIU_TEST_AGT_RDDATA_HI         (0x1c)
+#define MIU_TEST_AGT_RDDATA_UPPER_LO   (0x28)
+#define MIU_TEST_AGT_RDDATA_UPPER_HI   (0x2c)
+#define MIU_TEST_AGT_RDDATA(i)         (0x18+(0x10*((i)>>1))+(4*((i)&1)))
+
+#define MIU_TEST_AGT_ADDR_MASK         0xfffffff8
+#define MIU_TEST_AGT_UPPER_ADDR(off)   (0)
+
+/*
+ *   Register offsets for MS
+ */
+#define SIU_TEST_AGT_BASE              (0x60)
+
+#define SIU_TEST_AGT_ADDR_LO           (0x04)
+#define SIU_TEST_AGT_ADDR_HI           (0x18)
+#define SIU_TEST_AGT_WRDATA_LO         (0x08)
+#define SIU_TEST_AGT_WRDATA_HI         (0x0c)
+#define SIU_TEST_AGT_WRDATA(i)         (0x08+(4*(i)))
+#define SIU_TEST_AGT_RDDATA_LO         (0x10)
+#define SIU_TEST_AGT_RDDATA_HI         (0x14)
+#define SIU_TEST_AGT_RDDATA(i)         (0x10+(4*(i)))
+
+#define SIU_TEST_AGT_ADDR_MASK         0x3ffff8
+#define SIU_TEST_AGT_UPPER_ADDR(off)   ((off)>>22)
+
+/* XG Link status */
+#define XG_LINK_UP     0x10
+#define XG_LINK_DOWN   0x20
+
+#define XG_LINK_UP_P3  0x01
+#define XG_LINK_DOWN_P3        0x02
+#define XG_LINK_STATE_P3_MASK 0xf
+#define XG_LINK_STATE_P3(pcifn, val) \
+       (((val) >> ((pcifn) * 4)) & XG_LINK_STATE_P3_MASK)
+
+#define P3_LINK_SPEED_MHZ      100
+#define P3_LINK_SPEED_MASK     0xff
+#define P3_LINK_SPEED_REG(pcifn)       \
+       (CRB_PF_LINK_SPEED_1 + (((pcifn) / 4) * 4))
+#define P3_LINK_SPEED_VAL(pcifn, reg)  \
+       (((reg) >> (8 * ((pcifn) & 0x3))) & P3_LINK_SPEED_MASK)
+
+#define QLCNIC_CAM_RAM_BASE    (QLCNIC_CRB_CAM + 0x02000)
+#define QLCNIC_CAM_RAM(reg)    (QLCNIC_CAM_RAM_BASE + (reg))
+#define QLCNIC_FW_VERSION_MAJOR (QLCNIC_CAM_RAM(0x150))
+#define QLCNIC_FW_VERSION_MINOR (QLCNIC_CAM_RAM(0x154))
+#define QLCNIC_FW_VERSION_SUB  (QLCNIC_CAM_RAM(0x158))
+#define QLCNIC_ROM_LOCK_ID     (QLCNIC_CAM_RAM(0x100))
+#define QLCNIC_PHY_LOCK_ID     (QLCNIC_CAM_RAM(0x120))
+#define QLCNIC_CRB_WIN_LOCK_ID (QLCNIC_CAM_RAM(0x124))
+
+#define NIC_CRB_BASE           (QLCNIC_CAM_RAM(0x200))
+#define NIC_CRB_BASE_2         (QLCNIC_CAM_RAM(0x700))
+#define QLCNIC_REG(X)          (NIC_CRB_BASE+(X))
+#define QLCNIC_REG_2(X)        (NIC_CRB_BASE_2+(X))
+
+#define QLCNIC_CDRP_CRB_OFFSET         (QLCNIC_REG(0x18))
+#define QLCNIC_ARG1_CRB_OFFSET         (QLCNIC_REG(0x1c))
+#define QLCNIC_ARG2_CRB_OFFSET         (QLCNIC_REG(0x20))
+#define QLCNIC_ARG3_CRB_OFFSET         (QLCNIC_REG(0x24))
+#define QLCNIC_SIGN_CRB_OFFSET         (QLCNIC_REG(0x28))
+
+#define CRB_CMDPEG_STATE               (QLCNIC_REG(0x50))
+#define CRB_RCVPEG_STATE               (QLCNIC_REG(0x13c))
+
+#define CRB_XG_STATE_P3                (QLCNIC_REG(0x98))
+#define CRB_PF_LINK_SPEED_1            (QLCNIC_REG(0xe8))
+#define CRB_PF_LINK_SPEED_2            (QLCNIC_REG(0xec))
+
+#define CRB_MPORT_MODE                 (QLCNIC_REG(0xc4))
+#define CRB_DMA_SHIFT                  (QLCNIC_REG(0xcc))
+
+#define CRB_TEMP_STATE                 (QLCNIC_REG(0x1b4))
+
+#define CRB_V2P_0                      (QLCNIC_REG(0x290))
+#define CRB_V2P(port)                  (CRB_V2P_0+((port)*4))
+#define CRB_DRIVER_VERSION             (QLCNIC_REG(0x2a0))
+
+#define CRB_SW_INT_MASK_0              (QLCNIC_REG(0x1d8))
+#define CRB_SW_INT_MASK_1              (QLCNIC_REG(0x1e0))
+#define CRB_SW_INT_MASK_2              (QLCNIC_REG(0x1e4))
+#define CRB_SW_INT_MASK_3              (QLCNIC_REG(0x1e8))
+
+#define CRB_FW_CAPABILITIES_1          (QLCNIC_CAM_RAM(0x128))
+#define CRB_MAC_BLOCK_START            (QLCNIC_CAM_RAM(0x1c0))
+
+/*
+ * capabilities register, can be used to selectively enable/disable features
+ * for backward compability
+ */
+#define CRB_NIC_CAPABILITIES_HOST      QLCNIC_REG(0x1a8)
+#define CRB_NIC_CAPABILITIES_FW        QLCNIC_REG(0x1dc)
+#define CRB_NIC_MSI_MODE_HOST          QLCNIC_REG(0x270)
+#define CRB_NIC_MSI_MODE_FW            QLCNIC_REG(0x274)
+
+#define INTR_SCHEME_PERPORT            0x1
+#define MSI_MODE_MULTIFUNC             0x1
+
+/* used for ethtool tests */
+#define CRB_SCRATCHPAD_TEST        QLCNIC_REG(0x280)
+
+/*
+ * CrbPortPhanCntrHi/Lo is used to pass the address of HostPhantomIndex address
+ * which can be read by the Phantom host to get producer/consumer indexes from
+ * Phantom/Casper. If it is not HOST_SHARED_MEMORY, then the following
+ * registers will be used for the addresses of the ring's shared memory
+ * on the Phantom.
+ */
+
+#define qlcnic_get_temp_val(x)         ((x) >> 16)
+#define qlcnic_get_temp_state(x)       ((x) & 0xffff)
+#define qlcnic_encode_temp(val, state) (((val) << 16) | (state))
+
+/*
+ * Temperature control.
+ */
+enum {
+       QLCNIC_TEMP_NORMAL = 0x1,       /* Normal operating range */
+       QLCNIC_TEMP_WARN,       /* Sound alert, temperature getting high */
+       QLCNIC_TEMP_PANIC       /* Fatal error, hardware has shut down. */
+};
+
+/* Lock IDs for PHY lock */
+#define PHY_LOCK_DRIVER                0x44524956
+
+/* Used for PS PCI Memory access */
+#define PCIX_PS_OP_ADDR_LO     (0x10000)
+/*   via CRB  (PS side only)     */
+#define PCIX_PS_OP_ADDR_HI     (0x10004)
+
+#define PCIX_INT_VECTOR        (0x10100)
+#define PCIX_INT_MASK          (0x10104)
+
+#define PCIX_OCM_WINDOW                (0x10800)
+#define PCIX_OCM_WINDOW_REG(func)      (PCIX_OCM_WINDOW + 0x20 * (func))
+
+#define PCIX_TARGET_STATUS     (0x10118)
+#define PCIX_TARGET_STATUS_F1  (0x10160)
+#define PCIX_TARGET_STATUS_F2  (0x10164)
+#define PCIX_TARGET_STATUS_F3  (0x10168)
+#define PCIX_TARGET_STATUS_F4  (0x10360)
+#define PCIX_TARGET_STATUS_F5  (0x10364)
+#define PCIX_TARGET_STATUS_F6  (0x10368)
+#define PCIX_TARGET_STATUS_F7  (0x1036c)
+
+#define PCIX_TARGET_MASK       (0x10128)
+#define PCIX_TARGET_MASK_F1    (0x10170)
+#define PCIX_TARGET_MASK_F2    (0x10174)
+#define PCIX_TARGET_MASK_F3    (0x10178)
+#define PCIX_TARGET_MASK_F4    (0x10370)
+#define PCIX_TARGET_MASK_F5    (0x10374)
+#define PCIX_TARGET_MASK_F6    (0x10378)
+#define PCIX_TARGET_MASK_F7    (0x1037c)
+
+#define PCIX_MSI_F(i)          (0x13000+((i)*4))
+
+#define QLCNIC_PCIX_PH_REG(reg)        (QLCNIC_CRB_PCIE + (reg))
+#define QLCNIC_PCIX_PS_REG(reg)        (QLCNIC_CRB_PCIX_MD + (reg))
+#define QLCNIC_PCIE_REG(reg)   (QLCNIC_CRB_PCIE + (reg))
+
+#define PCIE_SEM0_LOCK         (0x1c000)
+#define PCIE_SEM0_UNLOCK       (0x1c004)
+#define PCIE_SEM_LOCK(N)       (PCIE_SEM0_LOCK + 8*(N))
+#define PCIE_SEM_UNLOCK(N)     (PCIE_SEM0_UNLOCK + 8*(N))
+
+#define PCIE_SETUP_FUNCTION    (0x12040)
+#define PCIE_SETUP_FUNCTION2   (0x12048)
+#define PCIE_MISCCFG_RC         (0x1206c)
+#define PCIE_TGT_SPLIT_CHICKEN (0x12080)
+#define PCIE_CHICKEN3          (0x120c8)
+
+#define ISR_INT_STATE_REG       (QLCNIC_PCIX_PS_REG(PCIE_MISCCFG_RC))
+#define PCIE_MAX_MASTER_SPLIT  (0x14048)
+
+#define QLCNIC_PORT_MODE_NONE          0
+#define QLCNIC_PORT_MODE_XG            1
+#define QLCNIC_PORT_MODE_GB            2
+#define QLCNIC_PORT_MODE_802_3_AP      3
+#define QLCNIC_PORT_MODE_AUTO_NEG      4
+#define QLCNIC_PORT_MODE_AUTO_NEG_1G   5
+#define QLCNIC_PORT_MODE_AUTO_NEG_XG   6
+#define QLCNIC_PORT_MODE_ADDR          (QLCNIC_CAM_RAM(0x24))
+#define QLCNIC_WOL_PORT_MODE           (QLCNIC_CAM_RAM(0x198))
+
+#define QLCNIC_WOL_CONFIG_NV           (QLCNIC_CAM_RAM(0x184))
+#define QLCNIC_WOL_CONFIG              (QLCNIC_CAM_RAM(0x188))
+
+#define QLCNIC_PEG_TUNE_MN_PRESENT     0x1
+#define QLCNIC_PEG_TUNE_CAPABILITY     (QLCNIC_CAM_RAM(0x02c))
+
+#define QLCNIC_DMA_WATCHDOG_CTRL       (QLCNIC_CAM_RAM(0x14))
+#define QLCNIC_PEG_ALIVE_COUNTER       (QLCNIC_CAM_RAM(0xb0))
+#define QLCNIC_PEG_HALT_STATUS1        (QLCNIC_CAM_RAM(0xa8))
+#define QLCNIC_PEG_HALT_STATUS2        (QLCNIC_CAM_RAM(0xac))
+#define QLCNIC_CRB_DEV_REF_COUNT       (QLCNIC_CAM_RAM(0x138))
+#define QLCNIC_CRB_DEV_STATE           (QLCNIC_CAM_RAM(0x140))
+
+#define QLCNIC_CRB_DRV_STATE               (QLCNIC_CAM_RAM(0x144))
+#define QLCNIC_CRB_DRV_SCRATCH             (QLCNIC_CAM_RAM(0x148))
+#define QLCNIC_CRB_DEV_PARTITION_INFO      (QLCNIC_CAM_RAM(0x14c))
+#define QLCNIC_CRB_DRV_IDC_VER             (QLCNIC_CAM_RAM(0x14c))
+
+                /* Device State */
+#define QLCNIC_DEV_COLD                1
+#define QLCNIC_DEV_INITALIZING         2
+#define QLCNIC_DEV_READY               3
+#define QLCNIC_DEV_NEED_RESET          4
+#define QLCNIC_DEV_NEED_QUISCENT       5
+#define QLCNIC_DEV_FAILED              6
+
+#define QLCNIC_RCODE_DRIVER_INFO               0x20000000
+#define QLCNIC_RCODE_DRIVER_CAN_RELOAD         0x40000000
+#define QLCNIC_RCODE_FATAL_ERROR               0x80000000
+#define QLCNIC_FWERROR_PEGNUM(code)            ((code) & 0xff)
+#define QLCNIC_FWERROR_CODE(code)              ((code >> 8) & 0xfffff)
+
+#define FW_POLL_DELAY                  (2 * HZ)
+#define FW_FAIL_THRESH                 3
+#define FW_POLL_THRESH                 10
+
+#define        ISR_MSI_INT_TRIGGER(FUNC) (QLCNIC_PCIX_PS_REG(PCIX_MSI_F(FUNC)))
+#define ISR_LEGACY_INT_TRIGGERED(VAL)  (((VAL) & 0x300) == 0x200)
+
+/*
+ * PCI Interrupt Vector Values.
+ */
+#define        PCIX_INT_VECTOR_BIT_F0  0x0080
+#define        PCIX_INT_VECTOR_BIT_F1  0x0100
+#define        PCIX_INT_VECTOR_BIT_F2  0x0200
+#define        PCIX_INT_VECTOR_BIT_F3  0x0400
+#define        PCIX_INT_VECTOR_BIT_F4  0x0800
+#define        PCIX_INT_VECTOR_BIT_F5  0x1000
+#define        PCIX_INT_VECTOR_BIT_F6  0x2000
+#define        PCIX_INT_VECTOR_BIT_F7  0x4000
+
+struct qlcnic_legacy_intr_set {
+       u32     int_vec_bit;
+       u32     tgt_status_reg;
+       u32     tgt_mask_reg;
+       u32     pci_int_reg;
+};
+
+#define        QLCNIC_LEGACY_INTR_CONFIG                                       \
+{                                                                      \
+       {                                                               \
+               .int_vec_bit    =       PCIX_INT_VECTOR_BIT_F0,         \
+               .tgt_status_reg =       ISR_INT_TARGET_STATUS,          \
+               .tgt_mask_reg   =       ISR_INT_TARGET_MASK,            \
+               .pci_int_reg    =       ISR_MSI_INT_TRIGGER(0) },       \
+                                                                       \
+       {                                                               \
+               .int_vec_bit    =       PCIX_INT_VECTOR_BIT_F1,         \
+               .tgt_status_reg =       ISR_INT_TARGET_STATUS_F1,       \
+               .tgt_mask_reg   =       ISR_INT_TARGET_MASK_F1,         \
+               .pci_int_reg    =       ISR_MSI_INT_TRIGGER(1) },       \
+                                                                       \
+       {                                                               \
+               .int_vec_bit    =       PCIX_INT_VECTOR_BIT_F2,         \
+               .tgt_status_reg =       ISR_INT_TARGET_STATUS_F2,       \
+               .tgt_mask_reg   =       ISR_INT_TARGET_MASK_F2,         \
+               .pci_int_reg    =       ISR_MSI_INT_TRIGGER(2) },       \
+                                                                       \
+       {                                                               \
+               .int_vec_bit    =       PCIX_INT_VECTOR_BIT_F3,         \
+               .tgt_status_reg =       ISR_INT_TARGET_STATUS_F3,       \
+               .tgt_mask_reg   =       ISR_INT_TARGET_MASK_F3,         \
+               .pci_int_reg    =       ISR_MSI_INT_TRIGGER(3) },       \
+                                                                       \
+       {                                                               \
+               .int_vec_bit    =       PCIX_INT_VECTOR_BIT_F4,         \
+               .tgt_status_reg =       ISR_INT_TARGET_STATUS_F4,       \
+               .tgt_mask_reg   =       ISR_INT_TARGET_MASK_F4,         \
+               .pci_int_reg    =       ISR_MSI_INT_TRIGGER(4) },       \
+                                                                       \
+       {                                                               \
+               .int_vec_bit    =       PCIX_INT_VECTOR_BIT_F5,         \
+               .tgt_status_reg =       ISR_INT_TARGET_STATUS_F5,       \
+               .tgt_mask_reg   =       ISR_INT_TARGET_MASK_F5,         \
+               .pci_int_reg    =       ISR_MSI_INT_TRIGGER(5) },       \
+                                                                       \
+       {                                                               \
+               .int_vec_bit    =       PCIX_INT_VECTOR_BIT_F6,         \
+               .tgt_status_reg =       ISR_INT_TARGET_STATUS_F6,       \
+               .tgt_mask_reg   =       ISR_INT_TARGET_MASK_F6,         \
+               .pci_int_reg    =       ISR_MSI_INT_TRIGGER(6) },       \
+                                                                       \
+       {                                                               \
+               .int_vec_bit    =       PCIX_INT_VECTOR_BIT_F7,         \
+               .tgt_status_reg =       ISR_INT_TARGET_STATUS_F7,       \
+               .tgt_mask_reg   =       ISR_INT_TARGET_MASK_F7,         \
+               .pci_int_reg    =       ISR_MSI_INT_TRIGGER(7) },       \
+}
+
+/* NIU REGS */
+
+#define _qlcnic_crb_get_bit(var, bit)  ((var >> bit) & 0x1)
+
+/*
+ * NIU GB MAC Config Register 0 (applies to GB0, GB1, GB2, GB3)
+ *
+ *     Bit 0 : enable_tx => 1:enable frame xmit, 0:disable
+ *     Bit 1 : tx_synced => R/O: xmit enable synched to xmit stream
+ *     Bit 2 : enable_rx => 1:enable frame recv, 0:disable
+ *     Bit 3 : rx_synced => R/O: recv enable synched to recv stream
+ *     Bit 4 : tx_flowctl => 1:enable pause frame generation, 0:disable
+ *     Bit 5 : rx_flowctl => 1:act on recv'd pause frames, 0:ignore
+ *     Bit 8 : loopback => 1:loop MAC xmits to MAC recvs, 0:normal
+ *     Bit 16: tx_reset_pb => 1:reset frame xmit protocol blk, 0:no-op
+ *     Bit 17: rx_reset_pb => 1:reset frame recv protocol blk, 0:no-op
+ *     Bit 18: tx_reset_mac => 1:reset data/ctl multiplexer blk, 0:no-op
+ *     Bit 19: rx_reset_mac => 1:reset ctl frames & timers blk, 0:no-op
+ *     Bit 31: soft_reset => 1:reset the MAC and the SERDES, 0:no-op
+ */
+#define qlcnic_gb_rx_flowctl(config_word)      \
+       ((config_word) |= 1 << 5)
+#define qlcnic_gb_get_rx_flowctl(config_word)  \
+       _qlcnic_crb_get_bit((config_word), 5)
+#define qlcnic_gb_unset_rx_flowctl(config_word)        \
+       ((config_word) &= ~(1 << 5))
+
+/*
+ * NIU GB Pause Ctl Register
+ */
+
+#define qlcnic_gb_set_gb0_mask(config_word)    \
+       ((config_word) |= 1 << 0)
+#define qlcnic_gb_set_gb1_mask(config_word)    \
+       ((config_word) |= 1 << 2)
+#define qlcnic_gb_set_gb2_mask(config_word)    \
+       ((config_word) |= 1 << 4)
+#define qlcnic_gb_set_gb3_mask(config_word)    \
+       ((config_word) |= 1 << 6)
+
+#define qlcnic_gb_get_gb0_mask(config_word)    \
+       _qlcnic_crb_get_bit((config_word), 0)
+#define qlcnic_gb_get_gb1_mask(config_word)    \
+       _qlcnic_crb_get_bit((config_word), 2)
+#define qlcnic_gb_get_gb2_mask(config_word)    \
+       _qlcnic_crb_get_bit((config_word), 4)
+#define qlcnic_gb_get_gb3_mask(config_word)    \
+       _qlcnic_crb_get_bit((config_word), 6)
+
+#define qlcnic_gb_unset_gb0_mask(config_word)  \
+       ((config_word) &= ~(1 << 0))
+#define qlcnic_gb_unset_gb1_mask(config_word)  \
+       ((config_word) &= ~(1 << 2))
+#define qlcnic_gb_unset_gb2_mask(config_word)  \
+       ((config_word) &= ~(1 << 4))
+#define qlcnic_gb_unset_gb3_mask(config_word)  \
+       ((config_word) &= ~(1 << 6))
+
+/*
+ * NIU XG Pause Ctl Register
+ *
+ *      Bit 0       : xg0_mask => 1:disable tx pause frames
+ *      Bit 1       : xg0_request => 1:request single pause frame
+ *      Bit 2       : xg0_on_off => 1:request is pause on, 0:off
+ *      Bit 3       : xg1_mask => 1:disable tx pause frames
+ *      Bit 4       : xg1_request => 1:request single pause frame
+ *      Bit 5       : xg1_on_off => 1:request is pause on, 0:off
+ */
+
+#define qlcnic_xg_set_xg0_mask(config_word)    \
+       ((config_word) |= 1 << 0)
+#define qlcnic_xg_set_xg1_mask(config_word)    \
+       ((config_word) |= 1 << 3)
+
+#define qlcnic_xg_get_xg0_mask(config_word)    \
+       _qlcnic_crb_get_bit((config_word), 0)
+#define qlcnic_xg_get_xg1_mask(config_word)    \
+       _qlcnic_crb_get_bit((config_word), 3)
+
+#define qlcnic_xg_unset_xg0_mask(config_word)  \
+       ((config_word) &= ~(1 << 0))
+#define qlcnic_xg_unset_xg1_mask(config_word)  \
+       ((config_word) &= ~(1 << 3))
+
+/*
+ * NIU XG Pause Ctl Register
+ *
+ *      Bit 0       : xg0_mask => 1:disable tx pause frames
+ *      Bit 1       : xg0_request => 1:request single pause frame
+ *      Bit 2       : xg0_on_off => 1:request is pause on, 0:off
+ *      Bit 3       : xg1_mask => 1:disable tx pause frames
+ *      Bit 4       : xg1_request => 1:request single pause frame
+ *      Bit 5       : xg1_on_off => 1:request is pause on, 0:off
+ */
+
+/*
+ * PHY-Specific MII control/status registers.
+ */
+#define QLCNIC_NIU_GB_MII_MGMT_ADDR_AUTONEG            4
+#define QLCNIC_NIU_GB_MII_MGMT_ADDR_PHY_STATUS         17
+
+/*
+ * PHY-Specific Status Register (reg 17).
+ *
+ * Bit 0      : jabber => 1:jabber detected, 0:not
+ * Bit 1      : polarity => 1:polarity reversed, 0:normal
+ * Bit 2      : recvpause => 1:receive pause enabled, 0:disabled
+ * Bit 3      : xmitpause => 1:transmit pause enabled, 0:disabled
+ * Bit 4      : energydetect => 1:sleep, 0:active
+ * Bit 5      : downshift => 1:downshift, 0:no downshift
+ * Bit 6      : crossover => 1:MDIX (crossover), 0:MDI (no crossover)
+ * Bits 7-9   : cablelen => not valid in 10Mb/s mode
+ *                     0:<50m, 1:50-80m, 2:80-110m, 3:110-140m, 4:>140m
+ * Bit 10     : link => 1:link up, 0:link down
+ * Bit 11     : resolved => 1:speed and duplex resolved, 0:not yet
+ * Bit 12     : pagercvd => 1:page received, 0:page not received
+ * Bit 13     : duplex => 1:full duplex, 0:half duplex
+ * Bits 14-15 : speed => 0:10Mb/s, 1:100Mb/s, 2:1000Mb/s, 3:rsvd
+ */
+
+#define qlcnic_get_phy_speed(config_word) (((config_word) >> 14) & 0x03)
+
+#define qlcnic_set_phy_speed(config_word, val) \
+               ((config_word) |= ((val & 0x03) << 14))
+#define qlcnic_set_phy_duplex(config_word)     \
+               ((config_word) |= 1 << 13)
+#define qlcnic_clear_phy_duplex(config_word)   \
+               ((config_word) &= ~(1 << 13))
+
+#define qlcnic_get_phy_link(config_word)       \
+               _qlcnic_crb_get_bit(config_word, 10)
+#define qlcnic_get_phy_duplex(config_word)     \
+               _qlcnic_crb_get_bit(config_word, 13)
+
+#define QLCNIC_NIU_NON_PROMISC_MODE    0
+#define QLCNIC_NIU_PROMISC_MODE                1
+#define QLCNIC_NIU_ALLMULTI_MODE       2
+
+struct crb_128M_2M_sub_block_map {
+       unsigned valid;
+       unsigned start_128M;
+       unsigned end_128M;
+       unsigned start_2M;
+};
+
+struct crb_128M_2M_block_map{
+       struct crb_128M_2M_sub_block_map sub_block[16];
+};
+#endif                         /* __QLCNIC_HDR_H_ */
diff --git a/drivers/net/qlcnic/qlcnic_hw.c b/drivers/net/qlcnic/qlcnic_hw.c
new file mode 100644 (file)
index 0000000..dc6cd69
--- /dev/null
@@ -0,0 +1,1275 @@
+/*
+ * Copyright (C) 2009 - QLogic Corporation.
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called "COPYING".
+ *
+ */
+
+#include "qlcnic.h"
+
+#include <net/ip.h>
+
+#define MASK(n) ((1ULL<<(n))-1)
+#define OCM_WIN_P3P(addr) (addr & 0xffc0000)
+
+#define GET_MEM_OFFS_2M(addr) (addr & MASK(18))
+
+#define CRB_BLK(off)   ((off >> 20) & 0x3f)
+#define CRB_SUBBLK(off)        ((off >> 16) & 0xf)
+#define CRB_WINDOW_2M  (0x130060)
+#define CRB_HI(off)    ((crb_hub_agt[CRB_BLK(off)] << 20) | ((off) & 0xf0000))
+#define CRB_INDIRECT_2M        (0x1e0000UL)
+
+
+#ifndef readq
+static inline u64 readq(void __iomem *addr)
+{
+       return readl(addr) | (((u64) readl(addr + 4)) << 32LL);
+}
+#endif
+
+#ifndef writeq
+static inline void writeq(u64 val, void __iomem *addr)
+{
+       writel(((u32) (val)), (addr));
+       writel(((u32) (val >> 32)), (addr + 4));
+}
+#endif
+
+#define ADDR_IN_RANGE(addr, low, high) \
+       (((addr) < (high)) && ((addr) >= (low)))
+
+#define PCI_OFFSET_FIRST_RANGE(adapter, off)    \
+       ((adapter)->ahw.pci_base0 + (off))
+
+static void __iomem *pci_base_offset(struct qlcnic_adapter *adapter,
+                                           unsigned long off)
+{
+       if (ADDR_IN_RANGE(off, FIRST_PAGE_GROUP_START, FIRST_PAGE_GROUP_END))
+               return PCI_OFFSET_FIRST_RANGE(adapter, off);
+
+       return NULL;
+}
+
+static const struct crb_128M_2M_block_map
+crb_128M_2M_map[64] __cacheline_aligned_in_smp = {
+    {{{0, 0,         0,         0} } },                /* 0: PCI */
+    {{{1, 0x0100000, 0x0102000, 0x120000},     /* 1: PCIE */
+         {1, 0x0110000, 0x0120000, 0x130000},
+         {1, 0x0120000, 0x0122000, 0x124000},
+         {1, 0x0130000, 0x0132000, 0x126000},
+         {1, 0x0140000, 0x0142000, 0x128000},
+         {1, 0x0150000, 0x0152000, 0x12a000},
+         {1, 0x0160000, 0x0170000, 0x110000},
+         {1, 0x0170000, 0x0172000, 0x12e000},
+         {0, 0x0000000, 0x0000000, 0x000000},
+         {0, 0x0000000, 0x0000000, 0x000000},
+         {0, 0x0000000, 0x0000000, 0x000000},
+         {0, 0x0000000, 0x0000000, 0x000000},
+         {0, 0x0000000, 0x0000000, 0x000000},
+         {0, 0x0000000, 0x0000000, 0x000000},
+         {1, 0x01e0000, 0x01e0800, 0x122000},
+         {0, 0x0000000, 0x0000000, 0x000000} } },
+       {{{1, 0x0200000, 0x0210000, 0x180000} } },/* 2: MN */
+    {{{0, 0,         0,         0} } },            /* 3: */
+    {{{1, 0x0400000, 0x0401000, 0x169000} } },/* 4: P2NR1 */
+    {{{1, 0x0500000, 0x0510000, 0x140000} } },/* 5: SRE   */
+    {{{1, 0x0600000, 0x0610000, 0x1c0000} } },/* 6: NIU   */
+    {{{1, 0x0700000, 0x0704000, 0x1b8000} } },/* 7: QM    */
+    {{{1, 0x0800000, 0x0802000, 0x170000},  /* 8: SQM0  */
+      {0, 0x0000000, 0x0000000, 0x000000},
+      {0, 0x0000000, 0x0000000, 0x000000},
+      {0, 0x0000000, 0x0000000, 0x000000},
+      {0, 0x0000000, 0x0000000, 0x000000},
+      {0, 0x0000000, 0x0000000, 0x000000},
+      {0, 0x0000000, 0x0000000, 0x000000},
+      {0, 0x0000000, 0x0000000, 0x000000},
+      {0, 0x0000000, 0x0000000, 0x000000},
+      {0, 0x0000000, 0x0000000, 0x000000},
+      {0, 0x0000000, 0x0000000, 0x000000},
+      {0, 0x0000000, 0x0000000, 0x000000},
+      {0, 0x0000000, 0x0000000, 0x000000},
+      {0, 0x0000000, 0x0000000, 0x000000},
+      {0, 0x0000000, 0x0000000, 0x000000},
+      {1, 0x08f0000, 0x08f2000, 0x172000} } },
+    {{{1, 0x0900000, 0x0902000, 0x174000},     /* 9: SQM1*/
+      {0, 0x0000000, 0x0000000, 0x000000},
+      {0, 0x0000000, 0x0000000, 0x000000},
+      {0, 0x0000000, 0x0000000, 0x000000},
+      {0, 0x0000000, 0x0000000, 0x000000},
+      {0, 0x0000000, 0x0000000, 0x000000},
+      {0, 0x0000000, 0x0000000, 0x000000},
+      {0, 0x0000000, 0x0000000, 0x000000},
+      {0, 0x0000000, 0x0000000, 0x000000},
+      {0, 0x0000000, 0x0000000, 0x000000},
+      {0, 0x0000000, 0x0000000, 0x000000},
+      {0, 0x0000000, 0x0000000, 0x000000},
+      {0, 0x0000000, 0x0000000, 0x000000},
+      {0, 0x0000000, 0x0000000, 0x000000},
+      {0, 0x0000000, 0x0000000, 0x000000},
+      {1, 0x09f0000, 0x09f2000, 0x176000} } },
+    {{{0, 0x0a00000, 0x0a02000, 0x178000},     /* 10: SQM2*/
+      {0, 0x0000000, 0x0000000, 0x000000},
+      {0, 0x0000000, 0x0000000, 0x000000},
+      {0, 0x0000000, 0x0000000, 0x000000},
+      {0, 0x0000000, 0x0000000, 0x000000},
+      {0, 0x0000000, 0x0000000, 0x000000},
+      {0, 0x0000000, 0x0000000, 0x000000},
+      {0, 0x0000000, 0x0000000, 0x000000},
+      {0, 0x0000000, 0x0000000, 0x000000},
+      {0, 0x0000000, 0x0000000, 0x000000},
+      {0, 0x0000000, 0x0000000, 0x000000},
+      {0, 0x0000000, 0x0000000, 0x000000},
+      {0, 0x0000000, 0x0000000, 0x000000},
+      {0, 0x0000000, 0x0000000, 0x000000},
+      {0, 0x0000000, 0x0000000, 0x000000},
+      {1, 0x0af0000, 0x0af2000, 0x17a000} } },
+    {{{0, 0x0b00000, 0x0b02000, 0x17c000},     /* 11: SQM3*/
+      {0, 0x0000000, 0x0000000, 0x000000},
+      {0, 0x0000000, 0x0000000, 0x000000},
+      {0, 0x0000000, 0x0000000, 0x000000},
+      {0, 0x0000000, 0x0000000, 0x000000},
+      {0, 0x0000000, 0x0000000, 0x000000},
+      {0, 0x0000000, 0x0000000, 0x000000},
+      {0, 0x0000000, 0x0000000, 0x000000},
+      {0, 0x0000000, 0x0000000, 0x000000},
+      {0, 0x0000000, 0x0000000, 0x000000},
+      {0, 0x0000000, 0x0000000, 0x000000},
+      {0, 0x0000000, 0x0000000, 0x000000},
+      {0, 0x0000000, 0x0000000, 0x000000},
+      {0, 0x0000000, 0x0000000, 0x000000},
+      {0, 0x0000000, 0x0000000, 0x000000},
+      {1, 0x0bf0000, 0x0bf2000, 0x17e000} } },
+       {{{1, 0x0c00000, 0x0c04000, 0x1d4000} } },/* 12: I2Q */
+       {{{1, 0x0d00000, 0x0d04000, 0x1a4000} } },/* 13: TMR */
+       {{{1, 0x0e00000, 0x0e04000, 0x1a0000} } },/* 14: ROMUSB */
+       {{{1, 0x0f00000, 0x0f01000, 0x164000} } },/* 15: PEG4 */
+       {{{0, 0x1000000, 0x1004000, 0x1a8000} } },/* 16: XDMA */
+       {{{1, 0x1100000, 0x1101000, 0x160000} } },/* 17: PEG0 */
+       {{{1, 0x1200000, 0x1201000, 0x161000} } },/* 18: PEG1 */
+       {{{1, 0x1300000, 0x1301000, 0x162000} } },/* 19: PEG2 */
+       {{{1, 0x1400000, 0x1401000, 0x163000} } },/* 20: PEG3 */
+       {{{1, 0x1500000, 0x1501000, 0x165000} } },/* 21: P2ND */
+       {{{1, 0x1600000, 0x1601000, 0x166000} } },/* 22: P2NI */
+       {{{0, 0,         0,         0} } },     /* 23: */
+       {{{0, 0,         0,         0} } },     /* 24: */
+       {{{0, 0,         0,         0} } },     /* 25: */
+       {{{0, 0,         0,         0} } },     /* 26: */
+       {{{0, 0,         0,         0} } },     /* 27: */
+       {{{0, 0,         0,         0} } },     /* 28: */
+       {{{1, 0x1d00000, 0x1d10000, 0x190000} } },/* 29: MS */
+    {{{1, 0x1e00000, 0x1e01000, 0x16a000} } },/* 30: P2NR2 */
+    {{{1, 0x1f00000, 0x1f10000, 0x150000} } },/* 31: EPG */
+       {{{0} } },                              /* 32: PCI */
+       {{{1, 0x2100000, 0x2102000, 0x120000},  /* 33: PCIE */
+         {1, 0x2110000, 0x2120000, 0x130000},
+         {1, 0x2120000, 0x2122000, 0x124000},
+         {1, 0x2130000, 0x2132000, 0x126000},
+         {1, 0x2140000, 0x2142000, 0x128000},
+         {1, 0x2150000, 0x2152000, 0x12a000},
+         {1, 0x2160000, 0x2170000, 0x110000},
+         {1, 0x2170000, 0x2172000, 0x12e000},
+         {0, 0x0000000, 0x0000000, 0x000000},
+         {0, 0x0000000, 0x0000000, 0x000000},
+         {0, 0x0000000, 0x0000000, 0x000000},
+         {0, 0x0000000, 0x0000000, 0x000000},
+         {0, 0x0000000, 0x0000000, 0x000000},
+         {0, 0x0000000, 0x0000000, 0x000000},
+         {0, 0x0000000, 0x0000000, 0x000000},
+         {0, 0x0000000, 0x0000000, 0x000000} } },
+       {{{1, 0x2200000, 0x2204000, 0x1b0000} } },/* 34: CAM */
+       {{{0} } },                              /* 35: */
+       {{{0} } },                              /* 36: */
+       {{{0} } },                              /* 37: */
+       {{{0} } },                              /* 38: */
+       {{{0} } },                              /* 39: */
+       {{{1, 0x2800000, 0x2804000, 0x1a4000} } },/* 40: TMR */
+       {{{1, 0x2900000, 0x2901000, 0x16b000} } },/* 41: P2NR3 */
+       {{{1, 0x2a00000, 0x2a00400, 0x1ac400} } },/* 42: RPMX1 */
+       {{{1, 0x2b00000, 0x2b00400, 0x1ac800} } },/* 43: RPMX2 */
+       {{{1, 0x2c00000, 0x2c00400, 0x1acc00} } },/* 44: RPMX3 */
+       {{{1, 0x2d00000, 0x2d00400, 0x1ad000} } },/* 45: RPMX4 */
+       {{{1, 0x2e00000, 0x2e00400, 0x1ad400} } },/* 46: RPMX5 */
+       {{{1, 0x2f00000, 0x2f00400, 0x1ad800} } },/* 47: RPMX6 */
+       {{{1, 0x3000000, 0x3000400, 0x1adc00} } },/* 48: RPMX7 */
+       {{{0, 0x3100000, 0x3104000, 0x1a8000} } },/* 49: XDMA */
+       {{{1, 0x3200000, 0x3204000, 0x1d4000} } },/* 50: I2Q */
+       {{{1, 0x3300000, 0x3304000, 0x1a0000} } },/* 51: ROMUSB */
+       {{{0} } },                              /* 52: */
+       {{{1, 0x3500000, 0x3500400, 0x1ac000} } },/* 53: RPMX0 */
+       {{{1, 0x3600000, 0x3600400, 0x1ae000} } },/* 54: RPMX8 */
+       {{{1, 0x3700000, 0x3700400, 0x1ae400} } },/* 55: RPMX9 */
+       {{{1, 0x3800000, 0x3804000, 0x1d0000} } },/* 56: OCM0 */
+       {{{1, 0x3900000, 0x3904000, 0x1b4000} } },/* 57: CRYPTO */
+       {{{1, 0x3a00000, 0x3a04000, 0x1d8000} } },/* 58: SMB */
+       {{{0} } },                              /* 59: I2C0 */
+       {{{0} } },                              /* 60: I2C1 */
+       {{{1, 0x3d00000, 0x3d04000, 0x1d8000} } },/* 61: LPC */
+       {{{1, 0x3e00000, 0x3e01000, 0x167000} } },/* 62: P2NC */
+       {{{1, 0x3f00000, 0x3f01000, 0x168000} } }       /* 63: P2NR0 */
+};
+
+/*
+ * top 12 bits of crb internal address (hub, agent)
+ */
+static const unsigned crb_hub_agt[64] = {
+       0,
+       QLCNIC_HW_CRB_HUB_AGT_ADR_PS,
+       QLCNIC_HW_CRB_HUB_AGT_ADR_MN,
+       QLCNIC_HW_CRB_HUB_AGT_ADR_MS,
+       0,
+       QLCNIC_HW_CRB_HUB_AGT_ADR_SRE,
+       QLCNIC_HW_CRB_HUB_AGT_ADR_NIU,
+       QLCNIC_HW_CRB_HUB_AGT_ADR_QMN,
+       QLCNIC_HW_CRB_HUB_AGT_ADR_SQN0,
+       QLCNIC_HW_CRB_HUB_AGT_ADR_SQN1,
+       QLCNIC_HW_CRB_HUB_AGT_ADR_SQN2,
+       QLCNIC_HW_CRB_HUB_AGT_ADR_SQN3,
+       QLCNIC_HW_CRB_HUB_AGT_ADR_I2Q,
+       QLCNIC_HW_CRB_HUB_AGT_ADR_TIMR,
+       QLCNIC_HW_CRB_HUB_AGT_ADR_ROMUSB,
+       QLCNIC_HW_CRB_HUB_AGT_ADR_PGN4,
+       QLCNIC_HW_CRB_HUB_AGT_ADR_XDMA,
+       QLCNIC_HW_CRB_HUB_AGT_ADR_PGN0,
+       QLCNIC_HW_CRB_HUB_AGT_ADR_PGN1,
+       QLCNIC_HW_CRB_HUB_AGT_ADR_PGN2,
+       QLCNIC_HW_CRB_HUB_AGT_ADR_PGN3,
+       QLCNIC_HW_CRB_HUB_AGT_ADR_PGND,
+       QLCNIC_HW_CRB_HUB_AGT_ADR_PGNI,
+       QLCNIC_HW_CRB_HUB_AGT_ADR_PGS0,
+       QLCNIC_HW_CRB_HUB_AGT_ADR_PGS1,
+       QLCNIC_HW_CRB_HUB_AGT_ADR_PGS2,
+       QLCNIC_HW_CRB_HUB_AGT_ADR_PGS3,
+       0,
+       QLCNIC_HW_CRB_HUB_AGT_ADR_PGSI,
+       QLCNIC_HW_CRB_HUB_AGT_ADR_SN,
+       0,
+       QLCNIC_HW_CRB_HUB_AGT_ADR_EG,
+       0,
+       QLCNIC_HW_CRB_HUB_AGT_ADR_PS,
+       QLCNIC_HW_CRB_HUB_AGT_ADR_CAM,
+       0,
+       0,
+       0,
+       0,
+       0,
+       QLCNIC_HW_CRB_HUB_AGT_ADR_TIMR,
+       0,
+       QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX1,
+       QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX2,
+       QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX3,
+       QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX4,
+       QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX5,
+       QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX6,
+       QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX7,
+       QLCNIC_HW_CRB_HUB_AGT_ADR_XDMA,
+       QLCNIC_HW_CRB_HUB_AGT_ADR_I2Q,
+       QLCNIC_HW_CRB_HUB_AGT_ADR_ROMUSB,
+       0,
+       QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX0,
+       QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX8,
+       QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX9,
+       QLCNIC_HW_CRB_HUB_AGT_ADR_OCM0,
+       0,
+       QLCNIC_HW_CRB_HUB_AGT_ADR_SMB,
+       QLCNIC_HW_CRB_HUB_AGT_ADR_I2C0,
+       QLCNIC_HW_CRB_HUB_AGT_ADR_I2C1,
+       0,
+       QLCNIC_HW_CRB_HUB_AGT_ADR_PGNC,
+       0,
+};
+
+/*  PCI Windowing for DDR regions.  */
+
+#define QLCNIC_PCIE_SEM_TIMEOUT        10000
+
+int
+qlcnic_pcie_sem_lock(struct qlcnic_adapter *adapter, int sem, u32 id_reg)
+{
+       int done = 0, timeout = 0;
+
+       while (!done) {
+               done = QLCRD32(adapter, QLCNIC_PCIE_REG(PCIE_SEM_LOCK(sem)));
+               if (done == 1)
+                       break;
+               if (++timeout >= QLCNIC_PCIE_SEM_TIMEOUT)
+                       return -EIO;
+               msleep(1);
+       }
+
+       if (id_reg)
+               QLCWR32(adapter, id_reg, adapter->portnum);
+
+       return 0;
+}
+
+void
+qlcnic_pcie_sem_unlock(struct qlcnic_adapter *adapter, int sem)
+{
+       QLCRD32(adapter, QLCNIC_PCIE_REG(PCIE_SEM_UNLOCK(sem)));
+}
+
+static int
+qlcnic_send_cmd_descs(struct qlcnic_adapter *adapter,
+               struct cmd_desc_type0 *cmd_desc_arr, int nr_desc)
+{
+       u32 i, producer, consumer;
+       struct qlcnic_cmd_buffer *pbuf;
+       struct cmd_desc_type0 *cmd_desc;
+       struct qlcnic_host_tx_ring *tx_ring;
+
+       i = 0;
+
+       if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
+               return -EIO;
+
+       tx_ring = adapter->tx_ring;
+       __netif_tx_lock_bh(tx_ring->txq);
+
+       producer = tx_ring->producer;
+       consumer = tx_ring->sw_consumer;
+
+       if (nr_desc >= qlcnic_tx_avail(tx_ring)) {
+               netif_tx_stop_queue(tx_ring->txq);
+               __netif_tx_unlock_bh(tx_ring->txq);
+               return -EBUSY;
+       }
+
+       do {
+               cmd_desc = &cmd_desc_arr[i];
+
+               pbuf = &tx_ring->cmd_buf_arr[producer];
+               pbuf->skb = NULL;
+               pbuf->frag_count = 0;
+
+               memcpy(&tx_ring->desc_head[producer],
+                       &cmd_desc_arr[i], sizeof(struct cmd_desc_type0));
+
+               producer = get_next_index(producer, tx_ring->num_desc);
+               i++;
+
+       } while (i != nr_desc);
+
+       tx_ring->producer = producer;
+
+       qlcnic_update_cmd_producer(adapter, tx_ring);
+
+       __netif_tx_unlock_bh(tx_ring->txq);
+
+       return 0;
+}
+
+static int
+qlcnic_sre_macaddr_change(struct qlcnic_adapter *adapter, u8 *addr,
+                               unsigned op)
+{
+       struct qlcnic_nic_req req;
+       struct qlcnic_mac_req *mac_req;
+       u64 word;
+
+       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 = op;
+       memcpy(mac_req->mac_addr, addr, 6);
+
+       return qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
+}
+
+static int qlcnic_nic_add_mac(struct qlcnic_adapter *adapter,
+               u8 *addr, struct list_head *del_list)
+{
+       struct list_head *head;
+       struct qlcnic_mac_list_s *cur;
+
+       /* look up if already exists */
+       list_for_each(head, del_list) {
+               cur = list_entry(head, struct qlcnic_mac_list_s, list);
+
+               if (memcmp(addr, cur->mac_addr, ETH_ALEN) == 0) {
+                       list_move_tail(head, &adapter->mac_list);
+                       return 0;
+               }
+       }
+
+       cur = kzalloc(sizeof(struct qlcnic_mac_list_s), GFP_ATOMIC);
+       if (cur == NULL) {
+               dev_err(&adapter->netdev->dev,
+                       "failed to add mac address filter\n");
+               return -ENOMEM;
+       }
+       memcpy(cur->mac_addr, addr, ETH_ALEN);
+       list_add_tail(&cur->list, &adapter->mac_list);
+
+       return qlcnic_sre_macaddr_change(adapter,
+                               cur->mac_addr, QLCNIC_MAC_ADD);
+}
+
+void qlcnic_set_multi(struct net_device *netdev)
+{
+       struct qlcnic_adapter *adapter = netdev_priv(netdev);
+       struct dev_mc_list *mc_ptr;
+       u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+       u32 mode = VPORT_MISS_MODE_DROP;
+       LIST_HEAD(del_list);
+       struct list_head *head;
+       struct qlcnic_mac_list_s *cur;
+
+       list_splice_tail_init(&adapter->mac_list, &del_list);
+
+       qlcnic_nic_add_mac(adapter, adapter->mac_addr, &del_list);
+       qlcnic_nic_add_mac(adapter, bcast_addr, &del_list);
+
+       if (netdev->flags & IFF_PROMISC) {
+               mode = VPORT_MISS_MODE_ACCEPT_ALL;
+               goto send_fw_cmd;
+       }
+
+       if ((netdev->flags & IFF_ALLMULTI) ||
+                       (netdev->mc_count > adapter->max_mc_count)) {
+               mode = VPORT_MISS_MODE_ACCEPT_MULTI;
+               goto send_fw_cmd;
+       }
+
+       if (netdev->mc_count > 0) {
+               for (mc_ptr = netdev->mc_list; mc_ptr;
+                                    mc_ptr = mc_ptr->next) {
+                       qlcnic_nic_add_mac(adapter, mc_ptr->dmi_addr,
+                                                       &del_list);
+               }
+       }
+
+send_fw_cmd:
+       qlcnic_nic_set_promisc(adapter, mode);
+       head = &del_list;
+       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);
+               list_del(&cur->list);
+               kfree(cur);
+       }
+}
+
+int qlcnic_nic_set_promisc(struct qlcnic_adapter *adapter, u32 mode)
+{
+       struct qlcnic_nic_req req;
+       u64 word;
+
+       memset(&req, 0, sizeof(struct qlcnic_nic_req));
+
+       req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23);
+
+       word = QLCNIC_H2C_OPCODE_PROXY_SET_VPORT_MISS_MODE |
+                       ((u64)adapter->portnum << 16);
+       req.req_hdr = cpu_to_le64(word);
+
+       req.words[0] = cpu_to_le64(mode);
+
+       return qlcnic_send_cmd_descs(adapter,
+                               (struct cmd_desc_type0 *)&req, 1);
+}
+
+void qlcnic_free_mac_list(struct qlcnic_adapter *adapter)
+{
+       struct qlcnic_mac_list_s *cur;
+       struct list_head *head = &adapter->mac_list;
+
+       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);
+               list_del(&cur->list);
+               kfree(cur);
+       }
+}
+
+#define        QLCNIC_CONFIG_INTR_COALESCE     3
+
+/*
+ * Send the interrupt coalescing parameter set by ethtool to the card.
+ */
+int qlcnic_config_intr_coalesce(struct qlcnic_adapter *adapter)
+{
+       struct qlcnic_nic_req req;
+       u64 word[6];
+       int rv, i;
+
+       memset(&req, 0, sizeof(struct qlcnic_nic_req));
+
+       req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23);
+
+       word[0] = QLCNIC_CONFIG_INTR_COALESCE | ((u64)adapter->portnum << 16);
+       req.req_hdr = cpu_to_le64(word[0]);
+
+       memcpy(&word[0], &adapter->coal, sizeof(adapter->coal));
+       for (i = 0; i < 6; i++)
+               req.words[i] = cpu_to_le64(word[i]);
+
+       rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
+       if (rv != 0)
+               dev_err(&adapter->netdev->dev,
+                       "Could not send interrupt coalescing parameters\n");
+
+       return rv;
+}
+
+int qlcnic_config_hw_lro(struct qlcnic_adapter *adapter, int enable)
+{
+       struct qlcnic_nic_req req;
+       u64 word;
+       int rv;
+
+       if ((adapter->flags & QLCNIC_LRO_ENABLED) == enable)
+               return 0;
+
+       memset(&req, 0, sizeof(struct qlcnic_nic_req));
+
+       req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23);
+
+       word = QLCNIC_H2C_OPCODE_CONFIG_HW_LRO | ((u64)adapter->portnum << 16);
+       req.req_hdr = cpu_to_le64(word);
+
+       req.words[0] = cpu_to_le64(enable);
+
+       rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
+       if (rv != 0)
+               dev_err(&adapter->netdev->dev,
+                       "Could not send configure hw lro request\n");
+
+       adapter->flags ^= QLCNIC_LRO_ENABLED;
+
+       return rv;
+}
+
+int qlcnic_config_bridged_mode(struct qlcnic_adapter *adapter, int enable)
+{
+       struct qlcnic_nic_req req;
+       u64 word;
+       int rv;
+
+       if (!!(adapter->flags & QLCNIC_BRIDGE_ENABLED) == enable)
+               return 0;
+
+       memset(&req, 0, sizeof(struct qlcnic_nic_req));
+
+       req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23);
+
+       word = QLCNIC_H2C_OPCODE_CONFIG_BRIDGING |
+               ((u64)adapter->portnum << 16);
+       req.req_hdr = cpu_to_le64(word);
+
+       req.words[0] = cpu_to_le64(enable);
+
+       rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
+       if (rv != 0)
+               dev_err(&adapter->netdev->dev,
+                       "Could not send configure bridge mode request\n");
+
+       adapter->flags ^= QLCNIC_BRIDGE_ENABLED;
+
+       return rv;
+}
+
+
+#define RSS_HASHTYPE_IP_TCP    0x3
+
+int qlcnic_config_rss(struct qlcnic_adapter *adapter, int enable)
+{
+       struct qlcnic_nic_req req;
+       u64 word;
+       int i, rv;
+
+       const u64 key[] = { 0xbeac01fa6a42b73bULL, 0x8030f20c77cb2da3ULL,
+                       0xae7b30b4d0ca2bcbULL, 0x43a38fb04167253dULL,
+                       0x255b0ec26d5a56daULL };
+
+
+       memset(&req, 0, sizeof(struct qlcnic_nic_req));
+       req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23);
+
+       word = QLCNIC_H2C_OPCODE_CONFIG_RSS | ((u64)adapter->portnum << 16);
+       req.req_hdr = cpu_to_le64(word);
+
+       /*
+        * RSS request:
+        * bits 3-0: hash_method
+        *      5-4: hash_type_ipv4
+        *      7-6: hash_type_ipv6
+        *        8: enable
+        *        9: use indirection table
+        *    47-10: reserved
+        *    63-48: indirection table mask
+        */
+       word =  ((u64)(RSS_HASHTYPE_IP_TCP & 0x3) << 4) |
+               ((u64)(RSS_HASHTYPE_IP_TCP & 0x3) << 6) |
+               ((u64)(enable & 0x1) << 8) |
+               ((0x7ULL) << 48);
+       req.words[0] = cpu_to_le64(word);
+       for (i = 0; i < 5; i++)
+               req.words[i+1] = cpu_to_le64(key[i]);
+
+       rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
+       if (rv != 0)
+               dev_err(&adapter->netdev->dev, "could not configure RSS\n");
+
+       return rv;
+}
+
+int qlcnic_config_ipaddr(struct qlcnic_adapter *adapter, u32 ip, int cmd)
+{
+       struct qlcnic_nic_req req;
+       u64 word;
+       int rv;
+
+       memset(&req, 0, sizeof(struct qlcnic_nic_req));
+       req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23);
+
+       word = QLCNIC_H2C_OPCODE_CONFIG_IPADDR | ((u64)adapter->portnum << 16);
+       req.req_hdr = cpu_to_le64(word);
+
+       req.words[0] = cpu_to_le64(cmd);
+       req.words[1] = cpu_to_le64(ip);
+
+       rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
+       if (rv != 0)
+               dev_err(&adapter->netdev->dev,
+                               "could not notify %s IP 0x%x reuqest\n",
+                               (cmd == QLCNIC_IP_UP) ? "Add" : "Remove", ip);
+
+       return rv;
+}
+
+int qlcnic_linkevent_request(struct qlcnic_adapter *adapter, int enable)
+{
+       struct qlcnic_nic_req req;
+       u64 word;
+       int rv;
+
+       memset(&req, 0, sizeof(struct qlcnic_nic_req));
+       req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23);
+
+       word = QLCNIC_H2C_OPCODE_GET_LINKEVENT | ((u64)adapter->portnum << 16);
+       req.req_hdr = cpu_to_le64(word);
+       req.words[0] = cpu_to_le64(enable | (enable << 8));
+
+       rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
+       if (rv != 0)
+               dev_err(&adapter->netdev->dev,
+                               "could not configure link notification\n");
+
+       return rv;
+}
+
+int qlcnic_send_lro_cleanup(struct qlcnic_adapter *adapter)
+{
+       struct qlcnic_nic_req req;
+       u64 word;
+       int rv;
+
+       memset(&req, 0, sizeof(struct qlcnic_nic_req));
+       req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23);
+
+       word = QLCNIC_H2C_OPCODE_LRO_REQUEST |
+               ((u64)adapter->portnum << 16) |
+               ((u64)QLCNIC_LRO_REQUEST_CLEANUP << 56) ;
+
+       req.req_hdr = cpu_to_le64(word);
+
+       rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
+       if (rv != 0)
+               dev_err(&adapter->netdev->dev,
+                                "could not cleanup lro flows\n");
+
+       return rv;
+}
+
+/*
+ * qlcnic_change_mtu - Change the Maximum Transfer Unit
+ * @returns 0 on success, negative on failure
+ */
+
+int qlcnic_change_mtu(struct net_device *netdev, int mtu)
+{
+       struct qlcnic_adapter *adapter = netdev_priv(netdev);
+       int rc = 0;
+
+       if (mtu > P3_MAX_MTU) {
+               dev_err(&adapter->netdev->dev, "mtu > %d bytes unsupported\n",
+                                               P3_MAX_MTU);
+               return -EINVAL;
+       }
+
+       rc = qlcnic_fw_cmd_set_mtu(adapter, mtu);
+
+       if (!rc)
+               netdev->mtu = mtu;
+
+       return rc;
+}
+
+int qlcnic_get_mac_addr(struct qlcnic_adapter *adapter, u64 *mac)
+{
+       u32 crbaddr, mac_hi, mac_lo;
+       int pci_func = adapter->ahw.pci_func;
+
+       crbaddr = CRB_MAC_BLOCK_START +
+               (4 * ((pci_func/2) * 3)) + (4 * (pci_func & 1));
+
+       mac_lo = QLCRD32(adapter, crbaddr);
+       mac_hi = QLCRD32(adapter, crbaddr+4);
+
+       if (pci_func & 1)
+               *mac = le64_to_cpu((mac_lo >> 16) | ((u64)mac_hi << 16));
+       else
+               *mac = le64_to_cpu((u64)mac_lo | ((u64)mac_hi << 32));
+
+       return 0;
+}
+
+/*
+ * Changes the CRB window to the specified window.
+ */
+ /* Returns < 0 if off is not valid,
+ *      1 if window access is needed. 'off' is set to offset from
+ *        CRB space in 128M pci map
+ *      0 if no window access is needed. 'off' is set to 2M addr
+ * In: 'off' is offset from base in 128M pci map
+ */
+static int
+qlcnic_pci_get_crb_addr_2M(struct qlcnic_adapter *adapter,
+               ulong off, void __iomem **addr)
+{
+       const struct crb_128M_2M_sub_block_map *m;
+
+       if ((off >= QLCNIC_CRB_MAX) || (off < QLCNIC_PCI_CRBSPACE))
+               return -EINVAL;
+
+       off -= QLCNIC_PCI_CRBSPACE;
+
+       /*
+        * Try direct map
+        */
+       m = &crb_128M_2M_map[CRB_BLK(off)].sub_block[CRB_SUBBLK(off)];
+
+       if (m->valid && (m->start_128M <= off) && (m->end_128M > off)) {
+               *addr = adapter->ahw.pci_base0 + m->start_2M +
+                       (off - m->start_128M);
+               return 0;
+       }
+
+       /*
+        * Not in direct map, use crb window
+        */
+       *addr = adapter->ahw.pci_base0 + CRB_INDIRECT_2M + (off & MASK(16));
+       return 1;
+}
+
+/*
+ * In: 'off' is offset from CRB space in 128M pci map
+ * Out: 'off' is 2M pci map addr
+ * side effect: lock crb window
+ */
+static void
+qlcnic_pci_set_crbwindow_2M(struct qlcnic_adapter *adapter, ulong off)
+{
+       u32 window;
+       void __iomem *addr = adapter->ahw.pci_base0 + CRB_WINDOW_2M;
+
+       off -= QLCNIC_PCI_CRBSPACE;
+
+       window = CRB_HI(off);
+
+       if (adapter->ahw.crb_win == window)
+               return;
+
+       writel(window, addr);
+       if (readl(addr) != window) {
+               if (printk_ratelimit())
+                       dev_warn(&adapter->pdev->dev,
+                               "failed to set CRB window to %d off 0x%lx\n",
+                               window, off);
+       }
+       adapter->ahw.crb_win = window;
+}
+
+int
+qlcnic_hw_write_wx_2M(struct qlcnic_adapter *adapter, ulong off, u32 data)
+{
+       unsigned long flags;
+       int rv;
+       void __iomem *addr = NULL;
+
+       rv = qlcnic_pci_get_crb_addr_2M(adapter, off, &addr);
+
+       if (rv == 0) {
+               writel(data, addr);
+               return 0;
+       }
+
+       if (rv > 0) {
+               /* indirect access */
+               write_lock_irqsave(&adapter->ahw.crb_lock, flags);
+               crb_win_lock(adapter);
+               qlcnic_pci_set_crbwindow_2M(adapter, off);
+               writel(data, addr);
+               crb_win_unlock(adapter);
+               write_unlock_irqrestore(&adapter->ahw.crb_lock, flags);
+               return 0;
+       }
+
+       dev_err(&adapter->pdev->dev,
+                       "%s: invalid offset: 0x%016lx\n", __func__, off);
+       dump_stack();
+       return -EIO;
+}
+
+u32
+qlcnic_hw_read_wx_2M(struct qlcnic_adapter *adapter, ulong off)
+{
+       unsigned long flags;
+       int rv;
+       u32 data;
+       void __iomem *addr = NULL;
+
+       rv = qlcnic_pci_get_crb_addr_2M(adapter, off, &addr);
+
+       if (rv == 0)
+               return readl(addr);
+
+       if (rv > 0) {
+               /* indirect access */
+               write_lock_irqsave(&adapter->ahw.crb_lock, flags);
+               crb_win_lock(adapter);
+               qlcnic_pci_set_crbwindow_2M(adapter, off);
+               data = readl(addr);
+               crb_win_unlock(adapter);
+               write_unlock_irqrestore(&adapter->ahw.crb_lock, flags);
+               return data;
+       }
+
+       dev_err(&adapter->pdev->dev,
+                       "%s: invalid offset: 0x%016lx\n", __func__, off);
+       dump_stack();
+       return -1;
+}
+
+
+void __iomem *
+qlcnic_get_ioaddr(struct qlcnic_adapter *adapter, u32 offset)
+{
+       void __iomem *addr = NULL;
+
+       WARN_ON(qlcnic_pci_get_crb_addr_2M(adapter, offset, &addr));
+
+       return addr;
+}
+
+
+static int
+qlcnic_pci_set_window_2M(struct qlcnic_adapter *adapter,
+               u64 addr, u32 *start)
+{
+       u32 window;
+       struct pci_dev *pdev = adapter->pdev;
+
+       if ((addr & 0x00ff800) == 0xff800) {
+               if (printk_ratelimit())
+                       dev_warn(&pdev->dev, "QM access not handled\n");
+               return -EIO;
+       }
+
+       window = OCM_WIN_P3P(addr);
+
+       writel(window, adapter->ahw.ocm_win_crb);
+       /* read back to flush */
+       readl(adapter->ahw.ocm_win_crb);
+
+       adapter->ahw.ocm_win = window;
+       *start = QLCNIC_PCI_OCM0_2M + GET_MEM_OFFS_2M(addr);
+       return 0;
+}
+
+static int
+qlcnic_pci_mem_access_direct(struct qlcnic_adapter *adapter, u64 off,
+               u64 *data, int op)
+{
+       void __iomem *addr, *mem_ptr = NULL;
+       resource_size_t mem_base;
+       int ret;
+       u32 start;
+
+       mutex_lock(&adapter->ahw.mem_lock);
+
+       ret = qlcnic_pci_set_window_2M(adapter, off, &start);
+       if (ret != 0)
+               goto unlock;
+
+       addr = pci_base_offset(adapter, start);
+       if (addr)
+               goto noremap;
+
+       mem_base = pci_resource_start(adapter->pdev, 0) + (start & PAGE_MASK);
+
+       mem_ptr = ioremap(mem_base, PAGE_SIZE);
+       if (mem_ptr == NULL) {
+               ret = -EIO;
+               goto unlock;
+       }
+
+       addr = mem_ptr + (start & (PAGE_SIZE - 1));
+
+noremap:
+       if (op == 0)    /* read */
+               *data = readq(addr);
+       else            /* write */
+               writeq(*data, addr);
+
+unlock:
+       mutex_unlock(&adapter->ahw.mem_lock);
+
+       if (mem_ptr)
+               iounmap(mem_ptr);
+       return ret;
+}
+
+#define MAX_CTL_CHECK   1000
+
+int
+qlcnic_pci_mem_write_2M(struct qlcnic_adapter *adapter,
+               u64 off, u64 data)
+{
+       int i, j, ret;
+       u32 temp, off8;
+       u64 stride;
+       void __iomem *mem_crb;
+
+       /* Only 64-bit aligned access */
+       if (off & 7)
+               return -EIO;
+
+       /* P3 onward, test agent base for MIU and SIU is same */
+       if (ADDR_IN_RANGE(off, QLCNIC_ADDR_QDR_NET,
+                               QLCNIC_ADDR_QDR_NET_MAX_P3)) {
+               mem_crb = qlcnic_get_ioaddr(adapter,
+                               QLCNIC_CRB_QDR_NET+MIU_TEST_AGT_BASE);
+               goto correct;
+       }
+
+       if (ADDR_IN_RANGE(off, QLCNIC_ADDR_DDR_NET, QLCNIC_ADDR_DDR_NET_MAX)) {
+               mem_crb = qlcnic_get_ioaddr(adapter,
+                               QLCNIC_CRB_DDR_NET+MIU_TEST_AGT_BASE);
+               goto correct;
+       }
+
+       if (ADDR_IN_RANGE(off, QLCNIC_ADDR_OCM0, QLCNIC_ADDR_OCM0_MAX))
+               return qlcnic_pci_mem_access_direct(adapter, off, &data, 1);
+
+       return -EIO;
+
+correct:
+       stride = QLCNIC_IS_REVISION_P3P(adapter->ahw.revision_id) ? 16 : 8;
+
+       off8 = off & ~(stride-1);
+
+       mutex_lock(&adapter->ahw.mem_lock);
+
+       writel(off8, (mem_crb + MIU_TEST_AGT_ADDR_LO));
+       writel(0, (mem_crb + MIU_TEST_AGT_ADDR_HI));
+
+       i = 0;
+       if (stride == 16) {
+               writel(TA_CTL_ENABLE, (mem_crb + TEST_AGT_CTRL));
+               writel((TA_CTL_START | TA_CTL_ENABLE),
+                               (mem_crb + TEST_AGT_CTRL));
+
+               for (j = 0; j < MAX_CTL_CHECK; j++) {
+                       temp = readl(mem_crb + TEST_AGT_CTRL);
+                       if ((temp & TA_CTL_BUSY) == 0)
+                               break;
+               }
+
+               if (j >= MAX_CTL_CHECK) {
+                       ret = -EIO;
+                       goto done;
+               }
+
+               i = (off & 0xf) ? 0 : 2;
+               writel(readl(mem_crb + MIU_TEST_AGT_RDDATA(i)),
+                               mem_crb + MIU_TEST_AGT_WRDATA(i));
+               writel(readl(mem_crb + MIU_TEST_AGT_RDDATA(i+1)),
+                               mem_crb + MIU_TEST_AGT_WRDATA(i+1));
+               i = (off & 0xf) ? 2 : 0;
+       }
+
+       writel(data & 0xffffffff,
+                       mem_crb + MIU_TEST_AGT_WRDATA(i));
+       writel((data >> 32) & 0xffffffff,
+                       mem_crb + MIU_TEST_AGT_WRDATA(i+1));
+
+       writel((TA_CTL_ENABLE | TA_CTL_WRITE), (mem_crb + TEST_AGT_CTRL));
+       writel((TA_CTL_START | TA_CTL_ENABLE | TA_CTL_WRITE),
+                       (mem_crb + TEST_AGT_CTRL));
+
+       for (j = 0; j < MAX_CTL_CHECK; j++) {
+               temp = readl(mem_crb + TEST_AGT_CTRL);
+               if ((temp & TA_CTL_BUSY) == 0)
+                       break;
+       }
+
+       if (j >= MAX_CTL_CHECK) {
+               if (printk_ratelimit())
+                       dev_err(&adapter->pdev->dev,
+                                       "failed to write through agent\n");
+               ret = -EIO;
+       } else
+               ret = 0;
+
+done:
+       mutex_unlock(&adapter->ahw.mem_lock);
+
+       return ret;
+}
+
+int
+qlcnic_pci_mem_read_2M(struct qlcnic_adapter *adapter,
+               u64 off, u64 *data)
+{
+       int j, ret;
+       u32 temp, off8;
+       u64 val, stride;
+       void __iomem *mem_crb;
+
+       /* Only 64-bit aligned access */
+       if (off & 7)
+               return -EIO;
+
+       /* P3 onward, test agent base for MIU and SIU is same */
+       if (ADDR_IN_RANGE(off, QLCNIC_ADDR_QDR_NET,
+                               QLCNIC_ADDR_QDR_NET_MAX_P3)) {
+               mem_crb = qlcnic_get_ioaddr(adapter,
+                               QLCNIC_CRB_QDR_NET+MIU_TEST_AGT_BASE);
+               goto correct;
+       }
+
+       if (ADDR_IN_RANGE(off, QLCNIC_ADDR_DDR_NET, QLCNIC_ADDR_DDR_NET_MAX)) {
+               mem_crb = qlcnic_get_ioaddr(adapter,
+                               QLCNIC_CRB_DDR_NET+MIU_TEST_AGT_BASE);
+               goto correct;
+       }
+
+       if (ADDR_IN_RANGE(off, QLCNIC_ADDR_OCM0, QLCNIC_ADDR_OCM0_MAX)) {
+               return qlcnic_pci_mem_access_direct(adapter,
+                               off, data, 0);
+       }
+
+       return -EIO;
+
+correct:
+       stride = QLCNIC_IS_REVISION_P3P(adapter->ahw.revision_id) ? 16 : 8;
+
+       off8 = off & ~(stride-1);
+
+       mutex_lock(&adapter->ahw.mem_lock);
+
+       writel(off8, (mem_crb + MIU_TEST_AGT_ADDR_LO));
+       writel(0, (mem_crb + MIU_TEST_AGT_ADDR_HI));
+       writel(TA_CTL_ENABLE, (mem_crb + TEST_AGT_CTRL));
+       writel((TA_CTL_START | TA_CTL_ENABLE), (mem_crb + TEST_AGT_CTRL));
+
+       for (j = 0; j < MAX_CTL_CHECK; j++) {
+               temp = readl(mem_crb + TEST_AGT_CTRL);
+               if ((temp & TA_CTL_BUSY) == 0)
+                       break;
+       }
+
+       if (j >= MAX_CTL_CHECK) {
+               if (printk_ratelimit())
+                       dev_err(&adapter->pdev->dev,
+                                       "failed to read through agent\n");
+               ret = -EIO;
+       } else {
+               off8 = MIU_TEST_AGT_RDDATA_LO;
+               if ((stride == 16) && (off & 0xf))
+                       off8 = MIU_TEST_AGT_RDDATA_UPPER_LO;
+
+               temp = readl(mem_crb + off8 + 4);
+               val = (u64)temp << 32;
+               val |= readl(mem_crb + off8);
+               *data = val;
+               ret = 0;
+       }
+
+       mutex_unlock(&adapter->ahw.mem_lock);
+
+       return ret;
+}
+
+int qlcnic_get_board_info(struct qlcnic_adapter *adapter)
+{
+       int offset, board_type, magic;
+       struct pci_dev *pdev = adapter->pdev;
+
+       offset = QLCNIC_FW_MAGIC_OFFSET;
+       if (qlcnic_rom_fast_read(adapter, offset, &magic))
+               return -EIO;
+
+       if (magic != QLCNIC_BDINFO_MAGIC) {
+               dev_err(&pdev->dev, "invalid board config, magic=%08x\n",
+                       magic);
+               return -EIO;
+       }
+
+       offset = QLCNIC_BRDTYPE_OFFSET;
+       if (qlcnic_rom_fast_read(adapter, offset, &board_type))
+               return -EIO;
+
+       adapter->ahw.board_type = board_type;
+
+       if (board_type == QLCNIC_BRDTYPE_P3_4_GB_MM) {
+               u32 gpio = QLCRD32(adapter, QLCNIC_ROMUSB_GLB_PAD_GPIO_I);
+               if ((gpio & 0x8000) == 0)
+                       board_type = QLCNIC_BRDTYPE_P3_10G_TP;
+       }
+
+       switch (board_type) {
+       case QLCNIC_BRDTYPE_P3_HMEZ:
+       case QLCNIC_BRDTYPE_P3_XG_LOM:
+       case QLCNIC_BRDTYPE_P3_10G_CX4:
+       case QLCNIC_BRDTYPE_P3_10G_CX4_LP:
+       case QLCNIC_BRDTYPE_P3_IMEZ:
+       case QLCNIC_BRDTYPE_P3_10G_SFP_PLUS:
+       case QLCNIC_BRDTYPE_P3_10G_SFP_CT:
+       case QLCNIC_BRDTYPE_P3_10G_SFP_QT:
+       case QLCNIC_BRDTYPE_P3_10G_XFP:
+       case QLCNIC_BRDTYPE_P3_10000_BASE_T:
+               adapter->ahw.port_type = QLCNIC_XGBE;
+               break;
+       case QLCNIC_BRDTYPE_P3_REF_QG:
+       case QLCNIC_BRDTYPE_P3_4_GB:
+       case QLCNIC_BRDTYPE_P3_4_GB_MM:
+               adapter->ahw.port_type = QLCNIC_GBE;
+               break;
+       case QLCNIC_BRDTYPE_P3_10G_TP:
+               adapter->ahw.port_type = (adapter->portnum < 2) ?
+                       QLCNIC_XGBE : QLCNIC_GBE;
+               break;
+       default:
+               dev_err(&pdev->dev, "unknown board type %x\n", board_type);
+               adapter->ahw.port_type = QLCNIC_XGBE;
+               break;
+       }
+
+       return 0;
+}
+
+int
+qlcnic_wol_supported(struct qlcnic_adapter *adapter)
+{
+       u32 wol_cfg;
+
+       wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV);
+       if (wol_cfg & (1UL << adapter->portnum)) {
+               wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG);
+               if (wol_cfg & (1 << adapter->portnum))
+                       return 1;
+       }
+
+       return 0;
+}
+
+int qlcnic_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate)
+{
+       struct qlcnic_nic_req   req;
+       int rv;
+       u64 word;
+
+       memset(&req, 0, sizeof(struct qlcnic_nic_req));
+       req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23);
+
+       word = QLCNIC_H2C_OPCODE_CONFIG_LED | ((u64)adapter->portnum << 16);
+       req.req_hdr = cpu_to_le64(word);
+
+       req.words[0] = cpu_to_le64((u64)rate << 32);
+       req.words[1] = cpu_to_le64(state);
+
+       rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
+       if (rv)
+               dev_err(&adapter->pdev->dev, "LED configuration failed.\n");
+
+       return rv;
+}
+
+static int qlcnic_set_fw_loopback(struct qlcnic_adapter *adapter, u32 flag)
+{
+       struct qlcnic_nic_req   req;
+       int                     rv;
+       u64                     word;
+
+       memset(&req, 0, sizeof(struct qlcnic_nic_req));
+       req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23);
+
+       word = QLCNIC_H2C_OPCODE_CONFIG_LOOPBACK |
+                       ((u64)adapter->portnum << 16);
+       req.req_hdr = cpu_to_le64(word);
+       req.words[0] = cpu_to_le64(flag);
+
+       rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
+       if (rv)
+               dev_err(&adapter->pdev->dev,
+                       "%sting loopback mode failed.\n",
+                                       flag ? "Set" : "Reset");
+       return rv;
+}
+
+int qlcnic_set_ilb_mode(struct qlcnic_adapter *adapter)
+{
+       if (qlcnic_set_fw_loopback(adapter, 1))
+               return -EIO;
+
+       if (qlcnic_nic_set_promisc(adapter,
+                               VPORT_MISS_MODE_ACCEPT_ALL)) {
+               qlcnic_set_fw_loopback(adapter, 0);
+               return -EIO;
+       }
+
+       msleep(1000);
+       return 0;
+}
+
+void qlcnic_clear_ilb_mode(struct qlcnic_adapter *adapter)
+{
+       int mode = VPORT_MISS_MODE_DROP;
+       struct net_device *netdev = adapter->netdev;
+
+       qlcnic_set_fw_loopback(adapter, 0);
+
+       if (netdev->flags & IFF_PROMISC)
+               mode = VPORT_MISS_MODE_ACCEPT_ALL;
+       else if (netdev->flags & IFF_ALLMULTI)
+               mode = VPORT_MISS_MODE_ACCEPT_MULTI;
+
+       qlcnic_nic_set_promisc(adapter, mode);
+}
diff --git a/drivers/net/qlcnic/qlcnic_init.c b/drivers/net/qlcnic/qlcnic_init.c
new file mode 100644 (file)
index 0000000..ea00ab4
--- /dev/null
@@ -0,0 +1,1541 @@
+/*
+ * Copyright (C) 2009 - QLogic Corporation.
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called "COPYING".
+ *
+ */
+
+#include <linux/netdevice.h>
+#include <linux/delay.h>
+#include "qlcnic.h"
+
+struct crb_addr_pair {
+       u32 addr;
+       u32 data;
+};
+
+#define QLCNIC_MAX_CRB_XFORM 60
+static unsigned int crb_addr_xform[QLCNIC_MAX_CRB_XFORM];
+
+#define crb_addr_transform(name) \
+       (crb_addr_xform[QLCNIC_HW_PX_MAP_CRB_##name] = \
+       QLCNIC_HW_CRB_HUB_AGT_ADR_##name << 20)
+
+#define QLCNIC_ADDR_ERROR (0xffffffff)
+
+static void
+qlcnic_post_rx_buffers_nodb(struct qlcnic_adapter *adapter,
+               struct qlcnic_host_rds_ring *rds_ring);
+
+static void crb_addr_transform_setup(void)
+{
+       crb_addr_transform(XDMA);
+       crb_addr_transform(TIMR);
+       crb_addr_transform(SRE);
+       crb_addr_transform(SQN3);
+       crb_addr_transform(SQN2);
+       crb_addr_transform(SQN1);
+       crb_addr_transform(SQN0);
+       crb_addr_transform(SQS3);
+       crb_addr_transform(SQS2);
+       crb_addr_transform(SQS1);
+       crb_addr_transform(SQS0);
+       crb_addr_transform(RPMX7);
+       crb_addr_transform(RPMX6);
+       crb_addr_transform(RPMX5);
+       crb_addr_transform(RPMX4);
+       crb_addr_transform(RPMX3);
+       crb_addr_transform(RPMX2);
+       crb_addr_transform(RPMX1);
+       crb_addr_transform(RPMX0);
+       crb_addr_transform(ROMUSB);
+       crb_addr_transform(SN);
+       crb_addr_transform(QMN);
+       crb_addr_transform(QMS);
+       crb_addr_transform(PGNI);
+       crb_addr_transform(PGND);
+       crb_addr_transform(PGN3);
+       crb_addr_transform(PGN2);
+       crb_addr_transform(PGN1);
+       crb_addr_transform(PGN0);
+       crb_addr_transform(PGSI);
+       crb_addr_transform(PGSD);
+       crb_addr_transform(PGS3);
+       crb_addr_transform(PGS2);
+       crb_addr_transform(PGS1);
+       crb_addr_transform(PGS0);
+       crb_addr_transform(PS);
+       crb_addr_transform(PH);
+       crb_addr_transform(NIU);
+       crb_addr_transform(I2Q);
+       crb_addr_transform(EG);
+       crb_addr_transform(MN);
+       crb_addr_transform(MS);
+       crb_addr_transform(CAS2);
+       crb_addr_transform(CAS1);
+       crb_addr_transform(CAS0);
+       crb_addr_transform(CAM);
+       crb_addr_transform(C2C1);
+       crb_addr_transform(C2C0);
+       crb_addr_transform(SMB);
+       crb_addr_transform(OCM0);
+       crb_addr_transform(I2C0);
+}
+
+void qlcnic_release_rx_buffers(struct qlcnic_adapter *adapter)
+{
+       struct qlcnic_recv_context *recv_ctx;
+       struct qlcnic_host_rds_ring *rds_ring;
+       struct qlcnic_rx_buffer *rx_buf;
+       int i, ring;
+
+       recv_ctx = &adapter->recv_ctx;
+       for (ring = 0; ring < adapter->max_rds_rings; ring++) {
+               rds_ring = &recv_ctx->rds_rings[ring];
+               for (i = 0; i < rds_ring->num_desc; ++i) {
+                       rx_buf = &(rds_ring->rx_buf_arr[i]);
+                       if (rx_buf->state == QLCNIC_BUFFER_FREE)
+                               continue;
+                       pci_unmap_single(adapter->pdev,
+                                       rx_buf->dma,
+                                       rds_ring->dma_size,
+                                       PCI_DMA_FROMDEVICE);
+                       if (rx_buf->skb != NULL)
+                               dev_kfree_skb_any(rx_buf->skb);
+               }
+       }
+}
+
+void qlcnic_release_tx_buffers(struct qlcnic_adapter *adapter)
+{
+       struct qlcnic_cmd_buffer *cmd_buf;
+       struct qlcnic_skb_frag *buffrag;
+       int i, j;
+       struct qlcnic_host_tx_ring *tx_ring = adapter->tx_ring;
+
+       cmd_buf = tx_ring->cmd_buf_arr;
+       for (i = 0; i < tx_ring->num_desc; i++) {
+               buffrag = cmd_buf->frag_array;
+               if (buffrag->dma) {
+                       pci_unmap_single(adapter->pdev, buffrag->dma,
+                                        buffrag->length, PCI_DMA_TODEVICE);
+                       buffrag->dma = 0ULL;
+               }
+               for (j = 0; j < cmd_buf->frag_count; j++) {
+                       buffrag++;
+                       if (buffrag->dma) {
+                               pci_unmap_page(adapter->pdev, buffrag->dma,
+                                              buffrag->length,
+                                              PCI_DMA_TODEVICE);
+                               buffrag->dma = 0ULL;
+                       }
+               }
+               if (cmd_buf->skb) {
+                       dev_kfree_skb_any(cmd_buf->skb);
+                       cmd_buf->skb = NULL;
+               }
+               cmd_buf++;
+       }
+}
+
+void qlcnic_free_sw_resources(struct qlcnic_adapter *adapter)
+{
+       struct qlcnic_recv_context *recv_ctx;
+       struct qlcnic_host_rds_ring *rds_ring;
+       struct qlcnic_host_tx_ring *tx_ring;
+       int ring;
+
+       recv_ctx = &adapter->recv_ctx;
+
+       if (recv_ctx->rds_rings == NULL)
+               goto skip_rds;
+
+       for (ring = 0; ring < adapter->max_rds_rings; ring++) {
+               rds_ring = &recv_ctx->rds_rings[ring];
+               vfree(rds_ring->rx_buf_arr);
+               rds_ring->rx_buf_arr = NULL;
+       }
+       kfree(recv_ctx->rds_rings);
+
+skip_rds:
+       if (adapter->tx_ring == NULL)
+               return;
+
+       tx_ring = adapter->tx_ring;
+       vfree(tx_ring->cmd_buf_arr);
+       kfree(adapter->tx_ring);
+}
+
+int qlcnic_alloc_sw_resources(struct qlcnic_adapter *adapter)
+{
+       struct qlcnic_recv_context *recv_ctx;
+       struct qlcnic_host_rds_ring *rds_ring;
+       struct qlcnic_host_sds_ring *sds_ring;
+       struct qlcnic_host_tx_ring *tx_ring;
+       struct qlcnic_rx_buffer *rx_buf;
+       int ring, i, size;
+
+       struct qlcnic_cmd_buffer *cmd_buf_arr;
+       struct net_device *netdev = adapter->netdev;
+
+       size = sizeof(struct qlcnic_host_tx_ring);
+       tx_ring = kzalloc(size, GFP_KERNEL);
+       if (tx_ring == NULL) {
+               dev_err(&netdev->dev, "failed to allocate tx ring struct\n");
+               return -ENOMEM;
+       }
+       adapter->tx_ring = tx_ring;
+
+       tx_ring->num_desc = adapter->num_txd;
+       tx_ring->txq = netdev_get_tx_queue(netdev, 0);
+
+       cmd_buf_arr = vmalloc(TX_BUFF_RINGSIZE(tx_ring));
+       if (cmd_buf_arr == NULL) {
+               dev_err(&netdev->dev, "failed to allocate cmd buffer ring\n");
+               return -ENOMEM;
+       }
+       memset(cmd_buf_arr, 0, TX_BUFF_RINGSIZE(tx_ring));
+       tx_ring->cmd_buf_arr = cmd_buf_arr;
+
+       recv_ctx = &adapter->recv_ctx;
+
+       size = adapter->max_rds_rings * sizeof(struct qlcnic_host_rds_ring);
+       rds_ring = kzalloc(size, GFP_KERNEL);
+       if (rds_ring == NULL) {
+               dev_err(&netdev->dev, "failed to allocate rds ring struct\n");
+               return -ENOMEM;
+       }
+       recv_ctx->rds_rings = rds_ring;
+
+       for (ring = 0; ring < adapter->max_rds_rings; ring++) {
+               rds_ring = &recv_ctx->rds_rings[ring];
+               switch (ring) {
+               case RCV_RING_NORMAL:
+                       rds_ring->num_desc = adapter->num_rxd;
+                       if (adapter->ahw.cut_through) {
+                               rds_ring->dma_size =
+                                       QLCNIC_CT_DEFAULT_RX_BUF_LEN;
+                               rds_ring->skb_size =
+                                       QLCNIC_CT_DEFAULT_RX_BUF_LEN;
+                       } else {
+                               rds_ring->dma_size =
+                                       QLCNIC_P3_RX_BUF_MAX_LEN;
+                               rds_ring->skb_size =
+                                       rds_ring->dma_size + NET_IP_ALIGN;
+                       }
+                       break;
+
+               case RCV_RING_JUMBO:
+                       rds_ring->num_desc = adapter->num_jumbo_rxd;
+                       rds_ring->dma_size =
+                               QLCNIC_P3_RX_JUMBO_BUF_MAX_LEN;
+
+                       if (adapter->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO)
+                               rds_ring->dma_size += QLCNIC_LRO_BUFFER_EXTRA;
+
+                       rds_ring->skb_size =
+                               rds_ring->dma_size + NET_IP_ALIGN;
+                       break;
+
+               case RCV_RING_LRO:
+                       rds_ring->num_desc = adapter->num_lro_rxd;
+                       rds_ring->dma_size = QLCNIC_RX_LRO_BUFFER_LENGTH;
+                       rds_ring->skb_size = rds_ring->dma_size + NET_IP_ALIGN;
+                       break;
+
+               }
+               rds_ring->rx_buf_arr = (struct qlcnic_rx_buffer *)
+                       vmalloc(RCV_BUFF_RINGSIZE(rds_ring));
+               if (rds_ring->rx_buf_arr == NULL) {
+                       dev_err(&netdev->dev, "Failed to allocate "
+                               "rx buffer ring %d\n", ring);
+                       goto err_out;
+               }
+               memset(rds_ring->rx_buf_arr, 0, RCV_BUFF_RINGSIZE(rds_ring));
+               INIT_LIST_HEAD(&rds_ring->free_list);
+               /*
+                * Now go through all of them, set reference handles
+                * and put them in the queues.
+                */
+               rx_buf = rds_ring->rx_buf_arr;
+               for (i = 0; i < rds_ring->num_desc; i++) {
+                       list_add_tail(&rx_buf->list,
+                                       &rds_ring->free_list);
+                       rx_buf->ref_handle = i;
+                       rx_buf->state = QLCNIC_BUFFER_FREE;
+                       rx_buf++;
+               }
+               spin_lock_init(&rds_ring->lock);
+       }
+
+       for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+               sds_ring = &recv_ctx->sds_rings[ring];
+               sds_ring->irq = adapter->msix_entries[ring].vector;
+               sds_ring->adapter = adapter;
+               sds_ring->num_desc = adapter->num_rxd;
+
+               for (i = 0; i < NUM_RCV_DESC_RINGS; i++)
+                       INIT_LIST_HEAD(&sds_ring->free_list[i]);
+       }
+
+       return 0;
+
+err_out:
+       qlcnic_free_sw_resources(adapter);
+       return -ENOMEM;
+}
+
+/*
+ * Utility to translate from internal Phantom CRB address
+ * to external PCI CRB address.
+ */
+static u32 qlcnic_decode_crb_addr(u32 addr)
+{
+       int i;
+       u32 base_addr, offset, pci_base;
+
+       crb_addr_transform_setup();
+
+       pci_base = QLCNIC_ADDR_ERROR;
+       base_addr = addr & 0xfff00000;
+       offset = addr & 0x000fffff;
+
+       for (i = 0; i < QLCNIC_MAX_CRB_XFORM; i++) {
+               if (crb_addr_xform[i] == base_addr) {
+                       pci_base = i << 20;
+                       break;
+               }
+       }
+       if (pci_base == QLCNIC_ADDR_ERROR)
+               return pci_base;
+       else
+               return pci_base + offset;
+}
+
+#define QLCNIC_MAX_ROM_WAIT_USEC       100
+
+static int qlcnic_wait_rom_done(struct qlcnic_adapter *adapter)
+{
+       long timeout = 0;
+       long done = 0;
+
+       cond_resched();
+
+       while (done == 0) {
+               done = QLCRD32(adapter, QLCNIC_ROMUSB_GLB_STATUS);
+               done &= 2;
+               if (++timeout >= QLCNIC_MAX_ROM_WAIT_USEC) {
+                       dev_err(&adapter->pdev->dev,
+                               "Timeout reached  waiting for rom done");
+                       return -EIO;
+               }
+               udelay(1);
+       }
+       return 0;
+}
+
+static int do_rom_fast_read(struct qlcnic_adapter *adapter,
+                           int addr, int *valp)
+{
+       QLCWR32(adapter, QLCNIC_ROMUSB_ROM_ADDRESS, addr);
+       QLCWR32(adapter, QLCNIC_ROMUSB_ROM_DUMMY_BYTE_CNT, 0);
+       QLCWR32(adapter, QLCNIC_ROMUSB_ROM_ABYTE_CNT, 3);
+       QLCWR32(adapter, QLCNIC_ROMUSB_ROM_INSTR_OPCODE, 0xb);
+       if (qlcnic_wait_rom_done(adapter)) {
+               dev_err(&adapter->pdev->dev, "Error waiting for rom done\n");
+               return -EIO;
+       }
+       /* reset abyte_cnt and dummy_byte_cnt */
+       QLCWR32(adapter, QLCNIC_ROMUSB_ROM_ABYTE_CNT, 0);
+       udelay(10);
+       QLCWR32(adapter, QLCNIC_ROMUSB_ROM_DUMMY_BYTE_CNT, 0);
+
+       *valp = QLCRD32(adapter, QLCNIC_ROMUSB_ROM_RDATA);
+       return 0;
+}
+
+static int do_rom_fast_read_words(struct qlcnic_adapter *adapter, int addr,
+                                 u8 *bytes, size_t size)
+{
+       int addridx;
+       int ret = 0;
+
+       for (addridx = addr; addridx < (addr + size); addridx += 4) {
+               int v;
+               ret = do_rom_fast_read(adapter, addridx, &v);
+               if (ret != 0)
+                       break;
+               *(__le32 *)bytes = cpu_to_le32(v);
+               bytes += 4;
+       }
+
+       return ret;
+}
+
+int
+qlcnic_rom_fast_read_words(struct qlcnic_adapter *adapter, int addr,
+                               u8 *bytes, size_t size)
+{
+       int ret;
+
+       ret = qlcnic_rom_lock(adapter);
+       if (ret < 0)
+               return ret;
+
+       ret = do_rom_fast_read_words(adapter, addr, bytes, size);
+
+       qlcnic_rom_unlock(adapter);
+       return ret;
+}
+
+int qlcnic_rom_fast_read(struct qlcnic_adapter *adapter, int addr, int *valp)
+{
+       int ret;
+
+       if (qlcnic_rom_lock(adapter) != 0)
+               return -EIO;
+
+       ret = do_rom_fast_read(adapter, addr, valp);
+       qlcnic_rom_unlock(adapter);
+       return ret;
+}
+
+int qlcnic_pinit_from_rom(struct qlcnic_adapter *adapter)
+{
+       int addr, val;
+       int i, n, init_delay;
+       struct crb_addr_pair *buf;
+       unsigned offset;
+       u32 off;
+       struct pci_dev *pdev = adapter->pdev;
+
+       /* resetall */
+       qlcnic_rom_lock(adapter);
+       QLCWR32(adapter, QLCNIC_ROMUSB_GLB_SW_RESET, 0xffffffff);
+       qlcnic_rom_unlock(adapter);
+
+       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);
+               return -EIO;
+       }
+       offset = n & 0xffffU;
+       n = (n >> 16) & 0xffffU;
+
+       if (n >= 1024) {
+               dev_err(&pdev->dev, "QLOGIC card flash not initialized.\n");
+               return -EIO;
+       }
+
+       buf = kcalloc(n, sizeof(struct crb_addr_pair), GFP_KERNEL);
+       if (buf == NULL) {
+               dev_err(&pdev->dev, "Unable to calloc memory for rom read.\n");
+               return -ENOMEM;
+       }
+
+       for (i = 0; i < n; i++) {
+               if (qlcnic_rom_fast_read(adapter, 8*i + 4*offset, &val) != 0 ||
+               qlcnic_rom_fast_read(adapter, 8*i + 4*offset + 4, &addr) != 0) {
+                       kfree(buf);
+                       return -EIO;
+               }
+
+               buf[i].addr = addr;
+               buf[i].data = val;
+       }
+
+       for (i = 0; i < n; i++) {
+
+               off = qlcnic_decode_crb_addr(buf[i].addr);
+               if (off == QLCNIC_ADDR_ERROR) {
+                       dev_err(&pdev->dev, "CRB init value out of range %x\n",
+                                       buf[i].addr);
+                       continue;
+               }
+               off += QLCNIC_PCI_CRBSPACE;
+
+               if (off & 1)
+                       continue;
+
+               /* skipping cold reboot MAGIC */
+               if (off == QLCNIC_CAM_RAM(0x1fc))
+                       continue;
+               if (off == (QLCNIC_CRB_I2C0 + 0x1c))
+                       continue;
+               if (off == (ROMUSB_GLB + 0xbc)) /* do not reset PCI */
+                       continue;
+               if (off == (ROMUSB_GLB + 0xa8))
+                       continue;
+               if (off == (ROMUSB_GLB + 0xc8)) /* core clock */
+                       continue;
+               if (off == (ROMUSB_GLB + 0x24)) /* MN clock */
+                       continue;
+               if (off == (ROMUSB_GLB + 0x1c)) /* MS clock */
+                       continue;
+               if ((off & 0x0ff00000) == QLCNIC_CRB_DDR_NET)
+                       continue;
+               /* skip the function enable register */
+               if (off == QLCNIC_PCIE_REG(PCIE_SETUP_FUNCTION))
+                       continue;
+               if (off == QLCNIC_PCIE_REG(PCIE_SETUP_FUNCTION2))
+                       continue;
+               if ((off & 0x0ff00000) == QLCNIC_CRB_SMB)
+                       continue;
+
+               init_delay = 1;
+               /* After writing this register, HW needs time for CRB */
+               /* to quiet down (else crb_window returns 0xffffffff) */
+               if (off == QLCNIC_ROMUSB_GLB_SW_RESET)
+                       init_delay = 1000;
+
+               QLCWR32(adapter, off, buf[i].data);
+
+               msleep(init_delay);
+       }
+       kfree(buf);
+
+       /* p2dn replyCount */
+       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);
+       QLCWR32(adapter, QLCNIC_CRB_PEG_NET_1 + 0xc, 0);
+       QLCWR32(adapter, QLCNIC_CRB_PEG_NET_2 + 0x8, 0);
+       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);
+       return 0;
+}
+
+static int
+qlcnic_has_mn(struct qlcnic_adapter *adapter)
+{
+       u32 capability, flashed_ver;
+       capability = 0;
+
+       qlcnic_rom_fast_read(adapter,
+                       QLCNIC_FW_VERSION_OFFSET, (int *)&flashed_ver);
+       flashed_ver = QLCNIC_DECODE_VERSION(flashed_ver);
+
+       if (flashed_ver >= QLCNIC_VERSION_CODE(4, 0, 220)) {
+
+               capability = QLCRD32(adapter, QLCNIC_PEG_TUNE_CAPABILITY);
+               if (capability & QLCNIC_PEG_TUNE_MN_PRESENT)
+                       return 1;
+       }
+       return 0;
+}
+
+static
+struct uni_table_desc *qlcnic_get_table_desc(const u8 *unirom, int section)
+{
+       u32 i;
+       struct uni_table_desc *directory = (struct uni_table_desc *) &unirom[0];
+       __le32 entries = cpu_to_le32(directory->num_entries);
+
+       for (i = 0; i < entries; i++) {
+
+               __le32 offs = cpu_to_le32(directory->findex) +
+                               (i * cpu_to_le32(directory->entry_size));
+               __le32 tab_type = cpu_to_le32(*((u32 *)&unirom[offs] + 8));
+
+               if (tab_type == section)
+                       return (struct uni_table_desc *) &unirom[offs];
+       }
+
+       return NULL;
+}
+
+static int
+qlcnic_set_product_offs(struct qlcnic_adapter *adapter)
+{
+       struct uni_table_desc *ptab_descr;
+       const u8 *unirom = adapter->fw->data;
+       u32 i;
+       __le32 entries;
+       int mn_present = qlcnic_has_mn(adapter);
+
+       ptab_descr = qlcnic_get_table_desc(unirom,
+                               QLCNIC_UNI_DIR_SECT_PRODUCT_TBL);
+       if (ptab_descr == NULL)
+               return -1;
+
+       entries = cpu_to_le32(ptab_descr->num_entries);
+nomn:
+       for (i = 0; i < entries; i++) {
+
+               __le32 flags, file_chiprev, offs;
+               u8 chiprev = adapter->ahw.revision_id;
+               u32 flagbit;
+
+               offs = cpu_to_le32(ptab_descr->findex) +
+                               (i * cpu_to_le32(ptab_descr->entry_size));
+               flags = cpu_to_le32(*((int *)&unirom[offs] +
+                                               QLCNIC_UNI_FLAGS_OFF));
+               file_chiprev = cpu_to_le32(*((int *)&unirom[offs] +
+                                               QLCNIC_UNI_CHIP_REV_OFF));
+
+               flagbit = mn_present ? 1 : 2;
+
+               if ((chiprev == file_chiprev) &&
+                                       ((1ULL << flagbit) & flags)) {
+                       adapter->file_prd_off = offs;
+                       return 0;
+               }
+       }
+       if (mn_present) {
+               mn_present = 0;
+               goto nomn;
+       }
+       return -1;
+}
+
+static
+struct uni_data_desc *qlcnic_get_data_desc(struct qlcnic_adapter *adapter,
+                       u32 section, u32 idx_offset)
+{
+       const u8 *unirom = adapter->fw->data;
+       int idx = cpu_to_le32(*((int *)&unirom[adapter->file_prd_off] +
+                                                               idx_offset));
+       struct uni_table_desc *tab_desc;
+       __le32 offs;
+
+       tab_desc = qlcnic_get_table_desc(unirom, section);
+
+       if (tab_desc == NULL)
+               return NULL;
+
+       offs = cpu_to_le32(tab_desc->findex) +
+                       (cpu_to_le32(tab_desc->entry_size) * idx);
+
+       return (struct uni_data_desc *)&unirom[offs];
+}
+
+static u8 *
+qlcnic_get_bootld_offs(struct qlcnic_adapter *adapter)
+{
+       u32 offs = QLCNIC_BOOTLD_START;
+
+       if (adapter->fw_type == QLCNIC_UNIFIED_ROMIMAGE)
+               offs = cpu_to_le32((qlcnic_get_data_desc(adapter,
+                                       QLCNIC_UNI_DIR_SECT_BOOTLD,
+                                       QLCNIC_UNI_BOOTLD_IDX_OFF))->findex);
+
+       return (u8 *)&adapter->fw->data[offs];
+}
+
+static u8 *
+qlcnic_get_fw_offs(struct qlcnic_adapter *adapter)
+{
+       u32 offs = QLCNIC_IMAGE_START;
+
+       if (adapter->fw_type == QLCNIC_UNIFIED_ROMIMAGE)
+               offs = cpu_to_le32((qlcnic_get_data_desc(adapter,
+                                       QLCNIC_UNI_DIR_SECT_FW,
+                                       QLCNIC_UNI_FIRMWARE_IDX_OFF))->findex);
+
+       return (u8 *)&adapter->fw->data[offs];
+}
+
+static __le32
+qlcnic_get_fw_size(struct qlcnic_adapter *adapter)
+{
+       if (adapter->fw_type == QLCNIC_UNIFIED_ROMIMAGE)
+               return cpu_to_le32((qlcnic_get_data_desc(adapter,
+                                       QLCNIC_UNI_DIR_SECT_FW,
+                                       QLCNIC_UNI_FIRMWARE_IDX_OFF))->size);
+       else
+               return cpu_to_le32(
+                       *(u32 *)&adapter->fw->data[QLCNIC_FW_SIZE_OFFSET]);
+}
+
+static __le32
+qlcnic_get_fw_version(struct qlcnic_adapter *adapter)
+{
+       struct uni_data_desc *fw_data_desc;
+       const struct firmware *fw = adapter->fw;
+       __le32 major, minor, sub;
+       const u8 *ver_str;
+       int i, ret;
+
+       if (adapter->fw_type != QLCNIC_UNIFIED_ROMIMAGE)
+               return cpu_to_le32(*(u32 *)&fw->data[QLCNIC_FW_VERSION_OFFSET]);
+
+       fw_data_desc = qlcnic_get_data_desc(adapter, QLCNIC_UNI_DIR_SECT_FW,
+                       QLCNIC_UNI_FIRMWARE_IDX_OFF);
+       ver_str = fw->data + cpu_to_le32(fw_data_desc->findex) +
+               cpu_to_le32(fw_data_desc->size) - 17;
+
+       for (i = 0; i < 12; i++) {
+               if (!strncmp(&ver_str[i], "REV=", 4)) {
+                       ret = sscanf(&ver_str[i+4], "%u.%u.%u ",
+                                       &major, &minor, &sub);
+                       if (ret != 3)
+                               return 0;
+                       else
+                               return major + (minor << 8) + (sub << 16);
+               }
+       }
+
+       return 0;
+}
+
+static __le32
+qlcnic_get_bios_version(struct qlcnic_adapter *adapter)
+{
+       const struct firmware *fw = adapter->fw;
+       __le32 bios_ver, prd_off = adapter->file_prd_off;
+
+       if (adapter->fw_type != QLCNIC_UNIFIED_ROMIMAGE)
+               return cpu_to_le32(
+                       *(u32 *)&fw->data[QLCNIC_BIOS_VERSION_OFFSET]);
+
+       bios_ver = cpu_to_le32(*((u32 *) (&fw->data[prd_off])
+                               + QLCNIC_UNI_BIOS_VERSION_OFF));
+
+       return (bios_ver << 24) + ((bios_ver >> 8) & 0xff00) + (bios_ver >> 24);
+}
+
+int
+qlcnic_need_fw_reset(struct qlcnic_adapter *adapter)
+{
+       u32 count, old_count;
+       u32 val, version, major, minor, build;
+       int i, timeout;
+
+       if (adapter->need_fw_reset)
+               return 1;
+
+       /* last attempt had failed */
+       if (QLCRD32(adapter, CRB_CMDPEG_STATE) == PHAN_INITIALIZE_FAILED)
+               return 1;
+
+       old_count = QLCRD32(adapter, QLCNIC_PEG_ALIVE_COUNTER);
+
+       for (i = 0; i < 10; i++) {
+
+               timeout = msleep_interruptible(200);
+               if (timeout) {
+                       QLCWR32(adapter, CRB_CMDPEG_STATE,
+                                       PHAN_INITIALIZE_FAILED);
+                       return -EINTR;
+               }
+
+               count = QLCRD32(adapter, QLCNIC_PEG_ALIVE_COUNTER);
+               if (count != old_count)
+                       break;
+       }
+
+       /* firmware is dead */
+       if (count == old_count)
+               return 1;
+
+       /* check if we have got newer or different file firmware */
+       if (adapter->fw) {
+
+               val = qlcnic_get_fw_version(adapter);
+
+               version = QLCNIC_DECODE_VERSION(val);
+
+               major = QLCRD32(adapter, QLCNIC_FW_VERSION_MAJOR);
+               minor = QLCRD32(adapter, QLCNIC_FW_VERSION_MINOR);
+               build = QLCRD32(adapter, QLCNIC_FW_VERSION_SUB);
+
+               if (version > QLCNIC_VERSION_CODE(major, minor, build))
+                       return 1;
+       }
+
+       return 0;
+}
+
+static const char *fw_name[] = {
+       QLCNIC_UNIFIED_ROMIMAGE_NAME,
+       QLCNIC_FLASH_ROMIMAGE_NAME,
+};
+
+int
+qlcnic_load_firmware(struct qlcnic_adapter *adapter)
+{
+       u64 *ptr64;
+       u32 i, flashaddr, size;
+       const struct firmware *fw = adapter->fw;
+       struct pci_dev *pdev = adapter->pdev;
+
+       dev_info(&pdev->dev, "loading firmware from %s\n",
+                       fw_name[adapter->fw_type]);
+
+       if (fw) {
+               __le64 data;
+
+               size = (QLCNIC_IMAGE_START - QLCNIC_BOOTLD_START) / 8;
+
+               ptr64 = (u64 *)qlcnic_get_bootld_offs(adapter);
+               flashaddr = QLCNIC_BOOTLD_START;
+
+               for (i = 0; i < size; i++) {
+                       data = cpu_to_le64(ptr64[i]);
+
+                       if (qlcnic_pci_mem_write_2M(adapter, flashaddr, data))
+                               return -EIO;
+
+                       flashaddr += 8;
+               }
+
+               size = (__force u32)qlcnic_get_fw_size(adapter) / 8;
+
+               ptr64 = (u64 *)qlcnic_get_fw_offs(adapter);
+               flashaddr = QLCNIC_IMAGE_START;
+
+               for (i = 0; i < size; i++) {
+                       data = cpu_to_le64(ptr64[i]);
+
+                       if (qlcnic_pci_mem_write_2M(adapter,
+                                               flashaddr, data))
+                               return -EIO;
+
+                       flashaddr += 8;
+               }
+       } else {
+               u64 data;
+               u32 hi, lo;
+
+               size = (QLCNIC_IMAGE_START - QLCNIC_BOOTLD_START) / 8;
+               flashaddr = QLCNIC_BOOTLD_START;
+
+               for (i = 0; i < size; i++) {
+                       if (qlcnic_rom_fast_read(adapter,
+                                       flashaddr, (int *)&lo) != 0)
+                               return -EIO;
+                       if (qlcnic_rom_fast_read(adapter,
+                                       flashaddr + 4, (int *)&hi) != 0)
+                               return -EIO;
+
+                       data = (((u64)hi << 32) | lo);
+
+                       if (qlcnic_pci_mem_write_2M(adapter,
+                                               flashaddr, data))
+                               return -EIO;
+
+                       flashaddr += 8;
+               }
+       }
+       msleep(1);
+
+       QLCWR32(adapter, QLCNIC_CRB_PEG_NET_0 + 0x18, 0x1020);
+       QLCWR32(adapter, QLCNIC_ROMUSB_GLB_SW_RESET, 0x80001e);
+       return 0;
+}
+
+static int
+qlcnic_validate_firmware(struct qlcnic_adapter *adapter)
+{
+       __le32 val;
+       u32 ver, min_ver, bios, min_size;
+       struct pci_dev *pdev = adapter->pdev;
+       const struct firmware *fw = adapter->fw;
+       u8 fw_type = adapter->fw_type;
+
+       if (fw_type == QLCNIC_UNIFIED_ROMIMAGE) {
+               if (qlcnic_set_product_offs(adapter))
+                       return -EINVAL;
+
+               min_size = QLCNIC_UNI_FW_MIN_SIZE;
+       } else {
+               val = cpu_to_le32(*(u32 *)&fw->data[QLCNIC_FW_MAGIC_OFFSET]);
+               if ((__force u32)val != QLCNIC_BDINFO_MAGIC)
+                       return -EINVAL;
+
+               min_size = QLCNIC_FW_MIN_SIZE;
+       }
+
+       if (fw->size < min_size)
+               return -EINVAL;
+
+       val = qlcnic_get_fw_version(adapter);
+
+       min_ver = QLCNIC_VERSION_CODE(4, 0, 216);
+
+       ver = QLCNIC_DECODE_VERSION(val);
+
+       if ((_major(ver) > _QLCNIC_LINUX_MAJOR) || (ver < min_ver)) {
+               dev_err(&pdev->dev,
+                               "%s: firmware version %d.%d.%d unsupported\n",
+               fw_name[fw_type], _major(ver), _minor(ver), _build(ver));
+               return -EINVAL;
+       }
+
+       val = qlcnic_get_bios_version(adapter);
+       qlcnic_rom_fast_read(adapter, QLCNIC_BIOS_VERSION_OFFSET, (int *)&bios);
+       if ((__force u32)val != bios) {
+               dev_err(&pdev->dev, "%s: firmware bios is incompatible\n",
+                               fw_name[fw_type]);
+               return -EINVAL;
+       }
+
+       /* check if flashed firmware is newer */
+       if (qlcnic_rom_fast_read(adapter,
+                       QLCNIC_FW_VERSION_OFFSET, (int *)&val))
+               return -EIO;
+
+       val = QLCNIC_DECODE_VERSION(val);
+       if (val > ver) {
+               dev_info(&pdev->dev, "%s: firmware is older than flash\n",
+                               fw_name[fw_type]);
+               return -EINVAL;
+       }
+
+       QLCWR32(adapter, QLCNIC_CAM_RAM(0x1fc), QLCNIC_BDINFO_MAGIC);
+       return 0;
+}
+
+static void
+qlcnic_get_next_fwtype(struct qlcnic_adapter *adapter)
+{
+       u8 fw_type;
+
+       switch (adapter->fw_type) {
+       case QLCNIC_UNKNOWN_ROMIMAGE:
+               fw_type = QLCNIC_UNIFIED_ROMIMAGE;
+               break;
+
+       case QLCNIC_UNIFIED_ROMIMAGE:
+       default:
+               fw_type = QLCNIC_FLASH_ROMIMAGE;
+               break;
+       }
+
+       adapter->fw_type = fw_type;
+}
+
+
+
+void qlcnic_request_firmware(struct qlcnic_adapter *adapter)
+{
+       struct pci_dev *pdev = adapter->pdev;
+       int rc;
+
+       adapter->fw_type = QLCNIC_UNKNOWN_ROMIMAGE;
+
+next:
+       qlcnic_get_next_fwtype(adapter);
+
+       if (adapter->fw_type == QLCNIC_FLASH_ROMIMAGE) {
+               adapter->fw = NULL;
+       } else {
+               rc = request_firmware(&adapter->fw,
+                               fw_name[adapter->fw_type], &pdev->dev);
+               if (rc != 0)
+                       goto next;
+
+               rc = qlcnic_validate_firmware(adapter);
+               if (rc != 0) {
+                       release_firmware(adapter->fw);
+                       msleep(1);
+                       goto next;
+               }
+       }
+}
+
+
+void
+qlcnic_release_firmware(struct qlcnic_adapter *adapter)
+{
+       if (adapter->fw)
+               release_firmware(adapter->fw);
+       adapter->fw = NULL;
+}
+
+int qlcnic_phantom_init(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, "firmware init failed\n");
+       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_receive_peg_ready(adapter);
+       if (err)
+               return err;
+
+       QLCWR32(adapter, CRB_NIC_CAPABILITIES_HOST, INTR_SCHEME_PERPORT);
+       QLCWR32(adapter, CRB_NIC_MSI_MODE_HOST, MSI_MODE_MULTIFUNC);
+       QLCWR32(adapter, CRB_MPORT_MODE, MPORT_MULTI_FUNCTION_MODE);
+       QLCWR32(adapter, CRB_CMDPEG_STATE, PHAN_INITIALIZE_ACK);
+
+       return err;
+}
+
+static void
+qlcnic_handle_linkevent(struct qlcnic_adapter *adapter,
+                               struct qlcnic_fw_msg *msg)
+{
+       u32 cable_OUI;
+       u16 cable_len;
+       u16 link_speed;
+       u8  link_status, module, duplex, autoneg;
+       struct net_device *netdev = adapter->netdev;
+
+       adapter->has_link_events = 1;
+
+       cable_OUI = msg->body[1] & 0xffffffff;
+       cable_len = (msg->body[1] >> 32) & 0xffff;
+       link_speed = (msg->body[1] >> 48) & 0xffff;
+
+       link_status = msg->body[2] & 0xff;
+       duplex = (msg->body[2] >> 16) & 0xff;
+       autoneg = (msg->body[2] >> 24) & 0xff;
+
+       module = (msg->body[2] >> 8) & 0xff;
+       if (module == LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLE)
+               dev_info(&netdev->dev, "unsupported cable: OUI 0x%x, "
+                               "length %d\n", cable_OUI, cable_len);
+       else if (module == LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLELEN)
+               dev_info(&netdev->dev, "unsupported cable length %d\n",
+                               cable_len);
+
+       qlcnic_advert_link_change(adapter, link_status);
+
+       if (duplex == LINKEVENT_FULL_DUPLEX)
+               adapter->link_duplex = DUPLEX_FULL;
+       else
+               adapter->link_duplex = DUPLEX_HALF;
+
+       adapter->module_type = module;
+       adapter->link_autoneg = autoneg;
+       adapter->link_speed = link_speed;
+}
+
+static void
+qlcnic_handle_fw_message(int desc_cnt, int index,
+               struct qlcnic_host_sds_ring *sds_ring)
+{
+       struct qlcnic_fw_msg msg;
+       struct status_desc *desc;
+       int i = 0, opcode;
+
+       while (desc_cnt > 0 && i < 8) {
+               desc = &sds_ring->desc_head[index];
+               msg.words[i++] = le64_to_cpu(desc->status_desc_data[0]);
+               msg.words[i++] = le64_to_cpu(desc->status_desc_data[1]);
+
+               index = get_next_index(index, sds_ring->num_desc);
+               desc_cnt--;
+       }
+
+       opcode = qlcnic_get_nic_msg_opcode(msg.body[0]);
+       switch (opcode) {
+       case QLCNIC_C2H_OPCODE_GET_LINKEVENT_RESPONSE:
+               qlcnic_handle_linkevent(sds_ring->adapter, &msg);
+               break;
+       default:
+               break;
+       }
+}
+
+static int
+qlcnic_alloc_rx_skb(struct qlcnic_adapter *adapter,
+               struct qlcnic_host_rds_ring *rds_ring,
+               struct qlcnic_rx_buffer *buffer)
+{
+       struct sk_buff *skb;
+       dma_addr_t dma;
+       struct pci_dev *pdev = adapter->pdev;
+
+       buffer->skb = dev_alloc_skb(rds_ring->skb_size);
+       if (!buffer->skb)
+               return -ENOMEM;
+
+       skb = buffer->skb;
+
+       if (!adapter->ahw.cut_through)
+               skb_reserve(skb, 2);
+
+       dma = pci_map_single(pdev, skb->data,
+                       rds_ring->dma_size, PCI_DMA_FROMDEVICE);
+
+       if (pci_dma_mapping_error(pdev, dma)) {
+               dev_kfree_skb_any(skb);
+               buffer->skb = NULL;
+               return -ENOMEM;
+       }
+
+       buffer->skb = skb;
+       buffer->dma = dma;
+       buffer->state = QLCNIC_BUFFER_BUSY;
+
+       return 0;
+}
+
+static struct sk_buff *qlcnic_process_rxbuf(struct qlcnic_adapter *adapter,
+               struct qlcnic_host_rds_ring *rds_ring, u16 index, u16 cksum)
+{
+       struct qlcnic_rx_buffer *buffer;
+       struct sk_buff *skb;
+
+       buffer = &rds_ring->rx_buf_arr[index];
+
+       pci_unmap_single(adapter->pdev, buffer->dma, rds_ring->dma_size,
+                       PCI_DMA_FROMDEVICE);
+
+       skb = buffer->skb;
+       if (!skb)
+               goto no_skb;
+
+       if (likely(adapter->rx_csum && cksum == STATUS_CKSUM_OK)) {
+               adapter->stats.csummed++;
+               skb->ip_summed = CHECKSUM_UNNECESSARY;
+       } else {
+               skb->ip_summed = CHECKSUM_NONE;
+       }
+
+       skb->dev = adapter->netdev;
+
+       buffer->skb = NULL;
+no_skb:
+       buffer->state = QLCNIC_BUFFER_FREE;
+       return skb;
+}
+
+static struct qlcnic_rx_buffer *
+qlcnic_process_rcv(struct qlcnic_adapter *adapter,
+               struct qlcnic_host_sds_ring *sds_ring,
+               int ring, u64 sts_data0)
+{
+       struct net_device *netdev = adapter->netdev;
+       struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
+       struct qlcnic_rx_buffer *buffer;
+       struct sk_buff *skb;
+       struct qlcnic_host_rds_ring *rds_ring;
+       int index, length, cksum, pkt_offset;
+
+       if (unlikely(ring >= adapter->max_rds_rings))
+               return NULL;
+
+       rds_ring = &recv_ctx->rds_rings[ring];
+
+       index = qlcnic_get_sts_refhandle(sts_data0);
+       if (unlikely(index >= rds_ring->num_desc))
+               return NULL;
+
+       buffer = &rds_ring->rx_buf_arr[index];
+
+       length = qlcnic_get_sts_totallength(sts_data0);
+       cksum  = qlcnic_get_sts_status(sts_data0);
+       pkt_offset = qlcnic_get_sts_pkt_offset(sts_data0);
+
+       skb = qlcnic_process_rxbuf(adapter, rds_ring, index, cksum);
+       if (!skb)
+               return buffer;
+
+       if (length > rds_ring->skb_size)
+               skb_put(skb, rds_ring->skb_size);
+       else
+               skb_put(skb, length);
+
+       if (pkt_offset)
+               skb_pull(skb, pkt_offset);
+
+       skb->truesize = skb->len + sizeof(struct sk_buff);
+       skb->protocol = eth_type_trans(skb, netdev);
+
+       napi_gro_receive(&sds_ring->napi, skb);
+
+       adapter->stats.rx_pkts++;
+       adapter->stats.rxbytes += length;
+
+       return buffer;
+}
+
+#define QLC_TCP_HDR_SIZE            20
+#define QLC_TCP_TS_OPTION_SIZE      12
+#define QLC_TCP_TS_HDR_SIZE         (QLC_TCP_HDR_SIZE + QLC_TCP_TS_OPTION_SIZE)
+
+static struct qlcnic_rx_buffer *
+qlcnic_process_lro(struct qlcnic_adapter *adapter,
+               struct qlcnic_host_sds_ring *sds_ring,
+               int ring, u64 sts_data0, u64 sts_data1)
+{
+       struct net_device *netdev = adapter->netdev;
+       struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
+       struct qlcnic_rx_buffer *buffer;
+       struct sk_buff *skb;
+       struct qlcnic_host_rds_ring *rds_ring;
+       struct iphdr *iph;
+       struct tcphdr *th;
+       bool push, timestamp;
+       int l2_hdr_offset, l4_hdr_offset;
+       int index;
+       u16 lro_length, length, data_offset;
+       u32 seq_number;
+
+       if (unlikely(ring > adapter->max_rds_rings))
+               return NULL;
+
+       rds_ring = &recv_ctx->rds_rings[ring];
+
+       index = qlcnic_get_lro_sts_refhandle(sts_data0);
+       if (unlikely(index > rds_ring->num_desc))
+               return NULL;
+
+       buffer = &rds_ring->rx_buf_arr[index];
+
+       timestamp = qlcnic_get_lro_sts_timestamp(sts_data0);
+       lro_length = qlcnic_get_lro_sts_length(sts_data0);
+       l2_hdr_offset = qlcnic_get_lro_sts_l2_hdr_offset(sts_data0);
+       l4_hdr_offset = qlcnic_get_lro_sts_l4_hdr_offset(sts_data0);
+       push = qlcnic_get_lro_sts_push_flag(sts_data0);
+       seq_number = qlcnic_get_lro_sts_seq_number(sts_data1);
+
+       skb = qlcnic_process_rxbuf(adapter, rds_ring, index, STATUS_CKSUM_OK);
+       if (!skb)
+               return buffer;
+
+       if (timestamp)
+               data_offset = l4_hdr_offset + QLC_TCP_TS_HDR_SIZE;
+       else
+               data_offset = l4_hdr_offset + QLC_TCP_HDR_SIZE;
+
+       skb_put(skb, lro_length + data_offset);
+
+       skb->truesize = skb->len + sizeof(struct sk_buff) + skb_headroom(skb);
+
+       skb_pull(skb, l2_hdr_offset);
+       skb->protocol = eth_type_trans(skb, netdev);
+
+       iph = (struct iphdr *)skb->data;
+       th = (struct tcphdr *)(skb->data + (iph->ihl << 2));
+
+       length = (iph->ihl << 2) + (th->doff << 2) + lro_length;
+       iph->tot_len = htons(length);
+       iph->check = 0;
+       iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
+       th->psh = push;
+       th->seq = htonl(seq_number);
+
+       length = skb->len;
+
+       netif_receive_skb(skb);
+
+       adapter->stats.lro_pkts++;
+       adapter->stats.rxbytes += length;
+
+       return buffer;
+}
+
+int
+qlcnic_process_rcv_ring(struct qlcnic_host_sds_ring *sds_ring, int max)
+{
+       struct qlcnic_adapter *adapter = sds_ring->adapter;
+       struct list_head *cur;
+       struct status_desc *desc;
+       struct qlcnic_rx_buffer *rxbuf;
+       u64 sts_data0, sts_data1;
+
+       int count = 0;
+       int opcode, ring, desc_cnt;
+       u32 consumer = sds_ring->consumer;
+
+       while (count < max) {
+               desc = &sds_ring->desc_head[consumer];
+               sts_data0 = le64_to_cpu(desc->status_desc_data[0]);
+
+               if (!(sts_data0 & STATUS_OWNER_HOST))
+                       break;
+
+               desc_cnt = qlcnic_get_sts_desc_cnt(sts_data0);
+               opcode = qlcnic_get_sts_opcode(sts_data0);
+
+               switch (opcode) {
+               case QLCNIC_RXPKT_DESC:
+               case QLCNIC_OLD_RXPKT_DESC:
+               case QLCNIC_SYN_OFFLOAD:
+                       ring = qlcnic_get_sts_type(sts_data0);
+                       rxbuf = qlcnic_process_rcv(adapter, sds_ring,
+                                       ring, sts_data0);
+                       break;
+               case QLCNIC_LRO_DESC:
+                       ring = qlcnic_get_lro_sts_type(sts_data0);
+                       sts_data1 = le64_to_cpu(desc->status_desc_data[1]);
+                       rxbuf = qlcnic_process_lro(adapter, sds_ring,
+                                       ring, sts_data0, sts_data1);
+                       break;
+               case QLCNIC_RESPONSE_DESC:
+                       qlcnic_handle_fw_message(desc_cnt, consumer, sds_ring);
+               default:
+                       goto skip;
+               }
+
+               WARN_ON(desc_cnt > 1);
+
+               if (rxbuf)
+                       list_add_tail(&rxbuf->list, &sds_ring->free_list[ring]);
+
+skip:
+               for (; desc_cnt > 0; desc_cnt--) {
+                       desc = &sds_ring->desc_head[consumer];
+                       desc->status_desc_data[0] =
+                               cpu_to_le64(STATUS_OWNER_PHANTOM);
+                       consumer = get_next_index(consumer, sds_ring->num_desc);
+               }
+               count++;
+       }
+
+       for (ring = 0; ring < adapter->max_rds_rings; ring++) {
+               struct qlcnic_host_rds_ring *rds_ring =
+                       &adapter->recv_ctx.rds_rings[ring];
+
+               if (!list_empty(&sds_ring->free_list[ring])) {
+                       list_for_each(cur, &sds_ring->free_list[ring]) {
+                               rxbuf = list_entry(cur,
+                                               struct qlcnic_rx_buffer, list);
+                               qlcnic_alloc_rx_skb(adapter, rds_ring, rxbuf);
+                       }
+                       spin_lock(&rds_ring->lock);
+                       list_splice_tail_init(&sds_ring->free_list[ring],
+                                               &rds_ring->free_list);
+                       spin_unlock(&rds_ring->lock);
+               }
+
+               qlcnic_post_rx_buffers_nodb(adapter, rds_ring);
+       }
+
+       if (count) {
+               sds_ring->consumer = consumer;
+               writel(consumer, sds_ring->crb_sts_consumer);
+       }
+
+       return count;
+}
+
+void
+qlcnic_post_rx_buffers(struct qlcnic_adapter *adapter, u32 ringid,
+       struct qlcnic_host_rds_ring *rds_ring)
+{
+       struct rcv_desc *pdesc;
+       struct qlcnic_rx_buffer *buffer;
+       int producer, count = 0;
+       struct list_head *head;
+
+       producer = rds_ring->producer;
+
+       spin_lock(&rds_ring->lock);
+       head = &rds_ring->free_list;
+       while (!list_empty(head)) {
+
+               buffer = list_entry(head->next, struct qlcnic_rx_buffer, list);
+
+               if (!buffer->skb) {
+                       if (qlcnic_alloc_rx_skb(adapter, rds_ring, buffer))
+                               break;
+               }
+
+               count++;
+               list_del(&buffer->list);
+
+               /* make a rcv descriptor  */
+               pdesc = &rds_ring->desc_head[producer];
+               pdesc->addr_buffer = cpu_to_le64(buffer->dma);
+               pdesc->reference_handle = cpu_to_le16(buffer->ref_handle);
+               pdesc->buffer_length = cpu_to_le32(rds_ring->dma_size);
+
+               producer = get_next_index(producer, rds_ring->num_desc);
+       }
+       spin_unlock(&rds_ring->lock);
+
+       if (count) {
+               rds_ring->producer = producer;
+               writel((producer-1) & (rds_ring->num_desc-1),
+                               rds_ring->crb_rcv_producer);
+       }
+}
+
+static void
+qlcnic_post_rx_buffers_nodb(struct qlcnic_adapter *adapter,
+               struct qlcnic_host_rds_ring *rds_ring)
+{
+       struct rcv_desc *pdesc;
+       struct qlcnic_rx_buffer *buffer;
+       int producer, count = 0;
+       struct list_head *head;
+
+       producer = rds_ring->producer;
+       if (!spin_trylock(&rds_ring->lock))
+               return;
+
+       head = &rds_ring->free_list;
+       while (!list_empty(head)) {
+
+               buffer = list_entry(head->next, struct qlcnic_rx_buffer, list);
+
+               if (!buffer->skb) {
+                       if (qlcnic_alloc_rx_skb(adapter, rds_ring, buffer))
+                               break;
+               }
+
+               count++;
+               list_del(&buffer->list);
+
+               /* make a rcv descriptor  */
+               pdesc = &rds_ring->desc_head[producer];
+               pdesc->reference_handle = cpu_to_le16(buffer->ref_handle);
+               pdesc->buffer_length = cpu_to_le32(rds_ring->dma_size);
+               pdesc->addr_buffer = cpu_to_le64(buffer->dma);
+
+               producer = get_next_index(producer, rds_ring->num_desc);
+       }
+
+       if (count) {
+               rds_ring->producer = producer;
+               writel((producer - 1) & (rds_ring->num_desc - 1),
+                               rds_ring->crb_rcv_producer);
+       }
+       spin_unlock(&rds_ring->lock);
+}
+
+static struct qlcnic_rx_buffer *
+qlcnic_process_rcv_diag(struct qlcnic_adapter *adapter,
+               struct qlcnic_host_sds_ring *sds_ring,
+               int ring, u64 sts_data0)
+{
+       struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
+       struct qlcnic_rx_buffer *buffer;
+       struct sk_buff *skb;
+       struct qlcnic_host_rds_ring *rds_ring;
+       int index, length, cksum, pkt_offset;
+
+       if (unlikely(ring >= adapter->max_rds_rings))
+               return NULL;
+
+       rds_ring = &recv_ctx->rds_rings[ring];
+
+       index = qlcnic_get_sts_refhandle(sts_data0);
+       if (unlikely(index >= rds_ring->num_desc))
+               return NULL;
+
+       buffer = &rds_ring->rx_buf_arr[index];
+
+       length = qlcnic_get_sts_totallength(sts_data0);
+       cksum  = qlcnic_get_sts_status(sts_data0);
+       pkt_offset = qlcnic_get_sts_pkt_offset(sts_data0);
+
+       skb = qlcnic_process_rxbuf(adapter, rds_ring, index, cksum);
+       if (!skb)
+               return buffer;
+
+       skb_put(skb, rds_ring->skb_size);
+
+       if (pkt_offset)
+               skb_pull(skb, pkt_offset);
+
+       skb->truesize = skb->len + sizeof(struct sk_buff);
+
+       if (!qlcnic_check_loopback_buff(skb->data))
+               adapter->diag_cnt++;
+
+       dev_kfree_skb_any(skb);
+
+       return buffer;
+}
+
+void
+qlcnic_process_rcv_ring_diag(struct qlcnic_host_sds_ring *sds_ring)
+{
+       struct qlcnic_adapter *adapter = sds_ring->adapter;
+       struct status_desc *desc;
+       struct qlcnic_rx_buffer *rxbuf;
+       u64 sts_data0;
+
+       int opcode, ring, desc_cnt;
+       u32 consumer = sds_ring->consumer;
+
+       desc = &sds_ring->desc_head[consumer];
+       sts_data0 = le64_to_cpu(desc->status_desc_data[0]);
+
+       if (!(sts_data0 & STATUS_OWNER_HOST))
+               return;
+
+       desc_cnt = qlcnic_get_sts_desc_cnt(sts_data0);
+       opcode = qlcnic_get_sts_opcode(sts_data0);
+
+       ring = qlcnic_get_sts_type(sts_data0);
+       rxbuf = qlcnic_process_rcv_diag(adapter, sds_ring,
+                                       ring, sts_data0);
+
+       desc->status_desc_data[0] = cpu_to_le64(STATUS_OWNER_PHANTOM);
+       consumer = get_next_index(consumer, sds_ring->num_desc);
+
+       sds_ring->consumer = consumer;
+       writel(consumer, sds_ring->crb_sts_consumer);
+}
diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c
new file mode 100644 (file)
index 0000000..665e8e5
--- /dev/null
@@ -0,0 +1,2720 @@
+/*
+ * Copyright (C) 2009 - QLogic Corporation.
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called "COPYING".
+ *
+ */
+
+#include <linux/vmalloc.h>
+#include <linux/interrupt.h>
+
+#include "qlcnic.h"
+
+#include <linux/dma-mapping.h>
+#include <linux/if_vlan.h>
+#include <net/ip.h>
+#include <linux/ipv6.h>
+#include <linux/inetdevice.h>
+#include <linux/sysfs.h>
+
+MODULE_DESCRIPTION("QLogic 10 GbE Converged Ethernet Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(QLCNIC_LINUX_VERSIONID);
+MODULE_FIRMWARE(QLCNIC_UNIFIED_ROMIMAGE_NAME);
+
+char qlcnic_driver_name[] = "qlcnic";
+static const char qlcnic_driver_string[] = "QLogic Converged Ethernet Driver v"
+    QLCNIC_LINUX_VERSIONID;
+
+static int port_mode = QLCNIC_PORT_MODE_AUTO_NEG;
+
+/* Default to restricted 1G auto-neg mode */
+static int wol_port_mode = 5;
+
+static int use_msi = 1;
+module_param(use_msi, int, 0644);
+MODULE_PARM_DESC(use_msi, "MSI interrupt (0=disabled, 1=enabled");
+
+static int use_msi_x = 1;
+module_param(use_msi_x, int, 0644);
+MODULE_PARM_DESC(use_msi_x, "MSI-X interrupt (0=disabled, 1=enabled");
+
+static int auto_fw_reset = AUTO_FW_RESET_ENABLED;
+module_param(auto_fw_reset, int, 0644);
+MODULE_PARM_DESC(auto_fw_reset, "Auto firmware reset (0=disabled, 1=enabled");
+
+static int __devinit qlcnic_probe(struct pci_dev *pdev,
+               const struct pci_device_id *ent);
+static void __devexit qlcnic_remove(struct pci_dev *pdev);
+static int qlcnic_open(struct net_device *netdev);
+static int qlcnic_close(struct net_device *netdev);
+static void qlcnic_tx_timeout(struct net_device *netdev);
+static void qlcnic_tx_timeout_task(struct work_struct *work);
+static void qlcnic_attach_work(struct work_struct *work);
+static void qlcnic_fwinit_work(struct work_struct *work);
+static void qlcnic_fw_poll_work(struct work_struct *work);
+static void qlcnic_schedule_work(struct qlcnic_adapter *adapter,
+               work_func_t func, int delay);
+static void qlcnic_cancel_fw_work(struct qlcnic_adapter *adapter);
+static int qlcnic_poll(struct napi_struct *napi, int budget);
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void qlcnic_poll_controller(struct net_device *netdev);
+#endif
+
+static void qlcnic_create_sysfs_entries(struct qlcnic_adapter *adapter);
+static void qlcnic_remove_sysfs_entries(struct qlcnic_adapter *adapter);
+static void qlcnic_create_diag_entries(struct qlcnic_adapter *adapter);
+static void qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter);
+
+static void qlcnic_clr_all_drv_state(struct qlcnic_adapter *adapter);
+static int qlcnic_can_start_firmware(struct qlcnic_adapter *adapter);
+
+static irqreturn_t qlcnic_tmp_intr(int irq, void *data);
+static irqreturn_t qlcnic_intr(int irq, void *data);
+static irqreturn_t qlcnic_msi_intr(int irq, void *data);
+static irqreturn_t qlcnic_msix_intr(int irq, void *data);
+
+static struct net_device_stats *qlcnic_get_stats(struct net_device *netdev);
+static void qlcnic_config_indev_addr(struct net_device *dev, unsigned long);
+
+/*  PCI Device ID Table  */
+#define ENTRY(device) \
+       {PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, (device)), \
+       .class = PCI_CLASS_NETWORK_ETHERNET << 8, .class_mask = ~0}
+
+#define PCI_DEVICE_ID_QLOGIC_QLE824X  0x8020
+
+static DEFINE_PCI_DEVICE_TABLE(qlcnic_pci_tbl) = {
+       ENTRY(PCI_DEVICE_ID_QLOGIC_QLE824X),
+       {0,}
+};
+
+MODULE_DEVICE_TABLE(pci, qlcnic_pci_tbl);
+
+
+void
+qlcnic_update_cmd_producer(struct qlcnic_adapter *adapter,
+               struct qlcnic_host_tx_ring *tx_ring)
+{
+       writel(tx_ring->producer, tx_ring->crb_cmd_producer);
+
+       if (qlcnic_tx_avail(tx_ring) <= TX_STOP_THRESH) {
+               netif_stop_queue(adapter->netdev);
+               smp_mb();
+       }
+}
+
+static const u32 msi_tgt_status[8] = {
+       ISR_INT_TARGET_STATUS, ISR_INT_TARGET_STATUS_F1,
+       ISR_INT_TARGET_STATUS_F2, ISR_INT_TARGET_STATUS_F3,
+       ISR_INT_TARGET_STATUS_F4, ISR_INT_TARGET_STATUS_F5,
+       ISR_INT_TARGET_STATUS_F6, ISR_INT_TARGET_STATUS_F7
+};
+
+static const
+struct qlcnic_legacy_intr_set legacy_intr[] = QLCNIC_LEGACY_INTR_CONFIG;
+
+static inline void qlcnic_disable_int(struct qlcnic_host_sds_ring *sds_ring)
+{
+       writel(0, sds_ring->crb_intr_mask);
+}
+
+static inline void qlcnic_enable_int(struct qlcnic_host_sds_ring *sds_ring)
+{
+       struct qlcnic_adapter *adapter = sds_ring->adapter;
+
+       writel(0x1, sds_ring->crb_intr_mask);
+
+       if (!QLCNIC_IS_MSI_FAMILY(adapter))
+               writel(0xfbff, adapter->tgt_mask_reg);
+}
+
+static int
+qlcnic_alloc_sds_rings(struct qlcnic_recv_context *recv_ctx, int count)
+{
+       int size = sizeof(struct qlcnic_host_sds_ring) * count;
+
+       recv_ctx->sds_rings = kzalloc(size, GFP_KERNEL);
+
+       return (recv_ctx->sds_rings == NULL);
+}
+
+static void
+qlcnic_free_sds_rings(struct qlcnic_recv_context *recv_ctx)
+{
+       if (recv_ctx->sds_rings != NULL)
+               kfree(recv_ctx->sds_rings);
+
+       recv_ctx->sds_rings = NULL;
+}
+
+static int
+qlcnic_napi_add(struct qlcnic_adapter *adapter, struct net_device *netdev)
+{
+       int ring;
+       struct qlcnic_host_sds_ring *sds_ring;
+       struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
+
+       if (qlcnic_alloc_sds_rings(recv_ctx, adapter->max_sds_rings))
+               return -ENOMEM;
+
+       for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+               sds_ring = &recv_ctx->sds_rings[ring];
+               netif_napi_add(netdev, &sds_ring->napi,
+                               qlcnic_poll, QLCNIC_NETDEV_WEIGHT);
+       }
+
+       return 0;
+}
+
+static void
+qlcnic_napi_del(struct qlcnic_adapter *adapter)
+{
+       int ring;
+       struct qlcnic_host_sds_ring *sds_ring;
+       struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
+
+       for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+               sds_ring = &recv_ctx->sds_rings[ring];
+               netif_napi_del(&sds_ring->napi);
+       }
+
+       qlcnic_free_sds_rings(&adapter->recv_ctx);
+}
+
+static void
+qlcnic_napi_enable(struct qlcnic_adapter *adapter)
+{
+       int ring;
+       struct qlcnic_host_sds_ring *sds_ring;
+       struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
+
+       for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+               sds_ring = &recv_ctx->sds_rings[ring];
+               napi_enable(&sds_ring->napi);
+               qlcnic_enable_int(sds_ring);
+       }
+}
+
+static void
+qlcnic_napi_disable(struct qlcnic_adapter *adapter)
+{
+       int ring;
+       struct qlcnic_host_sds_ring *sds_ring;
+       struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
+
+       for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+               sds_ring = &recv_ctx->sds_rings[ring];
+               qlcnic_disable_int(sds_ring);
+               napi_synchronize(&sds_ring->napi);
+               napi_disable(&sds_ring->napi);
+       }
+}
+
+static void qlcnic_clear_stats(struct qlcnic_adapter *adapter)
+{
+       memset(&adapter->stats, 0, sizeof(adapter->stats));
+       return;
+}
+
+static int qlcnic_set_dma_mask(struct qlcnic_adapter *adapter)
+{
+       struct pci_dev *pdev = adapter->pdev;
+       u64 mask, cmask;
+
+       adapter->pci_using_dac = 0;
+
+       mask = DMA_BIT_MASK(39);
+       cmask = mask;
+
+       if (pci_set_dma_mask(pdev, mask) == 0 &&
+                       pci_set_consistent_dma_mask(pdev, cmask) == 0) {
+               adapter->pci_using_dac = 1;
+               return 0;
+       }
+
+       return -EIO;
+}
+
+/* Update addressable range if firmware supports it */
+static int
+qlcnic_update_dma_mask(struct qlcnic_adapter *adapter)
+{
+       int change, shift, err;
+       u64 mask, old_mask, old_cmask;
+       struct pci_dev *pdev = adapter->pdev;
+
+       change = 0;
+
+       shift = QLCRD32(adapter, CRB_DMA_SHIFT);
+       if (shift > 32)
+               return 0;
+
+       if (shift > 9)
+               change = 1;
+
+       if (change) {
+               old_mask = pdev->dma_mask;
+               old_cmask = pdev->dev.coherent_dma_mask;
+
+               mask = DMA_BIT_MASK(32+shift);
+
+               err = pci_set_dma_mask(pdev, mask);
+               if (err)
+                       goto err_out;
+
+               err = pci_set_consistent_dma_mask(pdev, mask);
+               if (err)
+                       goto err_out;
+               dev_info(&pdev->dev, "using %d-bit dma mask\n", 32+shift);
+       }
+
+       return 0;
+
+err_out:
+       pci_set_dma_mask(pdev, old_mask);
+       pci_set_consistent_dma_mask(pdev, old_cmask);
+       return err;
+}
+
+static void qlcnic_set_port_mode(struct qlcnic_adapter *adapter)
+{
+       u32 val, data;
+
+       val = adapter->ahw.board_type;
+       if ((val == QLCNIC_BRDTYPE_P3_HMEZ) ||
+               (val == QLCNIC_BRDTYPE_P3_XG_LOM)) {
+               if (port_mode == QLCNIC_PORT_MODE_802_3_AP) {
+                       data = QLCNIC_PORT_MODE_802_3_AP;
+                       QLCWR32(adapter, QLCNIC_PORT_MODE_ADDR, data);
+               } else if (port_mode == QLCNIC_PORT_MODE_XG) {
+                       data = QLCNIC_PORT_MODE_XG;
+                       QLCWR32(adapter, QLCNIC_PORT_MODE_ADDR, data);
+               } else if (port_mode == QLCNIC_PORT_MODE_AUTO_NEG_1G) {
+                       data = QLCNIC_PORT_MODE_AUTO_NEG_1G;
+                       QLCWR32(adapter, QLCNIC_PORT_MODE_ADDR, data);
+               } else if (port_mode == QLCNIC_PORT_MODE_AUTO_NEG_XG) {
+                       data = QLCNIC_PORT_MODE_AUTO_NEG_XG;
+                       QLCWR32(adapter, QLCNIC_PORT_MODE_ADDR, data);
+               } else {
+                       data = QLCNIC_PORT_MODE_AUTO_NEG;
+                       QLCWR32(adapter, QLCNIC_PORT_MODE_ADDR, data);
+               }
+
+               if ((wol_port_mode != QLCNIC_PORT_MODE_802_3_AP) &&
+                       (wol_port_mode != QLCNIC_PORT_MODE_XG) &&
+                       (wol_port_mode != QLCNIC_PORT_MODE_AUTO_NEG_1G) &&
+                       (wol_port_mode != QLCNIC_PORT_MODE_AUTO_NEG_XG)) {
+                       wol_port_mode = QLCNIC_PORT_MODE_AUTO_NEG;
+               }
+               QLCWR32(adapter, QLCNIC_WOL_PORT_MODE, wol_port_mode);
+       }
+}
+
+static void qlcnic_set_msix_bit(struct pci_dev *pdev, int enable)
+{
+       u32 control;
+       int pos;
+
+       pos = pci_find_capability(pdev, PCI_CAP_ID_MSIX);
+       if (pos) {
+               pci_read_config_dword(pdev, pos, &control);
+               if (enable)
+                       control |= PCI_MSIX_FLAGS_ENABLE;
+               else
+                       control = 0;
+               pci_write_config_dword(pdev, pos, control);
+       }
+}
+
+static void qlcnic_init_msix_entries(struct qlcnic_adapter *adapter, int count)
+{
+       int i;
+
+       for (i = 0; i < count; i++)
+               adapter->msix_entries[i].entry = i;
+}
+
+static int
+qlcnic_read_mac_addr(struct qlcnic_adapter *adapter)
+{
+       int i;
+       unsigned char *p;
+       u64 mac_addr;
+       struct net_device *netdev = adapter->netdev;
+       struct pci_dev *pdev = adapter->pdev;
+
+       if (qlcnic_get_mac_addr(adapter, &mac_addr) != 0)
+               return -EIO;
+
+       p = (unsigned char *)&mac_addr;
+       for (i = 0; i < 6; i++)
+               netdev->dev_addr[i] = *(p + 5 - i);
+
+       memcpy(netdev->perm_addr, netdev->dev_addr, netdev->addr_len);
+       memcpy(adapter->mac_addr, netdev->dev_addr, netdev->addr_len);
+
+       /* set station address */
+
+       if (!is_valid_ether_addr(netdev->perm_addr))
+               dev_warn(&pdev->dev, "Bad MAC address %pM.\n",
+                                       netdev->dev_addr);
+
+       return 0;
+}
+
+static int qlcnic_set_mac(struct net_device *netdev, void *p)
+{
+       struct qlcnic_adapter *adapter = netdev_priv(netdev);
+       struct sockaddr *addr = p;
+
+       if (!is_valid_ether_addr(addr->sa_data))
+               return -EINVAL;
+
+       if (netif_running(netdev)) {
+               netif_device_detach(netdev);
+               qlcnic_napi_disable(adapter);
+       }
+
+       memcpy(adapter->mac_addr, addr->sa_data, netdev->addr_len);
+       memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
+       qlcnic_set_multi(adapter->netdev);
+
+       if (netif_running(netdev)) {
+               netif_device_attach(netdev);
+               qlcnic_napi_enable(adapter);
+       }
+       return 0;
+}
+
+static const struct net_device_ops qlcnic_netdev_ops = {
+       .ndo_open          = qlcnic_open,
+       .ndo_stop          = qlcnic_close,
+       .ndo_start_xmit    = qlcnic_xmit_frame,
+       .ndo_get_stats     = qlcnic_get_stats,
+       .ndo_validate_addr = eth_validate_addr,
+       .ndo_set_multicast_list = qlcnic_set_multi,
+       .ndo_set_mac_address    = qlcnic_set_mac,
+       .ndo_change_mtu    = qlcnic_change_mtu,
+       .ndo_tx_timeout    = qlcnic_tx_timeout,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       .ndo_poll_controller = qlcnic_poll_controller,
+#endif
+};
+
+static void
+qlcnic_setup_intr(struct qlcnic_adapter *adapter)
+{
+       const struct qlcnic_legacy_intr_set *legacy_intrp;
+       struct pci_dev *pdev = adapter->pdev;
+       int err, num_msix;
+
+       if (adapter->rss_supported) {
+               num_msix = (num_online_cpus() >= MSIX_ENTRIES_PER_ADAPTER) ?
+                       MSIX_ENTRIES_PER_ADAPTER : 2;
+       } else
+               num_msix = 1;
+
+       adapter->max_sds_rings = 1;
+
+       adapter->flags &= ~(QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED);
+
+       legacy_intrp = &legacy_intr[adapter->ahw.pci_func];
+
+       adapter->int_vec_bit = legacy_intrp->int_vec_bit;
+       adapter->tgt_status_reg = qlcnic_get_ioaddr(adapter,
+                       legacy_intrp->tgt_status_reg);
+       adapter->tgt_mask_reg = qlcnic_get_ioaddr(adapter,
+                       legacy_intrp->tgt_mask_reg);
+       adapter->isr_int_vec = qlcnic_get_ioaddr(adapter, ISR_INT_VECTOR);
+
+       adapter->crb_int_state_reg = qlcnic_get_ioaddr(adapter,
+                       ISR_INT_STATE_REG);
+
+       qlcnic_set_msix_bit(pdev, 0);
+
+       if (adapter->msix_supported) {
+
+               qlcnic_init_msix_entries(adapter, num_msix);
+               err = pci_enable_msix(pdev, adapter->msix_entries, num_msix);
+               if (err == 0) {
+                       adapter->flags |= QLCNIC_MSIX_ENABLED;
+                       qlcnic_set_msix_bit(pdev, 1);
+
+                       if (adapter->rss_supported)
+                               adapter->max_sds_rings = num_msix;
+
+                       dev_info(&pdev->dev, "using msi-x interrupts\n");
+                       return;
+               }
+
+               if (err > 0)
+                       pci_disable_msix(pdev);
+
+               /* fall through for msi */
+       }
+
+       if (use_msi && !pci_enable_msi(pdev)) {
+               adapter->flags |= QLCNIC_MSI_ENABLED;
+               adapter->tgt_status_reg = qlcnic_get_ioaddr(adapter,
+                               msi_tgt_status[adapter->ahw.pci_func]);
+               dev_info(&pdev->dev, "using msi interrupts\n");
+               adapter->msix_entries[0].vector = pdev->irq;
+               return;
+       }
+
+       dev_info(&pdev->dev, "using legacy interrupts\n");
+       adapter->msix_entries[0].vector = pdev->irq;
+}
+
+static void
+qlcnic_teardown_intr(struct qlcnic_adapter *adapter)
+{
+       if (adapter->flags & QLCNIC_MSIX_ENABLED)
+               pci_disable_msix(adapter->pdev);
+       if (adapter->flags & QLCNIC_MSI_ENABLED)
+               pci_disable_msi(adapter->pdev);
+}
+
+static void
+qlcnic_cleanup_pci_map(struct qlcnic_adapter *adapter)
+{
+       if (adapter->ahw.pci_base0 != NULL)
+               iounmap(adapter->ahw.pci_base0);
+}
+
+static int
+qlcnic_setup_pci_map(struct qlcnic_adapter *adapter)
+{
+       void __iomem *mem_ptr0 = NULL;
+       resource_size_t mem_base;
+       unsigned long mem_len, pci_len0 = 0;
+
+       struct pci_dev *pdev = adapter->pdev;
+       int pci_func = adapter->ahw.pci_func;
+
+       /*
+        * Set the CRB window to invalid. If any register in window 0 is
+        * accessed it should set the window to 0 and then reset it to 1.
+        */
+       adapter->ahw.crb_win = -1;
+       adapter->ahw.ocm_win = -1;
+
+       /* remap phys address */
+       mem_base = pci_resource_start(pdev, 0); /* 0 is for BAR 0 */
+       mem_len = pci_resource_len(pdev, 0);
+
+       if (mem_len == QLCNIC_PCI_2MB_SIZE) {
+
+               mem_ptr0 = pci_ioremap_bar(pdev, 0);
+               if (mem_ptr0 == NULL) {
+                       dev_err(&pdev->dev, "failed to map PCI bar 0\n");
+                       return -EIO;
+               }
+               pci_len0 = mem_len;
+       } else {
+               return -EIO;
+       }
+
+       dev_info(&pdev->dev, "%dMB memory map\n", (int)(mem_len>>20));
+
+       adapter->ahw.pci_base0 = mem_ptr0;
+       adapter->ahw.pci_len0 = pci_len0;
+
+       adapter->ahw.ocm_win_crb = qlcnic_get_ioaddr(adapter,
+               QLCNIC_PCIX_PS_REG(PCIX_OCM_WINDOW_REG(pci_func)));
+
+       return 0;
+}
+
+static void get_brd_name(struct qlcnic_adapter *adapter, char *name)
+{
+       struct pci_dev *pdev = adapter->pdev;
+       int i, found = 0;
+
+       for (i = 0; i < NUM_SUPPORTED_BOARDS; ++i) {
+               if (qlcnic_boards[i].vendor == pdev->vendor &&
+                       qlcnic_boards[i].device == pdev->device &&
+                       qlcnic_boards[i].sub_vendor == pdev->subsystem_vendor &&
+                       qlcnic_boards[i].sub_device == pdev->subsystem_device) {
+                               strcpy(name, qlcnic_boards[i].short_name);
+                               found = 1;
+                               break;
+               }
+
+       }
+
+       if (!found)
+               name = "Unknown";
+}
+
+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;
+
+       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);
+       fw_build = QLCRD32(adapter, QLCNIC_FW_VERSION_SUB);
+
+       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);
+       }
+
+       if (adapter->fw_version < QLCNIC_VERSION_CODE(3, 4, 216)) {
+               adapter->driver_mismatch = 1;
+               dev_warn(&pdev->dev, "firmware version %d.%d.%d unsupported\n",
+                               fw_major, fw_minor, fw_build);
+               return;
+       }
+
+       i = QLCRD32(adapter, QLCNIC_SRE_MISC);
+       adapter->ahw.cut_through = (i & 0x8000) ? 1 : 0;
+
+       dev_info(&pdev->dev, "firmware v%d.%d.%d [%s]\n",
+                       fw_major, fw_minor, fw_build,
+                       adapter->ahw.cut_through ? "cut-through" : "legacy");
+
+       if (adapter->fw_version >= QLCNIC_VERSION_CODE(4, 0, 222))
+               adapter->capabilities = QLCRD32(adapter, CRB_FW_CAPABILITIES_1);
+
+       adapter->flags &= ~QLCNIC_LRO_ENABLED;
+
+       if (adapter->ahw.port_type == QLCNIC_XGBE) {
+               adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_10G;
+               adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_10G;
+       } else if (adapter->ahw.port_type == QLCNIC_GBE) {
+               adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_1G;
+               adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_1G;
+       }
+
+       adapter->msix_supported = !!use_msi_x;
+       adapter->rss_supported = !!use_msi_x;
+
+       adapter->num_txd = MAX_CMD_DESCRIPTORS;
+
+       adapter->num_lro_rxd = 0;
+       adapter->max_rds_rings = 2;
+}
+
+static int
+qlcnic_start_firmware(struct qlcnic_adapter *adapter)
+{
+       int val, err, first_boot;
+
+       err = qlcnic_set_dma_mask(adapter);
+       if (err)
+               return err;
+
+       if (!qlcnic_can_start_firmware(adapter))
+               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);
+
+       qlcnic_request_firmware(adapter);
+
+       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);
+               qlcnic_pinit_from_rom(adapter);
+               msleep(1);
+       }
+
+       QLCWR32(adapter, CRB_DMA_SHIFT, 0x55555555);
+       QLCWR32(adapter, QLCNIC_PEG_HALT_STATUS1, 0);
+       QLCWR32(adapter, QLCNIC_PEG_HALT_STATUS2, 0);
+
+       qlcnic_set_port_mode(adapter);
+
+       err = qlcnic_load_firmware(adapter);
+       if (err)
+               goto err_out;
+
+       qlcnic_release_firmware(adapter);
+
+       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_phantom_init(adapter);
+       if (err)
+               goto err_out;
+
+       QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_READY);
+
+       qlcnic_update_dma_mask(adapter);
+
+       qlcnic_check_options(adapter);
+
+       adapter->need_fw_reset = 0;
+
+       /* fall through and release firmware */
+
+err_out:
+       qlcnic_release_firmware(adapter);
+       return err;
+}
+
+static int
+qlcnic_request_irq(struct qlcnic_adapter *adapter)
+{
+       irq_handler_t handler;
+       struct qlcnic_host_sds_ring *sds_ring;
+       int err, ring;
+
+       unsigned long flags = 0;
+       struct net_device *netdev = adapter->netdev;
+       struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
+
+       if (adapter->diag_test == QLCNIC_INTERRUPT_TEST) {
+               handler = qlcnic_tmp_intr;
+               if (!QLCNIC_IS_MSI_FAMILY(adapter))
+                       flags |= IRQF_SHARED;
+
+       } else {
+               if (adapter->flags & QLCNIC_MSIX_ENABLED)
+                       handler = qlcnic_msix_intr;
+               else if (adapter->flags & QLCNIC_MSI_ENABLED)
+                       handler = qlcnic_msi_intr;
+               else {
+                       flags |= IRQF_SHARED;
+                       handler = qlcnic_intr;
+               }
+       }
+       adapter->irq = netdev->irq;
+
+       for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+               sds_ring = &recv_ctx->sds_rings[ring];
+               sprintf(sds_ring->name, "%s[%d]", netdev->name, ring);
+               err = request_irq(sds_ring->irq, handler,
+                                 flags, sds_ring->name, sds_ring);
+               if (err)
+                       return err;
+       }
+
+       return 0;
+}
+
+static void
+qlcnic_free_irq(struct qlcnic_adapter *adapter)
+{
+       int ring;
+       struct qlcnic_host_sds_ring *sds_ring;
+
+       struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
+
+       for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+               sds_ring = &recv_ctx->sds_rings[ring];
+               free_irq(sds_ring->irq, sds_ring);
+       }
+}
+
+static void
+qlcnic_init_coalesce_defaults(struct qlcnic_adapter *adapter)
+{
+       adapter->coal.flags = QLCNIC_INTR_DEFAULT;
+       adapter->coal.normal.data.rx_time_us =
+               QLCNIC_DEFAULT_INTR_COALESCE_RX_TIME_US;
+       adapter->coal.normal.data.rx_packets =
+               QLCNIC_DEFAULT_INTR_COALESCE_RX_PACKETS;
+       adapter->coal.normal.data.tx_time_us =
+               QLCNIC_DEFAULT_INTR_COALESCE_TX_TIME_US;
+       adapter->coal.normal.data.tx_packets =
+               QLCNIC_DEFAULT_INTR_COALESCE_TX_PACKETS;
+}
+
+static int
+__qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev)
+{
+       if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
+               return -EIO;
+
+       qlcnic_set_multi(netdev);
+       qlcnic_fw_cmd_set_mtu(adapter, netdev->mtu);
+
+       adapter->ahw.linkup = 0;
+
+       if (adapter->max_sds_rings > 1)
+               qlcnic_config_rss(adapter, 1);
+
+       qlcnic_config_intr_coalesce(adapter);
+
+       if (adapter->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO)
+               qlcnic_config_hw_lro(adapter, QLCNIC_LRO_ENABLED);
+
+       qlcnic_napi_enable(adapter);
+
+       qlcnic_linkevent_request(adapter, 1);
+
+       set_bit(__QLCNIC_DEV_UP, &adapter->state);
+       return 0;
+}
+
+/* Usage: During resume and firmware recovery module.*/
+
+static int
+qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev)
+{
+       int err = 0;
+
+       rtnl_lock();
+       if (netif_running(netdev))
+               err = __qlcnic_up(adapter, netdev);
+       rtnl_unlock();
+
+       return err;
+}
+
+static void
+__qlcnic_down(struct qlcnic_adapter *adapter, struct net_device *netdev)
+{
+       if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
+               return;
+
+       if (!test_and_clear_bit(__QLCNIC_DEV_UP, &adapter->state))
+               return;
+
+       smp_mb();
+       spin_lock(&adapter->tx_clean_lock);
+       netif_carrier_off(netdev);
+       netif_tx_disable(netdev);
+
+       qlcnic_free_mac_list(adapter);
+
+       qlcnic_nic_set_promisc(adapter, QLCNIC_NIU_NON_PROMISC_MODE);
+
+       qlcnic_napi_disable(adapter);
+
+       qlcnic_release_tx_buffers(adapter);
+       spin_unlock(&adapter->tx_clean_lock);
+}
+
+/* Usage: During suspend and firmware recovery module */
+
+static void
+qlcnic_down(struct qlcnic_adapter *adapter, struct net_device *netdev)
+{
+       rtnl_lock();
+       if (netif_running(netdev))
+               __qlcnic_down(adapter, netdev);
+       rtnl_unlock();
+
+}
+
+static int
+qlcnic_attach(struct qlcnic_adapter *adapter)
+{
+       struct net_device *netdev = adapter->netdev;
+       struct pci_dev *pdev = adapter->pdev;
+       int err, ring;
+       struct qlcnic_host_rds_ring *rds_ring;
+
+       if (adapter->is_up == QLCNIC_ADAPTER_UP_MAGIC)
+               return 0;
+
+       err = qlcnic_init_firmware(adapter);
+       if (err)
+               return err;
+
+       err = qlcnic_napi_add(adapter, netdev);
+       if (err)
+               return err;
+
+       err = qlcnic_alloc_sw_resources(adapter);
+       if (err) {
+               dev_err(&pdev->dev, "Error in setting sw resources\n");
+               return err;
+       }
+
+       err = qlcnic_alloc_hw_resources(adapter);
+       if (err) {
+               dev_err(&pdev->dev, "Error in setting hw resources\n");
+               goto err_out_free_sw;
+       }
+
+
+       for (ring = 0; ring < adapter->max_rds_rings; ring++) {
+               rds_ring = &adapter->recv_ctx.rds_rings[ring];
+               qlcnic_post_rx_buffers(adapter, ring, rds_ring);
+       }
+
+       err = qlcnic_request_irq(adapter);
+       if (err) {
+               dev_err(&pdev->dev, "failed to setup interrupt\n");
+               goto err_out_free_rxbuf;
+       }
+
+       qlcnic_init_coalesce_defaults(adapter);
+
+       qlcnic_create_sysfs_entries(adapter);
+
+       adapter->is_up = QLCNIC_ADAPTER_UP_MAGIC;
+       return 0;
+
+err_out_free_rxbuf:
+       qlcnic_release_rx_buffers(adapter);
+       qlcnic_free_hw_resources(adapter);
+err_out_free_sw:
+       qlcnic_free_sw_resources(adapter);
+       return err;
+}
+
+static void
+qlcnic_detach(struct qlcnic_adapter *adapter)
+{
+       if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
+               return;
+
+       qlcnic_remove_sysfs_entries(adapter);
+
+       qlcnic_free_hw_resources(adapter);
+       qlcnic_release_rx_buffers(adapter);
+       qlcnic_free_irq(adapter);
+       qlcnic_napi_del(adapter);
+       qlcnic_free_sw_resources(adapter);
+
+       adapter->is_up = 0;
+}
+
+void qlcnic_diag_free_res(struct net_device *netdev, int max_sds_rings)
+{
+       struct qlcnic_adapter *adapter = netdev_priv(netdev);
+       struct qlcnic_host_sds_ring *sds_ring;
+       int ring;
+
+       if (adapter->diag_test == QLCNIC_INTERRUPT_TEST) {
+               for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+                       sds_ring = &adapter->recv_ctx.sds_rings[ring];
+                       qlcnic_disable_int(sds_ring);
+               }
+       }
+
+       qlcnic_detach(adapter);
+
+       adapter->diag_test = 0;
+       adapter->max_sds_rings = max_sds_rings;
+
+       if (qlcnic_attach(adapter))
+               return;
+
+       if (netif_running(netdev))
+               __qlcnic_up(adapter, netdev);
+
+       netif_device_attach(netdev);
+}
+
+int qlcnic_diag_alloc_res(struct net_device *netdev, int test)
+{
+       struct qlcnic_adapter *adapter = netdev_priv(netdev);
+       struct qlcnic_host_sds_ring *sds_ring;
+       int ring;
+       int ret;
+
+       netif_device_detach(netdev);
+
+       if (netif_running(netdev))
+               __qlcnic_down(adapter, netdev);
+
+       qlcnic_detach(adapter);
+
+       adapter->max_sds_rings = 1;
+       adapter->diag_test = test;
+
+       ret = qlcnic_attach(adapter);
+       if (ret)
+               return ret;
+
+       if (adapter->diag_test == QLCNIC_INTERRUPT_TEST) {
+               for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+                       sds_ring = &adapter->recv_ctx.sds_rings[ring];
+                       qlcnic_enable_int(sds_ring);
+               }
+       }
+
+       return 0;
+}
+
+int
+qlcnic_reset_context(struct qlcnic_adapter *adapter)
+{
+       int err = 0;
+       struct net_device *netdev = adapter->netdev;
+
+       if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
+               return -EBUSY;
+
+       if (adapter->is_up == QLCNIC_ADAPTER_UP_MAGIC) {
+
+               netif_device_detach(netdev);
+
+               if (netif_running(netdev))
+                       __qlcnic_down(adapter, netdev);
+
+               qlcnic_detach(adapter);
+
+               if (netif_running(netdev)) {
+                       err = qlcnic_attach(adapter);
+                       if (!err)
+                               err = __qlcnic_up(adapter, netdev);
+
+                       if (err)
+                               goto done;
+               }
+
+               netif_device_attach(netdev);
+       }
+
+done:
+       clear_bit(__QLCNIC_RESETTING, &adapter->state);
+       return err;
+}
+
+static int
+qlcnic_setup_netdev(struct qlcnic_adapter *adapter,
+               struct net_device *netdev)
+{
+       int err;
+       struct pci_dev *pdev = adapter->pdev;
+
+       adapter->rx_csum = 1;
+       adapter->mc_enabled = 0;
+       adapter->max_mc_count = 38;
+
+       netdev->netdev_ops         = &qlcnic_netdev_ops;
+       netdev->watchdog_timeo     = 2*HZ;
+
+       qlcnic_change_mtu(netdev, netdev->mtu);
+
+       SET_ETHTOOL_OPS(netdev, &qlcnic_ethtool_ops);
+
+       netdev->features |= (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO);
+       netdev->features |= (NETIF_F_GRO);
+       netdev->vlan_features |= (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO);
+
+       netdev->features |= (NETIF_F_IPV6_CSUM | NETIF_F_TSO6);
+       netdev->vlan_features |= (NETIF_F_IPV6_CSUM | NETIF_F_TSO6);
+
+       if (adapter->pci_using_dac) {
+               netdev->features |= NETIF_F_HIGHDMA;
+               netdev->vlan_features |= NETIF_F_HIGHDMA;
+       }
+
+       if (adapter->capabilities & QLCNIC_FW_CAPABILITY_FVLANTX)
+               netdev->features |= (NETIF_F_HW_VLAN_TX);
+
+       if (adapter->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO)
+               netdev->features |= NETIF_F_LRO;
+
+       netdev->irq = adapter->msix_entries[0].vector;
+
+       INIT_WORK(&adapter->tx_timeout_task, qlcnic_tx_timeout_task);
+
+       if (qlcnic_read_mac_addr(adapter))
+               dev_warn(&pdev->dev, "failed to read mac addr\n");
+
+       netif_carrier_off(netdev);
+       netif_stop_queue(netdev);
+
+       err = register_netdev(netdev);
+       if (err) {
+               dev_err(&pdev->dev, "failed to register net device\n");
+               return err;
+       }
+
+       return 0;
+}
+
+static int __devinit
+qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+       struct net_device *netdev = NULL;
+       struct qlcnic_adapter *adapter = NULL;
+       int err;
+       int pci_func_id = PCI_FUNC(pdev->devfn);
+       uint8_t revision_id;
+
+       err = pci_enable_device(pdev);
+       if (err)
+               return err;
+
+       if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
+               err = -ENODEV;
+               goto err_out_disable_pdev;
+       }
+
+       err = pci_request_regions(pdev, qlcnic_driver_name);
+       if (err)
+               goto err_out_disable_pdev;
+
+       pci_set_master(pdev);
+
+       netdev = alloc_etherdev(sizeof(struct qlcnic_adapter));
+       if (!netdev) {
+               dev_err(&pdev->dev, "failed to allocate net_device\n");
+               err = -ENOMEM;
+               goto err_out_free_res;
+       }
+
+       SET_NETDEV_DEV(netdev, &pdev->dev);
+
+       adapter = netdev_priv(netdev);
+       adapter->netdev  = netdev;
+       adapter->pdev    = pdev;
+       adapter->ahw.pci_func  = pci_func_id;
+
+       revision_id = pdev->revision;
+       adapter->ahw.revision_id = revision_id;
+
+       rwlock_init(&adapter->ahw.crb_lock);
+       mutex_init(&adapter->ahw.mem_lock);
+
+       spin_lock_init(&adapter->tx_clean_lock);
+       INIT_LIST_HEAD(&adapter->mac_list);
+
+       err = qlcnic_setup_pci_map(adapter);
+       if (err)
+               goto err_out_free_netdev;
+
+       /* This will be reset for mezz cards  */
+       adapter->portnum = pci_func_id;
+
+       err = qlcnic_get_board_info(adapter);
+       if (err) {
+               dev_err(&pdev->dev, "Error getting board config info.\n");
+               goto err_out_iounmap;
+       }
+
+
+       err = qlcnic_start_firmware(adapter);
+       if (err)
+               goto err_out_decr_ref;
+
+       /*
+        * See if the firmware gave us a virtual-physical port mapping.
+        */
+       adapter->physical_port = adapter->portnum;
+
+       qlcnic_clear_stats(adapter);
+
+       qlcnic_setup_intr(adapter);
+
+       err = qlcnic_setup_netdev(adapter, netdev);
+       if (err)
+               goto err_out_disable_msi;
+
+       pci_set_drvdata(pdev, adapter);
+
+       qlcnic_schedule_work(adapter, qlcnic_fw_poll_work, FW_POLL_DELAY);
+
+       switch (adapter->ahw.port_type) {
+       case QLCNIC_GBE:
+               dev_info(&adapter->pdev->dev, "%s: GbE port initialized\n",
+                               adapter->netdev->name);
+               break;
+       case QLCNIC_XGBE:
+               dev_info(&adapter->pdev->dev, "%s: XGbE port initialized\n",
+                               adapter->netdev->name);
+               break;
+       }
+
+       qlcnic_create_diag_entries(adapter);
+
+       return 0;
+
+err_out_disable_msi:
+       qlcnic_teardown_intr(adapter);
+
+err_out_decr_ref:
+       qlcnic_clr_all_drv_state(adapter);
+
+err_out_iounmap:
+       qlcnic_cleanup_pci_map(adapter);
+
+err_out_free_netdev:
+       free_netdev(netdev);
+
+err_out_free_res:
+       pci_release_regions(pdev);
+
+err_out_disable_pdev:
+       pci_set_drvdata(pdev, NULL);
+       pci_disable_device(pdev);
+       return err;
+}
+
+static void __devexit qlcnic_remove(struct pci_dev *pdev)
+{
+       struct qlcnic_adapter *adapter;
+       struct net_device *netdev;
+
+       adapter = pci_get_drvdata(pdev);
+       if (adapter == NULL)
+               return;
+
+       netdev = adapter->netdev;
+
+       qlcnic_cancel_fw_work(adapter);
+
+       unregister_netdev(netdev);
+
+       cancel_work_sync(&adapter->tx_timeout_task);
+
+       qlcnic_detach(adapter);
+
+       qlcnic_clr_all_drv_state(adapter);
+
+       clear_bit(__QLCNIC_RESETTING, &adapter->state);
+
+       qlcnic_teardown_intr(adapter);
+
+       qlcnic_remove_diag_entries(adapter);
+
+       qlcnic_cleanup_pci_map(adapter);
+
+       qlcnic_release_firmware(adapter);
+
+       pci_release_regions(pdev);
+       pci_disable_device(pdev);
+       pci_set_drvdata(pdev, NULL);
+
+       free_netdev(netdev);
+}
+static int __qlcnic_shutdown(struct pci_dev *pdev)
+{
+       struct qlcnic_adapter *adapter = pci_get_drvdata(pdev);
+       struct net_device *netdev = adapter->netdev;
+       int retval;
+
+       netif_device_detach(netdev);
+
+       qlcnic_cancel_fw_work(adapter);
+
+       if (netif_running(netdev))
+               qlcnic_down(adapter, netdev);
+
+       cancel_work_sync(&adapter->tx_timeout_task);
+
+       qlcnic_detach(adapter);
+
+       qlcnic_clr_all_drv_state(adapter);
+
+       clear_bit(__QLCNIC_RESETTING, &adapter->state);
+
+       retval = pci_save_state(pdev);
+       if (retval)
+               return retval;
+
+       if (qlcnic_wol_supported(adapter)) {
+               pci_enable_wake(pdev, PCI_D3cold, 1);
+               pci_enable_wake(pdev, PCI_D3hot, 1);
+       }
+
+       return 0;
+}
+
+static void qlcnic_shutdown(struct pci_dev *pdev)
+{
+       if (__qlcnic_shutdown(pdev))
+               return;
+
+       pci_disable_device(pdev);
+}
+
+#ifdef CONFIG_PM
+static int
+qlcnic_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+       int retval;
+
+       retval = __qlcnic_shutdown(pdev);
+       if (retval)
+               return retval;
+
+       pci_set_power_state(pdev, pci_choose_state(pdev, state));
+       return 0;
+}
+
+static int
+qlcnic_resume(struct pci_dev *pdev)
+{
+       struct qlcnic_adapter *adapter = pci_get_drvdata(pdev);
+       struct net_device *netdev = adapter->netdev;
+       int err;
+
+       err = pci_enable_device(pdev);
+       if (err)
+               return err;
+
+       pci_set_power_state(pdev, PCI_D0);
+       pci_set_master(pdev);
+       pci_restore_state(pdev);
+
+       adapter->ahw.crb_win = -1;
+       adapter->ahw.ocm_win = -1;
+
+       err = qlcnic_start_firmware(adapter);
+       if (err) {
+               dev_err(&pdev->dev, "failed to start firmware\n");
+               return err;
+       }
+
+       if (netif_running(netdev)) {
+               err = qlcnic_attach(adapter);
+               if (err)
+                       goto err_out;
+
+               err = qlcnic_up(adapter, netdev);
+               if (err)
+                       goto err_out_detach;
+
+
+               qlcnic_config_indev_addr(netdev, NETDEV_UP);
+       }
+
+       netif_device_attach(netdev);
+       qlcnic_schedule_work(adapter, qlcnic_fw_poll_work, FW_POLL_DELAY);
+       return 0;
+
+err_out_detach:
+       qlcnic_detach(adapter);
+err_out:
+       qlcnic_clr_all_drv_state(adapter);
+       return err;
+}
+#endif
+
+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;
+
+       err = __qlcnic_up(adapter, netdev);
+       if (err)
+               goto err_out;
+
+       netif_start_queue(netdev);
+
+       return 0;
+
+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_tso_check(struct net_device *netdev,
+               struct qlcnic_host_tx_ring *tx_ring,
+               struct cmd_desc_type0 *first_desc,
+               struct sk_buff *skb)
+{
+       u8 opcode = TX_ETHER_PKT;
+       __be16 protocol = skb->protocol;
+       u16 flags = 0, vid = 0;
+       u32 producer;
+       int copied, offset, copy_len, hdr_len = 0, tso = 0, vlan_oob = 0;
+       struct cmd_desc_type0 *hwdesc;
+       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;
+
+       } 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;
+       }
+
+       if ((netdev->features & (NETIF_F_TSO | NETIF_F_TSO6)) &&
+                       skb_shinfo(skb)->gso_size > 0) {
+
+               hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
+
+               first_desc->mss = cpu_to_le16(skb_shinfo(skb)->gso_size);
+               first_desc->total_hdr_length = hdr_len;
+               if (vlan_oob) {
+                       first_desc->total_hdr_length += VLAN_HLEN;
+                       first_desc->tcp_hdr_offset = VLAN_HLEN;
+                       first_desc->ip_hdr_offset = VLAN_HLEN;
+                       /* Only in case of TSO on vlan device */
+                       flags |= FLAGS_VLAN_TAGGED;
+               }
+
+               opcode = (protocol == cpu_to_be16(ETH_P_IPV6)) ?
+                               TX_TCP_LSO6 : TX_TCP_LSO;
+               tso = 1;
+
+       } else if (skb->ip_summed == CHECKSUM_PARTIAL) {
+               u8 l4proto;
+
+               if (protocol == cpu_to_be16(ETH_P_IP)) {
+                       l4proto = ip_hdr(skb)->protocol;
+
+                       if (l4proto == IPPROTO_TCP)
+                               opcode = TX_TCP_PKT;
+                       else if (l4proto == IPPROTO_UDP)
+                               opcode = TX_UDP_PKT;
+               } else if (protocol == cpu_to_be16(ETH_P_IPV6)) {
+                       l4proto = ipv6_hdr(skb)->nexthdr;
+
+                       if (l4proto == IPPROTO_TCP)
+                               opcode = TX_TCPV6_PKT;
+                       else if (l4proto == IPPROTO_UDP)
+                               opcode = TX_UDPV6_PKT;
+               }
+       }
+
+       first_desc->tcp_hdr_offset += skb_transport_offset(skb);
+       first_desc->ip_hdr_offset += skb_network_offset(skb);
+       qlcnic_set_tx_flags_opcode(first_desc, flags, opcode);
+
+       if (!tso)
+               return;
+
+       /* For LSO, we need to copy the MAC/IP/TCP headers into
+        * the descriptor ring
+        */
+       producer = tx_ring->producer;
+       copied = 0;
+       offset = 2;
+
+       if (vlan_oob) {
+               /* Create a TSO vlan header template for firmware */
+
+               hwdesc = &tx_ring->desc_head[producer];
+               tx_ring->cmd_buf_arr[producer].skb = NULL;
+
+               copy_len = min((int)sizeof(struct cmd_desc_type0) - offset,
+                               hdr_len + VLAN_HLEN);
+
+               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);
+               skb_copy_from_linear_data_offset(skb, 12,
+                               (char *)vh + 16, copy_len - 16);
+
+               copied = copy_len - VLAN_HLEN;
+               offset = 0;
+
+               producer = get_next_index(producer, tx_ring->num_desc);
+       }
+
+       while (copied < hdr_len) {
+
+               copy_len = min((int)sizeof(struct cmd_desc_type0) - offset,
+                               (hdr_len - copied));
+
+               hwdesc = &tx_ring->desc_head[producer];
+               tx_ring->cmd_buf_arr[producer].skb = NULL;
+
+               skb_copy_from_linear_data_offset(skb, copied,
+                                (char *)hwdesc + offset, copy_len);
+
+               copied += copy_len;
+               offset = 0;
+
+               producer = get_next_index(producer, tx_ring->num_desc);
+       }
+
+       tx_ring->producer = producer;
+       barrier();
+}
+
+static int
+qlcnic_map_tx_skb(struct pci_dev *pdev,
+               struct sk_buff *skb, struct qlcnic_cmd_buffer *pbuf)
+{
+       struct qlcnic_skb_frag *nf;
+       struct skb_frag_struct *frag;
+       int i, nr_frags;
+       dma_addr_t map;
+
+       nr_frags = skb_shinfo(skb)->nr_frags;
+       nf = &pbuf->frag_array[0];
+
+       map = pci_map_single(pdev, skb->data,
+                       skb_headlen(skb), PCI_DMA_TODEVICE);
+       if (pci_dma_mapping_error(pdev, map))
+               goto out_err;
+
+       nf->dma = map;
+       nf->length = skb_headlen(skb);
+
+       for (i = 0; i < nr_frags; i++) {
+               frag = &skb_shinfo(skb)->frags[i];
+               nf = &pbuf->frag_array[i+1];
+
+               map = pci_map_page(pdev, frag->page, frag->page_offset,
+                               frag->size, PCI_DMA_TODEVICE);
+               if (pci_dma_mapping_error(pdev, map))
+                       goto unwind;
+
+               nf->dma = map;
+               nf->length = frag->size;
+       }
+
+       return 0;
+
+unwind:
+       while (--i >= 0) {
+               nf = &pbuf->frag_array[i+1];
+               pci_unmap_page(pdev, nf->dma, nf->length, PCI_DMA_TODEVICE);
+       }
+
+       nf = &pbuf->frag_array[0];
+       pci_unmap_single(pdev, nf->dma, skb_headlen(skb), PCI_DMA_TODEVICE);
+
+out_err:
+       return -ENOMEM;
+}
+
+static inline void
+qlcnic_clear_cmddesc(u64 *desc)
+{
+       desc[0] = 0ULL;
+       desc[2] = 0ULL;
+}
+
+netdev_tx_t
+qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
+{
+       struct qlcnic_adapter *adapter = netdev_priv(netdev);
+       struct qlcnic_host_tx_ring *tx_ring = adapter->tx_ring;
+       struct qlcnic_cmd_buffer *pbuf;
+       struct qlcnic_skb_frag *buffrag;
+       struct cmd_desc_type0 *hwdesc, *first_desc;
+       struct pci_dev *pdev;
+       int i, k;
+
+       u32 producer;
+       int frag_count, no_of_desc;
+       u32 num_txd = tx_ring->num_desc;
+
+       frag_count = skb_shinfo(skb)->nr_frags + 1;
+
+       /* 4 fragments per cmd des */
+       no_of_desc = (frag_count + 3) >> 2;
+
+       if (unlikely(no_of_desc + 2 > qlcnic_tx_avail(tx_ring))) {
+               netif_stop_queue(netdev);
+               return NETDEV_TX_BUSY;
+       }
+
+       producer = tx_ring->producer;
+       pbuf = &tx_ring->cmd_buf_arr[producer];
+
+       pdev = adapter->pdev;
+
+       if (qlcnic_map_tx_skb(pdev, skb, pbuf))
+               goto drop_packet;
+
+       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);
+
+       for (i = 0; i < frag_count; i++) {
+
+               k = i % 4;
+
+               if ((k == 0) && (i > 0)) {
+                       /* move to next desc.*/
+                       producer = get_next_index(producer, num_txd);
+                       hwdesc = &tx_ring->desc_head[producer];
+                       qlcnic_clear_cmddesc((u64 *)hwdesc);
+                       tx_ring->cmd_buf_arr[producer].skb = NULL;
+               }
+
+               buffrag = &pbuf->frag_array[i];
+
+               hwdesc->buffer_length[k] = cpu_to_le16(buffrag->length);
+               switch (k) {
+               case 0:
+                       hwdesc->addr_buffer1 = cpu_to_le64(buffrag->dma);
+                       break;
+               case 1:
+                       hwdesc->addr_buffer2 = cpu_to_le64(buffrag->dma);
+                       break;
+               case 2:
+                       hwdesc->addr_buffer3 = cpu_to_le64(buffrag->dma);
+                       break;
+               case 3:
+                       hwdesc->addr_buffer4 = cpu_to_le64(buffrag->dma);
+                       break;
+               }
+       }
+
+       tx_ring->producer = get_next_index(producer, num_txd);
+
+       qlcnic_tso_check(netdev, tx_ring, first_desc, skb);
+
+       qlcnic_update_cmd_producer(adapter, tx_ring);
+
+       adapter->stats.txbytes += skb->len;
+       adapter->stats.xmitcalled++;
+
+       return NETDEV_TX_OK;
+
+drop_packet:
+       adapter->stats.txdropped++;
+       dev_kfree_skb_any(skb);
+       return NETDEV_TX_OK;
+}
+
+static int qlcnic_check_temp(struct qlcnic_adapter *adapter)
+{
+       struct net_device *netdev = adapter->netdev;
+       u32 temp, temp_state, temp_val;
+       int rv = 0;
+
+       temp = QLCRD32(adapter, CRB_TEMP_STATE);
+
+       temp_state = qlcnic_get_temp_state(temp);
+       temp_val = qlcnic_get_temp_val(temp);
+
+       if (temp_state == QLCNIC_TEMP_PANIC) {
+               dev_err(&netdev->dev,
+                      "Device temperature %d degrees C exceeds"
+                      " maximum allowed. Hardware has been shut down.\n",
+                      temp_val);
+               rv = 1;
+       } else if (temp_state == QLCNIC_TEMP_WARN) {
+               if (adapter->temp == QLCNIC_TEMP_NORMAL) {
+                       dev_err(&netdev->dev,
+                              "Device temperature %d degrees C "
+                              "exceeds operating range."
+                              " Immediate action needed.\n",
+                              temp_val);
+               }
+       } else {
+               if (adapter->temp == QLCNIC_TEMP_WARN) {
+                       dev_info(&netdev->dev,
+                              "Device temperature is now %d degrees C"
+                              " in normal range.\n", temp_val);
+               }
+       }
+       adapter->temp = temp_state;
+       return rv;
+}
+
+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");
+               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");
+               adapter->ahw.linkup = 1;
+               if (netif_running(netdev)) {
+                       netif_carrier_on(netdev);
+                       netif_wake_queue(netdev);
+               }
+       }
+}
+
+static void qlcnic_tx_timeout(struct net_device *netdev)
+{
+       struct qlcnic_adapter *adapter = netdev_priv(netdev);
+
+       if (test_bit(__QLCNIC_RESETTING, &adapter->state))
+               return;
+
+       dev_err(&netdev->dev, "transmit timeout, resetting.\n");
+       schedule_work(&adapter->tx_timeout_task);
+}
+
+static void qlcnic_tx_timeout_task(struct work_struct *work)
+{
+       struct qlcnic_adapter *adapter =
+               container_of(work, struct qlcnic_adapter, tx_timeout_task);
+
+       if (!netif_running(adapter->netdev))
+               return;
+
+       if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
+               return;
+
+       if (++adapter->tx_timeo_cnt >= QLCNIC_MAX_TX_TIMEOUTS)
+               goto request_reset;
+
+       clear_bit(__QLCNIC_RESETTING, &adapter->state);
+       if (!qlcnic_reset_context(adapter)) {
+               adapter->netdev->trans_start = jiffies;
+               return;
+
+               /* context reset failed, fall through for fw reset */
+       }
+
+request_reset:
+       adapter->need_fw_reset = 1;
+       clear_bit(__QLCNIC_RESETTING, &adapter->state);
+}
+
+static struct net_device_stats *qlcnic_get_stats(struct net_device *netdev)
+{
+       struct qlcnic_adapter *adapter = netdev_priv(netdev);
+       struct net_device_stats *stats = &netdev->stats;
+
+       memset(stats, 0, sizeof(*stats));
+
+       stats->rx_packets = adapter->stats.rx_pkts + adapter->stats.lro_pkts;
+       stats->tx_packets = adapter->stats.xmitfinished;
+       stats->rx_bytes = adapter->stats.rxbytes;
+       stats->tx_bytes = adapter->stats.txbytes;
+       stats->rx_dropped = adapter->stats.rxdropped;
+       stats->tx_dropped = adapter->stats.txdropped;
+
+       return stats;
+}
+
+static irqreturn_t qlcnic_clear_legacy_intr(struct qlcnic_adapter *adapter)
+{
+       u32 status;
+
+       status = readl(adapter->isr_int_vec);
+
+       if (!(status & adapter->int_vec_bit))
+               return IRQ_NONE;
+
+       /* check interrupt state machine, to be sure */
+       status = readl(adapter->crb_int_state_reg);
+       if (!ISR_LEGACY_INT_TRIGGERED(status))
+               return IRQ_NONE;
+
+       writel(0xffffffff, adapter->tgt_status_reg);
+       /* read twice to ensure write is flushed */
+       readl(adapter->isr_int_vec);
+       readl(adapter->isr_int_vec);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t qlcnic_tmp_intr(int irq, void *data)
+{
+       struct qlcnic_host_sds_ring *sds_ring = data;
+       struct qlcnic_adapter *adapter = sds_ring->adapter;
+
+       if (adapter->flags & QLCNIC_MSIX_ENABLED)
+               goto done;
+       else if (adapter->flags & QLCNIC_MSI_ENABLED) {
+               writel(0xffffffff, adapter->tgt_status_reg);
+               goto done;
+       }
+
+       if (qlcnic_clear_legacy_intr(adapter) == IRQ_NONE)
+               return IRQ_NONE;
+
+done:
+       adapter->diag_cnt++;
+       qlcnic_enable_int(sds_ring);
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t qlcnic_intr(int irq, void *data)
+{
+       struct qlcnic_host_sds_ring *sds_ring = data;
+       struct qlcnic_adapter *adapter = sds_ring->adapter;
+
+       if (qlcnic_clear_legacy_intr(adapter) == IRQ_NONE)
+               return IRQ_NONE;
+
+       napi_schedule(&sds_ring->napi);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t qlcnic_msi_intr(int irq, void *data)
+{
+       struct qlcnic_host_sds_ring *sds_ring = data;
+       struct qlcnic_adapter *adapter = sds_ring->adapter;
+
+       /* clear interrupt */
+       writel(0xffffffff, adapter->tgt_status_reg);
+
+       napi_schedule(&sds_ring->napi);
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t qlcnic_msix_intr(int irq, void *data)
+{
+       struct qlcnic_host_sds_ring *sds_ring = data;
+
+       napi_schedule(&sds_ring->napi);
+       return IRQ_HANDLED;
+}
+
+static int qlcnic_process_cmd_ring(struct qlcnic_adapter *adapter)
+{
+       u32 sw_consumer, hw_consumer;
+       int count = 0, i;
+       struct qlcnic_cmd_buffer *buffer;
+       struct pci_dev *pdev = adapter->pdev;
+       struct net_device *netdev = adapter->netdev;
+       struct qlcnic_skb_frag *frag;
+       int done;
+       struct qlcnic_host_tx_ring *tx_ring = adapter->tx_ring;
+
+       if (!spin_trylock(&adapter->tx_clean_lock))
+               return 1;
+
+       sw_consumer = tx_ring->sw_consumer;
+       hw_consumer = le32_to_cpu(*(tx_ring->hw_consumer));
+
+       while (sw_consumer != hw_consumer) {
+               buffer = &tx_ring->cmd_buf_arr[sw_consumer];
+               if (buffer->skb) {
+                       frag = &buffer->frag_array[0];
+                       pci_unmap_single(pdev, frag->dma, frag->length,
+                                        PCI_DMA_TODEVICE);
+                       frag->dma = 0ULL;
+                       for (i = 1; i < buffer->frag_count; i++) {
+                               frag++;
+                               pci_unmap_page(pdev, frag->dma, frag->length,
+                                              PCI_DMA_TODEVICE);
+                               frag->dma = 0ULL;
+                       }
+
+                       adapter->stats.xmitfinished++;
+                       dev_kfree_skb_any(buffer->skb);
+                       buffer->skb = NULL;
+               }
+
+               sw_consumer = get_next_index(sw_consumer, tx_ring->num_desc);
+               if (++count >= MAX_STATUS_HANDLE)
+                       break;
+       }
+
+       if (count && netif_running(netdev)) {
+               tx_ring->sw_consumer = sw_consumer;
+
+               smp_mb();
+
+               if (netif_queue_stopped(netdev) && netif_carrier_ok(netdev)) {
+                       __netif_tx_lock(tx_ring->txq, smp_processor_id());
+                       if (qlcnic_tx_avail(tx_ring) > TX_STOP_THRESH) {
+                               netif_wake_queue(netdev);
+                               adapter->tx_timeo_cnt = 0;
+                       }
+                       __netif_tx_unlock(tx_ring->txq);
+               }
+       }
+       /*
+        * If everything is freed up to consumer then check if the ring is full
+        * If the ring is full then check if more needs to be freed and
+        * schedule the call back again.
+        *
+        * This happens when there are 2 CPUs. One could be freeing and the
+        * other filling it. If the ring is full when we get out of here and
+        * the card has already interrupted the host then the host can miss the
+        * interrupt.
+        *
+        * There is still a possible race condition and the host could miss an
+        * interrupt. The card has to take care of this.
+        */
+       hw_consumer = le32_to_cpu(*(tx_ring->hw_consumer));
+       done = (sw_consumer == hw_consumer);
+       spin_unlock(&adapter->tx_clean_lock);
+
+       return done;
+}
+
+static int qlcnic_poll(struct napi_struct *napi, int budget)
+{
+       struct qlcnic_host_sds_ring *sds_ring =
+               container_of(napi, struct qlcnic_host_sds_ring, napi);
+
+       struct qlcnic_adapter *adapter = sds_ring->adapter;
+
+       int tx_complete;
+       int work_done;
+
+       tx_complete = qlcnic_process_cmd_ring(adapter);
+
+       work_done = qlcnic_process_rcv_ring(sds_ring, budget);
+
+       if ((work_done < budget) && tx_complete) {
+               napi_complete(&sds_ring->napi);
+               if (test_bit(__QLCNIC_DEV_UP, &adapter->state))
+                       qlcnic_enable_int(sds_ring);
+       }
+
+       return work_done;
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void qlcnic_poll_controller(struct net_device *netdev)
+{
+       struct qlcnic_adapter *adapter = netdev_priv(netdev);
+       disable_irq(adapter->irq);
+       qlcnic_intr(adapter->irq, adapter);
+       enable_irq(adapter->irq);
+}
+#endif
+
+static void
+qlcnic_set_drv_state(struct qlcnic_adapter *adapter, int state)
+{
+       u32  val;
+
+       WARN_ON(state != QLCNIC_DEV_NEED_RESET &&
+                       state != QLCNIC_DEV_NEED_QUISCENT);
+
+       if (qlcnic_api_lock(adapter))
+               return ;
+
+       val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
+
+       if (state == QLCNIC_DEV_NEED_RESET)
+               val |= ((u32)0x1 << (adapter->portnum * 4));
+       else if (state == QLCNIC_DEV_NEED_QUISCENT)
+               val |= ((u32)0x1 << ((adapter->portnum * 4) + 1));
+
+       QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
+
+       qlcnic_api_unlock(adapter);
+}
+
+static int
+qlcnic_clr_drv_state(struct qlcnic_adapter *adapter)
+{
+       u32  val;
+
+       if (qlcnic_api_lock(adapter))
+               return -EBUSY;
+
+       val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
+       val &= ~((u32)0x3 << (adapter->portnum * 4));
+       QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
+
+       qlcnic_api_unlock(adapter);
+
+       return 0;
+}
+
+static void
+qlcnic_clr_all_drv_state(struct qlcnic_adapter *adapter)
+{
+       u32  val;
+
+       if (qlcnic_api_lock(adapter))
+               goto err;
+
+       val = QLCRD32(adapter, QLCNIC_CRB_DEV_REF_COUNT);
+       val &= ~((u32)0x1 << (adapter->portnum * 4));
+       QLCWR32(adapter, QLCNIC_CRB_DEV_REF_COUNT, val);
+
+       if (!(val & 0x11111111))
+               QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_COLD);
+
+       val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
+       val &= ~((u32)0x3 << (adapter->portnum * 4));
+       QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
+
+       qlcnic_api_unlock(adapter);
+err:
+       adapter->fw_fail_cnt = 0;
+       clear_bit(__QLCNIC_START_FW, &adapter->state);
+       clear_bit(__QLCNIC_RESETTING, &adapter->state);
+}
+
+static int
+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);
+
+       if (((state & 0x11111111) == (act & 0x11111111)) ||
+                       ((act & 0x11111111) == ((state >> 1) & 0x11111111)))
+               return 0;
+       else
+               return 1;
+}
+
+static int
+qlcnic_can_start_firmware(struct qlcnic_adapter *adapter)
+{
+       u32 val, prev_state;
+       int cnt = 0;
+       int portnum = adapter->portnum;
+
+       if (qlcnic_api_lock(adapter))
+               return -1;
+
+       val = QLCRD32(adapter, QLCNIC_CRB_DEV_REF_COUNT);
+       if (!(val & ((int)0x1 << (portnum * 4)))) {
+               val |= ((u32)0x1 << (portnum * 4));
+               QLCWR32(adapter, QLCNIC_CRB_DEV_REF_COUNT, val);
+       } else if (test_and_clear_bit(__QLCNIC_START_FW, &adapter->state)) {
+               goto start_fw;
+       }
+
+       prev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
+
+       switch (prev_state) {
+       case QLCNIC_DEV_COLD:
+start_fw:
+               QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_INITALIZING);
+               qlcnic_api_unlock(adapter);
+               return 1;
+
+       case QLCNIC_DEV_READY:
+               qlcnic_api_unlock(adapter);
+               return 0;
+
+       case QLCNIC_DEV_NEED_RESET:
+               val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
+               val |= ((u32)0x1 << (portnum * 4));
+               QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
+               break;
+
+       case QLCNIC_DEV_NEED_QUISCENT:
+               val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
+               val |= ((u32)0x1 << ((portnum * 4) + 1));
+               QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
+               break;
+
+       case QLCNIC_DEV_FAILED:
+               qlcnic_api_unlock(adapter);
+               return -1;
+       }
+
+       qlcnic_api_unlock(adapter);
+       msleep(1000);
+       while ((QLCRD32(adapter, QLCNIC_CRB_DEV_STATE) != QLCNIC_DEV_READY) &&
+                       ++cnt < 20)
+               msleep(1000);
+
+       if (cnt >= 20)
+               return -1;
+
+       if (qlcnic_api_lock(adapter))
+               return -1;
+
+       val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
+       val &= ~((u32)0x3 << (portnum * 4));
+       QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
+
+       qlcnic_api_unlock(adapter);
+
+       return 0;
+}
+
+static void
+qlcnic_fwinit_work(struct work_struct *work)
+{
+       struct qlcnic_adapter *adapter = container_of(work,
+                       struct qlcnic_adapter, fw_work.work);
+       int dev_state;
+
+       if (++adapter->fw_wait_cnt > FW_POLL_THRESH)
+               goto err_ret;
+
+       if (test_bit(__QLCNIC_START_FW, &adapter->state)) {
+
+               if (qlcnic_check_drv_state(adapter)) {
+                       qlcnic_schedule_work(adapter,
+                                       qlcnic_fwinit_work, FW_POLL_DELAY);
+                       return;
+               }
+
+               if (!qlcnic_start_firmware(adapter)) {
+                       qlcnic_schedule_work(adapter, qlcnic_attach_work, 0);
+                       return;
+               }
+
+               goto err_ret;
+       }
+
+       dev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
+       switch (dev_state) {
+       case QLCNIC_DEV_READY:
+               if (!qlcnic_start_firmware(adapter)) {
+                       qlcnic_schedule_work(adapter, qlcnic_attach_work, 0);
+                       return;
+               }
+       case QLCNIC_DEV_FAILED:
+               break;
+
+       default:
+               qlcnic_schedule_work(adapter,
+                       qlcnic_fwinit_work, 2 * FW_POLL_DELAY);
+               return;
+       }
+
+err_ret:
+       qlcnic_clr_all_drv_state(adapter);
+}
+
+static void
+qlcnic_detach_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 status;
+
+       netif_device_detach(netdev);
+
+       qlcnic_down(adapter, netdev);
+
+       rtnl_lock();
+       qlcnic_detach(adapter);
+       rtnl_unlock();
+
+       status = QLCRD32(adapter, QLCNIC_PEG_HALT_STATUS1);
+
+       if (status & QLCNIC_RCODE_FATAL_ERROR)
+               goto err_ret;
+
+       if (adapter->temp == QLCNIC_TEMP_PANIC)
+               goto err_ret;
+
+       qlcnic_set_drv_state(adapter, adapter->dev_state);
+
+       adapter->fw_wait_cnt = 0;
+
+       qlcnic_schedule_work(adapter, qlcnic_fwinit_work, FW_POLL_DELAY);
+
+       return;
+
+err_ret:
+       qlcnic_clr_all_drv_state(adapter);
+
+}
+
+static void
+qlcnic_dev_request_reset(struct qlcnic_adapter *adapter)
+{
+       u32 state;
+
+       if (qlcnic_api_lock(adapter))
+               return;
+
+       state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
+
+       if (state != QLCNIC_DEV_INITALIZING && state != QLCNIC_DEV_NEED_RESET) {
+               QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_NEED_RESET);
+               set_bit(__QLCNIC_START_FW, &adapter->state);
+       }
+
+       qlcnic_api_unlock(adapter);
+}
+
+static void
+qlcnic_schedule_work(struct qlcnic_adapter *adapter,
+               work_func_t func, int delay)
+{
+       INIT_DELAYED_WORK(&adapter->fw_work, func);
+       schedule_delayed_work(&adapter->fw_work, round_jiffies_relative(delay));
+}
+
+static void
+qlcnic_cancel_fw_work(struct qlcnic_adapter *adapter)
+{
+       while (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
+               msleep(10);
+
+       cancel_delayed_work_sync(&adapter->fw_work);
+}
+
+static void
+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;
+       int err;
+
+       if (netif_running(netdev)) {
+               err = qlcnic_attach(adapter);
+               if (err)
+                       goto done;
+
+               err = qlcnic_up(adapter, netdev);
+               if (err) {
+                       qlcnic_detach(adapter);
+                       goto done;
+               }
+
+               qlcnic_config_indev_addr(netdev, NETDEV_UP);
+       }
+
+       netif_device_attach(netdev);
+
+done:
+       adapter->fw_fail_cnt = 0;
+       clear_bit(__QLCNIC_RESETTING, &adapter->state);
+
+       if (!qlcnic_clr_drv_state(adapter))
+               qlcnic_schedule_work(adapter, qlcnic_fw_poll_work,
+                                                       FW_POLL_DELAY);
+}
+
+static int
+qlcnic_check_health(struct qlcnic_adapter *adapter)
+{
+       u32 state = 0, heartbit;
+       struct net_device *netdev = adapter->netdev;
+
+       if (qlcnic_check_temp(adapter))
+               goto detach;
+
+       if (adapter->need_fw_reset) {
+               qlcnic_dev_request_reset(adapter);
+               goto detach;
+       }
+
+       state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
+       if (state == QLCNIC_DEV_NEED_RESET || state == QLCNIC_DEV_NEED_QUISCENT)
+               adapter->need_fw_reset = 1;
+
+       heartbit = QLCRD32(adapter, QLCNIC_PEG_ALIVE_COUNTER);
+       if (heartbit != adapter->heartbit) {
+               adapter->heartbit = heartbit;
+               adapter->fw_fail_cnt = 0;
+               if (adapter->need_fw_reset)
+                       goto detach;
+               return 0;
+       }
+
+       if (++adapter->fw_fail_cnt < FW_FAIL_THRESH)
+               return 0;
+
+       qlcnic_dev_request_reset(adapter);
+
+       clear_bit(__QLCNIC_FW_ATTACHED, &adapter->state);
+
+       dev_info(&netdev->dev, "firmware hang detected\n");
+
+detach:
+       adapter->dev_state = (state == QLCNIC_DEV_NEED_QUISCENT) ? state :
+               QLCNIC_DEV_NEED_RESET;
+
+       if ((auto_fw_reset == AUTO_FW_RESET_ENABLED) &&
+                       !test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
+               qlcnic_schedule_work(adapter, qlcnic_detach_work, 0);
+
+       return 1;
+}
+
+static void
+qlcnic_fw_poll_work(struct work_struct *work)
+{
+       struct qlcnic_adapter *adapter = container_of(work,
+                               struct qlcnic_adapter, fw_work.work);
+
+       if (test_bit(__QLCNIC_RESETTING, &adapter->state))
+               goto reschedule;
+
+
+       if (qlcnic_check_health(adapter))
+               return;
+
+reschedule:
+       qlcnic_schedule_work(adapter, qlcnic_fw_poll_work, FW_POLL_DELAY);
+}
+
+static ssize_t
+qlcnic_store_bridged_mode(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t len)
+{
+       struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+       unsigned long new;
+       int ret = -EINVAL;
+
+       if (!(adapter->capabilities & QLCNIC_FW_CAPABILITY_BDG))
+               goto err_out;
+
+       if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
+               goto err_out;
+
+       if (strict_strtoul(buf, 2, &new))
+               goto err_out;
+
+       if (!qlcnic_config_bridged_mode(adapter, !!new))
+               ret = len;
+
+err_out:
+       return ret;
+}
+
+static ssize_t
+qlcnic_show_bridged_mode(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+       int bridged_mode = 0;
+
+       if (adapter->capabilities & QLCNIC_FW_CAPABILITY_BDG)
+               bridged_mode = !!(adapter->flags & QLCNIC_BRIDGE_ENABLED);
+
+       return sprintf(buf, "%d\n", bridged_mode);
+}
+
+static struct device_attribute dev_attr_bridged_mode = {
+       .attr = {.name = "bridged_mode", .mode = (S_IRUGO | S_IWUSR)},
+       .show = qlcnic_show_bridged_mode,
+       .store = qlcnic_store_bridged_mode,
+};
+
+static ssize_t
+qlcnic_store_diag_mode(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t len)
+{
+       struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+       unsigned long new;
+
+       if (strict_strtoul(buf, 2, &new))
+               return -EINVAL;
+
+       if (!!new != !!(adapter->flags & QLCNIC_DIAG_ENABLED))
+               adapter->flags ^= QLCNIC_DIAG_ENABLED;
+
+       return len;
+}
+
+static ssize_t
+qlcnic_show_diag_mode(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%d\n",
+                       !!(adapter->flags & QLCNIC_DIAG_ENABLED));
+}
+
+static struct device_attribute dev_attr_diag_mode = {
+       .attr = {.name = "diag_mode", .mode = (S_IRUGO | S_IWUSR)},
+       .show = qlcnic_show_diag_mode,
+       .store = qlcnic_store_diag_mode,
+};
+
+static int
+qlcnic_sysfs_validate_crb(struct qlcnic_adapter *adapter,
+               loff_t offset, size_t size)
+{
+       if (!(adapter->flags & QLCNIC_DIAG_ENABLED))
+               return -EIO;
+
+       if ((size != 4) || (offset & 0x3))
+               return  -EINVAL;
+
+       if (offset < QLCNIC_PCI_CRBSPACE)
+               return -EINVAL;
+
+       return 0;
+}
+
+static ssize_t
+qlcnic_sysfs_read_crb(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);
+       u32 data;
+       int ret;
+
+       ret = qlcnic_sysfs_validate_crb(adapter, offset, size);
+       if (ret != 0)
+               return ret;
+
+       data = QLCRD32(adapter, offset);
+       memcpy(buf, &data, size);
+       return size;
+}
+
+static ssize_t
+qlcnic_sysfs_write_crb(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);
+       u32 data;
+       int ret;
+
+       ret = qlcnic_sysfs_validate_crb(adapter, offset, size);
+       if (ret != 0)
+               return ret;
+
+       memcpy(&data, buf, size);
+       QLCWR32(adapter, offset, data);
+       return size;
+}
+
+static int
+qlcnic_sysfs_validate_mem(struct qlcnic_adapter *adapter,
+               loff_t offset, size_t size)
+{
+       if (!(adapter->flags & QLCNIC_DIAG_ENABLED))
+               return -EIO;
+
+       if ((size != 8) || (offset & 0x7))
+               return  -EIO;
+
+       return 0;
+}
+
+static ssize_t
+qlcnic_sysfs_read_mem(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);
+       u64 data;
+       int ret;
+
+       ret = qlcnic_sysfs_validate_mem(adapter, offset, size);
+       if (ret != 0)
+               return ret;
+
+       if (qlcnic_pci_mem_read_2M(adapter, offset, &data))
+               return -EIO;
+
+       memcpy(buf, &data, size);
+
+       return size;
+}
+
+static ssize_t
+qlcnic_sysfs_write_mem(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);
+       u64 data;
+       int ret;
+
+       ret = qlcnic_sysfs_validate_mem(adapter, offset, size);
+       if (ret != 0)
+               return ret;
+
+       memcpy(&data, buf, size);
+
+       if (qlcnic_pci_mem_write_2M(adapter, offset, data))
+               return -EIO;
+
+       return size;
+}
+
+
+static struct bin_attribute bin_attr_crb = {
+       .attr = {.name = "crb", .mode = (S_IRUGO | S_IWUSR)},
+       .size = 0,
+       .read = qlcnic_sysfs_read_crb,
+       .write = qlcnic_sysfs_write_crb,
+};
+
+static struct bin_attribute bin_attr_mem = {
+       .attr = {.name = "mem", .mode = (S_IRUGO | S_IWUSR)},
+       .size = 0,
+       .read = qlcnic_sysfs_read_mem,
+       .write = qlcnic_sysfs_write_mem,
+};
+
+static void
+qlcnic_create_sysfs_entries(struct qlcnic_adapter *adapter)
+{
+       struct device *dev = &adapter->pdev->dev;
+
+       if (adapter->capabilities & QLCNIC_FW_CAPABILITY_BDG)
+               if (device_create_file(dev, &dev_attr_bridged_mode))
+                       dev_warn(dev,
+                               "failed to create bridged_mode sysfs entry\n");
+}
+
+static void
+qlcnic_remove_sysfs_entries(struct qlcnic_adapter *adapter)
+{
+       struct device *dev = &adapter->pdev->dev;
+
+       if (adapter->capabilities & QLCNIC_FW_CAPABILITY_BDG)
+               device_remove_file(dev, &dev_attr_bridged_mode);
+}
+
+static void
+qlcnic_create_diag_entries(struct qlcnic_adapter *adapter)
+{
+       struct device *dev = &adapter->pdev->dev;
+
+       if (device_create_file(dev, &dev_attr_diag_mode))
+               dev_info(dev, "failed to create diag_mode sysfs entry\n");
+       if (device_create_bin_file(dev, &bin_attr_crb))
+               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");
+}
+
+
+static void
+qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter)
+{
+       struct device *dev = &adapter->pdev->dev;
+
+       device_remove_file(dev, &dev_attr_diag_mode);
+       device_remove_bin_file(dev, &bin_attr_crb);
+       device_remove_bin_file(dev, &bin_attr_mem);
+}
+
+#ifdef CONFIG_INET
+
+#define is_qlcnic_netdev(dev) (dev->netdev_ops == &qlcnic_netdev_ops)
+
+static int
+qlcnic_destip_supported(struct qlcnic_adapter *adapter)
+{
+       if (adapter->ahw.cut_through)
+               return 0;
+
+       return 1;
+}
+
+static void
+qlcnic_config_indev_addr(struct net_device *dev, unsigned long event)
+{
+       struct in_device *indev;
+       struct qlcnic_adapter *adapter = netdev_priv(dev);
+
+       if (!qlcnic_destip_supported(adapter))
+               return;
+
+       indev = in_dev_get(dev);
+       if (!indev)
+               return;
+
+       for_ifa(indev) {
+               switch (event) {
+               case NETDEV_UP:
+                       qlcnic_config_ipaddr(adapter,
+                                       ifa->ifa_address, QLCNIC_IP_UP);
+                       break;
+               case NETDEV_DOWN:
+                       qlcnic_config_ipaddr(adapter,
+                                       ifa->ifa_address, QLCNIC_IP_DOWN);
+                       break;
+               default:
+                       break;
+               }
+       } endfor_ifa(indev);
+
+       in_dev_put(indev);
+       return;
+}
+
+static int qlcnic_netdev_event(struct notifier_block *this,
+                                unsigned long event, void *ptr)
+{
+       struct qlcnic_adapter *adapter;
+       struct net_device *dev = (struct net_device *)ptr;
+
+recheck:
+       if (dev == NULL)
+               goto done;
+
+       if (dev->priv_flags & IFF_802_1Q_VLAN) {
+               dev = vlan_dev_real_dev(dev);
+               goto recheck;
+       }
+
+       if (!is_qlcnic_netdev(dev))
+               goto done;
+
+       adapter = netdev_priv(dev);
+
+       if (!adapter)
+               goto done;
+
+       if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
+               goto done;
+
+       qlcnic_config_indev_addr(dev, event);
+done:
+       return NOTIFY_DONE;
+}
+
+static int
+qlcnic_inetaddr_event(struct notifier_block *this,
+               unsigned long event, void *ptr)
+{
+       struct qlcnic_adapter *adapter;
+       struct net_device *dev;
+
+       struct in_ifaddr *ifa = (struct in_ifaddr *)ptr;
+
+       dev = ifa->ifa_dev ? ifa->ifa_dev->dev : NULL;
+
+recheck:
+       if (dev == NULL || !netif_running(dev))
+               goto done;
+
+       if (dev->priv_flags & IFF_802_1Q_VLAN) {
+               dev = vlan_dev_real_dev(dev);
+               goto recheck;
+       }
+
+       if (!is_qlcnic_netdev(dev))
+               goto done;
+
+       adapter = netdev_priv(dev);
+
+       if (!adapter || !qlcnic_destip_supported(adapter))
+               goto done;
+
+       if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
+               goto done;
+
+       switch (event) {
+       case NETDEV_UP:
+               qlcnic_config_ipaddr(adapter, ifa->ifa_address, QLCNIC_IP_UP);
+               break;
+       case NETDEV_DOWN:
+               qlcnic_config_ipaddr(adapter, ifa->ifa_address, QLCNIC_IP_DOWN);
+               break;
+       default:
+               break;
+       }
+
+done:
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block   qlcnic_netdev_cb = {
+       .notifier_call = qlcnic_netdev_event,
+};
+
+static struct notifier_block qlcnic_inetaddr_cb = {
+       .notifier_call = qlcnic_inetaddr_event,
+};
+#else
+static void
+qlcnic_config_indev_addr(struct net_device *dev, unsigned long event)
+{ }
+#endif
+
+static struct pci_driver qlcnic_driver = {
+       .name = qlcnic_driver_name,
+       .id_table = qlcnic_pci_tbl,
+       .probe = qlcnic_probe,
+       .remove = __devexit_p(qlcnic_remove),
+#ifdef CONFIG_PM
+       .suspend = qlcnic_suspend,
+       .resume = qlcnic_resume,
+#endif
+       .shutdown = qlcnic_shutdown
+};
+
+static int __init qlcnic_init_module(void)
+{
+
+       printk(KERN_INFO "%s\n", qlcnic_driver_string);
+
+#ifdef CONFIG_INET
+       register_netdevice_notifier(&qlcnic_netdev_cb);
+       register_inetaddr_notifier(&qlcnic_inetaddr_cb);
+#endif
+
+
+       return pci_register_driver(&qlcnic_driver);
+}
+
+module_init(qlcnic_init_module);
+
+static void __exit qlcnic_exit_module(void)
+{
+
+       pci_unregister_driver(&qlcnic_driver);
+
+#ifdef CONFIG_INET
+       unregister_inetaddr_notifier(&qlcnic_inetaddr_cb);
+       unregister_netdevice_notifier(&qlcnic_netdev_cb);
+#endif
+}
+
+module_exit(qlcnic_exit_module);
index 862c1aaf38608955600fc6728c45850083845a1c..9169c4cf413a3c80c76f728c1969591a279fa773 100644 (file)
 #define RX_RING_SHADOW_SPACE   (sizeof(u64) + \
                MAX_DB_PAGES_PER_BQ(NUM_SMALL_BUFFERS) * sizeof(u64) + \
                MAX_DB_PAGES_PER_BQ(NUM_LARGE_BUFFERS) * sizeof(u64))
-#define SMALL_BUFFER_SIZE 512
-#define SMALL_BUF_MAP_SIZE (SMALL_BUFFER_SIZE / 2)
 #define LARGE_BUFFER_MAX_SIZE 8192
 #define LARGE_BUFFER_MIN_SIZE 2048
-#define MAX_SPLIT_SIZE 1023
-#define QLGE_SB_PAD 32
 
 #define MAX_CQ 128
 #define DFLT_COALESCE_WAIT 100 /* 100 usec wait for coalescing */
 #define TX_DESC_PER_OAL 0
 #endif
 
+/* Word shifting for converting 64-bit
+ * address to a series of 16-bit words.
+ * This is used for some MPI firmware
+ * mailbox commands.
+ */
+#define LSW(x)  ((u16)(x))
+#define MSW(x)  ((u16)((u32)(x) >> 16))
+#define LSD(x)  ((u32)((u64)(x)))
+#define MSD(x)  ((u32)((((u64)(x)) >> 32)))
+
 /* MPI test register definitions. This register
  * is used for determining alternate NIC function's
  * PCI->func number.
  */
 enum {
        MPI_TEST_FUNC_PORT_CFG = 0x1002,
+       MPI_TEST_FUNC_PRB_CTL = 0x100e,
+               MPI_TEST_FUNC_PRB_EN = 0x18a20000,
+       MPI_TEST_FUNC_RST_STS = 0x100a,
+               MPI_TEST_FUNC_RST_FRC = 0x00000003,
+       MPI_TEST_NIC_FUNC_MASK = 0x00000007,
+       MPI_TEST_NIC1_FUNCTION_ENABLE = (1 << 0),
+       MPI_TEST_NIC1_FUNCTION_MASK = 0x0000000e,
        MPI_TEST_NIC1_FUNC_SHIFT = 1,
+       MPI_TEST_NIC2_FUNCTION_ENABLE = (1 << 4),
+       MPI_TEST_NIC2_FUNCTION_MASK = 0x000000e0,
        MPI_TEST_NIC2_FUNC_SHIFT = 5,
-       MPI_TEST_NIC_FUNC_MASK = 0x00000007,
+       MPI_TEST_FC1_FUNCTION_ENABLE = (1 << 8),
+       MPI_TEST_FC1_FUNCTION_MASK      = 0x00000e00,
+       MPI_TEST_FC1_FUNCTION_SHIFT = 9,
+       MPI_TEST_FC2_FUNCTION_ENABLE = (1 << 12),
+       MPI_TEST_FC2_FUNCTION_MASK = 0x0000e000,
+       MPI_TEST_FC2_FUNCTION_SHIFT = 13,
+
+       MPI_NIC_READ = 0x00000000,
+       MPI_NIC_REG_BLOCK = 0x00020000,
+       MPI_NIC_FUNCTION_SHIFT = 6,
 };
 
 /*
@@ -468,7 +492,7 @@ enum {
        MDIO_PORT = 0x00000440,
        MDIO_STATUS = 0x00000450,
 
-       /* XGMAC AUX statistics  registers */
+       XGMAC_REGISTER_END = 0x00000740,
 };
 
 /*
@@ -509,6 +533,7 @@ enum {
 enum {
        MAC_ADDR_IDX_SHIFT = 4,
        MAC_ADDR_TYPE_SHIFT = 16,
+       MAC_ADDR_TYPE_COUNT = 10,
        MAC_ADDR_TYPE_MASK = 0x000f0000,
        MAC_ADDR_TYPE_CAM_MAC = 0x00000000,
        MAC_ADDR_TYPE_MULTI_MAC = 0x00010000,
@@ -526,6 +551,30 @@ enum {
        MAC_ADDR_MR = (1 << 30),
        MAC_ADDR_MW = (1 << 31),
        MAX_MULTICAST_ENTRIES = 32,
+
+       /* Entry count and words per entry
+        * for each address type in the filter.
+        */
+       MAC_ADDR_MAX_CAM_ENTRIES = 512,
+       MAC_ADDR_MAX_CAM_WCOUNT = 3,
+       MAC_ADDR_MAX_MULTICAST_ENTRIES = 32,
+       MAC_ADDR_MAX_MULTICAST_WCOUNT = 2,
+       MAC_ADDR_MAX_VLAN_ENTRIES = 4096,
+       MAC_ADDR_MAX_VLAN_WCOUNT = 1,
+       MAC_ADDR_MAX_MCAST_FLTR_ENTRIES = 4096,
+       MAC_ADDR_MAX_MCAST_FLTR_WCOUNT = 1,
+       MAC_ADDR_MAX_FC_MAC_ENTRIES = 4,
+       MAC_ADDR_MAX_FC_MAC_WCOUNT = 2,
+       MAC_ADDR_MAX_MGMT_MAC_ENTRIES = 8,
+       MAC_ADDR_MAX_MGMT_MAC_WCOUNT = 2,
+       MAC_ADDR_MAX_MGMT_VLAN_ENTRIES = 16,
+       MAC_ADDR_MAX_MGMT_VLAN_WCOUNT = 1,
+       MAC_ADDR_MAX_MGMT_V4_ENTRIES = 4,
+       MAC_ADDR_MAX_MGMT_V4_WCOUNT = 1,
+       MAC_ADDR_MAX_MGMT_V6_ENTRIES = 4,
+       MAC_ADDR_MAX_MGMT_V6_WCOUNT = 4,
+       MAC_ADDR_MAX_MGMT_TU_DP_ENTRIES = 4,
+       MAC_ADDR_MAX_MGMT_TU_DP_WCOUNT = 1,
 };
 
 /*
@@ -596,6 +645,7 @@ enum {
 enum {
        RT_IDX_IDX_SHIFT = 8,
        RT_IDX_TYPE_MASK = 0x000f0000,
+       RT_IDX_TYPE_SHIFT = 16,
        RT_IDX_TYPE_RT = 0x00000000,
        RT_IDX_TYPE_RT_INV = 0x00010000,
        RT_IDX_TYPE_NICQ = 0x00020000,
@@ -664,7 +714,89 @@ enum {
        RT_IDX_UNUSED013 = 13,
        RT_IDX_UNUSED014 = 14,
        RT_IDX_PROMISCUOUS_SLOT = 15,
-       RT_IDX_MAX_SLOTS = 16,
+       RT_IDX_MAX_RT_SLOTS = 8,
+       RT_IDX_MAX_NIC_SLOTS = 16,
+};
+
+/*
+ * Serdes Address Register (XG_SERDES_ADDR) bit definitions.
+ */
+enum {
+       XG_SERDES_ADDR_RDY = (1 << 31),
+       XG_SERDES_ADDR_R = (1 << 30),
+
+       XG_SERDES_ADDR_STS = 0x00001E06,
+       XG_SERDES_ADDR_XFI1_PWR_UP = 0x00000005,
+       XG_SERDES_ADDR_XFI2_PWR_UP = 0x0000000a,
+       XG_SERDES_ADDR_XAUI_PWR_DOWN = 0x00000001,
+
+       /* Serdes coredump definitions. */
+       XG_SERDES_XAUI_AN_START = 0x00000000,
+       XG_SERDES_XAUI_AN_END = 0x00000034,
+       XG_SERDES_XAUI_HSS_PCS_START = 0x00000800,
+       XG_SERDES_XAUI_HSS_PCS_END = 0x0000880,
+       XG_SERDES_XFI_AN_START = 0x00001000,
+       XG_SERDES_XFI_AN_END = 0x00001034,
+       XG_SERDES_XFI_TRAIN_START = 0x10001050,
+       XG_SERDES_XFI_TRAIN_END = 0x1000107C,
+       XG_SERDES_XFI_HSS_PCS_START = 0x00001800,
+       XG_SERDES_XFI_HSS_PCS_END = 0x00001838,
+       XG_SERDES_XFI_HSS_TX_START = 0x00001c00,
+       XG_SERDES_XFI_HSS_TX_END = 0x00001c1f,
+       XG_SERDES_XFI_HSS_RX_START = 0x00001c40,
+       XG_SERDES_XFI_HSS_RX_END = 0x00001c5f,
+       XG_SERDES_XFI_HSS_PLL_START = 0x00001e00,
+       XG_SERDES_XFI_HSS_PLL_END = 0x00001e1f,
+};
+
+/*
+ *  NIC Probe Mux Address Register (PRB_MX_ADDR) bit definitions.
+ */
+enum {
+       PRB_MX_ADDR_ARE = (1 << 16),
+       PRB_MX_ADDR_UP = (1 << 15),
+       PRB_MX_ADDR_SWP = (1 << 14),
+
+       /* Module select values. */
+       PRB_MX_ADDR_MAX_MODS = 21,
+       PRB_MX_ADDR_MOD_SEL_SHIFT = 9,
+       PRB_MX_ADDR_MOD_SEL_TBD = 0,
+       PRB_MX_ADDR_MOD_SEL_IDE1 = 1,
+       PRB_MX_ADDR_MOD_SEL_IDE2 = 2,
+       PRB_MX_ADDR_MOD_SEL_FRB = 3,
+       PRB_MX_ADDR_MOD_SEL_ODE1 = 4,
+       PRB_MX_ADDR_MOD_SEL_ODE2 = 5,
+       PRB_MX_ADDR_MOD_SEL_DA1 = 6,
+       PRB_MX_ADDR_MOD_SEL_DA2 = 7,
+       PRB_MX_ADDR_MOD_SEL_IMP1 = 8,
+       PRB_MX_ADDR_MOD_SEL_IMP2 = 9,
+       PRB_MX_ADDR_MOD_SEL_OMP1 = 10,
+       PRB_MX_ADDR_MOD_SEL_OMP2 = 11,
+       PRB_MX_ADDR_MOD_SEL_ORS1 = 12,
+       PRB_MX_ADDR_MOD_SEL_ORS2 = 13,
+       PRB_MX_ADDR_MOD_SEL_REG = 14,
+       PRB_MX_ADDR_MOD_SEL_MAC1 = 16,
+       PRB_MX_ADDR_MOD_SEL_MAC2 = 17,
+       PRB_MX_ADDR_MOD_SEL_VQM1 = 18,
+       PRB_MX_ADDR_MOD_SEL_VQM2 = 19,
+       PRB_MX_ADDR_MOD_SEL_MOP = 20,
+       /* Bit fields indicating which modules
+        * are valid for each clock domain.
+        */
+       PRB_MX_ADDR_VALID_SYS_MOD = 0x000f7ff7,
+       PRB_MX_ADDR_VALID_PCI_MOD = 0x000040c1,
+       PRB_MX_ADDR_VALID_XGM_MOD = 0x00037309,
+       PRB_MX_ADDR_VALID_FC_MOD = 0x00003001,
+       PRB_MX_ADDR_VALID_TOTAL = 34,
+
+       /* Clock domain values. */
+       PRB_MX_ADDR_CLOCK_SHIFT = 6,
+       PRB_MX_ADDR_SYS_CLOCK = 0,
+       PRB_MX_ADDR_PCI_CLOCK = 2,
+       PRB_MX_ADDR_FC_CLOCK = 5,
+       PRB_MX_ADDR_XGM_CLOCK = 6,
+
+       PRB_MX_ADDR_MAX_MUX = 64,
 };
 
 /*
@@ -737,6 +869,21 @@ enum {
        PRB_MX_DATA = 0xfc,     /* Use semaphore */
 };
 
+#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
+#define SMALL_BUFFER_SIZE 256
+#define SMALL_BUF_MAP_SIZE SMALL_BUFFER_SIZE
+#define SPLT_SETTING  FSC_DBRST_1024
+#define SPLT_LEN 0
+#define QLGE_SB_PAD 0
+#else
+#define SMALL_BUFFER_SIZE 512
+#define SMALL_BUF_MAP_SIZE (SMALL_BUFFER_SIZE / 2)
+#define SPLT_SETTING  FSC_SH
+#define SPLT_LEN (SPLT_HDR_EP | \
+       min(SMALL_BUF_MAP_SIZE, 1023))
+#define QLGE_SB_PAD 32
+#endif
+
 /*
  * CAM output format.
  */
@@ -1421,7 +1568,7 @@ struct nic_stats {
        u64 rx_nic_fifo_drop;
 };
 
-/* Address/Length pairs for the coredump. */
+/* Firmware coredump internal register address/length pairs. */
 enum {
        MPI_CORE_REGS_ADDR = 0x00030000,
        MPI_CORE_REGS_CNT = 127,
@@ -1476,7 +1623,7 @@ struct mpi_coredump_segment_header {
        u8      description[16];
 };
 
-/* Reg dump segment numbers. */
+/* Firmware coredump header segment numbers. */
 enum {
        CORE_SEG_NUM = 1,
        TEST_LOGIC_SEG_NUM = 2,
@@ -1527,6 +1674,67 @@ enum {
 
 };
 
+/* There are 64 generic NIC registers. */
+#define NIC_REGS_DUMP_WORD_COUNT               64
+/* XGMAC word count. */
+#define XGMAC_DUMP_WORD_COUNT          (XGMAC_REGISTER_END / 4)
+/* Word counts for the SERDES blocks. */
+#define XG_SERDES_XAUI_AN_COUNT                14
+#define XG_SERDES_XAUI_HSS_PCS_COUNT   33
+#define XG_SERDES_XFI_AN_COUNT         14
+#define XG_SERDES_XFI_TRAIN_COUNT              12
+#define XG_SERDES_XFI_HSS_PCS_COUNT    15
+#define XG_SERDES_XFI_HSS_TX_COUNT             32
+#define XG_SERDES_XFI_HSS_RX_COUNT             32
+#define XG_SERDES_XFI_HSS_PLL_COUNT    32
+
+/* There are 2 CNA ETS and 8 NIC ETS registers. */
+#define ETS_REGS_DUMP_WORD_COUNT               10
+
+/* Each probe mux entry stores the probe type plus 64 entries
+ * that are each each 64-bits in length. There are a total of
+ * 34 (PRB_MX_ADDR_VALID_TOTAL) valid probes.
+ */
+#define PRB_MX_ADDR_PRB_WORD_COUNT             (1 + (PRB_MX_ADDR_MAX_MUX * 2))
+#define PRB_MX_DUMP_TOT_COUNT          (PRB_MX_ADDR_PRB_WORD_COUNT * \
+                                                       PRB_MX_ADDR_VALID_TOTAL)
+/* Each routing entry consists of 4 32-bit words.
+ * They are route type, index, index word, and result.
+ * There are 2 route blocks with 8 entries each and
+ *  2 NIC blocks with 16 entries each.
+ * The totol entries is 48 with 4 words each.
+ */
+#define RT_IDX_DUMP_ENTRIES                    48
+#define RT_IDX_DUMP_WORDS_PER_ENTRY    4
+#define RT_IDX_DUMP_TOT_WORDS          (RT_IDX_DUMP_ENTRIES * \
+                                               RT_IDX_DUMP_WORDS_PER_ENTRY)
+/* There are 10 address blocks in filter, each with
+ * different entry counts and different word-count-per-entry.
+ */
+#define MAC_ADDR_DUMP_ENTRIES \
+       ((MAC_ADDR_MAX_CAM_ENTRIES * MAC_ADDR_MAX_CAM_WCOUNT) + \
+       (MAC_ADDR_MAX_MULTICAST_ENTRIES * MAC_ADDR_MAX_MULTICAST_WCOUNT) + \
+       (MAC_ADDR_MAX_VLAN_ENTRIES * MAC_ADDR_MAX_VLAN_WCOUNT) + \
+       (MAC_ADDR_MAX_MCAST_FLTR_ENTRIES * MAC_ADDR_MAX_MCAST_FLTR_WCOUNT) + \
+       (MAC_ADDR_MAX_FC_MAC_ENTRIES * MAC_ADDR_MAX_FC_MAC_WCOUNT) + \
+       (MAC_ADDR_MAX_MGMT_MAC_ENTRIES * MAC_ADDR_MAX_MGMT_MAC_WCOUNT) + \
+       (MAC_ADDR_MAX_MGMT_VLAN_ENTRIES * MAC_ADDR_MAX_MGMT_VLAN_WCOUNT) + \
+       (MAC_ADDR_MAX_MGMT_V4_ENTRIES * MAC_ADDR_MAX_MGMT_V4_WCOUNT) + \
+       (MAC_ADDR_MAX_MGMT_V6_ENTRIES * MAC_ADDR_MAX_MGMT_V6_WCOUNT) + \
+       (MAC_ADDR_MAX_MGMT_TU_DP_ENTRIES * MAC_ADDR_MAX_MGMT_TU_DP_WCOUNT))
+#define MAC_ADDR_DUMP_WORDS_PER_ENTRY  2
+#define MAC_ADDR_DUMP_TOT_WORDS                (MAC_ADDR_DUMP_ENTRIES * \
+                                               MAC_ADDR_DUMP_WORDS_PER_ENTRY)
+/* Maximum of 4 functions whose semaphore registeres are
+ * in the coredump.
+ */
+#define MAX_SEMAPHORE_FUNCTIONS                4
+/* Defines for access the MPI shadow registers. */
+#define RISC_124               0x0003007c
+#define RISC_127               0x0003007f
+#define SHADOW_OFFSET  0xb0000000
+#define SHADOW_REG_SHIFT       20
+
 struct ql_nic_misc {
        u32 rx_ring_count;
        u32 tx_ring_count;
@@ -1568,6 +1776,199 @@ struct ql_reg_dump {
        u32 ets[8+2];
 };
 
+struct ql_mpi_coredump {
+       /* segment 0 */
+       struct mpi_coredump_global_header mpi_global_header;
+
+       /* segment 1 */
+       struct mpi_coredump_segment_header core_regs_seg_hdr;
+       u32 mpi_core_regs[MPI_CORE_REGS_CNT];
+       u32 mpi_core_sh_regs[MPI_CORE_SH_REGS_CNT];
+
+       /* segment 2 */
+       struct mpi_coredump_segment_header test_logic_regs_seg_hdr;
+       u32 test_logic_regs[TEST_REGS_CNT];
+
+       /* segment 3 */
+       struct mpi_coredump_segment_header rmii_regs_seg_hdr;
+       u32 rmii_regs[RMII_REGS_CNT];
+
+       /* segment 4 */
+       struct mpi_coredump_segment_header fcmac1_regs_seg_hdr;
+       u32 fcmac1_regs[FCMAC_REGS_CNT];
+
+       /* segment 5 */
+       struct mpi_coredump_segment_header fcmac2_regs_seg_hdr;
+       u32 fcmac2_regs[FCMAC_REGS_CNT];
+
+       /* segment 6 */
+       struct mpi_coredump_segment_header fc1_mbx_regs_seg_hdr;
+       u32 fc1_mbx_regs[FC_MBX_REGS_CNT];
+
+       /* segment 7 */
+       struct mpi_coredump_segment_header ide_regs_seg_hdr;
+       u32 ide_regs[IDE_REGS_CNT];
+
+       /* segment 8 */
+       struct mpi_coredump_segment_header nic1_mbx_regs_seg_hdr;
+       u32 nic1_mbx_regs[NIC_MBX_REGS_CNT];
+
+       /* segment 9 */
+       struct mpi_coredump_segment_header smbus_regs_seg_hdr;
+       u32 smbus_regs[SMBUS_REGS_CNT];
+
+       /* segment 10 */
+       struct mpi_coredump_segment_header fc2_mbx_regs_seg_hdr;
+       u32 fc2_mbx_regs[FC_MBX_REGS_CNT];
+
+       /* segment 11 */
+       struct mpi_coredump_segment_header nic2_mbx_regs_seg_hdr;
+       u32 nic2_mbx_regs[NIC_MBX_REGS_CNT];
+
+       /* segment 12 */
+       struct mpi_coredump_segment_header i2c_regs_seg_hdr;
+       u32 i2c_regs[I2C_REGS_CNT];
+       /* segment 13 */
+       struct mpi_coredump_segment_header memc_regs_seg_hdr;
+       u32 memc_regs[MEMC_REGS_CNT];
+
+       /* segment 14 */
+       struct mpi_coredump_segment_header pbus_regs_seg_hdr;
+       u32 pbus_regs[PBUS_REGS_CNT];
+
+       /* segment 15 */
+       struct mpi_coredump_segment_header mde_regs_seg_hdr;
+       u32 mde_regs[MDE_REGS_CNT];
+
+       /* segment 16 */
+       struct mpi_coredump_segment_header nic_regs_seg_hdr;
+       u32 nic_regs[NIC_REGS_DUMP_WORD_COUNT];
+
+       /* segment 17 */
+       struct mpi_coredump_segment_header nic2_regs_seg_hdr;
+       u32 nic2_regs[NIC_REGS_DUMP_WORD_COUNT];
+
+       /* segment 18 */
+       struct mpi_coredump_segment_header xgmac1_seg_hdr;
+       u32 xgmac1[XGMAC_DUMP_WORD_COUNT];
+
+       /* segment 19 */
+       struct mpi_coredump_segment_header xgmac2_seg_hdr;
+       u32 xgmac2[XGMAC_DUMP_WORD_COUNT];
+
+       /* segment 20 */
+       struct mpi_coredump_segment_header code_ram_seg_hdr;
+       u32 code_ram[CODE_RAM_CNT];
+
+       /* segment 21 */
+       struct mpi_coredump_segment_header memc_ram_seg_hdr;
+       u32 memc_ram[MEMC_RAM_CNT];
+
+       /* segment 22 */
+       struct mpi_coredump_segment_header xaui_an_hdr;
+       u32 serdes_xaui_an[XG_SERDES_XAUI_AN_COUNT];
+
+       /* segment 23 */
+       struct mpi_coredump_segment_header xaui_hss_pcs_hdr;
+       u32 serdes_xaui_hss_pcs[XG_SERDES_XAUI_HSS_PCS_COUNT];
+
+       /* segment 24 */
+       struct mpi_coredump_segment_header xfi_an_hdr;
+       u32 serdes_xfi_an[XG_SERDES_XFI_AN_COUNT];
+
+       /* segment 25 */
+       struct mpi_coredump_segment_header xfi_train_hdr;
+       u32 serdes_xfi_train[XG_SERDES_XFI_TRAIN_COUNT];
+
+       /* segment 26 */
+       struct mpi_coredump_segment_header xfi_hss_pcs_hdr;
+       u32 serdes_xfi_hss_pcs[XG_SERDES_XFI_HSS_PCS_COUNT];
+
+       /* segment 27 */
+       struct mpi_coredump_segment_header xfi_hss_tx_hdr;
+       u32 serdes_xfi_hss_tx[XG_SERDES_XFI_HSS_TX_COUNT];
+
+       /* segment 28 */
+       struct mpi_coredump_segment_header xfi_hss_rx_hdr;
+       u32 serdes_xfi_hss_rx[XG_SERDES_XFI_HSS_RX_COUNT];
+
+       /* segment 29 */
+       struct mpi_coredump_segment_header xfi_hss_pll_hdr;
+       u32 serdes_xfi_hss_pll[XG_SERDES_XFI_HSS_PLL_COUNT];
+
+       /* segment 30 */
+       struct mpi_coredump_segment_header misc_nic_seg_hdr;
+       struct ql_nic_misc misc_nic_info;
+
+       /* segment 31 */
+       /* one interrupt state for each CQ */
+       struct mpi_coredump_segment_header intr_states_seg_hdr;
+       u32 intr_states[MAX_RX_RINGS];
+
+       /* segment 32 */
+       /* 3 cam words each for 16 unicast,
+        * 2 cam words for each of 32 multicast.
+        */
+       struct mpi_coredump_segment_header cam_entries_seg_hdr;
+       u32 cam_entries[(16 * 3) + (32 * 3)];
+
+       /* segment 33 */
+       struct mpi_coredump_segment_header nic_routing_words_seg_hdr;
+       u32 nic_routing_words[16];
+       /* segment 34 */
+       struct mpi_coredump_segment_header ets_seg_hdr;
+       u32 ets[ETS_REGS_DUMP_WORD_COUNT];
+
+       /* segment 35 */
+       struct mpi_coredump_segment_header probe_dump_seg_hdr;
+       u32 probe_dump[PRB_MX_DUMP_TOT_COUNT];
+
+       /* segment 36 */
+       struct mpi_coredump_segment_header routing_reg_seg_hdr;
+       u32 routing_regs[RT_IDX_DUMP_TOT_WORDS];
+
+       /* segment 37 */
+       struct mpi_coredump_segment_header mac_prot_reg_seg_hdr;
+       u32 mac_prot_regs[MAC_ADDR_DUMP_TOT_WORDS];
+
+       /* segment 38 */
+       struct mpi_coredump_segment_header xaui2_an_hdr;
+       u32 serdes2_xaui_an[XG_SERDES_XAUI_AN_COUNT];
+
+       /* segment 39 */
+       struct mpi_coredump_segment_header xaui2_hss_pcs_hdr;
+       u32 serdes2_xaui_hss_pcs[XG_SERDES_XAUI_HSS_PCS_COUNT];
+
+       /* segment 40 */
+       struct mpi_coredump_segment_header xfi2_an_hdr;
+       u32 serdes2_xfi_an[XG_SERDES_XFI_AN_COUNT];
+
+       /* segment 41 */
+       struct mpi_coredump_segment_header xfi2_train_hdr;
+       u32 serdes2_xfi_train[XG_SERDES_XFI_TRAIN_COUNT];
+
+       /* segment 42 */
+       struct mpi_coredump_segment_header xfi2_hss_pcs_hdr;
+       u32 serdes2_xfi_hss_pcs[XG_SERDES_XFI_HSS_PCS_COUNT];
+
+       /* segment 43 */
+       struct mpi_coredump_segment_header xfi2_hss_tx_hdr;
+       u32 serdes2_xfi_hss_tx[XG_SERDES_XFI_HSS_TX_COUNT];
+
+       /* segment 44 */
+       struct mpi_coredump_segment_header xfi2_hss_rx_hdr;
+       u32 serdes2_xfi_hss_rx[XG_SERDES_XFI_HSS_RX_COUNT];
+
+       /* segment 45 */
+       struct mpi_coredump_segment_header xfi2_hss_pll_hdr;
+       u32 serdes2_xfi_hss_pll[XG_SERDES_XFI_HSS_PLL_COUNT];
+
+       /* segment 50 */
+       /* semaphore register for all 5 functions */
+       struct mpi_coredump_segment_header sem_regs_seg_hdr;
+       u32 sem_regs[MAX_SEMAPHORE_FUNCTIONS];
+};
+
 /*
  * intr_context structure is used during initialization
  * to hook the interrupts.  It is also used in a single
@@ -1603,6 +2004,7 @@ enum {
        QL_CAM_RT_SET = 8,
        QL_SELFTEST = 9,
        QL_LB_LINK_UP = 10,
+       QL_FRC_COREDUMP = 11,
 };
 
 /* link_status bit definitions */
@@ -1724,6 +2126,8 @@ struct ql_adapter {
        u32 port_link_up;
        u32 port_init;
        u32 link_status;
+       struct ql_mpi_coredump *mpi_coredump;
+       u32 core_is_dumped;
        u32 link_config;
        u32 led_config;
        u32 max_frame_size;
@@ -1736,6 +2140,7 @@ struct ql_adapter {
        struct delayed_work mpi_work;
        struct delayed_work mpi_port_cfg_work;
        struct delayed_work mpi_idc_work;
+       struct delayed_work mpi_core_to_log;
        struct completion ide_completion;
        struct nic_operations *nic_ops;
        u16 device_id;
@@ -1807,6 +2212,7 @@ extern int ql_write_cfg(struct ql_adapter *qdev, void *ptr, int size, u32 bit,
 void ql_queue_fw_error(struct ql_adapter *qdev);
 void ql_mpi_work(struct work_struct *work);
 void ql_mpi_reset_work(struct work_struct *work);
+void ql_mpi_core_to_log(struct work_struct *work);
 int ql_wait_reg_rdy(struct ql_adapter *qdev, u32 reg, u32 bit, u32 ebit);
 void ql_queue_asic_error(struct ql_adapter *qdev);
 u32 ql_enable_completion_interrupt(struct ql_adapter *qdev, u32 intr);
@@ -1817,6 +2223,15 @@ void ql_mpi_port_cfg_work(struct work_struct *work);
 int ql_mb_get_fw_state(struct ql_adapter *qdev);
 int ql_cam_route_initialize(struct ql_adapter *qdev);
 int ql_read_mpi_reg(struct ql_adapter *qdev, u32 reg, u32 *data);
+int ql_write_mpi_reg(struct ql_adapter *qdev, u32 reg, u32 data);
+int ql_unpause_mpi_risc(struct ql_adapter *qdev);
+int ql_pause_mpi_risc(struct ql_adapter *qdev);
+int ql_hard_reset_mpi_risc(struct ql_adapter *qdev);
+int ql_dump_risc_ram_area(struct ql_adapter *qdev, void *buf,
+               u32 ram_addr, int word_count);
+int ql_core_dump(struct ql_adapter *qdev,
+               struct ql_mpi_coredump *mpi_coredump);
+int ql_mb_sys_err(struct ql_adapter *qdev);
 int ql_mb_about_fw(struct ql_adapter *qdev);
 int ql_wol(struct ql_adapter *qdev);
 int ql_mb_wol_set_magic(struct ql_adapter *qdev, u32 enable_wol);
@@ -1833,6 +2248,7 @@ void ql_gen_reg_dump(struct ql_adapter *qdev,
                        struct ql_reg_dump *mpi_coredump);
 netdev_tx_t ql_lb_send(struct sk_buff *skb, struct net_device *ndev);
 void ql_check_lb_frame(struct ql_adapter *, struct sk_buff *);
+int ql_own_firmware(struct ql_adapter *qdev);
 int ql_clean_lb_rx_ring(struct rx_ring *rx_ring, int budget);
 
 #if 1
index 9f58c47107618762c5f0fe761cd5a593c967b408..57df835147eb16337d274fe574570dd1ea7d43c5 100644 (file)
@@ -1,5 +1,405 @@
 #include "qlge.h"
 
+/* Read a NIC register from the alternate function. */
+static u32 ql_read_other_func_reg(struct ql_adapter *qdev,
+                                               u32 reg)
+{
+       u32 register_to_read;
+       u32 reg_val;
+       unsigned int status = 0;
+
+       register_to_read = MPI_NIC_REG_BLOCK
+                               | MPI_NIC_READ
+                               | (qdev->alt_func << MPI_NIC_FUNCTION_SHIFT)
+                               | reg;
+       status = ql_read_mpi_reg(qdev, register_to_read, &reg_val);
+       if (status != 0)
+               return 0xffffffff;
+
+       return reg_val;
+}
+
+/* Write a NIC register from the alternate function. */
+static int ql_write_other_func_reg(struct ql_adapter *qdev,
+                                       u32 reg, u32 reg_val)
+{
+       u32 register_to_read;
+       int status = 0;
+
+       register_to_read = MPI_NIC_REG_BLOCK
+                               | MPI_NIC_READ
+                               | (qdev->alt_func << MPI_NIC_FUNCTION_SHIFT)
+                               | reg;
+       status = ql_write_mpi_reg(qdev, register_to_read, reg_val);
+
+       return status;
+}
+
+static int ql_wait_other_func_reg_rdy(struct ql_adapter *qdev, u32 reg,
+                                       u32 bit, u32 err_bit)
+{
+       u32 temp;
+       int count = 10;
+
+       while (count) {
+               temp = ql_read_other_func_reg(qdev, reg);
+
+               /* check for errors */
+               if (temp & err_bit)
+                       return -1;
+               else if (temp & bit)
+                       return 0;
+               mdelay(10);
+               count--;
+       }
+       return -1;
+}
+
+static int ql_read_other_func_serdes_reg(struct ql_adapter *qdev, u32 reg,
+                                                       u32 *data)
+{
+       int status;
+
+       /* wait for reg to come ready */
+       status = ql_wait_other_func_reg_rdy(qdev, XG_SERDES_ADDR / 4,
+                                               XG_SERDES_ADDR_RDY, 0);
+       if (status)
+               goto exit;
+
+       /* set up for reg read */
+       ql_write_other_func_reg(qdev, XG_SERDES_ADDR/4, reg | PROC_ADDR_R);
+
+       /* wait for reg to come ready */
+       status = ql_wait_other_func_reg_rdy(qdev, XG_SERDES_ADDR / 4,
+                                               XG_SERDES_ADDR_RDY, 0);
+       if (status)
+               goto exit;
+
+       /* get the data */
+       *data = ql_read_other_func_reg(qdev, (XG_SERDES_DATA / 4));
+exit:
+       return status;
+}
+
+/* Read out the SERDES registers */
+static int ql_read_serdes_reg(struct ql_adapter *qdev, u32 reg, u32 * data)
+{
+       int status;
+
+       /* wait for reg to come ready */
+       status = ql_wait_reg_rdy(qdev, XG_SERDES_ADDR, XG_SERDES_ADDR_RDY, 0);
+       if (status)
+               goto exit;
+
+       /* set up for reg read */
+       ql_write32(qdev, XG_SERDES_ADDR, reg | PROC_ADDR_R);
+
+       /* wait for reg to come ready */
+       status = ql_wait_reg_rdy(qdev, XG_SERDES_ADDR, XG_SERDES_ADDR_RDY, 0);
+       if (status)
+               goto exit;
+
+       /* get the data */
+       *data = ql_read32(qdev, XG_SERDES_DATA);
+exit:
+       return status;
+}
+
+static void ql_get_both_serdes(struct ql_adapter *qdev, u32 addr,
+                       u32 *direct_ptr, u32 *indirect_ptr,
+                       unsigned int direct_valid, unsigned int indirect_valid)
+{
+       unsigned int status;
+
+       status = 1;
+       if (direct_valid)
+               status = ql_read_serdes_reg(qdev, addr, direct_ptr);
+       /* Dead fill any failures or invalids. */
+       if (status)
+               *direct_ptr = 0xDEADBEEF;
+
+       status = 1;
+       if (indirect_valid)
+               status = ql_read_other_func_serdes_reg(
+                                               qdev, addr, indirect_ptr);
+       /* Dead fill any failures or invalids. */
+       if (status)
+               *indirect_ptr = 0xDEADBEEF;
+}
+
+static int ql_get_serdes_regs(struct ql_adapter *qdev,
+                               struct ql_mpi_coredump *mpi_coredump)
+{
+       int status;
+       unsigned int xfi_direct_valid, xfi_indirect_valid, xaui_direct_valid;
+       unsigned int xaui_indirect_valid, i;
+       u32 *direct_ptr, temp;
+       u32 *indirect_ptr;
+
+       xfi_direct_valid = xfi_indirect_valid = 0;
+       xaui_direct_valid = xaui_indirect_valid = 1;
+
+       /* The XAUI needs to be read out per port */
+       if (qdev->func & 1) {
+               /* We are NIC 2 */
+               status = ql_read_other_func_serdes_reg(qdev,
+                               XG_SERDES_XAUI_HSS_PCS_START, &temp);
+               if (status)
+                       temp = XG_SERDES_ADDR_XAUI_PWR_DOWN;
+               if ((temp & XG_SERDES_ADDR_XAUI_PWR_DOWN) ==
+                                       XG_SERDES_ADDR_XAUI_PWR_DOWN)
+                       xaui_indirect_valid = 0;
+
+               status = ql_read_serdes_reg(qdev,
+                               XG_SERDES_XAUI_HSS_PCS_START, &temp);
+               if (status)
+                       temp = XG_SERDES_ADDR_XAUI_PWR_DOWN;
+
+               if ((temp & XG_SERDES_ADDR_XAUI_PWR_DOWN) ==
+                                       XG_SERDES_ADDR_XAUI_PWR_DOWN)
+                       xaui_direct_valid = 0;
+       } else {
+               /* We are NIC 1 */
+               status = ql_read_other_func_serdes_reg(qdev,
+                               XG_SERDES_XAUI_HSS_PCS_START, &temp);
+               if (status)
+                       temp = XG_SERDES_ADDR_XAUI_PWR_DOWN;
+               if ((temp & XG_SERDES_ADDR_XAUI_PWR_DOWN) ==
+                                       XG_SERDES_ADDR_XAUI_PWR_DOWN)
+                       xaui_indirect_valid = 0;
+
+               status = ql_read_serdes_reg(qdev,
+                               XG_SERDES_XAUI_HSS_PCS_START, &temp);
+               if (status)
+                       temp = XG_SERDES_ADDR_XAUI_PWR_DOWN;
+               if ((temp & XG_SERDES_ADDR_XAUI_PWR_DOWN) ==
+                                       XG_SERDES_ADDR_XAUI_PWR_DOWN)
+                       xaui_direct_valid = 0;
+       }
+
+       /*
+        * XFI register is shared so only need to read one
+        * functions and then check the bits.
+        */
+       status = ql_read_serdes_reg(qdev, XG_SERDES_ADDR_STS, &temp);
+       if (status)
+               temp = 0;
+
+       if ((temp & XG_SERDES_ADDR_XFI1_PWR_UP) ==
+                                       XG_SERDES_ADDR_XFI1_PWR_UP) {
+               /* now see if i'm NIC 1 or NIC 2 */
+               if (qdev->func & 1)
+                       /* I'm NIC 2, so the indirect (NIC1) xfi is up. */
+                       xfi_indirect_valid = 1;
+               else
+                       xfi_direct_valid = 1;
+       }
+       if ((temp & XG_SERDES_ADDR_XFI2_PWR_UP) ==
+                                       XG_SERDES_ADDR_XFI2_PWR_UP) {
+               /* now see if i'm NIC 1 or NIC 2 */
+               if (qdev->func & 1)
+                       /* I'm NIC 2, so the indirect (NIC1) xfi is up. */
+                       xfi_direct_valid = 1;
+               else
+                       xfi_indirect_valid = 1;
+       }
+
+       /* Get XAUI_AN register block. */
+       if (qdev->func & 1) {
+               /* Function 2 is direct */
+               direct_ptr = mpi_coredump->serdes2_xaui_an;
+               indirect_ptr = mpi_coredump->serdes_xaui_an;
+       } else {
+               /* Function 1 is direct */
+               direct_ptr = mpi_coredump->serdes_xaui_an;
+               indirect_ptr = mpi_coredump->serdes2_xaui_an;
+       }
+
+       for (i = 0; i <= 0x000000034; i += 4, direct_ptr++, indirect_ptr++)
+               ql_get_both_serdes(qdev, i, direct_ptr, indirect_ptr,
+                                       xaui_direct_valid, xaui_indirect_valid);
+
+       /* Get XAUI_HSS_PCS register block. */
+       if (qdev->func & 1) {
+               direct_ptr =
+                       mpi_coredump->serdes2_xaui_hss_pcs;
+               indirect_ptr =
+                       mpi_coredump->serdes_xaui_hss_pcs;
+       } else {
+               direct_ptr =
+                       mpi_coredump->serdes_xaui_hss_pcs;
+               indirect_ptr =
+                       mpi_coredump->serdes2_xaui_hss_pcs;
+       }
+
+       for (i = 0x800; i <= 0x880; i += 4, direct_ptr++, indirect_ptr++)
+               ql_get_both_serdes(qdev, i, direct_ptr, indirect_ptr,
+                                       xaui_direct_valid, xaui_indirect_valid);
+
+       /* Get XAUI_XFI_AN register block. */
+       if (qdev->func & 1) {
+               direct_ptr = mpi_coredump->serdes2_xfi_an;
+               indirect_ptr = mpi_coredump->serdes_xfi_an;
+       } else {
+               direct_ptr = mpi_coredump->serdes_xfi_an;
+               indirect_ptr = mpi_coredump->serdes2_xfi_an;
+       }
+
+       for (i = 0x1000; i <= 0x1034; i += 4, direct_ptr++, indirect_ptr++)
+               ql_get_both_serdes(qdev, i, direct_ptr, indirect_ptr,
+                                       xfi_direct_valid, xfi_indirect_valid);
+
+       /* Get XAUI_XFI_TRAIN register block. */
+       if (qdev->func & 1) {
+               direct_ptr = mpi_coredump->serdes2_xfi_train;
+               indirect_ptr =
+                       mpi_coredump->serdes_xfi_train;
+       } else {
+               direct_ptr = mpi_coredump->serdes_xfi_train;
+               indirect_ptr =
+                       mpi_coredump->serdes2_xfi_train;
+       }
+
+       for (i = 0x1050; i <= 0x107c; i += 4, direct_ptr++, indirect_ptr++)
+               ql_get_both_serdes(qdev, i, direct_ptr, indirect_ptr,
+                                       xfi_direct_valid, xfi_indirect_valid);
+
+       /* Get XAUI_XFI_HSS_PCS register block. */
+       if (qdev->func & 1) {
+               direct_ptr =
+                       mpi_coredump->serdes2_xfi_hss_pcs;
+               indirect_ptr =
+                       mpi_coredump->serdes_xfi_hss_pcs;
+       } else {
+               direct_ptr =
+                       mpi_coredump->serdes_xfi_hss_pcs;
+               indirect_ptr =
+                       mpi_coredump->serdes2_xfi_hss_pcs;
+       }
+
+       for (i = 0x1800; i <= 0x1838; i += 4, direct_ptr++, indirect_ptr++)
+               ql_get_both_serdes(qdev, i, direct_ptr, indirect_ptr,
+                                       xfi_direct_valid, xfi_indirect_valid);
+
+       /* Get XAUI_XFI_HSS_TX register block. */
+       if (qdev->func & 1) {
+               direct_ptr =
+                       mpi_coredump->serdes2_xfi_hss_tx;
+               indirect_ptr =
+                       mpi_coredump->serdes_xfi_hss_tx;
+       } else {
+               direct_ptr = mpi_coredump->serdes_xfi_hss_tx;
+               indirect_ptr =
+                       mpi_coredump->serdes2_xfi_hss_tx;
+       }
+       for (i = 0x1c00; i <= 0x1c1f; i++, direct_ptr++, indirect_ptr++)
+               ql_get_both_serdes(qdev, i, direct_ptr, indirect_ptr,
+                                       xfi_direct_valid, xfi_indirect_valid);
+
+       /* Get XAUI_XFI_HSS_RX register block. */
+       if (qdev->func & 1) {
+               direct_ptr =
+                       mpi_coredump->serdes2_xfi_hss_rx;
+               indirect_ptr =
+                       mpi_coredump->serdes_xfi_hss_rx;
+       } else {
+               direct_ptr = mpi_coredump->serdes_xfi_hss_rx;
+               indirect_ptr =
+                       mpi_coredump->serdes2_xfi_hss_rx;
+       }
+
+       for (i = 0x1c40; i <= 0x1c5f; i++, direct_ptr++, indirect_ptr++)
+               ql_get_both_serdes(qdev, i, direct_ptr, indirect_ptr,
+                                       xfi_direct_valid, xfi_indirect_valid);
+
+
+       /* Get XAUI_XFI_HSS_PLL register block. */
+       if (qdev->func & 1) {
+               direct_ptr =
+                       mpi_coredump->serdes2_xfi_hss_pll;
+               indirect_ptr =
+                       mpi_coredump->serdes_xfi_hss_pll;
+       } else {
+               direct_ptr =
+                       mpi_coredump->serdes_xfi_hss_pll;
+               indirect_ptr =
+                       mpi_coredump->serdes2_xfi_hss_pll;
+       }
+       for (i = 0x1e00; i <= 0x1e1f; i++, direct_ptr++, indirect_ptr++)
+               ql_get_both_serdes(qdev, i, direct_ptr, indirect_ptr,
+                                       xfi_direct_valid, xfi_indirect_valid);
+       return 0;
+}
+
+static int ql_read_other_func_xgmac_reg(struct ql_adapter *qdev, u32 reg,
+                                                       u32 *data)
+{
+       int status = 0;
+
+       /* wait for reg to come ready */
+       status = ql_wait_other_func_reg_rdy(qdev, XGMAC_ADDR / 4,
+                                               XGMAC_ADDR_RDY, XGMAC_ADDR_XME);
+       if (status)
+               goto exit;
+
+       /* set up for reg read */
+       ql_write_other_func_reg(qdev, XGMAC_ADDR / 4, reg | XGMAC_ADDR_R);
+
+       /* wait for reg to come ready */
+       status = ql_wait_other_func_reg_rdy(qdev, XGMAC_ADDR / 4,
+                                               XGMAC_ADDR_RDY, XGMAC_ADDR_XME);
+       if (status)
+               goto exit;
+
+       /* get the data */
+       *data = ql_read_other_func_reg(qdev, XGMAC_DATA / 4);
+exit:
+       return status;
+}
+
+/* Read the 400 xgmac control/statistics registers
+ * skipping unused locations.
+ */
+static int ql_get_xgmac_regs(struct ql_adapter *qdev, u32 * buf,
+                                       unsigned int other_function)
+{
+       int status = 0;
+       int i;
+
+       for (i = PAUSE_SRC_LO; i < XGMAC_REGISTER_END; i += 4, buf++) {
+               /* We're reading 400 xgmac registers, but we filter out
+                * serveral locations that are non-responsive to reads.
+                */
+               if ((i == 0x00000114) ||
+                       (i == 0x00000118) ||
+                       (i == 0x0000013c) ||
+                       (i == 0x00000140) ||
+                       (i > 0x00000150 && i < 0x000001fc) ||
+                       (i > 0x00000278 && i < 0x000002a0) ||
+                       (i > 0x000002c0 && i < 0x000002cf) ||
+                       (i > 0x000002dc && i < 0x000002f0) ||
+                       (i > 0x000003c8 && i < 0x00000400) ||
+                       (i > 0x00000400 && i < 0x00000410) ||
+                       (i > 0x00000410 && i < 0x00000420) ||
+                       (i > 0x00000420 && i < 0x00000430) ||
+                       (i > 0x00000430 && i < 0x00000440) ||
+                       (i > 0x00000440 && i < 0x00000450) ||
+                       (i > 0x00000450 && i < 0x00000500) ||
+                       (i > 0x0000054c && i < 0x00000568) ||
+                       (i > 0x000005c8 && i < 0x00000600)) {
+                       if (other_function)
+                               status =
+                               ql_read_other_func_xgmac_reg(qdev, i, buf);
+                       else
+                               status = ql_read_xgmac_reg(qdev, i, buf);
+
+                       if (status)
+                               *buf = 0xdeadbeef;
+                       break;
+               }
+       }
+       return status;
+}
 
 static int ql_get_ets_regs(struct ql_adapter *qdev, u32 * buf)
 {
@@ -91,6 +491,226 @@ err:
        return status;
 }
 
+/* Read the MPI Processor shadow registers */
+static int ql_get_mpi_shadow_regs(struct ql_adapter *qdev, u32 * buf)
+{
+       u32 i;
+       int status;
+
+       for (i = 0; i < MPI_CORE_SH_REGS_CNT; i++, buf++) {
+               status = ql_write_mpi_reg(qdev, RISC_124,
+                               (SHADOW_OFFSET | i << SHADOW_REG_SHIFT));
+               if (status)
+                       goto end;
+               status = ql_read_mpi_reg(qdev, RISC_127, buf);
+               if (status)
+                       goto end;
+       }
+end:
+       return status;
+}
+
+/* Read the MPI Processor core registers */
+static int ql_get_mpi_regs(struct ql_adapter *qdev, u32 * buf,
+                               u32 offset, u32 count)
+{
+       int i, status = 0;
+       for (i = 0; i < count; i++, buf++) {
+               status = ql_read_mpi_reg(qdev, offset + i, buf);
+               if (status)
+                       return status;
+       }
+       return status;
+}
+
+/* Read the ASIC probe dump */
+static unsigned int *ql_get_probe(struct ql_adapter *qdev, u32 clock,
+                                       u32 valid, u32 *buf)
+{
+       u32 module, mux_sel, probe, lo_val, hi_val;
+
+       for (module = 0; module < PRB_MX_ADDR_MAX_MODS; module++) {
+               if (!((valid >> module) & 1))
+                       continue;
+               for (mux_sel = 0; mux_sel < PRB_MX_ADDR_MAX_MUX; mux_sel++) {
+                       probe = clock
+                               | PRB_MX_ADDR_ARE
+                               | mux_sel
+                               | (module << PRB_MX_ADDR_MOD_SEL_SHIFT);
+                       ql_write32(qdev, PRB_MX_ADDR, probe);
+                       lo_val = ql_read32(qdev, PRB_MX_DATA);
+                       if (mux_sel == 0) {
+                               *buf = probe;
+                               buf++;
+                       }
+                       probe |= PRB_MX_ADDR_UP;
+                       ql_write32(qdev, PRB_MX_ADDR, probe);
+                       hi_val = ql_read32(qdev, PRB_MX_DATA);
+                       *buf = lo_val;
+                       buf++;
+                       *buf = hi_val;
+                       buf++;
+               }
+       }
+       return buf;
+}
+
+static int ql_get_probe_dump(struct ql_adapter *qdev, unsigned int *buf)
+{
+       /* First we have to enable the probe mux */
+       ql_write_mpi_reg(qdev, MPI_TEST_FUNC_PRB_CTL, MPI_TEST_FUNC_PRB_EN);
+       buf = ql_get_probe(qdev, PRB_MX_ADDR_SYS_CLOCK,
+                       PRB_MX_ADDR_VALID_SYS_MOD, buf);
+       buf = ql_get_probe(qdev, PRB_MX_ADDR_PCI_CLOCK,
+                       PRB_MX_ADDR_VALID_PCI_MOD, buf);
+       buf = ql_get_probe(qdev, PRB_MX_ADDR_XGM_CLOCK,
+                       PRB_MX_ADDR_VALID_XGM_MOD, buf);
+       buf = ql_get_probe(qdev, PRB_MX_ADDR_FC_CLOCK,
+                       PRB_MX_ADDR_VALID_FC_MOD, buf);
+       return 0;
+
+}
+
+/* Read out the routing index registers */
+static int ql_get_routing_index_registers(struct ql_adapter *qdev, u32 *buf)
+{
+       int status;
+       u32 type, index, index_max;
+       u32 result_index;
+       u32 result_data;
+       u32 val;
+
+       status = ql_sem_spinlock(qdev, SEM_RT_IDX_MASK);
+       if (status)
+               return status;
+
+       for (type = 0; type < 4; type++) {
+               if (type < 2)
+                       index_max = 8;
+               else
+                       index_max = 16;
+               for (index = 0; index < index_max; index++) {
+                       val = RT_IDX_RS
+                               | (type << RT_IDX_TYPE_SHIFT)
+                               | (index << RT_IDX_IDX_SHIFT);
+                       ql_write32(qdev, RT_IDX, val);
+                       result_index = 0;
+                       while ((result_index & RT_IDX_MR) == 0)
+                               result_index = ql_read32(qdev, RT_IDX);
+                       result_data = ql_read32(qdev, RT_DATA);
+                       *buf = type;
+                       buf++;
+                       *buf = index;
+                       buf++;
+                       *buf = result_index;
+                       buf++;
+                       *buf = result_data;
+                       buf++;
+               }
+       }
+       ql_sem_unlock(qdev, SEM_RT_IDX_MASK);
+       return status;
+}
+
+/* Read out the MAC protocol registers */
+static void ql_get_mac_protocol_registers(struct ql_adapter *qdev, u32 *buf)
+{
+       u32 result_index, result_data;
+       u32 type;
+       u32 index;
+       u32 offset;
+       u32 val;
+       u32 initial_val = MAC_ADDR_RS;
+       u32 max_index;
+       u32 max_offset;
+
+       for (type = 0; type < MAC_ADDR_TYPE_COUNT; type++) {
+               switch (type) {
+
+               case 0: /* CAM */
+                       initial_val |= MAC_ADDR_ADR;
+                       max_index = MAC_ADDR_MAX_CAM_ENTRIES;
+                       max_offset = MAC_ADDR_MAX_CAM_WCOUNT;
+                       break;
+               case 1: /* Multicast MAC Address */
+                       max_index = MAC_ADDR_MAX_CAM_WCOUNT;
+                       max_offset = MAC_ADDR_MAX_CAM_WCOUNT;
+                       break;
+               case 2: /* VLAN filter mask */
+               case 3: /* MC filter mask */
+                       max_index = MAC_ADDR_MAX_CAM_WCOUNT;
+                       max_offset = MAC_ADDR_MAX_CAM_WCOUNT;
+                       break;
+               case 4: /* FC MAC addresses */
+                       max_index = MAC_ADDR_MAX_FC_MAC_ENTRIES;
+                       max_offset = MAC_ADDR_MAX_FC_MAC_WCOUNT;
+                       break;
+               case 5: /* Mgmt MAC addresses */
+                       max_index = MAC_ADDR_MAX_MGMT_MAC_ENTRIES;
+                       max_offset = MAC_ADDR_MAX_MGMT_MAC_WCOUNT;
+                       break;
+               case 6: /* Mgmt VLAN addresses */
+                       max_index = MAC_ADDR_MAX_MGMT_VLAN_ENTRIES;
+                       max_offset = MAC_ADDR_MAX_MGMT_VLAN_WCOUNT;
+                       break;
+               case 7: /* Mgmt IPv4 address */
+                       max_index = MAC_ADDR_MAX_MGMT_V4_ENTRIES;
+                       max_offset = MAC_ADDR_MAX_MGMT_V4_WCOUNT;
+                       break;
+               case 8: /* Mgmt IPv6 address */
+                       max_index = MAC_ADDR_MAX_MGMT_V6_ENTRIES;
+                       max_offset = MAC_ADDR_MAX_MGMT_V6_WCOUNT;
+                       break;
+               case 9: /* Mgmt TCP/UDP Dest port */
+                       max_index = MAC_ADDR_MAX_MGMT_TU_DP_ENTRIES;
+                       max_offset = MAC_ADDR_MAX_MGMT_TU_DP_WCOUNT;
+                       break;
+               default:
+                       printk(KERN_ERR"Bad type!!! 0x%08x\n", type);
+                       max_index = 0;
+                       max_offset = 0;
+                       break;
+               }
+               for (index = 0; index < max_index; index++) {
+                       for (offset = 0; offset < max_offset; offset++) {
+                               val = initial_val
+                                       | (type << MAC_ADDR_TYPE_SHIFT)
+                                       | (index << MAC_ADDR_IDX_SHIFT)
+                                       | (offset);
+                               ql_write32(qdev, MAC_ADDR_IDX, val);
+                               result_index = 0;
+                               while ((result_index & MAC_ADDR_MR) == 0) {
+                                       result_index = ql_read32(qdev,
+                                                               MAC_ADDR_IDX);
+                               }
+                               result_data = ql_read32(qdev, MAC_ADDR_DATA);
+                               *buf = result_index;
+                               buf++;
+                               *buf = result_data;
+                               buf++;
+                       }
+               }
+       }
+}
+
+static void ql_get_sem_registers(struct ql_adapter *qdev, u32 *buf)
+{
+       u32 func_num, reg, reg_val;
+       int status;
+
+       for (func_num = 0; func_num < MAX_SEMAPHORE_FUNCTIONS ; func_num++) {
+               reg = MPI_NIC_REG_BLOCK
+                       | (func_num << MPI_NIC_FUNCTION_SHIFT)
+                       | (SEM / 4);
+               status = ql_read_mpi_reg(qdev, reg, &reg_val);
+               *buf = reg_val;
+               /* if the read failed then dead fill the element. */
+               if (!status)
+                       *buf = 0xdeadbeef;
+               buf++;
+       }
+}
+
 /* Create a coredump segment header */
 static void ql_build_coredump_seg_header(
                struct mpi_coredump_segment_header *seg_hdr,
@@ -103,6 +723,527 @@ static void ql_build_coredump_seg_header(
        memcpy(seg_hdr->description, desc, (sizeof(seg_hdr->description)) - 1);
 }
 
+/*
+ * This function should be called when a coredump / probedump
+ * is to be extracted from the HBA. It is assumed there is a
+ * qdev structure that contains the base address of the register
+ * space for this function as well as a coredump structure that
+ * will contain the dump.
+ */
+int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump)
+{
+       int status;
+       int i;
+
+       if (!mpi_coredump) {
+               QPRINTK(qdev, DRV, ERR,
+                       "No memory available.\n");
+               return -ENOMEM;
+       }
+
+       /* Try to get the spinlock, but dont worry if
+        * it isn't available.  If the firmware died it
+        * might be holding the sem.
+        */
+       ql_sem_spinlock(qdev, SEM_PROC_REG_MASK);
+
+       status = ql_pause_mpi_risc(qdev);
+       if (status) {
+               QPRINTK(qdev, DRV, ERR,
+                       "Failed RISC pause. Status = 0x%.08x\n", status);
+               goto err;
+       }
+
+       /* Insert the global header */
+       memset(&(mpi_coredump->mpi_global_header), 0,
+               sizeof(struct mpi_coredump_global_header));
+       mpi_coredump->mpi_global_header.cookie = MPI_COREDUMP_COOKIE;
+       mpi_coredump->mpi_global_header.headerSize =
+               sizeof(struct mpi_coredump_global_header);
+       mpi_coredump->mpi_global_header.imageSize =
+               sizeof(struct ql_mpi_coredump);
+       memcpy(mpi_coredump->mpi_global_header.idString, "MPI Coredump",
+               sizeof(mpi_coredump->mpi_global_header.idString));
+
+       /* Get generic NIC reg dump */
+       ql_build_coredump_seg_header(&mpi_coredump->nic_regs_seg_hdr,
+                       NIC1_CONTROL_SEG_NUM,
+                       sizeof(struct mpi_coredump_segment_header) +
+                       sizeof(mpi_coredump->nic_regs), "NIC1 Registers");
+
+       ql_build_coredump_seg_header(&mpi_coredump->nic2_regs_seg_hdr,
+                       NIC2_CONTROL_SEG_NUM,
+                       sizeof(struct mpi_coredump_segment_header) +
+                       sizeof(mpi_coredump->nic2_regs), "NIC2 Registers");
+
+       /* Get XGMac registers. (Segment 18, Rev C. step 21) */
+       ql_build_coredump_seg_header(&mpi_coredump->xgmac1_seg_hdr,
+                       NIC1_XGMAC_SEG_NUM,
+                       sizeof(struct mpi_coredump_segment_header) +
+                       sizeof(mpi_coredump->xgmac1), "NIC1 XGMac Registers");
+
+       ql_build_coredump_seg_header(&mpi_coredump->xgmac2_seg_hdr,
+                       NIC2_XGMAC_SEG_NUM,
+                       sizeof(struct mpi_coredump_segment_header) +
+                       sizeof(mpi_coredump->xgmac2), "NIC2 XGMac Registers");
+
+       if (qdev->func & 1) {
+               /* Odd means our function is NIC 2 */
+               for (i = 0; i < NIC_REGS_DUMP_WORD_COUNT; i++)
+                       mpi_coredump->nic2_regs[i] =
+                                        ql_read32(qdev, i * sizeof(u32));
+
+               for (i = 0; i < NIC_REGS_DUMP_WORD_COUNT; i++)
+                       mpi_coredump->nic_regs[i] =
+                       ql_read_other_func_reg(qdev, (i * sizeof(u32)) / 4);
+
+               ql_get_xgmac_regs(qdev, &mpi_coredump->xgmac2[0], 0);
+               ql_get_xgmac_regs(qdev, &mpi_coredump->xgmac1[0], 1);
+       } else {
+               /* Even means our function is NIC 1 */
+               for (i = 0; i < NIC_REGS_DUMP_WORD_COUNT; i++)
+                       mpi_coredump->nic_regs[i] =
+                                       ql_read32(qdev, i * sizeof(u32));
+               for (i = 0; i < NIC_REGS_DUMP_WORD_COUNT; i++)
+                       mpi_coredump->nic2_regs[i] =
+                       ql_read_other_func_reg(qdev, (i * sizeof(u32)) / 4);
+
+               ql_get_xgmac_regs(qdev, &mpi_coredump->xgmac1[0], 0);
+               ql_get_xgmac_regs(qdev, &mpi_coredump->xgmac2[0], 1);
+       }
+
+       /* Rev C. Step 20a */
+       ql_build_coredump_seg_header(&mpi_coredump->xaui_an_hdr,
+                       XAUI_AN_SEG_NUM,
+                       sizeof(struct mpi_coredump_segment_header) +
+                       sizeof(mpi_coredump->serdes_xaui_an),
+                       "XAUI AN Registers");
+
+       /* Rev C. Step 20b */
+       ql_build_coredump_seg_header(&mpi_coredump->xaui_hss_pcs_hdr,
+                       XAUI_HSS_PCS_SEG_NUM,
+                       sizeof(struct mpi_coredump_segment_header) +
+                       sizeof(mpi_coredump->serdes_xaui_hss_pcs),
+                       "XAUI HSS PCS Registers");
+
+       ql_build_coredump_seg_header(&mpi_coredump->xfi_an_hdr, XFI_AN_SEG_NUM,
+                       sizeof(struct mpi_coredump_segment_header) +
+                       sizeof(mpi_coredump->serdes_xfi_an),
+                       "XFI AN Registers");
+
+       ql_build_coredump_seg_header(&mpi_coredump->xfi_train_hdr,
+                       XFI_TRAIN_SEG_NUM,
+                       sizeof(struct mpi_coredump_segment_header) +
+                       sizeof(mpi_coredump->serdes_xfi_train),
+                       "XFI TRAIN Registers");
+
+       ql_build_coredump_seg_header(&mpi_coredump->xfi_hss_pcs_hdr,
+                       XFI_HSS_PCS_SEG_NUM,
+                       sizeof(struct mpi_coredump_segment_header) +
+                       sizeof(mpi_coredump->serdes_xfi_hss_pcs),
+                       "XFI HSS PCS Registers");
+
+       ql_build_coredump_seg_header(&mpi_coredump->xfi_hss_tx_hdr,
+                       XFI_HSS_TX_SEG_NUM,
+                       sizeof(struct mpi_coredump_segment_header) +
+                       sizeof(mpi_coredump->serdes_xfi_hss_tx),
+                       "XFI HSS TX Registers");
+
+       ql_build_coredump_seg_header(&mpi_coredump->xfi_hss_rx_hdr,
+                       XFI_HSS_RX_SEG_NUM,
+                       sizeof(struct mpi_coredump_segment_header) +
+                       sizeof(mpi_coredump->serdes_xfi_hss_rx),
+                       "XFI HSS RX Registers");
+
+       ql_build_coredump_seg_header(&mpi_coredump->xfi_hss_pll_hdr,
+                       XFI_HSS_PLL_SEG_NUM,
+                       sizeof(struct mpi_coredump_segment_header) +
+                       sizeof(mpi_coredump->serdes_xfi_hss_pll),
+                       "XFI HSS PLL Registers");
+
+       ql_build_coredump_seg_header(&mpi_coredump->xaui2_an_hdr,
+                       XAUI2_AN_SEG_NUM,
+                       sizeof(struct mpi_coredump_segment_header) +
+                       sizeof(mpi_coredump->serdes2_xaui_an),
+                       "XAUI2 AN Registers");
+
+       ql_build_coredump_seg_header(&mpi_coredump->xaui2_hss_pcs_hdr,
+                       XAUI2_HSS_PCS_SEG_NUM,
+                       sizeof(struct mpi_coredump_segment_header) +
+                       sizeof(mpi_coredump->serdes2_xaui_hss_pcs),
+                       "XAUI2 HSS PCS Registers");
+
+       ql_build_coredump_seg_header(&mpi_coredump->xfi2_an_hdr,
+                       XFI2_AN_SEG_NUM,
+                       sizeof(struct mpi_coredump_segment_header) +
+                       sizeof(mpi_coredump->serdes2_xfi_an),
+                       "XFI2 AN Registers");
+
+       ql_build_coredump_seg_header(&mpi_coredump->xfi2_train_hdr,
+                       XFI2_TRAIN_SEG_NUM,
+                       sizeof(struct mpi_coredump_segment_header) +
+                       sizeof(mpi_coredump->serdes2_xfi_train),
+                       "XFI2 TRAIN Registers");
+
+       ql_build_coredump_seg_header(&mpi_coredump->xfi2_hss_pcs_hdr,
+                       XFI2_HSS_PCS_SEG_NUM,
+                       sizeof(struct mpi_coredump_segment_header) +
+                       sizeof(mpi_coredump->serdes2_xfi_hss_pcs),
+                       "XFI2 HSS PCS Registers");
+
+       ql_build_coredump_seg_header(&mpi_coredump->xfi2_hss_tx_hdr,
+                       XFI2_HSS_TX_SEG_NUM,
+                       sizeof(struct mpi_coredump_segment_header) +
+                       sizeof(mpi_coredump->serdes2_xfi_hss_tx),
+                       "XFI2 HSS TX Registers");
+
+       ql_build_coredump_seg_header(&mpi_coredump->xfi2_hss_rx_hdr,
+                       XFI2_HSS_RX_SEG_NUM,
+                       sizeof(struct mpi_coredump_segment_header) +
+                       sizeof(mpi_coredump->serdes2_xfi_hss_rx),
+                       "XFI2 HSS RX Registers");
+
+       ql_build_coredump_seg_header(&mpi_coredump->xfi2_hss_pll_hdr,
+                       XFI2_HSS_PLL_SEG_NUM,
+                       sizeof(struct mpi_coredump_segment_header) +
+                       sizeof(mpi_coredump->serdes2_xfi_hss_pll),
+                       "XFI2 HSS PLL Registers");
+
+       status = ql_get_serdes_regs(qdev, mpi_coredump);
+       if (status) {
+               QPRINTK(qdev, DRV, ERR,
+                       "Failed Dump of Serdes Registers. Status = 0x%.08x\n",
+                       status);
+               goto err;
+       }
+
+       ql_build_coredump_seg_header(&mpi_coredump->core_regs_seg_hdr,
+                               CORE_SEG_NUM,
+                               sizeof(mpi_coredump->core_regs_seg_hdr) +
+                               sizeof(mpi_coredump->mpi_core_regs) +
+                               sizeof(mpi_coredump->mpi_core_sh_regs),
+                               "Core Registers");
+
+       /* Get the MPI Core Registers */
+       status = ql_get_mpi_regs(qdev, &mpi_coredump->mpi_core_regs[0],
+                                MPI_CORE_REGS_ADDR, MPI_CORE_REGS_CNT);
+       if (status)
+               goto err;
+       /* Get the 16 MPI shadow registers */
+       status = ql_get_mpi_shadow_regs(qdev,
+                                       &mpi_coredump->mpi_core_sh_regs[0]);
+       if (status)
+               goto err;
+
+       /* Get the Test Logic Registers */
+       ql_build_coredump_seg_header(&mpi_coredump->test_logic_regs_seg_hdr,
+                               TEST_LOGIC_SEG_NUM,
+                               sizeof(struct mpi_coredump_segment_header)
+                               + sizeof(mpi_coredump->test_logic_regs),
+                               "Test Logic Regs");
+       status = ql_get_mpi_regs(qdev, &mpi_coredump->test_logic_regs[0],
+                                TEST_REGS_ADDR, TEST_REGS_CNT);
+       if (status)
+               goto err;
+
+       /* Get the RMII Registers */
+       ql_build_coredump_seg_header(&mpi_coredump->rmii_regs_seg_hdr,
+                               RMII_SEG_NUM,
+                               sizeof(struct mpi_coredump_segment_header)
+                               + sizeof(mpi_coredump->rmii_regs),
+                               "RMII Registers");
+       status = ql_get_mpi_regs(qdev, &mpi_coredump->rmii_regs[0],
+                                RMII_REGS_ADDR, RMII_REGS_CNT);
+       if (status)
+               goto err;
+
+       /* Get the FCMAC1 Registers */
+       ql_build_coredump_seg_header(&mpi_coredump->fcmac1_regs_seg_hdr,
+                               FCMAC1_SEG_NUM,
+                               sizeof(struct mpi_coredump_segment_header)
+                               + sizeof(mpi_coredump->fcmac1_regs),
+                               "FCMAC1 Registers");
+       status = ql_get_mpi_regs(qdev, &mpi_coredump->fcmac1_regs[0],
+                                FCMAC1_REGS_ADDR, FCMAC_REGS_CNT);
+       if (status)
+               goto err;
+
+       /* Get the FCMAC2 Registers */
+
+       ql_build_coredump_seg_header(&mpi_coredump->fcmac2_regs_seg_hdr,
+                               FCMAC2_SEG_NUM,
+                               sizeof(struct mpi_coredump_segment_header)
+                               + sizeof(mpi_coredump->fcmac2_regs),
+                               "FCMAC2 Registers");
+
+       status = ql_get_mpi_regs(qdev, &mpi_coredump->fcmac2_regs[0],
+                                FCMAC2_REGS_ADDR, FCMAC_REGS_CNT);
+       if (status)
+               goto err;
+
+       /* Get the FC1 MBX Registers */
+       ql_build_coredump_seg_header(&mpi_coredump->fc1_mbx_regs_seg_hdr,
+                               FC1_MBOX_SEG_NUM,
+                               sizeof(struct mpi_coredump_segment_header)
+                               + sizeof(mpi_coredump->fc1_mbx_regs),
+                               "FC1 MBox Regs");
+       status = ql_get_mpi_regs(qdev, &mpi_coredump->fc1_mbx_regs[0],
+                                FC1_MBX_REGS_ADDR, FC_MBX_REGS_CNT);
+       if (status)
+               goto err;
+
+       /* Get the IDE Registers */
+       ql_build_coredump_seg_header(&mpi_coredump->ide_regs_seg_hdr,
+                               IDE_SEG_NUM,
+                               sizeof(struct mpi_coredump_segment_header)
+                               + sizeof(mpi_coredump->ide_regs),
+                               "IDE Registers");
+       status = ql_get_mpi_regs(qdev, &mpi_coredump->ide_regs[0],
+                                IDE_REGS_ADDR, IDE_REGS_CNT);
+       if (status)
+               goto err;
+
+       /* Get the NIC1 MBX Registers */
+       ql_build_coredump_seg_header(&mpi_coredump->nic1_mbx_regs_seg_hdr,
+                               NIC1_MBOX_SEG_NUM,
+                               sizeof(struct mpi_coredump_segment_header)
+                               + sizeof(mpi_coredump->nic1_mbx_regs),
+                               "NIC1 MBox Regs");
+       status = ql_get_mpi_regs(qdev, &mpi_coredump->nic1_mbx_regs[0],
+                                NIC1_MBX_REGS_ADDR, NIC_MBX_REGS_CNT);
+       if (status)
+               goto err;
+
+       /* Get the SMBus Registers */
+       ql_build_coredump_seg_header(&mpi_coredump->smbus_regs_seg_hdr,
+                               SMBUS_SEG_NUM,
+                               sizeof(struct mpi_coredump_segment_header)
+                               + sizeof(mpi_coredump->smbus_regs),
+                               "SMBus Registers");
+       status = ql_get_mpi_regs(qdev, &mpi_coredump->smbus_regs[0],
+                                SMBUS_REGS_ADDR, SMBUS_REGS_CNT);
+       if (status)
+               goto err;
+
+       /* Get the FC2 MBX Registers */
+       ql_build_coredump_seg_header(&mpi_coredump->fc2_mbx_regs_seg_hdr,
+                               FC2_MBOX_SEG_NUM,
+                               sizeof(struct mpi_coredump_segment_header)
+                               + sizeof(mpi_coredump->fc2_mbx_regs),
+                               "FC2 MBox Regs");
+       status = ql_get_mpi_regs(qdev, &mpi_coredump->fc2_mbx_regs[0],
+                                FC2_MBX_REGS_ADDR, FC_MBX_REGS_CNT);
+       if (status)
+               goto err;
+
+       /* Get the NIC2 MBX Registers */
+       ql_build_coredump_seg_header(&mpi_coredump->nic2_mbx_regs_seg_hdr,
+                               NIC2_MBOX_SEG_NUM,
+                               sizeof(struct mpi_coredump_segment_header)
+                               + sizeof(mpi_coredump->nic2_mbx_regs),
+                               "NIC2 MBox Regs");
+       status = ql_get_mpi_regs(qdev, &mpi_coredump->nic2_mbx_regs[0],
+                                NIC2_MBX_REGS_ADDR, NIC_MBX_REGS_CNT);
+       if (status)
+               goto err;
+
+       /* Get the I2C Registers */
+       ql_build_coredump_seg_header(&mpi_coredump->i2c_regs_seg_hdr,
+                               I2C_SEG_NUM,
+                               sizeof(struct mpi_coredump_segment_header)
+                               + sizeof(mpi_coredump->i2c_regs),
+                               "I2C Registers");
+       status = ql_get_mpi_regs(qdev, &mpi_coredump->i2c_regs[0],
+                                I2C_REGS_ADDR, I2C_REGS_CNT);
+       if (status)
+               goto err;
+
+       /* Get the MEMC Registers */
+       ql_build_coredump_seg_header(&mpi_coredump->memc_regs_seg_hdr,
+                               MEMC_SEG_NUM,
+                               sizeof(struct mpi_coredump_segment_header)
+                               + sizeof(mpi_coredump->memc_regs),
+                               "MEMC Registers");
+       status = ql_get_mpi_regs(qdev, &mpi_coredump->memc_regs[0],
+                                MEMC_REGS_ADDR, MEMC_REGS_CNT);
+       if (status)
+               goto err;
+
+       /* Get the PBus Registers */
+       ql_build_coredump_seg_header(&mpi_coredump->pbus_regs_seg_hdr,
+                               PBUS_SEG_NUM,
+                               sizeof(struct mpi_coredump_segment_header)
+                               + sizeof(mpi_coredump->pbus_regs),
+                               "PBUS Registers");
+       status = ql_get_mpi_regs(qdev, &mpi_coredump->pbus_regs[0],
+                                PBUS_REGS_ADDR, PBUS_REGS_CNT);
+       if (status)
+               goto err;
+
+       /* Get the MDE Registers */
+       ql_build_coredump_seg_header(&mpi_coredump->mde_regs_seg_hdr,
+                               MDE_SEG_NUM,
+                               sizeof(struct mpi_coredump_segment_header)
+                               + sizeof(mpi_coredump->mde_regs),
+                               "MDE Registers");
+       status = ql_get_mpi_regs(qdev, &mpi_coredump->mde_regs[0],
+                                MDE_REGS_ADDR, MDE_REGS_CNT);
+       if (status)
+               goto err;
+
+       ql_build_coredump_seg_header(&mpi_coredump->misc_nic_seg_hdr,
+                               MISC_NIC_INFO_SEG_NUM,
+                               sizeof(struct mpi_coredump_segment_header)
+                               + sizeof(mpi_coredump->misc_nic_info),
+                               "MISC NIC INFO");
+       mpi_coredump->misc_nic_info.rx_ring_count = qdev->rx_ring_count;
+       mpi_coredump->misc_nic_info.tx_ring_count = qdev->tx_ring_count;
+       mpi_coredump->misc_nic_info.intr_count = qdev->intr_count;
+       mpi_coredump->misc_nic_info.function = qdev->func;
+
+       /* Segment 31 */
+       /* Get indexed register values. */
+       ql_build_coredump_seg_header(&mpi_coredump->intr_states_seg_hdr,
+                               INTR_STATES_SEG_NUM,
+                               sizeof(struct mpi_coredump_segment_header)
+                               + sizeof(mpi_coredump->intr_states),
+                               "INTR States");
+       ql_get_intr_states(qdev, &mpi_coredump->intr_states[0]);
+
+       ql_build_coredump_seg_header(&mpi_coredump->cam_entries_seg_hdr,
+                               CAM_ENTRIES_SEG_NUM,
+                               sizeof(struct mpi_coredump_segment_header)
+                               + sizeof(mpi_coredump->cam_entries),
+                               "CAM Entries");
+       status = ql_get_cam_entries(qdev, &mpi_coredump->cam_entries[0]);
+       if (status)
+               goto err;
+
+       ql_build_coredump_seg_header(&mpi_coredump->nic_routing_words_seg_hdr,
+                               ROUTING_WORDS_SEG_NUM,
+                               sizeof(struct mpi_coredump_segment_header)
+                               + sizeof(mpi_coredump->nic_routing_words),
+                               "Routing Words");
+       status = ql_get_routing_entries(qdev,
+                        &mpi_coredump->nic_routing_words[0]);
+       if (status)
+               goto err;
+
+       /* Segment 34 (Rev C. step 23) */
+       ql_build_coredump_seg_header(&mpi_coredump->ets_seg_hdr,
+                               ETS_SEG_NUM,
+                               sizeof(struct mpi_coredump_segment_header)
+                               + sizeof(mpi_coredump->ets),
+                               "ETS Registers");
+       status = ql_get_ets_regs(qdev, &mpi_coredump->ets[0]);
+       if (status)
+               goto err;
+
+       ql_build_coredump_seg_header(&mpi_coredump->probe_dump_seg_hdr,
+                               PROBE_DUMP_SEG_NUM,
+                               sizeof(struct mpi_coredump_segment_header)
+                               + sizeof(mpi_coredump->probe_dump),
+                               "Probe Dump");
+       ql_get_probe_dump(qdev, &mpi_coredump->probe_dump[0]);
+
+       ql_build_coredump_seg_header(&mpi_coredump->routing_reg_seg_hdr,
+                               ROUTING_INDEX_SEG_NUM,
+                               sizeof(struct mpi_coredump_segment_header)
+                               + sizeof(mpi_coredump->routing_regs),
+                               "Routing Regs");
+       status = ql_get_routing_index_registers(qdev,
+                                       &mpi_coredump->routing_regs[0]);
+       if (status)
+               goto err;
+
+       ql_build_coredump_seg_header(&mpi_coredump->mac_prot_reg_seg_hdr,
+                               MAC_PROTOCOL_SEG_NUM,
+                               sizeof(struct mpi_coredump_segment_header)
+                               + sizeof(mpi_coredump->mac_prot_regs),
+                               "MAC Prot Regs");
+       ql_get_mac_protocol_registers(qdev, &mpi_coredump->mac_prot_regs[0]);
+
+       /* Get the semaphore registers for all 5 functions */
+       ql_build_coredump_seg_header(&mpi_coredump->sem_regs_seg_hdr,
+                       SEM_REGS_SEG_NUM,
+                       sizeof(struct mpi_coredump_segment_header) +
+                       sizeof(mpi_coredump->sem_regs), "Sem Registers");
+
+       ql_get_sem_registers(qdev, &mpi_coredump->sem_regs[0]);
+
+       /* Prevent the mpi restarting while we dump the memory.*/
+       ql_write_mpi_reg(qdev, MPI_TEST_FUNC_RST_STS, MPI_TEST_FUNC_RST_FRC);
+
+       /* clear the pause */
+       status = ql_unpause_mpi_risc(qdev);
+       if (status) {
+               QPRINTK(qdev, DRV, ERR,
+                       "Failed RISC unpause. Status = 0x%.08x\n", status);
+               goto err;
+       }
+
+       /* Reset the RISC so we can dump RAM */
+       status = ql_hard_reset_mpi_risc(qdev);
+       if (status) {
+               QPRINTK(qdev, DRV, ERR,
+                       "Failed RISC reset. Status = 0x%.08x\n", status);
+               goto err;
+       }
+
+       ql_build_coredump_seg_header(&mpi_coredump->code_ram_seg_hdr,
+                               WCS_RAM_SEG_NUM,
+                               sizeof(struct mpi_coredump_segment_header)
+                               + sizeof(mpi_coredump->code_ram),
+                               "WCS RAM");
+       status = ql_dump_risc_ram_area(qdev, &mpi_coredump->code_ram[0],
+                                       CODE_RAM_ADDR, CODE_RAM_CNT);
+       if (status) {
+               QPRINTK(qdev, DRV, ERR,
+                       "Failed Dump of CODE RAM. Status = 0x%.08x\n", status);
+               goto err;
+       }
+
+       /* Insert the segment header */
+       ql_build_coredump_seg_header(&mpi_coredump->memc_ram_seg_hdr,
+                               MEMC_RAM_SEG_NUM,
+                               sizeof(struct mpi_coredump_segment_header)
+                               + sizeof(mpi_coredump->memc_ram),
+                               "MEMC RAM");
+       status = ql_dump_risc_ram_area(qdev, &mpi_coredump->memc_ram[0],
+                                       MEMC_RAM_ADDR, MEMC_RAM_CNT);
+       if (status) {
+               QPRINTK(qdev, DRV, ERR,
+                       "Failed Dump of MEMC RAM. Status = 0x%.08x\n", status);
+               goto err;
+       }
+err:
+       ql_sem_unlock(qdev, SEM_PROC_REG_MASK); /* does flush too */
+       return status;
+
+}
+
+static void ql_get_core_dump(struct ql_adapter *qdev)
+{
+       if (!ql_own_firmware(qdev)) {
+               QPRINTK(qdev, DRV, ERR, "%s: Don't own firmware!\n",
+                                       qdev->ndev->name);
+               return;
+       }
+
+       if (!netif_running(qdev->ndev)) {
+               QPRINTK(qdev, IFUP, ERR,
+                       "Force Coredump can only be done from interface "
+                       "that is up.\n");
+               return;
+       }
+
+       if (ql_mb_sys_err(qdev)) {
+               QPRINTK(qdev, IFUP, ERR,
+                       "Fail force coredump with ql_mb_sys_err().\n");
+               return;
+       }
+}
+
 void ql_gen_reg_dump(struct ql_adapter *qdev,
                        struct ql_reg_dump *mpi_coredump)
 {
@@ -178,6 +1319,36 @@ void ql_gen_reg_dump(struct ql_adapter *qdev,
        status = ql_get_ets_regs(qdev, &mpi_coredump->ets[0]);
        if (status)
                return;
+
+       if (test_bit(QL_FRC_COREDUMP, &qdev->flags))
+               ql_get_core_dump(qdev);
+}
+
+/* Coredump to messages log file using separate worker thread */
+void ql_mpi_core_to_log(struct work_struct *work)
+{
+       struct ql_adapter *qdev =
+               container_of(work, struct ql_adapter, mpi_core_to_log.work);
+       u32 *tmp, count;
+       int i;
+
+       count = sizeof(struct ql_mpi_coredump) / sizeof(u32);
+       tmp = (u32 *)qdev->mpi_coredump;
+       QPRINTK(qdev, DRV, DEBUG, "Core is dumping to log file!\n");
+
+       for (i = 0; i < count; i += 8) {
+               printk(KERN_ERR "%.08x: %.08x %.08x %.08x %.08x %.08x "
+                       "%.08x %.08x %.08x \n", i,
+                       tmp[i + 0],
+                       tmp[i + 1],
+                       tmp[i + 2],
+                       tmp[i + 3],
+                       tmp[i + 4],
+                       tmp[i + 5],
+                       tmp[i + 6],
+                       tmp[i + 7]);
+               msleep(5);
+       }
 }
 
 #ifdef QL_REG_DUMP
index 894a7c84faeff851d2de5ca2a6112fe3107a7bd5..5be3ae2f5a16a376995674598077f2c4292026a3 100644 (file)
@@ -73,7 +73,19 @@ static int qlge_irq_type = MSIX_IRQ;
 module_param(qlge_irq_type, int, MSIX_IRQ);
 MODULE_PARM_DESC(qlge_irq_type, "0 = MSI-X, 1 = MSI, 2 = Legacy.");
 
-static struct pci_device_id qlge_pci_tbl[] __devinitdata = {
+static int qlge_mpi_coredump;
+module_param(qlge_mpi_coredump, int, 0);
+MODULE_PARM_DESC(qlge_mpi_coredump,
+               "Option to enable MPI firmware dump. "
+               "Default is OFF - Do Not allocate memory. ");
+
+static int qlge_force_coredump;
+module_param(qlge_force_coredump, int, 0);
+MODULE_PARM_DESC(qlge_force_coredump,
+               "Option to allow force of firmware core dump. "
+               "Default is OFF - Do not allow.");
+
+static DEFINE_PCI_DEVICE_TABLE(qlge_pci_tbl) = {
        {PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QLGE_DEVICE_ID_8012)},
        {PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QLGE_DEVICE_ID_8000)},
        /* required last entry */
@@ -452,9 +464,7 @@ static int ql_set_mac_addr(struct ql_adapter *qdev, int set)
        if (set) {
                addr = &qdev->ndev->dev_addr[0];
                QPRINTK(qdev, IFUP, DEBUG,
-                       "Set Mac addr %02x:%02x:%02x:%02x:%02x:%02x\n",
-                       addr[0], addr[1], addr[2], addr[3],
-                       addr[4], addr[5]);
+                       "Set Mac addr %pM\n", addr);
        } else {
                memset(zero_mac_addr, 0, ETH_ALEN);
                addr = &zero_mac_addr[0];
@@ -1433,6 +1443,254 @@ map_error:
        return NETDEV_TX_BUSY;
 }
 
+/* Process an inbound completion from an rx ring. */
+static void ql_process_mac_rx_gro_page(struct ql_adapter *qdev,
+                                       struct rx_ring *rx_ring,
+                                       struct ib_mac_iocb_rsp *ib_mac_rsp,
+                                       u32 length,
+                                       u16 vlan_id)
+{
+       struct sk_buff *skb;
+       struct bq_desc *lbq_desc = ql_get_curr_lchunk(qdev, rx_ring);
+       struct skb_frag_struct *rx_frag;
+       int nr_frags;
+       struct napi_struct *napi = &rx_ring->napi;
+
+       napi->dev = qdev->ndev;
+
+       skb = napi_get_frags(napi);
+       if (!skb) {
+               QPRINTK(qdev, DRV, ERR, "Couldn't get an skb, exiting.\n");
+               rx_ring->rx_dropped++;
+               put_page(lbq_desc->p.pg_chunk.page);
+               return;
+       }
+       prefetch(lbq_desc->p.pg_chunk.va);
+       rx_frag = skb_shinfo(skb)->frags;
+       nr_frags = skb_shinfo(skb)->nr_frags;
+       rx_frag += nr_frags;
+       rx_frag->page = lbq_desc->p.pg_chunk.page;
+       rx_frag->page_offset = lbq_desc->p.pg_chunk.offset;
+       rx_frag->size = length;
+
+       skb->len += length;
+       skb->data_len += length;
+       skb->truesize += length;
+       skb_shinfo(skb)->nr_frags++;
+
+       rx_ring->rx_packets++;
+       rx_ring->rx_bytes += length;
+       skb->ip_summed = CHECKSUM_UNNECESSARY;
+       skb_record_rx_queue(skb, rx_ring->cq_id);
+       if (qdev->vlgrp && (vlan_id != 0xffff))
+               vlan_gro_frags(&rx_ring->napi, qdev->vlgrp, vlan_id);
+       else
+               napi_gro_frags(napi);
+}
+
+/* Process an inbound completion from an rx ring. */
+static void ql_process_mac_rx_page(struct ql_adapter *qdev,
+                                       struct rx_ring *rx_ring,
+                                       struct ib_mac_iocb_rsp *ib_mac_rsp,
+                                       u32 length,
+                                       u16 vlan_id)
+{
+       struct net_device *ndev = qdev->ndev;
+       struct sk_buff *skb = NULL;
+       void *addr;
+       struct bq_desc *lbq_desc = ql_get_curr_lchunk(qdev, rx_ring);
+       struct napi_struct *napi = &rx_ring->napi;
+
+       skb = netdev_alloc_skb(ndev, length);
+       if (!skb) {
+               QPRINTK(qdev, DRV, ERR, "Couldn't get an skb, "
+                               "need to unwind!.\n");
+               rx_ring->rx_dropped++;
+               put_page(lbq_desc->p.pg_chunk.page);
+               return;
+       }
+
+       addr = lbq_desc->p.pg_chunk.va;
+       prefetch(addr);
+
+
+       /* Frame error, so drop the packet. */
+       if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_ERR_MASK) {
+               QPRINTK(qdev, DRV, ERR, "Receive error, flags2 = 0x%x\n",
+                               ib_mac_rsp->flags2);
+               rx_ring->rx_errors++;
+               goto err_out;
+       }
+
+       /* The max framesize filter on this chip is set higher than
+        * MTU since FCoE uses 2k frames.
+        */
+       if (skb->len > ndev->mtu + ETH_HLEN) {
+               QPRINTK(qdev, DRV, ERR, "Segment too small, dropping.\n");
+               rx_ring->rx_dropped++;
+               goto err_out;
+       }
+       memcpy(skb_put(skb, ETH_HLEN), addr, ETH_HLEN);
+       QPRINTK(qdev, RX_STATUS, DEBUG,
+               "%d bytes of headers and data in large. Chain "
+               "page to new skb and pull tail.\n", length);
+       skb_fill_page_desc(skb, 0, lbq_desc->p.pg_chunk.page,
+                               lbq_desc->p.pg_chunk.offset+ETH_HLEN,
+                               length-ETH_HLEN);
+       skb->len += length-ETH_HLEN;
+       skb->data_len += length-ETH_HLEN;
+       skb->truesize += length-ETH_HLEN;
+
+       rx_ring->rx_packets++;
+       rx_ring->rx_bytes += skb->len;
+       skb->protocol = eth_type_trans(skb, ndev);
+       skb->ip_summed = CHECKSUM_NONE;
+
+       if (qdev->rx_csum &&
+               !(ib_mac_rsp->flags1 & IB_MAC_CSUM_ERR_MASK)) {
+               /* TCP frame. */
+               if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_T) {
+                       QPRINTK(qdev, RX_STATUS, DEBUG,
+                                       "TCP checksum done!\n");
+                       skb->ip_summed = CHECKSUM_UNNECESSARY;
+               } else if ((ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_U) &&
+                               (ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_V4)) {
+                       /* Unfragmented ipv4 UDP frame. */
+                       struct iphdr *iph = (struct iphdr *) skb->data;
+                       if (!(iph->frag_off &
+                               cpu_to_be16(IP_MF|IP_OFFSET))) {
+                               skb->ip_summed = CHECKSUM_UNNECESSARY;
+                               QPRINTK(qdev, RX_STATUS, DEBUG,
+                                               "TCP checksum done!\n");
+                       }
+               }
+       }
+
+       skb_record_rx_queue(skb, rx_ring->cq_id);
+       if (skb->ip_summed == CHECKSUM_UNNECESSARY) {
+               if (qdev->vlgrp && (vlan_id != 0xffff))
+                       vlan_gro_receive(napi, qdev->vlgrp, vlan_id, skb);
+               else
+                       napi_gro_receive(napi, skb);
+       } else {
+               if (qdev->vlgrp && (vlan_id != 0xffff))
+                       vlan_hwaccel_receive_skb(skb, qdev->vlgrp, vlan_id);
+               else
+                       netif_receive_skb(skb);
+       }
+       return;
+err_out:
+       dev_kfree_skb_any(skb);
+       put_page(lbq_desc->p.pg_chunk.page);
+}
+
+/* Process an inbound completion from an rx ring. */
+static void ql_process_mac_rx_skb(struct ql_adapter *qdev,
+                                       struct rx_ring *rx_ring,
+                                       struct ib_mac_iocb_rsp *ib_mac_rsp,
+                                       u32 length,
+                                       u16 vlan_id)
+{
+       struct net_device *ndev = qdev->ndev;
+       struct sk_buff *skb = NULL;
+       struct sk_buff *new_skb = NULL;
+       struct bq_desc *sbq_desc = ql_get_curr_sbuf(rx_ring);
+
+       skb = sbq_desc->p.skb;
+       /* Allocate new_skb and copy */
+       new_skb = netdev_alloc_skb(qdev->ndev, length + NET_IP_ALIGN);
+       if (new_skb == NULL) {
+               QPRINTK(qdev, PROBE, ERR,
+                       "No skb available, drop the packet.\n");
+               rx_ring->rx_dropped++;
+               return;
+       }
+       skb_reserve(new_skb, NET_IP_ALIGN);
+       memcpy(skb_put(new_skb, length), skb->data, length);
+       skb = new_skb;
+
+       /* Frame error, so drop the packet. */
+       if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_ERR_MASK) {
+               QPRINTK(qdev, DRV, ERR, "Receive error, flags2 = 0x%x\n",
+                                       ib_mac_rsp->flags2);
+               dev_kfree_skb_any(skb);
+               rx_ring->rx_errors++;
+               return;
+       }
+
+       /* loopback self test for ethtool */
+       if (test_bit(QL_SELFTEST, &qdev->flags)) {
+               ql_check_lb_frame(qdev, skb);
+               dev_kfree_skb_any(skb);
+               return;
+       }
+
+       /* The max framesize filter on this chip is set higher than
+        * MTU since FCoE uses 2k frames.
+        */
+       if (skb->len > ndev->mtu + ETH_HLEN) {
+               dev_kfree_skb_any(skb);
+               rx_ring->rx_dropped++;
+               return;
+       }
+
+       prefetch(skb->data);
+       skb->dev = ndev;
+       if (ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_M_MASK) {
+               QPRINTK(qdev, RX_STATUS, DEBUG, "%s%s%s Multicast.\n",
+                       (ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_M_MASK) ==
+                       IB_MAC_IOCB_RSP_M_HASH ? "Hash" : "",
+                       (ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_M_MASK) ==
+                       IB_MAC_IOCB_RSP_M_REG ? "Registered" : "",
+                       (ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_M_MASK) ==
+                       IB_MAC_IOCB_RSP_M_PROM ? "Promiscuous" : "");
+       }
+       if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_P)
+               QPRINTK(qdev, RX_STATUS, DEBUG, "Promiscuous Packet.\n");
+
+       rx_ring->rx_packets++;
+       rx_ring->rx_bytes += skb->len;
+       skb->protocol = eth_type_trans(skb, ndev);
+       skb->ip_summed = CHECKSUM_NONE;
+
+       /* If rx checksum is on, and there are no
+        * csum or frame errors.
+        */
+       if (qdev->rx_csum &&
+               !(ib_mac_rsp->flags1 & IB_MAC_CSUM_ERR_MASK)) {
+               /* TCP frame. */
+               if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_T) {
+                       QPRINTK(qdev, RX_STATUS, DEBUG,
+                                       "TCP checksum done!\n");
+                       skb->ip_summed = CHECKSUM_UNNECESSARY;
+               } else if ((ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_U) &&
+                               (ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_V4)) {
+                       /* Unfragmented ipv4 UDP frame. */
+                       struct iphdr *iph = (struct iphdr *) skb->data;
+                       if (!(iph->frag_off &
+                               cpu_to_be16(IP_MF|IP_OFFSET))) {
+                               skb->ip_summed = CHECKSUM_UNNECESSARY;
+                               QPRINTK(qdev, RX_STATUS, DEBUG,
+                                               "TCP checksum done!\n");
+                       }
+               }
+       }
+
+       skb_record_rx_queue(skb, rx_ring->cq_id);
+       if (skb->ip_summed == CHECKSUM_UNNECESSARY) {
+               if (qdev->vlgrp && (vlan_id != 0xffff))
+                       vlan_gro_receive(&rx_ring->napi, qdev->vlgrp,
+                                               vlan_id, skb);
+               else
+                       napi_gro_receive(&rx_ring->napi, skb);
+       } else {
+               if (qdev->vlgrp && (vlan_id != 0xffff))
+                       vlan_hwaccel_receive_skb(skb, qdev->vlgrp, vlan_id);
+               else
+                       netif_receive_skb(skb);
+       }
+}
+
 static void ql_realign_skb(struct sk_buff *skb, int len)
 {
        void *temp_addr = skb->data;
@@ -1646,14 +1904,13 @@ static struct sk_buff *ql_build_rx_skb(struct ql_adapter *qdev,
 }
 
 /* Process an inbound completion from an rx ring. */
-static void ql_process_mac_rx_intr(struct ql_adapter *qdev,
+static void ql_process_mac_split_rx_intr(struct ql_adapter *qdev,
                                   struct rx_ring *rx_ring,
-                                  struct ib_mac_iocb_rsp *ib_mac_rsp)
+                                  struct ib_mac_iocb_rsp *ib_mac_rsp,
+                                  u16 vlan_id)
 {
        struct net_device *ndev = qdev->ndev;
        struct sk_buff *skb = NULL;
-       u16 vlan_id = (le16_to_cpu(ib_mac_rsp->vlan_id) &
-                       IB_MAC_IOCB_RSP_VLAN_MASK)
 
        QL_DUMP_IB_MAC_RSP(ib_mac_rsp);
 
@@ -1753,6 +2010,65 @@ static void ql_process_mac_rx_intr(struct ql_adapter *qdev,
        }
 }
 
+/* Process an inbound completion from an rx ring. */
+static unsigned long ql_process_mac_rx_intr(struct ql_adapter *qdev,
+                                       struct rx_ring *rx_ring,
+                                       struct ib_mac_iocb_rsp *ib_mac_rsp)
+{
+       u32 length = le32_to_cpu(ib_mac_rsp->data_len);
+       u16 vlan_id = (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_V) ?
+                       ((le16_to_cpu(ib_mac_rsp->vlan_id) &
+                       IB_MAC_IOCB_RSP_VLAN_MASK)) : 0xffff;
+
+       QL_DUMP_IB_MAC_RSP(ib_mac_rsp);
+
+       if (ib_mac_rsp->flags4 & IB_MAC_IOCB_RSP_HV) {
+               /* The data and headers are split into
+                * separate buffers.
+                */
+               ql_process_mac_split_rx_intr(qdev, rx_ring, ib_mac_rsp,
+                                               vlan_id);
+       } else if (ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_DS) {
+               /* The data fit in a single small buffer.
+                * Allocate a new skb, copy the data and
+                * return the buffer to the free pool.
+                */
+               ql_process_mac_rx_skb(qdev, rx_ring, ib_mac_rsp,
+                                               length, vlan_id);
+       } else if ((ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_DL) &&
+               !(ib_mac_rsp->flags1 & IB_MAC_CSUM_ERR_MASK) &&
+               (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_T)) {
+               /* TCP packet in a page chunk that's been checksummed.
+                * Tack it on to our GRO skb and let it go.
+                */
+               ql_process_mac_rx_gro_page(qdev, rx_ring, ib_mac_rsp,
+                                               length, vlan_id);
+       } else if (ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_DL) {
+               /* Non-TCP packet in a page chunk. Allocate an
+                * skb, tack it on frags, and send it up.
+                */
+               ql_process_mac_rx_page(qdev, rx_ring, ib_mac_rsp,
+                                               length, vlan_id);
+       } else {
+               struct bq_desc *lbq_desc;
+
+               /* Free small buffer that holds the IAL */
+               lbq_desc = ql_get_curr_sbuf(rx_ring);
+               QPRINTK(qdev, RX_ERR, ERR, "Dropping frame, len %d > mtu %d\n",
+                       length, qdev->ndev->mtu);
+
+               /* Unwind the large buffers for this frame. */
+               while (length > 0) {
+                       lbq_desc = ql_get_curr_lchunk(qdev, rx_ring);
+                       length -= (length < rx_ring->lbq_buf_size) ?
+                               length : rx_ring->lbq_buf_size;
+                       put_page(lbq_desc->p.pg_chunk.page);
+               }
+       }
+
+       return (unsigned long)length;
+}
+
 /* Process an outbound completion from an rx ring. */
 static void ql_process_mac_tx_intr(struct ql_adapter *qdev,
                                   struct ob_mac_iocb_rsp *mac_rsp)
@@ -3332,15 +3648,15 @@ static int ql_adapter_initialize(struct ql_adapter *qdev)
 
        /* Enable the function, set pagesize, enable error checking. */
        value = FSC_FE | FSC_EPC_INBOUND | FSC_EPC_OUTBOUND |
-           FSC_EC | FSC_VM_PAGE_4K | FSC_SH;
+           FSC_EC | FSC_VM_PAGE_4K;
+       value |= SPLT_SETTING;
 
        /* Set/clear header splitting. */
        mask = FSC_VM_PAGESIZE_MASK |
            FSC_DBL_MASK | FSC_DBRST_MASK | (value << 16);
        ql_write32(qdev, FSC, mask | value);
 
-       ql_write32(qdev, SPLT_HDR, SPLT_HDR_EP |
-               min(SMALL_BUF_MAP_SIZE, MAX_SPLIT_SIZE));
+       ql_write32(qdev, SPLT_HDR, SPLT_LEN);
 
        /* Set RX packet routing to use port/pci function on which the
         * packet arrived on in addition to usual frame routing.
@@ -3538,6 +3854,7 @@ static int ql_adapter_down(struct ql_adapter *qdev)
        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);
 
        for (i = 0; i < qdev->rss_ring_count; i++)
@@ -4094,6 +4411,7 @@ static void ql_release_all(struct pci_dev *pdev)
                iounmap(qdev->reg_base);
        if (qdev->doorbell_area)
                iounmap(qdev->doorbell_area);
+       vfree(qdev->mpi_coredump);
        pci_release_regions(pdev);
        pci_set_drvdata(pdev, NULL);
 }
@@ -4175,6 +4493,17 @@ static int __devinit ql_init_device(struct pci_dev *pdev,
        spin_lock_init(&qdev->hw_lock);
        spin_lock_init(&qdev->stats_lock);
 
+       if (qlge_mpi_coredump) {
+               qdev->mpi_coredump =
+                       vmalloc(sizeof(struct ql_mpi_coredump));
+               if (qdev->mpi_coredump == NULL) {
+                       dev_err(&pdev->dev, "Coredump alloc failed.\n");
+                       err = -ENOMEM;
+                       goto err_out2;
+               }
+               if (qlge_force_coredump)
+                       set_bit(QL_FRC_COREDUMP, &qdev->flags);
+       }
        /* make sure the EEPROM is good */
        err = qdev->nic_ops->get_flash(qdev);
        if (err) {
@@ -4204,6 +4533,7 @@ static int __devinit ql_init_device(struct pci_dev *pdev,
        INIT_DELAYED_WORK(&qdev->mpi_work, ql_mpi_work);
        INIT_DELAYED_WORK(&qdev->mpi_port_cfg_work, ql_mpi_port_cfg_work);
        INIT_DELAYED_WORK(&qdev->mpi_idc_work, ql_mpi_idc_work);
+       INIT_DELAYED_WORK(&qdev->mpi_core_to_log, ql_mpi_core_to_log);
        init_completion(&qdev->ide_completion);
 
        if (!cards_found) {
@@ -4327,6 +4657,7 @@ static void ql_eeh_close(struct net_device *ndev)
        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);
 
        for (i = 0; i < qdev->rss_ring_count; i++)
index e2b2286102d498795de75319c7f76920bb8f84fb..e2c846f17fc7616515d5f06a29fab48b15d98bc3 100644 (file)
@@ -1,5 +1,54 @@
 #include "qlge.h"
 
+int ql_unpause_mpi_risc(struct ql_adapter *qdev)
+{
+       u32 tmp;
+
+       /* Un-pause the RISC */
+       tmp = ql_read32(qdev, CSR);
+       if (!(tmp & CSR_RP))
+               return -EIO;
+
+       ql_write32(qdev, CSR, CSR_CMD_CLR_PAUSE);
+       return 0;
+}
+
+int ql_pause_mpi_risc(struct ql_adapter *qdev)
+{
+       u32 tmp;
+       int count = UDELAY_COUNT;
+
+       /* Pause the RISC */
+       ql_write32(qdev, CSR, CSR_CMD_SET_PAUSE);
+       do {
+               tmp = ql_read32(qdev, CSR);
+               if (tmp & CSR_RP)
+                       break;
+               mdelay(UDELAY_DELAY);
+               count--;
+       } while (count);
+       return (count == 0) ? -ETIMEDOUT : 0;
+}
+
+int ql_hard_reset_mpi_risc(struct ql_adapter *qdev)
+{
+       u32 tmp;
+       int count = UDELAY_COUNT;
+
+       /* Reset the RISC */
+       ql_write32(qdev, CSR, CSR_CMD_SET_RST);
+       do {
+               tmp = ql_read32(qdev, CSR);
+               if (tmp & CSR_RR) {
+                       ql_write32(qdev, CSR, CSR_CMD_CLR_RST);
+                       break;
+               }
+               mdelay(UDELAY_DELAY);
+               count--;
+       } while (count);
+       return (count == 0) ? -ETIMEDOUT : 0;
+}
+
 int ql_read_mpi_reg(struct ql_adapter *qdev, u32 reg, u32 *data)
 {
        int status;
@@ -45,6 +94,35 @@ int ql_soft_reset_mpi_risc(struct ql_adapter *qdev)
        return status;
 }
 
+/* Determine if we are in charge of the firwmare. If
+ * we are the lower of the 2 NIC pcie functions, or if
+ * we are the higher function and the lower function
+ * is not enabled.
+ */
+int ql_own_firmware(struct ql_adapter *qdev)
+{
+       u32 temp;
+
+       /* If we are the lower of the 2 NIC functions
+        * on the chip the we are responsible for
+        * core dump and firmware reset after an error.
+        */
+       if (qdev->func < qdev->alt_func)
+               return 1;
+
+       /* If we are the higher of the 2 NIC functions
+        * on the chip and the lower function is not
+        * enabled, then we are responsible for
+        * core dump and firmware reset after an error.
+        */
+       temp =  ql_read32(qdev, STS);
+       if (!(temp & (1 << (8 + qdev->alt_func))))
+               return 1;
+
+       return 0;
+
+}
+
 static int ql_get_mb_sts(struct ql_adapter *qdev, struct mbox_params *mbcp)
 {
        int i, status;
@@ -529,6 +607,22 @@ end:
        return status;
 }
 
+int ql_mb_sys_err(struct ql_adapter *qdev)
+{
+       struct mbox_params mbc;
+       struct mbox_params *mbcp = &mbc;
+       int status;
+
+       memset(mbcp, 0, sizeof(struct mbox_params));
+
+       mbcp->in_count = 1;
+       mbcp->out_count = 0;
+
+       mbcp->mbox_in[0] = MB_CMD_MAKE_SYS_ERR;
+
+       status = ql_mailbox_command(qdev, mbcp);
+       return status;
+}
 
 /* Get MPI firmware version. This will be used for
  * driver banner and for ethtool info.
@@ -669,6 +763,63 @@ int ql_mb_set_port_cfg(struct ql_adapter *qdev)
        return status;
 }
 
+int ql_mb_dump_ram(struct ql_adapter *qdev, u64 req_dma, u32 addr,
+       u32 size)
+{
+       int status = 0;
+       struct mbox_params mbc;
+       struct mbox_params *mbcp = &mbc;
+
+       memset(mbcp, 0, sizeof(struct mbox_params));
+
+       mbcp->in_count = 9;
+       mbcp->out_count = 1;
+
+       mbcp->mbox_in[0] = MB_CMD_DUMP_RISC_RAM;
+       mbcp->mbox_in[1] = LSW(addr);
+       mbcp->mbox_in[2] = MSW(req_dma);
+       mbcp->mbox_in[3] = LSW(req_dma);
+       mbcp->mbox_in[4] = MSW(size);
+       mbcp->mbox_in[5] = LSW(size);
+       mbcp->mbox_in[6] = MSW(MSD(req_dma));
+       mbcp->mbox_in[7] = LSW(MSD(req_dma));
+       mbcp->mbox_in[8] = MSW(addr);
+
+
+       status = ql_mailbox_command(qdev, mbcp);
+       if (status)
+               return status;
+
+       if (mbcp->mbox_out[0] != MB_CMD_STS_GOOD) {
+               QPRINTK(qdev, DRV, ERR,
+                       "Failed to dump risc RAM.\n");
+               status = -EIO;
+       }
+       return status;
+}
+
+/* Issue a mailbox command to dump RISC RAM. */
+int ql_dump_risc_ram_area(struct ql_adapter *qdev, void *buf,
+               u32 ram_addr, int word_count)
+{
+       int status;
+       char *my_buf;
+       dma_addr_t buf_dma;
+
+       my_buf = pci_alloc_consistent(qdev->pdev, word_count * sizeof(u32),
+                                       &buf_dma);
+       if (!my_buf)
+               return -EIO;
+
+       status = ql_mb_dump_ram(qdev, buf_dma, ram_addr, word_count);
+       if (!status)
+               memcpy(buf, my_buf, word_count * sizeof(u32));
+
+       pci_free_consistent(qdev->pdev, word_count * sizeof(u32), my_buf,
+                               buf_dma);
+       return status;
+}
+
 /* Get link settings and maximum frame size settings
  * for the current port.
  * Most likely will block.
@@ -1143,5 +1294,19 @@ void ql_mpi_reset_work(struct work_struct *work)
        cancel_delayed_work_sync(&qdev->mpi_work);
        cancel_delayed_work_sync(&qdev->mpi_port_cfg_work);
        cancel_delayed_work_sync(&qdev->mpi_idc_work);
+       /* If we're not the dominant NIC function,
+        * then there is nothing to do.
+        */
+       if (!ql_own_firmware(qdev)) {
+               QPRINTK(qdev, DRV, ERR, "Don't own firmware!\n");
+               return;
+       }
+
+       if (!ql_core_dump(qdev, qdev->mpi_coredump)) {
+               QPRINTK(qdev, DRV, ERR, "Core is dumped!\n");
+               qdev->core_is_dumped = 1;
+               queue_delayed_work(qdev->workqueue,
+                       &qdev->mpi_core_to_log, 5 * HZ);
+       }
        ql_soft_reset_mpi_risc(qdev);
 }
index f03e2e4a15a896bc39597bbf5a9eb5f2d7e71814..d68ba7a586317bc152891e9ab58a3caee357ad49 100644 (file)
@@ -1222,7 +1222,7 @@ static void __devexit r6040_remove_one(struct pci_dev *pdev)
 }
 
 
-static struct pci_device_id r6040_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(r6040_pci_tbl) = {
        { PCI_DEVICE(PCI_VENDOR_ID_RDC, 0x6040) },
        { 0 }
 };
index 60f96c468a2465e3f3b9c7d3634b4f521d153216..c1bb24cf07938e6541eddeed9ba4273854b09ab8 100644 (file)
@@ -168,7 +168,7 @@ static void rtl_hw_start_8169(struct net_device *);
 static void rtl_hw_start_8168(struct net_device *);
 static void rtl_hw_start_8101(struct net_device *);
 
-static struct pci_device_id rtl8169_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(rtl8169_pci_tbl) = {
        { PCI_DEVICE(PCI_VENDOR_ID_REALTEK,     0x8129), 0, 0, RTL_CFG_0 },
        { PCI_DEVICE(PCI_VENDOR_ID_REALTEK,     0x8136), 0, 0, RTL_CFG_2 },
        { PCI_DEVICE(PCI_VENDOR_ID_REALTEK,     0x8167), 0, 0, RTL_CFG_0 },
@@ -3188,15 +3188,10 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (netif_msg_probe(tp)) {
                u32 xid = RTL_R32(TxConfig) & 0x9cf0f8ff;
 
-               printk(KERN_INFO "%s: %s at 0x%lx, "
-                      "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
-                      "XID %08x IRQ %d\n",
+               printk(KERN_INFO "%s: %s at 0x%lx, %pM, XID %08x IRQ %d\n",
                       dev->name,
                       rtl_chip_info[tp->chipset].name,
-                      dev->base_addr,
-                      dev->dev_addr[0], dev->dev_addr[1],
-                      dev->dev_addr[2], dev->dev_addr[3],
-                      dev->dev_addr[4], dev->dev_addr[5], xid, dev->irq);
+                      dev->base_addr, dev->dev_addr, xid, dev->irq);
        }
 
        rtl8169_init_phy(dev, tp);
index 1c257098d0a61bb8c4719acaf75bcd0ca09072f1..266baf5349641ffef8f2afd578b79c684030d657 100644 (file)
@@ -1688,7 +1688,7 @@ static int rr_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
        }
 }
 
-static struct pci_device_id rr_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(rr_pci_tbl) = {
        { PCI_VENDOR_ID_ESSENTIAL, PCI_DEVICE_ID_ESSENTIAL_ROADRUNNER,
                PCI_ANY_ID, PCI_ANY_ID, },
        { 0,}
index 3c4836d0898f310403f9d44e714793a127514df0..d1664586e8ffce60c0b7eef01859e46c64622bd0 100644 (file)
@@ -523,7 +523,7 @@ module_param_array(rts_frm_len, uint, NULL, 0);
  * S2IO device table.
  * This table lists all the devices that this driver supports.
  */
-static struct pci_device_id s2io_tbl[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(s2io_tbl) = {
        {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_S2IO_WIN,
         PCI_ANY_ID, PCI_ANY_ID},
        {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_S2IO_UNI,
index e35050322f97c618f1dff983f79d2036b2c02311..fd8cb506a2bb76437aa88259347e4bf11615cea3 100644 (file)
@@ -1589,7 +1589,7 @@ out:
        return 0;
 }
 
-static struct pci_device_id sc92031_pci_device_id_table[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(sc92031_pci_device_id_table) = {
        { PCI_DEVICE(PCI_VENDOR_ID_SILAN, 0x2031) },
        { PCI_DEVICE(PCI_VENDOR_ID_SILAN, 0x8139) },
        { PCI_DEVICE(0x1088, 0x2031) },
index 103e8b0e2a0d67e6682cb827e010a7e8f260e025..62d5cd51a9dd5e022110afd887c66914ea287a55 100644 (file)
@@ -1940,7 +1940,7 @@ void efx_schedule_reset(struct efx_nic *efx, enum reset_type type)
  **************************************************************************/
 
 /* PCI device ID table */
-static struct pci_device_id efx_pci_table[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(efx_pci_table) = {
        {PCI_DEVICE(EFX_VENDID_SFC, FALCON_A_P_DEVID),
         .driver_data = (unsigned long) &falcon_a1_nic_type},
        {PCI_DEVICE(EFX_VENDID_SFC, FALCON_B_P_DEVID),
index a615ac05153005e0e0a9c1f83aeddf4a7d2ffbdb..7eff0a615cb39d07b394490c0d473dd3f10810e6 100644 (file)
@@ -79,8 +79,6 @@ extern int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok);
 
 /* Global */
 extern void efx_schedule_reset(struct efx_nic *efx, enum reset_type type);
-extern void efx_suspend(struct efx_nic *efx);
-extern void efx_resume(struct efx_nic *efx);
 extern void efx_init_irq_moderation(struct efx_nic *efx, int tx_usecs,
                                    int rx_usecs, bool rx_adaptive);
 extern int efx_request_power(struct efx_nic *efx, int mw, const char *name);
index 6c0bbed8c47721d08ed9ee456ce29a31207a2996..d9f9c02a928ecdb8cb44537bcfccce51116bc708 100644 (file)
@@ -196,7 +196,7 @@ int efx_ethtool_get_settings(struct net_device *net_dev,
        efx->phy_op->get_settings(efx, ecmd);
        mutex_unlock(&efx->mac_lock);
 
-       /* Falcon GMAC does not support 1000Mbps HD */
+       /* GMAC does not support 1000Mbps HD */
        ecmd->supported &= ~SUPPORTED_1000baseT_Half;
        /* Both MACs support pause frames (bidirectional and respond-only) */
        ecmd->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
@@ -216,7 +216,7 @@ int efx_ethtool_set_settings(struct net_device *net_dev,
        struct efx_nic *efx = netdev_priv(net_dev);
        int rc;
 
-       /* Falcon GMAC does not support 1000Mbps HD */
+       /* GMAC does not support 1000Mbps HD */
        if (ecmd->speed == SPEED_1000 && ecmd->duplex != DUPLEX_FULL) {
                EFX_LOG(efx, "rejecting unsupported 1000Mbps HD"
                        " setting\n");
@@ -342,8 +342,8 @@ static int efx_ethtool_fill_self_tests(struct efx_nic *efx,
        unsigned int n = 0, i;
        enum efx_loopback_mode mode;
 
-       efx_fill_test(n++, strings, data, &tests->mdio,
-                     "core", 0, "mdio", NULL);
+       efx_fill_test(n++, strings, data, &tests->phy_alive,
+                     "phy", 0, "alive", NULL);
        efx_fill_test(n++, strings, data, &tests->nvram,
                      "core", 0, "nvram", NULL);
        efx_fill_test(n++, strings, data, &tests->interrupt,
@@ -379,7 +379,7 @@ static int efx_ethtool_fill_self_tests(struct efx_nic *efx,
                        if (name == NULL)
                                break;
 
-                       efx_fill_test(n++, strings, data, &tests->phy[i],
+                       efx_fill_test(n++, strings, data, &tests->phy_ext[i],
                                      "phy", 0, name, NULL);
                }
        }
index 9d009c46e962c343befff8c1395e3651133e5ccb..1b8d83657aaa85e235e87686e6135775f0afd799 100644 (file)
@@ -909,6 +909,8 @@ static int falcon_probe_port(struct efx_nic *efx)
                efx->wanted_fc = EFX_FC_RX | EFX_FC_TX;
        else
                efx->wanted_fc = EFX_FC_RX;
+       if (efx->mdio.mmds & MDIO_DEVS_AN)
+               efx->wanted_fc |= EFX_FC_AUTO;
 
        /* Allocate buffer for stats */
        rc = efx_nic_alloc_buffer(efx, &efx->stats_buffer,
@@ -1006,7 +1008,7 @@ static int falcon_test_nvram(struct efx_nic *efx)
 
 static const struct efx_nic_register_test falcon_b0_register_tests[] = {
        { FR_AZ_ADR_REGION,
-         EFX_OWORD32(0x0001FFFF, 0x0001FFFF, 0x0001FFFF, 0x0001FFFF) },
+         EFX_OWORD32(0x0003FFFF, 0x0003FFFF, 0x0003FFFF, 0x0003FFFF) },
        { FR_AZ_RX_CFG,
          EFX_OWORD32(0xFFFFFFFE, 0x00017FFF, 0x00000000, 0x00000000) },
        { FR_AZ_TX_CFG,
@@ -1728,7 +1730,7 @@ static int falcon_set_wol(struct efx_nic *efx, u32 type)
 
 /**************************************************************************
  *
- * Revision-dependent attributes used by efx.c
+ * Revision-dependent attributes used by efx.c and nic.c
  *
  **************************************************************************
  */
index 9f035b9f03503245ca38c44d058cf350958d3884..86610db2cff53768eaa6791c602cc592af158112 100644 (file)
@@ -896,29 +896,73 @@ fail:
        return rc;
 }
 
-int efx_mcdi_handle_assertion(struct efx_nic *efx)
+static int efx_mcdi_nvram_test(struct efx_nic *efx, unsigned int type)
+{
+       u8 inbuf[MC_CMD_NVRAM_TEST_IN_LEN];
+       u8 outbuf[MC_CMD_NVRAM_TEST_OUT_LEN];
+       int rc;
+
+       MCDI_SET_DWORD(inbuf, NVRAM_TEST_IN_TYPE, type);
+
+       rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_TEST, inbuf, sizeof(inbuf),
+                         outbuf, sizeof(outbuf), NULL);
+       if (rc)
+               return rc;
+
+       switch (MCDI_DWORD(outbuf, NVRAM_TEST_OUT_RESULT)) {
+       case MC_CMD_NVRAM_TEST_PASS:
+       case MC_CMD_NVRAM_TEST_NOTSUPP:
+               return 0;
+       default:
+               return -EIO;
+       }
+}
+
+int efx_mcdi_nvram_test_all(struct efx_nic *efx)
+{
+       u32 nvram_types;
+       unsigned int type;
+       int rc;
+
+       rc = efx_mcdi_nvram_types(efx, &nvram_types);
+       if (rc)
+               return rc;
+
+       type = 0;
+       while (nvram_types != 0) {
+               if (nvram_types & 1) {
+                       rc = efx_mcdi_nvram_test(efx, type);
+                       if (rc)
+                               return rc;
+               }
+               type++;
+               nvram_types >>= 1;
+       }
+
+       return 0;
+}
+
+static int efx_mcdi_read_assertion(struct efx_nic *efx)
 {
-       union {
-               u8 asserts[MC_CMD_GET_ASSERTS_IN_LEN];
-               u8 reboot[MC_CMD_REBOOT_IN_LEN];
-       } inbuf;
-       u8 assertion[MC_CMD_GET_ASSERTS_OUT_LEN];
+       u8 inbuf[MC_CMD_GET_ASSERTS_IN_LEN];
+       u8 outbuf[MC_CMD_GET_ASSERTS_OUT_LEN];
        unsigned int flags, index, ofst;
        const char *reason;
        size_t outlen;
        int retry;
        int rc;
 
-       /* Check if the MC is in the assertion handler, retrying twice. Once
+       /* Attempt to read any stored assertion state before we reboot
+        * the mcfw out of the assertion handler. Retry twice, once
         * because a boot-time assertion might cause this command to fail
         * with EINTR. And once again because GET_ASSERTS can race with
         * MC_CMD_REBOOT running on the other port. */
        retry = 2;
        do {
-               MCDI_SET_DWORD(inbuf.asserts, GET_ASSERTS_IN_CLEAR, 0);
+               MCDI_SET_DWORD(inbuf, GET_ASSERTS_IN_CLEAR, 1);
                rc = efx_mcdi_rpc(efx, MC_CMD_GET_ASSERTS,
-                                 inbuf.asserts, MC_CMD_GET_ASSERTS_IN_LEN,
-                                 assertion, sizeof(assertion), &outlen);
+                                 inbuf, MC_CMD_GET_ASSERTS_IN_LEN,
+                                 outbuf, sizeof(outbuf), &outlen);
        } while ((rc == -EINTR || rc == -EIO) && retry-- > 0);
 
        if (rc)
@@ -926,21 +970,11 @@ int efx_mcdi_handle_assertion(struct efx_nic *efx)
        if (outlen < MC_CMD_GET_ASSERTS_OUT_LEN)
                return -EINVAL;
 
-       flags = MCDI_DWORD(assertion, GET_ASSERTS_OUT_GLOBAL_FLAGS);
+       /* Print out any recorded assertion state */
+       flags = MCDI_DWORD(outbuf, GET_ASSERTS_OUT_GLOBAL_FLAGS);
        if (flags == MC_CMD_GET_ASSERTS_FLAGS_NO_FAILS)
                return 0;
 
-       /* Reset the hardware atomically such that only one port with succeed.
-        * This command will succeed if a reboot is no longer required (because
-        * the other port did it first), but fail with EIO if it succeeds.
-        */
-       BUILD_BUG_ON(MC_CMD_REBOOT_OUT_LEN != 0);
-       MCDI_SET_DWORD(inbuf.reboot, REBOOT_IN_FLAGS,
-                      MC_CMD_REBOOT_FLAGS_AFTER_ASSERTION);
-       efx_mcdi_rpc(efx, MC_CMD_REBOOT, inbuf.reboot, MC_CMD_REBOOT_IN_LEN,
-                    NULL, 0, NULL);
-
-       /* Print out the assertion */
        reason = (flags == MC_CMD_GET_ASSERTS_FLAGS_SYS_FAIL)
                ? "system-level assertion"
                : (flags == MC_CMD_GET_ASSERTS_FLAGS_THR_FAIL)
@@ -949,20 +983,45 @@ int efx_mcdi_handle_assertion(struct efx_nic *efx)
                ? "watchdog reset"
                : "unknown assertion";
        EFX_ERR(efx, "MCPU %s at PC = 0x%.8x in thread 0x%.8x\n", reason,
-               MCDI_DWORD(assertion, GET_ASSERTS_OUT_SAVED_PC_OFFS),
-               MCDI_DWORD(assertion, GET_ASSERTS_OUT_THREAD_OFFS));
+               MCDI_DWORD(outbuf, GET_ASSERTS_OUT_SAVED_PC_OFFS),
+               MCDI_DWORD(outbuf, GET_ASSERTS_OUT_THREAD_OFFS));
 
        /* Print out the registers */
        ofst = MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_OFST;
        for (index = 1; index < 32; index++) {
                EFX_ERR(efx, "R%.2d (?): 0x%.8x\n", index,
-                       MCDI_DWORD2(assertion, ofst));
+                       MCDI_DWORD2(outbuf, ofst));
                ofst += sizeof(efx_dword_t);
        }
 
        return 0;
 }
 
+static void efx_mcdi_exit_assertion(struct efx_nic *efx)
+{
+       u8 inbuf[MC_CMD_REBOOT_IN_LEN];
+
+       /* Atomically reboot the mcfw out of the assertion handler */
+       BUILD_BUG_ON(MC_CMD_REBOOT_OUT_LEN != 0);
+       MCDI_SET_DWORD(inbuf, REBOOT_IN_FLAGS,
+                      MC_CMD_REBOOT_FLAGS_AFTER_ASSERTION);
+       efx_mcdi_rpc(efx, MC_CMD_REBOOT, inbuf, MC_CMD_REBOOT_IN_LEN,
+                    NULL, 0, NULL);
+}
+
+int efx_mcdi_handle_assertion(struct efx_nic *efx)
+{
+       int rc;
+
+       rc = efx_mcdi_read_assertion(efx);
+       if (rc)
+               return rc;
+
+       efx_mcdi_exit_assertion(efx);
+
+       return 0;
+}
+
 void efx_mcdi_set_id_led(struct efx_nic *efx, enum efx_led_mode mode)
 {
        u8 inbuf[MC_CMD_SET_ID_LED_IN_LEN];
index 10ce98f4c0fb40d3d466986d53c0a8f0228ca870..f1f89ad4075ac2750623a840dc66812217fa0ad9 100644 (file)
@@ -116,6 +116,7 @@ extern int efx_mcdi_nvram_erase(struct efx_nic *efx, unsigned int type,
                                loff_t offset, size_t length);
 extern int efx_mcdi_nvram_update_finish(struct efx_nic *efx,
                                        unsigned int type);
+extern int efx_mcdi_nvram_test_all(struct efx_nic *efx);
 extern int efx_mcdi_handle_assertion(struct efx_nic *efx);
 extern void efx_mcdi_set_id_led(struct efx_nic *efx, enum efx_led_mode mode);
 extern int efx_mcdi_reset_port(struct efx_nic *efx);
index 73e71f42062483b4fcb4df9dc0cb90c4bce09b3d..bd59302695b3af4d7d07c4c0983dcff488496e8f 100644 (file)
 #define MC_CMD_GET_PHY_CFG_OUT_FLAGS_OFST 0
 #define MC_CMD_GET_PHY_CFG_PRESENT_LBN 0
 #define MC_CMD_GET_PHY_CFG_PRESENT_WIDTH 1
-#define MC_CMD_GET_PHY_CFG_SHORTBIST_LBN 1
-#define MC_CMD_GET_PHY_CFG_SHORTBIST_WIDTH 1
-#define MC_CMD_GET_PHY_CFG_LONGBIST_LBN 2
-#define MC_CMD_GET_PHY_CFG_LONGBIST_WIDTH 1
+#define MC_CMD_GET_PHY_CFG_BIST_CABLE_SHORT_LBN 1
+#define MC_CMD_GET_PHY_CFG_BIST_CABLE_SHORT_WIDTH 1
+#define MC_CMD_GET_PHY_CFG_BIST_CABLE_LONG_LBN 2
+#define MC_CMD_GET_PHY_CFG_BIST_CABLE_LONG_WIDTH 1
 #define MC_CMD_GET_PHY_CFG_LOWPOWER_LBN 3
 #define MC_CMD_GET_PHY_CFG_LOWPOWER_WIDTH 1
 #define MC_CMD_GET_PHY_CFG_POWEROFF_LBN 4
 #define MC_CMD_GET_PHY_CFG_POWEROFF_WIDTH 1
 #define MC_CMD_GET_PHY_CFG_TXDIS_LBN 5
 #define MC_CMD_GET_PHY_CFG_TXDIS_WIDTH 1
+#define MC_CMD_GET_PHY_CFG_BIST_LBN 6
+#define MC_CMD_GET_PHY_CFG_BIST_WIDTH 1
 #define MC_CMD_GET_PHY_CFG_OUT_TYPE_OFST 4
 /* Bitmask of supported capabilities */
 #define MC_CMD_GET_PHY_CFG_OUT_SUPPORTED_CAP_OFST 8
 #define MC_CMD_GET_PHY_CFG_OUT_REVISION_OFST 52
 #define MC_CMD_GET_PHY_CFG_OUT_REVISION_LEN 20
 
-/* MC_CMD_START_PHY_BIST:
+/* MC_CMD_START_BIST:
  * Start a BIST test on the PHY.
  *
  * Locks required: PHY_LOCK if doing a  PHY BIST
  */
 #define MC_CMD_START_BIST 0x25
 #define MC_CMD_START_BIST_IN_LEN 4
-#define MC_CMD_START_BIST_TYPE_OFST 0
+#define MC_CMD_START_BIST_IN_TYPE_OFST 0
+#define MC_CMD_START_BIST_OUT_LEN 0
 
-/* Run the PHY's short BIST */
-#define MC_CMD_PHY_BIST_SHORT  1
-/* Run the PHY's long BIST */
-#define MC_CMD_PHY_BIST_LONG   2
+/* Run the PHY's short cable BIST */
+#define MC_CMD_PHY_BIST_CABLE_SHORT  1
+/* Run the PHY's long cable BIST */
+#define MC_CMD_PHY_BIST_CABLE_LONG   2
 /* Run BIST on the currently selected BPX Serdes (XAUI or XFI) */
 #define MC_CMD_BPX_SERDES_BIST 3
+/* Run the MC loopback tests */
+#define MC_CMD_MC_LOOPBACK_BIST 4
+/* Run the PHY's standard BIST */
+#define MC_CMD_PHY_BIST 5
 
 /* MC_CMD_POLL_PHY_BIST: (variadic output)
  * Poll for BIST completion
  *
- * Returns a single status code, and a binary blob of phy-specific
- * bist output. If the driver can't succesfully parse the BIST output,
- * it should still respect the Pass/Fail in OUT.RESULT.
+ * Returns a single status code, and optionally some PHY specific
+ * bist output. The driver should only consume the BIST output
+ * after validating OUTLEN and PHY_CFG.PHY_TYPE.
  *
- * Locks required: PHY_LOCK  if doing a  PHY BIST
+ * If a driver can't succesfully parse the BIST output, it should
+ * still respect the pass/Fail in OUT.RESULT
+ *
+ * Locks required: PHY_LOCK if doing a  PHY BIST
  * Return code: 0, EACCES (if PHY_LOCK is not held)
  */
 #define MC_CMD_POLL_BIST 0x26
 #define MC_CMD_POLL_BIST_IN_LEN 0
 #define MC_CMD_POLL_BIST_OUT_LEN UNKNOWN
+#define MC_CMD_POLL_BIST_OUT_SFT9001_LEN 40
+#define MC_CMD_POLL_BIST_OUT_MRSFP_LEN 8
 #define MC_CMD_POLL_BIST_OUT_RESULT_OFST 0
 #define MC_CMD_POLL_BIST_RUNNING 1
 #define MC_CMD_POLL_BIST_PASSED 2
 #define MC_CMD_POLL_BIST_FAILED 3
 #define MC_CMD_POLL_BIST_TIMEOUT 4
+/* Generic: */
 #define MC_CMD_POLL_BIST_OUT_PRIVATE_OFST 4
+/* SFT9001-specific: */
+/* (offset 4 unused?) */
+#define MC_CMD_POLL_BIST_OUT_SFT9001_CABLE_LENGTH_A_OFST 8
+#define MC_CMD_POLL_BIST_OUT_SFT9001_CABLE_LENGTH_B_OFST 12
+#define MC_CMD_POLL_BIST_OUT_SFT9001_CABLE_LENGTH_C_OFST 16
+#define MC_CMD_POLL_BIST_OUT_SFT9001_CABLE_LENGTH_D_OFST 20
+#define MC_CMD_POLL_BIST_OUT_SFT9001_CABLE_STATUS_A_OFST 24
+#define MC_CMD_POLL_BIST_OUT_SFT9001_CABLE_STATUS_B_OFST 28
+#define MC_CMD_POLL_BIST_OUT_SFT9001_CABLE_STATUS_C_OFST 32
+#define MC_CMD_POLL_BIST_OUT_SFT9001_CABLE_STATUS_D_OFST 36
+#define MC_CMD_POLL_BIST_SFT9001_PAIR_OK 1
+#define MC_CMD_POLL_BIST_SFT9001_PAIR_OPEN 2
+#define MC_CMD_POLL_BIST_SFT9001_INTRA_PAIR_SHORT 3
+#define MC_CMD_POLL_BIST_SFT9001_INTER_PAIR_SHORT 4
+#define MC_CMD_POLL_BIST_SFT9001_PAIR_BUSY 9
+/* mrsfp "PHY" driver: */
+#define MC_CMD_POLL_BIST_OUT_MRSFP_TEST_OFST 4
+#define MC_CMD_POLL_BIST_MRSFP_TEST_COMPLETE 0
+#define MC_CMD_POLL_BIST_MRSFP_TEST_BUS_SWITCH_OFF_I2C_WRITE 1
+#define MC_CMD_POLL_BIST_MRSFP_TEST_BUS_SWITCH_OFF_I2C_NO_ACCESS_IO_EXP 2
+#define MC_CMD_POLL_BIST_MRSFP_TEST_BUS_SWITCH_OFF_I2C_NO_ACCESS_MODULE 3
+#define MC_CMD_POLL_BIST_MRSFP_TEST_IO_EXP_I2C_CONFIGURE 4
+#define MC_CMD_POLL_BIST_MRSFP_TEST_BUS_SWITCH_I2C_NO_CROSSTALK 5
+#define MC_CMD_POLL_BIST_MRSFP_TEST_MODULE_PRESENCE 6
+#define MC_CMD_POLL_BIST_MRSFP_TEST_MODULE_ID_I2C_ACCESS 7
+#define MC_CMD_POLL_BIST_MRSFP_TEST_MODULE_ID_SANE_VALUE 8
 
 /* MC_CMD_PHY_SPI: (variadic in, variadic out)
  * Read/Write/Erase the PHY SPI device
 #define MC_CMD_WOL_FILTER_SET_IN_BITMAP_LAYER4_OFST    \
        (MC_CMD_WOL_FILTER_SET_IN_DATA_OFST + 178)
 
+#define MC_CMD_WOL_FILTER_SET_IN_LINK_MASK_OFST        \
+       MC_CMD_WOL_FILTER_SET_IN_DATA_OFST
+#define MC_CMD_WOL_FILTER_SET_IN_LINK_UP_LBN   0
+#define MC_CMD_WOL_FILTER_SET_IN_LINK_UP_WIDTH 1
+#define MC_CMD_WOL_FILTER_SET_IN_LINK_DOWN_LBN 1
+#define MC_CMD_WOL_FILTER_SET_IN_LINK_DOWN_WIDTH 1
+
 #define MC_CMD_WOL_FILTER_SET_OUT_LEN 4
 #define MC_CMD_WOL_FILTER_SET_OUT_FILTER_ID_OFST 0
 
 #define MC_CMD_WOL_TYPE_IPV4_SYN   0x3
 #define MC_CMD_WOL_TYPE_IPV6_SYN   0x4
 #define MC_CMD_WOL_TYPE_BITMAP     0x5
-#define MC_CMD_WOL_TYPE_MAX        0x6
+#define MC_CMD_WOL_TYPE_LINK       0x6
+#define MC_CMD_WOL_TYPE_MAX        0x7
 
 #define MC_CMD_FILTER_MODE_SIMPLE     0x0
 #define MC_CMD_FILTER_MODE_STRUCTURED 0xffffffff
  * Returns: 0, EINVAL (bad type/offset/length), EACCES (if PHY_LOCK required and not held)
  */
 #define MC_CMD_NVRAM_UPDATE_FINISH 0x3c
-#define MC_CMD_NVRAM_UPDATE_FINISH_IN_LEN 4
+#define MC_CMD_NVRAM_UPDATE_FINISH_IN_LEN 8
 #define MC_CMD_NVRAM_UPDATE_FINISH_IN_TYPE_OFST 0
+#define MC_CMD_NVRAM_UPDATE_FINISH_IN_REBOOT_OFST 4
 #define MC_CMD_NVRAM_UPDATE_FINISH_OUT_LEN 0
 
 /* MC_CMD_REBOOT:
- * Reboot the MC. The AFTER_ASSERTION flag is intended to be used
- * when the driver notices an assertion failure, to allow two ports to
- * both recover (semi-)gracefully.
+ * Reboot the MC.
+ *
+ * The AFTER_ASSERTION flag is intended to be used when the driver notices
+ * an assertion failure (at which point it is expected to perform a complete
+ * tear down and reinitialise), to allow both ports to reset the MC once
+ * in an atomic fashion.
+ *
+ * Production mc firmwares are generally compiled with REBOOT_ON_ASSERT=1,
+ * which means that they will automatically reboot out of the assertion
+ * handler, so this is in practise an optional operation. It is still
+ * recommended that drivers execute this to support custom firmwares
+ * with REBOOT_ON_ASSERT=0.
  *
  * Locks required: NONE
  * Returns: Nothing. You get back a response with ERR=1, DATALEN=0
        ((_ofst) + 6)
 
 /* MC_CMD_READ_SENSORS
- * Returns the current (value, state) for each sensor
+ * Returns the current reading from each sensor
  *
- * Returns the current (value, state) [each 16bit] of each sensor supported by
- * this board, by DMA'ing a sparse array (indexed by the sensor type) into host
- * memory.
+ * Returns a sparse array of sensor readings (indexed by the sensor
+ * type) into host memory.  Each array element is a dword.
  *
  * The MC will send a SENSOREVT event every time any sensor changes state. The
  * driver is responsible for ensuring that it doesn't miss any events. The board
 #define MC_CMD_READ_SENSORS_IN_DMA_ADDR_HI_OFST 4
 #define MC_CMD_READ_SENSORS_OUT_LEN 0
 
+/* Sensor reading fields */
+#define MC_CMD_READ_SENSOR_VALUE_LBN 0
+#define MC_CMD_READ_SENSOR_VALUE_WIDTH 16
+#define MC_CMD_READ_SENSOR_STATE_LBN 16
+#define MC_CMD_READ_SENSOR_STATE_WIDTH 8
+
 
 /* MC_CMD_GET_PHY_STATE:
  * Report current state of PHY.  A "zombie" PHY is a PHY that has failed to
 #define MC_CMD_MAC_RESET_RESTORE_IN_LEN 0
 #define MC_CMD_MAC_RESET_RESTORE_OUT_LEN 0
 
+
+/* MC_CMD_TEST_ASSERT:
+ * Deliberately trigger an assert-detonation in the firmware for testing
+ * purposes (i.e. to allow tests that the driver copes gracefully).
+ *
+ * Locks required: None
+ * Returns: 0
+ */
+
+#define MC_CMD_TESTASSERT 0x49
+#define MC_CMD_TESTASSERT_IN_LEN 0
+#define MC_CMD_TESTASSERT_OUT_LEN 0
+
+/* MC_CMD_WORKAROUND 0x4a
+ *
+ * Enable/Disable a given workaround. The mcfw will return EINVAL if it
+ * doesn't understand the given workaround number - which should not
+ * be treated as a hard error by client code.
+ *
+ * This op does not imply any semantics about each workaround, that's between
+ * the driver and the mcfw on a per-workaround basis.
+ *
+ * Locks required: None
+ * Returns: 0, EINVAL
+ */
+#define MC_CMD_WORKAROUND 0x4a
+#define MC_CMD_WORKAROUND_IN_LEN 8
+#define MC_CMD_WORKAROUND_IN_TYPE_OFST 0
+#define MC_CMD_WORKAROUND_BUG17230 1
+#define MC_CMD_WORKAROUND_IN_ENABLED_OFST 4
+#define MC_CMD_WORKAROUND_OUT_LEN 0
+
+/* MC_CMD_GET_PHY_MEDIA_INFO:
+ * Read media-specific data from PHY (e.g. SFP/SFP+ module ID information for
+ * SFP+ PHYs).
+ *
+ * The "media type" can be found via GET_PHY_CFG (GET_PHY_CFG_OUT_MEDIA_TYPE);
+ * the valid "page number" input values, and the output data, are interpreted
+ * on a per-type basis.
+ *
+ * For SFP+: PAGE=0 or 1 returns a 128-byte block read from module I2C address
+ *           0xA0 offset 0 or 0x80.
+ * Anything else: currently undefined.
+ *
+ * Locks required: None
+ * Return code: 0
+ */
+#define MC_CMD_GET_PHY_MEDIA_INFO 0x4b
+#define MC_CMD_GET_PHY_MEDIA_INFO_IN_LEN 4
+#define MC_CMD_GET_PHY_MEDIA_INFO_IN_PAGE_OFST 0
+#define MC_CMD_GET_PHY_MEDIA_INFO_OUT_LEN(_num_bytes) (4 + (_num_bytes))
+#define MC_CMD_GET_PHY_MEDIA_INFO_OUT_DATALEN_OFST 0
+#define MC_CMD_GET_PHY_MEDIA_INFO_OUT_DATA_OFST 4
+
+/* MC_CMD_NVRAM_TEST:
+ * Test a particular NVRAM partition for valid contents (where "valid"
+ * depends on the type of partition).
+ *
+ * Locks required: None
+ * Return code: 0
+ */
+#define MC_CMD_NVRAM_TEST 0x4c
+#define MC_CMD_NVRAM_TEST_IN_LEN 4
+#define MC_CMD_NVRAM_TEST_IN_TYPE_OFST 0
+#define MC_CMD_NVRAM_TEST_OUT_LEN 4
+#define MC_CMD_NVRAM_TEST_OUT_RESULT_OFST 0
+#define MC_CMD_NVRAM_TEST_PASS 0
+#define MC_CMD_NVRAM_TEST_FAIL 1
+#define MC_CMD_NVRAM_TEST_NOTSUPP 2
+
+/* MC_CMD_MRSFP_TWEAK: (debug)
+ * Read status and/or set parameters for the "mrsfp" driver in mr_rusty builds.
+ * I2C I/O expander bits are always read; if equaliser parameters are supplied,
+ * they are configured first.
+ *
+ * Locks required: None
+ * Return code: 0, EINVAL
+ */
+#define MC_CMD_MRSFP_TWEAK 0x4d
+#define MC_CMD_MRSFP_TWEAK_IN_LEN_READ_ONLY 0
+#define MC_CMD_MRSFP_TWEAK_IN_LEN_EQ_CONFIG 16
+#define MC_CMD_MRSFP_TWEAK_IN_TXEQ_LEVEL_OFST 0    /* 0-6 low->high de-emph. */
+#define MC_CMD_MRSFP_TWEAK_IN_TXEQ_DT_CFG_OFST 4   /* 0-8 low->high ref.V */
+#define MC_CMD_MRSFP_TWEAK_IN_RXEQ_BOOST_OFST 8    /* 0-8 low->high boost */
+#define MC_CMD_MRSFP_TWEAK_IN_RXEQ_DT_CFG_OFST 12  /* 0-8 low->high ref.V */
+#define MC_CMD_MRSFP_TWEAK_OUT_LEN 12
+#define MC_CMD_MRSFP_TWEAK_OUT_IOEXP_INPUTS_OFST 0     /* input bits */
+#define MC_CMD_MRSFP_TWEAK_OUT_IOEXP_OUTPUTS_OFST 4    /* output bits */
+#define MC_CMD_MRSFP_TWEAK_OUT_IOEXP_DIRECTION_OFST 8  /* dirs: 0=out, 1=in */
+
+/* Do NOT add new commands beyond 0x4f as part of 3.0 : 0x50 - 0x7f will be
+ * used for post-3.0 extensions. If you run out of space, look for gaps or
+ * commands that are unused in the existing range. */
+
 #endif /* MCDI_PCOL_H */
index eb694af7a473503b176a23fb37cddce97e70b6cc..34c22fa986e2b3147a08a27666a7f0dd4a545b6b 100644 (file)
@@ -381,6 +381,18 @@ static int efx_mcdi_phy_probe(struct efx_nic *efx)
         * but by convention we don't */
        efx->loopback_modes &= ~(1 << LOOPBACK_NONE);
 
+       /* Set the initial link mode */
+       efx_mcdi_phy_decode_link(
+               efx, &efx->link_state,
+               MCDI_DWORD(outbuf, GET_LINK_OUT_LINK_SPEED),
+               MCDI_DWORD(outbuf, GET_LINK_OUT_FLAGS),
+               MCDI_DWORD(outbuf, GET_LINK_OUT_FCNTL));
+
+       /* Default to Autonegotiated flow control if the PHY supports it */
+       efx->wanted_fc = EFX_FC_RX | EFX_FC_TX;
+       if (phy_data->supported_cap & (1 << MC_CMD_PHY_CAP_AN_LBN))
+               efx->wanted_fc |= EFX_FC_AUTO;
+
        return 0;
 
 fail:
@@ -436,7 +448,7 @@ void efx_mcdi_phy_check_fcntl(struct efx_nic *efx, u32 lpa)
 
        /* The link partner capabilities are only relevent if the
         * link supports flow control autonegotiation */
-       if (~phy_cfg->supported_cap & (1 << MC_CMD_PHY_CAP_ASYM_LBN))
+       if (~phy_cfg->supported_cap & (1 << MC_CMD_PHY_CAP_AN_LBN))
                return;
 
        /* If flow control autoneg is supported and enabled, then fine */
@@ -560,6 +572,27 @@ static int efx_mcdi_phy_set_settings(struct efx_nic *efx, struct ethtool_cmd *ec
        return 0;
 }
 
+static int efx_mcdi_phy_test_alive(struct efx_nic *efx)
+{
+       u8 outbuf[MC_CMD_GET_PHY_STATE_OUT_LEN];
+       size_t outlen;
+       int rc;
+
+       BUILD_BUG_ON(MC_CMD_GET_PHY_STATE_IN_LEN != 0);
+
+       rc = efx_mcdi_rpc(efx, MC_CMD_GET_PHY_STATE, NULL, 0,
+                         outbuf, sizeof(outbuf), &outlen);
+       if (rc)
+               return rc;
+
+       if (outlen < MC_CMD_GET_PHY_STATE_OUT_LEN)
+               return -EMSGSIZE;
+       if (MCDI_DWORD(outbuf, GET_PHY_STATE_STATE) != MC_CMD_PHY_STATE_OK)
+               return -EINVAL;
+
+       return 0;
+}
+
 struct efx_phy_operations efx_mcdi_phy_ops = {
        .probe          = efx_mcdi_phy_probe,
        .init           = efx_port_dummy_op_int,
@@ -569,6 +602,7 @@ struct efx_phy_operations efx_mcdi_phy_ops = {
        .remove         = efx_mcdi_phy_remove,
        .get_settings   = efx_mcdi_phy_get_settings,
        .set_settings   = efx_mcdi_phy_set_settings,
+       .test_alive     = efx_mcdi_phy_test_alive,
        .run_tests      = NULL,
        .test_name      = NULL,
 };
index 1574e52f05940f2e4ce7cc63c1a15c67b069223e..0548fcbbdcd0982ec1b8d2ca9b278d935951d7bc 100644 (file)
@@ -335,3 +335,27 @@ enum efx_fc_type efx_mdio_get_pause(struct efx_nic *efx)
                mii_advertise_flowctrl(efx->wanted_fc),
                efx_mdio_read(efx, MDIO_MMD_AN, MDIO_AN_LPA));
 }
+
+int efx_mdio_test_alive(struct efx_nic *efx)
+{
+       int rc;
+       int devad = __ffs(efx->mdio.mmds);
+       u16 physid1, physid2;
+
+       mutex_lock(&efx->mac_lock);
+
+       physid1 = efx_mdio_read(efx, devad, MDIO_DEVID1);
+       physid2 = efx_mdio_read(efx, devad, MDIO_DEVID2);
+
+       if ((physid1 == 0x0000) || (physid1 == 0xffff) ||
+           (physid2 == 0x0000) || (physid2 == 0xffff)) {
+               EFX_ERR(efx, "no MDIO PHY present with ID %d\n",
+                       efx->mdio.prtad);
+               rc = -EINVAL;
+       } else {
+               rc = efx_mdio_check_mmds(efx, efx->mdio.mmds, 0);
+       }
+
+       mutex_unlock(&efx->mac_lock);
+       return rc;
+}
index f6ac9503339dc365cd28659fa873c074d8deb0d0..f89e719296031194a6953eba58daebe66b08164b 100644 (file)
@@ -106,4 +106,7 @@ efx_mdio_set_flag(struct efx_nic *efx, int devad, int addr,
        mdio_set_flag(&efx->mdio, efx->mdio.prtad, devad, addr, mask, state);
 }
 
+/* Liveness self-test for MDIO PHYs */
+extern int efx_mdio_test_alive(struct efx_nic *efx);
+
 #endif /* EFX_MDIO_10G_H */
index d5aab5b3fa066e27666c44b01dd35c241a0b86f7..cb018e272097e56caee175c0cad55f72d353be8b 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/etherdevice.h>
 #include <linux/ethtool.h>
 #include <linux/if_vlan.h>
-#include <linux/timer.h>
 #include <linux/mdio.h>
 #include <linux/list.h>
 #include <linux/pci.h>
@@ -101,9 +100,6 @@ do {if (net_ratelimit()) EFX_LOG(efx, fmt, ##args); } while (0)
  * Special buffers are used for the event queues and the TX and RX
  * descriptor queues for each channel.  They are *not* used for the
  * actual transmit and receive buffers.
- *
- * Note that for Falcon, TX and RX descriptor queues live in host memory.
- * Allocation and freeing procedures must take this into account.
  */
 struct efx_special_buffer {
        void *addr;
@@ -300,7 +296,7 @@ struct efx_rx_queue {
  * @dma_addr: DMA base address of the buffer
  * @len: Buffer length, in bytes
  *
- * Falcon uses these buffers for its interrupt status registers and
+ * The NIC uses these buffers for its interrupt status registers and
  * MAC stats dumps.
  */
 struct efx_buffer {
@@ -516,8 +512,9 @@ struct efx_mac_operations {
  * @set_settings: Set ethtool settings. Serialised by the mac_lock.
  * @set_npage_adv: Set abilities advertised in (Extended) Next Page
  *     (only needed where AN bit is set in mmds)
+ * @test_alive: Test that PHY is 'alive' (online)
  * @test_name: Get the name of a PHY-specific test/result
- * @run_tests: Run tests and record results as appropriate.
+ * @run_tests: Run tests and record results as appropriate (offline).
  *     Flags are the ethtool tests flags.
  */
 struct efx_phy_operations {
@@ -532,6 +529,7 @@ struct efx_phy_operations {
        int (*set_settings) (struct efx_nic *efx,
                             struct ethtool_cmd *ecmd);
        void (*set_npage_adv) (struct efx_nic *efx, u32);
+       int (*test_alive) (struct efx_nic *efx);
        const char *(*test_name) (struct efx_nic *efx, unsigned int index);
        int (*run_tests) (struct efx_nic *efx, int *results, unsigned flags);
 };
@@ -672,7 +670,7 @@ union efx_multicast_hash {
  * @irq_status: Interrupt status buffer
  * @last_irq_cpu: Last CPU to handle interrupt.
  *     This register is written with the SMP processor ID whenever an
- *     interrupt is handled.  It is used by falcon_test_interrupt()
+ *     interrupt is handled.  It is used by efx_nic_test_interrupt()
  *     to verify that an interrupt has occurred.
  * @spi_flash: SPI flash device
  *     This field will be %NULL if no flash device is present (or for Siena).
@@ -721,8 +719,7 @@ union efx_multicast_hash {
  * @loopback_modes: Supported loopback mode bitmask
  * @loopback_selftest: Offline self-test private state
  *
- * The @priv field of the corresponding &struct net_device points to
- * this.
+ * This is stored in the private area of the &struct net_device.
  */
 struct efx_nic {
        char name[IFNAMSIZ];
@@ -995,7 +992,7 @@ static inline void clear_bit_le(unsigned nr, unsigned char *addr)
  * that the net driver will program into the MAC as the maximum frame
  * length.
  *
- * The 10G MAC used in Falcon requires 8-byte alignment on the frame
+ * The 10G MAC requires 8-byte alignment on the frame
  * length, so we round up to the nearest 8.
  *
  * Re-clocking by the XGXS on RX can reduce an IPG to 32 bits (half an
index db44224ed2cad53789f7d5410db1a7988f34bca1..b06f8e348307d3896f4f10e0e9f0cb3c4b7807e0 100644 (file)
@@ -623,10 +623,6 @@ void efx_nic_remove_rx(struct efx_rx_queue *rx_queue)
  *
  * This writes the EVQ_RPTR_REG register for the specified channel's
  * event queue.
- *
- * Note that EVQ_RPTR_REG contains the index of the "last read" event,
- * whereas channel->eventq_read_ptr contains the index of the "next to
- * read" event.
  */
 void efx_nic_eventq_read_ack(struct efx_channel *channel)
 {
@@ -1384,6 +1380,15 @@ static irqreturn_t efx_legacy_interrupt(int irq, void *dev_id)
                efx->last_irq_cpu = raw_smp_processor_id();
                EFX_TRACE(efx, "IRQ %d on CPU %d status " EFX_DWORD_FMT "\n",
                          irq, raw_smp_processor_id(), EFX_DWORD_VAL(reg));
+       } else if (EFX_WORKAROUND_15783(efx)) {
+               /* We can't return IRQ_HANDLED more than once on seeing ISR0=0
+                * because this might be a shared interrupt, but we do need to
+                * check the channel every time and preemptively rearm it if
+                * it's idle. */
+               efx_for_each_channel(channel, efx) {
+                       if (!channel->work_pending)
+                               efx_nic_eventq_read_ack(channel);
+               }
        }
 
        return result;
index e0d13a451019753112ebc72e23cf9def99486896..14793d8bd6615008d446cafa835f5c6def35e8d2 100644 (file)
@@ -445,4 +445,5 @@ struct efx_phy_operations falcon_qt202x_phy_ops = {
        .remove          = qt202x_phy_remove,
        .get_settings    = qt202x_phy_get_settings,
        .set_settings    = efx_mdio_set_settings,
+       .test_alive      = efx_mdio_test_alive,
 };
index 250c8827b842e57d169dad1a73f8dcf387527c52..cf0139a7d9a42a8b6115a711dfe8b038ccea845f 100644 (file)
@@ -24,9 +24,6 @@
 #include "nic.h"
 #include "selftest.h"
 #include "workarounds.h"
-#include "spi.h"
-#include "io.h"
-#include "mdio_10g.h"
 
 /*
  * Loopback test packet structure
@@ -76,42 +73,15 @@ struct efx_loopback_state {
  *
  **************************************************************************/
 
-static int efx_test_mdio(struct efx_nic *efx, struct efx_self_tests *tests)
+static int efx_test_phy_alive(struct efx_nic *efx, struct efx_self_tests *tests)
 {
        int rc = 0;
-       int devad;
-       u16 physid1, physid2;
-
-       if (efx->mdio.mode_support & MDIO_SUPPORTS_C45)
-               devad = __ffs(efx->mdio.mmds);
-       else if (efx->mdio.mode_support & MDIO_SUPPORTS_C22)
-               devad = MDIO_DEVAD_NONE;
-       else
-               return 0;
-
-       mutex_lock(&efx->mac_lock);
-       tests->mdio = -1;
-
-       physid1 = efx_mdio_read(efx, devad, MDIO_DEVID1);
-       physid2 = efx_mdio_read(efx, devad, MDIO_DEVID2);
 
-       if ((physid1 == 0x0000) || (physid1 == 0xffff) ||
-           (physid2 == 0x0000) || (physid2 == 0xffff)) {
-               EFX_ERR(efx, "no MDIO PHY present with ID %d\n",
-                       efx->mdio.prtad);
-               rc = -EINVAL;
-               goto out;
+       if (efx->phy_op->test_alive) {
+               rc = efx->phy_op->test_alive(efx);
+               tests->phy_alive = rc ? -1 : 1;
        }
 
-       if (EFX_IS10G(efx)) {
-               rc = efx_mdio_check_mmds(efx, efx->mdio.mmds, 0);
-               if (rc)
-                       goto out;
-       }
-
-out:
-       mutex_unlock(&efx->mac_lock);
-       tests->mdio = rc ? -1 : 1;
        return rc;
 }
 
@@ -258,7 +228,7 @@ static int efx_test_phy(struct efx_nic *efx, struct efx_self_tests *tests,
                return 0;
 
        mutex_lock(&efx->mac_lock);
-       rc = efx->phy_op->run_tests(efx, tests->phy, flags);
+       rc = efx->phy_op->run_tests(efx, tests->phy_ext, flags);
        mutex_unlock(&efx->mac_lock);
        return rc;
 }
@@ -684,7 +654,7 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests,
        /* Online (i.e. non-disruptive) testing
         * This checks interrupt generation, event delivery and PHY presence. */
 
-       rc = efx_test_mdio(efx, tests);
+       rc = efx_test_phy_alive(efx, tests);
        if (rc && !rc_test)
                rc_test = rc;
 
index f6feee04c96ba925ea187284cd6fffab812872ed..643bef72b99d0515647d7a783d056dfb79e88a03 100644 (file)
@@ -32,7 +32,7 @@ struct efx_loopback_self_tests {
  */
 struct efx_self_tests {
        /* online tests */
-       int mdio;
+       int phy_alive;
        int nvram;
        int interrupt;
        int eventq_dma[EFX_MAX_CHANNELS];
@@ -40,7 +40,7 @@ struct efx_self_tests {
        int eventq_poll[EFX_MAX_CHANNELS];
        /* offline tests */
        int registers;
-       int phy[EFX_MAX_PHY_TESTS];
+       int phy_ext[EFX_MAX_PHY_TESTS];
        struct efx_loopback_self_tests loopback[LOOPBACK_TEST_MAX + 1];
 };
 
index f8c6771e66d861488bd12fc69d51346a0fedebb6..1619fb5a64f5c0574b3dca25cdb49abd7d5f5571 100644 (file)
@@ -106,16 +106,11 @@ static int siena_probe_port(struct efx_nic *efx)
        efx->mdio.mdio_read = siena_mdio_read;
        efx->mdio.mdio_write = siena_mdio_write;
 
-       /* Fill out MDIO structure and loopback modes */
+       /* Fill out MDIO structure, loopback modes, and initial link state */
        rc = efx->phy_op->probe(efx);
        if (rc != 0)
                return rc;
 
-       /* Initial assumption */
-       efx->link_state.speed = 10000;
-       efx->link_state.fd = true;
-       efx->wanted_fc = EFX_FC_RX | EFX_FC_TX;
-
        /* Allocate buffer for stats */
        rc = efx_nic_alloc_buffer(efx, &efx->stats_buffer,
                                  MC_CMD_MAC_NSTATS * sizeof(u64));
@@ -139,7 +134,7 @@ void siena_remove_port(struct efx_nic *efx)
 
 static const struct efx_nic_register_test siena_register_tests[] = {
        { FR_AZ_ADR_REGION,
-         EFX_OWORD32(0x0001FFFF, 0x0001FFFF, 0x0001FFFF, 0x0001FFFF) },
+         EFX_OWORD32(0x0003FFFF, 0x0003FFFF, 0x0003FFFF, 0x0003FFFF) },
        { FR_CZ_USR_EV_CFG,
          EFX_OWORD32(0x000103FF, 0x00000000, 0x00000000, 0x00000000) },
        { FR_AZ_RX_CFG,
@@ -181,6 +176,12 @@ static int siena_test_registers(struct efx_nic *efx)
 
 static int siena_reset_hw(struct efx_nic *efx, enum reset_type method)
 {
+       int rc;
+
+       /* Recover from a failed assertion pre-reset */
+       rc = efx_mcdi_handle_assertion(efx);
+       if (rc)
+               return rc;
 
        if (method == RESET_TYPE_WORLD)
                return efx_mcdi_reset_mc(efx);
@@ -582,6 +583,7 @@ struct efx_nic_type siena_a0_nic_type = {
        .set_wol = siena_set_wol,
        .resume_wol = siena_init_wol,
        .test_registers = siena_test_registers,
+       .test_nvram = efx_mcdi_nvram_test_all,
        .default_mac_ops = &efx_mcdi_mac_operations,
 
        .revision = EFX_REV_SIENA_A0,
index 3009c297c135a647e945b26fc3acfe38fc24237b..10db071bd8378c29822b4f360f7f729b16f3ccc1 100644 (file)
@@ -842,6 +842,7 @@ struct efx_phy_operations falcon_sfx7101_phy_ops = {
        .get_settings     = tenxpress_get_settings,
        .set_settings     = tenxpress_set_settings,
        .set_npage_adv    = sfx7101_set_npage_adv,
+       .test_alive       = efx_mdio_test_alive,
        .test_name        = sfx7101_test_name,
        .run_tests        = sfx7101_run_tests,
 };
@@ -856,6 +857,7 @@ struct efx_phy_operations falcon_sft9001_phy_ops = {
        .get_settings     = tenxpress_get_settings,
        .set_settings     = tenxpress_set_settings,
        .set_npage_adv    = sft9001_set_npage_adv,
+       .test_alive       = efx_mdio_test_alive,
        .test_name        = sft9001_test_name,
        .run_tests        = sft9001_run_tests,
 };
index 7402b858cab7f306a77fa2922bb38fb1e5d719eb..42a35f086a9f5dccc9fc466340525f6154918df7 100644 (file)
@@ -1473,13 +1473,9 @@ static int sh_eth_drv_probe(struct platform_device *pdev)
        if (ret)
                goto out_unregister;
 
-       /* pritnt device infomation */
-       pr_info("Base address at 0x%x, ",
-              (u32)ndev->base_addr);
-
-       for (i = 0; i < 5; i++)
-               printk("%02X:", ndev->dev_addr[i]);
-       printk("%02X, IRQ %d.\n", ndev->dev_addr[i], ndev->irq);
+       /* print device infomation */
+       pr_info("Base address at 0x%x, %pM, IRQ %d.\n",
+              (u32)ndev->base_addr, ndev->dev_addr, ndev->irq);
 
        platform_set_drvdata(pdev, ndev);
 
index 31233b4c44a0ff01b19244ff11603bc16ff077b8..626de766443a914a2b7062bca641fbfef81c91cc 100644 (file)
@@ -334,7 +334,7 @@ static const struct {
        { "SiS 191 PCI Gigabit Ethernet adapter" },
 };
 
-static struct pci_device_id sis190_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(sis190_pci_tbl) = {
        { PCI_DEVICE(PCI_VENDOR_ID_SI, 0x0190), 0, 0, 0 },
        { PCI_DEVICE(PCI_VENDOR_ID_SI, 0x0191), 0, 0, 1 },
        { 0, },
index 7360d4bbf75e9c537bdc6838627961787921c823..20c5ce4748914c7b621b7c4714aec0dbed8dc9d9 100644 (file)
@@ -106,7 +106,7 @@ static const char * card_names[] = {
        "SiS 900 PCI Fast Ethernet",
        "SiS 7016 PCI Fast Ethernet"
 };
-static struct pci_device_id sis900_pci_tbl [] = {
+static DEFINE_PCI_DEVICE_TABLE(sis900_pci_tbl) = {
        {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_900,
         PCI_ANY_ID, PCI_ANY_ID, 0, 0, SIS_900},
        {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_7016,
index db216a7285035e24b742435cb93eb38bb5174939..6b955a4f19b2d25615b27e5e51b1be9ba27c4713 100644 (file)
@@ -149,7 +149,7 @@ extern void mac_drv_rx_mode(struct s_smc *smc, int mode);
 extern void mac_drv_clear_rx_queue(struct s_smc *smc);
 extern void enable_tx_irq(struct s_smc *smc, u_short queue);
 
-static struct pci_device_id skfddi_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(skfddi_pci_tbl) = {
        { PCI_VENDOR_ID_SK, PCI_DEVICE_ID_SK_FP, PCI_ANY_ID, PCI_ANY_ID, },
        { }                     /* Terminating entry */
 };
@@ -435,13 +435,7 @@ static  int skfp_driver_init(struct net_device *dev)
                goto fail;
        }
        read_address(smc, NULL);
-       pr_debug(KERN_INFO "HW-Addr: %02x %02x %02x %02x %02x %02x\n",
-              smc->hw.fddi_canon_addr.a[0],
-              smc->hw.fddi_canon_addr.a[1],
-              smc->hw.fddi_canon_addr.a[2],
-              smc->hw.fddi_canon_addr.a[3],
-              smc->hw.fddi_canon_addr.a[4],
-              smc->hw.fddi_canon_addr.a[5]);
+       pr_debug(KERN_INFO "HW-Addr: %pMF\n", smc->hw.fddi_canon_addr.a);
        memcpy(dev->dev_addr, smc->hw.fddi_canon_addr.a, 6);
 
        smt_reset_defaults(smc, 0);
@@ -890,15 +884,8 @@ static void skfp_ctl_set_multicast_list_wo_lock(struct net_device *dev)
                                                          (struct fddi_addr *)dmi->dmi_addr, 
                                                          1);
 
-                                       pr_debug(KERN_INFO "ENABLE MC ADDRESS:");
-                                       pr_debug(" %02x %02x %02x ",
-                                              dmi->dmi_addr[0],
-                                              dmi->dmi_addr[1],
-                                              dmi->dmi_addr[2]);
-                                       pr_debug("%02x %02x %02x\n",
-                                              dmi->dmi_addr[3],
-                                              dmi->dmi_addr[4],
-                                              dmi->dmi_addr[5]);
+                                       pr_debug(KERN_INFO "ENABLE MC ADDRESS: %pMF\n",
+                                               dmi->dmi_addr);
                                        dmi = dmi->next;
                                }       // for
 
index 379a3dc001637b3b0a0420dbbe0e616bf1daf5d1..5ff46eb18d0c4405d23a3e46c84afede152f9374 100644 (file)
@@ -78,7 +78,7 @@ static int debug = -1;        /* defaults above */
 module_param(debug, int, 0);
 MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
 
-static const struct pci_device_id skge_id_table[] = {
+static DEFINE_PCI_DEVICE_TABLE(skge_id_table) = {
        { PCI_DEVICE(PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C940) },
        { PCI_DEVICE(PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C940B) },
        { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_GE) },
index 67249c3c9f5046a471f1790745b2b0ccc83fb0c9..a6ddfc1a9cb2b8e1e1f8794b1d388f7aa9dde9ca 100644 (file)
@@ -3188,7 +3188,9 @@ static void sky2_reset(struct sky2_hw *hw)
 static void sky2_detach(struct net_device *dev)
 {
        if (netif_running(dev)) {
+               netif_tx_lock(dev);
                netif_device_detach(dev);       /* stop txq */
+               netif_tx_unlock(dev);
                sky2_down(dev);
        }
 }
@@ -3864,6 +3866,50 @@ static int sky2_get_regs_len(struct net_device *dev)
        return 0x4000;
 }
 
+static int sky2_reg_access_ok(struct sky2_hw *hw, unsigned int b)
+{
+       /* This complicated switch statement is to make sure and
+        * only access regions that are unreserved.
+        * Some blocks are only valid on dual port cards.
+        */
+       switch (b) {
+       /* second port */
+       case 5:         /* Tx Arbiter 2 */
+       case 9:         /* RX2 */
+       case 14 ... 15: /* TX2 */
+       case 17: case 19: /* Ram Buffer 2 */
+       case 22 ... 23: /* Tx Ram Buffer 2 */
+       case 25:        /* Rx MAC Fifo 1 */
+       case 27:        /* Tx MAC Fifo 2 */
+       case 31:        /* GPHY 2 */
+       case 40 ... 47: /* Pattern Ram 2 */
+       case 52: case 54: /* TCP Segmentation 2 */
+       case 112 ... 116: /* GMAC 2 */
+               return hw->ports > 1;
+
+       case 0:         /* Control */
+       case 2:         /* Mac address */
+       case 4:         /* Tx Arbiter 1 */
+       case 7:         /* PCI express reg */
+       case 8:         /* RX1 */
+       case 12 ... 13: /* TX1 */
+       case 16: case 18:/* Rx Ram Buffer 1 */
+       case 20 ... 21: /* Tx Ram Buffer 1 */
+       case 24:        /* Rx MAC Fifo 1 */
+       case 26:        /* Tx MAC Fifo 1 */
+       case 28 ... 29: /* Descriptor and status unit */
+       case 30:        /* GPHY 1*/
+       case 32 ... 39: /* Pattern Ram 1 */
+       case 48: case 50: /* TCP Segmentation 1 */
+       case 56 ... 60: /* PCI space */
+       case 80 ... 84: /* GMAC 1 */
+               return 1;
+
+       default:
+               return 0;
+       }
+}
+
 /*
  * Returns copy of control register region
  * Note: ethtool_get_regs always provides full size (16k) buffer
@@ -3878,55 +3924,13 @@ static void sky2_get_regs(struct net_device *dev, struct ethtool_regs *regs,
        regs->version = 1;
 
        for (b = 0; b < 128; b++) {
-               /* This complicated switch statement is to make sure and
-                * only access regions that are unreserved.
-                * Some blocks are only valid on dual port cards.
-                * and block 3 has some special diagnostic registers that
-                * are poison.
-                */
-               switch (b) {
-               case 3:
-                       /* skip diagnostic ram region */
+               /* skip poisonous diagnostic ram region in block 3 */
+               if (b == 3)
                        memcpy_fromio(p + 0x10, io + 0x10, 128 - 0x10);
-                       break;
-
-               /* dual port cards only */
-               case 5:         /* Tx Arbiter 2 */
-               case 9:         /* RX2 */
-               case 14 ... 15: /* TX2 */
-               case 17: case 19: /* Ram Buffer 2 */
-               case 22 ... 23: /* Tx Ram Buffer 2 */
-               case 25:        /* Rx MAC Fifo 1 */
-               case 27:        /* Tx MAC Fifo 2 */
-               case 31:        /* GPHY 2 */
-               case 40 ... 47: /* Pattern Ram 2 */
-               case 52: case 54: /* TCP Segmentation 2 */
-               case 112 ... 116: /* GMAC 2 */
-                       if (sky2->hw->ports == 1)
-                               goto reserved;
-                       /* fall through */
-               case 0:         /* Control */
-               case 2:         /* Mac address */
-               case 4:         /* Tx Arbiter 1 */
-               case 7:         /* PCI express reg */
-               case 8:         /* RX1 */
-               case 12 ... 13: /* TX1 */
-               case 16: case 18:/* Rx Ram Buffer 1 */
-               case 20 ... 21: /* Tx Ram Buffer 1 */
-               case 24:        /* Rx MAC Fifo 1 */
-               case 26:        /* Tx MAC Fifo 1 */
-               case 28 ... 29: /* Descriptor and status unit */
-               case 30:        /* GPHY 1*/
-               case 32 ... 39: /* Pattern Ram 1 */
-               case 48: case 50: /* TCP Segmentation 1 */
-               case 56 ... 60: /* PCI space */
-               case 80 ... 84: /* GMAC 1 */
+               else if (sky2_reg_access_ok(sky2->hw, b))
                        memcpy_fromio(p, io, 128);
-                       break;
-               default:
-reserved:
+               else
                        memset(p, 0, 128);
-               }
 
                p += 128;
                io += 128;
index 365d79c7d834b7b22f6f342ad9615a75b23f315d..54cb303443e0024824db29e0a35f38ea635049ed 100644 (file)
@@ -2156,7 +2156,7 @@ struct tx_ring_info {
        struct sk_buff  *skb;
        unsigned long flags;
 #define TX_MAP_SINGLE   0x0001
-#define TX_MAP_PAGE     000002
+#define TX_MAP_PAGE     0x0002
        DECLARE_PCI_UNMAP_ADDR(mapaddr);
        DECLARE_PCI_UNMAP_LEN(maplen);
 };
index 44ebbaa7457bbaeb4a9633256f98f879280e79a1..3c5a4f52345c6b49c185c6c7c47a47c2f8e97e8d 100644 (file)
@@ -2017,10 +2017,8 @@ static int __devinit smc911x_probe(struct net_device *dev)
                                        "set using ifconfig\n", dev->name);
                } else {
                        /* Print the Ethernet address */
-                       printk("%s: Ethernet addr: ", dev->name);
-                       for (i = 0; i < 5; i++)
-                               printk("%2.2x:", dev->dev_addr[i]);
-                       printk("%2.2x\n", dev->dev_addr[5]);
+                       printk("%s: Ethernet addr: %pM\n",
+                               dev->name, dev->dev_addr);
                }
 
                if (lp->phy_type == 0) {
index 12f0f5d74e3c74b7181c39ba6a65d897d0b2be92..1495a5dd4b469e7cd70552adafd199aedf09ad8f 100644 (file)
@@ -80,7 +80,7 @@ struct smsc9420_pdata {
        int last_carrier;
 };
 
-static const struct pci_device_id smsc9420_id_table[] = {
+static DEFINE_PCI_DEVICE_TABLE(smsc9420_id_table) = {
        { PCI_VENDOR_ID_9420, PCI_DEVICE_ID_9420, PCI_ANY_ID, PCI_ANY_ID, },
        { 0, }
 };
index 218524857bfc9d01b4b1ef7c132712c6e5bebdb6..16191998ac67bfc3c9d9378376f4ab4d0e0ac60e 100644 (file)
@@ -72,7 +72,7 @@ MODULE_PARM_DESC(tx_descriptors, "number of descriptors used " \
 
 char spider_net_driver_name[] = "spidernet";
 
-static struct pci_device_id spider_net_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(spider_net_pci_tbl) = {
        { PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_SPIDER_NET,
          PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
        { 0, }
index f9521136a869bde8e313072c26f5979e2f84277a..d0556a9b456c070c8b186bcef5883a9ed61aa8a5 100644 (file)
@@ -301,7 +301,7 @@ enum chipset {
        CH_6915 = 0,
 };
 
-static struct pci_device_id starfire_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(starfire_pci_tbl) = {
        { 0x9004, 0x6915, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_6915 },
        { 0, }
 };
index 35eaa5251d7f35e0f130faace0909134f4933941..fb287649a3054a16e55bda06027be354431e7990 100644 (file)
@@ -4,8 +4,9 @@ config STMMAC_ETH
        select PHYLIB
        depends on NETDEVICES && CPU_SUBTYPE_ST40
        help
-         This is the driver for the ST MAC 10/100/1000 on-chip Ethernet
-         controllers. ST Ethernet IPs are built around a Synopsys IP Core.
+         This is the driver for the Ethernet IPs are built around a
+         Synopsys IP Core and fully tested on the STMicroelectronics
+         platforms.
 
 if STMMAC_ETH
 
@@ -32,7 +33,8 @@ config STMMAC_TIMER
        default n
        help
          Use an external timer for mitigating the number of network
-         interrupts.
+         interrupts. Currently, for SH architectures, it is possible
+         to use the TMU channel 2 and the SH-RTC device.
 
 choice
         prompt "Select Timer device"
index b2d7a5564dfabbdaec027175b79c69a2c63336cb..c776af15fe1a690ba65a49e15fd92db895dadc94 100644 (file)
@@ -1,4 +1,5 @@
 obj-$(CONFIG_STMMAC_ETH) += stmmac.o
 stmmac-$(CONFIG_STMMAC_TIMER) += stmmac_timer.o
-stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o \
-               mac100.o  gmac.o $(stmmac-y)
+stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o     \
+             dwmac_lib.o dwmac1000_core.o  dwmac1000_dma.o     \
+             dwmac100.o $(stmmac-y)
index e49e5188e88724c69212faa8e6f36726e15b1056..7267bcd43d068b290922a1981d3a1401875fbce6 100644 (file)
 *******************************************************************************/
 
 #include "descs.h"
-#include <linux/io.h>
-
-/* *********************************************
-   DMA CRS Control and Status Register Mapping
- * *********************************************/
-#define DMA_BUS_MODE           0x00001000      /* Bus Mode */
-#define DMA_XMT_POLL_DEMAND    0x00001004      /* Transmit Poll Demand */
-#define DMA_RCV_POLL_DEMAND    0x00001008      /* Received Poll Demand */
-#define DMA_RCV_BASE_ADDR      0x0000100c      /* Receive List Base */
-#define DMA_TX_BASE_ADDR       0x00001010      /* Transmit List Base */
-#define DMA_STATUS             0x00001014      /* Status Register */
-#define DMA_CONTROL            0x00001018      /* Ctrl (Operational Mode) */
-#define DMA_INTR_ENA           0x0000101c      /* Interrupt Enable */
-#define DMA_MISSED_FRAME_CTR   0x00001020      /* Missed Frame Counter */
-#define DMA_CUR_TX_BUF_ADDR    0x00001050      /* Current Host Tx Buffer */
-#define DMA_CUR_RX_BUF_ADDR    0x00001054      /* Current Host Rx Buffer */
-
-/* ********************************
-   DMA Control register defines
- * ********************************/
-#define DMA_CONTROL_ST         0x00002000      /* Start/Stop Transmission */
-#define DMA_CONTROL_SR         0x00000002      /* Start/Stop Receive */
-
-/* **************************************
-   DMA Interrupt Enable register defines
- * **************************************/
-/**** NORMAL INTERRUPT ****/
-#define DMA_INTR_ENA_NIE 0x00010000    /* Normal Summary */
-#define DMA_INTR_ENA_TIE 0x00000001    /* Transmit Interrupt */
-#define DMA_INTR_ENA_TUE 0x00000004    /* Transmit Buffer Unavailable */
-#define DMA_INTR_ENA_RIE 0x00000040    /* Receive Interrupt */
-#define DMA_INTR_ENA_ERE 0x00004000    /* Early Receive */
-
-#define DMA_INTR_NORMAL        (DMA_INTR_ENA_NIE | DMA_INTR_ENA_RIE | \
-                       DMA_INTR_ENA_TIE)
-
-/**** ABNORMAL INTERRUPT ****/
-#define DMA_INTR_ENA_AIE 0x00008000    /* Abnormal Summary */
-#define DMA_INTR_ENA_FBE 0x00002000    /* Fatal Bus Error */
-#define DMA_INTR_ENA_ETE 0x00000400    /* Early Transmit */
-#define DMA_INTR_ENA_RWE 0x00000200    /* Receive Watchdog */
-#define DMA_INTR_ENA_RSE 0x00000100    /* Receive Stopped */
-#define DMA_INTR_ENA_RUE 0x00000080    /* Receive Buffer Unavailable */
-#define DMA_INTR_ENA_UNE 0x00000020    /* Tx Underflow */
-#define DMA_INTR_ENA_OVE 0x00000010    /* Receive Overflow */
-#define DMA_INTR_ENA_TJE 0x00000008    /* Transmit Jabber */
-#define DMA_INTR_ENA_TSE 0x00000002    /* Transmit Stopped */
-
-#define DMA_INTR_ABNORMAL      (DMA_INTR_ENA_AIE | DMA_INTR_ENA_FBE | \
-                               DMA_INTR_ENA_UNE)
-
-/* DMA default interrupt mask */
-#define DMA_INTR_DEFAULT_MASK  (DMA_INTR_NORMAL | DMA_INTR_ABNORMAL)
-
-/* ****************************
- *  DMA Status register defines
- * ****************************/
-#define DMA_STATUS_GPI         0x10000000      /* PMT interrupt */
-#define DMA_STATUS_GMI         0x08000000      /* MMC interrupt */
-#define DMA_STATUS_GLI         0x04000000      /* GMAC Line interface int. */
-#define DMA_STATUS_GMI         0x08000000
-#define DMA_STATUS_GLI         0x04000000
-#define DMA_STATUS_EB_MASK     0x00380000      /* Error Bits Mask */
-#define DMA_STATUS_EB_TX_ABORT 0x00080000      /* Error Bits - TX Abort */
-#define DMA_STATUS_EB_RX_ABORT 0x00100000      /* Error Bits - RX Abort */
-#define DMA_STATUS_TS_MASK     0x00700000      /* Transmit Process State */
-#define DMA_STATUS_TS_SHIFT    20
-#define DMA_STATUS_RS_MASK     0x000e0000      /* Receive Process State */
-#define DMA_STATUS_RS_SHIFT    17
-#define DMA_STATUS_NIS 0x00010000      /* Normal Interrupt Summary */
-#define DMA_STATUS_AIS 0x00008000      /* Abnormal Interrupt Summary */
-#define DMA_STATUS_ERI 0x00004000      /* Early Receive Interrupt */
-#define DMA_STATUS_FBI 0x00002000      /* Fatal Bus Error Interrupt */
-#define DMA_STATUS_ETI 0x00000400      /* Early Transmit Interrupt */
-#define DMA_STATUS_RWT 0x00000200      /* Receive Watchdog Timeout */
-#define DMA_STATUS_RPS 0x00000100      /* Receive Process Stopped */
-#define DMA_STATUS_RU  0x00000080      /* Receive Buffer Unavailable */
-#define DMA_STATUS_RI  0x00000040      /* Receive Interrupt */
-#define DMA_STATUS_UNF 0x00000020      /* Transmit Underflow */
-#define DMA_STATUS_OVF 0x00000010      /* Receive Overflow */
-#define DMA_STATUS_TJT 0x00000008      /* Transmit Jabber Timeout */
-#define DMA_STATUS_TU  0x00000004      /* Transmit Buffer Unavailable */
-#define DMA_STATUS_TPS 0x00000002      /* Transmit Process Stopped */
-#define DMA_STATUS_TI  0x00000001      /* Transmit Interrupt */
-
-/* Other defines */
-#define HASH_TABLE_SIZE 64
-#define PAUSE_TIME 0x200
-
-/* Flow Control defines */
-#define FLOW_OFF       0
-#define FLOW_RX                1
-#define FLOW_TX                2
-#define FLOW_AUTO      (FLOW_TX | FLOW_RX)
-
-/* DMA STORE-AND-FORWARD Operation Mode */
-#define SF_DMA_MODE 1
-
-#define HW_CSUM 1
-#define NO_HW_CSUM 0
-
-/* GMAC TX FIFO is 8K, Rx FIFO is 16K */
-#define BUF_SIZE_16KiB 16384
-#define BUF_SIZE_8KiB 8192
-#define BUF_SIZE_4KiB 4096
-#define BUF_SIZE_2KiB 2048
-
-/* Power Down and WOL */
-#define PMT_NOT_SUPPORTED 0
-#define PMT_SUPPORTED 1
-
-/* Common MAC defines */
-#define MAC_CTRL_REG           0x00000000      /* MAC Control */
-#define MAC_ENABLE_TX          0x00000008      /* Transmitter Enable */
-#define MAC_RNABLE_RX          0x00000004      /* Receiver Enable */
-
-/* MAC Management Counters register */
-#define MMC_CONTROL            0x00000100      /* MMC Control */
-#define MMC_HIGH_INTR          0x00000104      /* MMC High Interrupt */
-#define MMC_LOW_INTR           0x00000108      /* MMC Low Interrupt */
-#define MMC_HIGH_INTR_MASK     0x0000010c      /* MMC High Interrupt Mask */
-#define MMC_LOW_INTR_MASK      0x00000110      /* MMC Low Interrupt Mask */
-
-#define MMC_CONTROL_MAX_FRM_MASK       0x0003ff8       /* Maximum Frame Size */
-#define MMC_CONTROL_MAX_FRM_SHIFT      3
-#define MMC_CONTROL_MAX_FRAME          0x7FF
+#include <linux/netdevice.h>
 
 struct stmmac_extra_stats {
        /* Transmit errors */
@@ -198,66 +73,62 @@ struct stmmac_extra_stats {
        unsigned long normal_irq_n;
 };
 
-/* GMAC core can compute the checksums in HW. */
-enum rx_frame_status {
+#define HASH_TABLE_SIZE 64
+#define PAUSE_TIME 0x200
+
+/* Flow Control defines */
+#define FLOW_OFF       0
+#define FLOW_RX                1
+#define FLOW_TX                2
+#define FLOW_AUTO      (FLOW_TX | FLOW_RX)
+
+#define SF_DMA_MODE 1 /* DMA STORE-AND-FORWARD Operation Mode */
+
+#define HW_CSUM 1
+#define NO_HW_CSUM 0
+enum rx_frame_status { /* IPC status */
        good_frame = 0,
        discard_frame = 1,
        csum_none = 2,
 };
 
-static inline void stmmac_set_mac_addr(unsigned long ioaddr, u8 addr[6],
-                        unsigned int high, unsigned int low)
-{
-       unsigned long data;
-
-       data = (addr[5] << 8) | addr[4];
-       writel(data, ioaddr + high);
-       data = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0];
-       writel(data, ioaddr + low);
+enum tx_dma_irq_status {
+       tx_hard_error = 1,
+       tx_hard_error_bump_tc = 2,
+       handle_tx_rx = 3,
+};
 
-       return;
-}
+/* GMAC TX FIFO is 8K, Rx FIFO is 16K */
+#define BUF_SIZE_16KiB 16384
+#define BUF_SIZE_8KiB 8192
+#define BUF_SIZE_4KiB 4096
+#define BUF_SIZE_2KiB 2048
 
-static inline void stmmac_get_mac_addr(unsigned long ioaddr,
-                               unsigned char *addr, unsigned int high,
-                               unsigned int low)
-{
-       unsigned int hi_addr, lo_addr;
+/* Power Down and WOL */
+#define PMT_NOT_SUPPORTED 0
+#define PMT_SUPPORTED 1
 
-       /* Read the MAC address from the hardware */
-       hi_addr = readl(ioaddr + high);
-       lo_addr = readl(ioaddr + low);
+/* Common MAC defines */
+#define MAC_CTRL_REG           0x00000000      /* MAC Control */
+#define MAC_ENABLE_TX          0x00000008      /* Transmitter Enable */
+#define MAC_RNABLE_RX          0x00000004      /* Receiver Enable */
 
-       /* Extract the MAC address from the high and low words */
-       addr[0] = lo_addr & 0xff;
-       addr[1] = (lo_addr >> 8) & 0xff;
-       addr[2] = (lo_addr >> 16) & 0xff;
-       addr[3] = (lo_addr >> 24) & 0xff;
-       addr[4] = hi_addr & 0xff;
-       addr[5] = (hi_addr >> 8) & 0xff;
+/* MAC Management Counters register */
+#define MMC_CONTROL            0x00000100      /* MMC Control */
+#define MMC_HIGH_INTR          0x00000104      /* MMC High Interrupt */
+#define MMC_LOW_INTR           0x00000108      /* MMC Low Interrupt */
+#define MMC_HIGH_INTR_MASK     0x0000010c      /* MMC High Interrupt Mask */
+#define MMC_LOW_INTR_MASK      0x00000110      /* MMC Low Interrupt Mask */
 
-       return;
-}
+#define MMC_CONTROL_MAX_FRM_MASK       0x0003ff8       /* Maximum Frame Size */
+#define MMC_CONTROL_MAX_FRM_SHIFT      3
+#define MMC_CONTROL_MAX_FRAME          0x7FF
 
-struct stmmac_ops {
-       /* MAC core initialization */
-       void (*core_init) (unsigned long ioaddr) ____cacheline_aligned;
-       /* DMA core initialization */
-       int (*dma_init) (unsigned long ioaddr, int pbl, u32 dma_tx, u32 dma_rx);
-       /* Dump MAC registers */
-       void (*dump_mac_regs) (unsigned long ioaddr);
-       /* Dump DMA registers */
-       void (*dump_dma_regs) (unsigned long 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);
-       /* To track extra statistic (if supported) */
-       void (*dma_diagnostic_fr) (void *data, struct stmmac_extra_stats *x,
-                                  unsigned long ioaddr);
-       /* RX descriptor ring initialization */
+struct stmmac_desc_ops {
+       /* DMA RX descriptor ring initialization */
        void (*init_rx_desc) (struct dma_desc *p, unsigned int ring_size,
-                               int disable_rx_ic);
-       /* TX descriptor ring initialization */
+                             int disable_rx_ic);
+       /* DMA TX descriptor ring initialization */
        void (*init_tx_desc) (struct dma_desc *p, unsigned int ring_size);
 
        /* Invoked by the xmit function to prepare the tx descriptor */
@@ -281,7 +152,6 @@ struct stmmac_ops {
        /* Get the buffer size from the descriptor */
        int (*get_tx_len) (struct dma_desc *p);
        /* Handle extra events on specific interrupts hw dependent */
-       void (*host_irq_status) (unsigned long ioaddr);
        int (*get_rx_owner) (struct dma_desc *p);
        void (*set_rx_owner) (struct dma_desc *p);
        /* Get the receive frame size */
@@ -289,6 +159,37 @@ struct stmmac_ops {
        /* Return the reception status looking at the RDES1 */
        int (*rx_status) (void *data, struct stmmac_extra_stats *x,
                          struct dma_desc *p);
+};
+
+struct stmmac_dma_ops {
+       /* DMA core initialization */
+       int (*init) (unsigned long ioaddr, int pbl, u32 dma_tx, u32 dma_rx);
+       /* Dump DMA registers */
+       void (*dump_regs) (unsigned long 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);
+       /* 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,
+                             struct stmmac_extra_stats *x);
+};
+
+struct stmmac_ops {
+       /* MAC core initialization */
+       void (*core_init) (unsigned long ioaddr) ____cacheline_aligned;
+       /* Dump MAC registers */
+       void (*dump_regs) (unsigned long ioaddr);
+       /* Handle extra events on specific interrupts hw dependent */
+       void (*host_irq_status) (unsigned long ioaddr);
        /* Multicast filter setting */
        void (*set_filter) (struct net_device *dev);
        /* Flow control setting */
@@ -298,9 +199,9 @@ struct stmmac_ops {
        void (*pmt) (unsigned long ioaddr, unsigned long mode);
        /* Set/Get Unicast MAC addresses */
        void (*set_umac_addr) (unsigned long ioaddr, unsigned char *addr,
-                            unsigned int reg_n);
+                              unsigned int reg_n);
        void (*get_umac_addr) (unsigned long ioaddr, unsigned char *addr,
-                            unsigned int reg_n);
+                              unsigned int reg_n);
 };
 
 struct mac_link {
@@ -314,17 +215,19 @@ struct mii_regs {
        unsigned int data;      /* MII Data */
 };
 
-struct hw_cap {
-       unsigned int version;   /* Core Version register (GMAC) */
-       unsigned int pmt;       /* Power-Down mode (GMAC) */
+struct mac_device_info {
+       struct stmmac_ops       *mac;
+       struct stmmac_desc_ops  *desc;
+       struct stmmac_dma_ops   *dma;
+       unsigned int pmt;       /* support Power-Down */
+       struct mii_regs mii;    /* MII register Addresses */
        struct mac_link link;
-       struct mii_regs mii;
 };
 
-struct mac_device_info {
-       struct hw_cap hw;
-       struct stmmac_ops *ops;
-};
+struct mac_device_info *dwmac1000_setup(unsigned long addr);
+struct mac_device_info *dwmac100_setup(unsigned long addr);
 
-struct mac_device_info *gmac_setup(unsigned long addr);
-struct mac_device_info *mac100_setup(unsigned long addr);
+extern void stmmac_set_mac_addr(unsigned long ioaddr, u8 addr[6],
+                               unsigned int high, unsigned int low);
+extern void stmmac_get_mac_addr(unsigned long ioaddr, unsigned char *addr,
+                               unsigned int high, unsigned int low);
index 6d2a0b2f5e578dca2bf3bbc6df28e5595b60693e..63a03e26469442b77e528027932c9e570a51392b 100644 (file)
@@ -1,6 +1,6 @@
 /*******************************************************************************
-  Header File to describe the DMA descriptors
-  Use enhanced descriptors in case of GMAC Cores.
+  Header File to describe the DMA descriptors.
+  Enhanced descriptors have been in case of DWMAC1000 Cores.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
similarity index 69%
rename from drivers/net/stmmac/mac100.c
rename to drivers/net/stmmac/dwmac100.c
index 625171b6062b1af4b9f00528ca9b59e6adee73f4..82dde774d4c511e4f7a831ad11a5394420ebe01e 100644 (file)
   Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
 *******************************************************************************/
 
-#include <linux/netdevice.h>
 #include <linux/crc32.h>
 #include <linux/mii.h>
 #include <linux/phy.h>
 
 #include "common.h"
-#include "mac100.h"
+#include "dwmac100.h"
+#include "dwmac_dma.h"
 
-#undef MAC100_DEBUG
-/*#define MAC100_DEBUG*/
-#ifdef MAC100_DEBUG
+#undef DWMAC100_DEBUG
+/*#define DWMAC100_DEBUG*/
+#ifdef DWMAC100_DEBUG
 #define DBG(fmt, args...)  printk(fmt, ## args)
 #else
 #define DBG(fmt, args...)  do { } while (0)
 #endif
 
-static void mac100_core_init(unsigned long ioaddr)
+static void dwmac100_core_init(unsigned long ioaddr)
 {
        u32 value = readl(ioaddr + MAC_CONTROL);
 
@@ -54,43 +54,43 @@ static void mac100_core_init(unsigned long ioaddr)
        return;
 }
 
-static void mac100_dump_mac_regs(unsigned long ioaddr)
+static void dwmac100_dump_mac_regs(unsigned long ioaddr)
 {
        pr_info("\t----------------------------------------------\n"
-              "\t  MAC100 CSR (base addr = 0x%8x)\n"
-              "\t----------------------------------------------\n",
-              (unsigned int)ioaddr);
+               "\t  DWMAC 100 CSR (base addr = 0x%8x)\n"
+               "\t----------------------------------------------\n",
+               (unsigned int)ioaddr);
        pr_info("\tcontrol reg (offset 0x%x): 0x%08x\n", MAC_CONTROL,
-              readl(ioaddr + MAC_CONTROL));
+               readl(ioaddr + MAC_CONTROL));
        pr_info("\taddr HI (offset 0x%x): 0x%08x\n ", MAC_ADDR_HIGH,
-              readl(ioaddr + MAC_ADDR_HIGH));
+               readl(ioaddr + MAC_ADDR_HIGH));
        pr_info("\taddr LO (offset 0x%x): 0x%08x\n", MAC_ADDR_LOW,
-              readl(ioaddr + MAC_ADDR_LOW));
+               readl(ioaddr + MAC_ADDR_LOW));
        pr_info("\tmulticast hash HI (offset 0x%x): 0x%08x\n",
-                       MAC_HASH_HIGH, readl(ioaddr + MAC_HASH_HIGH));
+               MAC_HASH_HIGH, readl(ioaddr + MAC_HASH_HIGH));
        pr_info("\tmulticast hash LO (offset 0x%x): 0x%08x\n",
-                       MAC_HASH_LOW, readl(ioaddr + MAC_HASH_LOW));
+               MAC_HASH_LOW, readl(ioaddr + MAC_HASH_LOW));
        pr_info("\tflow control (offset 0x%x): 0x%08x\n",
                MAC_FLOW_CTRL, readl(ioaddr + MAC_FLOW_CTRL));
        pr_info("\tVLAN1 tag (offset 0x%x): 0x%08x\n", MAC_VLAN1,
-              readl(ioaddr + MAC_VLAN1));
+               readl(ioaddr + MAC_VLAN1));
        pr_info("\tVLAN2 tag (offset 0x%x): 0x%08x\n", MAC_VLAN2,
-              readl(ioaddr + MAC_VLAN2));
+               readl(ioaddr + MAC_VLAN2));
        pr_info("\n\tMAC management counter registers\n");
        pr_info("\t MMC crtl (offset 0x%x): 0x%08x\n",
-              MMC_CONTROL, readl(ioaddr + MMC_CONTROL));
+               MMC_CONTROL, readl(ioaddr + MMC_CONTROL));
        pr_info("\t MMC High Interrupt (offset 0x%x): 0x%08x\n",
-              MMC_HIGH_INTR, readl(ioaddr + MMC_HIGH_INTR));
+               MMC_HIGH_INTR, readl(ioaddr + MMC_HIGH_INTR));
        pr_info("\t MMC Low Interrupt (offset 0x%x): 0x%08x\n",
-              MMC_LOW_INTR, readl(ioaddr + MMC_LOW_INTR));
+               MMC_LOW_INTR, readl(ioaddr + MMC_LOW_INTR));
        pr_info("\t MMC High Interrupt Mask (offset 0x%x): 0x%08x\n",
-              MMC_HIGH_INTR_MASK, readl(ioaddr + MMC_HIGH_INTR_MASK));
+               MMC_HIGH_INTR_MASK, readl(ioaddr + MMC_HIGH_INTR_MASK));
        pr_info("\t MMC Low Interrupt Mask (offset 0x%x): 0x%08x\n",
-              MMC_LOW_INTR_MASK, readl(ioaddr + MMC_LOW_INTR_MASK));
+               MMC_LOW_INTR_MASK, readl(ioaddr + MMC_LOW_INTR_MASK));
        return;
 }
 
-static int mac100_dma_init(unsigned long ioaddr, int pbl, u32 dma_tx,
+static int dwmac100_dma_init(unsigned long ioaddr, int pbl, u32 dma_tx,
                           u32 dma_rx)
 {
        u32 value = readl(ioaddr + DMA_BUS_MODE);
@@ -117,7 +117,7 @@ static int mac100_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 mac100_dma_operation_mode(unsigned long ioaddr, int txmode,
+static void dwmac100_dma_operation_mode(unsigned long ioaddr, int txmode,
                                      int rxmode)
 {
        u32 csr6 = readl(ioaddr + DMA_CONTROL);
@@ -134,11 +134,11 @@ static void mac100_dma_operation_mode(unsigned long ioaddr, int txmode,
        return;
 }
 
-static void mac100_dump_dma_regs(unsigned long ioaddr)
+static void dwmac100_dump_dma_regs(unsigned long ioaddr)
 {
        int i;
 
-       DBG(KERN_DEBUG "MAC100 DMA CSR \n");
+       DBG(KERN_DEBUG "DWMAC 100 DMA CSR \n");
        for (i = 0; i < 9; i++)
                pr_debug("\t CSR%d (offset 0x%x): 0x%08x\n", i,
                       (DMA_BUS_MODE + i * 4),
@@ -151,8 +151,9 @@ static void mac100_dump_dma_regs(unsigned long ioaddr)
 }
 
 /* DMA controller has two counters to track the number of
-   the receive missed frames. */
-static void mac100_dma_diagnostic_fr(void *data, struct stmmac_extra_stats *x,
+ * the receive missed frames. */
+static void dwmac100_dma_diagnostic_fr(void *data,
+                                    struct stmmac_extra_stats *x,
                                     unsigned long ioaddr)
 {
        struct net_device_stats *stats = (struct net_device_stats *)data;
@@ -181,7 +182,8 @@ static void mac100_dma_diagnostic_fr(void *data, struct stmmac_extra_stats *x,
        return;
 }
 
-static int mac100_get_tx_frame_status(void *data, struct stmmac_extra_stats *x,
+static int dwmac100_get_tx_frame_status(void *data,
+                                     struct stmmac_extra_stats *x,
                                      struct dma_desc *p, unsigned long ioaddr)
 {
        int ret = 0;
@@ -217,7 +219,7 @@ static int mac100_get_tx_frame_status(void *data, struct stmmac_extra_stats *x,
        return ret;
 }
 
-static int mac100_get_tx_len(struct dma_desc *p)
+static int dwmac100_get_tx_len(struct dma_desc *p)
 {
        return p->des01.tx.buffer1_size;
 }
@@ -226,14 +228,15 @@ static int mac100_get_tx_len(struct dma_desc *p)
  * and, if required, updates the multicast statistics.
  * In case of success, it returns csum_none becasue the device
  * is not able to compute the csum in HW. */
-static int mac100_get_rx_frame_status(void *data, struct stmmac_extra_stats *x,
+static int dwmac100_get_rx_frame_status(void *data,
+                                     struct stmmac_extra_stats *x,
                                      struct dma_desc *p)
 {
        int ret = csum_none;
        struct net_device_stats *stats = (struct net_device_stats *)data;
 
        if (unlikely(p->des01.rx.last_descriptor == 0)) {
-               pr_warning("mac100 Error: Oversized Ethernet "
+               pr_warning("dwmac100 Error: Oversized Ethernet "
                           "frame spanned multiple buffers\n");
                stats->rx_length_errors++;
                return discard_frame;
@@ -276,24 +279,24 @@ static int mac100_get_rx_frame_status(void *data, struct stmmac_extra_stats *x,
        return ret;
 }
 
-static void mac100_irq_status(unsigned long ioaddr)
+static void dwmac100_irq_status(unsigned long ioaddr)
 {
        return;
 }
 
-static void mac100_set_umac_addr(unsigned long ioaddr, unsigned char *addr,
+static void dwmac100_set_umac_addr(unsigned long ioaddr, unsigned char *addr,
                          unsigned int reg_n)
 {
        stmmac_set_mac_addr(ioaddr, addr, MAC_ADDR_HIGH, MAC_ADDR_LOW);
 }
 
-static void mac100_get_umac_addr(unsigned long ioaddr, unsigned char *addr,
+static void dwmac100_get_umac_addr(unsigned long ioaddr, unsigned char *addr,
                          unsigned int reg_n)
 {
        stmmac_get_mac_addr(ioaddr, addr, MAC_ADDR_HIGH, MAC_ADDR_LOW);
 }
 
-static void mac100_set_filter(struct net_device *dev)
+static void dwmac100_set_filter(struct net_device *dev)
 {
        unsigned long ioaddr = dev->base_addr;
        u32 value = readl(ioaddr + MAC_CONTROL);
@@ -319,8 +322,8 @@ static void mac100_set_filter(struct net_device *dev)
                /* Perfect filter mode for physical address and Hash
                   filter for multicast */
                value |= MAC_CONTROL_HP;
-               value &= ~(MAC_CONTROL_PM | MAC_CONTROL_PR | MAC_CONTROL_IF
-                          | MAC_CONTROL_HO);
+               value &= ~(MAC_CONTROL_PM | MAC_CONTROL_PR |
+                          MAC_CONTROL_IF | MAC_CONTROL_HO);
 
                memset(mc_filter, 0, sizeof(mc_filter));
                for (i = 0, mclist = dev->mc_list;
@@ -347,7 +350,7 @@ static void mac100_set_filter(struct net_device *dev)
        return;
 }
 
-static void mac100_flow_ctrl(unsigned long ioaddr, unsigned int duplex,
+static void dwmac100_flow_ctrl(unsigned long ioaddr, unsigned int duplex,
                             unsigned int fc, unsigned int pause_time)
 {
        unsigned int flow = MAC_FLOW_CTRL_ENABLE;
@@ -359,13 +362,15 @@ static void mac100_flow_ctrl(unsigned long ioaddr, unsigned int duplex,
        return;
 }
 
-/* No PMT module supported in our SoC  for the Ethernet Controller. */
-static void mac100_pmt(unsigned long ioaddr, unsigned long mode)
+/* No PMT module supported for this Ethernet Controller.
+ * Tested on ST platforms only.
+ */
+static void dwmac100_pmt(unsigned long ioaddr, unsigned long mode)
 {
        return;
 }
 
-static void mac100_init_rx_desc(struct dma_desc *p, unsigned int ring_size,
+static void dwmac100_init_rx_desc(struct dma_desc *p, unsigned int ring_size,
                                int disable_rx_ic)
 {
        int i;
@@ -381,7 +386,7 @@ static void mac100_init_rx_desc(struct dma_desc *p, unsigned int ring_size,
        return;
 }
 
-static void mac100_init_tx_desc(struct dma_desc *p, unsigned int ring_size)
+static void dwmac100_init_tx_desc(struct dma_desc *p, unsigned int ring_size)
 {
        int i;
        for (i = 0; i < ring_size; i++) {
@@ -393,32 +398,32 @@ static void mac100_init_tx_desc(struct dma_desc *p, unsigned int ring_size)
        return;
 }
 
-static int mac100_get_tx_owner(struct dma_desc *p)
+static int dwmac100_get_tx_owner(struct dma_desc *p)
 {
        return p->des01.tx.own;
 }
 
-static int mac100_get_rx_owner(struct dma_desc *p)
+static int dwmac100_get_rx_owner(struct dma_desc *p)
 {
        return p->des01.rx.own;
 }
 
-static void mac100_set_tx_owner(struct dma_desc *p)
+static void dwmac100_set_tx_owner(struct dma_desc *p)
 {
        p->des01.tx.own = 1;
 }
 
-static void mac100_set_rx_owner(struct dma_desc *p)
+static void dwmac100_set_rx_owner(struct dma_desc *p)
 {
        p->des01.rx.own = 1;
 }
 
-static int mac100_get_tx_ls(struct dma_desc *p)
+static int dwmac100_get_tx_ls(struct dma_desc *p)
 {
        return p->des01.tx.last_segment;
 }
 
-static void mac100_release_tx_desc(struct dma_desc *p)
+static void dwmac100_release_tx_desc(struct dma_desc *p)
 {
        int ter = p->des01.tx.end_ring;
 
@@ -444,74 +449,91 @@ static void mac100_release_tx_desc(struct dma_desc *p)
        return;
 }
 
-static void mac100_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
+static void dwmac100_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
                                   int csum_flag)
 {
        p->des01.tx.first_segment = is_fs;
        p->des01.tx.buffer1_size = len;
 }
 
-static void mac100_clear_tx_ic(struct dma_desc *p)
+static void dwmac100_clear_tx_ic(struct dma_desc *p)
 {
        p->des01.tx.interrupt = 0;
 }
 
-static void mac100_close_tx_desc(struct dma_desc *p)
+static void dwmac100_close_tx_desc(struct dma_desc *p)
 {
        p->des01.tx.last_segment = 1;
        p->des01.tx.interrupt = 1;
 }
 
-static int mac100_get_rx_frame_len(struct dma_desc *p)
+static int dwmac100_get_rx_frame_len(struct dma_desc *p)
 {
        return p->des01.rx.frame_length;
 }
 
-struct stmmac_ops mac100_driver = {
-       .core_init = mac100_core_init,
-       .dump_mac_regs = mac100_dump_mac_regs,
-       .dma_init = mac100_dma_init,
-       .dump_dma_regs = mac100_dump_dma_regs,
-       .dma_mode = mac100_dma_operation_mode,
-       .dma_diagnostic_fr = mac100_dma_diagnostic_fr,
-       .tx_status = mac100_get_tx_frame_status,
-       .rx_status = mac100_get_rx_frame_status,
-       .get_tx_len = mac100_get_tx_len,
-       .set_filter = mac100_set_filter,
-       .flow_ctrl = mac100_flow_ctrl,
-       .pmt = mac100_pmt,
-       .init_rx_desc = mac100_init_rx_desc,
-       .init_tx_desc = mac100_init_tx_desc,
-       .get_tx_owner = mac100_get_tx_owner,
-       .get_rx_owner = mac100_get_rx_owner,
-       .release_tx_desc = mac100_release_tx_desc,
-       .prepare_tx_desc = mac100_prepare_tx_desc,
-       .clear_tx_ic = mac100_clear_tx_ic,
-       .close_tx_desc = mac100_close_tx_desc,
-       .get_tx_ls = mac100_get_tx_ls,
-       .set_tx_owner = mac100_set_tx_owner,
-       .set_rx_owner = mac100_set_rx_owner,
-       .get_rx_frame_len = mac100_get_rx_frame_len,
-       .host_irq_status = mac100_irq_status,
-       .set_umac_addr = mac100_set_umac_addr,
-       .get_umac_addr = mac100_get_umac_addr,
+struct stmmac_ops dwmac100_ops = {
+       .core_init = dwmac100_core_init,
+       .dump_regs = dwmac100_dump_mac_regs,
+       .host_irq_status = dwmac100_irq_status,
+       .set_filter = dwmac100_set_filter,
+       .flow_ctrl = dwmac100_flow_ctrl,
+       .pmt = dwmac100_pmt,
+       .set_umac_addr = dwmac100_set_umac_addr,
+       .get_umac_addr = dwmac100_get_umac_addr,
 };
 
-struct mac_device_info *mac100_setup(unsigned long ioaddr)
+struct stmmac_dma_ops dwmac100_dma_ops = {
+       .init = dwmac100_dma_init,
+       .dump_regs = dwmac100_dump_dma_regs,
+       .dma_mode = dwmac100_dma_operation_mode,
+       .dma_diagnostic_fr = dwmac100_dma_diagnostic_fr,
+       .enable_dma_transmission = dwmac_enable_dma_transmission,
+       .enable_dma_irq = dwmac_enable_dma_irq,
+       .disable_dma_irq = dwmac_disable_dma_irq,
+       .start_tx = dwmac_dma_start_tx,
+       .stop_tx = dwmac_dma_stop_tx,
+       .start_rx = dwmac_dma_start_rx,
+       .stop_rx = dwmac_dma_stop_rx,
+       .dma_interrupt = dwmac_dma_interrupt,
+};
+
+struct stmmac_desc_ops dwmac100_desc_ops = {
+       .tx_status = dwmac100_get_tx_frame_status,
+       .rx_status = dwmac100_get_rx_frame_status,
+       .get_tx_len = dwmac100_get_tx_len,
+       .init_rx_desc = dwmac100_init_rx_desc,
+       .init_tx_desc = dwmac100_init_tx_desc,
+       .get_tx_owner = dwmac100_get_tx_owner,
+       .get_rx_owner = dwmac100_get_rx_owner,
+       .release_tx_desc = dwmac100_release_tx_desc,
+       .prepare_tx_desc = dwmac100_prepare_tx_desc,
+       .clear_tx_ic = dwmac100_clear_tx_ic,
+       .close_tx_desc = dwmac100_close_tx_desc,
+       .get_tx_ls = dwmac100_get_tx_ls,
+       .set_tx_owner = dwmac100_set_tx_owner,
+       .set_rx_owner = dwmac100_set_rx_owner,
+       .get_rx_frame_len = dwmac100_get_rx_frame_len,
+};
+
+struct mac_device_info *dwmac100_setup(unsigned long ioaddr)
 {
        struct mac_device_info *mac;
 
        mac = kzalloc(sizeof(const struct mac_device_info), GFP_KERNEL);
 
-       pr_info("\tMAC 10/100\n");
+       pr_info("\tDWMAC100\n");
+
+       mac->mac = &dwmac100_ops;
+       mac->desc = &dwmac100_desc_ops;
+       mac->dma = &dwmac100_dma_ops;
 
-       mac->ops = &mac100_driver;
-       mac->hw.pmt = PMT_NOT_SUPPORTED;
-       mac->hw.link.port = MAC_CONTROL_PS;
-       mac->hw.link.duplex = MAC_CONTROL_F;
-       mac->hw.link.speed = 0;
-       mac->hw.mii.addr = MAC_MII_ADDR;
-       mac->hw.mii.data = MAC_MII_DATA;
+       mac->pmt = PMT_NOT_SUPPORTED;
+       mac->link.port = MAC_CONTROL_PS;
+       mac->link.duplex = MAC_CONTROL_F;
+       mac->link.speed = 0;
+       mac->mii.addr = MAC_MII_ADDR;
+       mac->mii.data = MAC_MII_DATA;
 
        return mac;
 }
similarity index 95%
rename from drivers/net/stmmac/gmac.h
rename to drivers/net/stmmac/dwmac1000.h
index 2e82d6c9a148df298e4dfc6e17bb144a127509a2..62dca0e384e726a01f01fd70744d4c8729f74027 100644 (file)
@@ -20,6 +20,9 @@
   Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
 *******************************************************************************/
 
+#include <linux/phy.h>
+#include "common.h"
+
 #define GMAC_CONTROL           0x00000000      /* Configuration */
 #define GMAC_FRAME_FILTER      0x00000004      /* Frame Filter */
 #define GMAC_HASH_HIGH         0x00000008      /* Multicast Hash Table High */
@@ -32,7 +35,7 @@
 #define GMAC_WAKEUP_FILTER     0x00000028      /* Wake-up Frame Filter */
 
 #define GMAC_INT_STATUS                0x00000038      /* interrupt status register */
-enum gmac_irq_status {
+enum dwmac1000_irq_status {
        time_stamp_irq = 0x0200,
        mmc_rx_csum_offload_irq = 0x0080,
        mmc_tx_irq = 0x0040,
@@ -202,3 +205,16 @@ enum rtc_control {
 #define GMAC_MMC_RX_INTR   0x104
 #define GMAC_MMC_TX_INTR   0x108
 #define GMAC_MMC_RX_CSUM_OFFLOAD   0x208
+
+#undef DWMAC1000_DEBUG
+/* #define DWMAC1000__DEBUG */
+#undef FRAME_FILTER_DEBUG
+/* #define FRAME_FILTER_DEBUG */
+#ifdef DWMAC1000__DEBUG
+#define DBG(fmt, args...)  printk(fmt, ## args)
+#else
+#define DBG(fmt, args...)  do { } while (0)
+#endif
+
+extern struct stmmac_dma_ops dwmac1000_dma_ops;
+extern struct stmmac_desc_ops dwmac1000_desc_ops;
diff --git a/drivers/net/stmmac/dwmac1000_core.c b/drivers/net/stmmac/dwmac1000_core.c
new file mode 100644 (file)
index 0000000..d812e9c
--- /dev/null
@@ -0,0 +1,245 @@
+/*******************************************************************************
+  This is the driver for the GMAC on-chip Ethernet controller for ST SoCs.
+  DWC Ether MAC 10/100/1000 Universal version 3.41a  has been used for
+  developing this code.
+
+  This only implements the mac core functions for this chip.
+
+  Copyright (C) 2007-2009  STMicroelectronics Ltd
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
+*******************************************************************************/
+
+#include <linux/crc32.h>
+#include "dwmac1000.h"
+
+static void dwmac1000_core_init(unsigned long ioaddr)
+{
+       u32 value = readl(ioaddr + GMAC_CONTROL);
+       value |= GMAC_CORE_INIT;
+       writel(value, ioaddr + GMAC_CONTROL);
+
+       /* STBus Bridge Configuration */
+       /*writel(0xc5608, ioaddr + 0x00007000);*/
+
+       /* Freeze MMC counters */
+       writel(0x8, ioaddr + GMAC_MMC_CTRL);
+       /* Mask GMAC interrupts */
+       writel(0x207, ioaddr + GMAC_INT_MASK);
+
+#ifdef STMMAC_VLAN_TAG_USED
+       /* Tag detection without filtering */
+       writel(0x0, ioaddr + GMAC_VLAN_TAG);
+#endif
+       return;
+}
+
+static void dwmac1000_dump_regs(unsigned long ioaddr)
+{
+       int i;
+       pr_info("\tDWMAC1000 regs (base addr = 0x%8x)\n", (unsigned int)ioaddr);
+
+       for (i = 0; i < 55; i++) {
+               int offset = i * 4;
+               pr_info("\tReg No. %d (offset 0x%x): 0x%08x\n", i,
+                       offset, readl(ioaddr + offset));
+       }
+       return;
+}
+
+static void dwmac1000_set_umac_addr(unsigned long 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,
+                               unsigned int reg_n)
+{
+       stmmac_get_mac_addr(ioaddr, addr, GMAC_ADDR_HIGH(reg_n),
+                               GMAC_ADDR_LOW(reg_n));
+}
+
+static void dwmac1000_set_filter(struct net_device *dev)
+{
+       unsigned long ioaddr = dev->base_addr;
+       unsigned int value = 0;
+
+       DBG(KERN_INFO "%s: # mcasts %d, # unicast %d\n",
+           __func__, dev->mc_count, netdev_uc_count(dev));
+
+       if (dev->flags & IFF_PROMISC)
+               value = GMAC_FRAME_FILTER_PR;
+       else if ((dev->mc_count > HASH_TABLE_SIZE)
+                  || (dev->flags & IFF_ALLMULTI)) {
+               value = GMAC_FRAME_FILTER_PM;   /* pass all multi */
+               writel(0xffffffff, ioaddr + GMAC_HASH_HIGH);
+               writel(0xffffffff, ioaddr + GMAC_HASH_LOW);
+       } else if (dev->mc_count > 0) {
+               int i;
+               u32 mc_filter[2];
+               struct dev_mc_list *mclist;
+
+               /* Hash filter for multicast */
+               value = GMAC_FRAME_FILTER_HMC;
+
+               memset(mc_filter, 0, sizeof(mc_filter));
+               for (i = 0, mclist = dev->mc_list;
+                    mclist && i < dev->mc_count; i++, mclist = mclist->next) {
+                       /* The upper 6 bits of the calculated CRC are used to
+                          index the contens of the hash table */
+                       int bit_nr =
+                           bitrev32(~crc32_le(~0, mclist->dmi_addr, 6)) >> 26;
+                       /* The most significant bit determines the register to
+                        * use (H/L) while the other 5 bits determine the bit
+                        * within the register. */
+                       mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
+               }
+               writel(mc_filter[0], ioaddr + GMAC_HASH_LOW);
+               writel(mc_filter[1], ioaddr + GMAC_HASH_HIGH);
+       }
+
+       /* Handle multiple unicast addresses (perfect filtering)*/
+       if (netdev_uc_count(dev) > GMAC_MAX_UNICAST_ADDRESSES)
+               /* Switch to promiscuous mode is more than 16 addrs
+                  are required */
+               value |= GMAC_FRAME_FILTER_PR;
+       else {
+               int reg = 1;
+               struct netdev_hw_addr *ha;
+
+               netdev_for_each_uc_addr(ha, dev) {
+                       dwmac1000_set_umac_addr(ioaddr, ha->addr, reg);
+                       reg++;
+               }
+       }
+
+#ifdef FRAME_FILTER_DEBUG
+       /* Enable Receive all mode (to debug filtering_fail errors) */
+       value |= GMAC_FRAME_FILTER_RA;
+#endif
+       writel(value, ioaddr + GMAC_FRAME_FILTER);
+
+       DBG(KERN_INFO "\tFrame Filter reg: 0x%08x\n\tHash regs: "
+           "HI 0x%08x, LO 0x%08x\n", readl(ioaddr + GMAC_FRAME_FILTER),
+           readl(ioaddr + GMAC_HASH_HIGH), readl(ioaddr + GMAC_HASH_LOW));
+
+       return;
+}
+
+static void dwmac1000_flow_ctrl(unsigned long ioaddr, unsigned int duplex,
+                          unsigned int fc, unsigned int pause_time)
+{
+       unsigned int flow = 0;
+
+       DBG(KERN_DEBUG "GMAC Flow-Control:\n");
+       if (fc & FLOW_RX) {
+               DBG(KERN_DEBUG "\tReceive Flow-Control ON\n");
+               flow |= GMAC_FLOW_CTRL_RFE;
+       }
+       if (fc & FLOW_TX) {
+               DBG(KERN_DEBUG "\tTransmit Flow-Control ON\n");
+               flow |= GMAC_FLOW_CTRL_TFE;
+       }
+
+       if (duplex) {
+               DBG(KERN_DEBUG "\tduplex mode: pause time: %d\n", pause_time);
+               flow |= (pause_time << GMAC_FLOW_CTRL_PT_SHIFT);
+       }
+
+       writel(flow, ioaddr + GMAC_FLOW_CTRL);
+       return;
+}
+
+static void dwmac1000_pmt(unsigned long ioaddr, unsigned long mode)
+{
+       unsigned int pmt = 0;
+
+       if (mode == WAKE_MAGIC) {
+               DBG(KERN_DEBUG "GMAC: WOL Magic frame\n");
+               pmt |= power_down | magic_pkt_en;
+       } else if (mode == WAKE_UCAST) {
+               DBG(KERN_DEBUG "GMAC: WOL on global unicast\n");
+               pmt |= global_unicast;
+       }
+
+       writel(pmt, ioaddr + GMAC_PMT);
+       return;
+}
+
+
+static void dwmac1000_irq_status(unsigned long ioaddr)
+{
+       u32 intr_status = readl(ioaddr + GMAC_INT_STATUS);
+
+       /* Not used events (e.g. MMC interrupts) are not handled. */
+       if ((intr_status & mmc_tx_irq))
+               DBG(KERN_DEBUG "GMAC: MMC tx interrupt: 0x%08x\n",
+                   readl(ioaddr + GMAC_MMC_TX_INTR));
+       if (unlikely(intr_status & mmc_rx_irq))
+               DBG(KERN_DEBUG "GMAC: MMC rx interrupt: 0x%08x\n",
+                   readl(ioaddr + GMAC_MMC_RX_INTR));
+       if (unlikely(intr_status & mmc_rx_csum_offload_irq))
+               DBG(KERN_DEBUG "GMAC: MMC rx csum offload: 0x%08x\n",
+                   readl(ioaddr + GMAC_MMC_RX_CSUM_OFFLOAD));
+       if (unlikely(intr_status & pmt_irq)) {
+               DBG(KERN_DEBUG "GMAC: received Magic frame\n");
+               /* clear the PMT bits 5 and 6 by reading the PMT
+                * status register. */
+               readl(ioaddr + GMAC_PMT);
+       }
+
+       return;
+}
+
+struct stmmac_ops dwmac1000_ops = {
+       .core_init = dwmac1000_core_init,
+       .dump_regs = dwmac1000_dump_regs,
+       .host_irq_status = dwmac1000_irq_status,
+       .set_filter = dwmac1000_set_filter,
+       .flow_ctrl = dwmac1000_flow_ctrl,
+       .pmt = dwmac1000_pmt,
+       .set_umac_addr = dwmac1000_set_umac_addr,
+       .get_umac_addr = dwmac1000_get_umac_addr,
+};
+
+struct mac_device_info *dwmac1000_setup(unsigned long ioaddr)
+{
+       struct mac_device_info *mac;
+       u32 uid = readl(ioaddr + GMAC_VERSION);
+
+       pr_info("\tDWMAC1000 - user ID: 0x%x, Synopsys ID: 0x%x\n",
+               ((uid & 0x0000ff00) >> 8), (uid & 0x000000ff));
+
+       mac = kzalloc(sizeof(const struct mac_device_info), GFP_KERNEL);
+
+       mac->mac = &dwmac1000_ops;
+       mac->desc = &dwmac1000_desc_ops;
+       mac->dma = &dwmac1000_dma_ops;
+
+       mac->pmt = PMT_SUPPORTED;
+       mac->link.port = GMAC_CONTROL_PS;
+       mac->link.duplex = GMAC_CONTROL_DM;
+       mac->link.speed = GMAC_CONTROL_FES;
+       mac->mii.addr = GMAC_MII_ADDR;
+       mac->mii.data = GMAC_MII_DATA;
+
+       return mac;
+}
similarity index 54%
rename from drivers/net/stmmac/gmac.c
rename to drivers/net/stmmac/dwmac1000_dma.c
index 52586ee68953f703cdbdc47b86ea96a403cbf55b..68245508e2de1ef153cb0ad5a9f23f8966346c86 100644 (file)
@@ -3,6 +3,8 @@
   DWC Ether MAC 10/100/1000 Universal version 3.41a  has been used for
   developing this code.
 
+  This contains the functions to handle the dma and descriptors.
+
   Copyright (C) 2007-2009  STMicroelectronics Ltd
 
   This program is free software; you can redistribute it and/or modify it
   Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
 *******************************************************************************/
 
-#include <linux/netdevice.h>
-#include <linux/crc32.h>
-#include <linux/mii.h>
-#include <linux/phy.h>
-
-#include "stmmac.h"
-#include "gmac.h"
-
-#undef GMAC_DEBUG
-/*#define GMAC_DEBUG*/
-#undef FRAME_FILTER_DEBUG
-/*#define FRAME_FILTER_DEBUG*/
-#ifdef GMAC_DEBUG
-#define DBG(fmt, args...)  printk(fmt, ## args)
-#else
-#define DBG(fmt, args...)  do { } while (0)
-#endif
+#include "dwmac1000.h"
+#include "dwmac_dma.h"
 
-static void gmac_dump_regs(unsigned long ioaddr)
-{
-       int i;
-       pr_info("\t----------------------------------------------\n"
-              "\t  GMAC registers (base addr = 0x%8x)\n"
-              "\t----------------------------------------------\n",
-              (unsigned int)ioaddr);
-
-       for (i = 0; i < 55; i++) {
-               int offset = i * 4;
-               pr_info("\tReg No. %d (offset 0x%x): 0x%08x\n", i,
-                      offset, readl(ioaddr + offset));
-       }
-       return;
-}
-
-static int gmac_dma_init(unsigned long ioaddr, int pbl, u32 dma_tx, u32 dma_rx)
+static int dwmac1000_dma_init(unsigned long ioaddr, int pbl, u32 dma_tx,
+                             u32 dma_rx)
 {
        u32 value = readl(ioaddr + DMA_BUS_MODE);
        /* DMA SW reset */
@@ -87,7 +59,7 @@ static int gmac_dma_init(unsigned long ioaddr, int pbl, u32 dma_tx, u32 dma_rx)
 }
 
 /* Transmit FIFO flush operation */
-static void gmac_flush_tx_fifo(unsigned long ioaddr)
+static void dwmac1000_flush_tx_fifo(unsigned long ioaddr)
 {
        u32 csr6 = readl(ioaddr + DMA_CONTROL);
        writel((csr6 | DMA_CONTROL_FTF), ioaddr + DMA_CONTROL);
@@ -95,7 +67,7 @@ static void gmac_flush_tx_fifo(unsigned long ioaddr)
        do {} while ((readl(ioaddr + DMA_CONTROL) & DMA_CONTROL_FTF));
 }
 
-static void gmac_dma_operation_mode(unsigned long ioaddr, int txmode,
+static void dwmac1000_dma_operation_mode(unsigned long ioaddr, int txmode,
                                    int rxmode)
 {
        u32 csr6 = readl(ioaddr + DMA_CONTROL);
@@ -148,13 +120,13 @@ static void gmac_dma_operation_mode(unsigned long ioaddr, int txmode,
 }
 
 /* Not yet implemented --- no RMON module */
-static void gmac_dma_diagnostic_fr(void *data, struct stmmac_extra_stats *x,
-                                  unsigned long ioaddr)
+static void dwmac1000_dma_diagnostic_fr(void *data,
+                 struct stmmac_extra_stats *x, unsigned long ioaddr)
 {
        return;
 }
 
-static void gmac_dump_dma_regs(unsigned long ioaddr)
+static void dwmac1000_dump_dma_regs(unsigned long ioaddr)
 {
        int i;
        pr_info(" DMA registers\n");
@@ -169,8 +141,9 @@ static void gmac_dump_dma_regs(unsigned long ioaddr)
        return;
 }
 
-static int gmac_get_tx_frame_status(void *data, struct stmmac_extra_stats *x,
-                                   struct dma_desc *p, unsigned long ioaddr)
+static int dwmac1000_get_tx_frame_status(void *data,
+                               struct stmmac_extra_stats *x,
+                               struct dma_desc *p, unsigned long ioaddr)
 {
        int ret = 0;
        struct net_device_stats *stats = (struct net_device_stats *)data;
@@ -185,7 +158,7 @@ static int gmac_get_tx_frame_status(void *data, struct stmmac_extra_stats *x,
                if (unlikely(p->des01.etx.frame_flushed)) {
                        DBG(KERN_ERR "\tframe_flushed error\n");
                        x->tx_frame_flushed++;
-                       gmac_flush_tx_fifo(ioaddr);
+                       dwmac1000_flush_tx_fifo(ioaddr);
                }
 
                if (unlikely(p->des01.etx.loss_carrier)) {
@@ -213,7 +186,7 @@ static int gmac_get_tx_frame_status(void *data, struct stmmac_extra_stats *x,
 
                if (unlikely(p->des01.etx.underflow_error)) {
                        DBG(KERN_ERR "\tunderflow error\n");
-                       gmac_flush_tx_fifo(ioaddr);
+                       dwmac1000_flush_tx_fifo(ioaddr);
                        x->tx_underflow++;
                }
 
@@ -225,7 +198,7 @@ static int gmac_get_tx_frame_status(void *data, struct stmmac_extra_stats *x,
                if (unlikely(p->des01.etx.payload_error)) {
                        DBG(KERN_ERR "\tAddr/Payload csum error\n");
                        x->tx_payload_error++;
-                       gmac_flush_tx_fifo(ioaddr);
+                       dwmac1000_flush_tx_fifo(ioaddr);
                }
 
                ret = -1;
@@ -245,12 +218,12 @@ static int gmac_get_tx_frame_status(void *data, struct stmmac_extra_stats *x,
        return ret;
 }
 
-static int gmac_get_tx_len(struct dma_desc *p)
+static int dwmac1000_get_tx_len(struct dma_desc *p)
 {
        return p->des01.etx.buffer1_size;
 }
 
-static int gmac_coe_rdes0(int ipc_err, int type, int payload_err)
+static int dwmac1000_coe_rdes0(int ipc_err, int type, int payload_err)
 {
        int ret = good_frame;
        u32 status = (type << 2 | ipc_err << 1 | payload_err) & 0x7;
@@ -293,8 +266,8 @@ static int gmac_coe_rdes0(int ipc_err, int type, int payload_err)
        return ret;
 }
 
-static int gmac_get_rx_frame_status(void *data, struct stmmac_extra_stats *x,
-                                   struct dma_desc *p)
+static int dwmac1000_get_rx_frame_status(void *data,
+                       struct stmmac_extra_stats *x, struct dma_desc *p)
 {
        int ret = good_frame;
        struct net_device_stats *stats = (struct net_device_stats *)data;
@@ -339,7 +312,7 @@ static int gmac_get_rx_frame_status(void *data, struct stmmac_extra_stats *x,
         * It doesn't match with the information reported into the databook.
         * At any rate, we need to understand if the CSUM hw computation is ok
         * and report this info to the upper layers. */
-       ret = gmac_coe_rdes0(p->des01.erx.ipc_csum_error,
+       ret = dwmac1000_coe_rdes0(p->des01.erx.ipc_csum_error,
                p->des01.erx.frame_type, p->des01.erx.payload_csum_error);
 
        if (unlikely(p->des01.erx.dribbling)) {
@@ -370,181 +343,7 @@ static int gmac_get_rx_frame_status(void *data, struct stmmac_extra_stats *x,
        return ret;
 }
 
-static void gmac_irq_status(unsigned long ioaddr)
-{
-       u32 intr_status = readl(ioaddr + GMAC_INT_STATUS);
-
-       /* Not used events (e.g. MMC interrupts) are not handled. */
-       if ((intr_status & mmc_tx_irq))
-               DBG(KERN_DEBUG "GMAC: MMC tx interrupt: 0x%08x\n",
-                   readl(ioaddr + GMAC_MMC_TX_INTR));
-       if (unlikely(intr_status & mmc_rx_irq))
-               DBG(KERN_DEBUG "GMAC: MMC rx interrupt: 0x%08x\n",
-                   readl(ioaddr + GMAC_MMC_RX_INTR));
-       if (unlikely(intr_status & mmc_rx_csum_offload_irq))
-               DBG(KERN_DEBUG "GMAC: MMC rx csum offload: 0x%08x\n",
-                   readl(ioaddr + GMAC_MMC_RX_CSUM_OFFLOAD));
-       if (unlikely(intr_status & pmt_irq)) {
-               DBG(KERN_DEBUG "GMAC: received Magic frame\n");
-               /* clear the PMT bits 5 and 6 by reading the PMT
-                * status register. */
-               readl(ioaddr + GMAC_PMT);
-       }
-
-       return;
-}
-
-static void gmac_core_init(unsigned long ioaddr)
-{
-       u32 value = readl(ioaddr + GMAC_CONTROL);
-       value |= GMAC_CORE_INIT;
-       writel(value, ioaddr + GMAC_CONTROL);
-
-       /* STBus Bridge Configuration */
-       /*writel(0xc5608, ioaddr + 0x00007000);*/
-
-       /* Freeze MMC counters */
-       writel(0x8, ioaddr + GMAC_MMC_CTRL);
-       /* Mask GMAC interrupts */
-       writel(0x207, ioaddr + GMAC_INT_MASK);
-
-#ifdef STMMAC_VLAN_TAG_USED
-       /* Tag detection without filtering */
-       writel(0x0, ioaddr + GMAC_VLAN_TAG);
-#endif
-       return;
-}
-
-static void gmac_set_umac_addr(unsigned long 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 gmac_get_umac_addr(unsigned long ioaddr, unsigned char *addr,
-                               unsigned int reg_n)
-{
-       stmmac_get_mac_addr(ioaddr, addr, GMAC_ADDR_HIGH(reg_n),
-                               GMAC_ADDR_LOW(reg_n));
-}
-
-static void gmac_set_filter(struct net_device *dev)
-{
-       unsigned long ioaddr = dev->base_addr;
-       unsigned int value = 0;
-
-       DBG(KERN_INFO "%s: # mcasts %d, # unicast %d\n",
-           __func__, dev->mc_count, dev->uc_count);
-
-       if (dev->flags & IFF_PROMISC)
-               value = GMAC_FRAME_FILTER_PR;
-       else if ((dev->mc_count > HASH_TABLE_SIZE)
-                  || (dev->flags & IFF_ALLMULTI)) {
-               value = GMAC_FRAME_FILTER_PM;   /* pass all multi */
-               writel(0xffffffff, ioaddr + GMAC_HASH_HIGH);
-               writel(0xffffffff, ioaddr + GMAC_HASH_LOW);
-       } else if (dev->mc_count > 0) {
-               int i;
-               u32 mc_filter[2];
-               struct dev_mc_list *mclist;
-
-               /* Hash filter for multicast */
-               value = GMAC_FRAME_FILTER_HMC;
-
-               memset(mc_filter, 0, sizeof(mc_filter));
-               for (i = 0, mclist = dev->mc_list;
-                    mclist && i < dev->mc_count; i++, mclist = mclist->next) {
-                       /* The upper 6 bits of the calculated CRC are used to
-                          index the contens of the hash table */
-                       int bit_nr =
-                           bitrev32(~crc32_le(~0, mclist->dmi_addr, 6)) >> 26;
-                       /* The most significant bit determines the register to
-                        * use (H/L) while the other 5 bits determine the bit
-                        * within the register. */
-                       mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
-               }
-               writel(mc_filter[0], ioaddr + GMAC_HASH_LOW);
-               writel(mc_filter[1], ioaddr + GMAC_HASH_HIGH);
-       }
-
-       /* Handle multiple unicast addresses (perfect filtering)*/
-       if (dev->uc_count > GMAC_MAX_UNICAST_ADDRESSES)
-               /* Switch to promiscuous mode is more than 16 addrs
-                  are required */
-               value |= GMAC_FRAME_FILTER_PR;
-       else {
-               int i;
-               struct dev_addr_list *uc_ptr = dev->uc_list;
-
-                       for (i = 0; i < dev->uc_count; i++) {
-                               gmac_set_umac_addr(ioaddr, uc_ptr->da_addr,
-                                               i + 1);
-
-                               DBG(KERN_INFO "\t%d "
-                               "- Unicast addr %02x:%02x:%02x:%02x:%02x:"
-                               "%02x\n", i + 1,
-                               uc_ptr->da_addr[0], uc_ptr->da_addr[1],
-                               uc_ptr->da_addr[2], uc_ptr->da_addr[3],
-                               uc_ptr->da_addr[4], uc_ptr->da_addr[5]);
-                               uc_ptr = uc_ptr->next;
-               }
-       }
-
-#ifdef FRAME_FILTER_DEBUG
-       /* Enable Receive all mode (to debug filtering_fail errors) */
-       value |= GMAC_FRAME_FILTER_RA;
-#endif
-       writel(value, ioaddr + GMAC_FRAME_FILTER);
-
-       DBG(KERN_INFO "\tFrame Filter reg: 0x%08x\n\tHash regs: "
-           "HI 0x%08x, LO 0x%08x\n", readl(ioaddr + GMAC_FRAME_FILTER),
-           readl(ioaddr + GMAC_HASH_HIGH), readl(ioaddr + GMAC_HASH_LOW));
-
-       return;
-}
-
-static void gmac_flow_ctrl(unsigned long ioaddr, unsigned int duplex,
-                          unsigned int fc, unsigned int pause_time)
-{
-       unsigned int flow = 0;
-
-       DBG(KERN_DEBUG "GMAC Flow-Control:\n");
-       if (fc & FLOW_RX) {
-               DBG(KERN_DEBUG "\tReceive Flow-Control ON\n");
-               flow |= GMAC_FLOW_CTRL_RFE;
-       }
-       if (fc & FLOW_TX) {
-               DBG(KERN_DEBUG "\tTransmit Flow-Control ON\n");
-               flow |= GMAC_FLOW_CTRL_TFE;
-       }
-
-       if (duplex) {
-               DBG(KERN_DEBUG "\tduplex mode: pause time: %d\n", pause_time);
-               flow |= (pause_time << GMAC_FLOW_CTRL_PT_SHIFT);
-       }
-
-       writel(flow, ioaddr + GMAC_FLOW_CTRL);
-       return;
-}
-
-static void gmac_pmt(unsigned long ioaddr, unsigned long mode)
-{
-       unsigned int pmt = 0;
-
-       if (mode == WAKE_MAGIC) {
-               DBG(KERN_DEBUG "GMAC: WOL Magic frame\n");
-               pmt |= power_down | magic_pkt_en;
-       } else if (mode == WAKE_UCAST) {
-               DBG(KERN_DEBUG "GMAC: WOL on global unicast\n");
-               pmt |= global_unicast;
-       }
-
-       writel(pmt, ioaddr + GMAC_PMT);
-       return;
-}
-
-static void gmac_init_rx_desc(struct dma_desc *p, unsigned int ring_size,
+static void dwmac1000_init_rx_desc(struct dma_desc *p, unsigned int ring_size,
                                int disable_rx_ic)
 {
        int i;
@@ -562,7 +361,7 @@ static void gmac_init_rx_desc(struct dma_desc *p, unsigned int ring_size,
        return;
 }
 
-static void gmac_init_tx_desc(struct dma_desc *p, unsigned int ring_size)
+static void dwmac1000_init_tx_desc(struct dma_desc *p, unsigned int ring_size)
 {
        int i;
 
@@ -576,32 +375,32 @@ static void gmac_init_tx_desc(struct dma_desc *p, unsigned int ring_size)
        return;
 }
 
-static int gmac_get_tx_owner(struct dma_desc *p)
+static int dwmac1000_get_tx_owner(struct dma_desc *p)
 {
        return p->des01.etx.own;
 }
 
-static int gmac_get_rx_owner(struct dma_desc *p)
+static int dwmac1000_get_rx_owner(struct dma_desc *p)
 {
        return p->des01.erx.own;
 }
 
-static void gmac_set_tx_owner(struct dma_desc *p)
+static void dwmac1000_set_tx_owner(struct dma_desc *p)
 {
        p->des01.etx.own = 1;
 }
 
-static void gmac_set_rx_owner(struct dma_desc *p)
+static void dwmac1000_set_rx_owner(struct dma_desc *p)
 {
        p->des01.erx.own = 1;
 }
 
-static int gmac_get_tx_ls(struct dma_desc *p)
+static int dwmac1000_get_tx_ls(struct dma_desc *p)
 {
        return p->des01.etx.last_segment;
 }
 
-static void gmac_release_tx_desc(struct dma_desc *p)
+static void dwmac1000_release_tx_desc(struct dma_desc *p)
 {
        int ter = p->des01.etx.end_ring;
 
@@ -611,7 +410,7 @@ static void gmac_release_tx_desc(struct dma_desc *p)
        return;
 }
 
-static void gmac_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
+static void dwmac1000_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
                                 int csum_flag)
 {
        p->des01.etx.first_segment = is_fs;
@@ -625,69 +424,51 @@ static void gmac_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
                p->des01.etx.checksum_insertion = cic_full;
 }
 
-static void gmac_clear_tx_ic(struct dma_desc *p)
+static void dwmac1000_clear_tx_ic(struct dma_desc *p)
 {
        p->des01.etx.interrupt = 0;
 }
 
-static void gmac_close_tx_desc(struct dma_desc *p)
+static void dwmac1000_close_tx_desc(struct dma_desc *p)
 {
        p->des01.etx.last_segment = 1;
        p->des01.etx.interrupt = 1;
 }
 
-static int gmac_get_rx_frame_len(struct dma_desc *p)
+static int dwmac1000_get_rx_frame_len(struct dma_desc *p)
 {
        return p->des01.erx.frame_length;
 }
 
-struct stmmac_ops gmac_driver = {
-       .core_init = gmac_core_init,
-       .dump_mac_regs = gmac_dump_regs,
-       .dma_init = gmac_dma_init,
-       .dump_dma_regs = gmac_dump_dma_regs,
-       .dma_mode = gmac_dma_operation_mode,
-       .dma_diagnostic_fr = gmac_dma_diagnostic_fr,
-       .tx_status = gmac_get_tx_frame_status,
-       .rx_status = gmac_get_rx_frame_status,
-       .get_tx_len = gmac_get_tx_len,
-       .set_filter = gmac_set_filter,
-       .flow_ctrl = gmac_flow_ctrl,
-       .pmt = gmac_pmt,
-       .init_rx_desc = gmac_init_rx_desc,
-       .init_tx_desc = gmac_init_tx_desc,
-       .get_tx_owner = gmac_get_tx_owner,
-       .get_rx_owner = gmac_get_rx_owner,
-       .release_tx_desc = gmac_release_tx_desc,
-       .prepare_tx_desc = gmac_prepare_tx_desc,
-       .clear_tx_ic = gmac_clear_tx_ic,
-       .close_tx_desc = gmac_close_tx_desc,
-       .get_tx_ls = gmac_get_tx_ls,
-       .set_tx_owner = gmac_set_tx_owner,
-       .set_rx_owner = gmac_set_rx_owner,
-       .get_rx_frame_len = gmac_get_rx_frame_len,
-       .host_irq_status = gmac_irq_status,
-       .set_umac_addr = gmac_set_umac_addr,
-       .get_umac_addr = gmac_get_umac_addr,
+struct stmmac_dma_ops dwmac1000_dma_ops = {
+       .init = dwmac1000_dma_init,
+       .dump_regs = dwmac1000_dump_dma_regs,
+       .dma_mode = dwmac1000_dma_operation_mode,
+       .dma_diagnostic_fr = dwmac1000_dma_diagnostic_fr,
+       .enable_dma_transmission = dwmac_enable_dma_transmission,
+       .enable_dma_irq = dwmac_enable_dma_irq,
+       .disable_dma_irq = dwmac_disable_dma_irq,
+       .start_tx = dwmac_dma_start_tx,
+       .stop_tx = dwmac_dma_stop_tx,
+       .start_rx = dwmac_dma_start_rx,
+       .stop_rx = dwmac_dma_stop_rx,
+       .dma_interrupt = dwmac_dma_interrupt,
 };
 
-struct mac_device_info *gmac_setup(unsigned long ioaddr)
-{
-       struct mac_device_info *mac;
-       u32 uid = readl(ioaddr + GMAC_VERSION);
-
-       pr_info("\tGMAC - user ID: 0x%x, Synopsys ID: 0x%x\n",
-              ((uid & 0x0000ff00) >> 8), (uid & 0x000000ff));
-
-       mac = kzalloc(sizeof(const struct mac_device_info), GFP_KERNEL);
-
-       mac->ops = &gmac_driver;
-       mac->hw.pmt = PMT_SUPPORTED;
-       mac->hw.link.port = GMAC_CONTROL_PS;
-       mac->hw.link.duplex = GMAC_CONTROL_DM;
-       mac->hw.link.speed = GMAC_CONTROL_FES;
-       mac->hw.mii.addr = GMAC_MII_ADDR;
-       mac->hw.mii.data = GMAC_MII_DATA;
-
-       return mac;
-}
+struct stmmac_desc_ops dwmac1000_desc_ops = {
+       .tx_status = dwmac1000_get_tx_frame_status,
+       .rx_status = dwmac1000_get_rx_frame_status,
+       .get_tx_len = dwmac1000_get_tx_len,
+       .init_rx_desc = dwmac1000_init_rx_desc,
+       .init_tx_desc = dwmac1000_init_tx_desc,
+       .get_tx_owner = dwmac1000_get_tx_owner,
+       .get_rx_owner = dwmac1000_get_rx_owner,
+       .release_tx_desc = dwmac1000_release_tx_desc,
+       .prepare_tx_desc = dwmac1000_prepare_tx_desc,
+       .clear_tx_ic = dwmac1000_clear_tx_ic,
+       .close_tx_desc = dwmac1000_close_tx_desc,
+       .get_tx_ls = dwmac1000_get_tx_ls,
+       .set_tx_owner = dwmac1000_set_tx_owner,
+       .set_rx_owner = dwmac1000_set_rx_owner,
+       .get_rx_frame_len = dwmac1000_get_rx_frame_len,
+};
diff --git a/drivers/net/stmmac/dwmac_dma.h b/drivers/net/stmmac/dwmac_dma.h
new file mode 100644 (file)
index 0000000..de848d9
--- /dev/null
@@ -0,0 +1,107 @@
+/*******************************************************************************
+  DWMAC DMA Header file.
+
+  Copyright (C) 2007-2009  STMicroelectronics Ltd
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
+*******************************************************************************/
+
+/* DMA CRS Control and Status Register Mapping */
+#define DMA_BUS_MODE           0x00001000      /* Bus Mode */
+#define DMA_XMT_POLL_DEMAND    0x00001004      /* Transmit Poll Demand */
+#define DMA_RCV_POLL_DEMAND    0x00001008      /* Received Poll Demand */
+#define DMA_RCV_BASE_ADDR      0x0000100c      /* Receive List Base */
+#define DMA_TX_BASE_ADDR       0x00001010      /* Transmit List Base */
+#define DMA_STATUS             0x00001014      /* Status Register */
+#define DMA_CONTROL            0x00001018      /* Ctrl (Operational Mode) */
+#define DMA_INTR_ENA           0x0000101c      /* Interrupt Enable */
+#define DMA_MISSED_FRAME_CTR   0x00001020      /* Missed Frame Counter */
+#define DMA_CUR_TX_BUF_ADDR    0x00001050      /* Current Host Tx Buffer */
+#define DMA_CUR_RX_BUF_ADDR    0x00001054      /* Current Host Rx Buffer */
+
+/* DMA Control register defines */
+#define DMA_CONTROL_ST         0x00002000      /* Start/Stop Transmission */
+#define DMA_CONTROL_SR         0x00000002      /* Start/Stop Receive */
+
+/* DMA Normal interrupt */
+#define DMA_INTR_ENA_NIE 0x00010000    /* Normal Summary */
+#define DMA_INTR_ENA_TIE 0x00000001    /* Transmit Interrupt */
+#define DMA_INTR_ENA_TUE 0x00000004    /* Transmit Buffer Unavailable */
+#define DMA_INTR_ENA_RIE 0x00000040    /* Receive Interrupt */
+#define DMA_INTR_ENA_ERE 0x00004000    /* Early Receive */
+
+#define DMA_INTR_NORMAL        (DMA_INTR_ENA_NIE | DMA_INTR_ENA_RIE | \
+                       DMA_INTR_ENA_TIE)
+
+/* DMA Abnormal interrupt */
+#define DMA_INTR_ENA_AIE 0x00008000    /* Abnormal Summary */
+#define DMA_INTR_ENA_FBE 0x00002000    /* Fatal Bus Error */
+#define DMA_INTR_ENA_ETE 0x00000400    /* Early Transmit */
+#define DMA_INTR_ENA_RWE 0x00000200    /* Receive Watchdog */
+#define DMA_INTR_ENA_RSE 0x00000100    /* Receive Stopped */
+#define DMA_INTR_ENA_RUE 0x00000080    /* Receive Buffer Unavailable */
+#define DMA_INTR_ENA_UNE 0x00000020    /* Tx Underflow */
+#define DMA_INTR_ENA_OVE 0x00000010    /* Receive Overflow */
+#define DMA_INTR_ENA_TJE 0x00000008    /* Transmit Jabber */
+#define DMA_INTR_ENA_TSE 0x00000002    /* Transmit Stopped */
+
+#define DMA_INTR_ABNORMAL      (DMA_INTR_ENA_AIE | DMA_INTR_ENA_FBE | \
+                               DMA_INTR_ENA_UNE)
+
+/* DMA default interrupt mask */
+#define DMA_INTR_DEFAULT_MASK  (DMA_INTR_NORMAL | DMA_INTR_ABNORMAL)
+
+/* DMA Status register defines */
+#define DMA_STATUS_GPI         0x10000000      /* PMT interrupt */
+#define DMA_STATUS_GMI         0x08000000      /* MMC interrupt */
+#define DMA_STATUS_GLI         0x04000000      /* GMAC Line interface int */
+#define DMA_STATUS_GMI         0x08000000
+#define DMA_STATUS_GLI         0x04000000
+#define DMA_STATUS_EB_MASK     0x00380000      /* Error Bits Mask */
+#define DMA_STATUS_EB_TX_ABORT 0x00080000      /* Error Bits - TX Abort */
+#define DMA_STATUS_EB_RX_ABORT 0x00100000      /* Error Bits - RX Abort */
+#define DMA_STATUS_TS_MASK     0x00700000      /* Transmit Process State */
+#define DMA_STATUS_TS_SHIFT    20
+#define DMA_STATUS_RS_MASK     0x000e0000      /* Receive Process State */
+#define DMA_STATUS_RS_SHIFT    17
+#define DMA_STATUS_NIS 0x00010000      /* Normal Interrupt Summary */
+#define DMA_STATUS_AIS 0x00008000      /* Abnormal Interrupt Summary */
+#define DMA_STATUS_ERI 0x00004000      /* Early Receive Interrupt */
+#define DMA_STATUS_FBI 0x00002000      /* Fatal Bus Error Interrupt */
+#define DMA_STATUS_ETI 0x00000400      /* Early Transmit Interrupt */
+#define DMA_STATUS_RWT 0x00000200      /* Receive Watchdog Timeout */
+#define DMA_STATUS_RPS 0x00000100      /* Receive Process Stopped */
+#define DMA_STATUS_RU  0x00000080      /* Receive Buffer Unavailable */
+#define DMA_STATUS_RI  0x00000040      /* Receive Interrupt */
+#define DMA_STATUS_UNF 0x00000020      /* Transmit Underflow */
+#define DMA_STATUS_OVF 0x00000010      /* Receive Overflow */
+#define DMA_STATUS_TJT 0x00000008      /* Transmit Jabber Timeout */
+#define DMA_STATUS_TU  0x00000004      /* Transmit Buffer Unavailable */
+#define DMA_STATUS_TPS 0x00000002      /* Transmit Process Stopped */
+#define DMA_STATUS_TI  0x00000001      /* Transmit Interrupt */
+
+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,
+                               struct stmmac_extra_stats *x);
diff --git a/drivers/net/stmmac/dwmac_lib.c b/drivers/net/stmmac/dwmac_lib.c
new file mode 100644 (file)
index 0000000..d4adb1e
--- /dev/null
@@ -0,0 +1,263 @@
+/*******************************************************************************
+  Copyright (C) 2007-2009  STMicroelectronics Ltd
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
+*******************************************************************************/
+
+#include <linux/io.h>
+#include "common.h"
+#include "dwmac_dma.h"
+
+#undef DWMAC_DMA_DEBUG
+#ifdef DWMAC_DMA_DEBUG
+#define DBG(fmt, args...)  printk(fmt, ## args)
+#else
+#define DBG(fmt, args...)  do { } while (0)
+#endif
+
+/* CSR1 enables the transmit DMA to check for new descriptor */
+void dwmac_enable_dma_transmission(unsigned long ioaddr)
+{
+       writel(1, ioaddr + DMA_XMT_POLL_DEMAND);
+}
+
+void dwmac_enable_dma_irq(unsigned long ioaddr)
+{
+       writel(DMA_INTR_DEFAULT_MASK, ioaddr + DMA_INTR_ENA);
+}
+
+void dwmac_disable_dma_irq(unsigned long ioaddr)
+{
+       writel(0, ioaddr + DMA_INTR_ENA);
+}
+
+void dwmac_dma_start_tx(unsigned long ioaddr)
+{
+       u32 value = readl(ioaddr + DMA_CONTROL);
+       value |= DMA_CONTROL_ST;
+       writel(value, ioaddr + DMA_CONTROL);
+       return;
+}
+
+void dwmac_dma_stop_tx(unsigned long ioaddr)
+{
+       u32 value = readl(ioaddr + DMA_CONTROL);
+       value &= ~DMA_CONTROL_ST;
+       writel(value, ioaddr + DMA_CONTROL);
+       return;
+}
+
+void dwmac_dma_start_rx(unsigned long ioaddr)
+{
+       u32 value = readl(ioaddr + DMA_CONTROL);
+       value |= DMA_CONTROL_SR;
+       writel(value, ioaddr + DMA_CONTROL);
+
+       return;
+}
+
+void dwmac_dma_stop_rx(unsigned long ioaddr)
+{
+       u32 value = readl(ioaddr + DMA_CONTROL);
+       value &= ~DMA_CONTROL_SR;
+       writel(value, ioaddr + DMA_CONTROL);
+
+       return;
+}
+
+#ifdef DWMAC_DMA_DEBUG
+static void show_tx_process_state(unsigned int status)
+{
+       unsigned int state;
+       state = (status & DMA_STATUS_TS_MASK) >> DMA_STATUS_TS_SHIFT;
+
+       switch (state) {
+       case 0:
+               pr_info("- TX (Stopped): Reset or Stop command\n");
+               break;
+       case 1:
+               pr_info("- TX (Running):Fetching the Tx desc\n");
+               break;
+       case 2:
+               pr_info("- TX (Running): Waiting for end of tx\n");
+               break;
+       case 3:
+               pr_info("- TX (Running): Reading the data "
+                      "and queuing the data into the Tx buf\n");
+               break;
+       case 6:
+               pr_info("- TX (Suspended): Tx Buff Underflow "
+                      "or an unavailable Transmit descriptor\n");
+               break;
+       case 7:
+               pr_info("- TX (Running): Closing Tx descriptor\n");
+               break;
+       default:
+               break;
+       }
+       return;
+}
+
+static void show_rx_process_state(unsigned int status)
+{
+       unsigned int state;
+       state = (status & DMA_STATUS_RS_MASK) >> DMA_STATUS_RS_SHIFT;
+
+       switch (state) {
+       case 0:
+               pr_info("- RX (Stopped): Reset or Stop command\n");
+               break;
+       case 1:
+               pr_info("- RX (Running): Fetching the Rx desc\n");
+               break;
+       case 2:
+               pr_info("- RX (Running):Checking for end of pkt\n");
+               break;
+       case 3:
+               pr_info("- RX (Running): Waiting for Rx pkt\n");
+               break;
+       case 4:
+               pr_info("- RX (Suspended): Unavailable Rx buf\n");
+               break;
+       case 5:
+               pr_info("- RX (Running): Closing Rx descriptor\n");
+               break;
+       case 6:
+               pr_info("- RX(Running): Flushing the current frame"
+                      " from the Rx buf\n");
+               break;
+       case 7:
+               pr_info("- RX (Running): Queuing the Rx frame"
+                      " from the Rx buf into memory\n");
+               break;
+       default:
+               break;
+       }
+       return;
+}
+#endif
+
+int dwmac_dma_interrupt(unsigned long ioaddr,
+                       struct stmmac_extra_stats *x)
+{
+       int ret = 0;
+       /* read the status register (CSR5) */
+       u32 intr_status = readl(ioaddr + DMA_STATUS);
+
+       DBG(INFO, "%s: [CSR5: 0x%08x]\n", __func__, intr_status);
+#ifdef DWMAC_DMA_DEBUG
+       /* It displays the DMA process states (CSR5 register) */
+       show_tx_process_state(intr_status);
+       show_rx_process_state(intr_status);
+#endif
+       /* ABNORMAL interrupts */
+       if (unlikely(intr_status & DMA_STATUS_AIS)) {
+               DBG(INFO, "CSR5[15] DMA ABNORMAL IRQ: ");
+               if (unlikely(intr_status & DMA_STATUS_UNF)) {
+                       DBG(INFO, "transmit underflow\n");
+                       ret = tx_hard_error_bump_tc;
+                       x->tx_undeflow_irq++;
+               }
+               if (unlikely(intr_status & DMA_STATUS_TJT)) {
+                       DBG(INFO, "transmit jabber\n");
+                       x->tx_jabber_irq++;
+               }
+               if (unlikely(intr_status & DMA_STATUS_OVF)) {
+                       DBG(INFO, "recv overflow\n");
+                       x->rx_overflow_irq++;
+               }
+               if (unlikely(intr_status & DMA_STATUS_RU)) {
+                       DBG(INFO, "receive buffer unavailable\n");
+                       x->rx_buf_unav_irq++;
+               }
+               if (unlikely(intr_status & DMA_STATUS_RPS)) {
+                       DBG(INFO, "receive process stopped\n");
+                       x->rx_process_stopped_irq++;
+               }
+               if (unlikely(intr_status & DMA_STATUS_RWT)) {
+                       DBG(INFO, "receive watchdog\n");
+                       x->rx_watchdog_irq++;
+               }
+               if (unlikely(intr_status & DMA_STATUS_ETI)) {
+                       DBG(INFO, "transmit early interrupt\n");
+                       x->tx_early_irq++;
+               }
+               if (unlikely(intr_status & DMA_STATUS_TPS)) {
+                       DBG(INFO, "transmit process stopped\n");
+                       x->tx_process_stopped_irq++;
+                       ret = tx_hard_error;
+               }
+               if (unlikely(intr_status & DMA_STATUS_FBI)) {
+                       DBG(INFO, "fatal bus error\n");
+                       x->fatal_bus_error_irq++;
+                       ret = tx_hard_error;
+               }
+       }
+       /* TX/RX NORMAL interrupts */
+       if (intr_status & DMA_STATUS_NIS) {
+               x->normal_irq_n++;
+               if (likely((intr_status & DMA_STATUS_RI) ||
+                        (intr_status & (DMA_STATUS_TI))))
+                               ret = handle_tx_rx;
+       }
+       /* Optional hardware blocks, interrupts should be disabled */
+       if (unlikely(intr_status &
+                    (DMA_STATUS_GPI | DMA_STATUS_GMI | DMA_STATUS_GLI)))
+               pr_info("%s: unexpected status %08x\n", __func__, intr_status);
+       /* Clear the interrupt by writing a logic 1 to the CSR5[15-0] */
+       writel((intr_status & 0x1ffff), ioaddr + DMA_STATUS);
+
+       DBG(INFO, "\n\n");
+       return ret;
+}
+
+
+void stmmac_set_mac_addr(unsigned long ioaddr, u8 addr[6],
+                        unsigned int high, unsigned int low)
+{
+       unsigned long data;
+
+       data = (addr[5] << 8) | addr[4];
+       writel(data, ioaddr + high);
+       data = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0];
+       writel(data, ioaddr + low);
+
+       return;
+}
+
+void stmmac_get_mac_addr(unsigned long ioaddr, unsigned char *addr,
+                        unsigned int high, unsigned int low)
+{
+       unsigned int hi_addr, lo_addr;
+
+       /* Read the MAC address from the hardware */
+       hi_addr = readl(ioaddr + high);
+       lo_addr = readl(ioaddr + low);
+
+       /* Extract the MAC address from the high and low words */
+       addr[0] = lo_addr & 0xff;
+       addr[1] = (lo_addr >> 8) & 0xff;
+       addr[2] = (lo_addr >> 16) & 0xff;
+       addr[3] = (lo_addr >> 24) & 0xff;
+       addr[4] = hi_addr & 0xff;
+       addr[5] = (hi_addr >> 8) & 0xff;
+
+       return;
+}
+
index 6d2eae3040e51ab027181c3d476f4c2b3aa418ab..ba35e6943cf4e956d4c94e54fbddd3c93bb31a6e 100644 (file)
@@ -20,7 +20,8 @@
   Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
 *******************************************************************************/
 
-#define DRV_MODULE_VERSION     "Oct_09"
+#define DRV_MODULE_VERSION     "Jan_2010"
+#include <linux/stmmac.h>
 
 #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
 #define STMMAC_VLAN_TAG_USED
@@ -57,7 +58,7 @@ struct stmmac_priv {
        int rx_csum;
        unsigned int dma_buf_sz;
        struct device *device;
-       struct mac_device_info *mac_type;
+       struct mac_device_info *hw;
 
        struct stmmac_extra_stats xstats;
        struct napi_struct napi;
@@ -69,6 +70,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 *bsp_priv;
 
        int phy_irq;
@@ -93,6 +95,28 @@ struct stmmac_priv {
 #endif
 };
 
+#ifdef CONFIG_STM_DRIVERS
+#include <linux/stm/pad.h>
+static inline int stmmac_claim_resource(struct platform_device *pdev)
+{
+       int ret = 0;
+       struct plat_stmmacenet_data *plat_dat = pdev->dev.platform_data;
+
+       /* Pad routing setup */
+       if (IS_ERR(devm_stm_pad_claim(&pdev->dev, plat_dat->pad_config,
+                       dev_name(&pdev->dev)))) {
+               printk(KERN_ERR "%s: Failed to request pads!\n", __func__);
+               ret = -ENODEV;
+       }
+       return ret;
+}
+#else
+static inline int stmmac_claim_resource(struct platform_device *pdev)
+{
+       return 0;
+}
+#endif
+
 extern int stmmac_mdio_unregister(struct net_device *ndev);
 extern int stmmac_mdio_register(struct net_device *ndev);
 extern void stmmac_set_ethtool_ops(struct net_device *netdev);
index 694ebe6a07582f93e81a3fdee272c2ae348109c3..0abeff6193a1a21eb48c028c28ba506dcf4749c0 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/phy.h>
 
 #include "stmmac.h"
+#include "dwmac_dma.h"
 
 #define REG_SPACE_SIZE 0x1054
 #define MAC100_ETHTOOL_NAME    "st_mac100"
@@ -268,8 +269,8 @@ stmmac_set_pauseparam(struct net_device *netdev,
                }
        } else {
                unsigned long ioaddr = netdev->base_addr;
-               priv->mac_type->ops->flow_ctrl(ioaddr, phy->duplex,
-                                              priv->flow_ctrl, priv->pause);
+               priv->hw->mac->flow_ctrl(ioaddr, phy->duplex,
+                                        priv->flow_ctrl, priv->pause);
        }
        spin_unlock(&priv->lock);
        return ret;
@@ -283,8 +284,8 @@ static void stmmac_get_ethtool_stats(struct net_device *dev,
        int i;
 
        /* Update HW stats if supported */
-       priv->mac_type->ops->dma_diagnostic_fr(&dev->stats, &priv->xstats,
-                                              ioaddr);
+       priv->hw->dma->dma_diagnostic_fr(&dev->stats, (void *) &priv->xstats,
+                                        ioaddr);
 
        for (i = 0; i < STMMAC_STATS_LEN; i++) {
                char *p = (char *)priv + stmmac_gstrings_stats[i].stat_offset;
index 508fba8fa07f41a12ed0be5a8828b630dd885c24..a6733612d64a66fb5f083699254d792da867bacf 100644 (file)
@@ -32,7 +32,6 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/interrupt.h>
-#include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/platform_device.h>
 #include <linux/ip.h>
@@ -45,7 +44,6 @@
 #include <linux/phy.h>
 #include <linux/if_vlan.h>
 #include <linux/dma-mapping.h>
-#include <linux/stm/soc.h>
 #include "stmmac.h"
 
 #define STMMAC_RESOURCE_NAME   "stmmaceth"
@@ -226,41 +224,38 @@ static void stmmac_adjust_link(struct net_device *dev)
                if (phydev->duplex != priv->oldduplex) {
                        new_state = 1;
                        if (!(phydev->duplex))
-                               ctrl &= ~priv->mac_type->hw.link.duplex;
+                               ctrl &= ~priv->hw->link.duplex;
                        else
-                               ctrl |= priv->mac_type->hw.link.duplex;
+                               ctrl |= priv->hw->link.duplex;
                        priv->oldduplex = phydev->duplex;
                }
                /* Flow Control operation */
                if (phydev->pause)
-                       priv->mac_type->ops->flow_ctrl(ioaddr, phydev->duplex,
-                                                      fc, pause_time);
+                       priv->hw->mac->flow_ctrl(ioaddr, phydev->duplex,
+                                                fc, pause_time);
 
                if (phydev->speed != priv->speed) {
                        new_state = 1;
                        switch (phydev->speed) {
                        case 1000:
                                if (likely(priv->is_gmac))
-                                       ctrl &= ~priv->mac_type->hw.link.port;
+                                       ctrl &= ~priv->hw->link.port;
                                break;
                        case 100:
                        case 10:
                                if (priv->is_gmac) {
-                                       ctrl |= priv->mac_type->hw.link.port;
+                                       ctrl |= priv->hw->link.port;
                                        if (phydev->speed == SPEED_100) {
-                                               ctrl |=
-                                                   priv->mac_type->hw.link.
-                                                   speed;
+                                               ctrl |= priv->hw->link.speed;
                                        } else {
-                                               ctrl &=
-                                                   ~(priv->mac_type->hw.
-                                                     link.speed);
+                                               ctrl &= ~(priv->hw->link.speed);
                                        }
                                } else {
-                                       ctrl &= ~priv->mac_type->hw.link.port;
+                                       ctrl &= ~priv->hw->link.port;
                                }
-                               priv->fix_mac_speed(priv->bsp_priv,
-                                                   phydev->speed);
+                               if (likely(priv->fix_mac_speed))
+                                       priv->fix_mac_speed(priv->bsp_priv,
+                                                           phydev->speed);
                                break;
                        default:
                                if (netif_msg_link(priv))
@@ -305,8 +300,8 @@ static int stmmac_init_phy(struct net_device *dev)
 {
        struct stmmac_priv *priv = netdev_priv(dev);
        struct phy_device *phydev;
-       char phy_id[BUS_ID_SIZE];       /* PHY to connect */
-       char bus_id[BUS_ID_SIZE];
+       char phy_id[MII_BUS_ID_SIZE + 3];
+       char bus_id[MII_BUS_ID_SIZE];
 
        priv->oldlink = 0;
        priv->speed = 0;
@@ -318,7 +313,8 @@ static int stmmac_init_phy(struct net_device *dev)
        }
 
        snprintf(bus_id, MII_BUS_ID_SIZE, "%x", priv->bus_id);
-       snprintf(phy_id, BUS_ID_SIZE, PHY_ID_FMT, bus_id, priv->phy_addr);
+       snprintf(phy_id, MII_BUS_ID_SIZE + 3, PHY_ID_FMT, bus_id,
+                priv->phy_addr);
        pr_debug("stmmac_init_phy:  trying to attach to %s\n", phy_id);
 
        phydev = phy_connect(dev, phy_id, &stmmac_adjust_link, 0,
@@ -508,8 +504,8 @@ static void init_dma_desc_rings(struct net_device *dev)
        priv->cur_tx = 0;
 
        /* Clear the Rx/Tx descriptors */
-       priv->mac_type->ops->init_rx_desc(priv->dma_rx, rxsize, dis_ic);
-       priv->mac_type->ops->init_tx_desc(priv->dma_tx, txsize);
+       priv->hw->desc->init_rx_desc(priv->dma_rx, rxsize, dis_ic);
+       priv->hw->desc->init_tx_desc(priv->dma_tx, txsize);
 
        if (netif_msg_hw(priv)) {
                pr_info("RX descriptor ring:\n");
@@ -544,8 +540,8 @@ static void dma_free_tx_skbufs(struct stmmac_priv *priv)
                        struct dma_desc *p = priv->dma_tx + i;
                        if (p->des2)
                                dma_unmap_single(priv->device, p->des2,
-                                priv->mac_type->ops->get_tx_len(p),
-                                DMA_TO_DEVICE);
+                                                priv->hw->desc->get_tx_len(p),
+                                                DMA_TO_DEVICE);
                        dev_kfree_skb_any(priv->tx_skbuff[i]);
                        priv->tx_skbuff[i] = NULL;
                }
@@ -574,50 +570,6 @@ static void free_dma_desc_resources(struct stmmac_priv *priv)
        return;
 }
 
-/**
- * stmmac_dma_start_tx
- * @ioaddr: device I/O address
- * Description:  this function starts the DMA tx process.
- */
-static void stmmac_dma_start_tx(unsigned long ioaddr)
-{
-       u32 value = readl(ioaddr + DMA_CONTROL);
-       value |= DMA_CONTROL_ST;
-       writel(value, ioaddr + DMA_CONTROL);
-       return;
-}
-
-static void stmmac_dma_stop_tx(unsigned long ioaddr)
-{
-       u32 value = readl(ioaddr + DMA_CONTROL);
-       value &= ~DMA_CONTROL_ST;
-       writel(value, ioaddr + DMA_CONTROL);
-       return;
-}
-
-/**
- * stmmac_dma_start_rx
- * @ioaddr: device I/O address
- * Description:  this function starts the DMA rx process.
- */
-static void stmmac_dma_start_rx(unsigned long ioaddr)
-{
-       u32 value = readl(ioaddr + DMA_CONTROL);
-       value |= DMA_CONTROL_SR;
-       writel(value, ioaddr + DMA_CONTROL);
-
-       return;
-}
-
-static void stmmac_dma_stop_rx(unsigned long ioaddr)
-{
-       u32 value = readl(ioaddr + DMA_CONTROL);
-       value &= ~DMA_CONTROL_SR;
-       writel(value, ioaddr + DMA_CONTROL);
-
-       return;
-}
-
 /**
  *  stmmac_dma_operation_mode - HW DMA operation mode
  *  @priv : pointer to the private device structure.
@@ -629,18 +581,18 @@ static void stmmac_dma_operation_mode(struct stmmac_priv *priv)
 {
        if (!priv->is_gmac) {
                /* MAC 10/100 */
-               priv->mac_type->ops->dma_mode(priv->dev->base_addr, tc, 0);
+               priv->hw->dma->dma_mode(priv->dev->base_addr, tc, 0);
                priv->tx_coe = NO_HW_CSUM;
        } else {
                if ((priv->dev->mtu <= ETH_DATA_LEN) && (tx_coe)) {
-                       priv->mac_type->ops->dma_mode(priv->dev->base_addr,
-                                                     SF_DMA_MODE, SF_DMA_MODE);
+                       priv->hw->dma->dma_mode(priv->dev->base_addr,
+                                               SF_DMA_MODE, SF_DMA_MODE);
                        tc = SF_DMA_MODE;
                        priv->tx_coe = HW_CSUM;
                } else {
                        /* Checksum computation is performed in software. */
-                       priv->mac_type->ops->dma_mode(priv->dev->base_addr, tc,
-                                                     SF_DMA_MODE);
+                       priv->hw->dma->dma_mode(priv->dev->base_addr, tc,
+                                               SF_DMA_MODE);
                        priv->tx_coe = NO_HW_CSUM;
                }
        }
@@ -649,88 +601,6 @@ static void stmmac_dma_operation_mode(struct stmmac_priv *priv)
        return;
 }
 
-#ifdef STMMAC_DEBUG
-/**
- * show_tx_process_state
- * @status: tx descriptor status field
- * Description: it shows the Transmit Process State for CSR5[22:20]
- */
-static void show_tx_process_state(unsigned int status)
-{
-       unsigned int state;
-       state = (status & DMA_STATUS_TS_MASK) >> DMA_STATUS_TS_SHIFT;
-
-       switch (state) {
-       case 0:
-               pr_info("- TX (Stopped): Reset or Stop command\n");
-               break;
-       case 1:
-               pr_info("- TX (Running):Fetching the Tx desc\n");
-               break;
-       case 2:
-               pr_info("- TX (Running): Waiting for end of tx\n");
-               break;
-       case 3:
-               pr_info("- TX (Running): Reading the data "
-                      "and queuing the data into the Tx buf\n");
-               break;
-       case 6:
-               pr_info("- TX (Suspended): Tx Buff Underflow "
-                      "or an unavailable Transmit descriptor\n");
-               break;
-       case 7:
-               pr_info("- TX (Running): Closing Tx descriptor\n");
-               break;
-       default:
-               break;
-       }
-       return;
-}
-
-/**
- * show_rx_process_state
- * @status: rx descriptor status field
- * Description: it shows the  Receive Process State for CSR5[19:17]
- */
-static void show_rx_process_state(unsigned int status)
-{
-       unsigned int state;
-       state = (status & DMA_STATUS_RS_MASK) >> DMA_STATUS_RS_SHIFT;
-
-       switch (state) {
-       case 0:
-               pr_info("- RX (Stopped): Reset or Stop command\n");
-               break;
-       case 1:
-               pr_info("- RX (Running): Fetching the Rx desc\n");
-               break;
-       case 2:
-               pr_info("- RX (Running):Checking for end of pkt\n");
-               break;
-       case 3:
-               pr_info("- RX (Running): Waiting for Rx pkt\n");
-               break;
-       case 4:
-               pr_info("- RX (Suspended): Unavailable Rx buf\n");
-               break;
-       case 5:
-               pr_info("- RX (Running): Closing Rx descriptor\n");
-               break;
-       case 6:
-               pr_info("- RX(Running): Flushing the current frame"
-                      " from the Rx buf\n");
-               break;
-       case 7:
-               pr_info("- RX (Running): Queuing the Rx frame"
-                      " from the Rx buf into memory\n");
-               break;
-       default:
-               break;
-       }
-       return;
-}
-#endif
-
 /**
  * stmmac_tx:
  * @priv: private driver structure
@@ -748,16 +618,16 @@ static void stmmac_tx(struct stmmac_priv *priv)
                struct dma_desc *p = priv->dma_tx + entry;
 
                /* Check if the descriptor is owned by the DMA. */
-               if (priv->mac_type->ops->get_tx_owner(p))
+               if (priv->hw->desc->get_tx_owner(p))
                        break;
 
                /* Verify tx error by looking at the last segment */
-               last = priv->mac_type->ops->get_tx_ls(p);
+               last = priv->hw->desc->get_tx_ls(p);
                if (likely(last)) {
                        int tx_error =
-                           priv->mac_type->ops->tx_status(&priv->dev->stats,
-                                                          &priv->xstats,
-                                                          p, ioaddr);
+                               priv->hw->desc->tx_status(&priv->dev->stats,
+                                                         &priv->xstats, p,
+                                                         ioaddr);
                        if (likely(tx_error == 0)) {
                                priv->dev->stats.tx_packets++;
                                priv->xstats.tx_pkt_n++;
@@ -769,7 +639,7 @@ static void stmmac_tx(struct stmmac_priv *priv)
 
                if (likely(p->des2))
                        dma_unmap_single(priv->device, p->des2,
-                                        priv->mac_type->ops->get_tx_len(p),
+                                        priv->hw->desc->get_tx_len(p),
                                         DMA_TO_DEVICE);
                if (unlikely(p->des3))
                        p->des3 = 0;
@@ -790,7 +660,7 @@ static void stmmac_tx(struct stmmac_priv *priv)
                        priv->tx_skbuff[entry] = NULL;
                }
 
-               priv->mac_type->ops->release_tx_desc(p);
+               priv->hw->desc->release_tx_desc(p);
 
                entry = (++priv->dirty_tx) % txsize;
        }
@@ -814,7 +684,7 @@ static inline void stmmac_enable_irq(struct stmmac_priv *priv)
                priv->tm->timer_start(tmrate);
        else
 #endif
-       writel(DMA_INTR_DEFAULT_MASK, priv->dev->base_addr + DMA_INTR_ENA);
+               priv->hw->dma->enable_dma_irq(priv->dev->base_addr);
 }
 
 static inline void stmmac_disable_irq(struct stmmac_priv *priv)
@@ -824,7 +694,7 @@ static inline void stmmac_disable_irq(struct stmmac_priv *priv)
                priv->tm->timer_stop();
        else
 #endif
-       writel(0, priv->dev->base_addr + DMA_INTR_ENA);
+               priv->hw->dma->disable_dma_irq(priv->dev->base_addr);
 }
 
 static int stmmac_has_work(struct stmmac_priv *priv)
@@ -832,7 +702,7 @@ static int stmmac_has_work(struct stmmac_priv *priv)
        unsigned int has_work = 0;
        int rxret, tx_work = 0;
 
-       rxret = priv->mac_type->ops->get_rx_owner(priv->dma_rx +
+       rxret = priv->hw->desc->get_rx_owner(priv->dma_rx +
                (priv->cur_rx % priv->dma_rx_size));
 
        if (priv->dirty_tx != priv->cur_tx)
@@ -883,12 +753,12 @@ static void stmmac_tx_err(struct stmmac_priv *priv)
 {
        netif_stop_queue(priv->dev);
 
-       stmmac_dma_stop_tx(priv->dev->base_addr);
+       priv->hw->dma->stop_tx(priv->dev->base_addr);
        dma_free_tx_skbufs(priv);
-       priv->mac_type->ops->init_tx_desc(priv->dma_tx, priv->dma_tx_size);
+       priv->hw->desc->init_tx_desc(priv->dma_tx, priv->dma_tx_size);
        priv->dirty_tx = 0;
        priv->cur_tx = 0;
-       stmmac_dma_start_tx(priv->dev->base_addr);
+       priv->hw->dma->start_tx(priv->dev->base_addr);
 
        priv->dev->stats.tx_errors++;
        netif_wake_queue(priv->dev);
@@ -896,95 +766,27 @@ static void stmmac_tx_err(struct stmmac_priv *priv)
        return;
 }
 
-/**
- * stmmac_dma_interrupt - Interrupt handler for the driver
- * @dev: net device structure
- * Description: Interrupt handler for the driver (DMA).
- */
-static void stmmac_dma_interrupt(struct net_device *dev)
-{
-       unsigned long ioaddr = dev->base_addr;
-       struct stmmac_priv *priv = netdev_priv(dev);
-       /* read the status register (CSR5) */
-       u32 intr_status = readl(ioaddr + DMA_STATUS);
-
-       DBG(intr, INFO, "%s: [CSR5: 0x%08x]\n", __func__, intr_status);
 
-#ifdef STMMAC_DEBUG
-       /* It displays the DMA transmit process state (CSR5 register) */
-       if (netif_msg_tx_done(priv))
-               show_tx_process_state(intr_status);
-       if (netif_msg_rx_status(priv))
-               show_rx_process_state(intr_status);
-#endif
-       /* ABNORMAL interrupts */
-       if (unlikely(intr_status & DMA_STATUS_AIS)) {
-               DBG(intr, INFO, "CSR5[15] DMA ABNORMAL IRQ: ");
-               if (unlikely(intr_status & DMA_STATUS_UNF)) {
-                       DBG(intr, INFO, "transmit underflow\n");
-                       if (unlikely(tc != SF_DMA_MODE) && (tc <= 256)) {
-                               /* Try to bump up the threshold */
-                               tc += 64;
-                               priv->mac_type->ops->dma_mode(ioaddr, tc,
-                                             SF_DMA_MODE);
-                               priv->xstats.threshold = tc;
-                       }
-                       stmmac_tx_err(priv);
-                       priv->xstats.tx_undeflow_irq++;
-               }
-               if (unlikely(intr_status & DMA_STATUS_TJT)) {
-                       DBG(intr, INFO, "transmit jabber\n");
-                       priv->xstats.tx_jabber_irq++;
-               }
-               if (unlikely(intr_status & DMA_STATUS_OVF)) {
-                       DBG(intr, INFO, "recv overflow\n");
-                       priv->xstats.rx_overflow_irq++;
-               }
-               if (unlikely(intr_status & DMA_STATUS_RU)) {
-                       DBG(intr, INFO, "receive buffer unavailable\n");
-                       priv->xstats.rx_buf_unav_irq++;
-               }
-               if (unlikely(intr_status & DMA_STATUS_RPS)) {
-                       DBG(intr, INFO, "receive process stopped\n");
-                       priv->xstats.rx_process_stopped_irq++;
-               }
-               if (unlikely(intr_status & DMA_STATUS_RWT)) {
-                       DBG(intr, INFO, "receive watchdog\n");
-                       priv->xstats.rx_watchdog_irq++;
-               }
-               if (unlikely(intr_status & DMA_STATUS_ETI)) {
-                       DBG(intr, INFO, "transmit early interrupt\n");
-                       priv->xstats.tx_early_irq++;
-               }
-               if (unlikely(intr_status & DMA_STATUS_TPS)) {
-                       DBG(intr, INFO, "transmit process stopped\n");
-                       priv->xstats.tx_process_stopped_irq++;
-                       stmmac_tx_err(priv);
-               }
-               if (unlikely(intr_status & DMA_STATUS_FBI)) {
-                       DBG(intr, INFO, "fatal bus error\n");
-                       priv->xstats.fatal_bus_error_irq++;
-                       stmmac_tx_err(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);
+       if (likely(status == handle_tx_rx))
+               _stmmac_schedule(priv);
+
+       else if (unlikely(status == tx_hard_error_bump_tc)) {
+               /* 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->xstats.threshold = tc;
                }
-       }
-
-       /* TX/RX NORMAL interrupts */
-       if (intr_status & DMA_STATUS_NIS) {
-               priv->xstats.normal_irq_n++;
-               if (likely((intr_status & DMA_STATUS_RI) ||
-                        (intr_status & (DMA_STATUS_TI))))
-                               _stmmac_schedule(priv);
-       }
-
-       /* Optional hardware blocks, interrupts should be disabled */
-       if (unlikely(intr_status &
-                    (DMA_STATUS_GPI | DMA_STATUS_GMI | DMA_STATUS_GLI)))
-               pr_info("%s: unexpected status %08x\n", __func__, intr_status);
-
-       /* Clear the interrupt by writing a logic 1 to the CSR5[15-0] */
-       writel((intr_status & 0x1ffff), ioaddr + DMA_STATUS);
-
-       DBG(intr, INFO, "\n\n");
+               stmmac_tx_err(priv);
+       } else if (unlikely(status == tx_hard_error))
+               stmmac_tx_err(priv);
 
        return;
 }
@@ -1058,17 +860,20 @@ static int stmmac_open(struct net_device *dev)
        init_dma_desc_rings(dev);
 
        /* DMA initialization and SW reset */
-       if (unlikely(priv->mac_type->ops->dma_init(ioaddr,
-               priv->pbl, priv->dma_tx_phy, priv->dma_rx_phy) < 0)) {
+       if (unlikely(priv->hw->dma->init(ioaddr, priv->pbl, priv->dma_tx_phy,
+                                        priv->dma_rx_phy) < 0)) {
 
                pr_err("%s: DMA initialization failed\n", __func__);
                return -1;
        }
 
        /* Copy the MAC addr into the HW  */
-       priv->mac_type->ops->set_umac_addr(ioaddr, dev->dev_addr, 0);
+       priv->hw->mac->set_umac_addr(ioaddr, dev->dev_addr, 0);
+       /* If required, perform hw setup of the bus. */
+       if (priv->bus_setup)
+               priv->bus_setup(ioaddr);
        /* Initialize the MAC Core */
-       priv->mac_type->ops->core_init(ioaddr);
+       priv->hw->mac->core_init(ioaddr);
 
        priv->shutdown = 0;
 
@@ -1089,16 +894,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);
-       stmmac_dma_start_tx(ioaddr);
-       stmmac_dma_start_rx(ioaddr);
+       priv->hw->dma->start_tx(ioaddr);
+       priv->hw->dma->start_rx(ioaddr);
 
 #ifdef CONFIG_STMMAC_TIMER
        priv->tm->timer_start(tmrate);
 #endif
        /* Dump DMA/MAC registers */
        if (netif_msg_hw(priv)) {
-               priv->mac_type->ops->dump_mac_regs(ioaddr);
-               priv->mac_type->ops->dump_dma_regs(ioaddr);
+               priv->hw->mac->dump_regs(ioaddr);
+               priv->hw->dma->dump_regs(ioaddr);
        }
 
        if (priv->phydev)
@@ -1142,8 +947,8 @@ static int stmmac_release(struct net_device *dev)
        free_irq(dev->irq, dev);
 
        /* Stop TX/RX DMA and clear the descriptors */
-       stmmac_dma_stop_tx(dev->base_addr);
-       stmmac_dma_stop_rx(dev->base_addr);
+       priv->hw->dma->stop_tx(dev->base_addr);
+       priv->hw->dma->stop_rx(dev->base_addr);
 
        /* Release and free the Rx/Tx resources */
        free_dma_desc_resources(priv);
@@ -1214,8 +1019,8 @@ static unsigned int stmmac_handle_jumbo_frames(struct sk_buff *skb,
                desc->des2 = dma_map_single(priv->device, skb->data,
                                            BUF_SIZE_8KiB, DMA_TO_DEVICE);
                desc->des3 = desc->des2 + BUF_SIZE_4KiB;
-               priv->mac_type->ops->prepare_tx_desc(desc, 1, BUF_SIZE_8KiB,
-                                                    csum_insertion);
+               priv->hw->desc->prepare_tx_desc(desc, 1, BUF_SIZE_8KiB,
+                                               csum_insertion);
 
                entry = (++priv->cur_tx) % txsize;
                desc = priv->dma_tx + entry;
@@ -1224,16 +1029,16 @@ static unsigned int stmmac_handle_jumbo_frames(struct sk_buff *skb,
                                        skb->data + BUF_SIZE_8KiB,
                                        buf2_size, DMA_TO_DEVICE);
                desc->des3 = desc->des2 + BUF_SIZE_4KiB;
-               priv->mac_type->ops->prepare_tx_desc(desc, 0,
-                                                    buf2_size, csum_insertion);
-               priv->mac_type->ops->set_tx_owner(desc);
+               priv->hw->desc->prepare_tx_desc(desc, 0, buf2_size,
+                                               csum_insertion);
+               priv->hw->desc->set_tx_owner(desc);
                priv->tx_skbuff[entry] = NULL;
        } else {
                desc->des2 = dma_map_single(priv->device, skb->data,
                                        nopaged_len, DMA_TO_DEVICE);
                desc->des3 = desc->des2 + BUF_SIZE_4KiB;
-               priv->mac_type->ops->prepare_tx_desc(desc, 1, nopaged_len,
-                                                    csum_insertion);
+               priv->hw->desc->prepare_tx_desc(desc, 1, nopaged_len,
+                                               csum_insertion);
        }
        return entry;
 }
@@ -1301,8 +1106,8 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
                unsigned int nopaged_len = skb_headlen(skb);
                desc->des2 = dma_map_single(priv->device, skb->data,
                                        nopaged_len, DMA_TO_DEVICE);
-               priv->mac_type->ops->prepare_tx_desc(desc, 1, nopaged_len,
-                                                    csum_insertion);
+               priv->hw->desc->prepare_tx_desc(desc, 1, nopaged_len,
+                                               csum_insertion);
        }
 
        for (i = 0; i < nfrags; i++) {
@@ -1317,21 +1122,20 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
                                          frag->page_offset,
                                          len, DMA_TO_DEVICE);
                priv->tx_skbuff[entry] = NULL;
-               priv->mac_type->ops->prepare_tx_desc(desc, 0, len,
-                                                    csum_insertion);
-               priv->mac_type->ops->set_tx_owner(desc);
+               priv->hw->desc->prepare_tx_desc(desc, 0, len, csum_insertion);
+               priv->hw->desc->set_tx_owner(desc);
        }
 
        /* Interrupt on completition only for the latest segment */
-       priv->mac_type->ops->close_tx_desc(desc);
+       priv->hw->desc->close_tx_desc(desc);
 
 #ifdef CONFIG_STMMAC_TIMER
        /* Clean IC while using timer */
        if (likely(priv->tm->enable))
-               priv->mac_type->ops->clear_tx_ic(desc);
+               priv->hw->desc->clear_tx_ic(desc);
 #endif
        /* To avoid raise condition */
-       priv->mac_type->ops->set_tx_owner(first);
+       priv->hw->desc->set_tx_owner(first);
 
        priv->cur_tx++;
 
@@ -1353,8 +1157,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
 
        dev->stats.tx_bytes += skb->len;
 
-       /* CSR1 enables the transmit DMA to check for new descriptor */
-       writel(1, dev->base_addr + DMA_XMT_POLL_DEMAND);
+       priv->hw->dma->enable_dma_transmission(dev->base_addr);
 
        return NETDEV_TX_OK;
 }
@@ -1391,7 +1194,7 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv)
                        }
                        RX_DBG(KERN_INFO "\trefill entry #%d\n", entry);
                }
-               priv->mac_type->ops->set_rx_owner(p + entry);
+               priv->hw->desc->set_rx_owner(p + entry);
        }
        return;
 }
@@ -1412,7 +1215,7 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit)
        }
 #endif
        count = 0;
-       while (!priv->mac_type->ops->get_rx_owner(p)) {
+       while (!priv->hw->desc->get_rx_owner(p)) {
                int status;
 
                if (count >= limit)
@@ -1425,15 +1228,14 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit)
                prefetch(p_next);
 
                /* read the status of the incoming frame */
-               status = (priv->mac_type->ops->rx_status(&priv->dev->stats,
-                                                        &priv->xstats, p));
+               status = (priv->hw->desc->rx_status(&priv->dev->stats,
+                                                   &priv->xstats, p));
                if (unlikely(status == discard_frame))
                        priv->dev->stats.rx_errors++;
                else {
                        struct sk_buff *skb;
                        /* Length should omit the CRC */
-                       int frame_len =
-                           priv->mac_type->ops->get_rx_frame_len(p) - 4;
+                       int frame_len = priv->hw->desc->get_rx_frame_len(p) - 4;
 
 #ifdef STMMAC_RX_DEBUG
                        if (frame_len > ETH_FRAME_LEN)
@@ -1569,7 +1371,7 @@ static void stmmac_multicast_list(struct net_device *dev)
        struct stmmac_priv *priv = netdev_priv(dev);
 
        spin_lock(&priv->lock);
-       priv->mac_type->ops->set_filter(dev);
+       priv->hw->mac->set_filter(dev);
        spin_unlock(&priv->lock);
        return;
 }
@@ -1623,9 +1425,10 @@ static irqreturn_t stmmac_interrupt(int irq, void *dev_id)
        if (priv->is_gmac) {
                unsigned long ioaddr = dev->base_addr;
                /* To handle GMAC own interrupts */
-               priv->mac_type->ops->host_irq_status(ioaddr);
+               priv->hw->mac->host_irq_status(ioaddr);
        }
-       stmmac_dma_interrupt(dev);
+
+       stmmac_dma_interrupt(priv);
 
        return IRQ_HANDLED;
 }
@@ -1744,7 +1547,7 @@ static int stmmac_probe(struct net_device *dev)
        netif_napi_add(dev, &priv->napi, stmmac_poll, 64);
 
        /* Get the MAC address */
-       priv->mac_type->ops->get_umac_addr(dev->base_addr, dev->dev_addr, 0);
+       priv->hw->mac->get_umac_addr(dev->base_addr, dev->dev_addr, 0);
 
        if (!is_valid_ether_addr(dev->dev_addr))
                pr_warning("\tno valid MAC address;"
@@ -1779,16 +1582,16 @@ static int stmmac_mac_device_setup(struct net_device *dev)
        struct mac_device_info *device;
 
        if (priv->is_gmac)
-               device = gmac_setup(ioaddr);
+               device = dwmac1000_setup(ioaddr);
        else
-               device = mac100_setup(ioaddr);
+               device = dwmac100_setup(ioaddr);
 
        if (!device)
                return -ENOMEM;
 
-       priv->mac_type = device;
+       priv->hw = device;
 
-       priv->wolenabled = priv->mac_type->hw.pmt;      /* PMT supported */
+       priv->wolenabled = priv->hw->pmt;       /* PMT supported */
        if (priv->wolenabled == PMT_SUPPORTED)
                priv->wolopts = WAKE_MAGIC;             /* Magic Frame */
 
@@ -1797,8 +1600,7 @@ static int stmmac_mac_device_setup(struct net_device *dev)
 
 static int stmmacphy_dvr_probe(struct platform_device *pdev)
 {
-       struct plat_stmmacphy_data *plat_dat;
-       plat_dat = (struct plat_stmmacphy_data *)((pdev->dev).platform_data);
+       struct plat_stmmacphy_data *plat_dat = pdev->dev.platform_data;
 
        pr_debug("stmmacphy_dvr_probe: added phy for bus %d\n",
               plat_dat->bus_id);
@@ -1830,9 +1632,7 @@ static struct platform_driver stmmacphy_driver = {
 static int stmmac_associate_phy(struct device *dev, void *data)
 {
        struct stmmac_priv *priv = (struct stmmac_priv *)data;
-       struct plat_stmmacphy_data *plat_dat;
-
-       plat_dat = (struct plat_stmmacphy_data *)(dev->platform_data);
+       struct plat_stmmacphy_data *plat_dat = dev->platform_data;
 
        DBG(probe, DEBUG, "%s: checking phy for bus %d\n", __func__,
                plat_dat->bus_id);
@@ -1922,7 +1722,7 @@ static int stmmac_dvr_probe(struct platform_device *pdev)
        priv = netdev_priv(ndev);
        priv->device = &(pdev->dev);
        priv->dev = ndev;
-       plat_dat = (struct plat_stmmacenet_data *)((pdev->dev).platform_data);
+       plat_dat = pdev->dev.platform_data;
        priv->bus_id = plat_dat->bus_id;
        priv->pbl = plat_dat->pbl;      /* TLI */
        priv->is_gmac = plat_dat->has_gmac;     /* GMAC is on board */
@@ -1932,6 +1732,11 @@ static int stmmac_dvr_probe(struct platform_device *pdev)
        /* Set the I/O base addr */
        ndev->base_addr = (unsigned long)addr;
 
+       /* Verify embedded resource for the platform */
+       ret = stmmac_claim_resource(pdev);
+       if (ret < 0)
+               goto out;
+
        /* MAC HW revice detection */
        ret = stmmac_mac_device_setup(ndev);
        if (ret < 0)
@@ -1952,6 +1757,7 @@ static int stmmac_dvr_probe(struct platform_device *pdev)
        }
 
        priv->fix_mac_speed = plat_dat->fix_mac_speed;
+       priv->bus_setup = plat_dat->bus_setup;
        priv->bsp_priv = plat_dat->bsp_priv;
 
        pr_info("\t%s - (dev. name: %s - id: %d, IRQ #%d\n"
@@ -1986,12 +1792,13 @@ out:
 static int stmmac_dvr_remove(struct platform_device *pdev)
 {
        struct net_device *ndev = platform_get_drvdata(pdev);
+       struct stmmac_priv *priv = netdev_priv(ndev);
        struct resource *res;
 
        pr_info("%s:\n\tremoving driver", __func__);
 
-       stmmac_dma_stop_rx(ndev->base_addr);
-       stmmac_dma_stop_tx(ndev->base_addr);
+       priv->hw->dma->stop_rx(ndev->base_addr);
+       priv->hw->dma->stop_tx(ndev->base_addr);
 
        stmmac_mac_disable_rx(ndev->base_addr);
        stmmac_mac_disable_tx(ndev->base_addr);
@@ -2038,21 +1845,20 @@ static int stmmac_suspend(struct platform_device *pdev, pm_message_t state)
                napi_disable(&priv->napi);
 
                /* Stop TX/RX DMA */
-               stmmac_dma_stop_tx(dev->base_addr);
-               stmmac_dma_stop_rx(dev->base_addr);
+               priv->hw->dma->stop_tx(dev->base_addr);
+               priv->hw->dma->stop_rx(dev->base_addr);
                /* Clear the Rx/Tx descriptors */
-               priv->mac_type->ops->init_rx_desc(priv->dma_rx,
-                                                 priv->dma_rx_size, dis_ic);
-               priv->mac_type->ops->init_tx_desc(priv->dma_tx,
-                                                 priv->dma_tx_size);
+               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);
 
                if (device_may_wakeup(&(pdev->dev))) {
                        /* Enable Power down mode by programming the PMT regs */
                        if (priv->wolenabled == PMT_SUPPORTED)
-                               priv->mac_type->ops->pmt(dev->base_addr,
-                                                        priv->wolopts);
+                               priv->hw->mac->pmt(dev->base_addr,
+                                                  priv->wolopts);
                } else {
                        stmmac_mac_disable_rx(dev->base_addr);
                }
@@ -2093,15 +1899,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->mac_type->ops->pmt(dev->base_addr, 0);
+                       priv->hw->mac->pmt(dev->base_addr, 0);
 
        netif_device_attach(dev);
 
        /* Enable the MAC and DMA */
        stmmac_mac_enable_rx(ioaddr);
        stmmac_mac_enable_tx(ioaddr);
-       stmmac_dma_start_tx(ioaddr);
-       stmmac_dma_start_rx(ioaddr);
+       priv->hw->dma->start_tx(ioaddr);
+       priv->hw->dma->start_rx(ioaddr);
 
 #ifdef CONFIG_STMMAC_TIMER
        priv->tm->timer_start(tmrate);
index 8498552a22fc20b9f99a0952b49bbd957fce5d09..fffe1d037fe667bfd2d2d6a39822e821d1227009 100644 (file)
@@ -24,7 +24,6 @@
   Maintainer: Giuseppe Cavallaro <peppe.cavallaro@st.com>
 *******************************************************************************/
 
-#include <linux/netdevice.h>
 #include <linux/mii.h>
 #include <linux/phy.h>
 
@@ -48,8 +47,8 @@ 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->mac_type->hw.mii.addr;
-       unsigned int mii_data = priv->mac_type->hw.mii.data;
+       unsigned int mii_address = priv->hw->mii.addr;
+       unsigned int mii_data = priv->hw->mii.data;
 
        int data;
        u16 regValue = (((phyaddr << 11) & (0x0000F800)) |
@@ -80,8 +79,8 @@ 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->mac_type->hw.mii.addr;
-       unsigned int mii_data = priv->mac_type->hw.mii.data;
+       unsigned int mii_address = priv->hw->mii.addr;
+       unsigned int mii_data = priv->hw->mii.data;
 
        u16 value =
            (((phyaddr << 11) & (0x0000F800)) | ((phyreg << 6) & (0x000007C0)))
@@ -112,7 +111,7 @@ 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->mac_type->hw.mii.addr;
+       unsigned int mii_address = priv->hw->mii.addr;
 
        if (priv->phy_reset) {
                pr_debug("stmmac_mdio_reset: calling phy_reset\n");
index d58e1891ca604577bb5bd1f0f83c4e09cf9c5ee5..0c972e560cf3069eeabd92bdac7ed043de13bff2 100644 (file)
@@ -206,7 +206,7 @@ IVc. Errata
 #define USE_IO_OPS 1
 #endif
 
-static const struct pci_device_id sundance_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(sundance_pci_tbl) = {
        { 0x1186, 0x1002, 0x1186, 0x1002, 0, 0, 0 },
        { 0x1186, 0x1002, 0x1186, 0x1003, 0, 0, 1 },
        { 0x1186, 0x1002, 0x1186, 0x1012, 0, 0, 2 },
index b571a1babab95e879be372bbb16bf760581559e8..b55ceb88d93f6c79b53d4a91025abf1c58ca2f7c 100644 (file)
@@ -107,7 +107,7 @@ MODULE_LICENSE("GPL");
 #define GEM_MODULE_NAME        "gem"
 #define PFX GEM_MODULE_NAME ": "
 
-static struct pci_device_id gem_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(gem_pci_tbl) = {
        { PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_GEM,
          PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
 
index 6762f1c6ec8a939da2d7f8c346fa48f4e7691c47..76ccd31cbf5099c445e35cb1124b80a7d6474331 100644 (file)
@@ -3211,7 +3211,7 @@ static void __devexit happy_meal_pci_remove(struct pci_dev *pdev)
        dev_set_drvdata(&pdev->dev, NULL);
 }
 
-static struct pci_device_id happymeal_pci_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(happymeal_pci_ids) = {
        { PCI_DEVICE(PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_HAPPYMEAL) },
        { }                     /* Terminating entry */
 };
index bc74db0d12f37e0b015f1d6b0d099b9ed77f6bc2..d65764ea1d8310cdec7cba20bc4642587bb3320e 100644 (file)
@@ -1062,10 +1062,7 @@ static struct vnet * __devinit vnet_new(const u64 *local_mac)
                goto err_out_free_dev;
        }
 
-       printk(KERN_INFO "%s: Sun LDOM vnet ", dev->name);
-
-       for (i = 0; i < 6; i++)
-               printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':');
+       printk(KERN_INFO "%s: Sun LDOM vnet %pM\n", dev->name, dev->dev_addr);
 
        list_add(&vp->list, &vnet_list);
 
index 75a669d48e5ebc4be3d79b84ee09ff7a50d85845..033408f589fb87a4357be8dcc550fdd1f020e32a 100644 (file)
@@ -65,7 +65,7 @@ static const struct {
        { "TOSHIBA TC35815/TX4939" },
 };
 
-static const struct pci_device_id tc35815_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(tc35815_pci_tbl) = {
        {PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815CF), .driver_data = TC35815CF },
        {PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815_NWU), .driver_data = TC35815_NWU },
        {PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815_TX4939), .driver_data = TC35815_TX4939 },
index 80b404f2b938fc9f1202639e7a0e9be05d675406..b907bee31fd5d3671ae324c559441298c36abfbd 100644 (file)
@@ -64,7 +64,7 @@
 
 #include "tehuti.h"
 
-static struct pci_device_id __devinitdata bdx_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(bdx_pci_tbl) = {
        {0x1FC9, 0x3009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
        {0x1FC9, 0x3010, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
        {0x1FC9, 0x3014, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
index 7f82b0238e08d3e2cc64892b4d317b58c2103270..7195bdec17f3efa33e63fe6a1a0f7ea34165cfac 100644 (file)
@@ -174,7 +174,7 @@ static int tg3_debug = -1;  /* -1 == use TG3_DEF_MSG_ENABLE as value */
 module_param(tg3_debug, int, 0);
 MODULE_PARM_DESC(tg3_debug, "Tigon3 bitmapped debugging message enable value");
 
-static struct pci_device_id tg3_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(tg3_pci_tbl) = {
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5700)},
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5701)},
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5702)},
@@ -244,6 +244,12 @@ static struct pci_device_id tg3_pci_tbl[] = {
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_5717)},
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_5718)},
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_5724)},
+       {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57781)},
+       {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57785)},
+       {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57761)},
+       {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57765)},
+       {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57791)},
+       {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57795)},
        {PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9DXX)},
        {PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9MXX)},
        {PCI_DEVICE(PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1000)},
@@ -1564,7 +1570,9 @@ static void tg3_phy_toggle_apd(struct tg3 *tp, bool enable)
 {
        u32 reg;
 
-       if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS))
+       if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS) ||
+               (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 &&
+            (tp->tg3_flags2 & TG3_FLG2_MII_SERDES)))
                return;
 
        if (tp->tg3_flags3 & TG3_FLG3_PHY_IS_FET) {
@@ -1939,6 +1947,10 @@ static int tg3_phy_reset(struct tg3 *tp)
                }
        }
 
+       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 &&
+           (tp->tg3_flags2 & TG3_FLG2_MII_SERDES))
+               return 0;
+
        tg3_phy_apply_otp(tp);
 
        if (tp->tg3_flags3 & TG3_FLG3_PHY_ENABLE_APD)
@@ -2019,7 +2031,9 @@ static void tg3_frob_aux_power(struct tg3 *tp)
 {
        struct tg3 *tp_peer = tp;
 
-       if ((tp->tg3_flags2 & TG3_FLG2_IS_NIC) == 0)
+       /* The GPIOs do something completely different on 57765. */
+       if ((tp->tg3_flags2 & TG3_FLG2_IS_NIC) == 0 ||
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765)
                return;
 
        if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 ||
@@ -7439,10 +7453,13 @@ static void tg3_rings_reset(struct tg3 *tp)
                for (i = 1; i < TG3_IRQ_MAX_VECS; i++) {
                        tp->napi[i].tx_prod = 0;
                        tp->napi[i].tx_cons = 0;
-                       tw32_mailbox(tp->napi[i].prodmbox, 0);
+                       if (tp->tg3_flags3 & TG3_FLG3_ENABLE_TSS)
+                               tw32_mailbox(tp->napi[i].prodmbox, 0);
                        tw32_rx_mbox(tp->napi[i].consmbox, 0);
                        tw32_mailbox_f(tp->napi[i].int_mbox, 1);
                }
+               if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_TSS))
+                       tw32_mailbox(tp->napi[0].prodmbox, 0);
        } else {
                tp->napi[0].tx_prod = 0;
                tp->napi[0].tx_cons = 0;
@@ -7574,6 +7591,20 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
                tw32(TG3_PCIE_LNKCTL, val | TG3_PCIE_LNKCTL_L1_PLL_PD_DIS);
        }
 
+       if (tp->tg3_flags3 & TG3_FLG3_L1PLLPD_EN) {
+               u32 grc_mode = tr32(GRC_MODE);
+
+               /* Access the lower 1K of PL PCIE block registers. */
+               val = grc_mode & ~GRC_MODE_PCIE_PORT_MASK;
+               tw32(GRC_MODE, val | GRC_MODE_PCIE_PL_SEL);
+
+               val = tr32(TG3_PCIE_TLDLPL_PORT + TG3_PCIE_PL_LO_PHYCTL1);
+               tw32(TG3_PCIE_TLDLPL_PORT + TG3_PCIE_PL_LO_PHYCTL1,
+                    val | TG3_PCIE_PL_LO_PHYCTL1_L1PLLPD_EN);
+
+               tw32(GRC_MODE, grc_mode);
+       }
+
        /* This works around an issue with Athlon chipsets on
         * B3 tigon3 silicon.  This bit has no effect on any
         * other revision.  But do not set this on PCI Express
@@ -7772,7 +7803,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
                        tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_MAXLEN_FLAGS,
                             (RX_JUMBO_MAX_SIZE << BDINFO_FLAGS_MAXLEN_SHIFT) |
                             BDINFO_FLAGS_USE_EXT_RECV);
-                       if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS))
+                       if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717)
                                tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_NIC_ADDR,
                                     NIC_SRAM_RX_JUMBO_BUFFER_DESC);
                } else {
@@ -8143,7 +8174,11 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
        /* Prevent chip from dropping frames when flow control
         * is enabled.
         */
-       tw32_f(MAC_LOW_WMARK_MAX_RX_FRAME, 2);
+       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765)
+               val = 1;
+       else
+               val = 2;
+       tw32_f(MAC_LOW_WMARK_MAX_RX_FRAME, val);
 
        if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 &&
            (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)) {
@@ -10640,12 +10675,27 @@ static int tg3_test_memory(struct tg3 *tp)
                { 0x00008000, 0x01000},
                { 0x00010000, 0x01000},
                { 0xffffffff, 0x00000}
+       }, mem_tbl_5717[] = {
+               { 0x00000200, 0x00008},
+               { 0x00010000, 0x0a000},
+               { 0x00020000, 0x13c00},
+               { 0xffffffff, 0x00000}
+       }, mem_tbl_57765[] = {
+               { 0x00000200, 0x00008},
+               { 0x00004000, 0x00800},
+               { 0x00006000, 0x09800},
+               { 0x00010000, 0x0a000},
+               { 0xffffffff, 0x00000}
        };
        struct mem_entry *mem_tbl;
        int err = 0;
        int i;
 
-       if (tp->tg3_flags3 & TG3_FLG3_5755_PLUS)
+       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717)
+               mem_tbl = mem_tbl_5717;
+       else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765)
+               mem_tbl = mem_tbl_57765;
+       else if (tp->tg3_flags3 & TG3_FLG3_5755_PLUS)
                mem_tbl = mem_tbl_5755;
        else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
                mem_tbl = mem_tbl_5906;
@@ -13102,6 +13152,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
                            tp->pci_chip_rev_id == CHIPREV_ID_57780_A0 ||
                            tp->pci_chip_rev_id == CHIPREV_ID_57780_A1)
                                tp->tg3_flags3 |= TG3_FLG3_CLKREQ_BUG;
+               } else if (tp->pci_chip_rev_id == CHIPREV_ID_5717_A0) {
+                       tp->tg3_flags3 |= TG3_FLG3_L1PLLPD_EN;
                }
        } else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) {
                tp->tg3_flags2 |= TG3_FLG2_PCI_EXPRESS;
@@ -13290,7 +13342,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
                tp->grc_local_ctrl |= GRC_LCLCTRL_GPIO_OE3;
 
        if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
-           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780)
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 ||
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765)
                tp->grc_local_ctrl |= GRC_LCLCTRL_GPIO_UART_SEL;
 
        if (tp->pdev->device == PCI_DEVICE_ID_TIGON3_5761 ||
@@ -14086,9 +14139,22 @@ static void __devinit tg3_init_link_config(struct tg3 *tp)
 
 static void __devinit tg3_init_bufmgr_config(struct tg3 *tp)
 {
-       if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS &&
-           GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717 &&
-           GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_57765) {
+       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) {
+               tp->bufmgr_config.mbuf_read_dma_low_water =
+                       DEFAULT_MB_RDMA_LOW_WATER_5705;
+               tp->bufmgr_config.mbuf_mac_rx_low_water =
+                       DEFAULT_MB_MACRX_LOW_WATER_57765;
+               tp->bufmgr_config.mbuf_high_water =
+                       DEFAULT_MB_HIGH_WATER_57765;
+
+               tp->bufmgr_config.mbuf_read_dma_low_water_jumbo =
+                       DEFAULT_MB_RDMA_LOW_WATER_5705;
+               tp->bufmgr_config.mbuf_mac_rx_low_water_jumbo =
+                       DEFAULT_MB_MACRX_LOW_WATER_JUMBO_57765;
+               tp->bufmgr_config.mbuf_high_water_jumbo =
+                       DEFAULT_MB_HIGH_WATER_JUMBO_57765;
+       } else if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) {
                tp->bufmgr_config.mbuf_read_dma_low_water =
                        DEFAULT_MB_RDMA_LOW_WATER_5705;
                tp->bufmgr_config.mbuf_mac_rx_low_water =
@@ -14148,7 +14214,9 @@ static char * __devinit tg3_phy_string(struct tg3 *tp)
        case PHY_ID_BCM5756:    return "5722/5756";
        case PHY_ID_BCM5906:    return "5906";
        case PHY_ID_BCM5761:    return "5761";
-       case PHY_ID_BCM5717:    return "5717";
+       case PHY_ID_BCM5718C:   return "5718C";
+       case PHY_ID_BCM5718S:   return "5718S";
+       case PHY_ID_BCM57765:   return "57765";
        case PHY_ID_BCM8002:    return "8002/serdes";
        case 0:                 return "serdes";
        default:                return "unknown";
index 8a167912902b6e13449a18343b21ebf9939a91d8..e7f6214a168058f9a212fd955a94e5cdbc4bef88 100644 (file)
 #define  DEFAULT_MB_MACRX_LOW_WATER      0x00000020
 #define  DEFAULT_MB_MACRX_LOW_WATER_5705  0x00000010
 #define  DEFAULT_MB_MACRX_LOW_WATER_5906  0x00000004
+#define  DEFAULT_MB_MACRX_LOW_WATER_57765 0x0000002a
 #define  DEFAULT_MB_MACRX_LOW_WATER_JUMBO 0x00000098
 #define  DEFAULT_MB_MACRX_LOW_WATER_JUMBO_5780 0x0000004b
+#define  DEFAULT_MB_MACRX_LOW_WATER_JUMBO_57765 0x0000007e
 #define BUFMGR_MB_HIGH_WATER           0x00004418
 #define  DEFAULT_MB_HIGH_WATER          0x00000060
 #define  DEFAULT_MB_HIGH_WATER_5705     0x00000060
 #define  DEFAULT_MB_HIGH_WATER_5906     0x00000010
+#define  DEFAULT_MB_HIGH_WATER_57765    0x000000a0
 #define  DEFAULT_MB_HIGH_WATER_JUMBO    0x0000017c
 #define  DEFAULT_MB_HIGH_WATER_JUMBO_5780 0x00000096
+#define  DEFAULT_MB_HIGH_WATER_JUMBO_57765 0x000000ea
 #define BUFMGR_RX_MB_ALLOC_REQ         0x0000441c
 #define  BUFMGR_MB_ALLOC_BIT            0x10000000
 #define BUFMGR_RX_MB_ALLOC_RESP                0x00004420
 #define  GRC_MODE_HOST_SENDBDS         0x00020000
 #define  GRC_MODE_NO_TX_PHDR_CSUM      0x00100000
 #define  GRC_MODE_NVRAM_WR_ENABLE      0x00200000
+#define  GRC_MODE_PCIE_TL_SEL          0x00000000
+#define  GRC_MODE_PCIE_PL_SEL          0x00400000
 #define  GRC_MODE_NO_RX_PHDR_CSUM      0x00800000
 #define  GRC_MODE_IRQ_ON_TX_CPU_ATTN   0x01000000
 #define  GRC_MODE_IRQ_ON_RX_CPU_ATTN   0x02000000
 #define  GRC_MODE_IRQ_ON_DMA_ATTN      0x08000000
 #define  GRC_MODE_IRQ_ON_FLOW_ATTN     0x10000000
 #define  GRC_MODE_4X_NIC_SEND_RINGS    0x20000000
+#define  GRC_MODE_PCIE_DL_SEL          0x20000000
 #define  GRC_MODE_MCAST_FRM_ENABLE     0x40000000
+#define  GRC_MODE_PCIE_HI_1K_EN                0x80000000
+#define  GRC_MODE_PCIE_PORT_MASK       (GRC_MODE_PCIE_TL_SEL | \
+                                        GRC_MODE_PCIE_PL_SEL | \
+                                        GRC_MODE_PCIE_DL_SEL | \
+                                        GRC_MODE_PCIE_HI_1K_EN)
 #define GRC_MISC_CFG                   0x00006804
 #define  GRC_MISC_CFG_CORECLK_RESET    0x00000001
 #define  GRC_MISC_CFG_PRESCALAR_MASK   0x000000fe
 /* 0x7e74 --> 0x8000 unused */
 
 
+/* Alternate PCIE definitions */
+#define TG3_PCIE_TLDLPL_PORT           0x00007c00
+#define TG3_PCIE_PL_LO_PHYCTL1          0x00000004
+#define TG3_PCIE_PL_LO_PHYCTL1_L1PLLPD_EN        0x00001000
+
 /* OTP bit definitions */
 #define TG3_OTP_AGCTGT_MASK            0x000000e0
 #define TG3_OTP_AGCTGT_SHIFT           1
@@ -2812,6 +2829,7 @@ struct tg3 {
 #define TG3_FLG3_40BIT_DMA_LIMIT_BUG   0x00100000
 #define TG3_FLG3_SHORT_DMA_BUG         0x00200000
 #define TG3_FLG3_USE_JUMBO_BDFLAG      0x00400000
+#define TG3_FLG3_L1PLLPD_EN            0x00800000
 
        struct timer_list               timer;
        u16                             timer_counter;
@@ -2878,7 +2896,9 @@ struct tg3 {
 #define PHY_ID_BCM5756                 0xbc050ed0
 #define PHY_ID_BCM5784                 0xbc050fa0
 #define PHY_ID_BCM5761                 0xbc050fd0
-#define PHY_ID_BCM5717                 0x5c0d8a00
+#define PHY_ID_BCM5718C                        0x5c0d8a00
+#define PHY_ID_BCM5718S                        0xbc050ff0
+#define PHY_ID_BCM57765                        0x5c0d8a40
 #define PHY_ID_BCM5906                 0xdc00ac40
 #define PHY_ID_BCM8002                 0x60010140
 #define PHY_ID_INVALID                 0xffffffff
@@ -2921,7 +2941,8 @@ struct tg3 {
         (X) == PHY_ID_BCM5780 || (X) == PHY_ID_BCM5787 || \
         (X) == PHY_ID_BCM5755 || (X) == PHY_ID_BCM5756 || \
         (X) == PHY_ID_BCM5906 || (X) == PHY_ID_BCM5761 || \
-        (X) == PHY_ID_BCM5717 || (X) == PHY_ID_BCM8002)
+        (X) == PHY_ID_BCM5718C || (X) == PHY_ID_BCM5718S || \
+        (X) == PHY_ID_BCM57765 || (X) == PHY_ID_BCM8002)
 
        struct tg3_hw_stats             *hw_stats;
        dma_addr_t                      stats_mapping;
index fabaeffb31550799cfa40002c8c90c072e951377..3ec31dce99f9ab46477c077b53f903c027d4764a 100644 (file)
@@ -254,7 +254,7 @@ static struct board {
        { "Compaq NetFlex-3/E", TLAN_ADAPTER_ACTIVITY_LED, 0x83 }, /* EISA card */
 };
 
-static struct pci_device_id tlan_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(tlan_pci_tbl) = {
        { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_NETEL10,
                PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
        { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_NETEL100,
@@ -338,7 +338,7 @@ static int  TLan_PhyInternalService( struct net_device * );
 static int     TLan_PhyDp83840aCheck( struct net_device * );
 */
 
-static int     TLan_MiiReadReg( struct net_device *, u16, u16, u16 * );
+static bool    TLan_MiiReadReg( struct net_device *, u16, u16, u16 * );
 static void    TLan_MiiSendData( u16, u32, unsigned );
 static void    TLan_MiiSync( u16 );
 static void    TLan_MiiWriteReg( struct net_device *, u16, u16, u16 );
@@ -2204,7 +2204,7 @@ TLan_ResetAdapter( struct net_device *dev )
        u32             data;
        u8              data8;
 
-       priv->tlanFullDuplex = FALSE;
+       priv->tlanFullDuplex = false;
        priv->phyOnline=0;
        netif_carrier_off(dev);
 
@@ -2259,7 +2259,7 @@ TLan_ResetAdapter( struct net_device *dev )
                        TLan_DioWrite8( dev->base_addr, TLAN_ACOMMIT, 0x0a );
                } else if ( priv->duplex == TLAN_DUPLEX_FULL ) {
                        TLan_DioWrite8( dev->base_addr, TLAN_ACOMMIT, 0x00 );
-                       priv->tlanFullDuplex = TRUE;
+                       priv->tlanFullDuplex = true;
                } else {
                        TLan_DioWrite8( dev->base_addr, TLAN_ACOMMIT, 0x08 );
                }
@@ -2651,14 +2651,14 @@ static void TLan_PhyStartLink( struct net_device *dev )
                        TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x0000);
                } else if ( priv->speed == TLAN_SPEED_10 &&
                            priv->duplex == TLAN_DUPLEX_FULL) {
-                       priv->tlanFullDuplex = TRUE;
+                       priv->tlanFullDuplex = true;
                        TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x0100);
                } else if ( priv->speed == TLAN_SPEED_100 &&
                            priv->duplex == TLAN_DUPLEX_HALF) {
                        TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x2000);
                } else if ( priv->speed == TLAN_SPEED_100 &&
                            priv->duplex == TLAN_DUPLEX_FULL) {
-                       priv->tlanFullDuplex = TRUE;
+                       priv->tlanFullDuplex = true;
                        TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x2100);
                } else {
 
@@ -2695,7 +2695,7 @@ static void TLan_PhyStartLink( struct net_device *dev )
                        tctl &= ~TLAN_TC_AUISEL;
                        if ( priv->duplex == TLAN_DUPLEX_FULL ) {
                                control |= MII_GC_DUPLEX;
-                               priv->tlanFullDuplex = TRUE;
+                               priv->tlanFullDuplex = true;
                        }
                        if ( priv->speed == TLAN_SPEED_100 ) {
                                control |= MII_GC_SPEEDSEL;
@@ -2750,9 +2750,9 @@ static void TLan_PhyFinishAutoNeg( struct net_device *dev )
        TLan_MiiReadReg( dev, phy, MII_AN_LPA, &an_lpa );
        mode = an_adv & an_lpa & 0x03E0;
        if ( mode & 0x0100 ) {
-               priv->tlanFullDuplex = TRUE;
+               priv->tlanFullDuplex = true;
        } else if ( ! ( mode & 0x0080 ) && ( mode & 0x0040 ) ) {
-               priv->tlanFullDuplex = TRUE;
+               priv->tlanFullDuplex = true;
        }
 
        if ( ( ! ( mode & 0x0180 ) ) &&
@@ -2855,8 +2855,8 @@ void TLan_PhyMonitor( struct net_device *dev )
         *      TLan_MiiReadReg
         *
         *      Returns:
-        *              0       if ack received ok
-        *              1       otherwise.
+        *              false   if ack received ok
+        *              true    if no ack received or other error
         *
         *      Parms:
         *              dev             The device structure containing
@@ -2875,17 +2875,17 @@ void TLan_PhyMonitor( struct net_device *dev )
         *
         **************************************************************/
 
-static int TLan_MiiReadReg( struct net_device *dev, u16 phy, u16 reg, u16 *val )
+static bool TLan_MiiReadReg( struct net_device *dev, u16 phy, u16 reg, u16 *val )
 {
        u8      nack;
        u16     sio, tmp;
        u32     i;
-       int     err;
+       bool    err;
        int     minten;
        TLanPrivateInfo *priv = netdev_priv(dev);
        unsigned long flags = 0;
 
-       err = FALSE;
+       err = false;
        outw(TLAN_NET_SIO, dev->base_addr + TLAN_DIO_ADR);
        sio = dev->base_addr + TLAN_DIO_DATA + TLAN_NET_SIO;
 
@@ -2918,7 +2918,7 @@ static int TLan_MiiReadReg( struct net_device *dev, u16 phy, u16 reg, u16 *val )
                        TLan_SetBit(TLAN_NET_SIO_MCLK, sio);
                }
                tmp = 0xffff;
-               err = TRUE;
+               err = true;
        } else {                                        /* ACK, so read data */
                for (tmp = 0, i = 0x8000; i; i >>= 1) {
                        TLan_ClearBit(TLAN_NET_SIO_MCLK, sio);
index 4b82f283e98552cfb975bc30a3b461d091e6cd54..d13ff12d7500b95cff207a67ecf9f4c5118ab83b 100644 (file)
@@ -31,9 +31,6 @@
         *
         ****************************************************************/
 
-#define FALSE                  0
-#define TRUE                   1
-
 #define TLAN_MIN_FRAME_SIZE    64
 #define TLAN_MAX_FRAME_SIZE    1600
 
index cf552d1d9629be1cf0751dbf834b261663c276af..b0d7db9d8bb41578f957db9572354ec04ef70adc 100644 (file)
@@ -117,7 +117,7 @@ MODULE_PARM_DESC(message_level, "3c359: Level of reported messages") ;
  *     will be stuck with 1555 lines of hex #'s in the code.
  */
 
-static struct pci_device_id xl_pci_tbl[] =
+static DEFINE_PCI_DEVICE_TABLE(xl_pci_tbl) =
 {
        {PCI_VENDOR_ID_3COM,PCI_DEVICE_ID_3COM_3C359, PCI_ANY_ID, PCI_ANY_ID, },
        { }                     /* terminate list */
index b9db1b5a58a3db04af268a0c5148ac147aa40c89..515f122777abcb361891196de2fb5a95d9343a8e 100644 (file)
@@ -45,7 +45,7 @@ static char version[] __devinitdata =
 
 #define ABYSS_IO_EXTENT 64
 
-static struct pci_device_id abyss_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(abyss_pci_tbl) = {
        { PCI_VENDOR_ID_MADGE, PCI_DEVICE_ID_MADGE_MK2,
          PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_TOKEN_RING << 8, 0x00ffffff, },
        { }                     /* Terminating entry */
index d6ccd59c7d074825c33dfab9e1296665cf6de205..3f9d5a25562e4fce32c325578cac1cdccd27592b 100644 (file)
 static char version[] = "LanStreamer.c v0.4.0 03/08/01 - Mike Sullivan\n"
                         "              v0.5.3 11/13/02 - Kent Yoder";
 
-static struct pci_device_id streamer_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(streamer_pci_tbl) = {
        { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_TR, PCI_ANY_ID, PCI_ANY_ID,},
        {}      /* terminating entry */
 };
index df32025c513220ec15e11459cd53714c790e08f8..f010a4dc5f19eff858a7316310158fe457b8a320 100644 (file)
@@ -172,7 +172,7 @@ module_param_array(message_level, int, NULL, 0) ;
 static int network_monitor[OLYMPIC_MAX_ADAPTERS] = {0,};
 module_param_array(network_monitor, int, NULL, 0);
 
-static struct pci_device_id olympic_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(olympic_pci_tbl) = {
        {PCI_VENDOR_ID_IBM,PCI_DEVICE_ID_IBM_TR_WAKE,PCI_ANY_ID,PCI_ANY_ID,},
        { }     /* Terminating Entry */
 };
index f92fe86fdcae2266c08eb773049c86883aeed81e..d4c7c0c0a3d64f405be97a242500a1a77d4df6fa 100644 (file)
@@ -57,7 +57,7 @@ static struct card_info card_info_table[] = {
        { {0x03, 0x01}, "3Com Token Link Velocity"},
 };
 
-static struct pci_device_id tmspci_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(tmspci_pci_tbl) = {
        { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_TOKENRING, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
        { PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_TR, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 },
        { PCI_VENDOR_ID_TCONRAD, PCI_DEVICE_ID_TCONRAD_TOKENRING, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2 },
index 9f6742fad6ca8da29bc14ed5d379f2841d540190..007d8e75666dbc6a836e2c7bc305a8d0379e5c05 100644 (file)
@@ -43,8 +43,8 @@ void t21142_media_task(struct work_struct *work)
        if ((csr14 & 0x80) && (csr12 & 0x7000) != 0x5000)
                csr12 |= 6;
        if (tulip_debug > 2)
-               printk(KERN_INFO"%s: 21143 negotiation status %8.8x, %s.\n",
-                          dev->name, csr12, medianame[dev->if_port]);
+               dev_info(&dev->dev, "21143 negotiation status %08x, %s\n",
+                        csr12, medianame[dev->if_port]);
        if (tulip_media_cap[dev->if_port] & MediaIsMII) {
                if (tulip_check_duplex(dev) < 0) {
                        netif_carrier_off(dev);
@@ -56,23 +56,26 @@ void t21142_media_task(struct work_struct *work)
        } else if (tp->nwayset) {
                /* Don't screw up a negotiated session! */
                if (tulip_debug > 1)
-                       printk(KERN_INFO"%s: Using NWay-set %s media, csr12 %8.8x.\n",
-                                  dev->name, medianame[dev->if_port], csr12);
+                       dev_info(&dev->dev,
+                                "Using NWay-set %s media, csr12 %08x\n",
+                                medianame[dev->if_port], csr12);
        } else if (tp->medialock) {
                        ;
        } else if (dev->if_port == 3) {
                if (csr12 & 2) {        /* No 100mbps link beat, revert to 10mbps. */
                        if (tulip_debug > 1)
-                               printk(KERN_INFO"%s: No 21143 100baseTx link beat, %8.8x, "
-                                          "trying NWay.\n", dev->name, csr12);
+                               dev_info(&dev->dev,
+                                        "No 21143 100baseTx link beat, %08x, trying NWay\n",
+                                        csr12);
                        t21142_start_nway(dev);
                        next_tick = 3*HZ;
                }
        } else if ((csr12 & 0x7000) != 0x5000) {
                /* Negotiation failed.  Search media types. */
                if (tulip_debug > 1)
-                       printk(KERN_INFO"%s: 21143 negotiation failed, status %8.8x.\n",
-                                  dev->name, csr12);
+                       dev_info(&dev->dev,
+                                "21143 negotiation failed, status %08x\n",
+                                csr12);
                if (!(csr12 & 4)) {             /* 10mbps link beat good. */
                        new_csr6 = 0x82420000;
                        dev->if_port = 0;
@@ -90,8 +93,8 @@ void t21142_media_task(struct work_struct *work)
                        iowrite32(1, ioaddr + CSR13);
                }
                if (tulip_debug > 1)
-                       printk(KERN_INFO"%s: Testing new 21143 media %s.\n",
-                                  dev->name, medianame[dev->if_port]);
+                       dev_info(&dev->dev, "Testing new 21143 media %s\n",
+                                medianame[dev->if_port]);
                if (new_csr6 != (tp->csr6 & ~0x00D5)) {
                        tp->csr6 &= 0x00D5;
                        tp->csr6 |= new_csr6;
@@ -119,8 +122,8 @@ void t21142_start_nway(struct net_device *dev)
        tp->nway = tp->mediasense = 1;
        tp->nwayset = tp->lpar = 0;
        if (tulip_debug > 1)
-               printk(KERN_DEBUG "%s: Restarting 21143 autonegotiation, csr14=%8.8x.\n",
-                          dev->name, csr14);
+               printk(KERN_DEBUG "%s: Restarting 21143 autonegotiation, csr14=%08x\n",
+                      dev->name, csr14);
        iowrite32(0x0001, ioaddr + CSR13);
        udelay(100);
        iowrite32(csr14, ioaddr + CSR14);
@@ -147,8 +150,9 @@ void t21142_lnk_change(struct net_device *dev, int csr5)
        if ((csr14 & 0x80) && (csr12 & 0x7000) != 0x5000)
                csr12 |= 6;
        if (tulip_debug > 1)
-               printk(KERN_INFO"%s: 21143 link status interrupt %8.8x, CSR5 %x, "
-                          "%8.8x.\n", dev->name, csr12, csr5, csr14);
+               dev_info(&dev->dev,
+                        "21143 link status interrupt %08x, CSR5 %x, %08x\n",
+                        csr12, csr5, csr14);
 
        /* If NWay finished and we have a negotiated partner capability. */
        if (tp->nway  &&  !tp->nwayset  &&  (csr12 & 0x7000) == 0x5000) {
@@ -171,14 +175,15 @@ void t21142_lnk_change(struct net_device *dev, int csr5)
 
                if (tulip_debug > 1) {
                        if (tp->nwayset)
-                               printk(KERN_INFO "%s: Switching to %s based on link "
-                                          "negotiation %4.4x & %4.4x = %4.4x.\n",
-                                          dev->name, medianame[dev->if_port], tp->sym_advertise,
-                                          tp->lpar, negotiated);
+                               dev_info(&dev->dev,
+                                        "Switching to %s based on link negotiation %04x & %04x = %04x\n",
+                                        medianame[dev->if_port],
+                                        tp->sym_advertise, tp->lpar,
+                                        negotiated);
                        else
-                               printk(KERN_INFO "%s: Autonegotiation failed, using %s,"
-                                          " link beat status %4.4x.\n",
-                                          dev->name, medianame[dev->if_port], csr12);
+                               dev_info(&dev->dev,
+                                        "Autonegotiation failed, using %s, link beat status %04x\n",
+                                        medianame[dev->if_port], csr12);
                }
 
                if (tp->mtable) {
@@ -201,14 +206,14 @@ void t21142_lnk_change(struct net_device *dev, int csr5)
 #if 0                                                  /* Restart shouldn't be needed. */
                iowrite32(tp->csr6 | RxOn, ioaddr + CSR6);
                if (tulip_debug > 2)
-                       printk(KERN_DEBUG "%s:  Restarting Tx and Rx, CSR5 is %8.8x.\n",
-                                  dev->name, ioread32(ioaddr + CSR5));
+                       printk(KERN_DEBUG "%s:  Restarting Tx and Rx, CSR5 is %08x\n",
+                              dev->name, ioread32(ioaddr + CSR5));
 #endif
                tulip_start_rxtx(tp);
                if (tulip_debug > 2)
-                       printk(KERN_DEBUG "%s:  Setting CSR6 %8.8x/%x CSR12 %8.8x.\n",
-                                  dev->name, tp->csr6, ioread32(ioaddr + CSR6),
-                                  ioread32(ioaddr + CSR12));
+                       printk(KERN_DEBUG "%s:  Setting CSR6 %08x/%x CSR12 %08x\n",
+                              dev->name, tp->csr6, ioread32(ioaddr + CSR6),
+                              ioread32(ioaddr + CSR12));
        } else if ((tp->nwayset  &&  (csr5 & 0x08000000) &&
                    (dev->if_port == 3  ||  dev->if_port == 5) &&
                    (csr12 & 2) == 2) ||
@@ -220,9 +225,9 @@ void t21142_lnk_change(struct net_device *dev, int csr5)
                add_timer(&tp->timer);
        } else if (dev->if_port == 3  ||  dev->if_port == 5) {
                if (tulip_debug > 1)
-                       printk(KERN_INFO"%s: 21143 %s link beat %s.\n",
-                                  dev->name, medianame[dev->if_port],
-                                  (csr12 & 2) ? "failed" : "good");
+                       dev_info(&dev->dev, "21143 %s link beat %s\n",
+                                medianame[dev->if_port],
+                                (csr12 & 2) ? "failed" : "good");
                if ((csr12 & 2)  &&  ! tp->medialock) {
                        del_timer_sync(&tp->timer);
                        t21142_start_nway(dev);
@@ -232,21 +237,18 @@ void t21142_lnk_change(struct net_device *dev, int csr5)
                        iowrite32(csr14 & ~0x080, ioaddr + CSR14);
        } else if (dev->if_port == 0  ||  dev->if_port == 4) {
                if ((csr12 & 4) == 0)
-                       printk(KERN_INFO"%s: 21143 10baseT link beat good.\n",
-                                  dev->name);
+                       dev_info(&dev->dev, "21143 10baseT link beat good\n");
        } else if (!(csr12 & 4)) {              /* 10mbps link beat good. */
                if (tulip_debug)
-                       printk(KERN_INFO"%s: 21143 10mbps sensed media.\n",
-                                  dev->name);
+                       dev_info(&dev->dev, "21143 10mbps sensed media\n");
                dev->if_port = 0;
        } else if (tp->nwayset) {
                if (tulip_debug)
-                       printk(KERN_INFO"%s: 21143 using NWay-set %s, csr6 %8.8x.\n",
-                                  dev->name, medianame[dev->if_port], tp->csr6);
+                       dev_info(&dev->dev, "21143 using NWay-set %s, csr6 %08x\n",
+                                medianame[dev->if_port], tp->csr6);
        } else {                /* 100mbps link beat good. */
                if (tulip_debug)
-                       printk(KERN_INFO"%s: 21143 100baseTx sensed media.\n",
-                                  dev->name);
+                       dev_info(&dev->dev, "21143 100baseTx sensed media\n");
                dev->if_port = 3;
                tp->csr6 = 0x838E0000 | (tp->csr6 & 0x20ff);
                iowrite32(0x0003FF7F, ioaddr + CSR14);
index d4255d44cb75c9e2cbc154e559001f0d6c29e168..29330209ad8b2d145964066afe0f262ac904e712 100644 (file)
@@ -337,7 +337,7 @@ static void de21041_media_timer (unsigned long data);
 static unsigned int de_ok_to_advertise (struct de_private *de, u32 new_media);
 
 
-static struct pci_device_id de_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(de_pci_tbl) = {
        { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP,
          PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
        { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_PLUS,
@@ -382,9 +382,9 @@ static void de_rx_err_acct (struct de_private *de, unsigned rx_tail,
                /* Ingore earlier buffers. */
                if ((status & 0xffff) != 0x7fff) {
                        if (netif_msg_rx_err(de))
-                               printk(KERN_WARNING "%s: Oversized Ethernet frame "
-                                          "spanned multiple buffers, status %8.8x!\n",
-                                          de->dev->name, status);
+                               dev_warn(&de->dev->dev,
+                                        "Oversized Ethernet frame spanned multiple buffers, status %08x!\n",
+                                        status);
                        de->net_stats.rx_length_errors++;
                }
        } else if (status & RxError) {
@@ -487,7 +487,7 @@ rx_next:
        }
 
        if (!rx_work)
-               printk(KERN_WARNING "%s: rx work limit reached\n", de->dev->name);
+               dev_warn(&de->dev->dev, "rx work limit reached\n");
 
        de->rx_tail = rx_tail;
 }
@@ -504,7 +504,8 @@ static irqreturn_t de_interrupt (int irq, void *dev_instance)
 
        if (netif_msg_intr(de))
                printk(KERN_DEBUG "%s: intr, status %08x mode %08x desc %u/%u/%u\n",
-                       dev->name, status, dr32(MacMode), de->rx_tail, de->tx_head, de->tx_tail);
+                      dev->name, status, dr32(MacMode),
+                      de->rx_tail, de->tx_head, de->tx_tail);
 
        dw32(MacStatus, status);
 
@@ -529,8 +530,9 @@ static irqreturn_t de_interrupt (int irq, void *dev_instance)
 
                pci_read_config_word(de->pdev, PCI_STATUS, &pci_status);
                pci_write_config_word(de->pdev, PCI_STATUS, pci_status);
-               printk(KERN_ERR "%s: PCI bus error, status=%08x, PCI status=%04x\n",
-                      dev->name, status, pci_status);
+               dev_err(&de->dev->dev,
+                       "PCI bus error, status=%08x, PCI status=%04x\n",
+                       status, pci_status);
        }
 
        return IRQ_HANDLED;
@@ -582,7 +584,8 @@ static void de_tx (struct de_private *de)
                                de->net_stats.tx_packets++;
                                de->net_stats.tx_bytes += skb->len;
                                if (netif_msg_tx_done(de))
-                                       printk(KERN_DEBUG "%s: tx done, slot %d\n", de->dev->name, tx_tail);
+                                       printk(KERN_DEBUG "%s: tx done, slot %d\n",
+                                              de->dev->name, tx_tail);
                        }
                        dev_kfree_skb_irq(skb);
                }
@@ -870,7 +873,7 @@ static void de_stop_rxtx (struct de_private *de)
                udelay(100);
        }
 
-       printk(KERN_WARNING "%s: timeout expired stopping DMA\n", de->dev->name);
+       dev_warn(&de->dev->dev, "timeout expired stopping DMA\n");
 }
 
 static inline void de_start_rxtx (struct de_private *de)
@@ -905,8 +908,8 @@ static void de_link_up(struct de_private *de)
        if (!netif_carrier_ok(de->dev)) {
                netif_carrier_on(de->dev);
                if (netif_msg_link(de))
-                       printk(KERN_INFO "%s: link up, media %s\n",
-                              de->dev->name, media_name[de->media_type]);
+                       dev_info(&de->dev->dev, "link up, media %s\n",
+                                media_name[de->media_type]);
        }
 }
 
@@ -915,7 +918,7 @@ static void de_link_down(struct de_private *de)
        if (netif_carrier_ok(de->dev)) {
                netif_carrier_off(de->dev);
                if (netif_msg_link(de))
-                       printk(KERN_INFO "%s: link down\n", de->dev->name);
+                       dev_info(&de->dev->dev, "link down\n");
        }
 }
 
@@ -925,7 +928,8 @@ static void de_set_media (struct de_private *de)
        u32 macmode = dr32(MacMode);
 
        if (de_is_running(de))
-               printk(KERN_WARNING "%s: chip is running while changing media!\n", de->dev->name);
+               dev_warn(&de->dev->dev,
+                        "chip is running while changing media!\n");
 
        if (de->de21040)
                dw32(CSR11, FULL_DUPLEX_MAGIC);
@@ -945,15 +949,15 @@ static void de_set_media (struct de_private *de)
                macmode &= ~FullDuplex;
 
        if (netif_msg_link(de)) {
-               printk(KERN_INFO
-                      "%s: set link %s\n"
-                      "%s:    mode 0x%x, sia 0x%x,0x%x,0x%x,0x%x\n"
-                      "%s:    set mode 0x%x, set sia 0x%x,0x%x,0x%x\n",
-                      de->dev->name, media_name[media],
-                      de->dev->name, dr32(MacMode), dr32(SIAStatus),
-                      dr32(CSR13), dr32(CSR14), dr32(CSR15),
-                      de->dev->name, macmode, de->media[media].csr13,
-                      de->media[media].csr14, de->media[media].csr15);
+               dev_info(&de->dev->dev, "set link %s\n", media_name[media]);
+               dev_info(&de->dev->dev, "mode 0x%x, sia 0x%x,0x%x,0x%x,0x%x\n",
+                        dr32(MacMode), dr32(SIAStatus),
+                        dr32(CSR13), dr32(CSR14), dr32(CSR15));
+
+               dev_info(&de->dev->dev,
+                        "set mode 0x%x, set sia 0x%x,0x%x,0x%x\n",
+                        macmode, de->media[media].csr13,
+                        de->media[media].csr14, de->media[media].csr15);
        }
        if (macmode != dr32(MacMode))
                dw32(MacMode, macmode);
@@ -992,9 +996,8 @@ static void de21040_media_timer (unsigned long data)
                        de_link_up(de);
                else
                        if (netif_msg_timer(de))
-                               printk(KERN_INFO "%s: %s link ok, status %x\n",
-                                      dev->name, media_name[de->media_type],
-                                      status);
+                               dev_info(&dev->dev, "%s link ok, status %x\n",
+                                        media_name[de->media_type], status);
                return;
        }
 
@@ -1022,8 +1025,8 @@ no_link_yet:
        add_timer(&de->media_timer);
 
        if (netif_msg_timer(de))
-               printk(KERN_INFO "%s: no link, trying media %s, status %x\n",
-                      dev->name, media_name[de->media_type], status);
+               dev_info(&dev->dev, "no link, trying media %s, status %x\n",
+                        media_name[de->media_type], status);
 }
 
 static unsigned int de_ok_to_advertise (struct de_private *de, u32 new_media)
@@ -1079,9 +1082,10 @@ static void de21041_media_timer (unsigned long data)
                        de_link_up(de);
                else
                        if (netif_msg_timer(de))
-                               printk(KERN_INFO "%s: %s link ok, mode %x status %x\n",
-                                      dev->name, media_name[de->media_type],
-                                      dr32(MacMode), status);
+                               dev_info(&dev->dev,
+                                        "%s link ok, mode %x status %x\n",
+                                        media_name[de->media_type],
+                                        dr32(MacMode), status);
                return;
        }
 
@@ -1150,8 +1154,8 @@ no_link_yet:
        add_timer(&de->media_timer);
 
        if (netif_msg_timer(de))
-               printk(KERN_INFO "%s: no link, trying media %s, status %x\n",
-                      dev->name, media_name[de->media_type], status);
+               dev_info(&dev->dev, "no link, trying media %s, status %x\n",
+                        media_name[de->media_type], status);
 }
 
 static void de_media_interrupt (struct de_private *de, u32 status)
@@ -1378,8 +1382,7 @@ static int de_open (struct net_device *dev)
 
        rc = de_alloc_rings(de);
        if (rc) {
-               printk(KERN_ERR "%s: ring allocation failure, err=%d\n",
-                      dev->name, rc);
+               dev_err(&dev->dev, "ring allocation failure, err=%d\n", rc);
                return rc;
        }
 
@@ -1387,15 +1390,14 @@ static int de_open (struct net_device *dev)
 
        rc = request_irq(dev->irq, de_interrupt, IRQF_SHARED, dev->name, dev);
        if (rc) {
-               printk(KERN_ERR "%s: IRQ %d request failure, err=%d\n",
-                      dev->name, dev->irq, rc);
+               dev_err(&dev->dev, "IRQ %d request failure, err=%d\n",
+                       dev->irq, rc);
                goto err_out_free;
        }
 
        rc = de_init_hw(de);
        if (rc) {
-               printk(KERN_ERR "%s: h/w init failure, err=%d\n",
-                      dev->name, rc);
+               dev_err(&dev->dev, "h/w init failure, err=%d\n", rc);
                goto err_out_free_irq;
        }
 
@@ -1666,8 +1668,8 @@ static int de_nway_reset(struct net_device *dev)
        status = dr32(SIAStatus);
        dw32(SIAStatus, (status & ~NWayState) | NWayRestart);
        if (netif_msg_link(de))
-               printk(KERN_INFO "%s: link nway restart, status %x,%x\n",
-                      de->dev->name, status, dr32(SIAStatus));
+               dev_info(&de->dev->dev, "link nway restart, status %x,%x\n",
+                        status, dr32(SIAStatus));
        return 0;
 }
 
@@ -1711,7 +1713,7 @@ static void __devinit de21040_get_mac_address (struct de_private *de)
                de->dev->dev_addr[i] = value;
                udelay(1);
                if (boguscnt <= 0)
-                       printk(KERN_WARNING PFX "timeout reading 21040 MAC address byte %u\n", i);
+                       pr_warning(PFX "timeout reading 21040 MAC address byte %u\n", i);
        }
 }
 
@@ -1830,9 +1832,8 @@ static void __devinit de21041_get_srom_info (struct de_private *de)
        }
 
        if (netif_msg_probe(de))
-               printk(KERN_INFO "de%d: SROM leaf offset %u, default media %s\n",
-                      de->board_idx, ofs,
-                      media_name[de->media_type]);
+               pr_info("de%d: SROM leaf offset %u, default media %s\n",
+                      de->board_idx, ofs, media_name[de->media_type]);
 
        /* init SIA register values to defaults */
        for (i = 0; i < DE_MAX_MEDIA; i++) {
@@ -1879,9 +1880,9 @@ static void __devinit de21041_get_srom_info (struct de_private *de)
                de->media[idx].type = idx;
 
                if (netif_msg_probe(de))
-                       printk(KERN_INFO "de%d:   media block #%u: %s",
-                              de->board_idx, i,
-                              media_name[de->media[idx].type]);
+                       pr_info("de%d:   media block #%u: %s",
+                               de->board_idx, i,
+                               media_name[de->media[idx].type]);
 
                bufp += sizeof (ib->opts);
 
@@ -1893,13 +1894,13 @@ static void __devinit de21041_get_srom_info (struct de_private *de)
                                sizeof(ib->csr15);
 
                        if (netif_msg_probe(de))
-                               printk(" (%x,%x,%x)\n",
-                                      de->media[idx].csr13,
-                                      de->media[idx].csr14,
-                                      de->media[idx].csr15);
+                               pr_cont(" (%x,%x,%x)\n",
+                                       de->media[idx].csr13,
+                                       de->media[idx].csr14,
+                                       de->media[idx].csr15);
 
                } else if (netif_msg_probe(de))
-                       printk("\n");
+                       pr_cont("\n");
 
                if (bufp > ((void *)&ee_data[DE_EEPROM_SIZE - 3]))
                        break;
@@ -2005,7 +2006,7 @@ static int __devinit de_init_one (struct pci_dev *pdev,
        /* check for invalid IRQ value */
        if (pdev->irq < 2) {
                rc = -EIO;
-               printk(KERN_ERR PFX "invalid irq (%d) for pci dev %s\n",
+               pr_err(PFX "invalid irq (%d) for pci dev %s\n",
                       pdev->irq, pci_name(pdev));
                goto err_out_res;
        }
@@ -2016,14 +2017,14 @@ static int __devinit de_init_one (struct pci_dev *pdev,
        pciaddr = pci_resource_start(pdev, 1);
        if (!pciaddr) {
                rc = -EIO;
-               printk(KERN_ERR PFX "no MMIO resource for pci dev %s\n",
-                      pci_name(pdev));
+               pr_err(PFX "no MMIO resource for pci dev %s\n", pci_name(pdev));
                goto err_out_res;
        }
        if (pci_resource_len(pdev, 1) < DE_REGS_SIZE) {
                rc = -EIO;
-               printk(KERN_ERR PFX "MMIO resource (%llx) too small on pci dev %s\n",
-                      (unsigned long long)pci_resource_len(pdev, 1), pci_name(pdev));
+               pr_err(PFX "MMIO resource (%llx) too small on pci dev %s\n",
+                      (unsigned long long)pci_resource_len(pdev, 1),
+                      pci_name(pdev));
                goto err_out_res;
        }
 
@@ -2031,9 +2032,9 @@ static int __devinit de_init_one (struct pci_dev *pdev,
        regs = ioremap_nocache(pciaddr, DE_REGS_SIZE);
        if (!regs) {
                rc = -EIO;
-               printk(KERN_ERR PFX "Cannot map PCI MMIO (%llx@%lx) on pci dev %s\n",
-                       (unsigned long long)pci_resource_len(pdev, 1),
-                       pciaddr, pci_name(pdev));
+               pr_err(PFX "Cannot map PCI MMIO (%llx@%lx) on pci dev %s\n",
+                      (unsigned long long)pci_resource_len(pdev, 1),
+                      pciaddr, pci_name(pdev));
                goto err_out_res;
        }
        dev->base_addr = (unsigned long) regs;
@@ -2044,8 +2045,7 @@ static int __devinit de_init_one (struct pci_dev *pdev,
        /* make sure hardware is not running */
        rc = de_reset_mac(de);
        if (rc) {
-               printk(KERN_ERR PFX "Cannot reset MAC, pci dev %s\n",
-                      pci_name(pdev));
+               pr_err(PFX "Cannot reset MAC, pci dev %s\n", pci_name(pdev));
                goto err_out_iomap;
        }
 
@@ -2065,12 +2065,11 @@ static int __devinit de_init_one (struct pci_dev *pdev,
                goto err_out_iomap;
 
        /* print info about board and interface just registered */
-       printk (KERN_INFO "%s: %s at 0x%lx, %pM, IRQ %d\n",
-               dev->name,
-               de->de21040 ? "21040" : "21041",
-               dev->base_addr,
-               dev->dev_addr,
-               dev->irq);
+       dev_info(&dev->dev, "%s at 0x%lx, %pM, IRQ %d\n",
+                de->de21040 ? "21040" : "21041",
+                dev->base_addr,
+                dev->dev_addr,
+                dev->irq);
 
        pci_set_drvdata(pdev, dev);
 
@@ -2158,8 +2157,7 @@ static int de_resume (struct pci_dev *pdev)
        if (!netif_running(dev))
                goto out_attach;
        if ((retval = pci_enable_device(pdev))) {
-               printk (KERN_ERR "%s: pci_enable_device failed in resume\n",
-                       dev->name);
+               dev_err(&dev->dev, "pci_enable_device failed in resume\n");
                goto out;
        }
        de_init_hw(de);
index 6f44ebf58910261a2aa8ef2ae3c9ae56da2e4808..5fc61c1012e570fb2875d965cb39922eb4755ae5 100644 (file)
@@ -61,6 +61,8 @@
     Test and make sure PCI latency is now correct for all cases.
 */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #define DRV_NAME       "dmfe"
 #define DRV_VERSION    "1.36.4"
 #define DRV_RELDATE    "2002-01-17"
 #define DMFE_TX_TIMEOUT ((3*HZ)/2)     /* tx packet time-out time 1.5 s" */
 #define DMFE_TX_KICK   (HZ/2)  /* tx packet Kick-out time 0.5 s" */
 
-#define DMFE_DBUG(dbug_now, msg, value) \
-       do { \
-               if (dmfe_debug || (dbug_now)) \
-                       printk(KERN_ERR DRV_NAME ": %s %lx\n",\
-                               (msg), (long) (value)); \
+#define DMFE_DBUG(dbug_now, msg, value)                        \
+       do {                                            \
+               if (dmfe_debug || (dbug_now))           \
+                       pr_err("%s %lx\n",              \
+                              (msg), (long) (value));  \
        } while (0)
 
-#define SHOW_MEDIA_TYPE(mode) \
-       printk (KERN_INFO DRV_NAME ": Change Speed to %sMhz %s duplex\n" , \
-               (mode & 1) ? "100":"10", (mode & 4) ? "full":"half");
+#define SHOW_MEDIA_TYPE(mode)                          \
+       pr_info("Change Speed to %sMhz %s duplex\n" ,   \
+               (mode & 1) ? "100":"10",                \
+               (mode & 4) ? "full":"half");
 
 
 /* CR9 definition: SROM/MII */
@@ -391,8 +394,7 @@ static int __devinit dmfe_init_one (struct pci_dev *pdev,
                struct device_node *dp = pci_device_to_OF_node(pdev);
 
                if (dp && of_get_property(dp, "local-mac-address", NULL)) {
-                       printk(KERN_INFO DRV_NAME
-                              ": skipping on-board DM910x (use tulip)\n");
+                       pr_info("skipping on-board DM910x (use tulip)\n");
                        return -ENODEV;
                }
        }
@@ -405,8 +407,7 @@ static int __devinit dmfe_init_one (struct pci_dev *pdev,
        SET_NETDEV_DEV(dev, &pdev->dev);
 
        if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) {
-               printk(KERN_WARNING DRV_NAME
-                       ": 32-bit PCI DMA not available.\n");
+               pr_warning("32-bit PCI DMA not available\n");
                err = -ENODEV;
                goto err_out_free;
        }
@@ -417,13 +418,13 @@ static int __devinit dmfe_init_one (struct pci_dev *pdev,
                goto err_out_free;
 
        if (!pci_resource_start(pdev, 0)) {
-               printk(KERN_ERR DRV_NAME ": I/O base is zero\n");
+               pr_err("I/O base is zero\n");
                err = -ENODEV;
                goto err_out_disable;
        }
 
        if (pci_resource_len(pdev, 0) < (CHK_IO_SIZE(pdev)) ) {
-               printk(KERN_ERR DRV_NAME ": Allocated I/O size too small\n");
+               pr_err("Allocated I/O size too small\n");
                err = -ENODEV;
                goto err_out_disable;
        }
@@ -438,7 +439,7 @@ static int __devinit dmfe_init_one (struct pci_dev *pdev,
 #endif
 
        if (pci_request_regions(pdev, DRV_NAME)) {
-               printk(KERN_ERR DRV_NAME ": Failed to request PCI regions\n");
+               pr_err("Failed to request PCI regions\n");
                err = -ENODEV;
                goto err_out_disable;
        }
@@ -497,12 +498,9 @@ static int __devinit dmfe_init_one (struct pci_dev *pdev,
        if (err)
                goto err_out_free_buf;
 
-       printk(KERN_INFO "%s: Davicom DM%04lx at pci%s, %pM, irq %d.\n",
-              dev->name,
-              ent->driver_data >> 16,
-              pci_name(pdev),
-              dev->dev_addr,
-              dev->irq);
+       dev_info(&dev->dev, "Davicom DM%04lx at pci%s, %pM, irq %d\n",
+                ent->driver_data >> 16,
+                pci_name(pdev), dev->dev_addr, dev->irq);
 
        pci_set_master(pdev);
 
@@ -696,7 +694,7 @@ static netdev_tx_t dmfe_start_xmit(struct sk_buff *skb,
 
        /* Too large packet check */
        if (skb->len > MAX_PACKET_SIZE) {
-               printk(KERN_ERR DRV_NAME ": big packet = %d\n", (u16)skb->len);
+               pr_err("big packet = %d\n", (u16)skb->len);
                dev_kfree_skb(skb);
                return NETDEV_TX_OK;
        }
@@ -706,8 +704,7 @@ static netdev_tx_t dmfe_start_xmit(struct sk_buff *skb,
        /* No Tx resource check, it never happen nromally */
        if (db->tx_queue_cnt >= TX_FREE_DESC_CNT) {
                spin_unlock_irqrestore(&db->lock, flags);
-               printk(KERN_ERR DRV_NAME ": No Tx resource %ld\n",
-                      db->tx_queue_cnt);
+               pr_err("No Tx resource %ld\n", db->tx_queue_cnt);
                return NETDEV_TX_BUSY;
        }
 
@@ -779,12 +776,11 @@ static int dmfe_stop(struct DEVICE *dev)
 
 #if 0
        /* show statistic counter */
-       printk(DRV_NAME ": FU:%lx EC:%lx LC:%lx NC:%lx"
-               " LOC:%lx TXJT:%lx RESET:%lx RCR8:%lx FAL:%lx TT:%lx\n",
-               db->tx_fifo_underrun, db->tx_excessive_collision,
-               db->tx_late_collision, db->tx_no_carrier, db->tx_loss_carrier,
-               db->tx_jabber_timeout, db->reset_count, db->reset_cr8,
-               db->reset_fatal, db->reset_TXtimeout);
+       printk("FU:%lx EC:%lx LC:%lx NC:%lx LOC:%lx TXJT:%lx RESET:%lx RCR8:%lx FAL:%lx TT:%lx\n",
+              db->tx_fifo_underrun, db->tx_excessive_collision,
+              db->tx_late_collision, db->tx_no_carrier, db->tx_loss_carrier,
+              db->tx_jabber_timeout, db->reset_count, db->reset_cr8,
+              db->reset_fatal, db->reset_TXtimeout);
 #endif
 
        return 0;
@@ -885,7 +881,7 @@ static void dmfe_free_tx_pkt(struct DEVICE *dev, struct dmfe_board_info * db)
        txptr = db->tx_remove_ptr;
        while(db->tx_packet_cnt) {
                tdes0 = le32_to_cpu(txptr->tdes0);
-               /* printk(DRV_NAME ": tdes0=%x\n", tdes0); */
+               pr_debug("tdes0=%x\n", tdes0);
                if (tdes0 & 0x80000000)
                        break;
 
@@ -895,7 +891,7 @@ static void dmfe_free_tx_pkt(struct DEVICE *dev, struct dmfe_board_info * db)
 
                /* Transmit statistic counter */
                if ( tdes0 != 0x7fffffff ) {
-                       /* printk(DRV_NAME ": tdes0=%x\n", tdes0); */
+                       pr_debug("tdes0=%x\n", tdes0);
                        dev->stats.collisions += (tdes0 >> 3) & 0xf;
                        dev->stats.tx_bytes += le32_to_cpu(txptr->tdes1) & 0x7ff;
                        if (tdes0 & TDES0_ERR_MASK) {
@@ -992,7 +988,7 @@ static void dmfe_rx_packet(struct DEVICE *dev, struct dmfe_board_info * db)
                        /* error summary bit check */
                        if (rdes0 & 0x8000) {
                                /* This is a error packet */
-                               //printk(DRV_NAME ": rdes0: %lx\n", rdes0);
+                               pr_debug("rdes0: %x\n", rdes0);
                                dev->stats.rx_errors++;
                                if (rdes0 & 1)
                                        dev->stats.rx_fifo_errors++;
@@ -1191,8 +1187,7 @@ static void dmfe_timer(unsigned long data)
                if ( time_after(jiffies, dev->trans_start + DMFE_TX_TIMEOUT) ) {
                        db->reset_TXtimeout++;
                        db->wait_reset = 1;
-                       printk(KERN_WARNING "%s: Tx timeout - resetting\n",
-                              dev->name);
+                       dev_warn(&dev->dev, "Tx timeout - resetting\n");
                }
        }
 
@@ -1646,7 +1641,7 @@ static u8 dmfe_sense_speed(struct dmfe_board_info * db)
                else                            /* DM9102/DM9102A */
                        phy_mode = phy_read(db->ioaddr,
                                    db->phy_addr, 17, db->chip_id) & 0xf000;
-               /* printk(DRV_NAME ": Phy_mode %x ",phy_mode); */
+               pr_debug("Phy_mode %x\n", phy_mode);
                switch (phy_mode) {
                case 0x1000: db->op_mode = DMFE_10MHF; break;
                case 0x2000: db->op_mode = DMFE_10MFD; break;
@@ -2089,7 +2084,7 @@ static void dmfe_HPNA_remote_cmd_chk(struct dmfe_board_info * db)
 
 
 
-static struct pci_device_id dmfe_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(dmfe_pci_tbl) = {
        { 0x1282, 0x9132, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_DM9132_ID },
        { 0x1282, 0x9102, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_DM9102_ID },
        { 0x1282, 0x9100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_DM9100_ID },
index 889f57aae89be3dc1c90f30f66a085e9d5fedeb0..93f4e8309f8195539b850aa3f83f957e01329784 100644 (file)
@@ -161,15 +161,15 @@ void __devinit tulip_parse_eeprom(struct net_device *dev)
                if (ee_data[0] == 0xff) {
                        if (last_mediatable) {
                                controller_index++;
-                               printk(KERN_INFO "%s:  Controller %d of multiport board.\n",
-                                          dev->name, controller_index);
+                               dev_info(&dev->dev,
+                                        "Controller %d of multiport board\n",
+                                        controller_index);
                                tp->mtable = last_mediatable;
                                ee_data = last_ee_data;
                                goto subsequent_board;
                        } else
-                               printk(KERN_INFO "%s:  Missing EEPROM, this interface may "
-                                          "not work correctly!\n",
-                          dev->name);
+                               dev_info(&dev->dev,
+                                        "Missing EEPROM, this interface may not work correctly!\n");
                        return;
                }
          /* Do a fix-up based on the vendor half of the station address prefix. */
@@ -181,16 +181,15 @@ void __devinit tulip_parse_eeprom(struct net_device *dev)
                          i++;                  /* An Accton EN1207, not an outlaw Maxtech. */
                  memcpy(ee_data + 26, eeprom_fixups[i].newtable,
                                 sizeof(eeprom_fixups[i].newtable));
-                 printk(KERN_INFO "%s: Old format EEPROM on '%s' board.  Using"
-                                " substitute media control info.\n",
-                                dev->name, eeprom_fixups[i].name);
+                 dev_info(&dev->dev,
+                          "Old format EEPROM on '%s' board.  Using substitute media control info\n",
+                          eeprom_fixups[i].name);
                  break;
                }
          }
          if (eeprom_fixups[i].name == NULL) { /* No fixup found. */
-                 printk(KERN_INFO "%s: Old style EEPROM with no media selection "
-                                "information.\n",
-                          dev->name);
+                 dev_info(&dev->dev,
+                          "Old style EEPROM with no media selection information\n");
                return;
          }
        }
@@ -218,7 +217,8 @@ subsequent_board:
                /* there is no phy information, don't even try to build mtable */
                if (count == 0) {
                        if (tulip_debug > 0)
-                               printk(KERN_WARNING "%s: no phy info, aborting mtable build\n", dev->name);
+                               dev_warn(&dev->dev,
+                                        "no phy info, aborting mtable build\n");
                        return;
                }
 
@@ -234,8 +234,8 @@ subsequent_board:
                mtable->has_nonmii = mtable->has_mii = mtable->has_reset = 0;
                mtable->csr15dir = mtable->csr15val = 0;
 
-               printk(KERN_INFO "%s:  EEPROM default media type %s.\n", dev->name,
-                          media & 0x0800 ? "Autosense" : medianame[media & MEDIA_MASK]);
+               dev_info(&dev->dev, "EEPROM default media type %s\n",
+                        media & 0x0800 ? "Autosense" : medianame[media & MEDIA_MASK]);
                for (i = 0; i < count; i++) {
                        struct medialeaf *leaf = &mtable->mleaf[i];
 
@@ -298,16 +298,17 @@ subsequent_board:
                        }
                        if (tulip_debug > 1  &&  leaf->media == 11) {
                                unsigned char *bp = leaf->leafdata;
-                               printk(KERN_INFO "%s:  MII interface PHY %d, setup/reset "
-                                          "sequences %d/%d long, capabilities %2.2x %2.2x.\n",
-                                          dev->name, bp[0], bp[1], bp[2 + bp[1]*2],
-                                          bp[5 + bp[2 + bp[1]*2]*2], bp[4 + bp[2 + bp[1]*2]*2]);
+                               dev_info(&dev->dev,
+                                        "MII interface PHY %d, setup/reset sequences %d/%d long, capabilities %02x %02x\n",
+                                        bp[0], bp[1], bp[2 + bp[1]*2],
+                                        bp[5 + bp[2 + bp[1]*2]*2],
+                                        bp[4 + bp[2 + bp[1]*2]*2]);
                        }
-                       printk(KERN_INFO "%s:  Index #%d - Media %s (#%d) described "
-                                  "by a %s (%d) block.\n",
-                                  dev->name, i, medianame[leaf->media & 15], leaf->media,
-                                  leaf->type < ARRAY_SIZE(block_name) ? block_name[leaf->type] : "<unknown>",
-                                  leaf->type);
+                       dev_info(&dev->dev,
+                                "Index #%d - Media %s (#%d) described by a %s (%d) block\n",
+                                i, medianame[leaf->media & 15], leaf->media,
+                                leaf->type < ARRAY_SIZE(block_name) ? block_name[leaf->type] : "<unknown>",
+                                leaf->type);
                }
                if (new_advertise)
                        tp->sym_advertise = new_advertise;
index 2e8e8ee893c7fee9e309570877e1a5b675dcaf7c..1faf7a4d72024da4ffd864dfddb99502edd6fcc6 100644 (file)
@@ -125,12 +125,12 @@ int tulip_poll(struct napi_struct *napi, int budget)
 #endif
 
        if (tulip_debug > 4)
-               printk(KERN_DEBUG " In tulip_rx(), entry %d %8.8x.\n", entry,
-                          tp->rx_ring[entry].status);
+               printk(KERN_DEBUG " In tulip_rx(), entry %d %08x\n",
+                      entry, tp->rx_ring[entry].status);
 
        do {
                if (ioread32(tp->base_addr + CSR5) == 0xffffffff) {
-                       printk(KERN_DEBUG " In tulip_poll(), hardware disappeared.\n");
+                       printk(KERN_DEBUG " In tulip_poll(), hardware disappeared\n");
                        break;
                }
                /* Acknowledge current RX interrupt sources. */
@@ -146,7 +146,7 @@ int tulip_poll(struct napi_struct *napi, int budget)
                                break;
 
                        if (tulip_debug > 5)
-                               printk(KERN_DEBUG "%s: In tulip_rx(), entry %d %8.8x.\n",
+                               printk(KERN_DEBUG "%s: In tulip_rx(), entry %d %08x\n",
                                       dev->name, entry, status);
 
                       if (++work_done >= budget)
@@ -177,15 +177,15 @@ int tulip_poll(struct napi_struct *napi, int budget)
                                 /* Ingore earlier buffers. */
                                        if ((status & 0xffff) != 0x7fff) {
                                                if (tulip_debug > 1)
-                                                       printk(KERN_WARNING "%s: Oversized Ethernet frame "
-                                                              "spanned multiple buffers, status %8.8x!\n",
-                                                              dev->name, status);
+                                                       dev_warn(&dev->dev,
+                                                               "Oversized Ethernet frame spanned multiple buffers, status %08x!\n",
+                                                               status);
                                                tp->stats.rx_length_errors++;
                                        }
                               } else {
                                 /* There was a fatal error. */
                                        if (tulip_debug > 2)
-                                               printk(KERN_DEBUG "%s: Receive error, Rx status %8.8x.\n",
+                                               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 ||
@@ -226,12 +226,11 @@ int tulip_poll(struct napi_struct *napi, int budget)
 #ifndef final_version
                                        if (tp->rx_buffers[entry].mapping !=
                                            le32_to_cpu(tp->rx_ring[entry].buffer1)) {
-                                               printk(KERN_ERR "%s: Internal fault: The skbuff addresses "
-                                                      "do not match in tulip_rx: %08x vs. %08llx %p / %p.\n",
-                                                      dev->name,
-                                                      le32_to_cpu(tp->rx_ring[entry].buffer1),
-                                                      (unsigned long long)tp->rx_buffers[entry].mapping,
-                                                      skb->head, temp);
+                                               dev_err(&dev->dev,
+                                                      "Internal fault: The skbuff addresses do not match in tulip_rx: %08x vs. %08llx %p / %p\n",
+                                                      le32_to_cpu(tp->rx_ring[entry].buffer1),
+                                                      (unsigned long long)tp->rx_buffers[entry].mapping,
+                                                      skb->head, temp);
                                        }
 #endif
 
@@ -365,16 +364,16 @@ static int tulip_rx(struct net_device *dev)
        int received = 0;
 
        if (tulip_debug > 4)
-               printk(KERN_DEBUG " In tulip_rx(), entry %d %8.8x.\n", entry,
-                          tp->rx_ring[entry].status);
+               printk(KERN_DEBUG " In tulip_rx(), entry %d %08x\n",
+                      entry, tp->rx_ring[entry].status);
        /* If we own the next entry, it is a new packet. Send it up. */
        while ( ! (tp->rx_ring[entry].status & cpu_to_le32(DescOwned))) {
                s32 status = le32_to_cpu(tp->rx_ring[entry].status);
                short pkt_len;
 
                if (tulip_debug > 5)
-                       printk(KERN_DEBUG "%s: In tulip_rx(), entry %d %8.8x.\n",
-                                  dev->name, entry, status);
+                       printk(KERN_DEBUG "%s: In tulip_rx(), entry %d %08x\n",
+                              dev->name, entry, status);
                if (--rx_work_limit < 0)
                        break;
 
@@ -402,16 +401,16 @@ static int tulip_rx(struct net_device *dev)
                                /* Ingore earlier buffers. */
                                if ((status & 0xffff) != 0x7fff) {
                                        if (tulip_debug > 1)
-                                               printk(KERN_WARNING "%s: Oversized Ethernet frame "
-                                                          "spanned multiple buffers, status %8.8x!\n",
-                                                          dev->name, status);
+                                               dev_warn(&dev->dev,
+                                                        "Oversized Ethernet frame spanned multiple buffers, status %08x!\n",
+                                                        status);
                                        tp->stats.rx_length_errors++;
                                }
                        } else {
                                /* There was a fatal error. */
                                if (tulip_debug > 2)
-                                       printk(KERN_DEBUG "%s: Receive error, Rx status %8.8x.\n",
-                                                  dev->name, status);
+                                       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))
@@ -450,12 +449,11 @@ static int tulip_rx(struct net_device *dev)
 #ifndef final_version
                                if (tp->rx_buffers[entry].mapping !=
                                    le32_to_cpu(tp->rx_ring[entry].buffer1)) {
-                                       printk(KERN_ERR "%s: Internal fault: The skbuff addresses "
-                                              "do not match in tulip_rx: %08x vs. %Lx %p / %p.\n",
-                                              dev->name,
-                                              le32_to_cpu(tp->rx_ring[entry].buffer1),
-                                              (long long)tp->rx_buffers[entry].mapping,
-                                              skb->head, temp);
+                                       dev_err(&dev->dev,
+                                               "Internal fault: The skbuff addresses do not match in tulip_rx: %08x vs. %Lx %p / %p\n",
+                                               le32_to_cpu(tp->rx_ring[entry].buffer1),
+                                               (long long)tp->rx_buffers[entry].mapping,
+                                               skb->head, temp);
                                }
 #endif
 
@@ -569,7 +567,7 @@ irqreturn_t tulip_interrupt(int irq, void *dev_instance)
 #endif /*  CONFIG_TULIP_NAPI */
 
                if (tulip_debug > 4)
-                       printk(KERN_DEBUG "%s: interrupt  csr5=%#8.8x new csr5=%#8.8x.\n",
+                       printk(KERN_DEBUG "%s: interrupt  csr5=%#8.8x new csr5=%#8.8x\n",
                               dev->name, csr5, ioread32(ioaddr + CSR5));
 
 
@@ -601,8 +599,8 @@ irqreturn_t tulip_interrupt(int irq, void *dev_instance)
                                        /* There was an major error, log it. */
 #ifndef final_version
                                        if (tulip_debug > 1)
-                                               printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n",
-                                                          dev->name, status);
+                                               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++;
@@ -631,8 +629,9 @@ irqreturn_t tulip_interrupt(int irq, void *dev_instance)
 
 #ifndef final_version
                        if (tp->cur_tx - dirty_tx > TX_RING_SIZE) {
-                               printk(KERN_ERR "%s: Out-of-sync dirty pointer, %d vs. %d.\n",
-                                          dev->name, dirty_tx, tp->cur_tx);
+                               dev_err(&dev->dev,
+                                       "Out-of-sync dirty pointer, %d vs. %d\n",
+                                       dirty_tx, tp->cur_tx);
                                dirty_tx += TX_RING_SIZE;
                        }
 #endif
@@ -643,9 +642,10 @@ irqreturn_t tulip_interrupt(int irq, void *dev_instance)
                        tp->dirty_tx = dirty_tx;
                        if (csr5 & TxDied) {
                                if (tulip_debug > 2)
-                                       printk(KERN_WARNING "%s: The transmitter stopped."
-                                                  "  CSR5 is %x, CSR6 %x, new CSR6 %x.\n",
-                                                  dev->name, csr5, ioread32(ioaddr + CSR6), tp->csr6);
+                                       dev_warn(&dev->dev,
+                                                "The transmitter stopped.  CSR5 is %x, CSR6 %x, new CSR6 %x\n",
+                                                csr5, ioread32(ioaddr + CSR6),
+                                                tp->csr6);
                                tulip_restart_rxtx(tp);
                        }
                        spin_unlock(&tp->lock);
@@ -696,8 +696,9 @@ irqreturn_t tulip_interrupt(int irq, void *dev_instance)
                                 * to the 21142/3 docs that is).
                                 *   -- rmk
                                 */
-                               printk(KERN_ERR "%s: (%lu) System Error occurred (%d)\n",
-                                       dev->name, tp->nir, error);
+                               dev_err(&dev->dev,
+                                       "(%lu) System Error occurred (%d)\n",
+                                       tp->nir, error);
                        }
                        /* Clear all error sources, included undocumented ones! */
                        iowrite32(0x0800f7ba, ioaddr + CSR5);
@@ -706,16 +707,17 @@ irqreturn_t tulip_interrupt(int irq, void *dev_instance)
                if (csr5 & TimerInt) {
 
                        if (tulip_debug > 2)
-                               printk(KERN_ERR "%s: Re-enabling interrupts, %8.8x.\n",
-                                          dev->name, csr5);
+                               dev_err(&dev->dev,
+                                       "Re-enabling interrupts, %08x\n",
+                                       csr5);
                        iowrite32(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7);
                        tp->ttimer = 0;
                        oi++;
                }
                if (tx > maxtx || rx > maxrx || oi > maxoi) {
                        if (tulip_debug > 1)
-                               printk(KERN_WARNING "%s: Too much work during an interrupt, "
-                                          "csr5=0x%8.8x. (%lu) (%d,%d,%d)\n", dev->name, csr5, tp->nir, tx, rx, oi);
+                               dev_warn(&dev->dev, "Too much work during an interrupt, csr5=0x%08x. (%lu) (%d,%d,%d)\n",
+                                        csr5, tp->nir, tx, rx, oi);
 
                        /* Acknowledge all interrupt sources. */
                         iowrite32(0x8001ffff, ioaddr + CSR5);
@@ -764,14 +766,18 @@ irqreturn_t tulip_interrupt(int irq, void *dev_instance)
        entry = tp->dirty_rx % RX_RING_SIZE;
        if (tp->rx_buffers[entry].skb == NULL) {
                if (tulip_debug > 1)
-                       printk(KERN_WARNING "%s: in rx suspend mode: (%lu) (tp->cur_rx = %u, ttimer = %d, rx = %d) go/stay in suspend mode\n", dev->name, tp->nir, tp->cur_rx, tp->ttimer, rx);
+                       dev_warn(&dev->dev,
+                                "in rx suspend mode: (%lu) (tp->cur_rx = %u, ttimer = %d, rx = %d) go/stay in suspend mode\n",
+                                tp->nir, tp->cur_rx, tp->ttimer, rx);
                if (tp->chip_id == LC82C168) {
                        iowrite32(0x00, ioaddr + CSR7);
                        mod_timer(&tp->timer, RUN_AT(HZ/50));
                } else {
                        if (tp->ttimer == 0 || (ioread32(ioaddr + CSR11) & 0xffff) == 0) {
                                if (tulip_debug > 1)
-                                       printk(KERN_WARNING "%s: in rx suspend mode: (%lu) set timer\n", dev->name, tp->nir);
+                                       dev_warn(&dev->dev,
+                                                "in rx suspend mode: (%lu) set timer\n",
+                                                tp->nir);
                                iowrite32(tulip_tbl[tp->chip_id].valid_intrs | TimerInt,
                                        ioaddr + CSR7);
                                iowrite32(TimerInt, ioaddr + CSR5);
@@ -787,8 +793,8 @@ irqreturn_t tulip_interrupt(int irq, void *dev_instance)
        }
 
        if (tulip_debug > 4)
-               printk(KERN_DEBUG "%s: exiting interrupt, csr5=%#4.4x.\n",
-                          dev->name, ioread32(ioaddr + CSR5));
+               printk(KERN_DEBUG "%s: exiting interrupt, csr5=%#04x\n",
+                      dev->name, ioread32(ioaddr + CSR5));
 
        return IRQ_HANDLED;
 }
index d8fda83705bf3e1434ee976fdc80fe78b32eeeff..68b170ae4d15a3c3c0e9d4d85e1ad53ff0eaf1b8 100644 (file)
@@ -182,9 +182,8 @@ void tulip_select_media(struct net_device *dev, int startup)
                switch (mleaf->type) {
                case 0:                                 /* 21140 non-MII xcvr. */
                        if (tulip_debug > 1)
-                               printk(KERN_DEBUG "%s: Using a 21140 non-MII transceiver"
-                                          " with control setting %2.2x.\n",
-                                          dev->name, p[1]);
+                               printk(KERN_DEBUG "%s: Using a 21140 non-MII transceiver with control setting %02x\n",
+                                      dev->name, p[1]);
                        dev->if_port = p[0];
                        if (startup)
                                iowrite32(mtable->csr12dir | 0x100, ioaddr + CSR12);
@@ -205,15 +204,15 @@ void tulip_select_media(struct net_device *dev, int startup)
                                struct medialeaf *rleaf = &mtable->mleaf[mtable->has_reset];
                                unsigned char *rst = rleaf->leafdata;
                                if (tulip_debug > 1)
-                                       printk(KERN_DEBUG "%s: Resetting the transceiver.\n",
-                                                  dev->name);
+                                       printk(KERN_DEBUG "%s: Resetting the transceiver\n",
+                                              dev->name);
                                for (i = 0; i < rst[0]; i++)
                                        iowrite32(get_u16(rst + 1 + (i<<1)) << 16, ioaddr + CSR15);
                        }
                        if (tulip_debug > 1)
-                               printk(KERN_DEBUG "%s: 21143 non-MII %s transceiver control "
-                                          "%4.4x/%4.4x.\n",
-                                          dev->name, medianame[dev->if_port], setup[0], setup[1]);
+                               printk(KERN_DEBUG "%s: 21143 non-MII %s transceiver control %04x/%04x\n",
+                                      dev->name, medianame[dev->if_port],
+                                      setup[0], setup[1]);
                        if (p[0] & 0x40) {      /* SIA (CSR13-15) setup values are provided. */
                                csr13val = setup[0];
                                csr14val = setup[1];
@@ -240,8 +239,8 @@ void tulip_select_media(struct net_device *dev, int startup)
                                if (startup) iowrite32(csr13val, ioaddr + CSR13);
                        }
                        if (tulip_debug > 1)
-                               printk(KERN_DEBUG "%s:  Setting CSR15 to %8.8x/%8.8x.\n",
-                                          dev->name, csr15dir, csr15val);
+                               printk(KERN_DEBUG "%s:  Setting CSR15 to %08x/%08x\n",
+                                      dev->name, csr15dir, csr15val);
                        if (mleaf->type == 4)
                                new_csr6 = 0x82020000 | ((setup[2] & 0x71) << 18);
                        else
@@ -317,8 +316,9 @@ void tulip_select_media(struct net_device *dev, int startup)
                                if (tp->mii_advertise == 0)
                                        tp->mii_advertise = tp->advertising[phy_num];
                                if (tulip_debug > 1)
-                                       printk(KERN_DEBUG "%s:  Advertising %4.4x on MII %d.\n",
-                                              dev->name, tp->mii_advertise, tp->phys[phy_num]);
+                                       printk(KERN_DEBUG "%s:  Advertising %04x on MII %d\n",
+                                              dev->name, tp->mii_advertise,
+                                              tp->phys[phy_num]);
                                tulip_mdio_write(dev, tp->phys[phy_num], 4, tp->mii_advertise);
                        }
                        break;
@@ -335,8 +335,8 @@ void tulip_select_media(struct net_device *dev, int startup)
                                struct medialeaf *rleaf = &mtable->mleaf[mtable->has_reset];
                                unsigned char *rst = rleaf->leafdata;
                                if (tulip_debug > 1)
-                                       printk(KERN_DEBUG "%s: Resetting the transceiver.\n",
-                                                  dev->name);
+                                       printk(KERN_DEBUG "%s: Resetting the transceiver\n",
+                                              dev->name);
                                for (i = 0; i < rst[0]; i++)
                                        iowrite32(get_u16(rst + 1 + (i<<1)) << 16, ioaddr + CSR15);
                        }
@@ -344,20 +344,20 @@ void tulip_select_media(struct net_device *dev, int startup)
                        break;
                }
                default:
-                       printk(KERN_DEBUG "%s:  Invalid media table selection %d.\n",
-                                          dev->name, mleaf->type);
+                       printk(KERN_DEBUG "%s:  Invalid media table selection %d\n",
+                              dev->name, mleaf->type);
                        new_csr6 = 0x020E0000;
                }
                if (tulip_debug > 1)
-                       printk(KERN_DEBUG "%s: Using media type %s, CSR12 is %2.2x.\n",
-                                  dev->name, medianame[dev->if_port],
+                       printk(KERN_DEBUG "%s: Using media type %s, CSR12 is %02x\n",
+                              dev->name, medianame[dev->if_port],
                                   ioread32(ioaddr + CSR12) & 0xff);
        } else if (tp->chip_id == LC82C168) {
                if (startup && ! tp->medialock)
                        dev->if_port = tp->mii_cnt ? 11 : 0;
                if (tulip_debug > 1)
-                       printk(KERN_DEBUG "%s: PNIC PHY status is %3.3x, media %s.\n",
-                                  dev->name, ioread32(ioaddr + 0xB8), medianame[dev->if_port]);
+                       printk(KERN_DEBUG "%s: PNIC PHY status is %3.3x, media %s\n",
+                              dev->name, ioread32(ioaddr + 0xB8), medianame[dev->if_port]);
                if (tp->mii_cnt) {
                        new_csr6 = 0x810C0000;
                        iowrite32(0x0001, ioaddr + CSR15);
@@ -388,10 +388,9 @@ void tulip_select_media(struct net_device *dev, int startup)
                } else
                        new_csr6 = 0x03860000;
                if (tulip_debug > 1)
-                       printk(KERN_DEBUG "%s: No media description table, assuming "
-                                  "%s transceiver, CSR12 %2.2x.\n",
-                                  dev->name, medianame[dev->if_port],
-                                  ioread32(ioaddr + CSR12));
+                       printk(KERN_DEBUG "%s: No media description table, assuming %s transceiver, CSR12 %02x\n",
+                              dev->name, medianame[dev->if_port],
+                              ioread32(ioaddr + CSR12));
        }
 
        tp->csr6 = new_csr6 | (tp->csr6 & 0xfdff) | (tp->full_duplex ? 0x0200 : 0);
@@ -415,16 +414,17 @@ int tulip_check_duplex(struct net_device *dev)
        bmsr = tulip_mdio_read(dev, tp->phys[0], MII_BMSR);
        lpa = tulip_mdio_read(dev, tp->phys[0], MII_LPA);
        if (tulip_debug > 1)
-               printk(KERN_INFO "%s: MII status %4.4x, Link partner report "
-                          "%4.4x.\n", dev->name, bmsr, lpa);
+               dev_info(&dev->dev, "MII status %04x, Link partner report %04x\n",
+                        bmsr, lpa);
        if (bmsr == 0xffff)
                return -2;
        if ((bmsr & BMSR_LSTATUS) == 0) {
                int new_bmsr = tulip_mdio_read(dev, tp->phys[0], MII_BMSR);
                if ((new_bmsr & BMSR_LSTATUS) == 0) {
                        if (tulip_debug  > 1)
-                               printk(KERN_INFO "%s: No link beat on the MII interface,"
-                                          " status %4.4x.\n", dev->name, new_bmsr);
+                               dev_info(&dev->dev,
+                                        "No link beat on the MII interface, status %04x\n",
+                                        new_bmsr);
                        return -1;
                }
        }
@@ -443,10 +443,10 @@ int tulip_check_duplex(struct net_device *dev)
                tulip_restart_rxtx(tp);
 
                if (tulip_debug > 0)
-                       printk(KERN_INFO "%s: Setting %s-duplex based on MII"
-                                  "#%d link partner capability of %4.4x.\n",
-                                  dev->name, tp->full_duplex ? "full" : "half",
-                                  tp->phys[0], lpa);
+                       dev_info(&dev->dev,
+                                "Setting %s-duplex based on MII#%d link partner capability of %04x\n",
+                                tp->full_duplex ? "full" : "half",
+                                tp->phys[0], lpa);
                return 1;
        }
 
@@ -501,15 +501,13 @@ void __devinit tulip_find_mii (struct net_device *dev, int board_idx)
 
                tp->phys[phy_idx++] = phy;
 
-               printk (KERN_INFO "tulip%d:  MII transceiver #%d "
-                       "config %4.4x status %4.4x advertising %4.4x.\n",
+               pr_info("tulip%d:  MII transceiver #%d config %04x status %04x advertising %04x\n",
                        board_idx, phy, mii_reg0, mii_status, mii_advert);
 
                /* Fixup for DLink with miswired PHY. */
                if (mii_advert != to_advert) {
-                       printk (KERN_DEBUG "tulip%d:  Advertising %4.4x on PHY %d,"
-                               " previously advertising %4.4x.\n",
-                               board_idx, to_advert, phy, mii_advert);
+                       printk(KERN_DEBUG "tulip%d:  Advertising %04x on PHY %d, previously advertising %04x\n",
+                              board_idx, to_advert, phy, mii_advert);
                        tulip_mdio_write (dev, phy, 4, to_advert);
                }
 
@@ -554,7 +552,7 @@ void __devinit tulip_find_mii (struct net_device *dev, int board_idx)
        }
        tp->mii_cnt = phy_idx;
        if (tp->mtable && tp->mtable->has_mii && phy_idx == 0) {
-               printk (KERN_INFO "tulip%d: ***WARNING***: No MII transceiver found!\n",
+               pr_info("tulip%d: ***WARNING***: No MII transceiver found!\n",
                        board_idx);
                tp->phys[0] = 1;
        }
index d3253ed09dfc61760b7bda7160547f022bdbe178..966efa1a27d70ca01c0c8cf3fb6458cd72c90bf0 100644 (file)
@@ -40,8 +40,8 @@ void pnic_do_nway(struct net_device *dev)
                        new_csr6 |= 0x00000200;
                }
                if (tulip_debug > 1)
-                       printk(KERN_DEBUG "%s: PNIC autonegotiated status %8.8x, %s.\n",
-                                  dev->name, phy_reg, medianame[dev->if_port]);
+                       printk(KERN_DEBUG "%s: PNIC autonegotiated status %08x, %s\n",
+                              dev->name, phy_reg, medianame[dev->if_port]);
                if (tp->csr6 != new_csr6) {
                        tp->csr6 = new_csr6;
                        /* Restart Tx */
@@ -58,8 +58,8 @@ void pnic_lnk_change(struct net_device *dev, int csr5)
        int phy_reg = ioread32(ioaddr + 0xB8);
 
        if (tulip_debug > 1)
-               printk(KERN_DEBUG "%s: PNIC link changed state %8.8x, CSR5 %8.8x.\n",
-                          dev->name, phy_reg, csr5);
+               printk(KERN_DEBUG "%s: PNIC link changed state %08x, CSR5 %08x\n",
+                      dev->name, phy_reg, csr5);
        if (ioread32(ioaddr + CSR5) & TPLnkFail) {
                iowrite32((ioread32(ioaddr + CSR7) & ~TPLnkFail) | TPLnkPass, ioaddr + CSR7);
                /* If we use an external MII, then we mustn't use the
@@ -114,9 +114,8 @@ void pnic_timer(unsigned long data)
                int csr5 = ioread32(ioaddr + CSR5);
 
                if (tulip_debug > 1)
-                       printk(KERN_DEBUG "%s: PNIC timer PHY status %8.8x, %s "
-                                  "CSR5 %8.8x.\n",
-                                  dev->name, phy_reg, medianame[dev->if_port], csr5);
+                       printk(KERN_DEBUG "%s: PNIC timer PHY status %08x, %s CSR5 %08x\n",
+                              dev->name, phy_reg, medianame[dev->if_port], csr5);
                if (phy_reg & 0x04000000) {     /* Remote link fault */
                        iowrite32(0x0201F078, ioaddr + 0xB8);
                        next_tick = 1*HZ;
@@ -126,10 +125,11 @@ void pnic_timer(unsigned long data)
                        next_tick = 60*HZ;
                } else if (csr5 & TPLnkFail) { /* 100baseTx link beat */
                        if (tulip_debug > 1)
-                               printk(KERN_DEBUG "%s: %s link beat failed, CSR12 %4.4x, "
-                                          "CSR5 %8.8x, PHY %3.3x.\n",
-                                          dev->name, medianame[dev->if_port], csr12,
-                                          ioread32(ioaddr + CSR5), ioread32(ioaddr + 0xB8));
+                               printk(KERN_DEBUG "%s: %s link beat failed, CSR12 %04x, CSR5 %08x, PHY %03x\n",
+                                      dev->name, medianame[dev->if_port],
+                                      csr12,
+                                      ioread32(ioaddr + CSR5),
+                                      ioread32(ioaddr + 0xB8));
                        next_tick = 3*HZ;
                        if (tp->medialock) {
                        } else if (tp->nwayset  &&  (dev->if_port & 1)) {
@@ -151,10 +151,11 @@ void pnic_timer(unsigned long data)
                                tulip_restart_rxtx(tp);
                                dev->trans_start = jiffies;
                                if (tulip_debug > 1)
-                                       printk(KERN_INFO "%s: Changing PNIC configuration to %s "
-                                                  "%s-duplex, CSR6 %8.8x.\n",
-                                                  dev->name, medianame[dev->if_port],
-                                                  tp->full_duplex ? "full" : "half", new_csr6);
+                                       dev_info(&dev->dev,
+                                                "Changing PNIC configuration to %s %s-duplex, CSR6 %08x\n",
+                                                medianame[dev->if_port],
+                                                tp->full_duplex ? "full" : "half",
+                                                new_csr6);
                        }
                }
        }
@@ -162,7 +163,7 @@ too_good_connection:
        mod_timer(&tp->timer, RUN_AT(next_tick));
        if(!ioread32(ioaddr + CSR7)) {
                if (tulip_debug > 1)
-                       printk(KERN_INFO "%s: sw timer wakeup.\n", dev->name);
+                       dev_info(&dev->dev, "sw timer wakeup\n");
                disable_irq(dev->irq);
                tulip_refill_rx(dev);
                enable_irq(dev->irq);
index d8418694bf466ded96824d76b926a9e4d9076c44..b8197666021e7b3e55e5660d76322657acfc9be7 100644 (file)
@@ -87,8 +87,8 @@ void pnic2_timer(unsigned long data)
        int next_tick = 60*HZ;
 
        if (tulip_debug > 3)
-               printk(KERN_INFO"%s: PNIC2 negotiation status %8.8x.\n",
-                    dev->name,ioread32(ioaddr + CSR12));
+               dev_info(&dev->dev, "PNIC2 negotiation status %08x\n",
+                        ioread32(ioaddr + CSR12));
 
        if (next_tick) {
                mod_timer(&tp->timer, RUN_AT(next_tick));
@@ -125,8 +125,8 @@ void pnic2_start_nway(struct net_device *dev)
         csr14 |= 0x00001184;
 
        if (tulip_debug > 1)
-               printk(KERN_DEBUG "%s: Restarting PNIC2 autonegotiation, "
-                      "csr14=%8.8x.\n", dev->name, csr14);
+               printk(KERN_DEBUG "%s: Restarting PNIC2 autonegotiation, csr14=%08x\n",
+                      dev->name, csr14);
 
         /* tell pnic2_lnk_change we are doing an nway negotiation */
        dev->if_port = 0;
@@ -137,8 +137,8 @@ void pnic2_start_nway(struct net_device *dev)
 
        tp->csr6 = ioread32(ioaddr + CSR6);
        if (tulip_debug > 1)
-               printk(KERN_DEBUG "%s: On Entry to Nway, "
-                      "csr6=%8.8x.\n", dev->name, tp->csr6);
+               printk(KERN_DEBUG "%s: On Entry to Nway, csr6=%08x\n",
+                      dev->name, tp->csr6);
 
         /* mask off any bits not to touch
          * comment at top of file explains mask value
@@ -181,9 +181,9 @@ void pnic2_lnk_change(struct net_device *dev, int csr5)
        int csr12 = ioread32(ioaddr + CSR12);
 
        if (tulip_debug > 1)
-               printk(KERN_INFO"%s: PNIC2 link status interrupt %8.8x, "
-                       " CSR5 %x, %8.8x.\n", dev->name, csr12,
-                       csr5, ioread32(ioaddr + CSR14));
+               dev_info(&dev->dev,
+                        "PNIC2 link status interrupt %08x,  CSR5 %x, %08x\n",
+                        csr12, csr5, ioread32(ioaddr + CSR14));
 
        /* If NWay finished and we have a negotiated partner capability.
          * check bits 14:12 for bit pattern 101 - all is good
@@ -215,9 +215,9 @@ void pnic2_lnk_change(struct net_device *dev, int csr5)
                        else if (negotiated & 0x0020)   dev->if_port = 0;
                        else {
                             if (tulip_debug > 1)
-                                  printk(KERN_INFO "%s: funny autonegotiate result "
-                                        "csr12 %8.8x advertising %4.4x\n",
-                                        dev->name, csr12, tp->sym_advertise);
+                                    dev_info(&dev->dev,
+                                             "funny autonegotiate result csr12 %08x advertising %04x\n",
+                                             csr12, tp->sym_advertise);
                             tp->nwayset = 0;
                             /* so check  if 100baseTx link state is okay */
                             if ((csr12 & 2) == 0  &&  (tp->sym_advertise & 0x0180))
@@ -231,10 +231,11 @@ void pnic2_lnk_change(struct net_device *dev, int csr5)
 
                        if (tulip_debug > 1) {
                               if (tp->nwayset)
-                                    printk(KERN_INFO "%s: Switching to %s based on link "
-                                   "negotiation %4.4x & %4.4x = %4.4x.\n",
-                                    dev->name, medianame[dev->if_port],
-                                     tp->sym_advertise, tp->lpar, negotiated);
+                                      dev_info(&dev->dev,
+                                               "Switching to %s based on link negotiation %04x & %04x = %04x\n",
+                                               medianame[dev->if_port],
+                                               tp->sym_advertise, tp->lpar,
+                                               negotiated);
                        }
 
                         /* remember to turn off bit 7 - autonegotiate
@@ -270,9 +271,9 @@ void pnic2_lnk_change(struct net_device *dev, int csr5)
                        iowrite32(1, ioaddr + CSR13);
 
                        if (tulip_debug > 2)
-                               printk(KERN_DEBUG "%s:  Setting CSR6 %8.8x/%x CSR12 "
-                                      "%8.8x.\n", dev->name, tp->csr6,
-                                      ioread32(ioaddr + CSR6), ioread32(ioaddr + CSR12));
+                               printk(KERN_DEBUG "%s: Setting CSR6 %08x/%x CSR12 %08x\n",
+                                      dev->name, tp->csr6,
+                                      ioread32(ioaddr + CSR6), ioread32(ioaddr + CSR12));
 
                        /* now the following actually writes out the
                         * new csr6 values
@@ -282,9 +283,9 @@ void pnic2_lnk_change(struct net_device *dev, int csr5)
                         return;
 
                } else {
-                       printk(KERN_INFO "%s: Autonegotiation failed, "
-                                    "using %s, link beat status %4.4x.\n",
-                                    dev->name, medianame[dev->if_port], csr12);
+                       dev_info(&dev->dev,
+                                "Autonegotiation failed, using %s, link beat status %04x\n",
+                                medianame[dev->if_port], csr12);
 
                         /* remember to turn off bit 7 - autonegotiate
                          * enable so we don't forget
@@ -339,9 +340,9 @@ void pnic2_lnk_change(struct net_device *dev, int csr5)
                /* we are at 100mb and a potential link change occurred */
 
                if (tulip_debug > 1)
-                       printk(KERN_INFO"%s: PNIC2 %s link beat %s.\n",
-                                  dev->name, medianame[dev->if_port],
-                                  (csr12 & 2) ? "failed" : "good");
+                       dev_info(&dev->dev, "PNIC2 %s link beat %s\n",
+                                medianame[dev->if_port],
+                                (csr12 & 2) ? "failed" : "good");
 
                 /* check 100 link beat */
 
@@ -364,9 +365,9 @@ void pnic2_lnk_change(struct net_device *dev, int csr5)
                /* we are at 10mb and a potential link change occurred */
 
                if (tulip_debug > 1)
-                       printk(KERN_INFO"%s: PNIC2 %s link beat %s.\n",
-                                  dev->name, medianame[dev->if_port],
-                                  (csr12 & 4) ? "failed" : "good");
+                       dev_info(&dev->dev, "PNIC2 %s link beat %s\n",
+                                medianame[dev->if_port],
+                                (csr12 & 4) ? "failed" : "good");
 
 
                 tp->nway = 0;
@@ -385,7 +386,7 @@ void pnic2_lnk_change(struct net_device *dev, int csr5)
 
 
        if (tulip_debug > 1)
-               printk(KERN_INFO"%s: PNIC2 Link Change Default?\n",dev->name);
+               dev_info(&dev->dev, "PNIC2 Link Change Default?\n");
 
         /* if all else fails default to trying 10baseT-HD */
        dev->if_port = 0;
index a0e0842230826dffd494c94c4cc62f9105b72000..36c2725ec8867804eddeb117d8032b73dc1ab32a 100644 (file)
@@ -28,11 +28,11 @@ void tulip_media_task(struct work_struct *work)
        unsigned long flags;
 
        if (tulip_debug > 2) {
-               printk(KERN_DEBUG "%s: Media selection tick, %s, status %8.8x mode"
-                          " %8.8x SIA %8.8x %8.8x %8.8x %8.8x.\n",
-                          dev->name, medianame[dev->if_port], ioread32(ioaddr + CSR5),
-                          ioread32(ioaddr + CSR6), csr12, ioread32(ioaddr + CSR13),
-                          ioread32(ioaddr + CSR14), ioread32(ioaddr + CSR15));
+               printk(KERN_DEBUG "%s: Media selection tick, %s, status %08x mode %08x SIA %08x %08x %08x %08x\n",
+                      dev->name, medianame[dev->if_port],
+                      ioread32(ioaddr + CSR5), ioread32(ioaddr + CSR6),
+                      csr12, ioread32(ioaddr + CSR13),
+                      ioread32(ioaddr + CSR14), ioread32(ioaddr + CSR15));
        }
        switch (tp->chip_id) {
        case DC21140:
@@ -48,9 +48,9 @@ void tulip_media_task(struct work_struct *work)
                           Assume this a generic MII or SYM transceiver. */
                        next_tick = 60*HZ;
                        if (tulip_debug > 2)
-                               printk(KERN_DEBUG "%s: network media monitor CSR6 %8.8x "
-                                          "CSR12 0x%2.2x.\n",
-                                          dev->name, ioread32(ioaddr + CSR6), csr12 & 0xff);
+                               printk(KERN_DEBUG "%s: network media monitor CSR6 %08x CSR12 0x%02x\n",
+                                      dev->name,
+                                      ioread32(ioaddr + CSR6), csr12 & 0xff);
                        break;
                }
                mleaf = &tp->mtable->mleaf[tp->cur_index];
@@ -62,9 +62,8 @@ void tulip_media_task(struct work_struct *work)
                        s8 bitnum = p[offset];
                        if (p[offset+1] & 0x80) {
                                if (tulip_debug > 1)
-                                       printk(KERN_DEBUG"%s: Transceiver monitor tick "
-                                                  "CSR12=%#2.2x, no media sense.\n",
-                                                  dev->name, csr12);
+                                       printk(KERN_DEBUG "%s: Transceiver monitor tick CSR12=%#02x, no media sense\n",
+                                              dev->name, csr12);
                                if (mleaf->type == 4) {
                                        if (mleaf->media == 3 && (csr12 & 0x02))
                                                goto select_next_media;
@@ -72,16 +71,16 @@ void tulip_media_task(struct work_struct *work)
                                break;
                        }
                        if (tulip_debug > 2)
-                               printk(KERN_DEBUG "%s: Transceiver monitor tick: CSR12=%#2.2x"
-                                          " bit %d is %d, expecting %d.\n",
-                                          dev->name, csr12, (bitnum >> 1) & 7,
-                                          (csr12 & (1 << ((bitnum >> 1) & 7))) != 0,
-                                          (bitnum >= 0));
+                               printk(KERN_DEBUG "%s: Transceiver monitor tick: CSR12=%#02x bit %d is %d, expecting %d\n",
+                                      dev->name, csr12, (bitnum >> 1) & 7,
+                                      (csr12 & (1 << ((bitnum >> 1) & 7))) != 0,
+                                      (bitnum >= 0));
                        /* Check that the specified bit has the proper value. */
                        if ((bitnum < 0) !=
                                ((csr12 & (1 << ((bitnum >> 1) & 7))) != 0)) {
                                if (tulip_debug > 2)
-                                       printk(KERN_DEBUG "%s: Link beat detected for %s.\n", dev->name,
+                                       printk(KERN_DEBUG "%s: Link beat detected for %s\n",
+                                              dev->name,
                                               medianame[mleaf->media & MEDIA_MASK]);
                                if ((p[2] & 0x61) == 0x01)      /* Bogus Znyx board. */
                                        goto actually_mii;
@@ -100,9 +99,9 @@ void tulip_media_task(struct work_struct *work)
                        if (tulip_media_cap[dev->if_port] & MediaIsFD)
                                goto select_next_media; /* Skip FD entries. */
                        if (tulip_debug > 1)
-                               printk(KERN_DEBUG "%s: No link beat on media %s,"
-                                      " trying transceiver type %s.\n",
-                                      dev->name, medianame[mleaf->media & MEDIA_MASK],
+                               printk(KERN_DEBUG "%s: No link beat on media %s, trying transceiver type %s\n",
+                                      dev->name,
+                                      medianame[mleaf->media & MEDIA_MASK],
                                       medianame[tp->mtable->mleaf[tp->cur_index].media]);
                        tulip_select_media(dev, 0);
                        /* Restart the transmit process. */
@@ -151,8 +150,8 @@ void mxic_timer(unsigned long data)
        int next_tick = 60*HZ;
 
        if (tulip_debug > 3) {
-               printk(KERN_INFO"%s: MXIC negotiation status %8.8x.\n", dev->name,
-                          ioread32(ioaddr + CSR12));
+               dev_info(&dev->dev, "MXIC negotiation status %08x\n",
+                        ioread32(ioaddr + CSR12));
        }
        if (next_tick) {
                mod_timer(&tp->timer, RUN_AT(next_tick));
@@ -167,11 +166,10 @@ void comet_timer(unsigned long data)
        int next_tick = 60*HZ;
 
        if (tulip_debug > 1)
-               printk(KERN_DEBUG "%s: Comet link status %4.4x partner capability "
-                          "%4.4x.\n",
-                          dev->name,
-                          tulip_mdio_read(dev, tp->phys[0], 1),
-                          tulip_mdio_read(dev, tp->phys[0], 5));
+               printk(KERN_DEBUG "%s: Comet link status %04x partner capability %04x\n",
+                      dev->name,
+                      tulip_mdio_read(dev, tp->phys[0], 1),
+                      tulip_mdio_read(dev, tp->phys[0], 5));
        /* mod_timer synchronizes us with potential add_timer calls
         * from interrupts.
         */
index 20696b5d60a5cd48385aa7241c90d80f0d408f96..e1a5f03a49c5850f7c79e0b4a60bc74b2d71a9c4 100644 (file)
@@ -41,7 +41,6 @@
 static char version[] __devinitdata =
        "Linux Tulip driver version " DRV_VERSION " (" DRV_RELDATE ")\n";
 
-
 /* A few user-configurable values. */
 
 /* Maximum events (Rx packets, etc.) to handle at each interrupt. */
@@ -211,7 +210,7 @@ struct tulip_chip_table tulip_tbl[] = {
 };
 
 
-static struct pci_device_id tulip_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(tulip_pci_tbl) = {
        { 0x1011, 0x0009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21140 },
        { 0x1011, 0x0019, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21143 },
        { 0x11AD, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, LC82C168 },
@@ -326,7 +325,8 @@ static void tulip_up(struct net_device *dev)
        udelay(100);
 
        if (tulip_debug > 1)
-               printk(KERN_DEBUG "%s: tulip_up(), irq==%d.\n", dev->name, dev->irq);
+               printk(KERN_DEBUG "%s: tulip_up(), irq==%d\n",
+                      dev->name, dev->irq);
 
        iowrite32(tp->rx_ring_dma, ioaddr + CSR3);
        iowrite32(tp->tx_ring_dma, ioaddr + CSR4);
@@ -387,8 +387,9 @@ static void tulip_up(struct net_device *dev)
                        (dev->if_port == 12 ? 0 : dev->if_port);
                for (i = 0; i < tp->mtable->leafcount; i++)
                        if (tp->mtable->mleaf[i].media == looking_for) {
-                               printk(KERN_INFO "%s: Using user-specified media %s.\n",
-                                          dev->name, medianame[dev->if_port]);
+                               dev_info(&dev->dev,
+                                        "Using user-specified media %s\n",
+                                        medianame[dev->if_port]);
                                goto media_picked;
                        }
        }
@@ -396,8 +397,9 @@ static void tulip_up(struct net_device *dev)
                int looking_for = tp->mtable->defaultmedia & MEDIA_MASK;
                for (i = 0; i < tp->mtable->leafcount; i++)
                        if (tp->mtable->mleaf[i].media == looking_for) {
-                               printk(KERN_INFO "%s: Using EEPROM-set media %s.\n",
-                                          dev->name, medianame[looking_for]);
+                               dev_info(&dev->dev,
+                                        "Using EEPROM-set media %s\n",
+                                        medianame[looking_for]);
                                goto media_picked;
                        }
        }
@@ -424,9 +426,10 @@ media_picked:
                if (tp->mii_cnt) {
                        tulip_select_media(dev, 1);
                        if (tulip_debug > 1)
-                               printk(KERN_INFO "%s: Using MII transceiver %d, status "
-                                          "%4.4x.\n",
-                                          dev->name, tp->phys[0], tulip_mdio_read(dev, tp->phys[0], 1));
+                               dev_info(&dev->dev,
+                                        "Using MII transceiver %d, status %04x\n",
+                                        tp->phys[0],
+                                        tulip_mdio_read(dev, tp->phys[0], 1));
                        iowrite32(csr6_mask_defstate, ioaddr + CSR6);
                        tp->csr6 = csr6_mask_hdcap;
                        dev->if_port = 11;
@@ -490,9 +493,10 @@ media_picked:
        iowrite32(0, ioaddr + CSR2);            /* Rx poll demand */
 
        if (tulip_debug > 2) {
-               printk(KERN_DEBUG "%s: Done tulip_up(), CSR0 %8.8x, CSR5 %8.8x CSR6 %8.8x.\n",
-                          dev->name, ioread32(ioaddr + CSR0), ioread32(ioaddr + CSR5),
-                          ioread32(ioaddr + CSR6));
+               printk(KERN_DEBUG "%s: Done tulip_up(), CSR0 %08x, CSR5 %08x CSR6 %08x\n",
+                      dev->name, ioread32(ioaddr + CSR0),
+                      ioread32(ioaddr + CSR5),
+                      ioread32(ioaddr + CSR6));
        }
 
        /* Set the timer to switch to check for link beat and perhaps switch
@@ -540,27 +544,30 @@ static void tulip_tx_timeout(struct net_device *dev)
        if (tulip_media_cap[dev->if_port] & MediaIsMII) {
                /* Do nothing -- the media monitor should handle this. */
                if (tulip_debug > 1)
-                       printk(KERN_WARNING "%s: Transmit timeout using MII device.\n",
-                                  dev->name);
+                       dev_warn(&dev->dev,
+                                "Transmit timeout using MII device\n");
        } else if (tp->chip_id == DC21140 || tp->chip_id == DC21142 ||
                   tp->chip_id == MX98713 || tp->chip_id == COMPEX9881 ||
                   tp->chip_id == DM910X) {
-               printk(KERN_WARNING "%s: 21140 transmit timed out, status %8.8x, "
-                          "SIA %8.8x %8.8x %8.8x %8.8x, resetting...\n",
-                          dev->name, ioread32(ioaddr + CSR5), ioread32(ioaddr + CSR12),
-                          ioread32(ioaddr + CSR13), ioread32(ioaddr + CSR14), ioread32(ioaddr + CSR15));
+               dev_warn(&dev->dev,
+                        "21140 transmit timed out, status %08x, SIA %08x %08x %08x %08x, resetting...\n",
+                        ioread32(ioaddr + CSR5), ioread32(ioaddr + CSR12),
+                        ioread32(ioaddr + CSR13), ioread32(ioaddr + CSR14),
+                        ioread32(ioaddr + CSR15));
                tp->timeout_recovery = 1;
                schedule_work(&tp->media_work);
                goto out_unlock;
        } else if (tp->chip_id == PNIC2) {
-               printk(KERN_WARNING "%s: PNIC2 transmit timed out, status %8.8x, "
-                      "CSR6/7 %8.8x / %8.8x CSR12 %8.8x, resetting...\n",
-                      dev->name, (int)ioread32(ioaddr + CSR5), (int)ioread32(ioaddr + CSR6),
-                      (int)ioread32(ioaddr + CSR7), (int)ioread32(ioaddr + CSR12));
+               dev_warn(&dev->dev,
+                        "PNIC2 transmit timed out, status %08x, CSR6/7 %08x / %08x CSR12 %08x, resetting...\n",
+                        (int)ioread32(ioaddr + CSR5),
+                        (int)ioread32(ioaddr + CSR6),
+                        (int)ioread32(ioaddr + CSR7),
+                        (int)ioread32(ioaddr + CSR12));
        } else {
-               printk(KERN_WARNING "%s: Transmit timed out, status %8.8x, CSR12 "
-                          "%8.8x, resetting...\n",
-                          dev->name, ioread32(ioaddr + CSR5), ioread32(ioaddr + CSR12));
+               dev_warn(&dev->dev,
+                        "Transmit timed out, status %08x, CSR12 %08x, resetting...\n",
+                        ioread32(ioaddr + CSR5), ioread32(ioaddr + CSR12));
                dev->if_port = 0;
        }
 
@@ -570,26 +577,26 @@ static void tulip_tx_timeout(struct net_device *dev)
                for (i = 0; i < RX_RING_SIZE; i++) {
                        u8 *buf = (u8 *)(tp->rx_ring[i].buffer1);
                        int j;
-                       printk(KERN_DEBUG "%2d: %8.8x %8.8x %8.8x %8.8x  "
-                                  "%2.2x %2.2x %2.2x.\n",
-                                  i, (unsigned int)tp->rx_ring[i].status,
-                                  (unsigned int)tp->rx_ring[i].length,
-                                  (unsigned int)tp->rx_ring[i].buffer1,
-                                  (unsigned int)tp->rx_ring[i].buffer2,
-                                  buf[0], buf[1], buf[2]);
+                       printk(KERN_DEBUG
+                              "%2d: %08x %08x %08x %08x  %02x %02x %02x\n",
+                              i,
+                              (unsigned int)tp->rx_ring[i].status,
+                              (unsigned int)tp->rx_ring[i].length,
+                              (unsigned int)tp->rx_ring[i].buffer1,
+                              (unsigned int)tp->rx_ring[i].buffer2,
+                              buf[0], buf[1], buf[2]);
                        for (j = 0; buf[j] != 0xee && j < 1600; j++)
                                if (j < 100)
-                                       printk(KERN_CONT " %2.2x", buf[j]);
-                       printk(KERN_CONT " j=%d.\n", j);
+                                       pr_cont(" %02x", buf[j]);
+                       pr_cont(" j=%d\n", j);
                }
-               printk(KERN_DEBUG "  Rx ring %8.8x: ", (int)tp->rx_ring);
+               printk(KERN_DEBUG "  Rx ring %08x: ", (int)tp->rx_ring);
                for (i = 0; i < RX_RING_SIZE; i++)
-                       printk(KERN_CONT " %8.8x",
-                              (unsigned int)tp->rx_ring[i].status);
-               printk(KERN_DEBUG "  Tx ring %8.8x: ", (int)tp->tx_ring);
+                       pr_cont(" %08x", (unsigned int)tp->rx_ring[i].status);
+               printk(KERN_DEBUG "  Tx ring %08x: ", (int)tp->tx_ring);
                for (i = 0; i < TX_RING_SIZE; i++)
-                       printk(KERN_CONT " %8.8x", (unsigned int)tp->tx_ring[i].status);
-               printk(KERN_CONT "\n");
+                       pr_cont(" %08x", (unsigned int)tp->tx_ring[i].status);
+               pr_cont("\n");
        }
 #endif
 
@@ -832,8 +839,9 @@ static int tulip_close (struct net_device *dev)
        tulip_down (dev);
 
        if (tulip_debug > 1)
-               printk (KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n",
-                       dev->name, ioread32 (ioaddr + CSR5));
+               dev_printk(KERN_DEBUG, &dev->dev,
+                          "Shutting down ethercard, status was %02x\n",
+                          ioread32 (ioaddr + CSR5));
 
        free_irq (dev->irq, dev);
 
@@ -1073,10 +1081,10 @@ static void set_rx_mode(struct net_device *dev)
                                filterbit &= 0x3f;
                                mc_filter[filterbit >> 5] |= 1 << (filterbit & 31);
                                if (tulip_debug > 2)
-                                       printk(KERN_INFO "%s: Added filter for %pM"
-                                              "  %8.8x bit %d.\n",
-                                              dev->name, mclist->dmi_addr,
-                                              ether_crc(ETH_ALEN, mclist->dmi_addr), filterbit);
+                                       dev_info(&dev->dev,
+                                                "Added filter for %pM  %08x bit %d\n",
+                                                mclist->dmi_addr,
+                                                ether_crc(ETH_ALEN, mclist->dmi_addr), filterbit);
                        }
                        if (mc_filter[0] == tp->mc_filter[0]  &&
                                mc_filter[1] == tp->mc_filter[1])
@@ -1288,9 +1296,8 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
        unsigned int force_csr0 = 0;
 
 #ifndef MODULE
-       static int did_version;         /* Already printed version info. */
-       if (tulip_debug > 0  &&  did_version++ == 0)
-               printk (KERN_INFO "%s", version);
+       if (tulip_debug > 0)
+               printk_once(KERN_INFO "%s", version);
 #endif
 
        board_idx++;
@@ -1301,7 +1308,7 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
         */
 
         if (pdev->subsystem_vendor == PCI_VENDOR_ID_LMC) {
-               printk (KERN_ERR PFX "skipping LMC card.\n");
+               pr_err(PFX "skipping LMC card\n");
                return -ENODEV;
        }
 
@@ -1317,15 +1324,13 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
 
                if (pdev->vendor == 0x1282 && pdev->device == 0x9100 &&
                    pdev->revision < 0x30) {
-                       printk(KERN_INFO PFX
-                              "skipping early DM9100 with Crc bug (use dmfe)\n");
+                       pr_info(PFX "skipping early DM9100 with Crc bug (use dmfe)\n");
                        return -ENODEV;
                }
 
                dp = pci_device_to_OF_node(pdev);
                if (!(dp && of_get_property(dp, "local-mac-address", NULL))) {
-                       printk(KERN_INFO PFX
-                              "skipping DM910x expansion card (use dmfe)\n");
+                       pr_info(PFX "skipping DM910x expansion card (use dmfe)\n");
                        return -ENODEV;
                }
        }
@@ -1372,9 +1377,8 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
 
        i = pci_enable_device(pdev);
        if (i) {
-               printk (KERN_ERR PFX
-                       "Cannot enable tulip board #%d, aborting\n",
-                       board_idx);
+               pr_err(PFX "Cannot enable tulip board #%d, aborting\n",
+                      board_idx);
                return i;
        }
 
@@ -1383,22 +1387,22 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
        /* alloc_etherdev ensures aligned and zeroed private structures */
        dev = alloc_etherdev (sizeof (*tp));
        if (!dev) {
-               printk (KERN_ERR PFX "ether device alloc failed, aborting\n");
+               pr_err(PFX "ether device alloc failed, aborting\n");
                return -ENOMEM;
        }
 
        SET_NETDEV_DEV(dev, &pdev->dev);
        if (pci_resource_len (pdev, 0) < tulip_tbl[chip_idx].io_size) {
-               printk (KERN_ERR PFX "%s: I/O region (0x%llx@0x%llx) too small, "
-                       "aborting\n", pci_name(pdev),
-                       (unsigned long long)pci_resource_len (pdev, 0),
-                       (unsigned long long)pci_resource_start (pdev, 0));
+               pr_err(PFX "%s: I/O region (0x%llx@0x%llx) too small, aborting\n",
+                      pci_name(pdev),
+                      (unsigned long long)pci_resource_len (pdev, 0),
+                      (unsigned long long)pci_resource_start (pdev, 0));
                goto err_out_free_netdev;
        }
 
        /* grab all resources from both PIO and MMIO regions, as we
         * don't want anyone else messing around with our hardware */
-       if (pci_request_regions (pdev, "tulip"))
+       if (pci_request_regions (pdev, DRV_NAME))
                goto err_out_free_netdev;
 
        ioaddr =  pci_iomap(pdev, TULIP_BAR, tulip_tbl[chip_idx].io_size);
@@ -1611,8 +1615,8 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
        if (dev->mem_start & MEDIA_MASK)
                tp->default_port = dev->mem_start & MEDIA_MASK;
        if (tp->default_port) {
-               printk(KERN_INFO "tulip%d: Transceiver selection forced to %s.\n",
-                      board_idx, medianame[tp->default_port & MEDIA_MASK]);
+               pr_info(DRV_NAME "%d: Transceiver selection forced to %s\n",
+                       board_idx, medianame[tp->default_port & MEDIA_MASK]);
                tp->medialock = 1;
                if (tulip_media_cap[tp->default_port] & MediaAlwaysFD)
                        tp->full_duplex = 1;
@@ -1627,7 +1631,7 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
        }
 
        if (tp->flags & HAS_MEDIA_TABLE) {
-               sprintf(dev->name, "tulip%d", board_idx);       /* hack */
+               sprintf(dev->name, DRV_NAME "%d", board_idx);   /* hack */
                tulip_parse_eeprom(dev);
                strcpy(dev->name, "eth%d");                     /* un-hack */
        }
@@ -1663,20 +1667,18 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
        if (register_netdev(dev))
                goto err_out_free_ring;
 
-       printk(KERN_INFO "%s: %s rev %d at "
+       pci_set_drvdata(pdev, dev);
+
+       dev_info(&dev->dev,
 #ifdef CONFIG_TULIP_MMIO
-               "MMIO"
+                "%s rev %d at MMIO %#llx,%s %pM, IRQ %d\n",
 #else
-               "Port"
+                "%s rev %d at Port %#llx,%s %pM, IRQ %d\n",
 #endif
-               " %#llx,", dev->name, chip_name, pdev->revision,
-               (unsigned long long) pci_resource_start(pdev, TULIP_BAR));
-       pci_set_drvdata(pdev, dev);
-
-       if (eeprom_missing)
-               printk(" EEPROM not present,");
-       printk(" %pM", dev->dev_addr);
-       printk(", IRQ %d.\n", irq);
+                chip_name, pdev->revision,
+                (unsigned long long)pci_resource_start(pdev, TULIP_BAR),
+                eeprom_missing ? " EEPROM not present," : "",
+                dev->dev_addr, irq);
 
         if (tp->chip_id == PNIC2)
                tp->link_change = pnic2_lnk_change;
@@ -1799,12 +1801,12 @@ static int tulip_resume(struct pci_dev *pdev)
                return 0;
 
        if ((retval = pci_enable_device(pdev))) {
-               printk (KERN_ERR "tulip: pci_enable_device failed in resume\n");
+               pr_err(PFX "pci_enable_device failed in resume\n");
                return retval;
        }
 
        if ((retval = request_irq(dev->irq, tulip_interrupt, IRQF_SHARED, dev->name, dev))) {
-               printk (KERN_ERR "tulip: request_irq failed in resume\n");
+               pr_err(PFX "request_irq failed in resume\n");
                return retval;
        }
 
@@ -1874,7 +1876,7 @@ static struct pci_driver tulip_driver = {
 static int __init tulip_init (void)
 {
 #ifdef MODULE
-       printk (KERN_INFO "%s", version);
+       pr_info("%s", version);
 #endif
 
        /* copy module parms into globals */
index fa019cabc355579baa1df2bab18e0ed774c4c65d..dc3335d906f631f5b9b105c76978b6729fea549d 100644 (file)
@@ -12,6 +12,8 @@
 
 */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #define DRV_NAME       "uli526x"
 #define DRV_VERSION    "0.9.3"
 #define DRV_RELDATE    "2005-7-29"
 #define ULI526X_TX_TIMEOUT ((16*HZ)/2) /* tx packet time-out time 8 s" */
 #define ULI526X_TX_KICK        (4*HZ/2)        /* tx packet Kick-out time 2 s" */
 
-#define ULI526X_DBUG(dbug_now, msg, value) if (uli526x_debug || (dbug_now)) printk(KERN_ERR DRV_NAME ": %s %lx\n", (msg), (long) (value))
+#define ULI526X_DBUG(dbug_now, msg, value)                     \
+do {                                                           \
+       if (uli526x_debug || (dbug_now))                        \
+               pr_err("%s %lx\n", (msg), (long) (value));      \
+} while (0)
 
-#define SHOW_MEDIA_TYPE(mode) printk(KERN_ERR DRV_NAME ": Change Speed to %sMhz %s duplex\n",mode & 1 ?"100":"10", mode & 4 ? "full":"half");
+#define SHOW_MEDIA_TYPE(mode)                                  \
+       pr_err("Change Speed to %sMhz %s duplex\n",             \
+              mode & 1 ? "100" : "10",                         \
+              mode & 4 ? "full" : "half");
 
 
 /* CR9 definition: SROM/MII */
@@ -284,7 +293,7 @@ static int __devinit uli526x_init_one (struct pci_dev *pdev,
        SET_NETDEV_DEV(dev, &pdev->dev);
 
        if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) {
-               printk(KERN_WARNING DRV_NAME ": 32-bit PCI DMA not available.\n");
+               pr_warning("32-bit PCI DMA not available\n");
                err = -ENODEV;
                goto err_out_free;
        }
@@ -295,19 +304,19 @@ static int __devinit uli526x_init_one (struct pci_dev *pdev,
                goto err_out_free;
 
        if (!pci_resource_start(pdev, 0)) {
-               printk(KERN_ERR DRV_NAME ": I/O base is zero\n");
+               pr_err("I/O base is zero\n");
                err = -ENODEV;
                goto err_out_disable;
        }
 
        if (pci_resource_len(pdev, 0) < (ULI526X_IO_SIZE) ) {
-               printk(KERN_ERR DRV_NAME ": Allocated I/O size too small\n");
+               pr_err("Allocated I/O size too small\n");
                err = -ENODEV;
                goto err_out_disable;
        }
 
        if (pci_request_regions(pdev, DRV_NAME)) {
-               printk(KERN_ERR DRV_NAME ": Failed to request PCI regions\n");
+               pr_err("Failed to request PCI regions\n");
                err = -ENODEV;
                goto err_out_disable;
        }
@@ -382,9 +391,9 @@ static int __devinit uli526x_init_one (struct pci_dev *pdev,
        if (err)
                goto err_out_res;
 
-       printk(KERN_INFO "%s: ULi M%04lx at pci%s, %pM, irq %d.\n",
-              dev->name,ent->driver_data >> 16,pci_name(pdev),
-              dev->dev_addr, dev->irq);
+       dev_info(&dev->dev, "ULi M%04lx at pci%s, %pM, irq %d\n",
+                ent->driver_data >> 16, pci_name(pdev),
+                dev->dev_addr, dev->irq);
 
        pci_set_master(pdev);
 
@@ -516,7 +525,7 @@ static void uli526x_init(struct net_device *dev)
                }
        }
        if(phy_tmp == 32)
-               printk(KERN_WARNING "Can not find the phy address!!!");
+               pr_warning("Can not find the phy address!!!");
        /* Parser SROM and media mode */
        db->media_mode = uli526x_media_mode;
 
@@ -582,7 +591,7 @@ static netdev_tx_t uli526x_start_xmit(struct sk_buff *skb,
 
        /* Too large packet check */
        if (skb->len > MAX_PACKET_SIZE) {
-               printk(KERN_ERR DRV_NAME ": big packet = %d\n", (u16)skb->len);
+               pr_err("big packet = %d\n", (u16)skb->len);
                dev_kfree_skb(skb);
                return NETDEV_TX_OK;
        }
@@ -592,7 +601,7 @@ static netdev_tx_t uli526x_start_xmit(struct sk_buff *skb,
        /* No Tx resource check, it never happen nromally */
        if (db->tx_packet_cnt >= TX_FREE_DESC_CNT) {
                spin_unlock_irqrestore(&db->lock, flags);
-               printk(KERN_ERR DRV_NAME ": No Tx resource %ld\n", db->tx_packet_cnt);
+               pr_err("No Tx resource %ld\n", db->tx_packet_cnt);
                return NETDEV_TX_BUSY;
        }
 
@@ -1058,7 +1067,7 @@ static void uli526x_timer(unsigned long data)
                /* Link Failed */
                ULI526X_DBUG(0, "Link Failed", tmp_cr12);
                netif_carrier_off(dev);
-               printk(KERN_INFO "uli526x: %s NIC Link is Down\n",dev->name);
+               pr_info("%s NIC Link is Down\n",dev->name);
                db->link_failed = 1;
 
                /* For Force 10/100M Half/Full mode: Enable Auto-Nego mode */
@@ -1090,11 +1099,11 @@ static void uli526x_timer(unsigned long data)
                                }
                                if(db->op_mode==ULI526X_10MFD || db->op_mode==ULI526X_100MFD)
                                {
-                                       printk(KERN_INFO "uli526x: %s NIC Link is Up %d Mbps Full duplex\n",dev->name,TmpSpeed);
+                                       pr_info("%s NIC Link is Up %d Mbps Full duplex\n",dev->name,TmpSpeed);
                                }
                                else
                                {
-                                       printk(KERN_INFO "uli526x: %s NIC Link is Up %d Mbps Half duplex\n",dev->name,TmpSpeed);
+                                       pr_info("%s NIC Link is Up %d Mbps Half duplex\n",dev->name,TmpSpeed);
                                }
                                netif_carrier_on(dev);
                        }
@@ -1104,7 +1113,7 @@ static void uli526x_timer(unsigned long data)
                {
                        if(db->init==1)
                        {
-                               printk(KERN_INFO "uli526x: %s NIC Link is Down\n",dev->name);
+                               pr_info("%s NIC Link is Down\n",dev->name);
                                netif_carrier_off(dev);
                        }
                }
@@ -1230,8 +1239,7 @@ static int uli526x_resume(struct pci_dev *pdev)
 
        err = pci_set_power_state(pdev, PCI_D0);
        if (err) {
-               printk(KERN_WARNING "%s: Could not put device into D0\n",
-                       dev->name);
+               dev_warn(&dev->dev, "Could not put device into D0\n");
                return err;
        }
 
@@ -1432,7 +1440,7 @@ static void send_filter_frame(struct net_device *dev, int mc_cnt)
                update_cr6(db->cr6_data, dev->base_addr);
                dev->trans_start = jiffies;
        } else
-               printk(KERN_ERR DRV_NAME ": No Tx resource - Send_filter_frame!\n");
+               pr_err("No Tx resource - Send_filter_frame!\n");
 }
 
 
@@ -1783,7 +1791,7 @@ static u16 phy_read_1bit(unsigned long ioaddr, u32 chip_id)
 }
 
 
-static struct pci_device_id uli526x_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(uli526x_pci_tbl) = {
        { 0x10B9, 0x5261, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_ULI5261_ID },
        { 0x10B9, 0x5263, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_ULI5263_ID },
        { 0, }
index 869a7a0005f9a152d34420da0b3343c3e8606fc6..9fb89afccf7cdad56fabe37eec8d6abda7dfadeb 100644 (file)
@@ -218,7 +218,7 @@ enum chip_capability_flags {
        CanHaveMII=1, HasBrokenTx=2, AlwaysFDX=4, FDXOnNoMII=8,
 };
 
-static const struct pci_device_id w840_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(w840_pci_tbl) = {
        { 0x1050, 0x0840, PCI_ANY_ID, 0x8153,     0, 0, 0 },
        { 0x1050, 0x0840, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 },
        { 0x11f6, 0x2011, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2 },
@@ -376,8 +376,8 @@ static int __devinit w840_probe1 (struct pci_dev *pdev,
        irq = pdev->irq;
 
        if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) {
-               printk(KERN_WARNING "Winbond-840: Device %s disabled due to DMA limitations.\n",
-                      pci_name(pdev));
+               pr_warning("Winbond-840: Device %s disabled due to DMA limitations\n",
+                          pci_name(pdev));
                return -EIO;
        }
        dev = alloc_etherdev(sizeof(*np));
@@ -422,8 +422,9 @@ static int __devinit w840_probe1 (struct pci_dev *pdev,
                if (option & 0x200)
                        np->mii_if.full_duplex = 1;
                if (option & 15)
-                       printk(KERN_INFO "%s: ignoring user supplied media type %d",
-                               dev->name, option & 15);
+                       dev_info(&dev->dev,
+                                "ignoring user supplied media type %d",
+                                option & 15);
        }
        if (find_cnt < MAX_UNITS  &&  full_duplex[find_cnt] > 0)
                np->mii_if.full_duplex = 1;
@@ -440,9 +441,8 @@ static int __devinit w840_probe1 (struct pci_dev *pdev,
        if (i)
                goto err_out_cleardev;
 
-       printk(KERN_INFO "%s: %s at %p, %pM, IRQ %d.\n",
-              dev->name, pci_id_tbl[chip_idx].name, ioaddr,
-              dev->dev_addr, irq);
+       dev_info(&dev->dev, "%s at %p, %pM, IRQ %d\n",
+                pci_id_tbl[chip_idx].name, ioaddr, dev->dev_addr, irq);
 
        if (np->drv_flags & CanHaveMII) {
                int phy, phy_idx = 0;
@@ -453,16 +453,17 @@ static int __devinit w840_probe1 (struct pci_dev *pdev,
                                np->mii_if.advertising = mdio_read(dev, phy, MII_ADVERTISE);
                                np->mii = (mdio_read(dev, phy, MII_PHYSID1) << 16)+
                                                mdio_read(dev, phy, MII_PHYSID2);
-                               printk(KERN_INFO "%s: MII PHY %8.8xh found at address %d, status "
-                                          "0x%4.4x advertising %4.4x.\n",
-                                          dev->name, np->mii, phy, mii_status, np->mii_if.advertising);
+                               dev_info(&dev->dev,
+                                        "MII PHY %08xh found at address %d, status 0x%04x advertising %04x\n",
+                                        np->mii, phy, mii_status,
+                                        np->mii_if.advertising);
                        }
                }
                np->mii_cnt = phy_idx;
                np->mii_if.phy_id = np->phys[0];
                if (phy_idx == 0) {
-                               printk(KERN_WARNING "%s: MII PHY not found -- this device may "
-                                          "not operate correctly.\n", dev->name);
+                       dev_warn(&dev->dev,
+                                "MII PHY not found -- this device may not operate correctly\n");
                }
        }
 
@@ -644,8 +645,8 @@ static int netdev_open(struct net_device *dev)
                goto out_err;
 
        if (debug > 1)
-               printk(KERN_DEBUG "%s: w89c840_open() irq %d.\n",
-                          dev->name, dev->irq);
+               printk(KERN_DEBUG "%s: w89c840_open() irq %d\n",
+                      dev->name, dev->irq);
 
        if((i=alloc_ringdesc(dev)))
                goto out_err;
@@ -657,7 +658,7 @@ static int netdev_open(struct net_device *dev)
 
        netif_start_queue(dev);
        if (debug > 2)
-               printk(KERN_DEBUG "%s: Done netdev_open().\n", dev->name);
+               printk(KERN_DEBUG "%s: Done netdev_open()\n", dev->name);
 
        /* Set the timer to check for link beat. */
        init_timer(&np->timer);
@@ -688,16 +689,18 @@ static int update_link(struct net_device *dev)
        if (!(mii_reg & 0x4)) {
                if (netif_carrier_ok(dev)) {
                        if (debug)
-                               printk(KERN_INFO "%s: MII #%d reports no link. Disabling watchdog.\n",
-                                       dev->name, np->phys[0]);
+                               dev_info(&dev->dev,
+                                        "MII #%d reports no link. Disabling watchdog\n",
+                                        np->phys[0]);
                        netif_carrier_off(dev);
                }
                return np->csr6;
        }
        if (!netif_carrier_ok(dev)) {
                if (debug)
-                       printk(KERN_INFO "%s: MII #%d link is back. Enabling watchdog.\n",
-                               dev->name, np->phys[0]);
+                       dev_info(&dev->dev,
+                                "MII #%d link is back. Enabling watchdog\n",
+                                np->phys[0]);
                netif_carrier_on(dev);
        }
 
@@ -729,9 +732,10 @@ static int update_link(struct net_device *dev)
        if (fasteth)
                result |= 0x20000000;
        if (result != np->csr6 && debug)
-               printk(KERN_INFO "%s: Setting %dMBit-%s-duplex based on MII#%d\n",
-                                dev->name, fasteth ? 100 : 10,
-                               duplex ? "full" : "half", np->phys[0]);
+               dev_info(&dev->dev,
+                        "Setting %dMBit-%s-duplex based on MII#%d\n",
+                        fasteth ? 100 : 10, duplex ? "full" : "half",
+                        np->phys[0]);
        return result;
 }
 
@@ -763,8 +767,8 @@ static inline void update_csr6(struct net_device *dev, int new)
 
                limit--;
                if(!limit) {
-                       printk(KERN_INFO "%s: couldn't stop rxtx, IntrStatus %xh.\n",
-                                       dev->name, csr5);
+                       dev_info(&dev->dev,
+                                "couldn't stop rxtx, IntrStatus %xh\n", csr5);
                        break;
                }
                udelay(1);
@@ -783,10 +787,9 @@ static void netdev_timer(unsigned long data)
        void __iomem *ioaddr = np->base_addr;
 
        if (debug > 2)
-               printk(KERN_DEBUG "%s: Media selection timer tick, status %8.8x "
-                          "config %8.8x.\n",
-                          dev->name, ioread32(ioaddr + IntrStatus),
-                          ioread32(ioaddr + NetworkConfig));
+               printk(KERN_DEBUG "%s: Media selection timer tick, status %08x config %08x\n",
+                      dev->name, ioread32(ioaddr + IntrStatus),
+                      ioread32(ioaddr + NetworkConfig));
        spin_lock_irq(&np->lock);
        update_csr6(dev, update_link(dev));
        spin_unlock_irq(&np->lock);
@@ -899,8 +902,8 @@ static void init_registers(struct net_device *dev)
        /* When not a module we can work around broken '486 PCI boards. */
        if (boot_cpu_data.x86 <= 4) {
                i |= 0x4800;
-               printk(KERN_INFO "%s: This is a 386/486 PCI system, setting cache "
-                          "alignment to 8 longwords.\n", dev->name);
+               dev_info(&dev->dev,
+                        "This is a 386/486 PCI system, setting cache alignment to 8 longwords\n");
        } else {
                i |= 0xE000;
        }
@@ -931,22 +934,23 @@ static void tx_timeout(struct net_device *dev)
        struct netdev_private *np = netdev_priv(dev);
        void __iomem *ioaddr = np->base_addr;
 
-       printk(KERN_WARNING "%s: Transmit timed out, status %8.8x,"
-                  " resetting...\n", dev->name, ioread32(ioaddr + IntrStatus));
+       dev_warn(&dev->dev, "Transmit timed out, status %08x, resetting...\n",
+                ioread32(ioaddr + IntrStatus));
 
        {
                int i;
                printk(KERN_DEBUG "  Rx ring %p: ", np->rx_ring);
                for (i = 0; i < RX_RING_SIZE; i++)
-                       printk(" %8.8x", (unsigned int)np->rx_ring[i].status);
-               printk(KERN_DEBUG"  Tx ring %p: ", np->tx_ring);
+                       printk(KERN_CONT " %08x", (unsigned int)np->rx_ring[i].status);
+               printk(KERN_CONT "\n");
+               printk(KERN_DEBUG "  Tx ring %p: ", np->tx_ring);
                for (i = 0; i < TX_RING_SIZE; i++)
-                       printk(" %8.8x", np->tx_ring[i].status);
-               printk("\n");
+                       printk(KERN_CONT " %08x", np->tx_ring[i].status);
+               printk(KERN_CONT "\n");
        }
-       printk(KERN_DEBUG "Tx cur %d Tx dirty %d Tx Full %d, q bytes %d.\n",
-                               np->cur_tx, np->dirty_tx, np->tx_full, np->tx_q_bytes);
-       printk(KERN_DEBUG "Tx Descriptor addr %xh.\n",ioread32(ioaddr+0x4C));
+       printk(KERN_DEBUG "Tx cur %d Tx dirty %d Tx Full %d, q bytes %d\n",
+              np->cur_tx, np->dirty_tx, np->tx_full, np->tx_q_bytes);
+       printk(KERN_DEBUG "Tx Descriptor addr %xh\n", ioread32(ioaddr+0x4C));
 
        disable_irq(dev->irq);
        spin_lock_irq(&np->lock);
@@ -1055,8 +1059,8 @@ static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev)
        dev->trans_start = jiffies;
 
        if (debug > 4) {
-               printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n",
-                          dev->name, np->cur_tx, entry);
+               printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d\n",
+                      dev->name, np->cur_tx, entry);
        }
        return NETDEV_TX_OK;
 }
@@ -1073,8 +1077,8 @@ static void netdev_tx_done(struct net_device *dev)
                if (tx_status & 0x8000) {       /* There was an error, log it. */
 #ifndef final_version
                        if (debug > 1)
-                               printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n",
-                                          dev->name, tx_status);
+                               printk(KERN_DEBUG "%s: Transmit error, Tx status %08x\n",
+                                      dev->name, tx_status);
 #endif
                        np->stats.tx_errors++;
                        if (tx_status & 0x0104) np->stats.tx_aborted_errors++;
@@ -1086,8 +1090,8 @@ static void netdev_tx_done(struct net_device *dev)
                } else {
 #ifndef final_version
                        if (debug > 3)
-                               printk(KERN_DEBUG "%s: Transmit slot %d ok, Tx status %8.8x.\n",
-                                          dev->name, entry, tx_status);
+                               printk(KERN_DEBUG "%s: Transmit slot %d ok, Tx status %08x\n",
+                                      dev->name, entry, tx_status);
 #endif
                        np->stats.tx_bytes += np->tx_skbuff[entry]->len;
                        np->stats.collisions += (tx_status >> 3) & 15;
@@ -1130,8 +1134,8 @@ static irqreturn_t intr_handler(int irq, void *dev_instance)
                iowrite32(intr_status & 0x001ffff, ioaddr + IntrStatus);
 
                if (debug > 4)
-                       printk(KERN_DEBUG "%s: Interrupt, status %4.4x.\n",
-                                  dev->name, intr_status);
+                       printk(KERN_DEBUG "%s: Interrupt, status %04x\n",
+                              dev->name, intr_status);
 
                if ((intr_status & (NormalIntr|AbnormalIntr)) == 0)
                        break;
@@ -1156,8 +1160,9 @@ static irqreturn_t intr_handler(int irq, void *dev_instance)
                        netdev_error(dev, intr_status);
 
                if (--work_limit < 0) {
-                       printk(KERN_WARNING "%s: Too much work at interrupt, "
-                                  "status=0x%4.4x.\n", dev->name, intr_status);
+                       dev_warn(&dev->dev,
+                                "Too much work at interrupt, status=0x%04x\n",
+                                intr_status);
                        /* Set the timer to re-enable the other interrupts after
                           10*82usec ticks. */
                        spin_lock(&np->lock);
@@ -1171,8 +1176,8 @@ static irqreturn_t intr_handler(int irq, void *dev_instance)
        } while (1);
 
        if (debug > 3)
-               printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",
-                          dev->name, ioread32(ioaddr + IntrStatus));
+               printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x\n",
+                      dev->name, ioread32(ioaddr + IntrStatus));
        return IRQ_RETVAL(handled);
 }
 
@@ -1185,8 +1190,8 @@ static int netdev_rx(struct net_device *dev)
        int work_limit = np->dirty_rx + RX_RING_SIZE - np->cur_rx;
 
        if (debug > 4) {
-               printk(KERN_DEBUG " In netdev_rx(), entry %d status %4.4x.\n",
-                          entry, np->rx_ring[entry].status);
+               printk(KERN_DEBUG " In netdev_rx(), entry %d status %04x\n",
+                      entry, np->rx_ring[entry].status);
        }
 
        /* If EOP is set on the next entry, it's a new packet. Send it up. */
@@ -1195,24 +1200,24 @@ static int netdev_rx(struct net_device *dev)
                s32 status = desc->status;
 
                if (debug > 4)
-                       printk(KERN_DEBUG "  netdev_rx() status was %8.8x.\n",
-                                  status);
+                       printk(KERN_DEBUG "  netdev_rx() status was %08x\n",
+                              status);
                if (status < 0)
                        break;
                if ((status & 0x38008300) != 0x0300) {
                        if ((status & 0x38000300) != 0x0300) {
                                /* Ingore earlier buffers. */
                                if ((status & 0xffff) != 0x7fff) {
-                                       printk(KERN_WARNING "%s: Oversized Ethernet frame spanned "
-                                                  "multiple buffers, entry %#x status %4.4x!\n",
-                                                  dev->name, np->cur_rx, status);
+                                       dev_warn(&dev->dev,
+                                                "Oversized Ethernet frame spanned multiple buffers, entry %#x status %04x!\n",
+                                                np->cur_rx, status);
                                        np->stats.rx_length_errors++;
                                }
                        } else if (status & 0x8000) {
                                /* There was a fatal error. */
                                if (debug > 2)
-                                       printk(KERN_DEBUG "%s: Receive error, Rx status %8.8x.\n",
-                                                  dev->name, status);
+                                       printk(KERN_DEBUG "%s: Receive error, Rx status %08x\n",
+                                              dev->name, status);
                                np->stats.rx_errors++; /* end of a packet.*/
                                if (status & 0x0890) np->stats.rx_length_errors++;
                                if (status & 0x004C) np->stats.rx_frame_errors++;
@@ -1225,8 +1230,8 @@ static int netdev_rx(struct net_device *dev)
 
 #ifndef final_version
                        if (debug > 4)
-                               printk(KERN_DEBUG "  netdev_rx() normal Rx pkt length %d"
-                                          " status %x.\n", pkt_len, status);
+                               printk(KERN_DEBUG "  netdev_rx() normal Rx pkt length %d status %x\n",
+                                      pkt_len, status);
 #endif
                        /* Check if the packet is long enough to accept without copying
                           to a minimally-sized skbuff. */
@@ -1251,11 +1256,10 @@ static int netdev_rx(struct net_device *dev)
 #ifndef final_version                          /* Remove after testing. */
                        /* You will want this info for the initial debug. */
                        if (debug > 5)
-                               printk(KERN_DEBUG "  Rx data %pM %pM"
-                                      " %2.2x%2.2x %d.%d.%d.%d.\n",
+                               printk(KERN_DEBUG "  Rx data %pM %pM %02x%02x %pI4\n",
                                       &skb->data[0], &skb->data[6],
                                       skb->data[12], skb->data[13],
-                                      skb->data[14], skb->data[15], skb->data[16], skb->data[17]);
+                                      &skb->data[14]);
 #endif
                        skb->protocol = eth_type_trans(skb, dev);
                        netif_rx(skb);
@@ -1293,8 +1297,8 @@ static void netdev_error(struct net_device *dev, int intr_status)
        void __iomem *ioaddr = np->base_addr;
 
        if (debug > 2)
-               printk(KERN_DEBUG "%s: Abnormal event, %8.8x.\n",
-                          dev->name, intr_status);
+               printk(KERN_DEBUG "%s: Abnormal event, %08x\n",
+                      dev->name, intr_status);
        if (intr_status == 0xffffffff)
                return;
        spin_lock(&np->lock);
@@ -1314,8 +1318,8 @@ static void netdev_error(struct net_device *dev, int intr_status)
                        new = 127; /* load full packet before starting */
                new = (np->csr6 & ~(0x7F << 14)) | (new<<14);
 #endif
-               printk(KERN_DEBUG "%s: Tx underflow, new csr6 %8.8x.\n",
-                          dev->name, new);
+               printk(KERN_DEBUG "%s: Tx underflow, new csr6 %08x\n",
+                      dev->name, new);
                update_csr6(dev, new);
        }
        if (intr_status & RxDied) {             /* Missed a Rx frame. */
@@ -1487,11 +1491,13 @@ static int netdev_close(struct net_device *dev)
        netif_stop_queue(dev);
 
        if (debug > 1) {
-               printk(KERN_DEBUG "%s: Shutting down ethercard, status was %8.8x "
-                          "Config %8.8x.\n", dev->name, ioread32(ioaddr + IntrStatus),
-                          ioread32(ioaddr + NetworkConfig));
-               printk(KERN_DEBUG "%s: Queue pointers were Tx %d / %d,  Rx %d / %d.\n",
-                          dev->name, np->cur_tx, np->dirty_tx, np->cur_rx, np->dirty_rx);
+               printk(KERN_DEBUG "%s: Shutting down ethercard, status was %08x Config %08x\n",
+                      dev->name, ioread32(ioaddr + IntrStatus),
+                      ioread32(ioaddr + NetworkConfig));
+               printk(KERN_DEBUG "%s: Queue pointers were Tx %d / %d,  Rx %d / %d\n",
+                      dev->name,
+                      np->cur_tx, np->dirty_tx,
+                      np->cur_rx, np->dirty_rx);
        }
 
        /* Stop the chip's Tx and Rx processes. */
@@ -1512,18 +1518,16 @@ static int netdev_close(struct net_device *dev)
        if (debug > 2) {
                int i;
 
-               printk(KERN_DEBUG"  Tx ring at %8.8x:\n",
-                          (int)np->tx_ring);
+               printk(KERN_DEBUG"  Tx ring at %08x:\n", (int)np->tx_ring);
                for (i = 0; i < TX_RING_SIZE; i++)
-                       printk(KERN_DEBUG " #%d desc. %4.4x %4.4x %8.8x.\n",
-                                  i, np->tx_ring[i].length,
-                                  np->tx_ring[i].status, np->tx_ring[i].buffer1);
-               printk(KERN_DEBUG "  Rx ring %8.8x:\n",
-                          (int)np->rx_ring);
+                       printk(KERN_DEBUG " #%d desc. %04x %04x %08x\n",
+                              i, np->tx_ring[i].length,
+                              np->tx_ring[i].status, np->tx_ring[i].buffer1);
+               printk(KERN_DEBUG "  Rx ring %08x:\n", (int)np->rx_ring);
                for (i = 0; i < RX_RING_SIZE; i++) {
-                       printk(KERN_DEBUG " #%d desc. %4.4x %4.4x %8.8x\n",
-                                  i, np->rx_ring[i].length,
-                                  np->rx_ring[i].status, np->rx_ring[i].buffer1);
+                       printk(KERN_DEBUG " #%d desc. %04x %04x %08x\n",
+                              i, np->rx_ring[i].length,
+                              np->rx_ring[i].status, np->rx_ring[i].buffer1);
                }
        }
 #endif /* __i386__ debugging only */
@@ -1622,9 +1626,8 @@ static int w840_resume (struct pci_dev *pdev)
                goto out; /* device not suspended */
        if (netif_running(dev)) {
                if ((retval = pci_enable_device(pdev))) {
-                       printk (KERN_ERR
-                               "%s: pci_enable_device failed in resume\n",
-                               dev->name);
+                       dev_err(&dev->dev,
+                               "pci_enable_device failed in resume\n");
                        goto out;
                }
                spin_lock_irq(&np->lock);
index 9924c4c7e2d6b0b47fa1474b38e513d556f9aa18..acfeeb980562d9a72df7f21f3e50c82be0f7280b 100644 (file)
@@ -14,6 +14,8 @@
  *     $Id: xircom_cb.c,v 1.33 2001/03/19 14:02:07 arjanv Exp $
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
@@ -144,7 +146,7 @@ static int link_status(struct xircom_private *card);
 
 
 
-static struct pci_device_id xircom_pci_table[] = {
+static DEFINE_PCI_DEVICE_TABLE(xircom_pci_table) = {
        {0x115D, 0x0003, PCI_ANY_ID, PCI_ANY_ID,},
        {0,},
 };
@@ -234,7 +236,7 @@ static int __devinit xircom_probe(struct pci_dev *pdev, const struct pci_device_
        pci_write_config_word (pdev, PCI_STATUS,tmp16);
 
        if (!request_region(pci_resource_start(pdev, 0), 128, "xircom_cb")) {
-               printk(KERN_ERR "xircom_probe: failed to allocate io-region\n");
+               pr_err("%s: failed to allocate io-region\n", __func__);
                return -ENODEV;
        }
 
@@ -245,7 +247,7 @@ static int __devinit xircom_probe(struct pci_dev *pdev, const struct pci_device_
         */
        dev = alloc_etherdev(sizeof(struct xircom_private));
        if (!dev) {
-               printk(KERN_ERR "xircom_probe: failed to allocate etherdev\n");
+               pr_err("%s: failed to allocate etherdev\n", __func__);
                goto device_fail;
        }
        private = netdev_priv(dev);
@@ -253,12 +255,12 @@ static int __devinit xircom_probe(struct pci_dev *pdev, const struct pci_device_
        /* Allocate the send/receive buffers */
        private->rx_buffer = pci_alloc_consistent(pdev,8192,&private->rx_dma_handle);
        if (private->rx_buffer == NULL) {
-               printk(KERN_ERR "xircom_probe: no memory for rx buffer \n");
+               pr_err("%s: no memory for rx buffer\n", __func__);
                goto rx_buf_fail;
        }
        private->tx_buffer = pci_alloc_consistent(pdev,8192,&private->tx_dma_handle);
        if (private->tx_buffer == NULL) {
-               printk(KERN_ERR "xircom_probe: no memory for tx buffer \n");
+               pr_err("%s: no memory for tx buffer\n", __func__);
                goto tx_buf_fail;
        }
 
@@ -281,11 +283,12 @@ static int __devinit xircom_probe(struct pci_dev *pdev, const struct pci_device_
        pci_set_drvdata(pdev, dev);
 
        if (register_netdev(dev)) {
-               printk(KERN_ERR "xircom_probe: netdevice registration failed.\n");
+               pr_err("%s: netdevice registration failed\n", __func__);
                goto reg_fail;
        }
 
-       printk(KERN_INFO "%s: Xircom cardbus revision %i at irq %i \n", dev->name, pdev->revision, pdev->irq);
+       dev_info(&dev->dev, "Xircom cardbus revision %i at irq %i\n",
+                pdev->revision, pdev->irq);
        /* start the transmitter to get a heartbeat */
        /* TODO: send 2 dummy packets here */
        transceiver_voodoo(private);
@@ -347,8 +350,10 @@ static irqreturn_t xircom_interrupt(int irq, void *dev_instance)
 
 #ifdef DEBUG
        print_binary(status);
-       printk("tx status 0x%08x 0x%08x \n",card->tx_buffer[0],card->tx_buffer[4]);
-       printk("rx status 0x%08x 0x%08x \n",card->rx_buffer[0],card->rx_buffer[4]);
+       printk("tx status 0x%08x 0x%08x \n",
+              card->tx_buffer[0], card->tx_buffer[4]);
+       printk("rx status 0x%08x 0x%08x \n",
+              card->rx_buffer[0], card->rx_buffer[4]);
 #endif
        /* Handle shared irq and hotplug */
        if (status == 0 || status == 0xffffffff) {
@@ -358,9 +363,9 @@ static irqreturn_t xircom_interrupt(int irq, void *dev_instance)
 
        if (link_status_changed(card)) {
                int newlink;
-               printk(KERN_DEBUG "xircom_cb: Link status has changed \n");
+               printk(KERN_DEBUG "xircom_cb: Link status has changed\n");
                newlink = link_status(card);
-               printk(KERN_INFO  "xircom_cb: Link is %i mbit \n",newlink);
+               dev_info(&dev->dev, "Link is %i mbit\n", newlink);
                if (newlink)
                        netif_carrier_on(dev);
                else
@@ -457,7 +462,8 @@ static int xircom_open(struct net_device *dev)
        struct xircom_private *xp = netdev_priv(dev);
        int retval;
        enter("xircom_open");
-       printk(KERN_INFO "xircom cardbus adaptor found, registering as %s, using irq %i \n",dev->name,dev->irq);
+       pr_info("xircom cardbus adaptor found, registering as %s, using irq %i \n",
+               dev->name, dev->irq);
        retval = request_irq(dev->irq, xircom_interrupt, IRQF_SHARED, dev->name, dev);
        if (retval) {
                leave("xircom_open - No IRQ");
@@ -770,7 +776,7 @@ static void activate_receiver(struct xircom_private *card)
                udelay(50);
                counter--;
                if (counter <= 0)
-                       printk(KERN_ERR "xircom_cb: Receiver failed to deactivate\n");
+                       pr_err("Receiver failed to deactivate\n");
        }
 
        /* enable the receiver */
@@ -787,7 +793,7 @@ static void activate_receiver(struct xircom_private *card)
                udelay(50);
                counter--;
                if (counter <= 0)
-                       printk(KERN_ERR "xircom_cb: Receiver failed to re-activate\n");
+                       pr_err("Receiver failed to re-activate\n");
        }
 
        leave("activate_receiver");
@@ -818,7 +824,7 @@ static void deactivate_receiver(struct xircom_private *card)
                udelay(50);
                counter--;
                if (counter <= 0)
-                       printk(KERN_ERR "xircom_cb: Receiver failed to deactivate\n");
+                       pr_err("Receiver failed to deactivate\n");
        }
 
 
@@ -861,7 +867,7 @@ static void activate_transmitter(struct xircom_private *card)
                udelay(50);
                counter--;
                if (counter <= 0)
-                       printk(KERN_ERR "xircom_cb: Transmitter failed to deactivate\n");
+                       pr_err("Transmitter failed to deactivate\n");
        }
 
        /* enable the transmitter */
@@ -878,7 +884,7 @@ static void activate_transmitter(struct xircom_private *card)
                udelay(50);
                counter--;
                if (counter <= 0)
-                       printk(KERN_ERR "xircom_cb: Transmitter failed to re-activate\n");
+                       pr_err("Transmitter failed to re-activate\n");
        }
 
        leave("activate_transmitter");
@@ -909,7 +915,7 @@ static void deactivate_transmitter(struct xircom_private *card)
                udelay(50);
                counter--;
                if (counter <= 0)
-                       printk(KERN_ERR "xircom_cb: Transmitter failed to deactivate\n");
+                       pr_err("Transmitter failed to deactivate\n");
        }
 
 
@@ -1184,7 +1190,7 @@ static void investigate_read_descriptor(struct net_device *dev,struct xircom_pri
                        struct sk_buff *skb;
 
                        if (pkt_len > 1518) {
-                               printk(KERN_ERR "xircom_cb: Packet length %i is bogus \n",pkt_len);
+                               pr_err("Packet length %i is bogus\n", pkt_len);
                                pkt_len = 1518;
                        }
 
@@ -1222,7 +1228,7 @@ static void investigate_write_descriptor(struct net_device *dev, struct xircom_p
                status = le32_to_cpu(card->tx_buffer[4*descnr]);
 #if 0
                if (status & 0x8000) {  /* Major error */
-                       printk(KERN_ERR "Major transmit error status %x \n", status);
+                       pr_err("Major transmit error status %x\n", status);
                        card->tx_buffer[4*descnr] = 0;
                        netif_wake_queue (dev);
                }
index 2834a01bae24a9d3e410f342a291b160b43cee02..5adb3d150552e0c6f792755edff973fd69306cd1 100644 (file)
@@ -144,6 +144,7 @@ static int tun_attach(struct tun_struct *tun, struct file *file)
        err = 0;
        tfile->tun = tun;
        tun->tfile = tfile;
+       tun->socket.file = file;
        dev_hold(tun->dev);
        sock_hold(tun->socket.sk);
        atomic_inc(&tfile->count);
@@ -158,6 +159,7 @@ static void __tun_detach(struct tun_struct *tun)
        /* Detach from net device */
        netif_tx_lock_bh(tun->dev);
        tun->tfile = NULL;
+       tun->socket.file = NULL;
        netif_tx_unlock_bh(tun->dev);
 
        /* Drop read queue */
@@ -387,7 +389,8 @@ static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev)
        /* Notify and wake up reader process */
        if (tun->flags & TUN_FASYNC)
                kill_fasync(&tun->fasync, SIGIO, POLL_IN);
-       wake_up_interruptible(&tun->socket.wait);
+       wake_up_interruptible_poll(&tun->socket.wait, POLLIN |
+                                  POLLRDNORM | POLLRDBAND);
        return NETDEV_TX_OK;
 
 drop:
@@ -743,7 +746,7 @@ static __inline__ ssize_t tun_put_user(struct tun_struct *tun,
        len = min_t(int, skb->len, len);
 
        skb_copy_datagram_const_iovec(skb, 0, iv, total, len);
-       total += len;
+       total += skb->len;
 
        tun->dev->stats.tx_packets++;
        tun->dev->stats.tx_bytes += len;
@@ -751,34 +754,23 @@ static __inline__ ssize_t tun_put_user(struct tun_struct *tun,
        return total;
 }
 
-static ssize_t tun_chr_aio_read(struct kiocb *iocb, const struct iovec *iv,
-                           unsigned long count, loff_t pos)
+static ssize_t tun_do_read(struct tun_struct *tun,
+                          struct kiocb *iocb, const struct iovec *iv,
+                          ssize_t len, int noblock)
 {
-       struct file *file = iocb->ki_filp;
-       struct tun_file *tfile = file->private_data;
-       struct tun_struct *tun = __tun_get(tfile);
        DECLARE_WAITQUEUE(wait, current);
        struct sk_buff *skb;
-       ssize_t len, ret = 0;
-
-       if (!tun)
-               return -EBADFD;
+       ssize_t ret = 0;
 
        DBG(KERN_INFO "%s: tun_chr_read\n", tun->dev->name);
 
-       len = iov_length(iv, count);
-       if (len < 0) {
-               ret = -EINVAL;
-               goto out;
-       }
-
        add_wait_queue(&tun->socket.wait, &wait);
        while (len) {
                current->state = TASK_INTERRUPTIBLE;
 
                /* Read frames from the queue */
                if (!(skb=skb_dequeue(&tun->socket.sk->sk_receive_queue))) {
-                       if (file->f_flags & O_NONBLOCK) {
+                       if (noblock) {
                                ret = -EAGAIN;
                                break;
                        }
@@ -805,6 +797,27 @@ static ssize_t tun_chr_aio_read(struct kiocb *iocb, const struct iovec *iv,
        current->state = TASK_RUNNING;
        remove_wait_queue(&tun->socket.wait, &wait);
 
+       return ret;
+}
+
+static ssize_t tun_chr_aio_read(struct kiocb *iocb, const struct iovec *iv,
+                           unsigned long count, loff_t pos)
+{
+       struct file *file = iocb->ki_filp;
+       struct tun_file *tfile = file->private_data;
+       struct tun_struct *tun = __tun_get(tfile);
+       ssize_t len, ret;
+
+       if (!tun)
+               return -EBADFD;
+       len = iov_length(iv, count);
+       if (len < 0) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       ret = tun_do_read(tun, iocb, iv, len, file->f_flags & O_NONBLOCK);
+       ret = min_t(ssize_t, ret, len);
 out:
        tun_put(tun);
        return ret;
@@ -847,7 +860,8 @@ static void tun_sock_write_space(struct sock *sk)
                return;
 
        if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
-               wake_up_interruptible_sync(sk->sk_sleep);
+               wake_up_interruptible_sync_poll(sk->sk_sleep, POLLOUT |
+                                               POLLWRNORM | POLLWRBAND);
 
        tun = tun_sk(sk)->tun;
        kill_fasync(&tun->fasync, SIGIO, POLL_OUT);
@@ -858,6 +872,37 @@ static void tun_sock_destruct(struct sock *sk)
        free_netdev(tun_sk(sk)->tun->dev);
 }
 
+static int tun_sendmsg(struct kiocb *iocb, struct socket *sock,
+                      struct msghdr *m, size_t total_len)
+{
+       struct tun_struct *tun = container_of(sock, struct tun_struct, socket);
+       return tun_get_user(tun, m->msg_iov, total_len,
+                           m->msg_flags & MSG_DONTWAIT);
+}
+
+static int tun_recvmsg(struct kiocb *iocb, struct socket *sock,
+                      struct msghdr *m, size_t total_len,
+                      int flags)
+{
+       struct tun_struct *tun = container_of(sock, struct tun_struct, socket);
+       int ret;
+       if (flags & ~(MSG_DONTWAIT|MSG_TRUNC))
+               return -EINVAL;
+       ret = tun_do_read(tun, iocb, m->msg_iov, total_len,
+                         flags & MSG_DONTWAIT);
+       if (ret > total_len) {
+               m->msg_flags |= MSG_TRUNC;
+               ret = flags & MSG_TRUNC ? ret : total_len;
+       }
+       return ret;
+}
+
+/* Ops structure to mimic raw sockets with tun */
+static const struct proto_ops tun_socket_ops = {
+       .sendmsg = tun_sendmsg,
+       .recvmsg = tun_recvmsg,
+};
+
 static struct proto tun_proto = {
        .name           = "tun",
        .owner          = THIS_MODULE,
@@ -986,6 +1031,7 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
                        goto err_free_dev;
 
                init_waitqueue_head(&tun->socket.wait);
+               tun->socket.ops = &tun_socket_ops;
                sock_init_data(&tun->socket, sk);
                sk->sk_write_space = tun_sock_write_space;
                sk->sk_sndbuf = INT_MAX;
@@ -1525,6 +1571,23 @@ static void tun_cleanup(void)
        rtnl_link_unregister(&tun_link_ops);
 }
 
+/* Get an underlying socket object from tun file.  Returns error unless file is
+ * attached to a device.  The returned object works like a packet socket, it
+ * can be used for sock_sendmsg/sock_recvmsg.  The caller is responsible for
+ * holding a reference to the file for as long as the socket is in use. */
+struct socket *tun_get_socket(struct file *file)
+{
+       struct tun_struct *tun;
+       if (file->f_op != &tun_fops)
+               return ERR_PTR(-EINVAL);
+       tun = tun_get(file);
+       if (!tun)
+               return ERR_PTR(-EBADFD);
+       tun_put(tun);
+       return &tun->socket;
+}
+EXPORT_SYMBOL_GPL(tun_get_socket);
+
 module_init(tun_init);
 module_exit(tun_cleanup);
 MODULE_DESCRIPTION(DRV_DESCRIPTION);
index 39f1fc650be622dcf8306656ab3fa3027cf4476b..6e4f754c4baf8d4710cda56711597b676f421d77 100644 (file)
@@ -215,7 +215,7 @@ static struct typhoon_card_info typhoon_card_info[] __devinitdata = {
  * bit 8 indicates if this is a (0) copper or (1) fiber card
  * bits 12-16 indicate card type: (0) client and (1) server
  */
-static struct pci_device_id typhoon_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(typhoon_pci_tbl) = {
        { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3CR990,
          PCI_ANY_ID, PCI_ANY_ID, 0, 0,TYPHOON_TX },
        { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3CR990_TX_95,
index eb8fe7e16c6cdd27319ec1e3a024328bd0d4c99b..225f65812f2ebaa82329530c235d2baa3f357572 100644 (file)
@@ -37,6 +37,7 @@
 #include <asm/qe.h>
 #include <asm/ucc.h>
 #include <asm/ucc_fast.h>
+#include <asm/machdep.h>
 
 #include "ucc_geth.h"
 #include "fsl_pq_mdio.h"
@@ -1334,7 +1335,7 @@ static int adjust_enet_interface(struct ucc_geth_private *ugeth)
        struct ucc_geth __iomem *ug_regs;
        struct ucc_fast __iomem *uf_regs;
        int ret_val;
-       u32 upsmr, maccfg2, tbiBaseAddress;
+       u32 upsmr, maccfg2;
        u16 value;
 
        ugeth_vdbg("%s: IN", __func__);
@@ -1389,14 +1390,20 @@ static int adjust_enet_interface(struct ucc_geth_private *ugeth)
        /* Note that this depends on proper setting in utbipar register. */
        if ((ugeth->phy_interface == PHY_INTERFACE_MODE_TBI) ||
            (ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) {
-               tbiBaseAddress = in_be32(&ug_regs->utbipar);
-               tbiBaseAddress &= UTBIPAR_PHY_ADDRESS_MASK;
-               tbiBaseAddress >>= UTBIPAR_PHY_ADDRESS_SHIFT;
-               value = ugeth->phydev->bus->read(ugeth->phydev->bus,
-                               (u8) tbiBaseAddress, ENET_TBI_MII_CR);
+               struct ucc_geth_info *ug_info = ugeth->ug_info;
+               struct phy_device *tbiphy;
+
+               if (!ug_info->tbi_node)
+                       ugeth_warn("TBI mode requires that the device "
+                               "tree specify a tbi-handle\n");
+
+               tbiphy = of_phy_find_device(ug_info->tbi_node);
+               if (!tbiphy)
+                       ugeth_warn("Could not get TBI device\n");
+
+               value = phy_read(tbiphy, ENET_TBI_MII_CR);
                value &= ~0x1000;       /* Turn off autonegotiation */
-               ugeth->phydev->bus->write(ugeth->phydev->bus,
-                               (u8) tbiBaseAddress, ENET_TBI_MII_CR, value);
+               phy_write(tbiphy, ENET_TBI_MII_CR, value);
        }
 
        init_check_frame_length_mode(ug_info->lengthCheckRx, &ug_regs->maccfg2);
index 22b87e64a810ccaa7c55fff97fd9ad3ae9be378a..7d3fa06980c1240320495a05f16908588cd7b1ca 100644 (file)
@@ -897,11 +897,9 @@ static int catc_probe(struct usb_interface *intf, const struct usb_device_id *id
                f5u011_rxmode(catc, catc->rxmode);
        }
        dbg("Init done.");
-       printk(KERN_INFO "%s: %s USB Ethernet at usb-%s-%s, ",
+       printk(KERN_INFO "%s: %s USB Ethernet at usb-%s-%s, %pM.\n",
               netdev->name, (catc->is_f5u011) ? "Belkin F5U011" : "CATC EL1210A NetMate",
-              usbdev->bus->bus_name, usbdev->devpath);
-       for (i = 0; i < 5; i++) printk("%2.2x:", netdev->dev_addr[i]);
-       printk("%2.2x.\n", netdev->dev_addr[i]);
+              usbdev->bus->bus_name, usbdev->devpath, netdev->dev_addr);
        usb_set_intfdata(intf, catc);
 
        SET_NETDEV_DEV(netdev, &intf->dev);
index 87374317f4806f58572131828e02d4efff307409..6fc098fe9ff756558e68dfcc5114285e0af066df 100644 (file)
@@ -1,13 +1,27 @@
 /*
- * MosChips MCS7830 based USB 2.0 Ethernet Devices
+ * MOSCHIP MCS7830 based USB 2.0 Ethernet Devices
  *
  * based on usbnet.c, asix.c and the vendor provided mcs7830 driver
  *
+ * Copyright (C) 2010 Andreas Mohr <andi@lisas.de>
  * Copyright (C) 2006 Arnd Bergmann <arnd@arndb.de>
  * Copyright (C) 2003-2005 David Hollis <dhollis@davehollis.com>
  * Copyright (C) 2005 Phil Chang <pchang23@sbcglobal.net>
  * Copyright (c) 2002-2003 TiVo Inc.
  *
+ * Definitions gathered from MOSCHIP, Data Sheet_7830DA.pdf (thanks!).
+ *
+ * TODO:
+ * - support HIF_REG_CONFIG_SLEEPMODE/HIF_REG_CONFIG_TXENABLE (via autopm?)
+ * - implement ethtool_ops get_pauseparam/set_pauseparam
+ *   via HIF_REG_PAUSE_THRESHOLD (>= revision C only!)
+ * - implement get_eeprom/[set_eeprom]
+ * - switch PHY on/off on ifup/ifdown (perhaps in usbnet.c, via MII)
+ * - mcs7830_get_regs() handling is weird: for rev 2 we return 32 regs,
+ *   can access only ~ 24, remaining user buffer is uninitialized garbage
+ * - anything else?
+ *
+ *
  * 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
@@ -55,7 +69,7 @@
                                 ADVERTISE_100HALF | ADVERTISE_10FULL | \
                                 ADVERTISE_10HALF | ADVERTISE_CSMA)
 
-/* HIF_REG_XX coressponding index value */
+/* HIF_REG_XX corresponding index value */
 enum {
        HIF_REG_MULTICAST_HASH                  = 0x00,
        HIF_REG_PACKET_GAP1                     = 0x08,
@@ -69,6 +83,7 @@ enum {
           HIF_REG_PHY_CMD2_PEND_FLAG_BIT       = 0x80,
           HIF_REG_PHY_CMD2_READY_FLAG_BIT      = 0x40,
        HIF_REG_CONFIG                          = 0x0e,
+       /* hmm, spec sez: "R/W", "Except bit 3" (likely TXENABLE). */
           HIF_REG_CONFIG_CFG                   = 0x80,
           HIF_REG_CONFIG_SPEED100              = 0x40,
           HIF_REG_CONFIG_FULLDUPLEX_ENABLE     = 0x20,
@@ -76,13 +91,24 @@ enum {
           HIF_REG_CONFIG_TXENABLE              = 0x08,
           HIF_REG_CONFIG_SLEEPMODE             = 0x04,
           HIF_REG_CONFIG_ALLMULTICAST          = 0x02,
-          HIF_REG_CONFIG_PROMISCIOUS           = 0x01,
+          HIF_REG_CONFIG_PROMISCUOUS           = 0x01,
        HIF_REG_ETHERNET_ADDR                   = 0x0f,
-       HIF_REG_22                              = 0x15,
+       HIF_REG_FRAME_DROP_COUNTER              = 0x15, /* 0..ff; reset: 0 */
        HIF_REG_PAUSE_THRESHOLD                 = 0x16,
           HIF_REG_PAUSE_THRESHOLD_DEFAULT      = 0,
 };
 
+/* Trailing status byte in Ethernet Rx frame */
+enum {
+       MCS7830_RX_SHORT_FRAME          = 0x01, /* < 64 bytes */
+       MCS7830_RX_LENGTH_ERROR         = 0x02, /* framelen != Ethernet length field */
+       MCS7830_RX_ALIGNMENT_ERROR      = 0x04, /* non-even number of nibbles */
+       MCS7830_RX_CRC_ERROR            = 0x08,
+       MCS7830_RX_LARGE_FRAME          = 0x10, /* > 1518 bytes */
+       MCS7830_RX_FRAME_CORRECT        = 0x20, /* frame is correct */
+       /* [7:6] reserved */
+};
+
 struct mcs7830_data {
        u8 multi_filter[8];
        u8 config;
@@ -109,7 +135,7 @@ static int mcs7830_get_reg(struct usbnet *dev, u16 index, u16 size, void *data)
        return ret;
 }
 
-static int mcs7830_set_reg(struct usbnet *dev, u16 index, u16 size, void *data)
+static int mcs7830_set_reg(struct usbnet *dev, u16 index, u16 size, const void *data)
 {
        struct usb_device *xdev = dev->udev;
        int ret;
@@ -183,13 +209,43 @@ out:
        usb_free_urb(urb);
 }
 
-static int mcs7830_get_address(struct usbnet *dev)
+static int mcs7830_hif_get_mac_address(struct usbnet *dev, unsigned char *addr)
+{
+       int ret = mcs7830_get_reg(dev, HIF_REG_ETHERNET_ADDR, ETH_ALEN, addr);
+       if (ret < 0)
+               return ret;
+       return 0;
+}
+
+static int mcs7830_hif_set_mac_address(struct usbnet *dev, unsigned char *addr)
+{
+       int ret = mcs7830_set_reg(dev, HIF_REG_ETHERNET_ADDR, ETH_ALEN, addr);
+
+       if (ret < 0)
+               return ret;
+       return 0;
+}
+
+static int mcs7830_set_mac_address(struct net_device *netdev, void *p)
 {
        int ret;
-       ret = mcs7830_get_reg(dev, HIF_REG_ETHERNET_ADDR, ETH_ALEN,
-                                  dev->net->dev_addr);
+       struct usbnet *dev = netdev_priv(netdev);
+       struct sockaddr *addr = p;
+
+       if (netif_running(netdev))
+               return -EBUSY;
+
+       if (!is_valid_ether_addr(addr->sa_data))
+               return -EINVAL;
+
+       ret = mcs7830_hif_set_mac_address(dev, addr->sa_data);
+
        if (ret < 0)
                return ret;
+
+       /* it worked --> adopt it on netdev side */
+       memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
+
        return 0;
 }
 
@@ -307,7 +363,7 @@ static int mcs7830_get_rev(struct usbnet *dev)
 {
        u8 dummy[2];
        int ret;
-       ret = mcs7830_get_reg(dev, HIF_REG_22, 2, dummy);
+       ret = mcs7830_get_reg(dev, HIF_REG_FRAME_DROP_COUNTER, 2, dummy);
        if (ret > 0)
                return 2; /* Rev C or later */
        return 1; /* earlier revision */
@@ -331,33 +387,6 @@ static void mcs7830_rev_C_fixup(struct usbnet *dev)
        }
 }
 
-static int mcs7830_init_dev(struct usbnet *dev)
-{
-       int ret;
-       int retry;
-
-       /* Read MAC address from EEPROM */
-       ret = -EINVAL;
-       for (retry = 0; retry < 5 && ret; retry++)
-               ret = mcs7830_get_address(dev);
-       if (ret) {
-               dev_warn(&dev->udev->dev, "Cannot read MAC address\n");
-               goto out;
-       }
-
-       /* Set up PHY */
-       ret = mcs7830_set_autoneg(dev, 0);
-       if (ret) {
-               dev_info(&dev->udev->dev, "Cannot set autoneg\n");
-               goto out;
-       }
-
-       mcs7830_rev_C_fixup(dev);
-       ret = 0;
-out:
-       return ret;
-}
-
 static int mcs7830_mdio_read(struct net_device *netdev, int phy_id,
                             int location)
 {
@@ -378,11 +407,33 @@ static int mcs7830_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
        return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);
 }
 
-/* credits go to asix_set_multicast */
-static void mcs7830_set_multicast(struct net_device *net)
+static inline struct mcs7830_data *mcs7830_get_data(struct usbnet *dev)
+{
+       return (struct mcs7830_data *)&dev->data;
+}
+
+static void mcs7830_hif_update_multicast_hash(struct usbnet *dev)
+{
+       struct mcs7830_data *data = mcs7830_get_data(dev);
+       mcs7830_set_reg_async(dev, HIF_REG_MULTICAST_HASH,
+                               sizeof data->multi_filter,
+                               data->multi_filter);
+}
+
+static void mcs7830_hif_update_config(struct usbnet *dev)
+{
+       /* implementation specific to data->config
+           (argument needs to be heap-based anyway - USB DMA!) */
+       struct mcs7830_data *data = mcs7830_get_data(dev);
+       mcs7830_set_reg_async(dev, HIF_REG_CONFIG, 1, &data->config);
+}
+
+static void mcs7830_data_set_multicast(struct net_device *net)
 {
        struct usbnet *dev = netdev_priv(net);
-       struct mcs7830_data *data = (struct mcs7830_data *)&dev->data;
+       struct mcs7830_data *data = mcs7830_get_data(dev);
+
+       memset(data->multi_filter, 0, sizeof data->multi_filter);
 
        data->config = HIF_REG_CONFIG_TXENABLE;
 
@@ -390,7 +441,7 @@ static void mcs7830_set_multicast(struct net_device *net)
        data->config |= HIF_REG_CONFIG_ALLMULTICAST;
 
        if (net->flags & IFF_PROMISC) {
-               data->config |= HIF_REG_CONFIG_PROMISCIOUS;
+               data->config |= HIF_REG_CONFIG_PROMISCUOUS;
        } else if (net->flags & IFF_ALLMULTI ||
                   net->mc_count > MCS7830_MAX_MCAST) {
                data->config |= HIF_REG_CONFIG_ALLMULTICAST;
@@ -405,21 +456,51 @@ static void mcs7830_set_multicast(struct net_device *net)
                u32 crc_bits;
                int i;
 
-               memset(data->multi_filter, 0, sizeof data->multi_filter);
-
                /* Build the multicast hash filter. */
                for (i = 0; i < net->mc_count; i++) {
                        crc_bits = ether_crc(ETH_ALEN, mc_list->dmi_addr) >> 26;
                        data->multi_filter[crc_bits >> 3] |= 1 << (crc_bits & 7);
                        mc_list = mc_list->next;
                }
+       }
+}
 
-               mcs7830_set_reg_async(dev, HIF_REG_MULTICAST_HASH,
-                               sizeof data->multi_filter,
-                               data->multi_filter);
+static int mcs7830_apply_base_config(struct usbnet *dev)
+{
+       int ret;
+
+       /* re-configure known MAC (suspend case etc.) */
+       ret = mcs7830_hif_set_mac_address(dev, dev->net->dev_addr);
+       if (ret) {
+               dev_info(&dev->udev->dev, "Cannot set MAC address\n");
+               goto out;
        }
 
-       mcs7830_set_reg_async(dev, HIF_REG_CONFIG, 1, &data->config);
+       /* Set up PHY */
+       ret = mcs7830_set_autoneg(dev, 0);
+       if (ret) {
+               dev_info(&dev->udev->dev, "Cannot set autoneg\n");
+               goto out;
+       }
+
+       mcs7830_hif_update_multicast_hash(dev);
+       mcs7830_hif_update_config(dev);
+
+       mcs7830_rev_C_fixup(dev);
+       ret = 0;
+out:
+       return ret;
+}
+
+/* credits go to asix_set_multicast */
+static void mcs7830_set_multicast(struct net_device *net)
+{
+       struct usbnet *dev = netdev_priv(net);
+
+       mcs7830_data_set_multicast(net);
+
+       mcs7830_hif_update_multicast_hash(dev);
+       mcs7830_hif_update_config(dev);
 }
 
 static int mcs7830_get_regs_len(struct net_device *net)
@@ -463,29 +544,6 @@ static const struct ethtool_ops mcs7830_ethtool_ops = {
        .nway_reset             = usbnet_nway_reset,
 };
 
-static int mcs7830_set_mac_address(struct net_device *netdev, void *p)
-{
-       int ret;
-       struct usbnet *dev = netdev_priv(netdev);
-       struct sockaddr *addr = p;
-
-       if (netif_running(netdev))
-               return -EBUSY;
-
-       if (!is_valid_ether_addr(addr->sa_data))
-               return -EINVAL;
-
-       memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
-
-       ret = mcs7830_set_reg(dev, HIF_REG_ETHERNET_ADDR, ETH_ALEN,
-                       netdev->dev_addr);
-
-       if (ret < 0)
-               return ret;
-
-       return 0;
-}
-
 static const struct net_device_ops mcs7830_netdev_ops = {
        .ndo_open               = usbnet_open,
        .ndo_stop               = usbnet_stop,
@@ -495,21 +553,32 @@ static const struct net_device_ops mcs7830_netdev_ops = {
        .ndo_validate_addr      = eth_validate_addr,
        .ndo_do_ioctl           = mcs7830_ioctl,
        .ndo_set_multicast_list = mcs7830_set_multicast,
-       .ndo_set_mac_address     = mcs7830_set_mac_address,
+       .ndo_set_mac_address    = mcs7830_set_mac_address,
 };
 
 static int mcs7830_bind(struct usbnet *dev, struct usb_interface *udev)
 {
        struct net_device *net = dev->net;
        int ret;
+       int retry;
 
-       ret = mcs7830_init_dev(dev);
+       /* Initial startup: Gather MAC address setting from EEPROM */
+       ret = -EINVAL;
+       for (retry = 0; retry < 5 && ret; retry++)
+               ret = mcs7830_hif_get_mac_address(dev, net->dev_addr);
+       if (ret) {
+               dev_warn(&dev->udev->dev, "Cannot read MAC address\n");
+               goto out;
+       }
+
+       mcs7830_data_set_multicast(net);
+
+       ret = mcs7830_apply_base_config(dev);
        if (ret)
                goto out;
 
        net->ethtool_ops = &mcs7830_ethtool_ops;
        net->netdev_ops = &mcs7830_netdev_ops;
-       mcs7830_set_multicast(net);
 
        /* reserve space for the status byte on rx */
        dev->rx_urb_size = ETH_FRAME_LEN + 1;
@@ -526,7 +595,7 @@ out:
        return ret;
 }
 
-/* The chip always appends a status bytes that we need to strip */
+/* The chip always appends a status byte that we need to strip */
 static int mcs7830_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
 {
        u8 status;
@@ -539,9 +608,23 @@ static int mcs7830_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
        skb_trim(skb, skb->len - 1);
        status = skb->data[skb->len];
 
-       if (status != 0x20)
+       if (status != MCS7830_RX_FRAME_CORRECT) {
                dev_dbg(&dev->udev->dev, "rx fixup status %x\n", status);
 
+               /* hmm, perhaps usbnet.c already sees a globally visible
+                  frame error and increments rx_errors on its own already? */
+               dev->net->stats.rx_errors++;
+
+               if (status &    (MCS7830_RX_SHORT_FRAME
+                               |MCS7830_RX_LENGTH_ERROR
+                               |MCS7830_RX_LARGE_FRAME))
+                       dev->net->stats.rx_length_errors++;
+               if (status & MCS7830_RX_ALIGNMENT_ERROR)
+                       dev->net->stats.rx_frame_errors++;
+               if (status & MCS7830_RX_CRC_ERROR)
+                       dev->net->stats.rx_crc_errors++;
+       }
+
        return skb->len > 0;
 }
 
@@ -580,6 +663,20 @@ static const struct usb_device_id products[] = {
 };
 MODULE_DEVICE_TABLE(usb, products);
 
+static int mcs7830_reset_resume (struct usb_interface *intf)
+{
+       /* YES, this function is successful enough that ethtool -d
+           does show same output pre-/post-suspend */
+
+       struct usbnet           *dev = usb_get_intfdata(intf);
+
+       mcs7830_apply_base_config(dev);
+
+       usbnet_resume(intf);
+
+       return 0;
+}
+
 static struct usb_driver mcs7830_driver = {
        .name = driver_name,
        .id_table = products,
@@ -587,6 +684,7 @@ static struct usb_driver mcs7830_driver = {
        .disconnect = usbnet_disconnect,
        .suspend = usbnet_suspend,
        .resume = usbnet_resume,
+       .reset_resume = mcs7830_reset_resume,
 };
 
 static int __init mcs7830_init(void)
index fd19db0d25048216e00a31f61738c443f8424c9b..21ac103fbb71b952d0ca3a493b3ff61ec449a8df 100644 (file)
@@ -313,20 +313,17 @@ static int rtl8150_set_mac_address(struct net_device *netdev, void *p)
 {
        struct sockaddr *addr = p;
        rtl8150_t *dev = netdev_priv(netdev);
-       int i;
 
        if (netif_running(netdev))
                return -EBUSY;
 
        memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
-       dbg("%s: Setting MAC address to ", netdev->name);
-       for (i = 0; i < 5; i++)
-               dbg("%02X:", netdev->dev_addr[i]);
-       dbg("%02X\n", netdev->dev_addr[i]);
+       dbg("%s: Setting MAC address to %pM\n", netdev->name, netdev->dev_addr);
        /* Set the IDR registers. */
        set_registers(dev, IDR, netdev->addr_len, netdev->dev_addr);
 #ifdef EEPROM_WRITE
        {
+       int i;
        u8 cr;
        /* Get the CR contents. */
        get_registers(dev, CR, 1, &cr);
index 611b80435955343eb53e25fc2ef868e76440d9a5..a7e0c84426ea621eb3dd336b8f5e2113b0358281 100644 (file)
@@ -267,7 +267,7 @@ enum rhine_quirks {
 /* Beware of PCI posted writes */
 #define IOSYNC do { ioread8(ioaddr + StationAddr); } while (0)
 
-static const struct pci_device_id rhine_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(rhine_pci_tbl) = {
        { 0x1106, 0x3043, PCI_ANY_ID, PCI_ANY_ID, },    /* VT86C100A */
        { 0x1106, 0x3065, PCI_ANY_ID, PCI_ANY_ID, },    /* VT6102 */
        { 0x1106, 0x3106, PCI_ANY_ID, PCI_ANY_ID, },    /* 6105{,L,LOM} */
index c93f58f5c6f2f14be1bbc51ad9133dd15a989f5f..f15485efe40e50c91c3647b6717925dc6c3a4500 100644 (file)
@@ -361,7 +361,7 @@ static struct velocity_info_tbl chip_info_table[] = {
  *     Describe the PCI device identifiers that we support in this
  *     device driver. Used for hotplug autoloading.
  */
-static const struct pci_device_id velocity_id_table[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(velocity_id_table) = {
        { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_612X) },
        { }
 };
@@ -2702,10 +2702,8 @@ static void __devinit velocity_print_info(struct velocity_info *vptr)
        struct net_device *dev = vptr->dev;
 
        printk(KERN_INFO "%s: %s\n", dev->name, get_chip_name(vptr->chip_id));
-       printk(KERN_INFO "%s: Ethernet Address: %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n",
-               dev->name,
-               dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
-               dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+       printk(KERN_INFO "%s: Ethernet Address: %pM\n",
+               dev->name, dev->dev_addr);
 }
 
 static u32 velocity_get_link(struct net_device *dev)
index 9ead30bd00c4227522aabc600e8032c02765d82f..9d8984a3741c3d0d8ef562d82e2f62ecd369b316 100644 (file)
@@ -56,8 +56,7 @@ struct virtnet_info
        /* Host will merge rx buffers for big packets (shake it! shake it!) */
        bool mergeable_rx_bufs;
 
-       /* Receive & send queues. */
-       struct sk_buff_head recv;
+       /* Send queue. */
        struct sk_buff_head send;
 
        /* Work struct for refilling if we run low on memory. */
@@ -75,34 +74,44 @@ struct skb_vnet_hdr {
        unsigned int num_sg;
 };
 
+struct padded_vnet_hdr {
+       struct virtio_net_hdr hdr;
+       /*
+        * virtio_net_hdr should be in a separated sg buffer because of a
+        * QEMU bug, and data sg buffer shares same page with this header sg.
+        * This padding makes next sg 16 byte aligned after virtio_net_hdr.
+        */
+       char padding[6];
+};
+
 static inline struct skb_vnet_hdr *skb_vnet_hdr(struct sk_buff *skb)
 {
        return (struct skb_vnet_hdr *)skb->cb;
 }
 
-static void give_a_page(struct virtnet_info *vi, struct page *page)
-{
-       page->private = (unsigned long)vi->pages;
-       vi->pages = page;
-}
-
-static void trim_pages(struct virtnet_info *vi, struct sk_buff *skb)
+/*
+ * private is used to chain pages for big packets, put the whole
+ * most recent used list in the beginning for reuse
+ */
+static void give_pages(struct virtnet_info *vi, struct page *page)
 {
-       unsigned int i;
+       struct page *end;
 
-       for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
-               give_a_page(vi, skb_shinfo(skb)->frags[i].page);
-       skb_shinfo(skb)->nr_frags = 0;
-       skb->data_len = 0;
+       /* Find end of list, sew whole thing into vi->pages. */
+       for (end = page; end->private; end = (struct page *)end->private);
+       end->private = (unsigned long)vi->pages;
+       vi->pages = page;
 }
 
 static struct page *get_a_page(struct virtnet_info *vi, gfp_t gfp_mask)
 {
        struct page *p = vi->pages;
 
-       if (p)
+       if (p) {
                vi->pages = (struct page *)p->private;
-       else
+               /* clear private here, it is used to chain pages */
+               p->private = 0;
+       } else
                p = alloc_page(gfp_mask);
        return p;
 }
@@ -118,99 +127,142 @@ static void skb_xmit_done(struct virtqueue *svq)
        netif_wake_queue(vi->dev);
 }
 
-static void receive_skb(struct net_device *dev, struct sk_buff *skb,
-                       unsigned len)
+static void set_skb_frag(struct sk_buff *skb, struct page *page,
+                        unsigned int offset, unsigned int *len)
 {
-       struct virtnet_info *vi = netdev_priv(dev);
-       struct skb_vnet_hdr *hdr = skb_vnet_hdr(skb);
-       int err;
-       int i;
-
-       if (unlikely(len < sizeof(struct virtio_net_hdr) + ETH_HLEN)) {
-               pr_debug("%s: short packet %i\n", dev->name, len);
-               dev->stats.rx_length_errors++;
-               goto drop;
-       }
+       int i = skb_shinfo(skb)->nr_frags;
+       skb_frag_t *f;
+
+       f = &skb_shinfo(skb)->frags[i];
+       f->size = min((unsigned)PAGE_SIZE - offset, *len);
+       f->page_offset = offset;
+       f->page = page;
+
+       skb->data_len += f->size;
+       skb->len += f->size;
+       skb_shinfo(skb)->nr_frags++;
+       *len -= f->size;
+}
 
-       if (vi->mergeable_rx_bufs) {
-               unsigned int copy;
-               char *p = page_address(skb_shinfo(skb)->frags[0].page);
+static struct sk_buff *page_to_skb(struct virtnet_info *vi,
+                                  struct page *page, unsigned int len)
+{
+       struct sk_buff *skb;
+       struct skb_vnet_hdr *hdr;
+       unsigned int copy, hdr_len, offset;
+       char *p;
 
-               if (len > PAGE_SIZE)
-                       len = PAGE_SIZE;
-               len -= sizeof(struct virtio_net_hdr_mrg_rxbuf);
+       p = page_address(page);
 
-               memcpy(&hdr->mhdr, p, sizeof(hdr->mhdr));
-               p += sizeof(hdr->mhdr);
+       /* copy small packet so we can reuse these pages for small data */
+       skb = netdev_alloc_skb_ip_align(vi->dev, GOOD_COPY_LEN);
+       if (unlikely(!skb))
+               return NULL;
 
-               copy = len;
-               if (copy > skb_tailroom(skb))
-                       copy = skb_tailroom(skb);
+       hdr = skb_vnet_hdr(skb);
 
-               memcpy(skb_put(skb, copy), p, copy);
+       if (vi->mergeable_rx_bufs) {
+               hdr_len = sizeof hdr->mhdr;
+               offset = hdr_len;
+       } else {
+               hdr_len = sizeof hdr->hdr;
+               offset = sizeof(struct padded_vnet_hdr);
+       }
 
-               len -= copy;
+       memcpy(hdr, p, hdr_len);
 
-               if (!len) {
-                       give_a_page(vi, skb_shinfo(skb)->frags[0].page);
-                       skb_shinfo(skb)->nr_frags--;
-               } else {
-                       skb_shinfo(skb)->frags[0].page_offset +=
-                               sizeof(hdr->mhdr) + copy;
-                       skb_shinfo(skb)->frags[0].size = len;
-                       skb->data_len += len;
-                       skb->len += len;
-               }
+       len -= hdr_len;
+       p += offset;
 
-               while (--hdr->mhdr.num_buffers) {
-                       struct sk_buff *nskb;
+       copy = len;
+       if (copy > skb_tailroom(skb))
+               copy = skb_tailroom(skb);
+       memcpy(skb_put(skb, copy), p, copy);
 
-                       i = skb_shinfo(skb)->nr_frags;
-                       if (i >= MAX_SKB_FRAGS) {
-                               pr_debug("%s: packet too long %d\n", dev->name,
-                                        len);
-                               dev->stats.rx_length_errors++;
-                               goto drop;
-                       }
+       len -= copy;
+       offset += copy;
 
-                       nskb = vi->rvq->vq_ops->get_buf(vi->rvq, &len);
-                       if (!nskb) {
-                               pr_debug("%s: rx error: %d buffers missing\n",
-                                        dev->name, hdr->mhdr.num_buffers);
-                               dev->stats.rx_length_errors++;
-                               goto drop;
-                       }
+       while (len) {
+               set_skb_frag(skb, page, offset, &len);
+               page = (struct page *)page->private;
+               offset = 0;
+       }
 
-                       __skb_unlink(nskb, &vi->recv);
-                       vi->num--;
+       if (page)
+               give_pages(vi, page);
 
-                       skb_shinfo(skb)->frags[i] = skb_shinfo(nskb)->frags[0];
-                       skb_shinfo(nskb)->nr_frags = 0;
-                       kfree_skb(nskb);
+       return skb;
+}
 
-                       if (len > PAGE_SIZE)
-                               len = PAGE_SIZE;
+static int receive_mergeable(struct virtnet_info *vi, struct sk_buff *skb)
+{
+       struct skb_vnet_hdr *hdr = skb_vnet_hdr(skb);
+       struct page *page;
+       int num_buf, i, len;
+
+       num_buf = hdr->mhdr.num_buffers;
+       while (--num_buf) {
+               i = skb_shinfo(skb)->nr_frags;
+               if (i >= MAX_SKB_FRAGS) {
+                       pr_debug("%s: packet too long\n", skb->dev->name);
+                       skb->dev->stats.rx_length_errors++;
+                       return -EINVAL;
+               }
 
-                       skb_shinfo(skb)->frags[i].size = len;
-                       skb_shinfo(skb)->nr_frags++;
-                       skb->data_len += len;
-                       skb->len += len;
+               page = vi->rvq->vq_ops->get_buf(vi->rvq, &len);
+               if (!page) {
+                       pr_debug("%s: rx error: %d buffers missing\n",
+                                skb->dev->name, hdr->mhdr.num_buffers);
+                       skb->dev->stats.rx_length_errors++;
+                       return -EINVAL;
                }
-       } else {
-               len -= sizeof(hdr->hdr);
+               if (len > PAGE_SIZE)
+                       len = PAGE_SIZE;
+
+               set_skb_frag(skb, page, 0, &len);
+
+               --vi->num;
+       }
+       return 0;
+}
+
+static void receive_buf(struct net_device *dev, void *buf, unsigned int len)
+{
+       struct virtnet_info *vi = netdev_priv(dev);
+       struct sk_buff *skb;
+       struct page *page;
+       struct skb_vnet_hdr *hdr;
 
-               if (len <= MAX_PACKET_LEN)
-                       trim_pages(vi, skb);
+       if (unlikely(len < sizeof(struct virtio_net_hdr) + ETH_HLEN)) {
+               pr_debug("%s: short packet %i\n", dev->name, len);
+               dev->stats.rx_length_errors++;
+               if (vi->mergeable_rx_bufs || vi->big_packets)
+                       give_pages(vi, buf);
+               else
+                       dev_kfree_skb(buf);
+               return;
+       }
 
-               err = pskb_trim(skb, len);
-               if (err) {
-                       pr_debug("%s: pskb_trim failed %i %d\n", dev->name,
-                                len, err);
+       if (!vi->mergeable_rx_bufs && !vi->big_packets) {
+               skb = buf;
+               len -= sizeof(struct virtio_net_hdr);
+               skb_trim(skb, len);
+       } else {
+               page = buf;
+               skb = page_to_skb(vi, page, len);
+               if (unlikely(!skb)) {
                        dev->stats.rx_dropped++;
-                       goto drop;
+                       give_pages(vi, page);
+                       return;
                }
+               if (vi->mergeable_rx_bufs)
+                       if (receive_mergeable(vi, skb)) {
+                               dev_kfree_skb(skb);
+                               return;
+                       }
        }
 
+       hdr = skb_vnet_hdr(skb);
        skb->truesize += skb->data_len;
        dev->stats.rx_bytes += skb->len;
        dev->stats.rx_packets++;
@@ -267,110 +319,119 @@ static void receive_skb(struct net_device *dev, struct sk_buff *skb,
 
 frame_err:
        dev->stats.rx_frame_errors++;
-drop:
        dev_kfree_skb(skb);
 }
 
-static bool try_fill_recv_maxbufs(struct virtnet_info *vi, gfp_t gfp)
+static int add_recvbuf_small(struct virtnet_info *vi, gfp_t gfp)
 {
        struct sk_buff *skb;
-       struct scatterlist sg[2+MAX_SKB_FRAGS];
-       int num, err, i;
-       bool oom = false;
-
-       sg_init_table(sg, 2+MAX_SKB_FRAGS);
-       do {
-               struct skb_vnet_hdr *hdr;
+       struct skb_vnet_hdr *hdr;
+       struct scatterlist sg[2];
+       int err;
 
-               skb = netdev_alloc_skb_ip_align(vi->dev, MAX_PACKET_LEN);
-               if (unlikely(!skb)) {
-                       oom = true;
-                       break;
-               }
+       skb = netdev_alloc_skb_ip_align(vi->dev, MAX_PACKET_LEN);
+       if (unlikely(!skb))
+               return -ENOMEM;
 
-               skb_put(skb, MAX_PACKET_LEN);
+       skb_put(skb, MAX_PACKET_LEN);
 
-               hdr = skb_vnet_hdr(skb);
-               sg_set_buf(sg, &hdr->hdr, sizeof(hdr->hdr));
+       hdr = skb_vnet_hdr(skb);
+       sg_set_buf(sg, &hdr->hdr, sizeof hdr->hdr);
 
-               if (vi->big_packets) {
-                       for (i = 0; i < MAX_SKB_FRAGS; i++) {
-                               skb_frag_t *f = &skb_shinfo(skb)->frags[i];
-                               f->page = get_a_page(vi, gfp);
-                               if (!f->page)
-                                       break;
+       skb_to_sgvec(skb, sg + 1, 0, skb->len);
 
-                               f->page_offset = 0;
-                               f->size = PAGE_SIZE;
+       err = vi->rvq->vq_ops->add_buf(vi->rvq, sg, 0, 2, skb);
+       if (err < 0)
+               dev_kfree_skb(skb);
 
-                               skb->data_len += PAGE_SIZE;
-                               skb->len += PAGE_SIZE;
+       return err;
+}
 
-                               skb_shinfo(skb)->nr_frags++;
-                       }
+static int add_recvbuf_big(struct virtnet_info *vi, gfp_t gfp)
+{
+       struct scatterlist sg[MAX_SKB_FRAGS + 2];
+       struct page *first, *list = NULL;
+       char *p;
+       int i, err, offset;
+
+       /* page in sg[MAX_SKB_FRAGS + 1] is list tail */
+       for (i = MAX_SKB_FRAGS + 1; i > 1; --i) {
+               first = get_a_page(vi, gfp);
+               if (!first) {
+                       if (list)
+                               give_pages(vi, list);
+                       return -ENOMEM;
                }
+               sg_set_buf(&sg[i], page_address(first), PAGE_SIZE);
 
-               num = skb_to_sgvec(skb, sg+1, 0, skb->len) + 1;
-               skb_queue_head(&vi->recv, skb);
+               /* chain new page in list head to match sg */
+               first->private = (unsigned long)list;
+               list = first;
+       }
 
-               err = vi->rvq->vq_ops->add_buf(vi->rvq, sg, 0, num, skb);
-               if (err < 0) {
-                       skb_unlink(skb, &vi->recv);
-                       trim_pages(vi, skb);
-                       kfree_skb(skb);
-                       break;
-               }
-               vi->num++;
-       } while (err >= num);
-       if (unlikely(vi->num > vi->max))
-               vi->max = vi->num;
-       vi->rvq->vq_ops->kick(vi->rvq);
-       return !oom;
+       first = get_a_page(vi, gfp);
+       if (!first) {
+               give_pages(vi, list);
+               return -ENOMEM;
+       }
+       p = page_address(first);
+
+       /* sg[0], sg[1] share the same page */
+       /* a separated sg[0] for  virtio_net_hdr only during to QEMU bug*/
+       sg_set_buf(&sg[0], p, sizeof(struct virtio_net_hdr));
+
+       /* sg[1] for data packet, from offset */
+       offset = sizeof(struct padded_vnet_hdr);
+       sg_set_buf(&sg[1], p + offset, PAGE_SIZE - offset);
+
+       /* chain first in list head */
+       first->private = (unsigned long)list;
+       err = vi->rvq->vq_ops->add_buf(vi->rvq, sg, 0, MAX_SKB_FRAGS + 2,
+                                      first);
+       if (err < 0)
+               give_pages(vi, first);
+
+       return err;
 }
 
-/* Returns false if we couldn't fill entirely (OOM). */
-static bool try_fill_recv(struct virtnet_info *vi, gfp_t gfp)
+static int add_recvbuf_mergeable(struct virtnet_info *vi, gfp_t gfp)
 {
-       struct sk_buff *skb;
-       struct scatterlist sg[1];
+       struct page *page;
+       struct scatterlist sg;
        int err;
-       bool oom = false;
-
-       if (!vi->mergeable_rx_bufs)
-               return try_fill_recv_maxbufs(vi, gfp);
 
-       do {
-               skb_frag_t *f;
+       page = get_a_page(vi, gfp);
+       if (!page)
+               return -ENOMEM;
 
-               skb = netdev_alloc_skb_ip_align(vi->dev, GOOD_COPY_LEN);
-               if (unlikely(!skb)) {
-                       oom = true;
-                       break;
-               }
+       sg_init_one(&sg, page_address(page), PAGE_SIZE);
 
-               f = &skb_shinfo(skb)->frags[0];
-               f->page = get_a_page(vi, gfp);
-               if (!f->page) {
-                       oom = true;
-                       kfree_skb(skb);
-                       break;
-               }
+       err = vi->rvq->vq_ops->add_buf(vi->rvq, &sg, 0, 1, page);
+       if (err < 0)
+               give_pages(vi, page);
 
-               f->page_offset = 0;
-               f->size = PAGE_SIZE;
+       return err;
+}
 
-               skb_shinfo(skb)->nr_frags++;
+/* Returns false if we couldn't fill entirely (OOM). */
+static bool try_fill_recv(struct virtnet_info *vi, gfp_t gfp)
+{
+       int err;
+       bool oom = false;
 
-               sg_init_one(sg, page_address(f->page), PAGE_SIZE);
-               skb_queue_head(&vi->recv, skb);
+       do {
+               if (vi->mergeable_rx_bufs)
+                       err = add_recvbuf_mergeable(vi, gfp);
+               else if (vi->big_packets)
+                       err = add_recvbuf_big(vi, gfp);
+               else
+                       err = add_recvbuf_small(vi, gfp);
 
-               err = vi->rvq->vq_ops->add_buf(vi->rvq, sg, 0, 1, skb);
                if (err < 0) {
-                       skb_unlink(skb, &vi->recv);
-                       kfree_skb(skb);
+                       oom = true;
                        break;
                }
-               vi->num++;
+               ++vi->num;
        } while (err > 0);
        if (unlikely(vi->num > vi->max))
                vi->max = vi->num;
@@ -407,15 +468,14 @@ static void refill_work(struct work_struct *work)
 static int virtnet_poll(struct napi_struct *napi, int budget)
 {
        struct virtnet_info *vi = container_of(napi, struct virtnet_info, napi);
-       struct sk_buff *skb = NULL;
+       void *buf;
        unsigned int len, received = 0;
 
 again:
        while (received < budget &&
-              (skb = vi->rvq->vq_ops->get_buf(vi->rvq, &len)) != NULL) {
-               __skb_unlink(skb, &vi->recv);
-               receive_skb(vi->dev, skb, len);
-               vi->num--;
+              (buf = vi->rvq->vq_ops->get_buf(vi->rvq, &len)) != NULL) {
+               receive_buf(vi->dev, buf, len);
+               --vi->num;
                received++;
        }
 
@@ -495,9 +555,9 @@ static int xmit_skb(struct virtnet_info *vi, struct sk_buff *skb)
 
        /* Encode metadata header at front. */
        if (vi->mergeable_rx_bufs)
-               sg_set_buf(sg, &hdr->mhdr, sizeof(hdr->mhdr));
+               sg_set_buf(sg, &hdr->mhdr, sizeof hdr->mhdr);
        else
-               sg_set_buf(sg, &hdr->hdr, sizeof(hdr->hdr));
+               sg_set_buf(sg, &hdr->hdr, sizeof hdr->hdr);
 
        hdr->num_sg = skb_to_sgvec(skb, sg+1, 0, skb->len) + 1;
        return vi->svq->vq_ops->add_buf(vi->svq, sg, hdr->num_sg, 0, skb);
@@ -674,6 +734,7 @@ static void virtnet_set_rx_mode(struct net_device *dev)
        struct virtio_net_ctrl_mac *mac_data;
        struct dev_addr_list *addr;
        struct netdev_hw_addr *ha;
+       int uc_count;
        void *buf;
        int i;
 
@@ -700,8 +761,9 @@ static void virtnet_set_rx_mode(struct net_device *dev)
                dev_warn(&dev->dev, "Failed to %sable allmulti mode.\n",
                         allmulti ? "en" : "dis");
 
+       uc_count = netdev_uc_count(dev);
        /* MAC filter - use one buffer for both lists */
-       mac_data = buf = kzalloc(((dev->uc.count + dev->mc_count) * ETH_ALEN) +
+       mac_data = buf = kzalloc(((uc_count + dev->mc_count) * ETH_ALEN) +
                                 (2 * sizeof(mac_data->entries)), GFP_ATOMIC);
        if (!buf) {
                dev_warn(&dev->dev, "No memory for MAC address buffer\n");
@@ -711,16 +773,16 @@ static void virtnet_set_rx_mode(struct net_device *dev)
        sg_init_table(sg, 2);
 
        /* Store the unicast list and count in the front of the buffer */
-       mac_data->entries = dev->uc.count;
+       mac_data->entries = uc_count;
        i = 0;
-       list_for_each_entry(ha, &dev->uc.list, list)
+       netdev_for_each_uc_addr(ha, dev)
                memcpy(&mac_data->macs[i++][0], ha->addr, ETH_ALEN);
 
        sg_set_buf(&sg[0], mac_data,
-                  sizeof(mac_data->entries) + (dev->uc.count * ETH_ALEN));
+                  sizeof(mac_data->entries) + (uc_count * ETH_ALEN));
 
        /* multicast list and count fill the end */
-       mac_data = (void *)&mac_data->macs[dev->uc.count][0];
+       mac_data = (void *)&mac_data->macs[uc_count][0];
 
        mac_data->entries = dev->mc_count;
        addr = dev->mc_list;
@@ -915,8 +977,7 @@ static int virtnet_probe(struct virtio_device *vdev)
                        dev->features |= NETIF_F_HW_VLAN_FILTER;
        }
 
-       /* Initialize our empty receive and send queues. */
-       skb_queue_head_init(&vi->recv);
+       /* Initialize our empty send queue. */
        skb_queue_head_init(&vi->send);
 
        err = register_netdev(dev);
@@ -951,25 +1012,35 @@ free:
        return err;
 }
 
+static void free_unused_bufs(struct virtnet_info *vi)
+{
+       void *buf;
+       while (1) {
+               buf = vi->rvq->vq_ops->detach_unused_buf(vi->rvq);
+               if (!buf)
+                       break;
+               if (vi->mergeable_rx_bufs || vi->big_packets)
+                       give_pages(vi, buf);
+               else
+                       dev_kfree_skb(buf);
+               --vi->num;
+       }
+       BUG_ON(vi->num != 0);
+}
+
 static void __devexit virtnet_remove(struct virtio_device *vdev)
 {
        struct virtnet_info *vi = vdev->priv;
-       struct sk_buff *skb;
 
        /* Stop all the virtqueues. */
        vdev->config->reset(vdev);
 
-       /* Free our skbs in send and recv queues, if any. */
-       while ((skb = __skb_dequeue(&vi->recv)) != NULL) {
-               kfree_skb(skb);
-               vi->num--;
-       }
+       /* Free our skbs in send queue, if any. */
        __skb_queue_purge(&vi->send);
 
-       BUG_ON(vi->num != 0);
-
        unregister_netdev(vi->dev);
        cancel_delayed_work_sync(&vi->refill);
+       free_unused_bufs(vi);
 
        vdev->config->del_vqs(vi->vdev);
 
index 9cc438282d776c5e8e4d57d96f0267a15371403a..b896f938611092c49e613814afe7863ca596ff8c 100644 (file)
@@ -35,7 +35,7 @@ char vmxnet3_driver_name[] = "vmxnet3";
  * PCI Device ID Table
  * Last entry must be all 0s
  */
-static const struct pci_device_id vmxnet3_pciid_table[] = {
+static DEFINE_PCI_DEVICE_TABLE(vmxnet3_pciid_table) = {
        {PCI_VDEVICE(VMWARE, PCI_DEVICE_ID_VMWARE_VMXNET3)},
        {0}
 };
index b9685e82f7b66b4c2b08cd9cc177d3b9cae808d8..a6606b8948e94dcf60b55cad8a3d1b736273691a 100644 (file)
@@ -54,7 +54,7 @@ MODULE_LICENSE("Dual BSD/GPL");
 MODULE_DESCRIPTION("Neterion's X3100 Series 10GbE PCIe I/O"
        "Virtualized Server Adapter");
 
-static struct pci_device_id vxge_id_table[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(vxge_id_table) = {
        {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_TITAN_WIN, PCI_ANY_ID,
        PCI_ANY_ID},
        {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_TITAN_UNI, PCI_ANY_ID,
@@ -4297,10 +4297,8 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
        vxge_debug_init(VXGE_TRACE, "%s: Neterion %s Server Adapter",
                vdev->ndev->name, ll_config.device_hw_info.product_desc);
 
-       vxge_debug_init(VXGE_TRACE,
-               "%s: MAC ADDR: %02X:%02X:%02X:%02X:%02X:%02X",
-               vdev->ndev->name, macaddr[0], macaddr[1], macaddr[2],
-               macaddr[3], macaddr[4], macaddr[5]);
+       vxge_debug_init(VXGE_TRACE, "%s: MAC ADDR: %pM",
+               vdev->ndev->name, macaddr);
 
        vxge_debug_init(VXGE_TRACE, "%s: Link Width x%d",
                vdev->ndev->name, vxge_hw_device_link_width_get(hldev));
index 3f759daf3ca4a9869fdb2c5b3c5da22e8fee9342..f88c07c131978dfd58e046543b04d818e037fbd9 100644 (file)
@@ -2050,7 +2050,7 @@ static int __init dscc4_setup(char *str)
 __setup("dscc4.setup=", dscc4_setup);
 #endif
 
-static struct pci_device_id dscc4_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(dscc4_pci_tbl) = {
        { PCI_VENDOR_ID_SIEMENS, PCI_DEVICE_ID_SIEMENS_DSCC4,
                PCI_ANY_ID, PCI_ANY_ID, },
        { 0,}
index 9bc2e364915755e6874b0f1a390a29f28229ad3a..40d724a8e02044fbfc8d144fa520c47c7681b472 100644 (file)
@@ -528,7 +528,7 @@ static int fst_debug_mask = { FST_DEBUG };
 /*
  *      PCI ID lookup table
  */
-static struct pci_device_id fst_pci_dev_id[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(fst_pci_dev_id) = {
        {PCI_VENDOR_ID_FARSITE, PCI_DEVICE_ID_FARSITE_T2P, PCI_ANY_ID, 
         PCI_ANY_ID, 0, 0, FST_TYPE_T2P},
 
index 4b6f27e7c820fa0cb4655d67f71fd65a2b757129..b278503771212dd02b59977dba0033957181a587 100644 (file)
@@ -77,7 +77,7 @@
 
 static int LMC_PKT_BUF_SZ = 1542;
 
-static struct pci_device_id lmc_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(lmc_pci_tbl) = {
        { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_FAST,
          PCI_VENDOR_ID_LMC, PCI_ANY_ID },
        { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_FAST,
index aec4d39554202acf7effaa7ed569252497926888..f4f1c00d0d23737cfc7b6b8e0066c2d2e6490743 100644 (file)
@@ -251,7 +251,7 @@ static char rcsid[] =
 #undef PC300_DEBUG_RX
 #undef PC300_DEBUG_OTHER
 
-static struct pci_device_id cpc_pci_dev_id[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(cpc_pci_dev_id) = {
        /* PC300/RSV or PC300/X21, 2 chan */
        {0x120e, 0x300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0x300},
        /* PC300/RSV or PC300/X21, 1 chan */
index 60ece54bdd940452f301215743b4658c7bbe2e59..c7ab3becd261c4fe0085574ceb38a1b833a29138 100644 (file)
@@ -481,7 +481,7 @@ static int __devinit pc300_pci_init_one(struct pci_dev *pdev,
 
 
 
-static struct pci_device_id pc300_pci_tbl[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(pc300_pci_tbl) = {
        { PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_PC300_RX_1, PCI_ANY_ID,
          PCI_ANY_ID, 0, 0, 0 },
        { PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_PC300_RX_2, PCI_ANY_ID,
index f1340faaf022a248274ab502cdc7076e89087172..e2cff64a446a1bb102cabdcb263b260c2b59ecc3 100644 (file)
@@ -417,7 +417,7 @@ static int __devinit pci200_pci_init_one(struct pci_dev *pdev,
 
 
 
-static struct pci_device_id pci200_pci_tbl[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(pci200_pci_tbl) = {
        { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_VENDOR_ID_PLX,
          PCI_DEVICE_ID_PLX_PCI200SYN, 0, 0, 0 },
        { 0, }
index daee8a0624eee14a0370ebeb20124e60a8373845..541c700dceef44b84d54f06db8c2797073bc3b3f 100644 (file)
@@ -814,7 +814,7 @@ static int __devinit wanxl_pci_init_one(struct pci_dev *pdev,
        return 0;
 }
 
-static struct pci_device_id wanxl_pci_tbl[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(wanxl_pci_tbl) = {
        { PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_SBE_WANXL100, PCI_ANY_ID,
          PCI_ANY_ID, 0, 0, 0 },
        { PCI_VENDOR_ID_SBE, PCI_DEVICE_ID_SBE_WANXL200, PCI_ANY_ID,
index 96a615fe09ded2c16c79b6ac3629c8fb2f9d0f25..6cead321bc15d664f924105852f5deef740cf392 100644 (file)
@@ -301,24 +301,15 @@ int i2400m_check_mac_addr(struct i2400m *i2400m)
        /* Extract MAC addresss */
        ddi = (void *) skb->data;
        BUILD_BUG_ON(ETH_ALEN != sizeof(ddi->mac_address));
-       d_printf(2, dev, "GET DEVICE INFO: mac addr "
-                "%02x:%02x:%02x:%02x:%02x:%02x\n",
-                ddi->mac_address[0], ddi->mac_address[1],
-                ddi->mac_address[2], ddi->mac_address[3],
-                ddi->mac_address[4], ddi->mac_address[5]);
+       d_printf(2, dev, "GET DEVICE INFO: mac addr %pM\n",
+                ddi->mac_address);
        if (!memcmp(net_dev->perm_addr, ddi->mac_address,
                   sizeof(ddi->mac_address)))
                goto ok;
        dev_warn(dev, "warning: device reports a different MAC address "
                 "to that of boot mode's\n");
-       dev_warn(dev, "device reports     %02x:%02x:%02x:%02x:%02x:%02x\n",
-                ddi->mac_address[0], ddi->mac_address[1],
-                ddi->mac_address[2], ddi->mac_address[3],
-                ddi->mac_address[4], ddi->mac_address[5]);
-       dev_warn(dev, "boot mode reported %02x:%02x:%02x:%02x:%02x:%02x\n",
-                net_dev->perm_addr[0], net_dev->perm_addr[1],
-                net_dev->perm_addr[2], net_dev->perm_addr[3],
-                net_dev->perm_addr[4], net_dev->perm_addr[5]);
+       dev_warn(dev, "device reports     %pM\n", ddi->mac_address);
+       dev_warn(dev, "boot mode reported %pM\n", net_dev->perm_addr);
        if (!memcmp(zeromac, ddi->mac_address, sizeof(zeromac)))
                dev_err(dev, "device reports an invalid MAC address, "
                        "not updating\n");
index 64cdfeb299ca1be36f7169276d3205391569c27c..e803a7dc6502e057f6acfc8610eb4ffcbbd66eac 100644 (file)
@@ -1041,21 +1041,14 @@ int i2400m_read_mac_addr(struct i2400m *i2400m)
                dev_err(dev, "BM: read mac addr failed: %d\n", result);
                goto error_read_mac;
        }
-       d_printf(2, dev,
-                "mac addr is %02x:%02x:%02x:%02x:%02x:%02x\n",
-                ack_buf.ack_pl[0], ack_buf.ack_pl[1],
-                ack_buf.ack_pl[2], ack_buf.ack_pl[3],
-                ack_buf.ack_pl[4], ack_buf.ack_pl[5]);
+       d_printf(2, dev, "mac addr is %pM\n", ack_buf.ack_pl);
        if (i2400m->bus_bm_mac_addr_impaired == 1) {
                ack_buf.ack_pl[0] = 0x00;
                ack_buf.ack_pl[1] = 0x16;
                ack_buf.ack_pl[2] = 0xd3;
                get_random_bytes(&ack_buf.ack_pl[3], 3);
                dev_err(dev, "BM is MAC addr impaired, faking MAC addr to "
-                       "mac addr is %02x:%02x:%02x:%02x:%02x:%02x\n",
-                       ack_buf.ack_pl[0], ack_buf.ack_pl[1],
-                       ack_buf.ack_pl[2], ack_buf.ack_pl[3],
-                       ack_buf.ack_pl[4], ack_buf.ack_pl[5]);
+                       "mac addr is %pM\n", ack_buf.ack_pl);
                result = 0;
        }
        net_dev->addr_len = ETH_ALEN;
index 39410016b4ffb8e467607ef9ffb0e9737f57e0f5..e6ca3eb4c0d3c4fd9211dde6cc01015811d9f2c4 100644 (file)
@@ -39,7 +39,7 @@ static unsigned int rx_ring_size __read_mostly = 16;
 module_param(tx_ring_size, uint, 0);
 module_param(rx_ring_size, uint, 0);
 
-static struct pci_device_id adm8211_pci_id_table[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(adm8211_pci_id_table) = {
        /* ADMtek ADM8211 */
        { PCI_DEVICE(0x10B7, 0x6000) }, /* 3Com 3CRSHPW796 */
        { PCI_DEVICE(0x1200, 0x8201) }, /* ? */
@@ -1400,15 +1400,15 @@ static void adm8211_configure_filter(struct ieee80211_hw *dev,
 }
 
 static int adm8211_add_interface(struct ieee80211_hw *dev,
-                                struct ieee80211_if_init_conf *conf)
+                                struct ieee80211_vif *vif)
 {
        struct adm8211_priv *priv = dev->priv;
        if (priv->mode != NL80211_IFTYPE_MONITOR)
                return -EOPNOTSUPP;
 
-       switch (conf->type) {
+       switch (vif->type) {
        case NL80211_IFTYPE_STATION:
-               priv->mode = conf->type;
+               priv->mode = vif->type;
                break;
        default:
                return -EOPNOTSUPP;
@@ -1416,8 +1416,8 @@ static int adm8211_add_interface(struct ieee80211_hw *dev,
 
        ADM8211_IDLE();
 
-       ADM8211_CSR_WRITE(PAR0, le32_to_cpu(*(__le32 *)conf->mac_addr));
-       ADM8211_CSR_WRITE(PAR1, le16_to_cpu(*(__le16 *)(conf->mac_addr + 4)));
+       ADM8211_CSR_WRITE(PAR0, le32_to_cpu(*(__le32 *)vif->addr));
+       ADM8211_CSR_WRITE(PAR1, le16_to_cpu(*(__le16 *)(vif->addr + 4)));
 
        adm8211_update_mode(dev);
 
@@ -1427,7 +1427,7 @@ static int adm8211_add_interface(struct ieee80211_hw *dev,
 }
 
 static void adm8211_remove_interface(struct ieee80211_hw *dev,
-                                    struct ieee80211_if_init_conf *conf)
+                                    struct ieee80211_vif *vif)
 {
        struct adm8211_priv *priv = dev->priv;
        priv->mode = NL80211_IFTYPE_MONITOR;
index 4331d675fcc62d2550d6036ec0672ef2c093e109..37e4ab737f2ad6913246c30b19839aabd1dae371 100644 (file)
@@ -57,7 +57,7 @@
 #define DRV_NAME "airo"
 
 #ifdef CONFIG_PCI
-static struct pci_device_id card_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(card_ids) = {
        { 0x14b9, 1, PCI_ANY_ID, PCI_ANY_ID, },
        { 0x14b9, 0x4500, PCI_ANY_ID, PCI_ANY_ID },
        { 0x14b9, 0x4800, PCI_ANY_ID, PCI_ANY_ID, },
index 2517364d3ebedbf038e48aa6a93bcbf1e2dc1426..0fb419936dfff58e0b8780107c07c70d842d712b 100644 (file)
@@ -1789,7 +1789,7 @@ static void at76_mac80211_stop(struct ieee80211_hw *hw)
 }
 
 static int at76_add_interface(struct ieee80211_hw *hw,
-                             struct ieee80211_if_init_conf *conf)
+                             struct ieee80211_vif *vif)
 {
        struct at76_priv *priv = hw->priv;
        int ret = 0;
@@ -1798,7 +1798,7 @@ static int at76_add_interface(struct ieee80211_hw *hw,
 
        mutex_lock(&priv->mtx);
 
-       switch (conf->type) {
+       switch (vif->type) {
        case NL80211_IFTYPE_STATION:
                priv->iw_mode = IW_MODE_INFRA;
                break;
@@ -1814,7 +1814,7 @@ exit:
 }
 
 static void at76_remove_interface(struct ieee80211_hw *hw,
-                                 struct ieee80211_if_init_conf *conf)
+                                 struct ieee80211_vif *vif)
 {
        at76_dbg(DBG_MAC80211, "%s()", __func__);
 }
index 9f9459860d82bba9f092cc6c7621b95b9f7f12b9..b99a8c2053d8f9a3a0321b62fe55fe80495a4af6 100644 (file)
@@ -109,7 +109,6 @@ struct ar9170_rxstream_mpdu_merge {
        bool has_plcp;
 };
 
-#define AR9170_NUM_MAX_BA_RETRY        5
 #define AR9170_NUM_TID 16
 #define WME_BA_BMP_SIZE         64
 #define AR9170_NUM_MAX_AGG_LEN (2 * WME_BA_BMP_SIZE)
@@ -143,7 +142,6 @@ struct ar9170_sta_tid {
        u16 tid;
        enum ar9170_tid_state state;
        bool active;
-       u8 retry;
 };
 
 #define AR9170_QUEUE_TIMEOUT           64
@@ -154,6 +152,8 @@ struct ar9170_sta_tid {
 
 #define AR9170_NUM_TX_STATUS           128
 #define AR9170_NUM_TX_AGG_MAX          30
+#define AR9170_NUM_TX_LIMIT_HARD       AR9170_TXQ_DEPTH
+#define AR9170_NUM_TX_LIMIT_SOFT       (AR9170_TXQ_DEPTH - 10)
 
 struct ar9170 {
        struct ieee80211_hw *hw;
@@ -248,13 +248,8 @@ struct ar9170_sta_info {
        unsigned int ampdu_max_len;
 };
 
-#define AR9170_TX_FLAG_WAIT_FOR_ACK    BIT(0)
-#define AR9170_TX_FLAG_NO_ACK          BIT(1)
-#define AR9170_TX_FLAG_BLOCK_ACK       BIT(2)
-
 struct ar9170_tx_info {
        unsigned long timeout;
-       unsigned int flags;
 };
 
 #define IS_STARTED(a)          (((struct ar9170 *)a)->state >= AR9170_STARTED)
index 701ddb7d84004766a9f9e7e37ae796ecc709f39b..0a1d4c28e68a346e05a82c15c0599824bb5a4678 100644 (file)
@@ -276,6 +276,7 @@ struct ar9170_tx_control {
 #define AR9170_TX_MAC_RATE_PROBE               0x8000
 
 /* either-or */
+#define AR9170_TX_PHY_MOD_MASK                 0x00000003
 #define AR9170_TX_PHY_MOD_CCK                  0x00000000
 #define AR9170_TX_PHY_MOD_OFDM                 0x00000001
 #define AR9170_TX_PHY_MOD_HT                   0x00000002
index ddc8c09dc79e321051bc8325714b9642806eea91..857e86104295a07a6c6f586aa1268faae9027608 100644 (file)
@@ -117,7 +117,7 @@ int ar9170_set_qos(struct ar9170 *ar)
        ar9170_regwrite(AR9170_MAC_REG_AC1_AC0_TXOP,
                        ar->edcf[0].txop | ar->edcf[1].txop << 16);
        ar9170_regwrite(AR9170_MAC_REG_AC3_AC2_TXOP,
-                       ar->edcf[1].txop | ar->edcf[3].txop << 16);
+                       ar->edcf[2].txop | ar->edcf[3].txop << 16);
 
        ar9170_regwrite_finish();
 
index f9d6db8d013ec9bea5545dea749f5ba4013d4786..4d27f7f67c76cbf72f35fbca8958108567a63ab4 100644 (file)
@@ -194,12 +194,15 @@ static inline u16 ar9170_get_seq(struct sk_buff *skb)
        return ar9170_get_seq_h((void *) txc->frame_data);
 }
 
+static inline u16 ar9170_get_tid_h(struct ieee80211_hdr *hdr)
+{
+       return (ieee80211_get_qos_ctl(hdr))[0] & IEEE80211_QOS_CTL_TID_MASK;
+}
+
 static inline u16 ar9170_get_tid(struct sk_buff *skb)
 {
        struct ar9170_tx_control *txc = (void *) skb->data;
-       struct ieee80211_hdr *hdr = (void *) txc->frame_data;
-
-       return (ieee80211_get_qos_ctl(hdr))[0] & IEEE80211_QOS_CTL_TID_MASK;
+       return ar9170_get_tid_h((struct ieee80211_hdr *) txc->frame_data);
 }
 
 #define GET_NEXT_SEQ(seq)      ((seq + 1) & 0x0fff)
@@ -213,10 +216,10 @@ static void ar9170_print_txheader(struct ar9170 *ar, struct sk_buff *skb)
        struct ar9170_tx_info *arinfo = (void *) txinfo->rate_driver_data;
        struct ieee80211_hdr *hdr = (void *) txc->frame_data;
 
-       printk(KERN_DEBUG "%s: => FRAME [skb:%p, q:%d, DA:[%pM] flags:%x s:%d "
+       printk(KERN_DEBUG "%s: => FRAME [skb:%p, q:%d, DA:[%pM] s:%d "
                          "mac_ctrl:%04x, phy_ctrl:%08x, timeout:[%d ms]]\n",
               wiphy_name(ar->hw->wiphy), skb, skb_get_queue_mapping(skb),
-              ieee80211_get_DA(hdr), arinfo->flags, ar9170_get_seq_h(hdr),
+              ieee80211_get_DA(hdr), ar9170_get_seq_h(hdr),
               le16_to_cpu(txc->mac_control), le32_to_cpu(txc->phy_control),
               jiffies_to_msecs(arinfo->timeout - jiffies));
 }
@@ -430,7 +433,7 @@ void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb)
        spin_lock_irqsave(&ar->tx_stats_lock, flags);
        ar->tx_stats[queue].len--;
 
-       if (skb_queue_empty(&ar->tx_pending[queue])) {
+       if (ar->tx_stats[queue].len < AR9170_NUM_TX_LIMIT_SOFT) {
 #ifdef AR9170_QUEUE_STOP_DEBUG
                printk(KERN_DEBUG "%s: wake queue %d\n",
                       wiphy_name(ar->hw->wiphy), queue);
@@ -440,22 +443,17 @@ void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb)
        }
        spin_unlock_irqrestore(&ar->tx_stats_lock, flags);
 
-       if (arinfo->flags & AR9170_TX_FLAG_BLOCK_ACK) {
-               ar9170_tx_ampdu_callback(ar, skb);
-       } else if (arinfo->flags & AR9170_TX_FLAG_WAIT_FOR_ACK) {
-               arinfo->timeout = jiffies +
-                                 msecs_to_jiffies(AR9170_TX_TIMEOUT);
-
-               skb_queue_tail(&ar->tx_status[queue], skb);
-       } else if (arinfo->flags & AR9170_TX_FLAG_NO_ACK) {
+       if (info->flags & IEEE80211_TX_CTL_NO_ACK) {
                ar9170_tx_status(ar, skb, AR9170_TX_STATUS_FAILED);
        } else {
-#ifdef AR9170_QUEUE_DEBUG
-               printk(KERN_DEBUG "%s: unsupported frame flags!\n",
-                      wiphy_name(ar->hw->wiphy));
-               ar9170_print_txheader(ar, skb);
-#endif /* AR9170_QUEUE_DEBUG */
-               dev_kfree_skb_any(skb);
+               if (info->flags & IEEE80211_TX_CTL_AMPDU) {
+                       ar9170_tx_ampdu_callback(ar, skb);
+               } else {
+                       arinfo->timeout = jiffies +
+                                 msecs_to_jiffies(AR9170_TX_TIMEOUT);
+
+                       skb_queue_tail(&ar->tx_status[queue], skb);
+               }
        }
 
        if (!ar->tx_stats[queue].len &&
@@ -1407,17 +1405,6 @@ static int ar9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb)
 
        if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) &&
             (is_valid_ether_addr(ieee80211_get_DA(hdr)))) {
-               if (info->flags & IEEE80211_TX_CTL_AMPDU) {
-                       if (unlikely(!info->control.sta))
-                               goto err_out;
-
-                       txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_AGGR);
-                       arinfo->flags = AR9170_TX_FLAG_BLOCK_ACK;
-
-                       goto out;
-               }
-
-               txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_RATE_PROBE);
                /*
                 * WARNING:
                 * Putting the QoS queue bits into an unexplored territory is
@@ -1431,12 +1418,17 @@ static int ar9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb)
 
                txc->phy_control |=
                        cpu_to_le32(queue << AR9170_TX_PHY_QOS_SHIFT);
-               arinfo->flags = AR9170_TX_FLAG_WAIT_FOR_ACK;
-       } else {
-               arinfo->flags = AR9170_TX_FLAG_NO_ACK;
+
+               if (info->flags & IEEE80211_TX_CTL_AMPDU) {
+                       if (unlikely(!info->control.sta))
+                               goto err_out;
+
+                       txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_AGGR);
+               } else {
+                       txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_RATE_PROBE);
+               }
        }
 
-out:
        return 0;
 
 err_out:
@@ -1671,8 +1663,7 @@ static bool ar9170_tx_ampdu(struct ar9170 *ar)
                 * tell the FW/HW that this is the last frame,
                 * that way it will wait for the immediate block ack.
                 */
-               if (likely(skb_peek_tail(&agg)))
-                       ar9170_tx_indicate_immba(ar, skb_peek_tail(&agg));
+               ar9170_tx_indicate_immba(ar, skb_peek_tail(&agg));
 
 #ifdef AR9170_TXAGG_DEBUG
                printk(KERN_DEBUG "%s: generated A-MPDU looks like this:\n",
@@ -1716,6 +1707,21 @@ static void ar9170_tx(struct ar9170 *ar)
 
        for (i = 0; i < __AR9170_NUM_TXQ; i++) {
                spin_lock_irqsave(&ar->tx_stats_lock, flags);
+               frames = min(ar->tx_stats[i].limit - ar->tx_stats[i].len,
+                            skb_queue_len(&ar->tx_pending[i]));
+
+               if (remaining_space < frames) {
+#ifdef AR9170_QUEUE_DEBUG
+                       printk(KERN_DEBUG "%s: tx quota reached queue:%d, "
+                              "remaining slots:%d, needed:%d\n",
+                              wiphy_name(ar->hw->wiphy), i, remaining_space,
+                              frames);
+#endif /* AR9170_QUEUE_DEBUG */
+                       frames = remaining_space;
+               }
+
+               ar->tx_stats[i].len += frames;
+               ar->tx_stats[i].count += frames;
                if (ar->tx_stats[i].len >= ar->tx_stats[i].limit) {
 #ifdef AR9170_QUEUE_DEBUG
                        printk(KERN_DEBUG "%s: queue %d full\n",
@@ -1733,25 +1739,8 @@ static void ar9170_tx(struct ar9170 *ar)
                        __ar9170_dump_txstats(ar);
 #endif /* AR9170_QUEUE_STOP_DEBUG */
                        ieee80211_stop_queue(ar->hw, i);
-                       spin_unlock_irqrestore(&ar->tx_stats_lock, flags);
-                       continue;
                }
 
-               frames = min(ar->tx_stats[i].limit - ar->tx_stats[i].len,
-                            skb_queue_len(&ar->tx_pending[i]));
-
-               if (remaining_space < frames) {
-#ifdef AR9170_QUEUE_DEBUG
-                       printk(KERN_DEBUG "%s: tx quota reached queue:%d, "
-                              "remaining slots:%d, needed:%d\n",
-                              wiphy_name(ar->hw->wiphy), i, remaining_space,
-                              frames);
-#endif /* AR9170_QUEUE_DEBUG */
-                       frames = remaining_space;
-               }
-
-               ar->tx_stats[i].len += frames;
-               ar->tx_stats[i].count += frames;
                spin_unlock_irqrestore(&ar->tx_stats_lock, flags);
 
                if (!frames)
@@ -1773,7 +1762,7 @@ static void ar9170_tx(struct ar9170 *ar)
                        arinfo->timeout = jiffies +
                                          msecs_to_jiffies(AR9170_TX_TIMEOUT);
 
-                       if (arinfo->flags == AR9170_TX_FLAG_BLOCK_ACK)
+                       if (info->flags & IEEE80211_TX_CTL_AMPDU)
                                atomic_inc(&ar->tx_ampdu_pending);
 
 #ifdef AR9170_QUEUE_DEBUG
@@ -1784,7 +1773,7 @@ static void ar9170_tx(struct ar9170 *ar)
 
                        err = ar->tx(ar, skb);
                        if (unlikely(err)) {
-                               if (arinfo->flags == AR9170_TX_FLAG_BLOCK_ACK)
+                               if (info->flags & IEEE80211_TX_CTL_AMPDU)
                                        atomic_dec(&ar->tx_ampdu_pending);
 
                                frames_failed++;
@@ -1950,7 +1939,7 @@ err_free:
 }
 
 static int ar9170_op_add_interface(struct ieee80211_hw *hw,
-                                  struct ieee80211_if_init_conf *conf)
+                                  struct ieee80211_vif *vif)
 {
        struct ar9170 *ar = hw->priv;
        struct ath_common *common = &ar->common;
@@ -1963,8 +1952,8 @@ static int ar9170_op_add_interface(struct ieee80211_hw *hw,
                goto unlock;
        }
 
-       ar->vif = conf->vif;
-       memcpy(common->macaddr, conf->mac_addr, ETH_ALEN);
+       ar->vif = vif;
+       memcpy(common->macaddr, vif->addr, ETH_ALEN);
 
        if (modparam_nohwcrypt || (ar->vif->type != NL80211_IFTYPE_STATION)) {
                ar->rx_software_decryption = true;
@@ -1984,7 +1973,7 @@ unlock:
 }
 
 static void ar9170_op_remove_interface(struct ieee80211_hw *hw,
-                                      struct ieee80211_if_init_conf *conf)
+                                      struct ieee80211_vif *vif)
 {
        struct ar9170 *ar = hw->priv;
 
@@ -2366,7 +2355,6 @@ static void ar9170_sta_notify(struct ieee80211_hw *hw,
                        sta_info->agg[i].state = AR9170_TID_STATE_SHUTDOWN;
                        sta_info->agg[i].active = false;
                        sta_info->agg[i].ssn = 0;
-                       sta_info->agg[i].retry = 0;
                        sta_info->agg[i].tid = i;
                        INIT_LIST_HEAD(&sta_info->agg[i].list);
                        skb_queue_head_init(&sta_info->agg[i].queue);
index e0799d92405773206f9e2128b5a5cddeb6765d06..0f361186b78ffb0dca6e03fdf799493fba0b595d 100644 (file)
@@ -84,6 +84,8 @@ static struct usb_device_id ar9170_usb_ids[] = {
        { USB_DEVICE(0x0cde, 0x0023) },
        /* Z-Com UB82 ABG */
        { USB_DEVICE(0x0cde, 0x0026) },
+       /* Sphairon Homelink 1202 */
+       { USB_DEVICE(0x0cde, 0x0027) },
        /* Arcadyan WN7512 */
        { USB_DEVICE(0x083a, 0xf522) },
        /* Planex GWUS300 */
index 6a2a9676111121cc1523aadbad93a22e9edc4382..66bcb506a1123e7f25e82ef7fa7d46a1b48f8aed 100644 (file)
@@ -1063,6 +1063,7 @@ struct ath5k_hw {
        u32                     ah_cw_min;
        u32                     ah_cw_max;
        u32                     ah_limit_tx_retries;
+       u8                      ah_coverage_class;
 
        /* Antenna Control */
        u32                     ah_ant_ctl[AR5K_EEPROM_N_MODES][AR5K_ANT_MAX];
@@ -1200,6 +1201,7 @@ extern bool ath5k_eeprom_is_hb63(struct ath5k_hw *ah);
 
 /* Protocol Control Unit Functions */
 extern int ath5k_hw_set_opmode(struct ath5k_hw *ah);
+extern void ath5k_hw_set_coverage_class(struct ath5k_hw *ah, u8 coverage_class);
 /* BSSID Functions */
 extern int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac);
 extern void ath5k_hw_set_associd(struct ath5k_hw *ah);
@@ -1231,6 +1233,10 @@ extern int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout);
 extern unsigned int ath5k_hw_get_ack_timeout(struct ath5k_hw *ah);
 extern int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout);
 extern unsigned int ath5k_hw_get_cts_timeout(struct ath5k_hw *ah);
+/* Clock rate related functions */
+unsigned int ath5k_hw_htoclock(struct ath5k_hw *ah, unsigned int usec);
+unsigned int ath5k_hw_clocktoh(struct ath5k_hw *ah, unsigned int clock);
+unsigned int ath5k_hw_get_clockrate(struct ath5k_hw *ah);
 /* Key table (WEP) functions */
 extern int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry);
 extern int ath5k_hw_is_key_valid(struct ath5k_hw *ah, u16 entry);
@@ -1310,24 +1316,6 @@ extern int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 txpower);
  * Functions used internaly
  */
 
-/*
- * Translate usec to hw clock units
- * TODO: Half/quarter rate
- */
-static inline unsigned int ath5k_hw_htoclock(unsigned int usec, bool turbo)
-{
-       return turbo ? (usec * 80) : (usec * 40);
-}
-
-/*
- * Translate hw clock units to usec
- * TODO: Half/quarter rate
- */
-static inline unsigned int ath5k_hw_clocktoh(unsigned int clock, bool turbo)
-{
-       return turbo ? (clock / 80) : (clock / 40);
-}
-
 static inline struct ath_common *ath5k_hw_common(struct ath5k_hw *ah)
 {
         return &ah->common;
index e63b7c40d0eeb5ce0b8fcca0df66beece476e209..5577bcc80eac04ed1443e3c221eaadd6edbd5491 100644 (file)
@@ -83,7 +83,7 @@ MODULE_VERSION("0.6.0 (EXPERIMENTAL)");
 
 
 /* Known PCI ids */
-static const struct pci_device_id ath5k_pci_id_table[] = {
+static DEFINE_PCI_DEVICE_TABLE(ath5k_pci_id_table) = {
        { PCI_VDEVICE(ATHEROS, 0x0207) }, /* 5210 early */
        { PCI_VDEVICE(ATHEROS, 0x0007) }, /* 5210 */
        { PCI_VDEVICE(ATHEROS, 0x0011) }, /* 5311 - this is on AHB bus !*/
@@ -225,9 +225,9 @@ static int ath5k_reset_wake(struct ath5k_softc *sc);
 static int ath5k_start(struct ieee80211_hw *hw);
 static void ath5k_stop(struct ieee80211_hw *hw);
 static int ath5k_add_interface(struct ieee80211_hw *hw,
-               struct ieee80211_if_init_conf *conf);
+               struct ieee80211_vif *vif);
 static void ath5k_remove_interface(struct ieee80211_hw *hw,
-               struct ieee80211_if_init_conf *conf);
+               struct ieee80211_vif *vif);
 static int ath5k_config(struct ieee80211_hw *hw, u32 changed);
 static u64 ath5k_prepare_multicast(struct ieee80211_hw *hw,
                                   int mc_count, struct dev_addr_list *mc_list);
@@ -254,6 +254,8 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw,
                u32 changes);
 static void ath5k_sw_scan_start(struct ieee80211_hw *hw);
 static void ath5k_sw_scan_complete(struct ieee80211_hw *hw);
+static void ath5k_set_coverage_class(struct ieee80211_hw *hw,
+               u8 coverage_class);
 
 static const struct ieee80211_ops ath5k_hw_ops = {
        .tx             = ath5k_tx,
@@ -274,6 +276,7 @@ static const struct ieee80211_ops ath5k_hw_ops = {
        .bss_info_changed = ath5k_bss_info_changed,
        .sw_scan_start  = ath5k_sw_scan_start,
        .sw_scan_complete = ath5k_sw_scan_complete,
+       .set_coverage_class = ath5k_set_coverage_class,
 };
 
 /*
@@ -2773,7 +2776,7 @@ static void ath5k_stop(struct ieee80211_hw *hw)
 }
 
 static int ath5k_add_interface(struct ieee80211_hw *hw,
-               struct ieee80211_if_init_conf *conf)
+               struct ieee80211_vif *vif)
 {
        struct ath5k_softc *sc = hw->priv;
        int ret;
@@ -2784,22 +2787,22 @@ static int ath5k_add_interface(struct ieee80211_hw *hw,
                goto end;
        }
 
-       sc->vif = conf->vif;
+       sc->vif = vif;
 
-       switch (conf->type) {
+       switch (vif->type) {
        case NL80211_IFTYPE_AP:
        case NL80211_IFTYPE_STATION:
        case NL80211_IFTYPE_ADHOC:
        case NL80211_IFTYPE_MESH_POINT:
        case NL80211_IFTYPE_MONITOR:
-               sc->opmode = conf->type;
+               sc->opmode = vif->type;
                break;
        default:
                ret = -EOPNOTSUPP;
                goto end;
        }
 
-       ath5k_hw_set_lladdr(sc->ah, conf->mac_addr);
+       ath5k_hw_set_lladdr(sc->ah, vif->addr);
        ath5k_mode_setup(sc);
 
        ret = 0;
@@ -2810,13 +2813,13 @@ end:
 
 static void
 ath5k_remove_interface(struct ieee80211_hw *hw,
-                       struct ieee80211_if_init_conf *conf)
+                       struct ieee80211_vif *vif)
 {
        struct ath5k_softc *sc = hw->priv;
        u8 mac[ETH_ALEN] = {};
 
        mutex_lock(&sc->lock);
-       if (sc->vif != conf->vif)
+       if (sc->vif != vif)
                goto end;
 
        ath5k_hw_set_lladdr(sc->ah, mac);
@@ -3262,3 +3265,22 @@ static void ath5k_sw_scan_complete(struct ieee80211_hw *hw)
        ath5k_hw_set_ledstate(sc->ah, sc->assoc ?
                AR5K_LED_ASSOC : AR5K_LED_INIT);
 }
+
+/**
+ * ath5k_set_coverage_class - Set IEEE 802.11 coverage class
+ *
+ * @hw: struct ieee80211_hw pointer
+ * @coverage_class: IEEE 802.11 coverage class number
+ *
+ * Mac80211 callback. Sets slot time, ACK timeout and CTS timeout for given
+ * coverage class. The values are persistent, they are restored after device
+ * reset.
+ */
+static void ath5k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class)
+{
+       struct ath5k_softc *sc = hw->priv;
+
+       mutex_lock(&sc->lock);
+       ath5k_hw_set_coverage_class(sc->ah, coverage_class);
+       mutex_unlock(&sc->lock);
+}
index 64fc1eb9b6d91964d724f389661d8d1d7b828b0c..aefe84f9c04bf8136abea73bd24e6bd49d0b4dc5 100644 (file)
@@ -187,8 +187,8 @@ unsigned int ath5k_hw_get_ack_timeout(struct ath5k_hw *ah)
 {
        ATH5K_TRACE(ah->ah_sc);
 
-       return ath5k_hw_clocktoh(AR5K_REG_MS(ath5k_hw_reg_read(ah,
-                       AR5K_TIME_OUT), AR5K_TIME_OUT_ACK), ah->ah_turbo);
+       return ath5k_hw_clocktoh(ah, AR5K_REG_MS(ath5k_hw_reg_read(ah,
+                       AR5K_TIME_OUT), AR5K_TIME_OUT_ACK));
 }
 
 /**
@@ -200,12 +200,12 @@ unsigned int ath5k_hw_get_ack_timeout(struct ath5k_hw *ah)
 int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout)
 {
        ATH5K_TRACE(ah->ah_sc);
-       if (ath5k_hw_clocktoh(AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_ACK),
-                       ah->ah_turbo) <= timeout)
+       if (ath5k_hw_clocktoh(ah, AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_ACK))
+                       <= timeout)
                return -EINVAL;
 
        AR5K_REG_WRITE_BITS(ah, AR5K_TIME_OUT, AR5K_TIME_OUT_ACK,
-               ath5k_hw_htoclock(timeout, ah->ah_turbo));
+               ath5k_hw_htoclock(ah, timeout));
 
        return 0;
 }
@@ -218,8 +218,8 @@ int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout)
 unsigned int ath5k_hw_get_cts_timeout(struct ath5k_hw *ah)
 {
        ATH5K_TRACE(ah->ah_sc);
-       return ath5k_hw_clocktoh(AR5K_REG_MS(ath5k_hw_reg_read(ah,
-                       AR5K_TIME_OUT), AR5K_TIME_OUT_CTS), ah->ah_turbo);
+       return ath5k_hw_clocktoh(ah, AR5K_REG_MS(ath5k_hw_reg_read(ah,
+                       AR5K_TIME_OUT), AR5K_TIME_OUT_CTS));
 }
 
 /**
@@ -231,16 +231,96 @@ unsigned int ath5k_hw_get_cts_timeout(struct ath5k_hw *ah)
 int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout)
 {
        ATH5K_TRACE(ah->ah_sc);
-       if (ath5k_hw_clocktoh(AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_CTS),
-                       ah->ah_turbo) <= timeout)
+       if (ath5k_hw_clocktoh(ah, AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_CTS))
+                       <= timeout)
                return -EINVAL;
 
        AR5K_REG_WRITE_BITS(ah, AR5K_TIME_OUT, AR5K_TIME_OUT_CTS,
-                       ath5k_hw_htoclock(timeout, ah->ah_turbo));
+                       ath5k_hw_htoclock(ah, timeout));
 
        return 0;
 }
 
+/**
+ * ath5k_hw_htoclock - Translate usec to hw clock units
+ *
+ * @ah: The &struct ath5k_hw
+ * @usec: value in microseconds
+ */
+unsigned int ath5k_hw_htoclock(struct ath5k_hw *ah, unsigned int usec)
+{
+       return usec * ath5k_hw_get_clockrate(ah);
+}
+
+/**
+ * ath5k_hw_clocktoh - Translate hw clock units to usec
+ * @clock: value in hw clock units
+ */
+unsigned int ath5k_hw_clocktoh(struct ath5k_hw *ah, unsigned int clock)
+{
+       return clock / ath5k_hw_get_clockrate(ah);
+}
+
+/**
+ * ath5k_hw_get_clockrate - Get the clock rate for current mode
+ *
+ * @ah: The &struct ath5k_hw
+ */
+unsigned int ath5k_hw_get_clockrate(struct ath5k_hw *ah)
+{
+       struct ieee80211_channel *channel = ah->ah_current_channel;
+       int clock;
+
+       if (channel->hw_value & CHANNEL_5GHZ)
+               clock = 40; /* 802.11a */
+       else if (channel->hw_value & CHANNEL_CCK)
+               clock = 22; /* 802.11b */
+       else
+               clock = 44; /* 802.11g */
+
+       /* Clock rate in turbo modes is twice the normal rate */
+       if (channel->hw_value & CHANNEL_TURBO)
+               clock *= 2;
+
+       return clock;
+}
+
+/**
+ * ath5k_hw_get_default_slottime - Get the default slot time for current mode
+ *
+ * @ah: The &struct ath5k_hw
+ */
+unsigned int ath5k_hw_get_default_slottime(struct ath5k_hw *ah)
+{
+       struct ieee80211_channel *channel = ah->ah_current_channel;
+
+       if (channel->hw_value & CHANNEL_TURBO)
+               return 6; /* both turbo modes */
+
+       if (channel->hw_value & CHANNEL_CCK)
+               return 20; /* 802.11b */
+
+       return 9; /* 802.11 a/g */
+}
+
+/**
+ * ath5k_hw_get_default_sifs - Get the default SIFS for current mode
+ *
+ * @ah: The &struct ath5k_hw
+ */
+unsigned int ath5k_hw_get_default_sifs(struct ath5k_hw *ah)
+{
+       struct ieee80211_channel *channel = ah->ah_current_channel;
+
+       if (channel->hw_value & CHANNEL_TURBO)
+               return 8; /* both turbo modes */
+
+       if (channel->hw_value & CHANNEL_5GHZ)
+               return 16; /* 802.11a */
+
+       return 10; /* 802.11 b/g */
+}
+
 /**
  * ath5k_hw_set_lladdr - Set station id
  *
@@ -1050,3 +1130,24 @@ int ath5k_hw_set_key_lladdr(struct ath5k_hw *ah, u16 entry, const u8 *mac)
        return 0;
 }
 
+/**
+ * ath5k_hw_set_coverage_class - Set IEEE 802.11 coverage class
+ *
+ * @ah: The &struct ath5k_hw
+ * @coverage_class: IEEE 802.11 coverage class number
+ *
+ * Sets slot time, ACK timeout and CTS timeout for given coverage class.
+ */
+void ath5k_hw_set_coverage_class(struct ath5k_hw *ah, u8 coverage_class)
+{
+       /* As defined by IEEE 802.11-2007 17.3.8.6 */
+       int slot_time = ath5k_hw_get_default_slottime(ah) + 3 * coverage_class;
+       int ack_timeout = ath5k_hw_get_default_sifs(ah) + slot_time;
+       int cts_timeout = ack_timeout;
+
+       ath5k_hw_set_slot_time(ah, slot_time);
+       ath5k_hw_set_ack_timeout(ah, ack_timeout);
+       ath5k_hw_set_cts_timeout(ah, cts_timeout);
+
+       ah->ah_coverage_class = coverage_class;
+}
index eeebb9aef2060eb90bb10f487c875f2d0982057a..abe36c0d139c72f4e60dde1d006423b82185570b 100644 (file)
@@ -520,12 +520,16 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
  */
 unsigned int ath5k_hw_get_slot_time(struct ath5k_hw *ah)
 {
+       unsigned int slot_time_clock;
+
        ATH5K_TRACE(ah->ah_sc);
+
        if (ah->ah_version == AR5K_AR5210)
-               return ath5k_hw_clocktoh(ath5k_hw_reg_read(ah,
-                               AR5K_SLOT_TIME) & 0xffff, ah->ah_turbo);
+               slot_time_clock = ath5k_hw_reg_read(ah, AR5K_SLOT_TIME);
        else
-               return ath5k_hw_reg_read(ah, AR5K_DCU_GBL_IFS_SLOT) & 0xffff;
+               slot_time_clock = ath5k_hw_reg_read(ah, AR5K_DCU_GBL_IFS_SLOT);
+
+       return ath5k_hw_clocktoh(ah, slot_time_clock & 0xffff);
 }
 
 /*
@@ -533,15 +537,17 @@ unsigned int ath5k_hw_get_slot_time(struct ath5k_hw *ah)
  */
 int ath5k_hw_set_slot_time(struct ath5k_hw *ah, unsigned int slot_time)
 {
+       u32 slot_time_clock = ath5k_hw_htoclock(ah, slot_time);
+
        ATH5K_TRACE(ah->ah_sc);
-       if (slot_time < AR5K_SLOT_TIME_9 || slot_time > AR5K_SLOT_TIME_MAX)
+
+       if (slot_time < 6 || slot_time_clock > AR5K_SLOT_TIME_MAX)
                return -EINVAL;
 
        if (ah->ah_version == AR5K_AR5210)
-               ath5k_hw_reg_write(ah, ath5k_hw_htoclock(slot_time,
-                               ah->ah_turbo), AR5K_SLOT_TIME);
+               ath5k_hw_reg_write(ah, slot_time_clock, AR5K_SLOT_TIME);
        else
-               ath5k_hw_reg_write(ah, slot_time, AR5K_DCU_GBL_IFS_SLOT);
+               ath5k_hw_reg_write(ah, slot_time_clock, AR5K_DCU_GBL_IFS_SLOT);
 
        return 0;
 }
index 62954fc778692dae949ee32c91a4528b3d4a098e..6690923fd78cee4700adc05c647856e29b167d93 100644 (file)
@@ -60,12 +60,11 @@ static inline int ath5k_hw_write_ofdm_timings(struct ath5k_hw *ah,
                !(channel->hw_value & CHANNEL_OFDM));
 
        /* Get coefficient
-        * ALGO: coef = (5 * clock * carrier_freq) / 2)
+        * ALGO: coef = (5 * clock / carrier_freq) / 2
         * we scale coef by shifting clock value by 24 for
         * better precision since we use integers */
        /* TODO: Half/quarter rate */
-       clock =  ath5k_hw_htoclock(1, channel->hw_value & CHANNEL_TURBO);
-
+       clock =  (channel->hw_value & CHANNEL_TURBO) ? 80 : 40;
        coef_scaled = ((5 * (clock << 24)) / 2) / channel->center_freq;
 
        /* Get exponent
@@ -1317,6 +1316,10 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
        /* Restore antenna mode */
        ath5k_hw_set_antenna_mode(ah, ah->ah_ant_mode);
 
+       /* Restore slot time and ACK timeouts */
+       if (ah->ah_coverage_class > 0)
+               ath5k_hw_set_coverage_class(ah, ah->ah_coverage_class);
+
        /*
         * Configure QCUs/DCUs
         */
index 4985b2b1b0a9aab399f17cd4a347392773f0f475..6b50d5eb9ec3e8821ea0bb44475669742b77c739 100644 (file)
@@ -1,4 +1,6 @@
 ath9k-y +=     beacon.o \
+               gpio.o \
+               init.o \
                main.o \
                recv.o \
                xmit.o \
index 329e6bc137ab36ea7b86f9fc86d1a12ef06a44f5..9e62a569e816bf59ba7307647149701faf0354c5 100644 (file)
@@ -121,16 +121,19 @@ static int ath_ahb_probe(struct platform_device *pdev)
        sc->mem = mem;
        sc->irq = irq;
 
-       ret = ath_init_device(AR5416_AR9100_DEVID, sc, 0x0, &ath_ahb_bus_ops);
+       /* Will be cleared in ath9k_start() */
+       sc->sc_flags |= SC_OP_INVALID;
+
+       ret = request_irq(irq, ath_isr, IRQF_SHARED, "ath9k", sc);
        if (ret) {
-               dev_err(&pdev->dev, "failed to initialize device\n");
+               dev_err(&pdev->dev, "request_irq failed\n");
                goto err_free_hw;
        }
 
-       ret = request_irq(irq, ath_isr, IRQF_SHARED, "ath9k", sc);
+       ret = ath9k_init_device(AR5416_AR9100_DEVID, sc, 0x0, &ath_ahb_bus_ops);
        if (ret) {
-               dev_err(&pdev->dev, "request_irq failed\n");
-               goto err_detach;
+               dev_err(&pdev->dev, "failed to initialize device\n");
+               goto err_irq;
        }
 
        ah = sc->sc_ah;
@@ -143,8 +146,8 @@ static int ath_ahb_probe(struct platform_device *pdev)
 
        return 0;
 
- err_detach:
-       ath_detach(sc);
+ err_irq:
+       free_irq(irq, sc);
  err_free_hw:
        ieee80211_free_hw(hw);
        platform_set_drvdata(pdev, NULL);
@@ -161,8 +164,12 @@ static int ath_ahb_remove(struct platform_device *pdev)
        if (hw) {
                struct ath_wiphy *aphy = hw->priv;
                struct ath_softc *sc = aphy->sc;
+               struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 
-               ath_cleanup(sc);
+               ath9k_deinit_device(sc);
+               free_irq(sc->irq, sc);
+               ieee80211_free_hw(sc->hw);
+               ath_bus_cleanup(common);
                platform_set_drvdata(pdev, NULL);
        }
 
index 1597a42731edc58c55e3a6a37b69953f57f2623e..bf3d4c4bfa522788691aab1c63991aaba9cf310d 100644 (file)
@@ -341,6 +341,12 @@ int ath_beaconq_config(struct ath_softc *sc);
 #define ATH_LONG_CALINTERVAL      30000   /* 30 seconds */
 #define ATH_RESTART_CALINTERVAL   1200000 /* 20 minutes */
 
+void ath_ani_calibrate(unsigned long data);
+
+/**********/
+/* BTCOEX */
+/**********/
+
 /* Defines the BT AR_BT_COEX_WGHT used */
 enum ath_stomp_type {
        ATH_BTCOEX_NO_STOMP,
@@ -361,6 +367,10 @@ struct ath_btcoex {
        struct ath_gen_timer *no_stomp_timer; /* Timer for no BT stomping */
 };
 
+int ath_init_btcoex_timer(struct ath_softc *sc);
+void ath9k_btcoex_timer_resume(struct ath_softc *sc);
+void ath9k_btcoex_timer_pause(struct ath_softc *sc);
+
 /********************/
 /*   LED Control    */
 /********************/
@@ -385,6 +395,9 @@ struct ath_led {
        bool registered;
 };
 
+void ath_init_leds(struct ath_softc *sc);
+void ath_deinit_leds(struct ath_softc *sc);
+
 /********************/
 /* Main driver core */
 /********************/
@@ -403,26 +416,28 @@ struct ath_led {
 #define ATH_TXPOWER_MAX         100     /* .5 dBm units */
 #define ATH_RATE_DUMMY_MARKER   0
 
-#define SC_OP_INVALID           BIT(0)
-#define SC_OP_BEACONS           BIT(1)
-#define SC_OP_RXAGGR            BIT(2)
-#define SC_OP_TXAGGR            BIT(3)
-#define SC_OP_FULL_RESET        BIT(4)
-#define SC_OP_PREAMBLE_SHORT    BIT(5)
-#define SC_OP_PROTECT_ENABLE    BIT(6)
-#define SC_OP_RXFLUSH           BIT(7)
-#define SC_OP_LED_ASSOCIATED    BIT(8)
-#define SC_OP_WAIT_FOR_BEACON   BIT(12)
-#define SC_OP_LED_ON            BIT(13)
-#define SC_OP_SCANNING          BIT(14)
-#define SC_OP_TSF_RESET         BIT(15)
-#define SC_OP_WAIT_FOR_CAB      BIT(16)
-#define SC_OP_WAIT_FOR_PSPOLL_DATA BIT(17)
-#define SC_OP_WAIT_FOR_TX_ACK   BIT(18)
-#define SC_OP_BEACON_SYNC       BIT(19)
-#define SC_OP_BT_PRIORITY_DETECTED BIT(21)
-#define SC_OP_NULLFUNC_COMPLETED BIT(22)
-#define SC_OP_PS_ENABLED       BIT(23)
+#define SC_OP_INVALID                BIT(0)
+#define SC_OP_BEACONS                BIT(1)
+#define SC_OP_RXAGGR                 BIT(2)
+#define SC_OP_TXAGGR                 BIT(3)
+#define SC_OP_FULL_RESET             BIT(4)
+#define SC_OP_PREAMBLE_SHORT         BIT(5)
+#define SC_OP_PROTECT_ENABLE         BIT(6)
+#define SC_OP_RXFLUSH                BIT(7)
+#define SC_OP_LED_ASSOCIATED         BIT(8)
+#define SC_OP_LED_ON                 BIT(9)
+#define SC_OP_SCANNING               BIT(10)
+#define SC_OP_TSF_RESET              BIT(11)
+#define SC_OP_BT_PRIORITY_DETECTED   BIT(12)
+
+/* Powersave flags */
+#define PS_WAIT_FOR_BEACON        BIT(0)
+#define PS_WAIT_FOR_CAB           BIT(1)
+#define PS_WAIT_FOR_PSPOLL_DATA   BIT(2)
+#define PS_WAIT_FOR_TX_ACK        BIT(3)
+#define PS_BEACON_SYNC            BIT(4)
+#define PS_NULLFUNC_COMPLETED     BIT(5)
+#define PS_ENABLED                BIT(6)
 
 struct ath_wiphy;
 struct ath_rate_table;
@@ -453,12 +468,12 @@ struct ath_softc {
        int irq;
        spinlock_t sc_resetlock;
        spinlock_t sc_serial_rw;
-       spinlock_t ani_lock;
        spinlock_t sc_pm_lock;
        struct mutex mutex;
 
        u32 intrstatus;
        u32 sc_flags; /* SC_OP_* */
+       u16 ps_flags; /* PS_* */
        u16 curtxpow;
        u8 nbcnvifs;
        u16 nvifs;
@@ -509,6 +524,7 @@ struct ath_wiphy {
        int chan_is_ht;
 };
 
+void ath9k_tasklet(unsigned long data);
 int ath_reset(struct ath_softc *sc, bool retry_tx);
 int ath_get_hal_qnum(u16 queue, struct ath_softc *sc);
 int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc);
@@ -525,15 +541,15 @@ static inline void ath_bus_cleanup(struct ath_common *common)
 }
 
 extern struct ieee80211_ops ath9k_ops;
+extern int modparam_nohwcrypt;
 
 irqreturn_t ath_isr(int irq, void *dev);
-void ath_cleanup(struct ath_softc *sc);
-int ath_init_device(u16 devid, struct ath_softc *sc, u16 subsysid,
+int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid,
                    const struct ath_bus_ops *bus_ops);
-void ath_detach(struct ath_softc *sc);
+void ath9k_deinit_device(struct ath_softc *sc);
 const char *ath_mac_bb_name(u32 mac_bb_version);
 const char *ath_rf_name(u16 rf_version);
-void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw);
+void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw);
 void ath9k_update_ichannel(struct ath_softc *sc, struct ieee80211_hw *hw,
                           struct ath9k_channel *ichan);
 void ath_update_chainmask(struct ath_softc *sc, int is_ht);
@@ -542,6 +558,7 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
 
 void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw);
 void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw);
+bool ath9k_setpower(struct ath_softc *sc, enum ath9k_power_mode mode);
 
 #ifdef CONFIG_PCI
 int ath_pci_init(void);
@@ -583,4 +600,8 @@ void ath_mac80211_stop_queue(struct ath_softc *sc, u16 skb_queue);
 void ath_mac80211_start_queue(struct ath_softc *sc, u16 skb_queue);
 
 int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype);
+
+void ath_start_rfkill_poll(struct ath_softc *sc);
+extern void ath9k_rfkill_poll_state(struct ieee80211_hw *hw);
+
 #endif /* ATH9K_H */
index 1660ef17aaf5479215171bcc7211028a1bae4db6..422454fe4ff0b199b98e7b2e8ae75f653a22f8c6 100644 (file)
@@ -480,7 +480,8 @@ void ath_beacon_tasklet(unsigned long data)
                sc->beacon.updateslot = COMMIT; /* commit next beacon */
                sc->beacon.slotupdate = slot;
        } else if (sc->beacon.updateslot == COMMIT && sc->beacon.slotupdate == slot) {
-               ath9k_hw_setslottime(sc->sc_ah, sc->beacon.slottime);
+               ah->slottime = sc->beacon.slottime;
+               ath9k_hw_init_global_settings(ah);
                sc->beacon.updateslot = OK;
        }
        if (bfaddr != 0) {
index b66f72dbf7b93f9c52bc254b1c54f7c0dd256422..9489b6b25b5fc97ab3bc3d0ba146aeecced088fd 100644 (file)
@@ -289,23 +289,49 @@ static ssize_t read_file_rcstat(struct file *file, char __user *user_buf,
        if (sc->cur_rate_table == NULL)
                return 0;
 
-       max = 80 + sc->cur_rate_table->rate_cnt * 64;
+       max = 80 + sc->cur_rate_table->rate_cnt * 1024;
        buf = kmalloc(max + 1, GFP_KERNEL);
        if (buf == NULL)
                return 0;
        buf[max] = 0;
 
-       len += sprintf(buf, "%5s %15s %8s %9s %3s\n\n", "Rate", "Success",
-                      "Retries", "XRetries", "PER");
+       len += sprintf(buf, "%6s %6s %6s "
+                      "%10s %10s %10s %10s\n",
+                      "HT", "MCS", "Rate",
+                      "Success", "Retries", "XRetries", "PER");
 
        for (i = 0; i < sc->cur_rate_table->rate_cnt; i++) {
                u32 ratekbps = sc->cur_rate_table->info[i].ratekbps;
                struct ath_rc_stats *stats = &sc->debug.stats.rcstats[i];
+               char mcs[5];
+               char htmode[5];
+               int used_mcs = 0, used_htmode = 0;
+
+               if (WLAN_RC_PHY_HT(sc->cur_rate_table->info[i].phy)) {
+                       used_mcs = snprintf(mcs, 5, "%d",
+                               sc->cur_rate_table->info[i].ratecode);
+
+                       if (WLAN_RC_PHY_40(sc->cur_rate_table->info[i].phy))
+                               used_htmode = snprintf(htmode, 5, "HT40");
+                       else if (WLAN_RC_PHY_20(sc->cur_rate_table->info[i].phy))
+                               used_htmode = snprintf(htmode, 5, "HT20");
+                       else
+                               used_htmode = snprintf(htmode, 5, "????");
+               }
+
+               mcs[used_mcs] = '\0';
+               htmode[used_htmode] = '\0';
 
                len += snprintf(buf + len, max - len,
-                       "%3u.%d: %8u %8u %8u %8u\n", ratekbps / 1000,
-                       (ratekbps % 1000) / 100, stats->success,
-                       stats->retries, stats->xretries,
+                       "%6s %6s %3u.%d: "
+                       "%10u %10u %10u %10u\n",
+                       htmode,
+                       mcs,
+                       ratekbps / 1000,
+                       (ratekbps % 1000) / 100,
+                       stats->success,
+                       stats->retries,
+                       stats->xretries,
                        stats->per);
        }
 
@@ -554,6 +580,116 @@ static const struct file_operations fops_xmit = {
        .owner = THIS_MODULE
 };
 
+static ssize_t read_file_recv(struct file *file, char __user *user_buf,
+                             size_t count, loff_t *ppos)
+{
+#define PHY_ERR(s, p) \
+       len += snprintf(buf + len, size - len, "%18s : %10u\n", s, \
+                       sc->debug.stats.rxstats.phy_err_stats[p]);
+
+       struct ath_softc *sc = file->private_data;
+       char *buf;
+       unsigned int len = 0, size = 1152;
+       ssize_t retval = 0;
+
+       buf = kzalloc(size, GFP_KERNEL);
+       if (buf == NULL)
+               return 0;
+
+       len += snprintf(buf + len, size - len,
+                       "%18s : %10u\n", "CRC ERR",
+                       sc->debug.stats.rxstats.crc_err);
+       len += snprintf(buf + len, size - len,
+                       "%18s : %10u\n", "DECRYPT CRC ERR",
+                       sc->debug.stats.rxstats.decrypt_crc_err);
+       len += snprintf(buf + len, size - len,
+                       "%18s : %10u\n", "PHY ERR",
+                       sc->debug.stats.rxstats.phy_err);
+       len += snprintf(buf + len, size - len,
+                       "%18s : %10u\n", "MIC ERR",
+                       sc->debug.stats.rxstats.mic_err);
+       len += snprintf(buf + len, size - len,
+                       "%18s : %10u\n", "PRE-DELIM CRC ERR",
+                       sc->debug.stats.rxstats.pre_delim_crc_err);
+       len += snprintf(buf + len, size - len,
+                       "%18s : %10u\n", "POST-DELIM CRC ERR",
+                       sc->debug.stats.rxstats.post_delim_crc_err);
+       len += snprintf(buf + len, size - len,
+                       "%18s : %10u\n", "DECRYPT BUSY ERR",
+                       sc->debug.stats.rxstats.decrypt_busy_err);
+
+       PHY_ERR("UNDERRUN", ATH9K_PHYERR_UNDERRUN);
+       PHY_ERR("TIMING", ATH9K_PHYERR_TIMING);
+       PHY_ERR("PARITY", ATH9K_PHYERR_PARITY);
+       PHY_ERR("RATE", ATH9K_PHYERR_RATE);
+       PHY_ERR("LENGTH", ATH9K_PHYERR_LENGTH);
+       PHY_ERR("RADAR", ATH9K_PHYERR_RADAR);
+       PHY_ERR("SERVICE", ATH9K_PHYERR_SERVICE);
+       PHY_ERR("TOR", ATH9K_PHYERR_TOR);
+       PHY_ERR("OFDM-TIMING", ATH9K_PHYERR_OFDM_TIMING);
+       PHY_ERR("OFDM-SIGNAL-PARITY", ATH9K_PHYERR_OFDM_SIGNAL_PARITY);
+       PHY_ERR("OFDM-RATE", ATH9K_PHYERR_OFDM_RATE_ILLEGAL);
+       PHY_ERR("OFDM-LENGTH", ATH9K_PHYERR_OFDM_LENGTH_ILLEGAL);
+       PHY_ERR("OFDM-POWER-DROP", ATH9K_PHYERR_OFDM_POWER_DROP);
+       PHY_ERR("OFDM-SERVICE", ATH9K_PHYERR_OFDM_SERVICE);
+       PHY_ERR("OFDM-RESTART", ATH9K_PHYERR_OFDM_RESTART);
+       PHY_ERR("FALSE-RADAR-EXT", ATH9K_PHYERR_FALSE_RADAR_EXT);
+       PHY_ERR("CCK-TIMING", ATH9K_PHYERR_CCK_TIMING);
+       PHY_ERR("CCK-HEADER-CRC", ATH9K_PHYERR_CCK_HEADER_CRC);
+       PHY_ERR("CCK-RATE", ATH9K_PHYERR_CCK_RATE_ILLEGAL);
+       PHY_ERR("CCK-SERVICE", ATH9K_PHYERR_CCK_SERVICE);
+       PHY_ERR("CCK-RESTART", ATH9K_PHYERR_CCK_RESTART);
+       PHY_ERR("CCK-LENGTH", ATH9K_PHYERR_CCK_LENGTH_ILLEGAL);
+       PHY_ERR("CCK-POWER-DROP", ATH9K_PHYERR_CCK_POWER_DROP);
+       PHY_ERR("HT-CRC", ATH9K_PHYERR_HT_CRC_ERROR);
+       PHY_ERR("HT-LENGTH", ATH9K_PHYERR_HT_LENGTH_ILLEGAL);
+       PHY_ERR("HT-RATE", ATH9K_PHYERR_HT_RATE_ILLEGAL);
+
+       retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+       kfree(buf);
+
+       return retval;
+
+#undef PHY_ERR
+}
+
+void ath_debug_stat_rx(struct ath_softc *sc, struct ath_buf *bf)
+{
+#define RX_STAT_INC(c) sc->debug.stats.rxstats.c++
+#define RX_PHY_ERR_INC(c) sc->debug.stats.rxstats.phy_err_stats[c]++
+
+       struct ath_desc *ds = bf->bf_desc;
+       u32 phyerr;
+
+       if (ds->ds_rxstat.rs_status & ATH9K_RXERR_CRC)
+               RX_STAT_INC(crc_err);
+       if (ds->ds_rxstat.rs_status & ATH9K_RXERR_DECRYPT)
+               RX_STAT_INC(decrypt_crc_err);
+       if (ds->ds_rxstat.rs_status & ATH9K_RXERR_MIC)
+               RX_STAT_INC(mic_err);
+       if (ds->ds_rxstat.rs_status & ATH9K_RX_DELIM_CRC_PRE)
+               RX_STAT_INC(pre_delim_crc_err);
+       if (ds->ds_rxstat.rs_status & ATH9K_RX_DELIM_CRC_POST)
+               RX_STAT_INC(post_delim_crc_err);
+       if (ds->ds_rxstat.rs_status & ATH9K_RX_DECRYPT_BUSY)
+               RX_STAT_INC(decrypt_busy_err);
+
+       if (ds->ds_rxstat.rs_status & ATH9K_RXERR_PHY) {
+               RX_STAT_INC(phy_err);
+               phyerr = ds->ds_rxstat.rs_phyerr & 0x24;
+               RX_PHY_ERR_INC(phyerr);
+       }
+
+#undef RX_STAT_INC
+#undef RX_PHY_ERR_INC
+}
+
+static const struct file_operations fops_recv = {
+       .read = read_file_recv,
+       .open = ath9k_debugfs_open,
+       .owner = THIS_MODULE
+};
+
 int ath9k_init_debug(struct ath_hw *ah)
 {
        struct ath_common *common = ath9k_hw_common(ah);
@@ -606,6 +742,13 @@ int ath9k_init_debug(struct ath_hw *ah)
        if (!sc->debug.debugfs_xmit)
                goto err;
 
+       sc->debug.debugfs_recv = debugfs_create_file("recv",
+                                                    S_IRUSR,
+                                                    sc->debug.debugfs_phy,
+                                                    sc, &fops_recv);
+       if (!sc->debug.debugfs_recv)
+               goto err;
+
        return 0;
 err:
        ath9k_exit_debug(ah);
@@ -617,6 +760,7 @@ void ath9k_exit_debug(struct ath_hw *ah)
        struct ath_common *common = ath9k_hw_common(ah);
        struct ath_softc *sc = (struct ath_softc *) common->priv;
 
+       debugfs_remove(sc->debug.debugfs_recv);
        debugfs_remove(sc->debug.debugfs_xmit);
        debugfs_remove(sc->debug.debugfs_wiphy);
        debugfs_remove(sc->debug.debugfs_rcstat);
index 536663e3ee1124ea9c560f3d9c51a45311527f65..86780e68b31e64ffeae8174354baabace6b80bfe 100644 (file)
@@ -116,10 +116,35 @@ struct ath_tx_stats {
        u32 delim_underrun;
 };
 
+/**
+ * struct ath_rx_stats - RX Statistics
+ * @crc_err: No. of frames with incorrect CRC value
+ * @decrypt_crc_err: No. of frames whose CRC check failed after
+       decryption process completed
+ * @phy_err: No. of frames whose reception failed because the PHY
+       encountered an error
+ * @mic_err: No. of frames with incorrect TKIP MIC verification failure
+ * @pre_delim_crc_err: Pre-Frame delimiter CRC error detections
+ * @post_delim_crc_err: Post-Frame delimiter CRC error detections
+ * @decrypt_busy_err: Decryption interruptions counter
+ * @phy_err_stats: Individual PHY error statistics
+ */
+struct ath_rx_stats {
+       u32 crc_err;
+       u32 decrypt_crc_err;
+       u32 phy_err;
+       u32 mic_err;
+       u32 pre_delim_crc_err;
+       u32 post_delim_crc_err;
+       u32 decrypt_busy_err;
+       u32 phy_err_stats[ATH9K_PHYERR_MAX];
+};
+
 struct ath_stats {
        struct ath_interrupt_stats istats;
        struct ath_rc_stats rcstats[RATE_TABLE_SIZE];
        struct ath_tx_stats txstats[ATH9K_NUM_TX_QUEUES];
+       struct ath_rx_stats rxstats;
 };
 
 struct ath9k_debug {
@@ -130,6 +155,7 @@ struct ath9k_debug {
        struct dentry *debugfs_rcstat;
        struct dentry *debugfs_wiphy;
        struct dentry *debugfs_xmit;
+       struct dentry *debugfs_recv;
        struct ath_stats stats;
 };
 
@@ -142,6 +168,7 @@ void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status);
 void ath_debug_stat_rc(struct ath_softc *sc, int final_rate);
 void ath_debug_stat_tx(struct ath_softc *sc, struct ath_txq *txq,
                       struct ath_buf *bf);
+void ath_debug_stat_rx(struct ath_softc *sc, struct ath_buf *bf);
 void ath_debug_stat_retries(struct ath_softc *sc, int rix,
                            int xretries, int retries, u8 per);
 
@@ -181,6 +208,11 @@ static inline void ath_debug_stat_tx(struct ath_softc *sc,
 {
 }
 
+static inline void ath_debug_stat_rx(struct ath_softc *sc,
+                                    struct ath_buf *bf)
+{
+}
+
 static inline void ath_debug_stat_retries(struct ath_softc *sc, int rix,
                                          int xretries, int retries, u8 per)
 {
diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c
new file mode 100644 (file)
index 0000000..e204bd2
--- /dev/null
@@ -0,0 +1,428 @@
+/*
+ * Copyright (c) 2008-2009 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "ath9k.h"
+
+/********************************/
+/*      LED functions          */
+/********************************/
+
+static void ath_led_blink_work(struct work_struct *work)
+{
+       struct ath_softc *sc = container_of(work, struct ath_softc,
+                                           ath_led_blink_work.work);
+
+       if (!(sc->sc_flags & SC_OP_LED_ASSOCIATED))
+               return;
+
+       if ((sc->led_on_duration == ATH_LED_ON_DURATION_IDLE) ||
+           (sc->led_off_duration == ATH_LED_OFF_DURATION_IDLE))
+               ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 0);
+       else
+               ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin,
+                                 (sc->sc_flags & SC_OP_LED_ON) ? 1 : 0);
+
+       ieee80211_queue_delayed_work(sc->hw,
+                                    &sc->ath_led_blink_work,
+                                    (sc->sc_flags & SC_OP_LED_ON) ?
+                                       msecs_to_jiffies(sc->led_off_duration) :
+                                       msecs_to_jiffies(sc->led_on_duration));
+
+       sc->led_on_duration = sc->led_on_cnt ?
+                       max((ATH_LED_ON_DURATION_IDLE - sc->led_on_cnt), 25) :
+                       ATH_LED_ON_DURATION_IDLE;
+       sc->led_off_duration = sc->led_off_cnt ?
+                       max((ATH_LED_OFF_DURATION_IDLE - sc->led_off_cnt), 10) :
+                       ATH_LED_OFF_DURATION_IDLE;
+       sc->led_on_cnt = sc->led_off_cnt = 0;
+       if (sc->sc_flags & SC_OP_LED_ON)
+               sc->sc_flags &= ~SC_OP_LED_ON;
+       else
+               sc->sc_flags |= SC_OP_LED_ON;
+}
+
+static void ath_led_brightness(struct led_classdev *led_cdev,
+                              enum led_brightness brightness)
+{
+       struct ath_led *led = container_of(led_cdev, struct ath_led, led_cdev);
+       struct ath_softc *sc = led->sc;
+
+       switch (brightness) {
+       case LED_OFF:
+               if (led->led_type == ATH_LED_ASSOC ||
+                   led->led_type == ATH_LED_RADIO) {
+                       ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin,
+                               (led->led_type == ATH_LED_RADIO));
+                       sc->sc_flags &= ~SC_OP_LED_ASSOCIATED;
+                       if (led->led_type == ATH_LED_RADIO)
+                               sc->sc_flags &= ~SC_OP_LED_ON;
+               } else {
+                       sc->led_off_cnt++;
+               }
+               break;
+       case LED_FULL:
+               if (led->led_type == ATH_LED_ASSOC) {
+                       sc->sc_flags |= SC_OP_LED_ASSOCIATED;
+                       ieee80211_queue_delayed_work(sc->hw,
+                                                    &sc->ath_led_blink_work, 0);
+               } else if (led->led_type == ATH_LED_RADIO) {
+                       ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 0);
+                       sc->sc_flags |= SC_OP_LED_ON;
+               } else {
+                       sc->led_on_cnt++;
+               }
+               break;
+       default:
+               break;
+       }
+}
+
+static int ath_register_led(struct ath_softc *sc, struct ath_led *led,
+                           char *trigger)
+{
+       int ret;
+
+       led->sc = sc;
+       led->led_cdev.name = led->name;
+       led->led_cdev.default_trigger = trigger;
+       led->led_cdev.brightness_set = ath_led_brightness;
+
+       ret = led_classdev_register(wiphy_dev(sc->hw->wiphy), &led->led_cdev);
+       if (ret)
+               ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
+                         "Failed to register led:%s", led->name);
+       else
+               led->registered = 1;
+       return ret;
+}
+
+static void ath_unregister_led(struct ath_led *led)
+{
+       if (led->registered) {
+               led_classdev_unregister(&led->led_cdev);
+               led->registered = 0;
+       }
+}
+
+void ath_deinit_leds(struct ath_softc *sc)
+{
+       ath_unregister_led(&sc->assoc_led);
+       sc->sc_flags &= ~SC_OP_LED_ASSOCIATED;
+       ath_unregister_led(&sc->tx_led);
+       ath_unregister_led(&sc->rx_led);
+       ath_unregister_led(&sc->radio_led);
+       ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1);
+}
+
+void ath_init_leds(struct ath_softc *sc)
+{
+       char *trigger;
+       int ret;
+
+       if (AR_SREV_9287(sc->sc_ah))
+               sc->sc_ah->led_pin = ATH_LED_PIN_9287;
+       else
+               sc->sc_ah->led_pin = ATH_LED_PIN_DEF;
+
+       /* Configure gpio 1 for output */
+       ath9k_hw_cfg_output(sc->sc_ah, sc->sc_ah->led_pin,
+                           AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
+       /* LED off, active low */
+       ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1);
+
+       INIT_DELAYED_WORK(&sc->ath_led_blink_work, ath_led_blink_work);
+
+       trigger = ieee80211_get_radio_led_name(sc->hw);
+       snprintf(sc->radio_led.name, sizeof(sc->radio_led.name),
+               "ath9k-%s::radio", wiphy_name(sc->hw->wiphy));
+       ret = ath_register_led(sc, &sc->radio_led, trigger);
+       sc->radio_led.led_type = ATH_LED_RADIO;
+       if (ret)
+               goto fail;
+
+       trigger = ieee80211_get_assoc_led_name(sc->hw);
+       snprintf(sc->assoc_led.name, sizeof(sc->assoc_led.name),
+               "ath9k-%s::assoc", wiphy_name(sc->hw->wiphy));
+       ret = ath_register_led(sc, &sc->assoc_led, trigger);
+       sc->assoc_led.led_type = ATH_LED_ASSOC;
+       if (ret)
+               goto fail;
+
+       trigger = ieee80211_get_tx_led_name(sc->hw);
+       snprintf(sc->tx_led.name, sizeof(sc->tx_led.name),
+               "ath9k-%s::tx", wiphy_name(sc->hw->wiphy));
+       ret = ath_register_led(sc, &sc->tx_led, trigger);
+       sc->tx_led.led_type = ATH_LED_TX;
+       if (ret)
+               goto fail;
+
+       trigger = ieee80211_get_rx_led_name(sc->hw);
+       snprintf(sc->rx_led.name, sizeof(sc->rx_led.name),
+               "ath9k-%s::rx", wiphy_name(sc->hw->wiphy));
+       ret = ath_register_led(sc, &sc->rx_led, trigger);
+       sc->rx_led.led_type = ATH_LED_RX;
+       if (ret)
+               goto fail;
+
+       return;
+
+fail:
+       cancel_delayed_work_sync(&sc->ath_led_blink_work);
+       ath_deinit_leds(sc);
+}
+
+/*******************/
+/*     Rfkill     */
+/*******************/
+
+static bool ath_is_rfkill_set(struct ath_softc *sc)
+{
+       struct ath_hw *ah = sc->sc_ah;
+
+       return ath9k_hw_gpio_get(ah, ah->rfkill_gpio) ==
+                                 ah->rfkill_polarity;
+}
+
+void ath9k_rfkill_poll_state(struct ieee80211_hw *hw)
+{
+       struct ath_wiphy *aphy = hw->priv;
+       struct ath_softc *sc = aphy->sc;
+       bool blocked = !!ath_is_rfkill_set(sc);
+
+       wiphy_rfkill_set_hw_state(hw->wiphy, blocked);
+}
+
+void ath_start_rfkill_poll(struct ath_softc *sc)
+{
+       struct ath_hw *ah = sc->sc_ah;
+
+       if (ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
+               wiphy_rfkill_start_polling(sc->hw->wiphy);
+}
+
+/******************/
+/*     BTCOEX     */
+/******************/
+
+/*
+ * Detects if there is any priority bt traffic
+ */
+static void ath_detect_bt_priority(struct ath_softc *sc)
+{
+       struct ath_btcoex *btcoex = &sc->btcoex;
+       struct ath_hw *ah = sc->sc_ah;
+
+       if (ath9k_hw_gpio_get(sc->sc_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))) {
+               if (btcoex->bt_priority_cnt >= ATH_BT_CNT_THRESHOLD) {
+                       ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_BTCOEX,
+                                 "BT priority traffic detected");
+                       sc->sc_flags |= SC_OP_BT_PRIORITY_DETECTED;
+               } else {
+                       sc->sc_flags &= ~SC_OP_BT_PRIORITY_DETECTED;
+               }
+
+               btcoex->bt_priority_cnt = 0;
+               btcoex->bt_priority_time = jiffies;
+       }
+}
+
+/*
+ * 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,
+                                 u32 timer_period)
+{
+       struct ath_common *common = ath9k_hw_common(ah);
+       struct ath_softc *sc = (struct ath_softc *) common->priv;
+
+       ath9k_hw_gen_timer_start(ah, timer, timer_next, timer_period);
+
+       if ((sc->imask & ATH9K_INT_GENTIMER) == 0) {
+               ath9k_hw_set_interrupts(ah, 0);
+               sc->imask |= ATH9K_INT_GENTIMER;
+               ath9k_hw_set_interrupts(ah, sc->imask);
+       }
+}
+
+static void ath9k_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer)
+{
+       struct ath_common *common = ath9k_hw_common(ah);
+       struct ath_softc *sc = (struct ath_softc *) common->priv;
+       struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers;
+
+       ath9k_hw_gen_timer_stop(ah, timer);
+
+       /* if no timer is enabled, turn off interrupt mask */
+       if (timer_table->timer_mask.val == 0) {
+               ath9k_hw_set_interrupts(ah, 0);
+               sc->imask &= ~ATH9K_INT_GENTIMER;
+               ath9k_hw_set_interrupts(ah, sc->imask);
+       }
+}
+
+/*
+ * This is the master bt coex timer 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_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;
+
+       ath_detect_bt_priority(sc);
+
+       spin_lock_bh(&btcoex->btcoex_lock);
+
+       ath9k_btcoex_bt_stomp(sc, btcoex->bt_stomp_type);
+
+       spin_unlock_bh(&btcoex->btcoex_lock);
+
+       if (btcoex->btcoex_period != btcoex->btcoex_no_stomp) {
+               if (btcoex->hw_timer_enabled)
+                       ath9k_gen_timer_stop(ah, btcoex->no_stomp_timer);
+
+               ath9k_gen_timer_start(ah,
+                                     btcoex->no_stomp_timer,
+                                     (ath9k_hw_gettsf32(ah) +
+                                      btcoex->btcoex_no_stomp),
+                                      btcoex->btcoex_no_stomp * 10);
+               btcoex->hw_timer_enabled = true;
+       }
+
+       mod_timer(&btcoex->period_timer, jiffies +
+                                 msecs_to_jiffies(ATH_BTCOEX_DEF_BT_PERIOD));
+}
+
+/*
+ * Generic tsf based hw timer which configures weight
+ * registers to time slice between wlan and bt traffic
+ */
+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;
+
+       ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX,
+                 "no stomp timer running \n");
+
+       spin_lock_bh(&btcoex->btcoex_lock);
+
+       if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW)
+               ath9k_btcoex_bt_stomp(sc, ATH_BTCOEX_STOMP_NONE);
+        else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL)
+               ath9k_btcoex_bt_stomp(sc, ATH_BTCOEX_STOMP_LOW);
+
+       spin_unlock_bh(&btcoex->btcoex_lock);
+}
+
+int ath_init_btcoex_timer(struct ath_softc *sc)
+{
+       struct ath_btcoex *btcoex = &sc->btcoex;
+
+       btcoex->btcoex_period = ATH_BTCOEX_DEF_BT_PERIOD * 1000;
+       btcoex->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) *
+               btcoex->btcoex_period / 100;
+
+       setup_timer(&btcoex->period_timer, ath_btcoex_period_timer,
+                       (unsigned long) sc);
+
+       spin_lock_init(&btcoex->btcoex_lock);
+
+       btcoex->no_stomp_timer = ath_gen_timer_alloc(sc->sc_ah,
+                       ath_btcoex_no_stomp_timer,
+                       ath_btcoex_no_stomp_timer,
+                       (void *) sc, AR_FIRST_NDP_TIMER);
+
+       if (!btcoex->no_stomp_timer)
+               return -ENOMEM;
+
+       return 0;
+}
+
+/*
+ * (Re)start btcoex timers
+ */
+void ath9k_btcoex_timer_resume(struct ath_softc *sc)
+{
+       struct ath_btcoex *btcoex = &sc->btcoex;
+       struct ath_hw *ah = sc->sc_ah;
+
+       ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX,
+                 "Starting btcoex timers");
+
+       /* make sure duty cycle timer is also stopped when resuming */
+       if (btcoex->hw_timer_enabled)
+               ath9k_gen_timer_stop(sc->sc_ah, btcoex->no_stomp_timer);
+
+       btcoex->bt_priority_cnt = 0;
+       btcoex->bt_priority_time = jiffies;
+       sc->sc_flags &= ~SC_OP_BT_PRIORITY_DETECTED;
+
+       mod_timer(&btcoex->period_timer, jiffies);
+}
+
+
+/*
+ * Pause btcoex timer and bt duty cycle timer
+ */
+void ath9k_btcoex_timer_pause(struct ath_softc *sc)
+{
+       struct ath_btcoex *btcoex = &sc->btcoex;
+       struct ath_hw *ah = sc->sc_ah;
+
+       del_timer_sync(&btcoex->period_timer);
+
+       if (btcoex->hw_timer_enabled)
+               ath9k_gen_timer_stop(ah, btcoex->no_stomp_timer);
+
+       btcoex->hw_timer_enabled = false;
+}
index ae371448b5a0cad6b093b06d64ce3da3bc5e67c7..1a27f39c1adc8e776c3e3cfcb853aca580052288 100644 (file)
@@ -52,28 +52,6 @@ module_exit(ath9k_exit);
 /* Helper Functions */
 /********************/
 
-static u32 ath9k_hw_mac_usec(struct ath_hw *ah, u32 clks)
-{
-       struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
-
-       if (!ah->curchan) /* should really check for CCK instead */
-               return clks / ATH9K_CLOCK_RATE_CCK;
-       if (conf->channel->band == IEEE80211_BAND_2GHZ)
-               return clks / ATH9K_CLOCK_RATE_2GHZ_OFDM;
-
-       return clks / ATH9K_CLOCK_RATE_5GHZ_OFDM;
-}
-
-static u32 ath9k_hw_mac_to_usec(struct ath_hw *ah, u32 clks)
-{
-       struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
-
-       if (conf_is_ht40(conf))
-               return ath9k_hw_mac_usec(ah, clks) / 2;
-       else
-               return ath9k_hw_mac_usec(ah, clks);
-}
-
 static u32 ath9k_hw_mac_clks(struct ath_hw *ah, u32 usecs)
 {
        struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
@@ -343,30 +321,6 @@ static bool ath9k_hw_chip_test(struct ath_hw *ah)
        return true;
 }
 
-static const char *ath9k_hw_devname(u16 devid)
-{
-       switch (devid) {
-       case AR5416_DEVID_PCI:
-               return "Atheros 5416";
-       case AR5416_DEVID_PCIE:
-               return "Atheros 5418";
-       case AR9160_DEVID_PCI:
-               return "Atheros 9160";
-       case AR5416_AR9100_DEVID:
-               return "Atheros 9100";
-       case AR9280_DEVID_PCI:
-       case AR9280_DEVID_PCIE:
-               return "Atheros 9280";
-       case AR9285_DEVID_PCIE:
-               return "Atheros 9285";
-       case AR5416_DEVID_AR9287_PCI:
-       case AR5416_DEVID_AR9287_PCIE:
-               return "Atheros 9287";
-       }
-
-       return NULL;
-}
-
 static void ath9k_hw_init_config(struct ath_hw *ah)
 {
        int i;
@@ -392,7 +346,7 @@ static void ath9k_hw_init_config(struct ath_hw *ah)
                ah->config.spurchans[i][1] = AR_NO_SPUR;
        }
 
-       ah->config.intr_mitigation = true;
+       ah->config.rx_intr_mitigation = true;
 
        /*
         * We need this for PCI devices only (Cardbus, PCI, miniPCI)
@@ -437,8 +391,6 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah)
        ah->beacon_interval = 100;
        ah->enable_32kHz_clock = DONT_USE_32KHZ;
        ah->slottime = (u32) -1;
-       ah->acktimeout = (u32) -1;
-       ah->ctstimeout = (u32) -1;
        ah->globaltxtimeout = (u32) -1;
        ah->power_mode = ATH9K_PM_UNDEFINED;
 }
@@ -1183,7 +1135,7 @@ static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah,
                AR_IMR_RXORN |
                AR_IMR_BCNMISC;
 
-       if (ah->config.intr_mitigation)
+       if (ah->config.rx_intr_mitigation)
                ah->mask_reg |= AR_IMR_RXINTM | AR_IMR_RXMINTR;
        else
                ah->mask_reg |= AR_IMR_RXOK;
@@ -1203,34 +1155,25 @@ static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah,
        }
 }
 
-static bool ath9k_hw_set_ack_timeout(struct ath_hw *ah, u32 us)
+static void ath9k_hw_setslottime(struct ath_hw *ah, u32 us)
 {
-       if (us > ath9k_hw_mac_to_usec(ah, MS(0xffffffff, AR_TIME_OUT_ACK))) {
-               ath_print(ath9k_hw_common(ah), ATH_DBG_RESET,
-                         "bad ack timeout %u\n", us);
-               ah->acktimeout = (u32) -1;
-               return false;
-       } else {
-               REG_RMW_FIELD(ah, AR_TIME_OUT,
-                             AR_TIME_OUT_ACK, ath9k_hw_mac_to_clks(ah, us));
-               ah->acktimeout = us;
-               return true;
-       }
+       u32 val = ath9k_hw_mac_to_clks(ah, us);
+       val = min(val, (u32) 0xFFFF);
+       REG_WRITE(ah, AR_D_GBL_IFS_SLOT, val);
 }
 
-static bool ath9k_hw_set_cts_timeout(struct ath_hw *ah, u32 us)
+static void ath9k_hw_set_ack_timeout(struct ath_hw *ah, u32 us)
 {
-       if (us > ath9k_hw_mac_to_usec(ah, MS(0xffffffff, AR_TIME_OUT_CTS))) {
-               ath_print(ath9k_hw_common(ah), ATH_DBG_RESET,
-                         "bad cts timeout %u\n", us);
-               ah->ctstimeout = (u32) -1;
-               return false;
-       } else {
-               REG_RMW_FIELD(ah, AR_TIME_OUT,
-                             AR_TIME_OUT_CTS, ath9k_hw_mac_to_clks(ah, us));
-               ah->ctstimeout = us;
-               return true;
-       }
+       u32 val = ath9k_hw_mac_to_clks(ah, us);
+       val = min(val, (u32) MS(0xFFFFFFFF, AR_TIME_OUT_ACK));
+       REG_RMW_FIELD(ah, AR_TIME_OUT, AR_TIME_OUT_ACK, val);
+}
+
+static void ath9k_hw_set_cts_timeout(struct ath_hw *ah, u32 us)
+{
+       u32 val = ath9k_hw_mac_to_clks(ah, us);
+       val = min(val, (u32) MS(0xFFFFFFFF, AR_TIME_OUT_CTS));
+       REG_RMW_FIELD(ah, AR_TIME_OUT, AR_TIME_OUT_CTS, val);
 }
 
 static bool ath9k_hw_set_global_txtimeout(struct ath_hw *ah, u32 tu)
@@ -1247,31 +1190,37 @@ static bool ath9k_hw_set_global_txtimeout(struct ath_hw *ah, u32 tu)
        }
 }
 
-static void ath9k_hw_init_user_settings(struct ath_hw *ah)
+void ath9k_hw_init_global_settings(struct ath_hw *ah)
 {
+       struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
+       int acktimeout;
+       int slottime;
+       int sifstime;
+
        ath_print(ath9k_hw_common(ah), ATH_DBG_RESET, "ah->misc_mode 0x%x\n",
                  ah->misc_mode);
 
        if (ah->misc_mode != 0)
                REG_WRITE(ah, AR_PCU_MISC,
                          REG_READ(ah, AR_PCU_MISC) | ah->misc_mode);
-       if (ah->slottime != (u32) -1)
-               ath9k_hw_setslottime(ah, ah->slottime);
-       if (ah->acktimeout != (u32) -1)
-               ath9k_hw_set_ack_timeout(ah, ah->acktimeout);
-       if (ah->ctstimeout != (u32) -1)
-               ath9k_hw_set_cts_timeout(ah, ah->ctstimeout);
+
+       if (conf->channel && conf->channel->band == IEEE80211_BAND_5GHZ)
+               sifstime = 16;
+       else
+               sifstime = 10;
+
+       /* As defined by IEEE 802.11-2007 17.3.8.6 */
+       slottime = ah->slottime + 3 * ah->coverage_class;
+       acktimeout = slottime + sifstime;
+       ath9k_hw_setslottime(ah, slottime);
+       ath9k_hw_set_ack_timeout(ah, acktimeout);
+       ath9k_hw_set_cts_timeout(ah, acktimeout);
        if (ah->globaltxtimeout != (u32) -1)
                ath9k_hw_set_global_txtimeout(ah, ah->globaltxtimeout);
 }
+EXPORT_SYMBOL(ath9k_hw_init_global_settings);
 
-const char *ath9k_hw_probe(u16 vendorid, u16 devid)
-{
-       return vendorid == ATHEROS_VENDOR_ID ?
-               ath9k_hw_devname(devid) : NULL;
-}
-
-void ath9k_hw_detach(struct ath_hw *ah)
+void ath9k_hw_deinit(struct ath_hw *ah)
 {
        struct ath_common *common = ath9k_hw_common(ah);
 
@@ -1289,7 +1238,7 @@ free_hw:
        kfree(ah);
        ah = NULL;
 }
-EXPORT_SYMBOL(ath9k_hw_detach);
+EXPORT_SYMBOL(ath9k_hw_deinit);
 
 /*******/
 /* INI */
@@ -2090,7 +2039,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
        if (ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
                ath9k_enable_rfkill(ah);
 
-       ath9k_hw_init_user_settings(ah);
+       ath9k_hw_init_global_settings(ah);
 
        if (AR_SREV_9287_12_OR_LATER(ah)) {
                REG_WRITE(ah, AR_D_GBL_IFS_SIFS,
@@ -2120,7 +2069,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
 
        REG_WRITE(ah, AR_OBS, 8);
 
-       if (ah->config.intr_mitigation) {
+       if (ah->config.rx_intr_mitigation) {
                REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_LAST, 500);
                REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_FIRST, 2000);
        }
@@ -2780,7 +2729,7 @@ bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked)
 
                *masked = isr & ATH9K_INT_COMMON;
 
-               if (ah->config.intr_mitigation) {
+               if (ah->config.rx_intr_mitigation) {
                        if (isr & (AR_ISR_RXMINTR | AR_ISR_RXINTM))
                                *masked |= ATH9K_INT_RX;
                }
@@ -2913,7 +2862,7 @@ enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints)
        }
        if (ints & ATH9K_INT_RX) {
                mask |= AR_IMR_RXERR;
-               if (ah->config.intr_mitigation)
+               if (ah->config.rx_intr_mitigation)
                        mask |= AR_IMR_RXMINTR | AR_IMR_RXINTM;
                else
                        mask |= AR_IMR_RXOK | AR_IMR_RXDESC;
@@ -3687,21 +3636,6 @@ u64 ath9k_hw_extend_tsf(struct ath_hw *ah, u32 rstamp)
 }
 EXPORT_SYMBOL(ath9k_hw_extend_tsf);
 
-bool ath9k_hw_setslottime(struct ath_hw *ah, u32 us)
-{
-       if (us < ATH9K_SLOT_TIME_9 || us > ath9k_hw_mac_to_usec(ah, 0xffff)) {
-               ath_print(ath9k_hw_common(ah), ATH_DBG_RESET,
-                         "bad slot time %u\n", us);
-               ah->slottime = (u32) -1;
-               return false;
-       } else {
-               REG_WRITE(ah, AR_D_GBL_IFS_SLOT, ath9k_hw_mac_to_clks(ah, us));
-               ah->slottime = us;
-               return true;
-       }
-}
-EXPORT_SYMBOL(ath9k_hw_setslottime);
-
 void ath9k_hw_set11nmac2040(struct ath_hw *ah)
 {
        struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
index e2b0c73a616f30ac5834a6bc0a2abb9b7ce7259a..ab1f1981d857a2a697375f17bad6527ca4ed64c6 100644 (file)
@@ -212,7 +212,7 @@ struct ath9k_ops_config {
        u32 cck_trig_low;
        u32 enable_ani;
        int serialize_regmode;
-       bool intr_mitigation;
+       bool rx_intr_mitigation;
 #define SPUR_DISABLE           0
 #define SPUR_ENABLE_IOCTL      1
 #define SPUR_ENABLE_EEPROM     2
@@ -551,10 +551,9 @@ struct ath_hw {
        u32 *bank6Temp;
 
        int16_t txpower_indexoffset;
+       int coverage_class;
        u32 beacon_interval;
        u32 slottime;
-       u32 acktimeout;
-       u32 ctstimeout;
        u32 globaltxtimeout;
 
        /* ANI */
@@ -616,7 +615,7 @@ static inline struct ath_regulatory *ath9k_hw_regulatory(struct ath_hw *ah)
 
 /* Initialization, Detach, Reset */
 const char *ath9k_hw_probe(u16 vendorid, u16 devid);
-void ath9k_hw_detach(struct ath_hw *ah);
+void ath9k_hw_deinit(struct ath_hw *ah);
 int ath9k_hw_init(struct ath_hw *ah);
 int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
                   bool bChannelChange);
@@ -668,7 +667,7 @@ void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64);
 void ath9k_hw_reset_tsf(struct ath_hw *ah);
 void ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting);
 u64 ath9k_hw_extend_tsf(struct ath_hw *ah, u32 rstamp);
-bool ath9k_hw_setslottime(struct ath_hw *ah, u32 us);
+void ath9k_hw_init_global_settings(struct ath_hw *ah);
 void ath9k_hw_set11nmac2040(struct ath_hw *ah);
 void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period);
 void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah,
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
new file mode 100644 (file)
index 0000000..5f78d7a
--- /dev/null
@@ -0,0 +1,861 @@
+/*
+ * Copyright (c) 2008-2009 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "ath9k.h"
+
+static char *dev_info = "ath9k";
+
+MODULE_AUTHOR("Atheros Communications");
+MODULE_DESCRIPTION("Support for Atheros 802.11n wireless LAN cards.");
+MODULE_SUPPORTED_DEVICE("Atheros 802.11n WLAN cards");
+MODULE_LICENSE("Dual BSD/GPL");
+
+static unsigned int ath9k_debug = ATH_DBG_DEFAULT;
+module_param_named(debug, ath9k_debug, uint, 0);
+MODULE_PARM_DESC(debug, "Debugging mask");
+
+int modparam_nohwcrypt;
+module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444);
+MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption");
+
+/* We use the hw_value as an index into our private channel structure */
+
+#define CHAN2G(_freq, _idx)  { \
+       .center_freq = (_freq), \
+       .hw_value = (_idx), \
+       .max_power = 20, \
+}
+
+#define CHAN5G(_freq, _idx) { \
+       .band = IEEE80211_BAND_5GHZ, \
+       .center_freq = (_freq), \
+       .hw_value = (_idx), \
+       .max_power = 20, \
+}
+
+/* Some 2 GHz radios are actually tunable on 2312-2732
+ * on 5 MHz steps, we support the channels which we know
+ * we have calibration data for all cards though to make
+ * this static */
+static struct ieee80211_channel ath9k_2ghz_chantable[] = {
+       CHAN2G(2412, 0), /* Channel 1 */
+       CHAN2G(2417, 1), /* Channel 2 */
+       CHAN2G(2422, 2), /* Channel 3 */
+       CHAN2G(2427, 3), /* Channel 4 */
+       CHAN2G(2432, 4), /* Channel 5 */
+       CHAN2G(2437, 5), /* Channel 6 */
+       CHAN2G(2442, 6), /* Channel 7 */
+       CHAN2G(2447, 7), /* Channel 8 */
+       CHAN2G(2452, 8), /* Channel 9 */
+       CHAN2G(2457, 9), /* Channel 10 */
+       CHAN2G(2462, 10), /* Channel 11 */
+       CHAN2G(2467, 11), /* Channel 12 */
+       CHAN2G(2472, 12), /* Channel 13 */
+       CHAN2G(2484, 13), /* Channel 14 */
+};
+
+/* Some 5 GHz radios are actually tunable on XXXX-YYYY
+ * on 5 MHz steps, we support the channels which we know
+ * we have calibration data for all cards though to make
+ * this static */
+static struct ieee80211_channel ath9k_5ghz_chantable[] = {
+       /* _We_ call this UNII 1 */
+       CHAN5G(5180, 14), /* Channel 36 */
+       CHAN5G(5200, 15), /* Channel 40 */
+       CHAN5G(5220, 16), /* Channel 44 */
+       CHAN5G(5240, 17), /* Channel 48 */
+       /* _We_ call this UNII 2 */
+       CHAN5G(5260, 18), /* Channel 52 */
+       CHAN5G(5280, 19), /* Channel 56 */
+       CHAN5G(5300, 20), /* Channel 60 */
+       CHAN5G(5320, 21), /* Channel 64 */
+       /* _We_ call this "Middle band" */
+       CHAN5G(5500, 22), /* Channel 100 */
+       CHAN5G(5520, 23), /* Channel 104 */
+       CHAN5G(5540, 24), /* Channel 108 */
+       CHAN5G(5560, 25), /* Channel 112 */
+       CHAN5G(5580, 26), /* Channel 116 */
+       CHAN5G(5600, 27), /* Channel 120 */
+       CHAN5G(5620, 28), /* Channel 124 */
+       CHAN5G(5640, 29), /* Channel 128 */
+       CHAN5G(5660, 30), /* Channel 132 */
+       CHAN5G(5680, 31), /* Channel 136 */
+       CHAN5G(5700, 32), /* Channel 140 */
+       /* _We_ call this UNII 3 */
+       CHAN5G(5745, 33), /* Channel 149 */
+       CHAN5G(5765, 34), /* Channel 153 */
+       CHAN5G(5785, 35), /* Channel 157 */
+       CHAN5G(5805, 36), /* Channel 161 */
+       CHAN5G(5825, 37), /* Channel 165 */
+};
+
+/* Atheros hardware rate code addition for short premble */
+#define SHPCHECK(__hw_rate, __flags) \
+       ((__flags & IEEE80211_RATE_SHORT_PREAMBLE) ? (__hw_rate | 0x04 ) : 0)
+
+#define RATE(_bitrate, _hw_rate, _flags) {              \
+       .bitrate        = (_bitrate),                   \
+       .flags          = (_flags),                     \
+       .hw_value       = (_hw_rate),                   \
+       .hw_value_short = (SHPCHECK(_hw_rate, _flags))  \
+}
+
+static struct ieee80211_rate ath9k_legacy_rates[] = {
+       RATE(10, 0x1b, 0),
+       RATE(20, 0x1a, IEEE80211_RATE_SHORT_PREAMBLE),
+       RATE(55, 0x19, IEEE80211_RATE_SHORT_PREAMBLE),
+       RATE(110, 0x18, IEEE80211_RATE_SHORT_PREAMBLE),
+       RATE(60, 0x0b, 0),
+       RATE(90, 0x0f, 0),
+       RATE(120, 0x0a, 0),
+       RATE(180, 0x0e, 0),
+       RATE(240, 0x09, 0),
+       RATE(360, 0x0d, 0),
+       RATE(480, 0x08, 0),
+       RATE(540, 0x0c, 0),
+};
+
+static void ath9k_deinit_softc(struct ath_softc *sc);
+
+/*
+ * Read and write, they both share the same lock. We do this to serialize
+ * reads and writes on Atheros 802.11n PCI devices only. This is required
+ * as the FIFO on these devices can only accept sanely 2 requests.
+ */
+
+static void ath9k_iowrite32(void *hw_priv, u32 val, u32 reg_offset)
+{
+       struct ath_hw *ah = (struct ath_hw *) hw_priv;
+       struct ath_common *common = ath9k_hw_common(ah);
+       struct ath_softc *sc = (struct ath_softc *) common->priv;
+
+       if (ah->config.serialize_regmode == SER_REG_MODE_ON) {
+               unsigned long flags;
+               spin_lock_irqsave(&sc->sc_serial_rw, flags);
+               iowrite32(val, sc->mem + reg_offset);
+               spin_unlock_irqrestore(&sc->sc_serial_rw, flags);
+       } else
+               iowrite32(val, sc->mem + reg_offset);
+}
+
+static unsigned int ath9k_ioread32(void *hw_priv, u32 reg_offset)
+{
+       struct ath_hw *ah = (struct ath_hw *) hw_priv;
+       struct ath_common *common = ath9k_hw_common(ah);
+       struct ath_softc *sc = (struct ath_softc *) common->priv;
+       u32 val;
+
+       if (ah->config.serialize_regmode == SER_REG_MODE_ON) {
+               unsigned long flags;
+               spin_lock_irqsave(&sc->sc_serial_rw, flags);
+               val = ioread32(sc->mem + reg_offset);
+               spin_unlock_irqrestore(&sc->sc_serial_rw, flags);
+       } else
+               val = ioread32(sc->mem + reg_offset);
+       return val;
+}
+
+static const struct ath_ops ath9k_common_ops = {
+       .read = ath9k_ioread32,
+       .write = ath9k_iowrite32,
+};
+
+/**************************/
+/*     Initialization     */
+/**************************/
+
+static void setup_ht_cap(struct ath_softc *sc,
+                        struct ieee80211_sta_ht_cap *ht_info)
+{
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+       u8 tx_streams, rx_streams;
+
+       ht_info->ht_supported = true;
+       ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
+                      IEEE80211_HT_CAP_SM_PS |
+                      IEEE80211_HT_CAP_SGI_40 |
+                      IEEE80211_HT_CAP_DSSSCCK40;
+
+       ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
+       ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_8;
+
+       /* set up supported mcs set */
+       memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
+       tx_streams = !(common->tx_chainmask & (common->tx_chainmask - 1)) ?
+                    1 : 2;
+       rx_streams = !(common->rx_chainmask & (common->rx_chainmask - 1)) ?
+                    1 : 2;
+
+       if (tx_streams != rx_streams) {
+               ath_print(common, ATH_DBG_CONFIG,
+                         "TX streams %d, RX streams: %d\n",
+                         tx_streams, rx_streams);
+               ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF;
+               ht_info->mcs.tx_params |= ((tx_streams - 1) <<
+                               IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT);
+       }
+
+       ht_info->mcs.rx_mask[0] = 0xff;
+       if (rx_streams >= 2)
+               ht_info->mcs.rx_mask[1] = 0xff;
+
+       ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED;
+}
+
+static int ath9k_reg_notifier(struct wiphy *wiphy,
+                             struct regulatory_request *request)
+{
+       struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
+       struct ath_wiphy *aphy = hw->priv;
+       struct ath_softc *sc = aphy->sc;
+       struct ath_regulatory *reg = ath9k_hw_regulatory(sc->sc_ah);
+
+       return ath_reg_notifier_apply(wiphy, request, reg);
+}
+
+/*
+ *  This function will allocate both the DMA descriptor structure, and the
+ *  buffers it contains.  These are used to contain the descriptors used
+ *  by the system.
+*/
+int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
+                     struct list_head *head, const char *name,
+                     int nbuf, int ndesc)
+{
+#define        DS2PHYS(_dd, _ds)                                               \
+       ((_dd)->dd_desc_paddr + ((caddr_t)(_ds) - (caddr_t)(_dd)->dd_desc))
+#define ATH_DESC_4KB_BOUND_CHECK(_daddr) ((((_daddr) & 0xFFF) > 0xF7F) ? 1 : 0)
+#define ATH_DESC_4KB_BOUND_NUM_SKIPPED(_len) ((_len) / 4096)
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+       struct ath_desc *ds;
+       struct ath_buf *bf;
+       int i, bsize, error;
+
+       ath_print(common, ATH_DBG_CONFIG, "%s DMA: %u buffers %u desc/buf\n",
+                 name, nbuf, ndesc);
+
+       INIT_LIST_HEAD(head);
+       /* ath_desc must be a multiple of DWORDs */
+       if ((sizeof(struct ath_desc) % 4) != 0) {
+               ath_print(common, ATH_DBG_FATAL,
+                         "ath_desc not DWORD aligned\n");
+               BUG_ON((sizeof(struct ath_desc) % 4) != 0);
+               error = -ENOMEM;
+               goto fail;
+       }
+
+       dd->dd_desc_len = sizeof(struct ath_desc) * nbuf * ndesc;
+
+       /*
+        * Need additional DMA memory because we can't use
+        * descriptors that cross the 4K page boundary. Assume
+        * one skipped descriptor per 4K page.
+        */
+       if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_4KB_SPLITTRANS)) {
+               u32 ndesc_skipped =
+                       ATH_DESC_4KB_BOUND_NUM_SKIPPED(dd->dd_desc_len);
+               u32 dma_len;
+
+               while (ndesc_skipped) {
+                       dma_len = ndesc_skipped * sizeof(struct ath_desc);
+                       dd->dd_desc_len += dma_len;
+
+                       ndesc_skipped = ATH_DESC_4KB_BOUND_NUM_SKIPPED(dma_len);
+               };
+       }
+
+       /* allocate descriptors */
+       dd->dd_desc = dma_alloc_coherent(sc->dev, dd->dd_desc_len,
+                                        &dd->dd_desc_paddr, GFP_KERNEL);
+       if (dd->dd_desc == NULL) {
+               error = -ENOMEM;
+               goto fail;
+       }
+       ds = dd->dd_desc;
+       ath_print(common, ATH_DBG_CONFIG, "%s DMA map: %p (%u) -> %llx (%u)\n",
+                 name, ds, (u32) dd->dd_desc_len,
+                 ito64(dd->dd_desc_paddr), /*XXX*/(u32) dd->dd_desc_len);
+
+       /* allocate buffers */
+       bsize = sizeof(struct ath_buf) * nbuf;
+       bf = kzalloc(bsize, GFP_KERNEL);
+       if (bf == NULL) {
+               error = -ENOMEM;
+               goto fail2;
+       }
+       dd->dd_bufptr = bf;
+
+       for (i = 0; i < nbuf; i++, bf++, ds += ndesc) {
+               bf->bf_desc = ds;
+               bf->bf_daddr = DS2PHYS(dd, ds);
+
+               if (!(sc->sc_ah->caps.hw_caps &
+                     ATH9K_HW_CAP_4KB_SPLITTRANS)) {
+                       /*
+                        * Skip descriptor addresses which can cause 4KB
+                        * boundary crossing (addr + length) with a 32 dword
+                        * descriptor fetch.
+                        */
+                       while (ATH_DESC_4KB_BOUND_CHECK(bf->bf_daddr)) {
+                               BUG_ON((caddr_t) bf->bf_desc >=
+                                      ((caddr_t) dd->dd_desc +
+                                       dd->dd_desc_len));
+
+                               ds += ndesc;
+                               bf->bf_desc = ds;
+                               bf->bf_daddr = DS2PHYS(dd, ds);
+                       }
+               }
+               list_add_tail(&bf->list, head);
+       }
+       return 0;
+fail2:
+       dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc,
+                         dd->dd_desc_paddr);
+fail:
+       memset(dd, 0, sizeof(*dd));
+       return error;
+#undef ATH_DESC_4KB_BOUND_CHECK
+#undef ATH_DESC_4KB_BOUND_NUM_SKIPPED
+#undef DS2PHYS
+}
+
+static void ath9k_init_crypto(struct ath_softc *sc)
+{
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+       int i = 0;
+
+       /* Get the hardware key cache size. */
+       common->keymax = sc->sc_ah->caps.keycache_size;
+       if (common->keymax > ATH_KEYMAX) {
+               ath_print(common, ATH_DBG_ANY,
+                         "Warning, using only %u entries in %u key cache\n",
+                         ATH_KEYMAX, common->keymax);
+               common->keymax = ATH_KEYMAX;
+       }
+
+       /*
+        * Reset the key cache since some parts do not
+        * reset the contents on initial power up.
+        */
+       for (i = 0; i < common->keymax; i++)
+               ath9k_hw_keyreset(sc->sc_ah, (u16) i);
+
+       if (ath9k_hw_getcapability(sc->sc_ah, ATH9K_CAP_CIPHER,
+                                  ATH9K_CIPHER_TKIP, NULL)) {
+               /*
+                * Whether we should enable h/w TKIP MIC.
+                * XXX: if we don't support WME TKIP MIC, then we wouldn't
+                * report WMM capable, so it's always safe to turn on
+                * TKIP MIC in this case.
+                */
+               ath9k_hw_setcapability(sc->sc_ah, ATH9K_CAP_TKIP_MIC, 0, 1, NULL);
+       }
+
+       /*
+        * Check whether the separate key cache entries
+        * are required to handle both tx+rx MIC keys.
+        * With split mic keys the number of stations is limited
+        * to 27 otherwise 59.
+        */
+       if (ath9k_hw_getcapability(sc->sc_ah, ATH9K_CAP_CIPHER,
+                                  ATH9K_CIPHER_TKIP, NULL)
+           && ath9k_hw_getcapability(sc->sc_ah, ATH9K_CAP_CIPHER,
+                                     ATH9K_CIPHER_MIC, NULL)
+           && ath9k_hw_getcapability(sc->sc_ah, ATH9K_CAP_TKIP_SPLIT,
+                                     0, NULL))
+               common->splitmic = 1;
+
+       /* turn on mcast key search if possible */
+       if (!ath9k_hw_getcapability(sc->sc_ah, ATH9K_CAP_MCAST_KEYSRCH, 0, NULL))
+               (void)ath9k_hw_setcapability(sc->sc_ah, ATH9K_CAP_MCAST_KEYSRCH,
+                                            1, 1, NULL);
+
+}
+
+static int ath9k_init_btcoex(struct ath_softc *sc)
+{
+       int r, qnum;
+
+       switch (sc->sc_ah->btcoex_hw.scheme) {
+       case ATH_BTCOEX_CFG_NONE:
+               break;
+       case ATH_BTCOEX_CFG_2WIRE:
+               ath9k_hw_btcoex_init_2wire(sc->sc_ah);
+               break;
+       case ATH_BTCOEX_CFG_3WIRE:
+               ath9k_hw_btcoex_init_3wire(sc->sc_ah);
+               r = ath_init_btcoex_timer(sc);
+               if (r)
+                       return -1;
+               qnum = ath_tx_get_qnum(sc, ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BE);
+               ath9k_hw_init_btcoex_hw(sc->sc_ah, qnum);
+               sc->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW;
+               break;
+       default:
+               WARN_ON(1);
+               break;
+       }
+
+       return 0;
+}
+
+static int ath9k_init_queues(struct ath_softc *sc)
+{
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+       int i = 0;
+
+       for (i = 0; i < ARRAY_SIZE(sc->tx.hwq_map); i++)
+               sc->tx.hwq_map[i] = -1;
+
+       sc->beacon.beaconq = ath9k_hw_beaconq_setup(sc->sc_ah);
+       if (sc->beacon.beaconq == -1) {
+               ath_print(common, ATH_DBG_FATAL,
+                         "Unable to setup a beacon xmit queue\n");
+               goto err;
+       }
+
+       sc->beacon.cabq = ath_txq_setup(sc, ATH9K_TX_QUEUE_CAB, 0);
+       if (sc->beacon.cabq == NULL) {
+               ath_print(common, ATH_DBG_FATAL,
+                         "Unable to setup CAB xmit queue\n");
+               goto err;
+       }
+
+       sc->config.cabqReadytime = ATH_CABQ_READY_TIME;
+       ath_cabq_update(sc);
+
+       if (!ath_tx_setup(sc, ATH9K_WME_AC_BK)) {
+               ath_print(common, ATH_DBG_FATAL,
+                         "Unable to setup xmit queue for BK traffic\n");
+               goto err;
+       }
+
+       if (!ath_tx_setup(sc, ATH9K_WME_AC_BE)) {
+               ath_print(common, ATH_DBG_FATAL,
+                         "Unable to setup xmit queue for BE traffic\n");
+               goto err;
+       }
+       if (!ath_tx_setup(sc, ATH9K_WME_AC_VI)) {
+               ath_print(common, ATH_DBG_FATAL,
+                         "Unable to setup xmit queue for VI traffic\n");
+               goto err;
+       }
+       if (!ath_tx_setup(sc, ATH9K_WME_AC_VO)) {
+               ath_print(common, ATH_DBG_FATAL,
+                         "Unable to setup xmit queue for VO traffic\n");
+               goto err;
+       }
+
+       return 0;
+
+err:
+       for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
+               if (ATH_TXQ_SETUP(sc, i))
+                       ath_tx_cleanupq(sc, &sc->tx.txq[i]);
+
+       return -EIO;
+}
+
+static void ath9k_init_channels_rates(struct ath_softc *sc)
+{
+       if (test_bit(ATH9K_MODE_11G, sc->sc_ah->caps.wireless_modes)) {
+               sc->sbands[IEEE80211_BAND_2GHZ].channels = ath9k_2ghz_chantable;
+               sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ;
+               sc->sbands[IEEE80211_BAND_2GHZ].n_channels =
+                       ARRAY_SIZE(ath9k_2ghz_chantable);
+               sc->sbands[IEEE80211_BAND_2GHZ].bitrates = ath9k_legacy_rates;
+               sc->sbands[IEEE80211_BAND_2GHZ].n_bitrates =
+                       ARRAY_SIZE(ath9k_legacy_rates);
+       }
+
+       if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes)) {
+               sc->sbands[IEEE80211_BAND_5GHZ].channels = ath9k_5ghz_chantable;
+               sc->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ;
+               sc->sbands[IEEE80211_BAND_5GHZ].n_channels =
+                       ARRAY_SIZE(ath9k_5ghz_chantable);
+               sc->sbands[IEEE80211_BAND_5GHZ].bitrates =
+                       ath9k_legacy_rates + 4;
+               sc->sbands[IEEE80211_BAND_5GHZ].n_bitrates =
+                       ARRAY_SIZE(ath9k_legacy_rates) - 4;
+       }
+}
+
+static void ath9k_init_misc(struct ath_softc *sc)
+{
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+       int i = 0;
+
+       common->ani.noise_floor = ATH_DEFAULT_NOISE_FLOOR;
+       setup_timer(&common->ani.timer, ath_ani_calibrate, (unsigned long)sc);
+
+       sc->config.txpowlimit = ATH_TXPOWER_MAX;
+
+       if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) {
+               sc->sc_flags |= SC_OP_TXAGGR;
+               sc->sc_flags |= SC_OP_RXAGGR;
+       }
+
+       common->tx_chainmask = sc->sc_ah->caps.tx_chainmask;
+       common->rx_chainmask = sc->sc_ah->caps.rx_chainmask;
+
+       ath9k_hw_setcapability(sc->sc_ah, ATH9K_CAP_DIVERSITY, 1, true, NULL);
+       sc->rx.defant = ath9k_hw_getdefantenna(sc->sc_ah);
+
+       if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK)
+               memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN);
+
+       sc->beacon.slottime = ATH9K_SLOT_TIME_9;
+
+       for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) {
+               sc->beacon.bslot[i] = NULL;
+               sc->beacon.bslot_aphy[i] = NULL;
+       }
+}
+
+static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid,
+                           const struct ath_bus_ops *bus_ops)
+{
+       struct ath_hw *ah = NULL;
+       struct ath_common *common;
+       int ret = 0, i;
+       int csz = 0;
+
+       ah = kzalloc(sizeof(struct ath_hw), GFP_KERNEL);
+       if (!ah)
+               return -ENOMEM;
+
+       ah->hw_version.devid = devid;
+       ah->hw_version.subsysid = subsysid;
+       sc->sc_ah = ah;
+
+       common = ath9k_hw_common(ah);
+       common->ops = &ath9k_common_ops;
+       common->bus_ops = bus_ops;
+       common->ah = ah;
+       common->hw = sc->hw;
+       common->priv = sc;
+       common->debug_mask = ath9k_debug;
+
+       spin_lock_init(&sc->wiphy_lock);
+       spin_lock_init(&sc->sc_resetlock);
+       spin_lock_init(&sc->sc_serial_rw);
+       spin_lock_init(&sc->sc_pm_lock);
+       mutex_init(&sc->mutex);
+       tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc);
+       tasklet_init(&sc->bcon_tasklet, ath_beacon_tasklet,
+                    (unsigned long)sc);
+
+       /*
+        * Cache line size is used to size and align various
+        * structures used to communicate with the hardware.
+        */
+       ath_read_cachesize(common, &csz);
+       common->cachelsz = csz << 2; /* convert to bytes */
+
+       ret = ath9k_hw_init(ah);
+       if (ret) {
+               ath_print(common, ATH_DBG_FATAL,
+                         "Unable to initialize hardware; "
+                         "initialization status: %d\n", ret);
+               goto err_hw;
+       }
+
+       ret = ath9k_init_debug(ah);
+       if (ret) {
+               ath_print(common, ATH_DBG_FATAL,
+                         "Unable to create debugfs files\n");
+               goto err_debug;
+       }
+
+       ret = ath9k_init_queues(sc);
+       if (ret)
+               goto err_queues;
+
+       ret =  ath9k_init_btcoex(sc);
+       if (ret)
+               goto err_btcoex;
+
+       ath9k_init_crypto(sc);
+       ath9k_init_channels_rates(sc);
+       ath9k_init_misc(sc);
+
+       return 0;
+
+err_btcoex:
+       for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
+               if (ATH_TXQ_SETUP(sc, i))
+                       ath_tx_cleanupq(sc, &sc->tx.txq[i]);
+err_queues:
+       ath9k_exit_debug(ah);
+err_debug:
+       ath9k_hw_deinit(ah);
+err_hw:
+       tasklet_kill(&sc->intr_tq);
+       tasklet_kill(&sc->bcon_tasklet);
+
+       kfree(ah);
+       sc->sc_ah = NULL;
+
+       return ret;
+}
+
+void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
+{
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+
+       hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
+               IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
+               IEEE80211_HW_SIGNAL_DBM |
+               IEEE80211_HW_AMPDU_AGGREGATION |
+               IEEE80211_HW_SUPPORTS_PS |
+               IEEE80211_HW_PS_NULLFUNC_STACK |
+               IEEE80211_HW_SPECTRUM_MGMT;
+
+       if (AR_SREV_9160_10_OR_LATER(sc->sc_ah) || modparam_nohwcrypt)
+               hw->flags |= IEEE80211_HW_MFP_CAPABLE;
+
+       hw->wiphy->interface_modes =
+               BIT(NL80211_IFTYPE_AP) |
+               BIT(NL80211_IFTYPE_STATION) |
+               BIT(NL80211_IFTYPE_ADHOC) |
+               BIT(NL80211_IFTYPE_MESH_POINT);
+
+       hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
+
+       hw->queues = 4;
+       hw->max_rates = 4;
+       hw->channel_change_time = 5000;
+       hw->max_listen_interval = 10;
+       /* Hardware supports 10 but we use 4 */
+       hw->max_rate_tries = 4;
+       hw->sta_data_size = sizeof(struct ath_node);
+       hw->vif_data_size = sizeof(struct ath_vif);
+
+       hw->rate_control_algorithm = "ath9k_rate_control";
+
+       if (test_bit(ATH9K_MODE_11G, sc->sc_ah->caps.wireless_modes))
+               hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
+                       &sc->sbands[IEEE80211_BAND_2GHZ];
+       if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes))
+               hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
+                       &sc->sbands[IEEE80211_BAND_5GHZ];
+
+       if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) {
+               if (test_bit(ATH9K_MODE_11G, sc->sc_ah->caps.wireless_modes))
+                       setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_2GHZ].ht_cap);
+               if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes))
+                       setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_5GHZ].ht_cap);
+       }
+
+       SET_IEEE80211_PERM_ADDR(hw, common->macaddr);
+}
+
+int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid,
+                   const struct ath_bus_ops *bus_ops)
+{
+       struct ieee80211_hw *hw = sc->hw;
+       struct ath_common *common;
+       struct ath_hw *ah;
+       int error = 0;
+       struct ath_regulatory *reg;
+
+       /* Bring up device */
+       error = ath9k_init_softc(devid, sc, subsysid, bus_ops);
+       if (error != 0)
+               goto error_init;
+
+       ah = sc->sc_ah;
+       common = ath9k_hw_common(ah);
+       ath9k_set_hw_capab(sc, hw);
+
+       /* Initialize regulatory */
+       error = ath_regd_init(&common->regulatory, sc->hw->wiphy,
+                             ath9k_reg_notifier);
+       if (error)
+               goto error_regd;
+
+       reg = &common->regulatory;
+
+       /* Setup TX DMA */
+       error = ath_tx_init(sc, ATH_TXBUF);
+       if (error != 0)
+               goto error_tx;
+
+       /* Setup RX DMA */
+       error = ath_rx_init(sc, ATH_RXBUF);
+       if (error != 0)
+               goto error_rx;
+
+       /* Register with mac80211 */
+       error = ieee80211_register_hw(hw);
+       if (error)
+               goto error_register;
+
+       /* Handle world regulatory */
+       if (!ath_is_world_regd(reg)) {
+               error = regulatory_hint(hw->wiphy, reg->alpha2);
+               if (error)
+                       goto error_world;
+       }
+
+       INIT_WORK(&sc->chan_work, ath9k_wiphy_chan_work);
+       INIT_DELAYED_WORK(&sc->wiphy_work, ath9k_wiphy_work);
+       sc->wiphy_scheduler_int = msecs_to_jiffies(500);
+
+       ath_init_leds(sc);
+       ath_start_rfkill_poll(sc);
+
+       return 0;
+
+error_world:
+       ieee80211_unregister_hw(hw);
+error_register:
+       ath_rx_cleanup(sc);
+error_rx:
+       ath_tx_cleanup(sc);
+error_tx:
+       /* Nothing */
+error_regd:
+       ath9k_deinit_softc(sc);
+error_init:
+       return error;
+}
+
+/*****************************/
+/*     De-Initialization     */
+/*****************************/
+
+static void ath9k_deinit_softc(struct ath_softc *sc)
+{
+       int i = 0;
+
+        if ((sc->btcoex.no_stomp_timer) &&
+           sc->sc_ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE)
+               ath_gen_timer_free(sc->sc_ah, sc->btcoex.no_stomp_timer);
+
+       for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
+               if (ATH_TXQ_SETUP(sc, i))
+                       ath_tx_cleanupq(sc, &sc->tx.txq[i]);
+
+       ath9k_exit_debug(sc->sc_ah);
+       ath9k_hw_deinit(sc->sc_ah);
+
+       tasklet_kill(&sc->intr_tq);
+       tasklet_kill(&sc->bcon_tasklet);
+}
+
+void ath9k_deinit_device(struct ath_softc *sc)
+{
+       struct ieee80211_hw *hw = sc->hw;
+       int i = 0;
+
+       ath9k_ps_wakeup(sc);
+
+       wiphy_rfkill_stop_polling(sc->hw->wiphy);
+       ath_deinit_leds(sc);
+
+       for (i = 0; i < sc->num_sec_wiphy; i++) {
+               struct ath_wiphy *aphy = sc->sec_wiphy[i];
+               if (aphy == NULL)
+                       continue;
+               sc->sec_wiphy[i] = NULL;
+               ieee80211_unregister_hw(aphy->hw);
+               ieee80211_free_hw(aphy->hw);
+       }
+       kfree(sc->sec_wiphy);
+
+       ieee80211_unregister_hw(hw);
+       ath_rx_cleanup(sc);
+       ath_tx_cleanup(sc);
+       ath9k_deinit_softc(sc);
+}
+
+void ath_descdma_cleanup(struct ath_softc *sc,
+                        struct ath_descdma *dd,
+                        struct list_head *head)
+{
+       dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc,
+                         dd->dd_desc_paddr);
+
+       INIT_LIST_HEAD(head);
+       kfree(dd->dd_bufptr);
+       memset(dd, 0, sizeof(*dd));
+}
+
+/************************/
+/*     Module Hooks     */
+/************************/
+
+static int __init ath9k_init(void)
+{
+       int error;
+
+       /* Register rate control algorithm */
+       error = ath_rate_control_register();
+       if (error != 0) {
+               printk(KERN_ERR
+                       "ath9k: Unable to register rate control "
+                       "algorithm: %d\n",
+                       error);
+               goto err_out;
+       }
+
+       error = ath9k_debug_create_root();
+       if (error) {
+               printk(KERN_ERR
+                       "ath9k: Unable to create debugfs root: %d\n",
+                       error);
+               goto err_rate_unregister;
+       }
+
+       error = ath_pci_init();
+       if (error < 0) {
+               printk(KERN_ERR
+                       "ath9k: No PCI devices found, driver not installed.\n");
+               error = -ENODEV;
+               goto err_remove_root;
+       }
+
+       error = ath_ahb_init();
+       if (error < 0) {
+               error = -ENODEV;
+               goto err_pci_exit;
+       }
+
+       return 0;
+
+ err_pci_exit:
+       ath_pci_exit();
+
+ err_remove_root:
+       ath9k_debug_remove_root();
+ err_rate_unregister:
+       ath_rate_control_unregister();
+ err_out:
+       return error;
+}
+module_init(ath9k_init);
+
+static void __exit ath9k_exit(void)
+{
+       ath_ahb_exit();
+       ath_pci_exit();
+       ath9k_debug_remove_root();
+       ath_rate_control_unregister();
+       printk(KERN_INFO "%s: Driver unloaded\n", dev_info);
+}
+module_exit(ath9k_exit);
index e185479e295e9407e771b654ee7cfcfecf436ad1..29851e6376a9606a095cc6c2d88ab7078e6b5af6 100644 (file)
@@ -167,6 +167,40 @@ struct ath_rx_status {
 #define ATH9K_RXKEYIX_INVALID  ((u8)-1)
 #define ATH9K_TXKEYIX_INVALID  ((u32)-1)
 
+enum ath9k_phyerr {
+       ATH9K_PHYERR_UNDERRUN             = 0,  /* Transmit underrun */
+       ATH9K_PHYERR_TIMING               = 1,  /* Timing error */
+       ATH9K_PHYERR_PARITY               = 2,  /* Illegal parity */
+       ATH9K_PHYERR_RATE                 = 3,  /* Illegal rate */
+       ATH9K_PHYERR_LENGTH               = 4,  /* Illegal length */
+       ATH9K_PHYERR_RADAR                = 5,  /* Radar detect */
+       ATH9K_PHYERR_SERVICE              = 6,  /* Illegal service */
+       ATH9K_PHYERR_TOR                  = 7,  /* Transmit override receive */
+
+       ATH9K_PHYERR_OFDM_TIMING          = 17,
+       ATH9K_PHYERR_OFDM_SIGNAL_PARITY   = 18,
+       ATH9K_PHYERR_OFDM_RATE_ILLEGAL    = 19,
+       ATH9K_PHYERR_OFDM_LENGTH_ILLEGAL  = 20,
+       ATH9K_PHYERR_OFDM_POWER_DROP      = 21,
+       ATH9K_PHYERR_OFDM_SERVICE         = 22,
+       ATH9K_PHYERR_OFDM_RESTART         = 23,
+       ATH9K_PHYERR_FALSE_RADAR_EXT      = 24,
+
+       ATH9K_PHYERR_CCK_TIMING           = 25,
+       ATH9K_PHYERR_CCK_HEADER_CRC       = 26,
+       ATH9K_PHYERR_CCK_RATE_ILLEGAL     = 27,
+       ATH9K_PHYERR_CCK_SERVICE          = 30,
+       ATH9K_PHYERR_CCK_RESTART          = 31,
+       ATH9K_PHYERR_CCK_LENGTH_ILLEGAL   = 32,
+       ATH9K_PHYERR_CCK_POWER_DROP       = 33,
+
+       ATH9K_PHYERR_HT_CRC_ERROR         = 34,
+       ATH9K_PHYERR_HT_LENGTH_ILLEGAL    = 35,
+       ATH9K_PHYERR_HT_RATE_ILLEGAL      = 36,
+
+       ATH9K_PHYERR_MAX                  = 37,
+};
+
 struct ath_desc {
        u32 ds_link;
        u32 ds_data;
index 643bea35686fe302f582078226bc3d1e3e531c9a..6aaca0026da8355714ba3c2ed1d4b7f52b497f3d 100644 (file)
 #include "ath9k.h"
 #include "btcoex.h"
 
-static char *dev_info = "ath9k";
-
-MODULE_AUTHOR("Atheros Communications");
-MODULE_DESCRIPTION("Support for Atheros 802.11n wireless LAN cards.");
-MODULE_SUPPORTED_DEVICE("Atheros 802.11n WLAN cards");
-MODULE_LICENSE("Dual BSD/GPL");
-
-static int modparam_nohwcrypt;
-module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444);
-MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption");
-
-static unsigned int ath9k_debug = ATH_DBG_DEFAULT;
-module_param_named(debug, ath9k_debug, uint, 0);
-MODULE_PARM_DESC(debug, "Debugging mask");
-
-/* We use the hw_value as an index into our private channel structure */
-
-#define CHAN2G(_freq, _idx)  { \
-       .center_freq = (_freq), \
-       .hw_value = (_idx), \
-       .max_power = 20, \
-}
-
-#define CHAN5G(_freq, _idx) { \
-       .band = IEEE80211_BAND_5GHZ, \
-       .center_freq = (_freq), \
-       .hw_value = (_idx), \
-       .max_power = 20, \
-}
-
-/* Some 2 GHz radios are actually tunable on 2312-2732
- * on 5 MHz steps, we support the channels which we know
- * we have calibration data for all cards though to make
- * this static */
-static struct ieee80211_channel ath9k_2ghz_chantable[] = {
-       CHAN2G(2412, 0), /* Channel 1 */
-       CHAN2G(2417, 1), /* Channel 2 */
-       CHAN2G(2422, 2), /* Channel 3 */
-       CHAN2G(2427, 3), /* Channel 4 */
-       CHAN2G(2432, 4), /* Channel 5 */
-       CHAN2G(2437, 5), /* Channel 6 */
-       CHAN2G(2442, 6), /* Channel 7 */
-       CHAN2G(2447, 7), /* Channel 8 */
-       CHAN2G(2452, 8), /* Channel 9 */
-       CHAN2G(2457, 9), /* Channel 10 */
-       CHAN2G(2462, 10), /* Channel 11 */
-       CHAN2G(2467, 11), /* Channel 12 */
-       CHAN2G(2472, 12), /* Channel 13 */
-       CHAN2G(2484, 13), /* Channel 14 */
-};
-
-/* Some 5 GHz radios are actually tunable on XXXX-YYYY
- * on 5 MHz steps, we support the channels which we know
- * we have calibration data for all cards though to make
- * this static */
-static struct ieee80211_channel ath9k_5ghz_chantable[] = {
-       /* _We_ call this UNII 1 */
-       CHAN5G(5180, 14), /* Channel 36 */
-       CHAN5G(5200, 15), /* Channel 40 */
-       CHAN5G(5220, 16), /* Channel 44 */
-       CHAN5G(5240, 17), /* Channel 48 */
-       /* _We_ call this UNII 2 */
-       CHAN5G(5260, 18), /* Channel 52 */
-       CHAN5G(5280, 19), /* Channel 56 */
-       CHAN5G(5300, 20), /* Channel 60 */
-       CHAN5G(5320, 21), /* Channel 64 */
-       /* _We_ call this "Middle band" */
-       CHAN5G(5500, 22), /* Channel 100 */
-       CHAN5G(5520, 23), /* Channel 104 */
-       CHAN5G(5540, 24), /* Channel 108 */
-       CHAN5G(5560, 25), /* Channel 112 */
-       CHAN5G(5580, 26), /* Channel 116 */
-       CHAN5G(5600, 27), /* Channel 120 */
-       CHAN5G(5620, 28), /* Channel 124 */
-       CHAN5G(5640, 29), /* Channel 128 */
-       CHAN5G(5660, 30), /* Channel 132 */
-       CHAN5G(5680, 31), /* Channel 136 */
-       CHAN5G(5700, 32), /* Channel 140 */
-       /* _We_ call this UNII 3 */
-       CHAN5G(5745, 33), /* Channel 149 */
-       CHAN5G(5765, 34), /* Channel 153 */
-       CHAN5G(5785, 35), /* Channel 157 */
-       CHAN5G(5805, 36), /* Channel 161 */
-       CHAN5G(5825, 37), /* Channel 165 */
-};
-
-/* Atheros hardware rate code addition for short premble */
-#define SHPCHECK(__hw_rate, __flags) \
-       ((__flags & IEEE80211_RATE_SHORT_PREAMBLE) ? (__hw_rate | 0x04 ) : 0)
-
-#define RATE(_bitrate, _hw_rate, _flags) {              \
-       .bitrate        = (_bitrate),                   \
-       .flags          = (_flags),                     \
-       .hw_value       = (_hw_rate),                   \
-       .hw_value_short = (SHPCHECK(_hw_rate, _flags))  \
-}
-
-static struct ieee80211_rate ath9k_legacy_rates[] = {
-       RATE(10, 0x1b, 0),
-       RATE(20, 0x1a, IEEE80211_RATE_SHORT_PREAMBLE),
-       RATE(55, 0x19, IEEE80211_RATE_SHORT_PREAMBLE),
-       RATE(110, 0x18, IEEE80211_RATE_SHORT_PREAMBLE),
-       RATE(60, 0x0b, 0),
-       RATE(90, 0x0f, 0),
-       RATE(120, 0x0a, 0),
-       RATE(180, 0x0e, 0),
-       RATE(240, 0x09, 0),
-       RATE(360, 0x0d, 0),
-       RATE(480, 0x08, 0),
-       RATE(540, 0x0c, 0),
-};
-
 static void ath_cache_conf_rate(struct ath_softc *sc,
                                struct ieee80211_conf *conf)
 {
@@ -221,7 +109,7 @@ static struct ath9k_channel *ath_get_curchannel(struct ath_softc *sc,
        return channel;
 }
 
-static bool ath9k_setpower(struct ath_softc *sc, enum ath9k_power_mode mode)
+bool ath9k_setpower(struct ath_softc *sc, enum ath9k_power_mode mode)
 {
        unsigned long flags;
        bool ret;
@@ -256,10 +144,10 @@ void ath9k_ps_restore(struct ath_softc *sc)
                goto unlock;
 
        if (sc->ps_enabled &&
-           !(sc->sc_flags & (SC_OP_WAIT_FOR_BEACON |
-                             SC_OP_WAIT_FOR_CAB |
-                             SC_OP_WAIT_FOR_PSPOLL_DATA |
-                             SC_OP_WAIT_FOR_TX_ACK)))
+           !(sc->ps_flags & (PS_WAIT_FOR_BEACON |
+                             PS_WAIT_FOR_CAB |
+                             PS_WAIT_FOR_PSPOLL_DATA |
+                             PS_WAIT_FOR_TX_ACK)))
                ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_NETWORK_SLEEP);
 
  unlock:
@@ -349,7 +237,7 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
  *  When the task is complete, it reschedules itself depending on the
  *  appropriate interval that was calculated.
  */
-static void ath_ani_calibrate(unsigned long data)
+void ath_ani_calibrate(unsigned long data)
 {
        struct ath_softc *sc = (struct ath_softc *)data;
        struct ath_hw *ah = sc->sc_ah;
@@ -363,14 +251,6 @@ static void ath_ani_calibrate(unsigned long data)
        short_cal_interval = (ah->opmode == NL80211_IFTYPE_AP) ?
                ATH_AP_SHORT_CALINTERVAL : ATH_STA_SHORT_CALINTERVAL;
 
-       /*
-       * don't calibrate when we're scanning.
-       * we are most likely not on our home channel.
-       */
-       spin_lock(&sc->ani_lock);
-       if (sc->sc_flags & SC_OP_SCANNING)
-               goto set_timer;
-
        /* Only calibrate if awake */
        if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE)
                goto set_timer;
@@ -437,7 +317,6 @@ static void ath_ani_calibrate(unsigned long data)
        ath9k_ps_restore(sc);
 
 set_timer:
-       spin_unlock(&sc->ani_lock);
        /*
        * Set timer interval based on previous results.
        * The interval must be the shortest necessary to satisfy ANI,
@@ -513,7 +392,7 @@ static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta)
                ath_tx_node_cleanup(sc, an);
 }
 
-static void ath9k_tasklet(unsigned long data)
+void ath9k_tasklet(unsigned long data)
 {
        struct ath_softc *sc = (struct ath_softc *)data;
        struct ath_hw *ah = sc->sc_ah;
@@ -545,7 +424,7 @@ static void ath9k_tasklet(unsigned long data)
                 */
                ath_print(common, ATH_DBG_PS,
                          "TSFOOR - Sync with next Beacon\n");
-               sc->sc_flags |= SC_OP_WAIT_FOR_BEACON | SC_OP_BEACON_SYNC;
+               sc->ps_flags |= PS_WAIT_FOR_BEACON | PS_BEACON_SYNC;
        }
 
        if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE)
@@ -646,7 +525,7 @@ irqreturn_t ath_isr(int irq, void *dev)
                         * receive frames */
                        ath9k_setpower(sc, ATH9K_PM_AWAKE);
                        ath9k_hw_setrxabort(sc->sc_ah, 0);
-                       sc->sc_flags |= SC_OP_WAIT_FOR_BEACON;
+                       sc->ps_flags |= PS_WAIT_FOR_BEACON;
                }
 
 chip_reset:
@@ -933,44 +812,6 @@ static void ath_key_delete(struct ath_common *common, struct ieee80211_key_conf
        }
 }
 
-static void setup_ht_cap(struct ath_softc *sc,
-                        struct ieee80211_sta_ht_cap *ht_info)
-{
-       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
-       u8 tx_streams, rx_streams;
-
-       ht_info->ht_supported = true;
-       ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
-                      IEEE80211_HT_CAP_SM_PS |
-                      IEEE80211_HT_CAP_SGI_40 |
-                      IEEE80211_HT_CAP_DSSSCCK40;
-
-       ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
-       ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_8;
-
-       /* set up supported mcs set */
-       memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
-       tx_streams = !(common->tx_chainmask & (common->tx_chainmask - 1)) ?
-                    1 : 2;
-       rx_streams = !(common->rx_chainmask & (common->rx_chainmask - 1)) ?
-                    1 : 2;
-
-       if (tx_streams != rx_streams) {
-               ath_print(common, ATH_DBG_CONFIG,
-                         "TX streams %d, RX streams: %d\n",
-                         tx_streams, rx_streams);
-               ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF;
-               ht_info->mcs.tx_params |= ((tx_streams - 1) <<
-                               IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT);
-       }
-
-       ht_info->mcs.rx_mask[0] = 0xff;
-       if (rx_streams >= 2)
-               ht_info->mcs.rx_mask[1] = 0xff;
-
-       ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED;
-}
-
 static void ath9k_bss_assoc_info(struct ath_softc *sc,
                                 struct ieee80211_vif *vif,
                                 struct ieee80211_bss_conf *bss_conf)
@@ -992,7 +833,7 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc,
                 * on the receipt of the first Beacon frame (i.e.,
                 * after time sync with the AP).
                 */
-               sc->sc_flags |= SC_OP_BEACON_SYNC;
+               sc->ps_flags |= PS_BEACON_SYNC;
 
                /* Configure the beacon */
                ath_beacon_config(sc, vif);
@@ -1009,174 +850,6 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc,
        }
 }
 
-/********************************/
-/*      LED functions          */
-/********************************/
-
-static void ath_led_blink_work(struct work_struct *work)
-{
-       struct ath_softc *sc = container_of(work, struct ath_softc,
-                                           ath_led_blink_work.work);
-
-       if (!(sc->sc_flags & SC_OP_LED_ASSOCIATED))
-               return;
-
-       if ((sc->led_on_duration == ATH_LED_ON_DURATION_IDLE) ||
-           (sc->led_off_duration == ATH_LED_OFF_DURATION_IDLE))
-               ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 0);
-       else
-               ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin,
-                                 (sc->sc_flags & SC_OP_LED_ON) ? 1 : 0);
-
-       ieee80211_queue_delayed_work(sc->hw,
-                                    &sc->ath_led_blink_work,
-                                    (sc->sc_flags & SC_OP_LED_ON) ?
-                                       msecs_to_jiffies(sc->led_off_duration) :
-                                       msecs_to_jiffies(sc->led_on_duration));
-
-       sc->led_on_duration = sc->led_on_cnt ?
-                       max((ATH_LED_ON_DURATION_IDLE - sc->led_on_cnt), 25) :
-                       ATH_LED_ON_DURATION_IDLE;
-       sc->led_off_duration = sc->led_off_cnt ?
-                       max((ATH_LED_OFF_DURATION_IDLE - sc->led_off_cnt), 10) :
-                       ATH_LED_OFF_DURATION_IDLE;
-       sc->led_on_cnt = sc->led_off_cnt = 0;
-       if (sc->sc_flags & SC_OP_LED_ON)
-               sc->sc_flags &= ~SC_OP_LED_ON;
-       else
-               sc->sc_flags |= SC_OP_LED_ON;
-}
-
-static void ath_led_brightness(struct led_classdev *led_cdev,
-                              enum led_brightness brightness)
-{
-       struct ath_led *led = container_of(led_cdev, struct ath_led, led_cdev);
-       struct ath_softc *sc = led->sc;
-
-       switch (brightness) {
-       case LED_OFF:
-               if (led->led_type == ATH_LED_ASSOC ||
-                   led->led_type == ATH_LED_RADIO) {
-                       ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin,
-                               (led->led_type == ATH_LED_RADIO));
-                       sc->sc_flags &= ~SC_OP_LED_ASSOCIATED;
-                       if (led->led_type == ATH_LED_RADIO)
-                               sc->sc_flags &= ~SC_OP_LED_ON;
-               } else {
-                       sc->led_off_cnt++;
-               }
-               break;
-       case LED_FULL:
-               if (led->led_type == ATH_LED_ASSOC) {
-                       sc->sc_flags |= SC_OP_LED_ASSOCIATED;
-                       ieee80211_queue_delayed_work(sc->hw,
-                                                    &sc->ath_led_blink_work, 0);
-               } else if (led->led_type == ATH_LED_RADIO) {
-                       ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 0);
-                       sc->sc_flags |= SC_OP_LED_ON;
-               } else {
-                       sc->led_on_cnt++;
-               }
-               break;
-       default:
-               break;
-       }
-}
-
-static int ath_register_led(struct ath_softc *sc, struct ath_led *led,
-                           char *trigger)
-{
-       int ret;
-
-       led->sc = sc;
-       led->led_cdev.name = led->name;
-       led->led_cdev.default_trigger = trigger;
-       led->led_cdev.brightness_set = ath_led_brightness;
-
-       ret = led_classdev_register(wiphy_dev(sc->hw->wiphy), &led->led_cdev);
-       if (ret)
-               ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
-                         "Failed to register led:%s", led->name);
-       else
-               led->registered = 1;
-       return ret;
-}
-
-static void ath_unregister_led(struct ath_led *led)
-{
-       if (led->registered) {
-               led_classdev_unregister(&led->led_cdev);
-               led->registered = 0;
-       }
-}
-
-static void ath_deinit_leds(struct ath_softc *sc)
-{
-       ath_unregister_led(&sc->assoc_led);
-       sc->sc_flags &= ~SC_OP_LED_ASSOCIATED;
-       ath_unregister_led(&sc->tx_led);
-       ath_unregister_led(&sc->rx_led);
-       ath_unregister_led(&sc->radio_led);
-       ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1);
-}
-
-static void ath_init_leds(struct ath_softc *sc)
-{
-       char *trigger;
-       int ret;
-
-       if (AR_SREV_9287(sc->sc_ah))
-               sc->sc_ah->led_pin = ATH_LED_PIN_9287;
-       else
-               sc->sc_ah->led_pin = ATH_LED_PIN_DEF;
-
-       /* Configure gpio 1 for output */
-       ath9k_hw_cfg_output(sc->sc_ah, sc->sc_ah->led_pin,
-                           AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
-       /* LED off, active low */
-       ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1);
-
-       INIT_DELAYED_WORK(&sc->ath_led_blink_work, ath_led_blink_work);
-
-       trigger = ieee80211_get_radio_led_name(sc->hw);
-       snprintf(sc->radio_led.name, sizeof(sc->radio_led.name),
-               "ath9k-%s::radio", wiphy_name(sc->hw->wiphy));
-       ret = ath_register_led(sc, &sc->radio_led, trigger);
-       sc->radio_led.led_type = ATH_LED_RADIO;
-       if (ret)
-               goto fail;
-
-       trigger = ieee80211_get_assoc_led_name(sc->hw);
-       snprintf(sc->assoc_led.name, sizeof(sc->assoc_led.name),
-               "ath9k-%s::assoc", wiphy_name(sc->hw->wiphy));
-       ret = ath_register_led(sc, &sc->assoc_led, trigger);
-       sc->assoc_led.led_type = ATH_LED_ASSOC;
-       if (ret)
-               goto fail;
-
-       trigger = ieee80211_get_tx_led_name(sc->hw);
-       snprintf(sc->tx_led.name, sizeof(sc->tx_led.name),
-               "ath9k-%s::tx", wiphy_name(sc->hw->wiphy));
-       ret = ath_register_led(sc, &sc->tx_led, trigger);
-       sc->tx_led.led_type = ATH_LED_TX;
-       if (ret)
-               goto fail;
-
-       trigger = ieee80211_get_rx_led_name(sc->hw);
-       snprintf(sc->rx_led.name, sizeof(sc->rx_led.name),
-               "ath9k-%s::rx", wiphy_name(sc->hw->wiphy));
-       ret = ath_register_led(sc, &sc->rx_led, trigger);
-       sc->rx_led.led_type = ATH_LED_RX;
-       if (ret)
-               goto fail;
-
-       return;
-
-fail:
-       cancel_delayed_work_sync(&sc->ath_led_blink_work);
-       ath_deinit_leds(sc);
-}
-
 void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw)
 {
        struct ath_hw *ah = sc->sc_ah;
@@ -1261,711 +934,6 @@ void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw)
        ath9k_setpower(sc, ATH9K_PM_FULL_SLEEP);
 }
 
-/*******************/
-/*     Rfkill     */
-/*******************/
-
-static bool ath_is_rfkill_set(struct ath_softc *sc)
-{
-       struct ath_hw *ah = sc->sc_ah;
-
-       return ath9k_hw_gpio_get(ah, ah->rfkill_gpio) ==
-                                 ah->rfkill_polarity;
-}
-
-static void ath9k_rfkill_poll_state(struct ieee80211_hw *hw)
-{
-       struct ath_wiphy *aphy = hw->priv;
-       struct ath_softc *sc = aphy->sc;
-       bool blocked = !!ath_is_rfkill_set(sc);
-
-       wiphy_rfkill_set_hw_state(hw->wiphy, blocked);
-}
-
-static void ath_start_rfkill_poll(struct ath_softc *sc)
-{
-       struct ath_hw *ah = sc->sc_ah;
-
-       if (ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
-               wiphy_rfkill_start_polling(sc->hw->wiphy);
-}
-
-static void ath9k_uninit_hw(struct ath_softc *sc)
-{
-       struct ath_hw *ah = sc->sc_ah;
-
-       BUG_ON(!ah);
-
-       ath9k_exit_debug(ah);
-       ath9k_hw_detach(ah);
-       sc->sc_ah = NULL;
-}
-
-static void ath_clean_core(struct ath_softc *sc)
-{
-       struct ieee80211_hw *hw = sc->hw;
-       struct ath_hw *ah = sc->sc_ah;
-       int i = 0;
-
-       ath9k_ps_wakeup(sc);
-
-       dev_dbg(sc->dev, "Detach ATH hw\n");
-
-       ath_deinit_leds(sc);
-       wiphy_rfkill_stop_polling(sc->hw->wiphy);
-
-       for (i = 0; i < sc->num_sec_wiphy; i++) {
-               struct ath_wiphy *aphy = sc->sec_wiphy[i];
-               if (aphy == NULL)
-                       continue;
-               sc->sec_wiphy[i] = NULL;
-               ieee80211_unregister_hw(aphy->hw);
-               ieee80211_free_hw(aphy->hw);
-       }
-       ieee80211_unregister_hw(hw);
-       ath_rx_cleanup(sc);
-       ath_tx_cleanup(sc);
-
-       tasklet_kill(&sc->intr_tq);
-       tasklet_kill(&sc->bcon_tasklet);
-
-       if (!(sc->sc_flags & SC_OP_INVALID))
-               ath9k_setpower(sc, ATH9K_PM_AWAKE);
-
-       /* cleanup tx queues */
-       for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
-               if (ATH_TXQ_SETUP(sc, i))
-                       ath_tx_cleanupq(sc, &sc->tx.txq[i]);
-
-       if ((sc->btcoex.no_stomp_timer) &&
-           ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE)
-               ath_gen_timer_free(ah, sc->btcoex.no_stomp_timer);
-}
-
-void ath_detach(struct ath_softc *sc)
-{
-       ath_clean_core(sc);
-       ath9k_uninit_hw(sc);
-}
-
-void ath_cleanup(struct ath_softc *sc)
-{
-       struct ath_hw *ah = sc->sc_ah;
-       struct ath_common *common = ath9k_hw_common(ah);
-
-       ath_clean_core(sc);
-       free_irq(sc->irq, sc);
-       ath_bus_cleanup(common);
-       kfree(sc->sec_wiphy);
-       ieee80211_free_hw(sc->hw);
-
-       ath9k_uninit_hw(sc);
-}
-
-static int ath9k_reg_notifier(struct wiphy *wiphy,
-                             struct regulatory_request *request)
-{
-       struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
-       struct ath_wiphy *aphy = hw->priv;
-       struct ath_softc *sc = aphy->sc;
-       struct ath_regulatory *reg = ath9k_hw_regulatory(sc->sc_ah);
-
-       return ath_reg_notifier_apply(wiphy, request, reg);
-}
-
-/*
- * Detects if there is any priority bt traffic
- */
-static void ath_detect_bt_priority(struct ath_softc *sc)
-{
-       struct ath_btcoex *btcoex = &sc->btcoex;
-       struct ath_hw *ah = sc->sc_ah;
-
-       if (ath9k_hw_gpio_get(sc->sc_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))) {
-               if (btcoex->bt_priority_cnt >= ATH_BT_CNT_THRESHOLD) {
-                       ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_BTCOEX,
-                                 "BT priority traffic detected");
-                       sc->sc_flags |= SC_OP_BT_PRIORITY_DETECTED;
-               } else {
-                       sc->sc_flags &= ~SC_OP_BT_PRIORITY_DETECTED;
-               }
-
-               btcoex->bt_priority_cnt = 0;
-               btcoex->bt_priority_time = jiffies;
-       }
-}
-
-/*
- * 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,
-                                 u32 timer_period)
-{
-       struct ath_common *common = ath9k_hw_common(ah);
-       struct ath_softc *sc = (struct ath_softc *) common->priv;
-
-       ath9k_hw_gen_timer_start(ah, timer, timer_next, timer_period);
-
-       if ((sc->imask & ATH9K_INT_GENTIMER) == 0) {
-               ath9k_hw_set_interrupts(ah, 0);
-               sc->imask |= ATH9K_INT_GENTIMER;
-               ath9k_hw_set_interrupts(ah, sc->imask);
-       }
-}
-
-static void ath9k_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer)
-{
-       struct ath_common *common = ath9k_hw_common(ah);
-       struct ath_softc *sc = (struct ath_softc *) common->priv;
-       struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers;
-
-       ath9k_hw_gen_timer_stop(ah, timer);
-
-       /* if no timer is enabled, turn off interrupt mask */
-       if (timer_table->timer_mask.val == 0) {
-               ath9k_hw_set_interrupts(ah, 0);
-               sc->imask &= ~ATH9K_INT_GENTIMER;
-               ath9k_hw_set_interrupts(ah, sc->imask);
-       }
-}
-
-/*
- * This is the master bt coex timer 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_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;
-
-       ath_detect_bt_priority(sc);
-
-       spin_lock_bh(&btcoex->btcoex_lock);
-
-       ath9k_btcoex_bt_stomp(sc, btcoex->bt_stomp_type);
-
-       spin_unlock_bh(&btcoex->btcoex_lock);
-
-       if (btcoex->btcoex_period != btcoex->btcoex_no_stomp) {
-               if (btcoex->hw_timer_enabled)
-                       ath9k_gen_timer_stop(ah, btcoex->no_stomp_timer);
-
-               ath9k_gen_timer_start(ah,
-                                     btcoex->no_stomp_timer,
-                                     (ath9k_hw_gettsf32(ah) +
-                                      btcoex->btcoex_no_stomp),
-                                      btcoex->btcoex_no_stomp * 10);
-               btcoex->hw_timer_enabled = true;
-       }
-
-       mod_timer(&btcoex->period_timer, jiffies +
-                                 msecs_to_jiffies(ATH_BTCOEX_DEF_BT_PERIOD));
-}
-
-/*
- * Generic tsf based hw timer which configures weight
- * registers to time slice between wlan and bt traffic
- */
-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;
-
-       ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX,
-                 "no stomp timer running \n");
-
-       spin_lock_bh(&btcoex->btcoex_lock);
-
-       if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW)
-               ath9k_btcoex_bt_stomp(sc, ATH_BTCOEX_STOMP_NONE);
-        else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL)
-               ath9k_btcoex_bt_stomp(sc, ATH_BTCOEX_STOMP_LOW);
-
-       spin_unlock_bh(&btcoex->btcoex_lock);
-}
-
-static int ath_init_btcoex_timer(struct ath_softc *sc)
-{
-       struct ath_btcoex *btcoex = &sc->btcoex;
-
-       btcoex->btcoex_period = ATH_BTCOEX_DEF_BT_PERIOD * 1000;
-       btcoex->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) *
-               btcoex->btcoex_period / 100;
-
-       setup_timer(&btcoex->period_timer, ath_btcoex_period_timer,
-                       (unsigned long) sc);
-
-       spin_lock_init(&btcoex->btcoex_lock);
-
-       btcoex->no_stomp_timer = ath_gen_timer_alloc(sc->sc_ah,
-                       ath_btcoex_no_stomp_timer,
-                       ath_btcoex_no_stomp_timer,
-                       (void *) sc, AR_FIRST_NDP_TIMER);
-
-       if (!btcoex->no_stomp_timer)
-               return -ENOMEM;
-
-       return 0;
-}
-
-/*
- * Read and write, they both share the same lock. We do this to serialize
- * reads and writes on Atheros 802.11n PCI devices only. This is required
- * as the FIFO on these devices can only accept sanely 2 requests. After
- * that the device goes bananas. Serializing the reads/writes prevents this
- * from happening.
- */
-
-static void ath9k_iowrite32(void *hw_priv, u32 val, u32 reg_offset)
-{
-       struct ath_hw *ah = (struct ath_hw *) hw_priv;
-       struct ath_common *common = ath9k_hw_common(ah);
-       struct ath_softc *sc = (struct ath_softc *) common->priv;
-
-       if (ah->config.serialize_regmode == SER_REG_MODE_ON) {
-               unsigned long flags;
-               spin_lock_irqsave(&sc->sc_serial_rw, flags);
-               iowrite32(val, sc->mem + reg_offset);
-               spin_unlock_irqrestore(&sc->sc_serial_rw, flags);
-       } else
-               iowrite32(val, sc->mem + reg_offset);
-}
-
-static unsigned int ath9k_ioread32(void *hw_priv, u32 reg_offset)
-{
-       struct ath_hw *ah = (struct ath_hw *) hw_priv;
-       struct ath_common *common = ath9k_hw_common(ah);
-       struct ath_softc *sc = (struct ath_softc *) common->priv;
-       u32 val;
-
-       if (ah->config.serialize_regmode == SER_REG_MODE_ON) {
-               unsigned long flags;
-               spin_lock_irqsave(&sc->sc_serial_rw, flags);
-               val = ioread32(sc->mem + reg_offset);
-               spin_unlock_irqrestore(&sc->sc_serial_rw, flags);
-       } else
-               val = ioread32(sc->mem + reg_offset);
-       return val;
-}
-
-static const struct ath_ops ath9k_common_ops = {
-       .read = ath9k_ioread32,
-       .write = ath9k_iowrite32,
-};
-
-/*
- * Initialize and fill ath_softc, ath_sofct is the
- * "Software Carrier" struct. Historically it has existed
- * to allow the separation between hardware specific
- * variables (now in ath_hw) and driver specific variables.
- */
-static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid,
-                         const struct ath_bus_ops *bus_ops)
-{
-       struct ath_hw *ah = NULL;
-       struct ath_common *common;
-       int r = 0, i;
-       int csz = 0;
-       int qnum;
-
-       /* XXX: hardware will not be ready until ath_open() being called */
-       sc->sc_flags |= SC_OP_INVALID;
-
-       spin_lock_init(&sc->wiphy_lock);
-       spin_lock_init(&sc->sc_resetlock);
-       spin_lock_init(&sc->sc_serial_rw);
-       spin_lock_init(&sc->ani_lock);
-       spin_lock_init(&sc->sc_pm_lock);
-       mutex_init(&sc->mutex);
-       tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc);
-       tasklet_init(&sc->bcon_tasklet, ath_beacon_tasklet,
-                    (unsigned long)sc);
-
-       ah = kzalloc(sizeof(struct ath_hw), GFP_KERNEL);
-       if (!ah)
-               return -ENOMEM;
-
-       ah->hw_version.devid = devid;
-       ah->hw_version.subsysid = subsysid;
-       sc->sc_ah = ah;
-
-       common = ath9k_hw_common(ah);
-       common->ops = &ath9k_common_ops;
-       common->bus_ops = bus_ops;
-       common->ah = ah;
-       common->hw = sc->hw;
-       common->priv = sc;
-       common->debug_mask = ath9k_debug;
-
-       /*
-        * Cache line size is used to size and align various
-        * structures used to communicate with the hardware.
-        */
-       ath_read_cachesize(common, &csz);
-       /* XXX assert csz is non-zero */
-       common->cachelsz = csz << 2;    /* convert to bytes */
-
-       r = ath9k_hw_init(ah);
-       if (r) {
-               ath_print(common, ATH_DBG_FATAL,
-                         "Unable to initialize hardware; "
-                         "initialization status: %d\n", r);
-               goto bad_free_hw;
-       }
-
-       if (ath9k_init_debug(ah) < 0) {
-               ath_print(common, ATH_DBG_FATAL,
-                         "Unable to create debugfs files\n");
-               goto bad_free_hw;
-       }
-
-       /* Get the hardware key cache size. */
-       common->keymax = ah->caps.keycache_size;
-       if (common->keymax > ATH_KEYMAX) {
-               ath_print(common, ATH_DBG_ANY,
-                         "Warning, using only %u entries in %u key cache\n",
-                         ATH_KEYMAX, common->keymax);
-               common->keymax = ATH_KEYMAX;
-       }
-
-       /*
-        * Reset the key cache since some parts do not
-        * reset the contents on initial power up.
-        */
-       for (i = 0; i < common->keymax; i++)
-               ath9k_hw_keyreset(ah, (u16) i);
-
-       /* default to MONITOR mode */
-       sc->sc_ah->opmode = NL80211_IFTYPE_MONITOR;
-
-       /*
-        * Allocate hardware transmit queues: one queue for
-        * beacon frames and one data queue for each QoS
-        * priority.  Note that the hal handles reseting
-        * these queues at the needed time.
-        */
-       sc->beacon.beaconq = ath9k_hw_beaconq_setup(ah);
-       if (sc->beacon.beaconq == -1) {
-               ath_print(common, ATH_DBG_FATAL,
-                         "Unable to setup a beacon xmit queue\n");
-               r = -EIO;
-               goto bad2;
-       }
-       sc->beacon.cabq = ath_txq_setup(sc, ATH9K_TX_QUEUE_CAB, 0);
-       if (sc->beacon.cabq == NULL) {
-               ath_print(common, ATH_DBG_FATAL,
-                         "Unable to setup CAB xmit queue\n");
-               r = -EIO;
-               goto bad2;
-       }
-
-       sc->config.cabqReadytime = ATH_CABQ_READY_TIME;
-       ath_cabq_update(sc);
-
-       for (i = 0; i < ARRAY_SIZE(sc->tx.hwq_map); i++)
-               sc->tx.hwq_map[i] = -1;
-
-       /* Setup data queues */
-       /* NB: ensure BK queue is the lowest priority h/w queue */
-       if (!ath_tx_setup(sc, ATH9K_WME_AC_BK)) {
-               ath_print(common, ATH_DBG_FATAL,
-                         "Unable to setup xmit queue for BK traffic\n");
-               r = -EIO;
-               goto bad2;
-       }
-
-       if (!ath_tx_setup(sc, ATH9K_WME_AC_BE)) {
-               ath_print(common, ATH_DBG_FATAL,
-                         "Unable to setup xmit queue for BE traffic\n");
-               r = -EIO;
-               goto bad2;
-       }
-       if (!ath_tx_setup(sc, ATH9K_WME_AC_VI)) {
-               ath_print(common, ATH_DBG_FATAL,
-                         "Unable to setup xmit queue for VI traffic\n");
-               r = -EIO;
-               goto bad2;
-       }
-       if (!ath_tx_setup(sc, ATH9K_WME_AC_VO)) {
-               ath_print(common, ATH_DBG_FATAL,
-                         "Unable to setup xmit queue for VO traffic\n");
-               r = -EIO;
-               goto bad2;
-       }
-
-       /* Initializes the noise floor to a reasonable default value.
-        * Later on this will be updated during ANI processing. */
-
-       common->ani.noise_floor = ATH_DEFAULT_NOISE_FLOOR;
-       setup_timer(&common->ani.timer, ath_ani_calibrate, (unsigned long)sc);
-
-       if (ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER,
-                                  ATH9K_CIPHER_TKIP, NULL)) {
-               /*
-                * Whether we should enable h/w TKIP MIC.
-                * XXX: if we don't support WME TKIP MIC, then we wouldn't
-                * report WMM capable, so it's always safe to turn on
-                * TKIP MIC in this case.
-                */
-               ath9k_hw_setcapability(sc->sc_ah, ATH9K_CAP_TKIP_MIC,
-                                      0, 1, NULL);
-       }
-
-       /*
-        * Check whether the separate key cache entries
-        * are required to handle both tx+rx MIC keys.
-        * With split mic keys the number of stations is limited
-        * to 27 otherwise 59.
-        */
-       if (ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER,
-                                  ATH9K_CIPHER_TKIP, NULL)
-           && ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER,
-                                     ATH9K_CIPHER_MIC, NULL)
-           && ath9k_hw_getcapability(ah, ATH9K_CAP_TKIP_SPLIT,
-                                     0, NULL))
-               common->splitmic = 1;
-
-       /* turn on mcast key search if possible */
-       if (!ath9k_hw_getcapability(ah, ATH9K_CAP_MCAST_KEYSRCH, 0, NULL))
-               (void)ath9k_hw_setcapability(ah, ATH9K_CAP_MCAST_KEYSRCH, 1,
-                                            1, NULL);
-
-       sc->config.txpowlimit = ATH_TXPOWER_MAX;
-
-       /* 11n Capabilities */
-       if (ah->caps.hw_caps & ATH9K_HW_CAP_HT) {
-               sc->sc_flags |= SC_OP_TXAGGR;
-               sc->sc_flags |= SC_OP_RXAGGR;
-       }
-
-       common->tx_chainmask = ah->caps.tx_chainmask;
-       common->rx_chainmask = ah->caps.rx_chainmask;
-
-       ath9k_hw_setcapability(ah, ATH9K_CAP_DIVERSITY, 1, true, NULL);
-       sc->rx.defant = ath9k_hw_getdefantenna(ah);
-
-       if (ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK)
-               memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN);
-
-       sc->beacon.slottime = ATH9K_SLOT_TIME_9;        /* default to short slot time */
-
-       /* initialize beacon slots */
-       for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) {
-               sc->beacon.bslot[i] = NULL;
-               sc->beacon.bslot_aphy[i] = NULL;
-       }
-
-       /* setup channels and rates */
-
-       if (test_bit(ATH9K_MODE_11G, sc->sc_ah->caps.wireless_modes)) {
-               sc->sbands[IEEE80211_BAND_2GHZ].channels = ath9k_2ghz_chantable;
-               sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ;
-               sc->sbands[IEEE80211_BAND_2GHZ].n_channels =
-                       ARRAY_SIZE(ath9k_2ghz_chantable);
-               sc->sbands[IEEE80211_BAND_2GHZ].bitrates = ath9k_legacy_rates;
-               sc->sbands[IEEE80211_BAND_2GHZ].n_bitrates =
-                       ARRAY_SIZE(ath9k_legacy_rates);
-       }
-
-       if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes)) {
-               sc->sbands[IEEE80211_BAND_5GHZ].channels = ath9k_5ghz_chantable;
-               sc->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ;
-               sc->sbands[IEEE80211_BAND_5GHZ].n_channels =
-                       ARRAY_SIZE(ath9k_5ghz_chantable);
-               sc->sbands[IEEE80211_BAND_5GHZ].bitrates =
-                       ath9k_legacy_rates + 4;
-               sc->sbands[IEEE80211_BAND_5GHZ].n_bitrates =
-                       ARRAY_SIZE(ath9k_legacy_rates) - 4;
-       }
-
-       switch (ah->btcoex_hw.scheme) {
-       case ATH_BTCOEX_CFG_NONE:
-               break;
-       case ATH_BTCOEX_CFG_2WIRE:
-               ath9k_hw_btcoex_init_2wire(ah);
-               break;
-       case ATH_BTCOEX_CFG_3WIRE:
-               ath9k_hw_btcoex_init_3wire(ah);
-               r = ath_init_btcoex_timer(sc);
-               if (r)
-                       goto bad2;
-               qnum = ath_tx_get_qnum(sc, ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BE);
-               ath9k_hw_init_btcoex_hw(ah, qnum);
-               sc->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW;
-               break;
-       default:
-               WARN_ON(1);
-               break;
-       }
-
-       return 0;
-bad2:
-       /* cleanup tx queues */
-       for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
-               if (ATH_TXQ_SETUP(sc, i))
-                       ath_tx_cleanupq(sc, &sc->tx.txq[i]);
-
-bad_free_hw:
-       ath9k_uninit_hw(sc);
-       return r;
-}
-
-void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
-{
-       hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
-               IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
-               IEEE80211_HW_SIGNAL_DBM |
-               IEEE80211_HW_AMPDU_AGGREGATION |
-               IEEE80211_HW_SUPPORTS_PS |
-               IEEE80211_HW_PS_NULLFUNC_STACK |
-               IEEE80211_HW_SPECTRUM_MGMT;
-
-       if (AR_SREV_9160_10_OR_LATER(sc->sc_ah) || modparam_nohwcrypt)
-               hw->flags |= IEEE80211_HW_MFP_CAPABLE;
-
-       hw->wiphy->interface_modes =
-               BIT(NL80211_IFTYPE_AP) |
-               BIT(NL80211_IFTYPE_STATION) |
-               BIT(NL80211_IFTYPE_ADHOC) |
-               BIT(NL80211_IFTYPE_MESH_POINT);
-
-       hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
-
-       hw->queues = 4;
-       hw->max_rates = 4;
-       hw->channel_change_time = 5000;
-       hw->max_listen_interval = 10;
-       /* Hardware supports 10 but we use 4 */
-       hw->max_rate_tries = 4;
-       hw->sta_data_size = sizeof(struct ath_node);
-       hw->vif_data_size = sizeof(struct ath_vif);
-
-       hw->rate_control_algorithm = "ath9k_rate_control";
-
-       if (test_bit(ATH9K_MODE_11G, sc->sc_ah->caps.wireless_modes))
-               hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
-                       &sc->sbands[IEEE80211_BAND_2GHZ];
-       if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes))
-               hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
-                       &sc->sbands[IEEE80211_BAND_5GHZ];
-}
-
-/* Device driver core initialization */
-int ath_init_device(u16 devid, struct ath_softc *sc, u16 subsysid,
-                   const struct ath_bus_ops *bus_ops)
-{
-       struct ieee80211_hw *hw = sc->hw;
-       struct ath_common *common;
-       struct ath_hw *ah;
-       int error = 0, i;
-       struct ath_regulatory *reg;
-
-       dev_dbg(sc->dev, "Attach ATH hw\n");
-
-       error = ath_init_softc(devid, sc, subsysid, bus_ops);
-       if (error != 0)
-               return error;
-
-       ah = sc->sc_ah;
-       common = ath9k_hw_common(ah);
-
-       /* get mac address from hardware and set in mac80211 */
-
-       SET_IEEE80211_PERM_ADDR(hw, common->macaddr);
-
-       ath_set_hw_capab(sc, hw);
-
-       error = ath_regd_init(&common->regulatory, sc->hw->wiphy,
-                             ath9k_reg_notifier);
-       if (error)
-               return error;
-
-       reg = &common->regulatory;
-
-       if (ah->caps.hw_caps & ATH9K_HW_CAP_HT) {
-               if (test_bit(ATH9K_MODE_11G, ah->caps.wireless_modes))
-                       setup_ht_cap(sc,
-                                    &sc->sbands[IEEE80211_BAND_2GHZ].ht_cap);
-               if (test_bit(ATH9K_MODE_11A, ah->caps.wireless_modes))
-                       setup_ht_cap(sc,
-                                    &sc->sbands[IEEE80211_BAND_5GHZ].ht_cap);
-       }
-
-       /* initialize tx/rx engine */
-       error = ath_tx_init(sc, ATH_TXBUF);
-       if (error != 0)
-               goto error_attach;
-
-       error = ath_rx_init(sc, ATH_RXBUF);
-       if (error != 0)
-               goto error_attach;
-
-       INIT_WORK(&sc->chan_work, ath9k_wiphy_chan_work);
-       INIT_DELAYED_WORK(&sc->wiphy_work, ath9k_wiphy_work);
-       sc->wiphy_scheduler_int = msecs_to_jiffies(500);
-
-       error = ieee80211_register_hw(hw);
-
-       if (!ath_is_world_regd(reg)) {
-               error = regulatory_hint(hw->wiphy, reg->alpha2);
-               if (error)
-                       goto error_attach;
-       }
-
-       /* Initialize LED control */
-       ath_init_leds(sc);
-
-       ath_start_rfkill_poll(sc);
-
-       return 0;
-
-error_attach:
-       /* cleanup tx queues */
-       for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
-               if (ATH_TXQ_SETUP(sc, i))
-                       ath_tx_cleanupq(sc, &sc->tx.txq[i]);
-
-       ath9k_uninit_hw(sc);
-
-       return error;
-}
-
 int ath_reset(struct ath_softc *sc, bool retry_tx)
 {
        struct ath_hw *ah = sc->sc_ah;
@@ -1976,6 +944,8 @@ int ath_reset(struct ath_softc *sc, bool retry_tx)
        /* Stop ANI */
        del_timer_sync(&common->ani.timer);
 
+       ieee80211_stop_queues(hw);
+
        ath9k_hw_set_interrupts(ah, 0);
        ath_drain_all_txq(sc, retry_tx);
        ath_stoprecv(sc);
@@ -2017,131 +987,14 @@ int ath_reset(struct ath_softc *sc, bool retry_tx)
                }
        }
 
+       ieee80211_wake_queues(hw);
+
        /* Start ANI */
        ath_start_ani(common);
 
        return r;
 }
 
-/*
- *  This function will allocate both the DMA descriptor structure, and the
- *  buffers it contains.  These are used to contain the descriptors used
- *  by the system.
-*/
-int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
-                     struct list_head *head, const char *name,
-                     int nbuf, int ndesc)
-{
-#define        DS2PHYS(_dd, _ds)                                               \
-       ((_dd)->dd_desc_paddr + ((caddr_t)(_ds) - (caddr_t)(_dd)->dd_desc))
-#define ATH_DESC_4KB_BOUND_CHECK(_daddr) ((((_daddr) & 0xFFF) > 0xF7F) ? 1 : 0)
-#define ATH_DESC_4KB_BOUND_NUM_SKIPPED(_len) ((_len) / 4096)
-       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
-       struct ath_desc *ds;
-       struct ath_buf *bf;
-       int i, bsize, error;
-
-       ath_print(common, ATH_DBG_CONFIG, "%s DMA: %u buffers %u desc/buf\n",
-                 name, nbuf, ndesc);
-
-       INIT_LIST_HEAD(head);
-       /* ath_desc must be a multiple of DWORDs */
-       if ((sizeof(struct ath_desc) % 4) != 0) {
-               ath_print(common, ATH_DBG_FATAL,
-                         "ath_desc not DWORD aligned\n");
-               BUG_ON((sizeof(struct ath_desc) % 4) != 0);
-               error = -ENOMEM;
-               goto fail;
-       }
-
-       dd->dd_desc_len = sizeof(struct ath_desc) * nbuf * ndesc;
-
-       /*
-        * Need additional DMA memory because we can't use
-        * descriptors that cross the 4K page boundary. Assume
-        * one skipped descriptor per 4K page.
-        */
-       if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_4KB_SPLITTRANS)) {
-               u32 ndesc_skipped =
-                       ATH_DESC_4KB_BOUND_NUM_SKIPPED(dd->dd_desc_len);
-               u32 dma_len;
-
-               while (ndesc_skipped) {
-                       dma_len = ndesc_skipped * sizeof(struct ath_desc);
-                       dd->dd_desc_len += dma_len;
-
-                       ndesc_skipped = ATH_DESC_4KB_BOUND_NUM_SKIPPED(dma_len);
-               };
-       }
-
-       /* allocate descriptors */
-       dd->dd_desc = dma_alloc_coherent(sc->dev, dd->dd_desc_len,
-                                        &dd->dd_desc_paddr, GFP_KERNEL);
-       if (dd->dd_desc == NULL) {
-               error = -ENOMEM;
-               goto fail;
-       }
-       ds = dd->dd_desc;
-       ath_print(common, ATH_DBG_CONFIG, "%s DMA map: %p (%u) -> %llx (%u)\n",
-                 name, ds, (u32) dd->dd_desc_len,
-                 ito64(dd->dd_desc_paddr), /*XXX*/(u32) dd->dd_desc_len);
-
-       /* allocate buffers */
-       bsize = sizeof(struct ath_buf) * nbuf;
-       bf = kzalloc(bsize, GFP_KERNEL);
-       if (bf == NULL) {
-               error = -ENOMEM;
-               goto fail2;
-       }
-       dd->dd_bufptr = bf;
-
-       for (i = 0; i < nbuf; i++, bf++, ds += ndesc) {
-               bf->bf_desc = ds;
-               bf->bf_daddr = DS2PHYS(dd, ds);
-
-               if (!(sc->sc_ah->caps.hw_caps &
-                     ATH9K_HW_CAP_4KB_SPLITTRANS)) {
-                       /*
-                        * Skip descriptor addresses which can cause 4KB
-                        * boundary crossing (addr + length) with a 32 dword
-                        * descriptor fetch.
-                        */
-                       while (ATH_DESC_4KB_BOUND_CHECK(bf->bf_daddr)) {
-                               BUG_ON((caddr_t) bf->bf_desc >=
-                                      ((caddr_t) dd->dd_desc +
-                                       dd->dd_desc_len));
-
-                               ds += ndesc;
-                               bf->bf_desc = ds;
-                               bf->bf_daddr = DS2PHYS(dd, ds);
-                       }
-               }
-               list_add_tail(&bf->list, head);
-       }
-       return 0;
-fail2:
-       dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc,
-                         dd->dd_desc_paddr);
-fail:
-       memset(dd, 0, sizeof(*dd));
-       return error;
-#undef ATH_DESC_4KB_BOUND_CHECK
-#undef ATH_DESC_4KB_BOUND_NUM_SKIPPED
-#undef DS2PHYS
-}
-
-void ath_descdma_cleanup(struct ath_softc *sc,
-                        struct ath_descdma *dd,
-                        struct list_head *head)
-{
-       dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc,
-                         dd->dd_desc_paddr);
-
-       INIT_LIST_HEAD(head);
-       kfree(dd->dd_bufptr);
-       memset(dd, 0, sizeof(*dd));
-}
-
 int ath_get_hal_qnum(u16 queue, struct ath_softc *sc)
 {
        int qnum;
@@ -2220,28 +1073,6 @@ void ath9k_update_ichannel(struct ath_softc *sc, struct ieee80211_hw *hw,
 /* mac80211 callbacks */
 /**********************/
 
-/*
- * (Re)start btcoex timers
- */
-static void ath9k_btcoex_timer_resume(struct ath_softc *sc)
-{
-       struct ath_btcoex *btcoex = &sc->btcoex;
-       struct ath_hw *ah = sc->sc_ah;
-
-       ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX,
-                 "Starting btcoex timers");
-
-       /* make sure duty cycle timer is also stopped when resuming */
-       if (btcoex->hw_timer_enabled)
-               ath9k_gen_timer_stop(sc->sc_ah, btcoex->no_stomp_timer);
-
-       btcoex->bt_priority_cnt = 0;
-       btcoex->bt_priority_time = jiffies;
-       sc->sc_flags &= ~SC_OP_BT_PRIORITY_DETECTED;
-
-       mod_timer(&btcoex->period_timer, jiffies);
-}
-
 static int ath9k_start(struct ieee80211_hw *hw)
 {
        struct ath_wiphy *aphy = hw->priv;
@@ -2411,11 +1242,11 @@ static int ath9k_tx(struct ieee80211_hw *hw,
                if (ieee80211_is_pspoll(hdr->frame_control)) {
                        ath_print(common, ATH_DBG_PS,
                                  "Sending PS-Poll to pick a buffered frame\n");
-                       sc->sc_flags |= SC_OP_WAIT_FOR_PSPOLL_DATA;
+                       sc->ps_flags |= PS_WAIT_FOR_PSPOLL_DATA;
                } else {
                        ath_print(common, ATH_DBG_PS,
                                  "Wake up to complete TX\n");
-                       sc->sc_flags |= SC_OP_WAIT_FOR_TX_ACK;
+                       sc->ps_flags |= PS_WAIT_FOR_TX_ACK;
                }
                /*
                 * The actual restore operation will happen only after
@@ -2468,22 +1299,6 @@ exit:
        return 0;
 }
 
-/*
- * Pause btcoex timer and bt duty cycle timer
- */
-static void ath9k_btcoex_timer_pause(struct ath_softc *sc)
-{
-       struct ath_btcoex *btcoex = &sc->btcoex;
-       struct ath_hw *ah = sc->sc_ah;
-
-       del_timer_sync(&btcoex->period_timer);
-
-       if (btcoex->hw_timer_enabled)
-               ath9k_gen_timer_stop(ah, btcoex->no_stomp_timer);
-
-       btcoex->hw_timer_enabled = false;
-}
-
 static void ath9k_stop(struct ieee80211_hw *hw)
 {
        struct ath_wiphy *aphy = hw->priv;
@@ -2550,12 +1365,12 @@ static void ath9k_stop(struct ieee80211_hw *hw)
 }
 
 static int ath9k_add_interface(struct ieee80211_hw *hw,
-                              struct ieee80211_if_init_conf *conf)
+                              struct ieee80211_vif *vif)
 {
        struct ath_wiphy *aphy = hw->priv;
        struct ath_softc *sc = aphy->sc;
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
-       struct ath_vif *avp = (void *)conf->vif->drv_priv;
+       struct ath_vif *avp = (void *)vif->drv_priv;
        enum nl80211_iftype ic_opmode = NL80211_IFTYPE_UNSPECIFIED;
        int ret = 0;
 
@@ -2567,7 +1382,7 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
                goto out;
        }
 
-       switch (conf->type) {
+       switch (vif->type) {
        case NL80211_IFTYPE_STATION:
                ic_opmode = NL80211_IFTYPE_STATION;
                break;
@@ -2578,11 +1393,11 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
                        ret = -ENOBUFS;
                        goto out;
                }
-               ic_opmode = conf->type;
+               ic_opmode = vif->type;
                break;
        default:
                ath_print(common, ATH_DBG_FATAL,
-                       "Interface type %d not yet supported\n", conf->type);
+                       "Interface type %d not yet supported\n", vif->type);
                ret = -EOPNOTSUPP;
                goto out;
        }
@@ -2614,18 +1429,18 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
         * Enable MIB interrupts when there are hardware phy counters.
         * Note we only do this (at the moment) for station mode.
         */
-       if ((conf->type == NL80211_IFTYPE_STATION) ||
-           (conf->type == NL80211_IFTYPE_ADHOC) ||
-           (conf->type == NL80211_IFTYPE_MESH_POINT)) {
+       if ((vif->type == NL80211_IFTYPE_STATION) ||
+           (vif->type == NL80211_IFTYPE_ADHOC) ||
+           (vif->type == NL80211_IFTYPE_MESH_POINT)) {
                sc->imask |= ATH9K_INT_MIB;
                sc->imask |= ATH9K_INT_TSFOOR;
        }
 
        ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);
 
-       if (conf->type == NL80211_IFTYPE_AP    ||
-           conf->type == NL80211_IFTYPE_ADHOC ||
-           conf->type == NL80211_IFTYPE_MONITOR)
+       if (vif->type == NL80211_IFTYPE_AP    ||
+           vif->type == NL80211_IFTYPE_ADHOC ||
+           vif->type == NL80211_IFTYPE_MONITOR)
                ath_start_ani(common);
 
 out:
@@ -2634,12 +1449,12 @@ out:
 }
 
 static void ath9k_remove_interface(struct ieee80211_hw *hw,
-                                  struct ieee80211_if_init_conf *conf)
+                                  struct ieee80211_vif *vif)
 {
        struct ath_wiphy *aphy = hw->priv;
        struct ath_softc *sc = aphy->sc;
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
-       struct ath_vif *avp = (void *)conf->vif->drv_priv;
+       struct ath_vif *avp = (void *)vif->drv_priv;
        int i;
 
        ath_print(common, ATH_DBG_CONFIG, "Detach Interface\n");
@@ -2662,7 +1477,7 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw,
        sc->sc_flags &= ~SC_OP_BEACONS;
 
        for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) {
-               if (sc->beacon.bslot[i] == conf->vif) {
+               if (sc->beacon.bslot[i] == vif) {
                        printk(KERN_DEBUG "%s: vif had allocated beacon "
                               "slot\n", __func__);
                        sc->beacon.bslot[i] = NULL;
@@ -2727,7 +1542,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
         */
        if (changed & IEEE80211_CONF_CHANGE_PS) {
                if (conf->flags & IEEE80211_CONF_PS) {
-                       sc->sc_flags |= SC_OP_PS_ENABLED;
+                       sc->ps_flags |= PS_ENABLED;
                        if (!(ah->caps.hw_caps &
                              ATH9K_HW_CAP_AUTOSLEEP)) {
                                if ((sc->imask & ATH9K_INT_TIM_TIMER) == 0) {
@@ -2740,23 +1555,23 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
                         * At this point we know hardware has received an ACK
                         * of a previously sent null data frame.
                         */
-                       if ((sc->sc_flags & SC_OP_NULLFUNC_COMPLETED)) {
-                               sc->sc_flags &= ~SC_OP_NULLFUNC_COMPLETED;
+                       if ((sc->ps_flags & PS_NULLFUNC_COMPLETED)) {
+                               sc->ps_flags &= ~PS_NULLFUNC_COMPLETED;
                                sc->ps_enabled = true;
                                ath9k_hw_setrxabort(sc->sc_ah, 1);
                         }
                } else {
                        sc->ps_enabled = false;
-                       sc->sc_flags &= ~(SC_OP_PS_ENABLED |
-                                         SC_OP_NULLFUNC_COMPLETED);
+                       sc->ps_flags &= ~(PS_ENABLED |
+                                         PS_NULLFUNC_COMPLETED);
                        ath9k_setpower(sc, ATH9K_PM_AWAKE);
                        if (!(ah->caps.hw_caps &
                              ATH9K_HW_CAP_AUTOSLEEP)) {
                                ath9k_hw_setrxabort(sc->sc_ah, 0);
-                               sc->sc_flags &= ~(SC_OP_WAIT_FOR_BEACON |
-                                                 SC_OP_WAIT_FOR_CAB |
-                                                 SC_OP_WAIT_FOR_PSPOLL_DATA |
-                                                 SC_OP_WAIT_FOR_TX_ACK);
+                               sc->ps_flags &= ~(PS_WAIT_FOR_BEACON |
+                                                 PS_WAIT_FOR_CAB |
+                                                 PS_WAIT_FOR_PSPOLL_DATA |
+                                                 PS_WAIT_FOR_TX_ACK);
                                if (sc->imask & ATH9K_INT_TIM_TIMER) {
                                        sc->imask &= ~ATH9K_INT_TIM_TIMER;
                                        ath9k_hw_set_interrupts(sc->sc_ah,
@@ -2766,6 +1581,14 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
                }
        }
 
+       if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
+               if (conf->flags & IEEE80211_CONF_MONITOR) {
+                       ath_print(common, ATH_DBG_CONFIG,
+                                 "HW opmode set to Monitor mode\n");
+                       sc->sc_ah->opmode = NL80211_IFTYPE_MONITOR;
+               }
+       }
+
        if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
                struct ieee80211_channel *curchan = hw->conf.channel;
                int pos = curchan->hw_value;
@@ -2966,6 +1789,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
        struct ath_hw *ah = sc->sc_ah;
        struct ath_common *common = ath9k_hw_common(ah);
        struct ath_vif *avp = (void *)vif->drv_priv;
+       int slottime;
        int error;
 
        mutex_lock(&sc->mutex);
@@ -3001,6 +1825,25 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
                        ath_beacon_config(sc, vif);
        }
 
+       if (changed & BSS_CHANGED_ERP_SLOT) {
+               if (bss_conf->use_short_slot)
+                       slottime = 9;
+               else
+                       slottime = 20;
+               if (vif->type == NL80211_IFTYPE_AP) {
+                       /*
+                        * Defer update, so that connected stations can adjust
+                        * their settings at the same time.
+                        * See beacon.c for more details
+                        */
+                       sc->beacon.slottime = slottime;
+                       sc->beacon.updateslot = UPDATE;
+               } else {
+                       ah->slottime = slottime;
+                       ath9k_hw_init_global_settings(ah);
+               }
+       }
+
        /* Disable transmission of beacons */
        if ((changed & BSS_CHANGED_BEACON_ENABLED) && !bss_conf->enable_beacon)
                ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
@@ -3133,6 +1976,7 @@ static void ath9k_sw_scan_start(struct ieee80211_hw *hw)
 {
        struct ath_wiphy *aphy = hw->priv;
        struct ath_softc *sc = aphy->sc;
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 
        mutex_lock(&sc->mutex);
        if (ath9k_wiphy_scanning(sc)) {
@@ -3148,10 +1992,9 @@ static void ath9k_sw_scan_start(struct ieee80211_hw *hw)
 
        aphy->state = ATH_WIPHY_SCAN;
        ath9k_wiphy_pause_all_forced(sc, aphy);
-
-       spin_lock_bh(&sc->ani_lock);
        sc->sc_flags |= SC_OP_SCANNING;
-       spin_unlock_bh(&sc->ani_lock);
+       del_timer_sync(&common->ani.timer);
+       cancel_delayed_work_sync(&sc->tx_complete_work);
        mutex_unlock(&sc->mutex);
 }
 
@@ -3159,17 +2002,30 @@ static void ath9k_sw_scan_complete(struct ieee80211_hw *hw)
 {
        struct ath_wiphy *aphy = hw->priv;
        struct ath_softc *sc = aphy->sc;
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 
        mutex_lock(&sc->mutex);
-       spin_lock_bh(&sc->ani_lock);
        aphy->state = ATH_WIPHY_ACTIVE;
        sc->sc_flags &= ~SC_OP_SCANNING;
        sc->sc_flags |= SC_OP_FULL_RESET;
-       spin_unlock_bh(&sc->ani_lock);
+       ath_start_ani(common);
+       ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0);
        ath_beacon_config(sc, NULL);
        mutex_unlock(&sc->mutex);
 }
 
+static void ath9k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class)
+{
+       struct ath_wiphy *aphy = hw->priv;
+       struct ath_softc *sc = aphy->sc;
+       struct ath_hw *ah = sc->sc_ah;
+
+       mutex_lock(&sc->mutex);
+       ah->coverage_class = coverage_class;
+       ath9k_hw_init_global_settings(ah);
+       mutex_unlock(&sc->mutex);
+}
+
 struct ieee80211_ops ath9k_ops = {
        .tx                 = ath9k_tx,
        .start              = ath9k_start,
@@ -3189,64 +2045,5 @@ struct ieee80211_ops ath9k_ops = {
        .sw_scan_start      = ath9k_sw_scan_start,
        .sw_scan_complete   = ath9k_sw_scan_complete,
        .rfkill_poll        = ath9k_rfkill_poll_state,
+       .set_coverage_class = ath9k_set_coverage_class,
 };
-
-static int __init ath9k_init(void)
-{
-       int error;
-
-       /* Register rate control algorithm */
-       error = ath_rate_control_register();
-       if (error != 0) {
-               printk(KERN_ERR
-                       "ath9k: Unable to register rate control "
-                       "algorithm: %d\n",
-                       error);
-               goto err_out;
-       }
-
-       error = ath9k_debug_create_root();
-       if (error) {
-               printk(KERN_ERR
-                       "ath9k: Unable to create debugfs root: %d\n",
-                       error);
-               goto err_rate_unregister;
-       }
-
-       error = ath_pci_init();
-       if (error < 0) {
-               printk(KERN_ERR
-                       "ath9k: No PCI devices found, driver not installed.\n");
-               error = -ENODEV;
-               goto err_remove_root;
-       }
-
-       error = ath_ahb_init();
-       if (error < 0) {
-               error = -ENODEV;
-               goto err_pci_exit;
-       }
-
-       return 0;
-
- err_pci_exit:
-       ath_pci_exit();
-
- err_remove_root:
-       ath9k_debug_remove_root();
- err_rate_unregister:
-       ath_rate_control_unregister();
- err_out:
-       return error;
-}
-module_init(ath9k_init);
-
-static void __exit ath9k_exit(void)
-{
-       ath_ahb_exit();
-       ath_pci_exit();
-       ath9k_debug_remove_root();
-       ath_rate_control_unregister();
-       printk(KERN_INFO "%s: Driver unloaded\n", dev_info);
-}
-module_exit(ath9k_exit);
index f7af5ea54753725b45325d719c8e3b0ad22f97c8..fe2c3a644a6ed01583c0f5c1116f5f4a5111dbda 100644 (file)
@@ -18,7 +18,7 @@
 #include <linux/pci.h>
 #include "ath9k.h"
 
-static struct pci_device_id ath_pci_id_table[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = {
        { PCI_VDEVICE(ATHEROS, 0x0023) }, /* PCI   */
        { PCI_VDEVICE(ATHEROS, 0x0024) }, /* PCI-E */
        { PCI_VDEVICE(ATHEROS, 0x0027) }, /* PCI   */
@@ -113,25 +113,22 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        u16 subsysid;
        u32 val;
        int ret = 0;
-       struct ath_hw *ah;
        char hw_name[64];
 
        if (pci_enable_device(pdev))
                return -EIO;
 
        ret =  pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
-
        if (ret) {
                printk(KERN_ERR "ath9k: 32-bit DMA not available\n");
-               goto bad;
+               goto err_dma;
        }
 
        ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
-
        if (ret) {
                printk(KERN_ERR "ath9k: 32-bit DMA consistent "
                        "DMA enable failed\n");
-               goto bad;
+               goto err_dma;
        }
 
        /*
@@ -171,22 +168,22 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        if (ret) {
                dev_err(&pdev->dev, "PCI memory region reserve error\n");
                ret = -ENODEV;
-               goto bad;
+               goto err_region;
        }
 
        mem = pci_iomap(pdev, 0, 0);
        if (!mem) {
                printk(KERN_ERR "PCI memory map error\n") ;
                ret = -EIO;
-               goto bad1;
+               goto err_iomap;
        }
 
        hw = ieee80211_alloc_hw(sizeof(struct ath_wiphy) +
                                sizeof(struct ath_softc), &ath9k_ops);
        if (!hw) {
-               dev_err(&pdev->dev, "no memory for ieee80211_hw\n");
+               dev_err(&pdev->dev, "No memory for ieee80211_hw\n");
                ret = -ENOMEM;
-               goto bad2;
+               goto err_alloc_hw;
        }
 
        SET_IEEE80211_DEV(hw, &pdev->dev);
@@ -201,25 +198,25 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        sc->dev = &pdev->dev;
        sc->mem = mem;
 
-       pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &subsysid);
-       ret = ath_init_device(id->device, sc, subsysid, &ath_pci_bus_ops);
-       if (ret) {
-               dev_err(&pdev->dev, "failed to initialize device\n");
-               goto bad3;
-       }
-
-       /* setup interrupt service routine */
+       /* Will be cleared in ath9k_start() */
+       sc->sc_flags |= SC_OP_INVALID;
 
        ret = request_irq(pdev->irq, ath_isr, IRQF_SHARED, "ath9k", sc);
        if (ret) {
                dev_err(&pdev->dev, "request_irq failed\n");
-               goto bad4;
+               goto err_irq;
        }
 
        sc->irq = pdev->irq;
 
-       ah = sc->sc_ah;
-       ath9k_hw_name(ah, hw_name, sizeof(hw_name));
+       pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &subsysid);
+       ret = ath9k_init_device(id->device, sc, subsysid, &ath_pci_bus_ops);
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to initialize device\n");
+               goto err_init;
+       }
+
+       ath9k_hw_name(sc->sc_ah, hw_name, sizeof(hw_name));
        printk(KERN_INFO
               "%s: %s mem=0x%lx, irq=%d\n",
               wiphy_name(hw->wiphy),
@@ -227,15 +224,18 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
               (unsigned long)mem, pdev->irq);
 
        return 0;
-bad4:
-       ath_detach(sc);
-bad3:
+
+err_init:
+       free_irq(sc->irq, sc);
+err_irq:
        ieee80211_free_hw(hw);
-bad2:
+err_alloc_hw:
        pci_iounmap(pdev, mem);
-bad1:
+err_iomap:
        pci_release_region(pdev, 0);
-bad:
+err_region:
+       /* Nothing */
+err_dma:
        pci_disable_device(pdev);
        return ret;
 }
@@ -245,8 +245,12 @@ static void ath_pci_remove(struct pci_dev *pdev)
        struct ieee80211_hw *hw = pci_get_drvdata(pdev);
        struct ath_wiphy *aphy = hw->priv;
        struct ath_softc *sc = aphy->sc;
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 
-       ath_cleanup(sc);
+       ath9k_deinit_device(sc);
+       free_irq(sc->irq, sc);
+       ieee80211_free_hw(sc->hw);
+       ath_bus_cleanup(common);
 }
 
 #ifdef CONFIG_PM
index 9eb96f506998ea37f6b35992a2dded99ceb29ebe..4f6d6fd442f477f6d7d759539cec602459259b5d 100644 (file)
@@ -57,6 +57,10 @@ enum {
                                || (_phy == WLAN_RC_PHY_HT_40_DS)       \
                                || (_phy == WLAN_RC_PHY_HT_20_DS_HGI)   \
                                || (_phy == WLAN_RC_PHY_HT_40_DS_HGI))
+#define WLAN_RC_PHY_20(_phy)   ((_phy == WLAN_RC_PHY_HT_20_SS)         \
+                               || (_phy == WLAN_RC_PHY_HT_20_DS)       \
+                               || (_phy == WLAN_RC_PHY_HT_20_SS_HGI)   \
+                               || (_phy == WLAN_RC_PHY_HT_20_DS_HGI))
 #define WLAN_RC_PHY_40(_phy)   ((_phy == WLAN_RC_PHY_HT_40_SS)         \
                                || (_phy == WLAN_RC_PHY_HT_40_DS)       \
                                || (_phy == WLAN_RC_PHY_HT_40_SS_HGI)   \
index 477365e5ae6939403882c6821dcf28c6dc6fed0f..40b5d05edcce8ab274ad216d90aed3800b78e67f 100644 (file)
@@ -364,10 +364,10 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
        if (memcmp(common->curbssid, mgmt->bssid, ETH_ALEN) != 0)
                return; /* not from our current AP */
 
-       sc->sc_flags &= ~SC_OP_WAIT_FOR_BEACON;
+       sc->ps_flags &= ~PS_WAIT_FOR_BEACON;
 
-       if (sc->sc_flags & SC_OP_BEACON_SYNC) {
-               sc->sc_flags &= ~SC_OP_BEACON_SYNC;
+       if (sc->ps_flags & PS_BEACON_SYNC) {
+               sc->ps_flags &= ~PS_BEACON_SYNC;
                ath_print(common, ATH_DBG_PS,
                          "Reconfigure Beacon timers based on "
                          "timestamp from the AP\n");
@@ -384,17 +384,17 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
                 */
                ath_print(common, ATH_DBG_PS, "Received DTIM beacon indicating "
                          "buffered broadcast/multicast frame(s)\n");
-               sc->sc_flags |= SC_OP_WAIT_FOR_CAB | SC_OP_WAIT_FOR_BEACON;
+               sc->ps_flags |= PS_WAIT_FOR_CAB | PS_WAIT_FOR_BEACON;
                return;
        }
 
-       if (sc->sc_flags & SC_OP_WAIT_FOR_CAB) {
+       if (sc->ps_flags & PS_WAIT_FOR_CAB) {
                /*
                 * This can happen if a broadcast frame is dropped or the AP
                 * fails to send a frame indicating that all CAB frames have
                 * been delivered.
                 */
-               sc->sc_flags &= ~SC_OP_WAIT_FOR_CAB;
+               sc->ps_flags &= ~PS_WAIT_FOR_CAB;
                ath_print(common, ATH_DBG_PS,
                          "PS wait for CAB frames timed out\n");
        }
@@ -408,10 +408,10 @@ static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb)
        hdr = (struct ieee80211_hdr *)skb->data;
 
        /* Process Beacon and CAB receive in PS state */
-       if ((sc->sc_flags & SC_OP_WAIT_FOR_BEACON) &&
+       if ((sc->ps_flags & PS_WAIT_FOR_BEACON) &&
            ieee80211_is_beacon(hdr->frame_control))
                ath_rx_ps_beacon(sc, skb);
-       else if ((sc->sc_flags & SC_OP_WAIT_FOR_CAB) &&
+       else if ((sc->ps_flags & PS_WAIT_FOR_CAB) &&
                 (ieee80211_is_data(hdr->frame_control) ||
                  ieee80211_is_action(hdr->frame_control)) &&
                 is_multicast_ether_addr(hdr->addr1) &&
@@ -420,20 +420,20 @@ static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb)
                 * No more broadcast/multicast frames to be received at this
                 * point.
                 */
-               sc->sc_flags &= ~SC_OP_WAIT_FOR_CAB;
+               sc->ps_flags &= ~PS_WAIT_FOR_CAB;
                ath_print(common, ATH_DBG_PS,
                          "All PS CAB frames received, back to sleep\n");
-       } else if ((sc->sc_flags & SC_OP_WAIT_FOR_PSPOLL_DATA) &&
+       } else if ((sc->ps_flags & PS_WAIT_FOR_PSPOLL_DATA) &&
                   !is_multicast_ether_addr(hdr->addr1) &&
                   !ieee80211_has_morefrags(hdr->frame_control)) {
-               sc->sc_flags &= ~SC_OP_WAIT_FOR_PSPOLL_DATA;
+               sc->ps_flags &= ~PS_WAIT_FOR_PSPOLL_DATA;
                ath_print(common, ATH_DBG_PS,
                          "Going back to sleep after having received "
                          "PS-Poll data (0x%x)\n",
-                       sc->sc_flags & (SC_OP_WAIT_FOR_BEACON |
-                                       SC_OP_WAIT_FOR_CAB |
-                                       SC_OP_WAIT_FOR_PSPOLL_DATA |
-                                       SC_OP_WAIT_FOR_TX_ACK));
+                       sc->ps_flags & (PS_WAIT_FOR_BEACON |
+                                       PS_WAIT_FOR_CAB |
+                                       PS_WAIT_FOR_PSPOLL_DATA |
+                                       PS_WAIT_FOR_TX_ACK));
        }
 }
 
@@ -571,6 +571,8 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
                hw = ath_get_virt_hw(sc, hdr);
                rx_stats = &ds->ds_rxstat;
 
+               ath_debug_stat_rx(sc, bf);
+
                /*
                 * If we're asked to flush receive queue, directly
                 * chain it back at the queue without processing it.
@@ -631,9 +633,9 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
                        sc->rx.rxotherant = 0;
                }
 
-               if (unlikely(sc->sc_flags & (SC_OP_WAIT_FOR_BEACON |
-                                            SC_OP_WAIT_FOR_CAB |
-                                            SC_OP_WAIT_FOR_PSPOLL_DATA)))
+               if (unlikely(sc->ps_flags & (PS_WAIT_FOR_BEACON |
+                                            PS_WAIT_FOR_CAB |
+                                            PS_WAIT_FOR_PSPOLL_DATA)))
                        ath_rx_ps(sc, skb);
 
                ath_rx_send_to_mac80211(hw, sc, skb, rxs);
index cd26caaf44e7a3e18803dc90f632e442c6481094..a43fbf84dab9c7c5efc45029a2a0b85a9c0eee11 100644 (file)
@@ -152,7 +152,7 @@ int ath9k_wiphy_add(struct ath_softc *sc)
 
        SET_IEEE80211_PERM_ADDR(hw, addr);
 
-       ath_set_hw_capab(sc, hw);
+       ath9k_set_hw_capab(sc, hw);
 
        error = ieee80211_register_hw(hw);
 
index fa12b9060b0bbc1f0d5ae375501abdb9c2d31a0b..a821bb687b3bdb72d45d533d123a5708e3c8ca7b 100644 (file)
@@ -1648,7 +1648,7 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf,
        /* tag if this is a nullfunc frame to enable PS when AP acks it */
        if (ieee80211_is_nullfunc(fc) && ieee80211_has_pm(fc)) {
                bf->bf_isnullfunc = true;
-               sc->sc_flags &= ~SC_OP_NULLFUNC_COMPLETED;
+               sc->ps_flags &= ~PS_NULLFUNC_COMPLETED;
        } else
                bf->bf_isnullfunc = false;
 
@@ -1858,15 +1858,15 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
                skb_pull(skb, padsize);
        }
 
-       if (sc->sc_flags & SC_OP_WAIT_FOR_TX_ACK) {
-               sc->sc_flags &= ~SC_OP_WAIT_FOR_TX_ACK;
+       if (sc->ps_flags & PS_WAIT_FOR_TX_ACK) {
+               sc->ps_flags &= ~PS_WAIT_FOR_TX_ACK;
                ath_print(common, ATH_DBG_PS,
                          "Going back to sleep after having "
                          "received TX status (0x%x)\n",
-                       sc->sc_flags & (SC_OP_WAIT_FOR_BEACON |
-                                       SC_OP_WAIT_FOR_CAB |
-                                       SC_OP_WAIT_FOR_PSPOLL_DATA |
-                                       SC_OP_WAIT_FOR_TX_ACK));
+                       sc->ps_flags & (PS_WAIT_FOR_BEACON |
+                                       PS_WAIT_FOR_CAB |
+                                       PS_WAIT_FOR_PSPOLL_DATA |
+                                       PS_WAIT_FOR_TX_ACK));
        }
 
        if (unlikely(tx_info->pad[0] & ATH_TX_INFO_FRAME_TYPE_INTERNAL))
@@ -2053,11 +2053,11 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
                 */
                if (bf->bf_isnullfunc &&
                    (ds->ds_txstat.ts_status & ATH9K_TX_ACKED)) {
-                       if ((sc->sc_flags & SC_OP_PS_ENABLED)) {
+                       if ((sc->ps_flags & PS_ENABLED)) {
                                sc->ps_enabled = true;
                                ath9k_hw_setrxabort(sc->sc_ah, 1);
                        } else
-                               sc->sc_flags |= SC_OP_NULLFUNC_COMPLETED;
+                               sc->ps_flags |= PS_NULLFUNC_COMPLETED;
                }
 
                /*
index 92f87fbe750ff170059bccf3ba75ced0c9d99654..9ab1192004c038c92316238362a46d82b0093f3e 100644 (file)
@@ -31,7 +31,7 @@ MODULE_DESCRIPTION("Support for Atmel at76c50x 802.11 wireless ethernet cards.")
 MODULE_LICENSE("GPL");
 MODULE_SUPPORTED_DEVICE("Atmel at76c506 PCI wireless cards");
 
-static struct pci_device_id card_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(card_ids) = {
        { 0x1114, 0x0506, PCI_ANY_ID, PCI_ANY_ID },
        { 0, }
 };
index 64c12e1bced3368fb93d07ad0f0cbc56caed63ef..073be566d05e3355c9c5314846f1fed3be5f7853 100644 (file)
@@ -3,6 +3,7 @@ config B43
        depends on SSB_POSSIBLE && MAC80211 && HAS_DMA
        select SSB
        select FW_LOADER
+       select SSB_BLOCKIO
        ---help---
          b43 is a driver for the Broadcom 43xx series wireless devices.
 
@@ -78,14 +79,6 @@ config B43_SDIO
 
          If unsure, say N.
 
-# Data transfers to the device via PIO
-# This is only needed on PCMCIA and SDIO devices. All others can do DMA properly.
-config B43_PIO
-       bool
-       depends on B43 && (B43_SDIO || B43_PCMCIA || B43_FORCE_PIO)
-       select SSB_BLOCKIO
-       default y
-
 config B43_NPHY
        bool "Pre IEEE 802.11n support (BROKEN)"
        depends on B43 && EXPERIMENTAL && BROKEN
@@ -137,12 +130,4 @@ config B43_DEBUG
          for production use.
          Only say Y, if you are debugging a problem in the b43 driver sourcecode.
 
-config B43_FORCE_PIO
-       bool "Force usage of PIO instead of DMA"
-       depends on B43 && B43_DEBUG
-       ---help---
-         This will disable DMA and always enable PIO instead.
 
-         Say N!
-         This is only for debugging the PIO engine code. You do
-         _NOT_ want to enable this.
index 84772a2542dca6a21148e2449e544027213c5b39..5e83b6f0a3a013aeeb8cd090fd2bcd9267223356 100644 (file)
@@ -12,7 +12,7 @@ b43-y                         += xmit.o
 b43-y                          += lo.o
 b43-y                          += wa.o
 b43-y                          += dma.o
-b43-$(CONFIG_B43_PIO)          += pio.o
+b43-y                          += pio.o
 b43-y                          += rfkill.o
 b43-$(CONFIG_B43_LEDS)         += leds.o
 b43-$(CONFIG_B43_PCMCIA)       += pcmcia.o
index fe3bf949199780bea902d3ad3cad122311c5612f..54d6085a887ba3b26893ccf17d843a0d8e421d9f 100644 (file)
@@ -253,6 +253,14 @@ enum {
 #define B43_SHM_SH_MAXBFRAMES          0x0080  /* Maximum number of frames in a burst */
 #define B43_SHM_SH_SPUWKUP             0x0094  /* pre-wakeup for synth PU in us */
 #define B43_SHM_SH_PRETBTT             0x0096  /* pre-TBTT in us */
+/* SHM_SHARED tx iq workarounds */
+#define B43_SHM_SH_NPHY_TXIQW0         0x0700
+#define B43_SHM_SH_NPHY_TXIQW1         0x0702
+#define B43_SHM_SH_NPHY_TXIQW2         0x0704
+#define B43_SHM_SH_NPHY_TXIQW3         0x0706
+/* SHM_SHARED tx pwr ctrl */
+#define B43_SHM_SH_NPHY_TXPWR_INDX0    0x0708
+#define B43_SHM_SH_NPHY_TXPWR_INDX1    0x070E
 
 /* SHM_SCRATCH offsets */
 #define B43_SHM_SC_MINCONT             0x0003  /* Minimum contention window */
@@ -821,11 +829,9 @@ struct b43_wl {
        /* The device LEDs. */
        struct b43_leds leds;
 
-#ifdef CONFIG_B43_PIO
        /* Kmalloc'ed scratch space for PIO TX/RX. Protected by wl->mutex. */
        u8 pio_scratchspace[110] __attribute__((__aligned__(8)));
        u8 pio_tailspace[4] __attribute__((__aligned__(8)));
-#endif /* CONFIG_B43_PIO */
 };
 
 static inline struct b43_wl *hw_to_b43_wl(struct ieee80211_hw *hw)
@@ -876,20 +882,9 @@ static inline void b43_write32(struct b43_wldev *dev, u16 offset, u32 value)
 
 static inline bool b43_using_pio_transfers(struct b43_wldev *dev)
 {
-#ifdef CONFIG_B43_PIO
        return dev->__using_pio_transfers;
-#else
-       return 0;
-#endif
 }
 
-#ifdef CONFIG_B43_FORCE_PIO
-# define B43_FORCE_PIO 1
-#else
-# define B43_FORCE_PIO 0
-#endif
-
-
 /* Message printing */
 void b43info(struct b43_wl *wl, const char *fmt, ...)
     __attribute__ ((format(printf, 2, 3)));
index 88d1fd02d40ae50fd01b645e921e83e8c48fbced..615af22c49fd1f34df3ad688841e4b7643caa843 100644 (file)
@@ -1653,7 +1653,6 @@ void b43_dma_tx_resume(struct b43_wldev *dev)
        b43_power_saving_ctl_bits(dev, 0);
 }
 
-#ifdef CONFIG_B43_PIO
 static void direct_fifo_rx(struct b43_wldev *dev, enum b43_dmatype type,
                           u16 mmio_base, bool enable)
 {
@@ -1687,4 +1686,3 @@ void b43_dma_direct_fifo_rx(struct b43_wldev *dev,
        mmio_base = b43_dmacontroller_base(type, engine_index);
        direct_fifo_rx(dev, type, mmio_base, enable);
 }
-#endif /* CONFIG_B43_PIO */
index 4c41cfe44f261494eceaa4080d85d7889344b42c..9c5c7c9ad530212b0c0446e813390cd45b8e920a 100644 (file)
@@ -67,7 +67,12 @@ MODULE_AUTHOR("Gábor Stefanik");
 MODULE_LICENSE("GPL");
 
 MODULE_FIRMWARE(B43_SUPPORTED_FIRMWARE_ID);
-
+MODULE_FIRMWARE("b43/ucode11.fw");
+MODULE_FIRMWARE("b43/ucode13.fw");
+MODULE_FIRMWARE("b43/ucode14.fw");
+MODULE_FIRMWARE("b43/ucode15.fw");
+MODULE_FIRMWARE("b43/ucode5.fw");
+MODULE_FIRMWARE("b43/ucode9.fw");
 
 static int modparam_bad_frames_preempt;
 module_param_named(bad_frames_preempt, modparam_bad_frames_preempt, int, 0444);
@@ -102,6 +107,9 @@ int b43_modparam_verbose = B43_VERBOSITY_DEFAULT;
 module_param_named(verbose, b43_modparam_verbose, int, 0644);
 MODULE_PARM_DESC(verbose, "Log message verbosity: 0=error, 1=warn, 2=info(default), 3=debug");
 
+static int modparam_pio;
+module_param_named(pio, modparam_pio, int, 0444);
+MODULE_PARM_DESC(pio, "enable(1) / disable(0) PIO mode");
 
 static const struct ssb_device_id b43_ssb_tbl[] = {
        SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 5),
@@ -110,6 +118,7 @@ static const struct ssb_device_id b43_ssb_tbl[] = {
        SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 9),
        SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 10),
        SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 11),
+       SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 12),
        SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 13),
        SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 15),
        SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 16),
@@ -1786,8 +1795,8 @@ static void b43_do_interrupt_thread(struct b43_wldev *dev)
                               dma_reason[4], dma_reason[5]);
                        b43err(dev->wl, "This device does not support DMA "
                               "on your system. Please use PIO instead.\n");
-                       b43err(dev->wl, "CONFIG_B43_FORCE_PIO must be set in "
-                              "your kernel configuration.\n");
+                       b43err(dev->wl, "Unload the b43 module and reload "
+                              "with 'pio=1'\n");
                        return;
                }
                if (merged_dma_reason & B43_DMAIRQ_NONFATALMASK) {
@@ -4353,7 +4362,7 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
 
        if ((dev->dev->bus->bustype == SSB_BUSTYPE_PCMCIA) ||
            (dev->dev->bus->bustype == SSB_BUSTYPE_SDIO) ||
-           B43_FORCE_PIO) {
+           modparam_pio) {
                dev->__using_pio_transfers = 1;
                err = b43_pio_init(dev);
        } else {
@@ -4388,7 +4397,7 @@ err_busdown:
 }
 
 static int b43_op_add_interface(struct ieee80211_hw *hw,
-                               struct ieee80211_if_init_conf *conf)
+                               struct ieee80211_vif *vif)
 {
        struct b43_wl *wl = hw_to_b43_wl(hw);
        struct b43_wldev *dev;
@@ -4396,24 +4405,24 @@ static int b43_op_add_interface(struct ieee80211_hw *hw,
 
        /* TODO: allow WDS/AP devices to coexist */
 
-       if (conf->type != NL80211_IFTYPE_AP &&
-           conf->type != NL80211_IFTYPE_MESH_POINT &&
-           conf->type != NL80211_IFTYPE_STATION &&
-           conf->type != NL80211_IFTYPE_WDS &&
-           conf->type != NL80211_IFTYPE_ADHOC)
+       if (vif->type != NL80211_IFTYPE_AP &&
+           vif->type != NL80211_IFTYPE_MESH_POINT &&
+           vif->type != NL80211_IFTYPE_STATION &&
+           vif->type != NL80211_IFTYPE_WDS &&
+           vif->type != NL80211_IFTYPE_ADHOC)
                return -EOPNOTSUPP;
 
        mutex_lock(&wl->mutex);
        if (wl->operating)
                goto out_mutex_unlock;
 
-       b43dbg(wl, "Adding Interface type %d\n", conf->type);
+       b43dbg(wl, "Adding Interface type %d\n", vif->type);
 
        dev = wl->current_dev;
        wl->operating = 1;
-       wl->vif = conf->vif;
-       wl->if_type = conf->type;
-       memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN);
+       wl->vif = vif;
+       wl->if_type = vif->type;
+       memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
 
        b43_adjust_opmode(dev);
        b43_set_pretbtt(dev);
@@ -4428,17 +4437,17 @@ static int b43_op_add_interface(struct ieee80211_hw *hw,
 }
 
 static void b43_op_remove_interface(struct ieee80211_hw *hw,
-                                   struct ieee80211_if_init_conf *conf)
+                                   struct ieee80211_vif *vif)
 {
        struct b43_wl *wl = hw_to_b43_wl(hw);
        struct b43_wldev *dev = wl->current_dev;
 
-       b43dbg(wl, "Removing Interface type %d\n", conf->type);
+       b43dbg(wl, "Removing Interface type %d\n", vif->type);
 
        mutex_lock(&wl->mutex);
 
        B43_WARN_ON(!wl->operating);
-       B43_WARN_ON(wl->vif != conf->vif);
+       B43_WARN_ON(wl->vif != vif);
        wl->vif = NULL;
 
        wl->operating = 0;
index 3e046ec1ff869a7898495f0ab67a20b3214b5295..b58d6cf26580a90c79d0b84c11b9148192d241be 100644 (file)
@@ -80,6 +80,7 @@ static void b43_lpphy_op_free(struct b43_wldev *dev)
        dev->phy.lp = NULL;
 }
 
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/LP/ReadBandSrom */
 static void lpphy_read_band_sprom(struct b43_wldev *dev)
 {
        struct b43_phy_lp *lpphy = dev->phy.lp;
@@ -101,6 +102,12 @@ static void lpphy_read_band_sprom(struct b43_wldev *dev)
                maxpwr = bus->sprom.maxpwr_bg;
                lpphy->max_tx_pwr_med_band = maxpwr;
                cckpo = bus->sprom.cck2gpo;
+               /*
+                * We don't read SPROM's opo as specs say. On rev8 SPROMs
+                * opo == ofdm2gpo and we don't know any SSB with LP-PHY
+                * and SPROM rev below 8.
+                */
+               B43_WARN_ON(bus->sprom.revision < 8);
                ofdmpo = bus->sprom.ofdm2gpo;
                if (cckpo) {
                        for (i = 0; i < 4; i++) {
@@ -1703,19 +1710,6 @@ static const struct lpphy_rx_iq_comp lpphy_rev2plus_iq_comp = {
        .c0 = 0,
 };
 
-static u8 lpphy_nbits(s32 val)
-{
-       u32 tmp = abs(val);
-       u8 nbits = 0;
-
-       while (tmp != 0) {
-               nbits++;
-               tmp >>= 1;
-       }
-
-       return nbits;
-}
-
 static int lpphy_calc_rx_iq_comp(struct b43_wldev *dev, u16 samples)
 {
        struct lpphy_iq_est iq_est;
@@ -1742,8 +1736,8 @@ static int lpphy_calc_rx_iq_comp(struct b43_wldev *dev, u16 samples)
                goto out;
        }
 
-       prod_msb = lpphy_nbits(prod);
-       q_msb = lpphy_nbits(qpwr);
+       prod_msb = fls(abs(prod));
+       q_msb = fls(abs(qpwr));
        tmp1 = prod_msb - 20;
 
        if (tmp1 >= 0) {
index 992318a78077b2c60f872495a8a6acf8bb981c96..4a817e3da163c73b79d8194c8c6f4293c348ed0c 100644 (file)
 #include "b43.h"
 #include "phy_n.h"
 #include "tables_nphy.h"
+#include "main.h"
 
+struct nphy_txgains {
+       u16 txgm[2];
+       u16 pga[2];
+       u16 pad[2];
+       u16 ipa[2];
+};
+
+struct nphy_iqcal_params {
+       u16 txgm;
+       u16 pga;
+       u16 pad;
+       u16 ipa;
+       u16 cal_gain;
+       u16 ncorr[5];
+};
+
+struct nphy_iq_est {
+       s32 iq0_prod;
+       u32 i0_pwr;
+       u32 q0_pwr;
+       s32 iq1_prod;
+       u32 i1_pwr;
+       u32 q1_pwr;
+};
 
 void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna)
 {//TODO
@@ -197,44 +222,16 @@ void b43_nphy_radio_turn_off(struct b43_wldev *dev)
                     ~B43_NPHY_RFCTL_CMD_EN);
 }
 
-#define ntab_upload(dev, offset, data) do { \
-               unsigned int i;                                         \
-               for (i = 0; i < (offset##_SIZE); i++)                   \
-                       b43_ntab_write(dev, (offset) + i, (data)[i]);   \
-       } while (0)
-
-/* Upload the N-PHY tables. */
+/*
+ * Upload the N-PHY tables.
+ * http://bcm-v4.sipsolutions.net/802.11/PHY/N/InitTables
+ */
 static void b43_nphy_tables_init(struct b43_wldev *dev)
 {
-       /* Static tables */
-       ntab_upload(dev, B43_NTAB_FRAMESTRUCT, b43_ntab_framestruct);
-       ntab_upload(dev, B43_NTAB_FRAMELT, b43_ntab_framelookup);
-       ntab_upload(dev, B43_NTAB_TMAP, b43_ntab_tmap);
-       ntab_upload(dev, B43_NTAB_TDTRN, b43_ntab_tdtrn);
-       ntab_upload(dev, B43_NTAB_INTLEVEL, b43_ntab_intlevel);
-       ntab_upload(dev, B43_NTAB_PILOT, b43_ntab_pilot);
-       ntab_upload(dev, B43_NTAB_PILOTLT, b43_ntab_pilotlt);
-       ntab_upload(dev, B43_NTAB_TDI20A0, b43_ntab_tdi20a0);
-       ntab_upload(dev, B43_NTAB_TDI20A1, b43_ntab_tdi20a1);
-       ntab_upload(dev, B43_NTAB_TDI40A0, b43_ntab_tdi40a0);
-       ntab_upload(dev, B43_NTAB_TDI40A1, b43_ntab_tdi40a1);
-       ntab_upload(dev, B43_NTAB_BDI, b43_ntab_bdi);
-       ntab_upload(dev, B43_NTAB_CHANEST, b43_ntab_channelest);
-       ntab_upload(dev, B43_NTAB_MCS, b43_ntab_mcs);
-
-       /* Volatile tables */
-       ntab_upload(dev, B43_NTAB_NOISEVAR10, b43_ntab_noisevar10);
-       ntab_upload(dev, B43_NTAB_NOISEVAR11, b43_ntab_noisevar11);
-       ntab_upload(dev, B43_NTAB_C0_ESTPLT, b43_ntab_estimatepowerlt0);
-       ntab_upload(dev, B43_NTAB_C1_ESTPLT, b43_ntab_estimatepowerlt1);
-       ntab_upload(dev, B43_NTAB_C0_ADJPLT, b43_ntab_adjustpower0);
-       ntab_upload(dev, B43_NTAB_C1_ADJPLT, b43_ntab_adjustpower1);
-       ntab_upload(dev, B43_NTAB_C0_GAINCTL, b43_ntab_gainctl0);
-       ntab_upload(dev, B43_NTAB_C1_GAINCTL, b43_ntab_gainctl1);
-       ntab_upload(dev, B43_NTAB_C0_IQLT, b43_ntab_iqlt0);
-       ntab_upload(dev, B43_NTAB_C1_IQLT, b43_ntab_iqlt1);
-       ntab_upload(dev, B43_NTAB_C0_LOFEEDTH, b43_ntab_loftlt0);
-       ntab_upload(dev, B43_NTAB_C1_LOFEEDTH, b43_ntab_loftlt1);
+       if (dev->phy.rev < 3)
+               b43_nphy_rev0_1_2_tables_init(dev);
+       else
+               b43_nphy_rev3plus_tables_init(dev);
 }
 
 static void b43_nphy_workarounds(struct b43_wldev *dev)
@@ -341,18 +338,386 @@ static void b43_nphy_workarounds(struct b43_wldev *dev)
        b43_phy_write(dev, B43_NPHY_PHASETR_B2, 0x20);
 }
 
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/PA%20override */
+static void b43_nphy_pa_override(struct b43_wldev *dev, bool enable)
+{
+       struct b43_phy_n *nphy = dev->phy.n;
+       enum ieee80211_band band;
+       u16 tmp;
+
+       if (!enable) {
+               nphy->rfctrl_intc1_save = b43_phy_read(dev,
+                                                      B43_NPHY_RFCTL_INTC1);
+               nphy->rfctrl_intc2_save = b43_phy_read(dev,
+                                                      B43_NPHY_RFCTL_INTC2);
+               band = b43_current_band(dev->wl);
+               if (dev->phy.rev >= 3) {
+                       if (band == IEEE80211_BAND_5GHZ)
+                               tmp = 0x600;
+                       else
+                               tmp = 0x480;
+               } else {
+                       if (band == IEEE80211_BAND_5GHZ)
+                               tmp = 0x180;
+                       else
+                               tmp = 0x120;
+               }
+               b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, tmp);
+               b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, tmp);
+       } else {
+               b43_phy_write(dev, B43_NPHY_RFCTL_INTC1,
+                               nphy->rfctrl_intc1_save);
+               b43_phy_write(dev, B43_NPHY_RFCTL_INTC2,
+                               nphy->rfctrl_intc2_save);
+       }
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxLpFbw */
+static void b43_nphy_tx_lp_fbw(struct b43_wldev *dev)
+{
+       struct b43_phy_n *nphy = dev->phy.n;
+       u16 tmp;
+       enum ieee80211_band band = b43_current_band(dev->wl);
+       bool ipa = (nphy->ipa2g_on && band == IEEE80211_BAND_2GHZ) ||
+                       (nphy->ipa5g_on && band == IEEE80211_BAND_5GHZ);
+
+       if (dev->phy.rev >= 3) {
+               if (ipa) {
+                       tmp = 4;
+                       b43_phy_write(dev, B43_NPHY_TXF_40CO_B32S2,
+                             (((((tmp << 3) | tmp) << 3) | tmp) << 3) | tmp);
+               }
+
+               tmp = 1;
+               b43_phy_write(dev, B43_NPHY_TXF_40CO_B1S2,
+                             (((((tmp << 3) | tmp) << 3) | tmp) << 3) | tmp);
+       }
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/BmacPhyClkFgc */
+static void b43_nphy_bmac_clock_fgc(struct b43_wldev *dev, bool force)
+{
+       u32 tmslow;
+
+       if (dev->phy.type != B43_PHYTYPE_N)
+               return;
+
+       tmslow = ssb_read32(dev->dev, SSB_TMSLOW);
+       if (force)
+               tmslow |= SSB_TMSLOW_FGC;
+       else
+               tmslow &= ~SSB_TMSLOW_FGC;
+       ssb_write32(dev->dev, SSB_TMSLOW, tmslow);
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/CCA */
 static void b43_nphy_reset_cca(struct b43_wldev *dev)
 {
        u16 bbcfg;
 
-       ssb_write32(dev->dev, SSB_TMSLOW,
-                   ssb_read32(dev->dev, SSB_TMSLOW) | SSB_TMSLOW_FGC);
+       b43_nphy_bmac_clock_fgc(dev, 1);
        bbcfg = b43_phy_read(dev, B43_NPHY_BBCFG);
-       b43_phy_set(dev, B43_NPHY_BBCFG, B43_NPHY_BBCFG_RSTCCA);
-       b43_phy_write(dev, B43_NPHY_BBCFG,
-                     bbcfg & ~B43_NPHY_BBCFG_RSTCCA);
-       ssb_write32(dev->dev, SSB_TMSLOW,
-                   ssb_read32(dev->dev, SSB_TMSLOW) & ~SSB_TMSLOW_FGC);
+       b43_phy_write(dev, B43_NPHY_BBCFG, bbcfg | B43_NPHY_BBCFG_RSTCCA);
+       udelay(1);
+       b43_phy_write(dev, B43_NPHY_BBCFG, bbcfg & ~B43_NPHY_BBCFG_RSTCCA);
+       b43_nphy_bmac_clock_fgc(dev, 0);
+       /* TODO: N PHY Force RF Seq with argument 2 */
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RxIqEst */
+static void b43_nphy_rx_iq_est(struct b43_wldev *dev, struct nphy_iq_est *est,
+                               u16 samps, u8 time, bool wait)
+{
+       int i;
+       u16 tmp;
+
+       b43_phy_write(dev, B43_NPHY_IQEST_SAMCNT, samps);
+       b43_phy_maskset(dev, B43_NPHY_IQEST_WT, ~B43_NPHY_IQEST_WT_VAL, time);
+       if (wait)
+               b43_phy_set(dev, B43_NPHY_IQEST_CMD, B43_NPHY_IQEST_CMD_MODE);
+       else
+               b43_phy_mask(dev, B43_NPHY_IQEST_CMD, ~B43_NPHY_IQEST_CMD_MODE);
+
+       b43_phy_set(dev, B43_NPHY_IQEST_CMD, B43_NPHY_IQEST_CMD_START);
+
+       for (i = 1000; i; i--) {
+               tmp = b43_phy_read(dev, B43_NPHY_IQEST_CMD);
+               if (!(tmp & B43_NPHY_IQEST_CMD_START)) {
+                       est->i0_pwr = (b43_phy_read(dev, B43_NPHY_IQEST_IPACC_HI0) << 16) |
+                                       b43_phy_read(dev, B43_NPHY_IQEST_IPACC_LO0);
+                       est->q0_pwr = (b43_phy_read(dev, B43_NPHY_IQEST_QPACC_HI0) << 16) |
+                                       b43_phy_read(dev, B43_NPHY_IQEST_QPACC_LO0);
+                       est->iq0_prod = (b43_phy_read(dev, B43_NPHY_IQEST_IQACC_HI0) << 16) |
+                                       b43_phy_read(dev, B43_NPHY_IQEST_IQACC_LO0);
+
+                       est->i1_pwr = (b43_phy_read(dev, B43_NPHY_IQEST_IPACC_HI1) << 16) |
+                                       b43_phy_read(dev, B43_NPHY_IQEST_IPACC_LO1);
+                       est->q1_pwr = (b43_phy_read(dev, B43_NPHY_IQEST_QPACC_HI1) << 16) |
+                                       b43_phy_read(dev, B43_NPHY_IQEST_QPACC_LO1);
+                       est->iq1_prod = (b43_phy_read(dev, B43_NPHY_IQEST_IQACC_HI1) << 16) |
+                                       b43_phy_read(dev, B43_NPHY_IQEST_IQACC_LO1);
+                       return;
+               }
+               udelay(10);
+       }
+       memset(est, 0, sizeof(*est));
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RxIqCoeffs */
+static void b43_nphy_rx_iq_coeffs(struct b43_wldev *dev, bool write,
+                                       struct b43_phy_n_iq_comp *pcomp)
+{
+       if (write) {
+               b43_phy_write(dev, B43_NPHY_C1_RXIQ_COMPA0, pcomp->a0);
+               b43_phy_write(dev, B43_NPHY_C1_RXIQ_COMPB0, pcomp->b0);
+               b43_phy_write(dev, B43_NPHY_C2_RXIQ_COMPA1, pcomp->a1);
+               b43_phy_write(dev, B43_NPHY_C2_RXIQ_COMPB1, pcomp->b1);
+       } else {
+               pcomp->a0 = b43_phy_read(dev, B43_NPHY_C1_RXIQ_COMPA0);
+               pcomp->b0 = b43_phy_read(dev, B43_NPHY_C1_RXIQ_COMPB0);
+               pcomp->a1 = b43_phy_read(dev, B43_NPHY_C2_RXIQ_COMPA1);
+               pcomp->b1 = b43_phy_read(dev, B43_NPHY_C2_RXIQ_COMPB1);
+       }
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/CalcRxIqComp */
+static void b43_nphy_calc_rx_iq_comp(struct b43_wldev *dev, u8 mask)
+{
+       int i;
+       s32 iq;
+       u32 ii;
+       u32 qq;
+       int iq_nbits, qq_nbits;
+       int arsh, brsh;
+       u16 tmp, a, b;
+
+       struct nphy_iq_est est;
+       struct b43_phy_n_iq_comp old;
+       struct b43_phy_n_iq_comp new = { };
+       bool error = false;
+
+       if (mask == 0)
+               return;
+
+       b43_nphy_rx_iq_coeffs(dev, false, &old);
+       b43_nphy_rx_iq_coeffs(dev, true, &new);
+       b43_nphy_rx_iq_est(dev, &est, 0x4000, 32, false);
+       new = old;
+
+       for (i = 0; i < 2; i++) {
+               if (i == 0 && (mask & 1)) {
+                       iq = est.iq0_prod;
+                       ii = est.i0_pwr;
+                       qq = est.q0_pwr;
+               } else if (i == 1 && (mask & 2)) {
+                       iq = est.iq1_prod;
+                       ii = est.i1_pwr;
+                       qq = est.q1_pwr;
+               } else {
+                       B43_WARN_ON(1);
+                       continue;
+               }
+
+               if (ii + qq < 2) {
+                       error = true;
+                       break;
+               }
+
+               iq_nbits = fls(abs(iq));
+               qq_nbits = fls(qq);
+
+               arsh = iq_nbits - 20;
+               if (arsh >= 0) {
+                       a = -((iq << (30 - iq_nbits)) + (ii >> (1 + arsh)));
+                       tmp = ii >> arsh;
+               } else {
+                       a = -((iq << (30 - iq_nbits)) + (ii << (-1 - arsh)));
+                       tmp = ii << -arsh;
+               }
+               if (tmp == 0) {
+                       error = true;
+                       break;
+               }
+               a /= tmp;
+
+               brsh = qq_nbits - 11;
+               if (brsh >= 0) {
+                       b = (qq << (31 - qq_nbits));
+                       tmp = ii >> brsh;
+               } else {
+                       b = (qq << (31 - qq_nbits));
+                       tmp = ii << -brsh;
+               }
+               if (tmp == 0) {
+                       error = true;
+                       break;
+               }
+               b = int_sqrt(b / tmp - a * a) - (1 << 10);
+
+               if (i == 0 && (mask & 0x1)) {
+                       if (dev->phy.rev >= 3) {
+                               new.a0 = a & 0x3FF;
+                               new.b0 = b & 0x3FF;
+                       } else {
+                               new.a0 = b & 0x3FF;
+                               new.b0 = a & 0x3FF;
+                       }
+               } else if (i == 1 && (mask & 0x2)) {
+                       if (dev->phy.rev >= 3) {
+                               new.a1 = a & 0x3FF;
+                               new.b1 = b & 0x3FF;
+                       } else {
+                               new.a1 = b & 0x3FF;
+                               new.b1 = a & 0x3FF;
+                       }
+               }
+       }
+
+       if (error)
+               new = old;
+
+       b43_nphy_rx_iq_coeffs(dev, true, &new);
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxIqWar */
+static void b43_nphy_tx_iq_workaround(struct b43_wldev *dev)
+{
+       u16 array[4];
+       int i;
+
+       b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x3C50);
+       for (i = 0; i < 4; i++)
+               array[i] = b43_phy_read(dev, B43_NPHY_TABLE_DATALO);
+
+       b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_NPHY_TXIQW0, array[0]);
+       b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_NPHY_TXIQW1, array[1]);
+       b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_NPHY_TXIQW2, array[2]);
+       b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_NPHY_TXIQW3, array[3]);
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/clip-detection */
+static void b43_nphy_write_clip_detection(struct b43_wldev *dev, u16 *clip_st)
+{
+       b43_phy_write(dev, B43_NPHY_C1_CLIP1THRES, clip_st[0]);
+       b43_phy_write(dev, B43_NPHY_C2_CLIP1THRES, clip_st[1]);
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/clip-detection */
+static void b43_nphy_read_clip_detection(struct b43_wldev *dev, u16 *clip_st)
+{
+       clip_st[0] = b43_phy_read(dev, B43_NPHY_C1_CLIP1THRES);
+       clip_st[1] = b43_phy_read(dev, B43_NPHY_C2_CLIP1THRES);
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/classifier */
+static u16 b43_nphy_classifier(struct b43_wldev *dev, u16 mask, u16 val)
+{
+       u16 tmp;
+
+       if (dev->dev->id.revision == 16)
+               b43_mac_suspend(dev);
+
+       tmp = b43_phy_read(dev, B43_NPHY_CLASSCTL);
+       tmp &= (B43_NPHY_CLASSCTL_CCKEN | B43_NPHY_CLASSCTL_OFDMEN |
+               B43_NPHY_CLASSCTL_WAITEDEN);
+       tmp &= ~mask;
+       tmp |= (val & mask);
+       b43_phy_maskset(dev, B43_NPHY_CLASSCTL, 0xFFF8, tmp);
+
+       if (dev->dev->id.revision == 16)
+               b43_mac_enable(dev);
+
+       return tmp;
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/carriersearch */
+static void b43_nphy_stay_in_carrier_search(struct b43_wldev *dev, bool enable)
+{
+       struct b43_phy *phy = &dev->phy;
+       struct b43_phy_n *nphy = phy->n;
+
+       if (enable) {
+               u16 clip[] = { 0xFFFF, 0xFFFF };
+               if (nphy->deaf_count++ == 0) {
+                       nphy->classifier_state = b43_nphy_classifier(dev, 0, 0);
+                       b43_nphy_classifier(dev, 0x7, 0);
+                       b43_nphy_read_clip_detection(dev, nphy->clip_state);
+                       b43_nphy_write_clip_detection(dev, clip);
+               }
+               b43_nphy_reset_cca(dev);
+       } else {
+               if (--nphy->deaf_count == 0) {
+                       b43_nphy_classifier(dev, 0x7, nphy->classifier_state);
+                       b43_nphy_write_clip_detection(dev, nphy->clip_state);
+               }
+       }
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxPwrCtrlCoefSetup */
+static void b43_nphy_tx_pwr_ctrl_coef_setup(struct b43_wldev *dev)
+{
+       struct b43_phy_n *nphy = dev->phy.n;
+       int i, j;
+       u32 tmp;
+       u32 cur_real, cur_imag, real_part, imag_part;
+
+       u16 buffer[7];
+
+       if (nphy->hang_avoid)
+               b43_nphy_stay_in_carrier_search(dev, true);
+
+       /* TODO: Read an N PHY Table with ID 15, length 7, offset 80,
+               width 16, and data pointer buffer */
+
+       for (i = 0; i < 2; i++) {
+               tmp = ((buffer[i * 2] & 0x3FF) << 10) |
+                       (buffer[i * 2 + 1] & 0x3FF);
+               b43_phy_write(dev, B43_NPHY_TABLE_ADDR,
+                               (((i + 26) << 10) | 320));
+               for (j = 0; j < 128; j++) {
+                       b43_phy_write(dev, B43_NPHY_TABLE_DATAHI,
+                                       ((tmp >> 16) & 0xFFFF));
+                       b43_phy_write(dev, B43_NPHY_TABLE_DATALO,
+                                       (tmp & 0xFFFF));
+               }
+       }
+
+       for (i = 0; i < 2; i++) {
+               tmp = buffer[5 + i];
+               real_part = (tmp >> 8) & 0xFF;
+               imag_part = (tmp & 0xFF);
+               b43_phy_write(dev, B43_NPHY_TABLE_ADDR,
+                               (((i + 26) << 10) | 448));
+
+               if (dev->phy.rev >= 3) {
+                       cur_real = real_part;
+                       cur_imag = imag_part;
+                       tmp = ((cur_real & 0xFF) << 8) | (cur_imag & 0xFF);
+               }
+
+               for (j = 0; j < 128; j++) {
+                       if (dev->phy.rev < 3) {
+                               cur_real = (real_part * loscale[j] + 128) >> 8;
+                               cur_imag = (imag_part * loscale[j] + 128) >> 8;
+                               tmp = ((cur_real & 0xFF) << 8) |
+                                       (cur_imag & 0xFF);
+                       }
+                       b43_phy_write(dev, B43_NPHY_TABLE_DATAHI,
+                                       ((tmp >> 16) & 0xFFFF));
+                       b43_phy_write(dev, B43_NPHY_TABLE_DATALO,
+                                       (tmp & 0xFFFF));
+               }
+       }
+
+       if (dev->phy.rev >= 3) {
+               b43_shm_write16(dev, B43_SHM_SHARED,
+                               B43_SHM_SH_NPHY_TXPWR_INDX0, 0xFFFF);
+               b43_shm_write16(dev, B43_SHM_SHARED,
+                               B43_SHM_SH_NPHY_TXPWR_INDX1, 0xFFFF);
+       }
+
+       if (nphy->hang_avoid)
+               b43_nphy_stay_in_carrier_search(dev, false);
 }
 
 enum b43_nphy_rf_sequence {
@@ -411,81 +776,1339 @@ static void b43_nphy_bphy_init(struct b43_wldev *dev)
        b43_phy_write(dev, B43_PHY_N_BMODE(0x38), 0x668);
 }
 
-/* RSSI Calibration */
-static void b43_nphy_rssi_cal(struct b43_wldev *dev, u8 type)
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/ScaleOffsetRssi */
+static void b43_nphy_scale_offset_rssi(struct b43_wldev *dev, u16 scale,
+                                      s8 offset, u8 core, u8 rail, u8 type)
 {
-       //TODO
+       u16 tmp;
+       bool core1or5 = (core == 1) || (core == 5);
+       bool core2or5 = (core == 2) || (core == 5);
+
+       offset = clamp_val(offset, -32, 31);
+       tmp = ((scale & 0x3F) << 8) | (offset & 0x3F);
+
+       if (core1or5 && (rail == 0) && (type == 2))
+               b43_phy_write(dev, B43_NPHY_RSSIMC_0I_RSSI_Z, tmp);
+       if (core1or5 && (rail == 1) && (type == 2))
+               b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_RSSI_Z, tmp);
+       if (core2or5 && (rail == 0) && (type == 2))
+               b43_phy_write(dev, B43_NPHY_RSSIMC_1I_RSSI_Z, tmp);
+       if (core2or5 && (rail == 1) && (type == 2))
+               b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_RSSI_Z, tmp);
+       if (core1or5 && (rail == 0) && (type == 0))
+               b43_phy_write(dev, B43_NPHY_RSSIMC_0I_RSSI_X, tmp);
+       if (core1or5 && (rail == 1) && (type == 0))
+               b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_RSSI_X, tmp);
+       if (core2or5 && (rail == 0) && (type == 0))
+               b43_phy_write(dev, B43_NPHY_RSSIMC_1I_RSSI_X, tmp);
+       if (core2or5 && (rail == 1) && (type == 0))
+               b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_RSSI_X, tmp);
+       if (core1or5 && (rail == 0) && (type == 1))
+               b43_phy_write(dev, B43_NPHY_RSSIMC_0I_RSSI_Y, tmp);
+       if (core1or5 && (rail == 1) && (type == 1))
+               b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_RSSI_Y, tmp);
+       if (core2or5 && (rail == 0) && (type == 1))
+               b43_phy_write(dev, B43_NPHY_RSSIMC_1I_RSSI_Y, tmp);
+       if (core2or5 && (rail == 1) && (type == 1))
+               b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_RSSI_Y, tmp);
+       if (core1or5 && (rail == 0) && (type == 6))
+               b43_phy_write(dev, B43_NPHY_RSSIMC_0I_TBD, tmp);
+       if (core1or5 && (rail == 1) && (type == 6))
+               b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_TBD, tmp);
+       if (core2or5 && (rail == 0) && (type == 6))
+               b43_phy_write(dev, B43_NPHY_RSSIMC_1I_TBD, tmp);
+       if (core2or5 && (rail == 1) && (type == 6))
+               b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_TBD, tmp);
+       if (core1or5 && (rail == 0) && (type == 3))
+               b43_phy_write(dev, B43_NPHY_RSSIMC_0I_PWRDET, tmp);
+       if (core1or5 && (rail == 1) && (type == 3))
+               b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_PWRDET, tmp);
+       if (core2or5 && (rail == 0) && (type == 3))
+               b43_phy_write(dev, B43_NPHY_RSSIMC_1I_PWRDET, tmp);
+       if (core2or5 && (rail == 1) && (type == 3))
+               b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_PWRDET, tmp);
+       if (core1or5 && (type == 4))
+               b43_phy_write(dev, B43_NPHY_RSSIMC_0I_TSSI, tmp);
+       if (core2or5 && (type == 4))
+               b43_phy_write(dev, B43_NPHY_RSSIMC_1I_TSSI, tmp);
+       if (core1or5 && (type == 5))
+               b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_TSSI, tmp);
+       if (core2or5 && (type == 5))
+               b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_TSSI, tmp);
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSISel */
+static void b43_nphy_rssi_select(struct b43_wldev *dev, u8 code, u8 type)
+{
+       u16 val;
+
+       if (dev->phy.rev >= 3) {
+               /* TODO */
+       } else {
+               if (type < 3)
+                       val = 0;
+               else if (type == 6)
+                       val = 1;
+               else if (type == 3)
+                       val = 2;
+               else
+                       val = 3;
+
+               val = (val << 12) | (val << 14);
+               b43_phy_maskset(dev, B43_NPHY_AFECTL_C1, 0x0FFF, val);
+               b43_phy_maskset(dev, B43_NPHY_AFECTL_C2, 0x0FFF, val);
+
+               if (type < 3) {
+                       b43_phy_maskset(dev, B43_NPHY_RFCTL_RSSIO1, 0xFFCF,
+                                       (type + 1) << 4);
+                       b43_phy_maskset(dev, B43_NPHY_RFCTL_RSSIO2, 0xFFCF,
+                                       (type + 1) << 4);
+               }
+
+               /* TODO use some definitions */
+               if (code == 0) {
+                       b43_phy_maskset(dev, B43_NPHY_AFECTL_OVER, 0xCFFF, 0);
+                       if (type < 3) {
+                               b43_phy_maskset(dev, B43_NPHY_RFCTL_CMD,
+                                               0xFEC7, 0);
+                               b43_phy_maskset(dev, B43_NPHY_RFCTL_OVER,
+                                               0xEFDC, 0);
+                               b43_phy_maskset(dev, B43_NPHY_RFCTL_CMD,
+                                               0xFFFE, 0);
+                               udelay(20);
+                               b43_phy_maskset(dev, B43_NPHY_RFCTL_OVER,
+                                               0xFFFE, 0);
+                       }
+               } else {
+                       b43_phy_maskset(dev, B43_NPHY_AFECTL_OVER, 0xCFFF,
+                                       0x3000);
+                       if (type < 3) {
+                               b43_phy_maskset(dev, B43_NPHY_RFCTL_CMD,
+                                               0xFEC7, 0x0180);
+                               b43_phy_maskset(dev, B43_NPHY_RFCTL_OVER,
+                                               0xEFDC, (code << 1 | 0x1021));
+                               b43_phy_maskset(dev, B43_NPHY_RFCTL_CMD,
+                                               0xFFFE, 0x0001);
+                               udelay(20);
+                               b43_phy_maskset(dev, B43_NPHY_RFCTL_OVER,
+                                               0xFFFE, 0);
+                       }
+               }
+       }
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/SetRssi2055Vcm */
+static void b43_nphy_set_rssi_2055_vcm(struct b43_wldev *dev, u8 type, u8 *buf)
+{
+       int i;
+       for (i = 0; i < 2; i++) {
+               if (type == 2) {
+                       if (i == 0) {
+                               b43_radio_maskset(dev, B2055_C1_B0NB_RSSIVCM,
+                                                 0xFC, buf[0]);
+                               b43_radio_maskset(dev, B2055_C1_RX_BB_RSSICTL5,
+                                                 0xFC, buf[1]);
+                       } else {
+                               b43_radio_maskset(dev, B2055_C2_B0NB_RSSIVCM,
+                                                 0xFC, buf[2 * i]);
+                               b43_radio_maskset(dev, B2055_C2_RX_BB_RSSICTL5,
+                                                 0xFC, buf[2 * i + 1]);
+                       }
+               } else {
+                       if (i == 0)
+                               b43_radio_maskset(dev, B2055_C1_RX_BB_RSSICTL5,
+                                                 0xF3, buf[0] << 2);
+                       else
+                               b43_radio_maskset(dev, B2055_C2_RX_BB_RSSICTL5,
+                                                 0xF3, buf[2 * i + 1] << 2);
+               }
+       }
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/PollRssi */
+static int b43_nphy_poll_rssi(struct b43_wldev *dev, u8 type, s32 *buf,
+                               u8 nsamp)
+{
+       int i;
+       int out;
+       u16 save_regs_phy[9];
+       u16 s[2];
+
+       if (dev->phy.rev >= 3) {
+               save_regs_phy[0] = b43_phy_read(dev,
+                                               B43_NPHY_RFCTL_LUT_TRSW_UP1);
+               save_regs_phy[1] = b43_phy_read(dev,
+                                               B43_NPHY_RFCTL_LUT_TRSW_UP2);
+               save_regs_phy[2] = b43_phy_read(dev, B43_NPHY_AFECTL_C1);
+               save_regs_phy[3] = b43_phy_read(dev, B43_NPHY_AFECTL_C2);
+               save_regs_phy[4] = b43_phy_read(dev, B43_NPHY_AFECTL_OVER1);
+               save_regs_phy[5] = b43_phy_read(dev, B43_NPHY_AFECTL_OVER);
+               save_regs_phy[6] = b43_phy_read(dev, B43_NPHY_TXF_40CO_B1S0);
+               save_regs_phy[7] = b43_phy_read(dev, B43_NPHY_TXF_40CO_B32S1);
+       }
+
+       b43_nphy_rssi_select(dev, 5, type);
+
+       if (dev->phy.rev < 2) {
+               save_regs_phy[8] = b43_phy_read(dev, B43_NPHY_GPIO_SEL);
+               b43_phy_write(dev, B43_NPHY_GPIO_SEL, 5);
+       }
+
+       for (i = 0; i < 4; i++)
+               buf[i] = 0;
+
+       for (i = 0; i < nsamp; i++) {
+               if (dev->phy.rev < 2) {
+                       s[0] = b43_phy_read(dev, B43_NPHY_GPIO_LOOUT);
+                       s[1] = b43_phy_read(dev, B43_NPHY_GPIO_HIOUT);
+               } else {
+                       s[0] = b43_phy_read(dev, B43_NPHY_RSSI1);
+                       s[1] = b43_phy_read(dev, B43_NPHY_RSSI2);
+               }
+
+               buf[0] += ((s8)((s[0] & 0x3F) << 2)) >> 2;
+               buf[1] += ((s8)(((s[0] >> 8) & 0x3F) << 2)) >> 2;
+               buf[2] += ((s8)((s[1] & 0x3F) << 2)) >> 2;
+               buf[3] += ((s8)(((s[1] >> 8) & 0x3F) << 2)) >> 2;
+       }
+       out = (buf[0] & 0xFF) << 24 | (buf[1] & 0xFF) << 16 |
+               (buf[2] & 0xFF) << 8 | (buf[3] & 0xFF);
+
+       if (dev->phy.rev < 2)
+               b43_phy_write(dev, B43_NPHY_GPIO_SEL, save_regs_phy[8]);
+
+       if (dev->phy.rev >= 3) {
+               b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP1,
+                               save_regs_phy[0]);
+               b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP2,
+                               save_regs_phy[1]);
+               b43_phy_write(dev, B43_NPHY_AFECTL_C1, save_regs_phy[2]);
+               b43_phy_write(dev, B43_NPHY_AFECTL_C2, save_regs_phy[3]);
+               b43_phy_write(dev, B43_NPHY_AFECTL_OVER1, save_regs_phy[4]);
+               b43_phy_write(dev, B43_NPHY_AFECTL_OVER, save_regs_phy[5]);
+               b43_phy_write(dev, B43_NPHY_TXF_40CO_B1S0, save_regs_phy[6]);
+               b43_phy_write(dev, B43_NPHY_TXF_40CO_B32S1, save_regs_phy[7]);
+       }
+
+       return out;
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSICal */
+static void b43_nphy_rev2_rssi_cal(struct b43_wldev *dev, u8 type)
+{
+       int i, j;
+       u8 state[4];
+       u8 code, val;
+       u16 class, override;
+       u8 regs_save_radio[2];
+       u16 regs_save_phy[2];
+       s8 offset[4];
+
+       u16 clip_state[2];
+       u16 clip_off[2] = { 0xFFFF, 0xFFFF };
+       s32 results_min[4] = { };
+       u8 vcm_final[4] = { };
+       s32 results[4][4] = { };
+       s32 miniq[4][2] = { };
+
+       if (type == 2) {
+               code = 0;
+               val = 6;
+       } else if (type < 2) {
+               code = 25;
+               val = 4;
+       } else {
+               B43_WARN_ON(1);
+               return;
+       }
+
+       class = b43_nphy_classifier(dev, 0, 0);
+       b43_nphy_classifier(dev, 7, 4);
+       b43_nphy_read_clip_detection(dev, clip_state);
+       b43_nphy_write_clip_detection(dev, clip_off);
+
+       if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ)
+               override = 0x140;
+       else
+               override = 0x110;
+
+       regs_save_phy[0] = b43_phy_read(dev, B43_NPHY_RFCTL_INTC1);
+       regs_save_radio[0] = b43_radio_read16(dev, B2055_C1_PD_RXTX);
+       b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, override);
+       b43_radio_write16(dev, B2055_C1_PD_RXTX, val);
+
+       regs_save_phy[1] = b43_phy_read(dev, B43_NPHY_RFCTL_INTC2);
+       regs_save_radio[1] = b43_radio_read16(dev, B2055_C2_PD_RXTX);
+       b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, override);
+       b43_radio_write16(dev, B2055_C2_PD_RXTX, val);
+
+       state[0] = b43_radio_read16(dev, B2055_C1_PD_RSSIMISC) & 0x07;
+       state[1] = b43_radio_read16(dev, B2055_C2_PD_RSSIMISC) & 0x07;
+       b43_radio_mask(dev, B2055_C1_PD_RSSIMISC, 0xF8);
+       b43_radio_mask(dev, B2055_C2_PD_RSSIMISC, 0xF8);
+       state[2] = b43_radio_read16(dev, B2055_C1_SP_RSSI) & 0x07;
+       state[3] = b43_radio_read16(dev, B2055_C2_SP_RSSI) & 0x07;
+
+       b43_nphy_rssi_select(dev, 5, type);
+       b43_nphy_scale_offset_rssi(dev, 0, 0, 5, 0, type);
+       b43_nphy_scale_offset_rssi(dev, 0, 0, 5, 1, type);
+
+       for (i = 0; i < 4; i++) {
+               u8 tmp[4];
+               for (j = 0; j < 4; j++)
+                       tmp[j] = i;
+               if (type != 1)
+                       b43_nphy_set_rssi_2055_vcm(dev, type, tmp);
+               b43_nphy_poll_rssi(dev, type, results[i], 8);
+               if (type < 2)
+                       for (j = 0; j < 2; j++)
+                               miniq[i][j] = min(results[i][2 * j],
+                                               results[i][2 * j + 1]);
+       }
+
+       for (i = 0; i < 4; i++) {
+               s32 mind = 40;
+               u8 minvcm = 0;
+               s32 minpoll = 249;
+               s32 curr;
+               for (j = 0; j < 4; j++) {
+                       if (type == 2)
+                               curr = abs(results[j][i]);
+                       else
+                               curr = abs(miniq[j][i / 2] - code * 8);
+
+                       if (curr < mind) {
+                               mind = curr;
+                               minvcm = j;
+                       }
+
+                       if (results[j][i] < minpoll)
+                               minpoll = results[j][i];
+               }
+               results_min[i] = minpoll;
+               vcm_final[i] = minvcm;
+       }
+
+       if (type != 1)
+               b43_nphy_set_rssi_2055_vcm(dev, type, vcm_final);
+
+       for (i = 0; i < 4; i++) {
+               offset[i] = (code * 8) - results[vcm_final[i]][i];
+
+               if (offset[i] < 0)
+                       offset[i] = -((abs(offset[i]) + 4) / 8);
+               else
+                       offset[i] = (offset[i] + 4) / 8;
+
+               if (results_min[i] == 248)
+                       offset[i] = code - 32;
+
+               if (i % 2 == 0)
+                       b43_nphy_scale_offset_rssi(dev, 0, offset[i], 1, 0,
+                                                       type);
+               else
+                       b43_nphy_scale_offset_rssi(dev, 0, offset[i], 2, 1,
+                                                       type);
+       }
+
+       b43_radio_maskset(dev, B2055_C1_PD_RSSIMISC, 0xF8, state[0]);
+       b43_radio_maskset(dev, B2055_C1_PD_RSSIMISC, 0xF8, state[1]);
+
+       switch (state[2]) {
+       case 1:
+               b43_nphy_rssi_select(dev, 1, 2);
+               break;
+       case 4:
+               b43_nphy_rssi_select(dev, 1, 0);
+               break;
+       case 2:
+               b43_nphy_rssi_select(dev, 1, 1);
+               break;
+       default:
+               b43_nphy_rssi_select(dev, 1, 1);
+               break;
+       }
+
+       switch (state[3]) {
+       case 1:
+               b43_nphy_rssi_select(dev, 2, 2);
+               break;
+       case 4:
+               b43_nphy_rssi_select(dev, 2, 0);
+               break;
+       default:
+               b43_nphy_rssi_select(dev, 2, 1);
+               break;
+       }
+
+       b43_nphy_rssi_select(dev, 0, type);
+
+       b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, regs_save_phy[0]);
+       b43_radio_write16(dev, B2055_C1_PD_RXTX, regs_save_radio[0]);
+       b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, regs_save_phy[1]);
+       b43_radio_write16(dev, B2055_C2_PD_RXTX, regs_save_radio[1]);
+
+       b43_nphy_classifier(dev, 7, class);
+       b43_nphy_write_clip_detection(dev, clip_state);
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSICalRev3 */
+static void b43_nphy_rev3_rssi_cal(struct b43_wldev *dev)
+{
+       /* TODO */
+}
+
+/*
+ * RSSI Calibration
+ * http://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSICal
+ */
+static void b43_nphy_rssi_cal(struct b43_wldev *dev)
+{
+       if (dev->phy.rev >= 3) {
+               b43_nphy_rev3_rssi_cal(dev);
+       } else {
+               b43_nphy_rev2_rssi_cal(dev, 2);
+               b43_nphy_rev2_rssi_cal(dev, 0);
+               b43_nphy_rev2_rssi_cal(dev, 1);
+       }
+}
+
+/*
+ * Restore RSSI Calibration
+ * http://bcm-v4.sipsolutions.net/802.11/PHY/N/RestoreRssiCal
+ */
+static void b43_nphy_restore_rssi_cal(struct b43_wldev *dev)
+{
+       struct b43_phy_n *nphy = dev->phy.n;
+
+       u16 *rssical_radio_regs = NULL;
+       u16 *rssical_phy_regs = NULL;
+
+       if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
+               if (!nphy->rssical_chanspec_2G)
+                       return;
+               rssical_radio_regs = nphy->rssical_cache.rssical_radio_regs_2G;
+               rssical_phy_regs = nphy->rssical_cache.rssical_phy_regs_2G;
+       } else {
+               if (!nphy->rssical_chanspec_5G)
+                       return;
+               rssical_radio_regs = nphy->rssical_cache.rssical_radio_regs_5G;
+               rssical_phy_regs = nphy->rssical_cache.rssical_phy_regs_5G;
+       }
+
+       /* TODO use some definitions */
+       b43_radio_maskset(dev, 0x602B, 0xE3, rssical_radio_regs[0]);
+       b43_radio_maskset(dev, 0x702B, 0xE3, rssical_radio_regs[1]);
+
+       b43_phy_write(dev, B43_NPHY_RSSIMC_0I_RSSI_Z, rssical_phy_regs[0]);
+       b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_RSSI_Z, rssical_phy_regs[1]);
+       b43_phy_write(dev, B43_NPHY_RSSIMC_1I_RSSI_Z, rssical_phy_regs[2]);
+       b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_RSSI_Z, rssical_phy_regs[3]);
+
+       b43_phy_write(dev, B43_NPHY_RSSIMC_0I_RSSI_X, rssical_phy_regs[4]);
+       b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_RSSI_X, rssical_phy_regs[5]);
+       b43_phy_write(dev, B43_NPHY_RSSIMC_1I_RSSI_X, rssical_phy_regs[6]);
+       b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_RSSI_X, rssical_phy_regs[7]);
+
+       b43_phy_write(dev, B43_NPHY_RSSIMC_0I_RSSI_Y, rssical_phy_regs[8]);
+       b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_RSSI_Y, rssical_phy_regs[9]);
+       b43_phy_write(dev, B43_NPHY_RSSIMC_1I_RSSI_Y, rssical_phy_regs[10]);
+       b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_RSSI_Y, rssical_phy_regs[11]);
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/GetIpaGainTbl */
+static const u32 *b43_nphy_get_ipa_gain_table(struct b43_wldev *dev)
+{
+       if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
+               if (dev->phy.rev >= 6) {
+                       /* TODO If the chip is 47162
+                               return txpwrctrl_tx_gain_ipa_rev5 */
+                       return txpwrctrl_tx_gain_ipa_rev6;
+               } else if (dev->phy.rev >= 5) {
+                       return txpwrctrl_tx_gain_ipa_rev5;
+               } else {
+                       return txpwrctrl_tx_gain_ipa;
+               }
+       } else {
+               return txpwrctrl_tx_gain_ipa_5g;
+       }
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxCalRadioSetup */
+static void b43_nphy_tx_cal_radio_setup(struct b43_wldev *dev)
+{
+       struct b43_phy_n *nphy = dev->phy.n;
+       u16 *save = nphy->tx_rx_cal_radio_saveregs;
+
+       if (dev->phy.rev >= 3) {
+               /* TODO */
+       } else {
+               save[0] = b43_radio_read16(dev, B2055_C1_TX_RF_IQCAL1);
+               b43_radio_write16(dev, B2055_C1_TX_RF_IQCAL1, 0x29);
+
+               save[1] = b43_radio_read16(dev, B2055_C1_TX_RF_IQCAL2);
+               b43_radio_write16(dev, B2055_C1_TX_RF_IQCAL2, 0x54);
+
+               save[2] = b43_radio_read16(dev, B2055_C2_TX_RF_IQCAL1);
+               b43_radio_write16(dev, B2055_C2_TX_RF_IQCAL1, 0x29);
+
+               save[3] = b43_radio_read16(dev, B2055_C2_TX_RF_IQCAL2);
+               b43_radio_write16(dev, B2055_C2_TX_RF_IQCAL2, 0x54);
+
+               save[3] = b43_radio_read16(dev, B2055_C1_PWRDET_RXTX);
+               save[4] = b43_radio_read16(dev, B2055_C2_PWRDET_RXTX);
+
+               if (!(b43_phy_read(dev, B43_NPHY_BANDCTL) &
+                   B43_NPHY_BANDCTL_5GHZ)) {
+                       b43_radio_write16(dev, B2055_C1_PWRDET_RXTX, 0x04);
+                       b43_radio_write16(dev, B2055_C2_PWRDET_RXTX, 0x04);
+               } else {
+                       b43_radio_write16(dev, B2055_C1_PWRDET_RXTX, 0x20);
+                       b43_radio_write16(dev, B2055_C2_PWRDET_RXTX, 0x20);
+               }
+
+               if (dev->phy.rev < 2) {
+                       b43_radio_set(dev, B2055_C1_TX_BB_MXGM, 0x20);
+                       b43_radio_set(dev, B2055_C2_TX_BB_MXGM, 0x20);
+               } else {
+                       b43_radio_mask(dev, B2055_C1_TX_BB_MXGM, ~0x20);
+                       b43_radio_mask(dev, B2055_C2_TX_BB_MXGM, ~0x20);
+               }
+       }
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/IqCalGainParams */
+static void b43_nphy_iq_cal_gain_params(struct b43_wldev *dev, u16 core,
+                                       struct nphy_txgains target,
+                                       struct nphy_iqcal_params *params)
+{
+       int i, j, indx;
+       u16 gain;
+
+       if (dev->phy.rev >= 3) {
+               params->txgm = target.txgm[core];
+               params->pga = target.pga[core];
+               params->pad = target.pad[core];
+               params->ipa = target.ipa[core];
+               params->cal_gain = (params->txgm << 12) | (params->pga << 8) |
+                                       (params->pad << 4) | (params->ipa);
+               for (j = 0; j < 5; j++)
+                       params->ncorr[j] = 0x79;
+       } else {
+               gain = (target.pad[core]) | (target.pga[core] << 4) |
+                       (target.txgm[core] << 8);
+
+               indx = (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) ?
+                       1 : 0;
+               for (i = 0; i < 9; i++)
+                       if (tbl_iqcal_gainparams[indx][i][0] == gain)
+                               break;
+               i = min(i, 8);
+
+               params->txgm = tbl_iqcal_gainparams[indx][i][1];
+               params->pga = tbl_iqcal_gainparams[indx][i][2];
+               params->pad = tbl_iqcal_gainparams[indx][i][3];
+               params->cal_gain = (params->txgm << 7) | (params->pga << 4) |
+                                       (params->pad << 2);
+               for (j = 0; j < 4; j++)
+                       params->ncorr[j] = tbl_iqcal_gainparams[indx][i][4 + j];
+       }
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/UpdateTxCalLadder */
+static void b43_nphy_update_tx_cal_ladder(struct b43_wldev *dev, u16 core)
+{
+       struct b43_phy_n *nphy = dev->phy.n;
+       int i;
+       u16 scale, entry;
+
+       u16 tmp = nphy->txcal_bbmult;
+       if (core == 0)
+               tmp >>= 8;
+       tmp &= 0xff;
+
+       for (i = 0; i < 18; i++) {
+               scale = (ladder_lo[i].percent * tmp) / 100;
+               entry = ((scale & 0xFF) << 8) | ladder_lo[i].g_env;
+               /* TODO: Write an N PHY Table with ID 15, length 1,
+                       offset i, width 16, and data entry */
+
+               scale = (ladder_iq[i].percent * tmp) / 100;
+               entry = ((scale & 0xFF) << 8) | ladder_iq[i].g_env;
+               /* TODO: Write an N PHY Table with ID 15, length 1,
+                       offset i + 32, width 16, and data entry */
+       }
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/GetTxGain */
+static struct nphy_txgains b43_nphy_get_tx_gains(struct b43_wldev *dev)
+{
+       struct b43_phy_n *nphy = dev->phy.n;
+
+       u16 curr_gain[2];
+       struct nphy_txgains target;
+       const u32 *table = NULL;
+
+       if (nphy->txpwrctrl == 0) {
+               int i;
+
+               if (nphy->hang_avoid)
+                       b43_nphy_stay_in_carrier_search(dev, true);
+               /* TODO: Read an N PHY Table with ID 7, length 2,
+                       offset 0x110, width 16, and curr_gain */
+               if (nphy->hang_avoid)
+                       b43_nphy_stay_in_carrier_search(dev, false);
+
+               for (i = 0; i < 2; ++i) {
+                       if (dev->phy.rev >= 3) {
+                               target.ipa[i] = curr_gain[i] & 0x000F;
+                               target.pad[i] = (curr_gain[i] & 0x00F0) >> 4;
+                               target.pga[i] = (curr_gain[i] & 0x0F00) >> 8;
+                               target.txgm[i] = (curr_gain[i] & 0x7000) >> 12;
+                       } else {
+                               target.ipa[i] = curr_gain[i] & 0x0003;
+                               target.pad[i] = (curr_gain[i] & 0x000C) >> 2;
+                               target.pga[i] = (curr_gain[i] & 0x0070) >> 4;
+                               target.txgm[i] = (curr_gain[i] & 0x0380) >> 7;
+                       }
+               }
+       } else {
+               int i;
+               u16 index[2];
+               index[0] = (b43_phy_read(dev, B43_NPHY_C1_TXPCTL_STAT) &
+                       B43_NPHY_TXPCTL_STAT_BIDX) >>
+                       B43_NPHY_TXPCTL_STAT_BIDX_SHIFT;
+               index[1] = (b43_phy_read(dev, B43_NPHY_C2_TXPCTL_STAT) &
+                       B43_NPHY_TXPCTL_STAT_BIDX) >>
+                       B43_NPHY_TXPCTL_STAT_BIDX_SHIFT;
+
+               for (i = 0; i < 2; ++i) {
+                       if (dev->phy.rev >= 3) {
+                               enum ieee80211_band band =
+                                       b43_current_band(dev->wl);
+
+                               if ((nphy->ipa2g_on &&
+                                    band == IEEE80211_BAND_2GHZ) ||
+                                   (nphy->ipa5g_on &&
+                                    band == IEEE80211_BAND_5GHZ)) {
+                                       table = b43_nphy_get_ipa_gain_table(dev);
+                               } else {
+                                       if (band == IEEE80211_BAND_5GHZ) {
+                                               if (dev->phy.rev == 3)
+                                                       table = b43_ntab_tx_gain_rev3_5ghz;
+                                               else if (dev->phy.rev == 4)
+                                                       table = b43_ntab_tx_gain_rev4_5ghz;
+                                               else
+                                                       table = b43_ntab_tx_gain_rev5plus_5ghz;
+                                       } else {
+                                               table = b43_ntab_tx_gain_rev3plus_2ghz;
+                                       }
+                               }
+
+                               target.ipa[i] = (table[index[i]] >> 16) & 0xF;
+                               target.pad[i] = (table[index[i]] >> 20) & 0xF;
+                               target.pga[i] = (table[index[i]] >> 24) & 0xF;
+                               target.txgm[i] = (table[index[i]] >> 28) & 0xF;
+                       } else {
+                               table = b43_ntab_tx_gain_rev0_1_2;
+
+                               target.ipa[i] = (table[index[i]] >> 16) & 0x3;
+                               target.pad[i] = (table[index[i]] >> 18) & 0x3;
+                               target.pga[i] = (table[index[i]] >> 20) & 0x7;
+                               target.txgm[i] = (table[index[i]] >> 23) & 0x7;
+                       }
+               }
+       }
+
+       return target;
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RestoreCal */
+static void b43_nphy_restore_cal(struct b43_wldev *dev)
+{
+       struct b43_phy_n *nphy = dev->phy.n;
+
+       u16 coef[4];
+       u16 *loft = NULL;
+       u16 *table = NULL;
+
+       int i;
+       u16 *txcal_radio_regs = NULL;
+       struct b43_phy_n_iq_comp *rxcal_coeffs = NULL;
+
+       if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
+               if (nphy->iqcal_chanspec_2G == 0)
+                       return;
+               table = nphy->cal_cache.txcal_coeffs_2G;
+               loft = &nphy->cal_cache.txcal_coeffs_2G[5];
+       } else {
+               if (nphy->iqcal_chanspec_5G == 0)
+                       return;
+               table = nphy->cal_cache.txcal_coeffs_5G;
+               loft = &nphy->cal_cache.txcal_coeffs_5G[5];
+       }
+
+       /* TODO: Write an N PHY table with ID 15, length 4, offset 80,
+               width 16, and data from table */
+
+       for (i = 0; i < 4; i++) {
+               if (dev->phy.rev >= 3)
+                       table[i] = coef[i];
+               else
+                       coef[i] = 0;
+       }
+
+       /* TODO: Write an N PHY table with ID 15, length 4, offset 88,
+               width 16, and data from coef */
+       /* TODO: Write an N PHY table with ID 15, length 2, offset 85,
+               width 16 and data from loft */
+       /* TODO: Write an N PHY table with ID 15, length 2, offset 93,
+               width 16 and data from loft */
+
+       if (dev->phy.rev < 2)
+               b43_nphy_tx_iq_workaround(dev);
+
+       if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
+               txcal_radio_regs = nphy->cal_cache.txcal_radio_regs_2G;
+               rxcal_coeffs = &nphy->cal_cache.rxcal_coeffs_2G;
+       } else {
+               txcal_radio_regs = nphy->cal_cache.txcal_radio_regs_5G;
+               rxcal_coeffs = &nphy->cal_cache.rxcal_coeffs_5G;
+       }
+
+       /* TODO use some definitions */
+       if (dev->phy.rev >= 3) {
+               b43_radio_write(dev, 0x2021, txcal_radio_regs[0]);
+               b43_radio_write(dev, 0x2022, txcal_radio_regs[1]);
+               b43_radio_write(dev, 0x3021, txcal_radio_regs[2]);
+               b43_radio_write(dev, 0x3022, txcal_radio_regs[3]);
+               b43_radio_write(dev, 0x2023, txcal_radio_regs[4]);
+               b43_radio_write(dev, 0x2024, txcal_radio_regs[5]);
+               b43_radio_write(dev, 0x3023, txcal_radio_regs[6]);
+               b43_radio_write(dev, 0x3024, txcal_radio_regs[7]);
+       } else {
+               b43_radio_write(dev, 0x8B, txcal_radio_regs[0]);
+               b43_radio_write(dev, 0xBA, txcal_radio_regs[1]);
+               b43_radio_write(dev, 0x8D, txcal_radio_regs[2]);
+               b43_radio_write(dev, 0xBC, txcal_radio_regs[3]);
+       }
+       b43_nphy_rx_iq_coeffs(dev, true, rxcal_coeffs);
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/CalTxIqlo */
+static int b43_nphy_cal_tx_iq_lo(struct b43_wldev *dev,
+                               struct nphy_txgains target,
+                               bool full, bool mphase)
+{
+       struct b43_phy_n *nphy = dev->phy.n;
+       int i;
+       int error = 0;
+       int freq;
+       bool avoid = false;
+       u8 length;
+       u16 tmp, core, type, count, max, numb, last, cmd;
+       const u16 *table;
+       bool phy6or5x;
+
+       u16 buffer[11];
+       u16 diq_start = 0;
+       u16 save[2];
+       u16 gain[2];
+       struct nphy_iqcal_params params[2];
+       bool updated[2] = { };
+
+       b43_nphy_stay_in_carrier_search(dev, true);
+
+       if (dev->phy.rev >= 4) {
+               avoid = nphy->hang_avoid;
+               nphy->hang_avoid = 0;
+       }
+
+       /* TODO: Read an N PHY Table with ID 7, length 2, offset 0x110,
+               width 16, and data pointer save */
+
+       for (i = 0; i < 2; i++) {
+               b43_nphy_iq_cal_gain_params(dev, i, target, &params[i]);
+               gain[i] = params[i].cal_gain;
+       }
+       /* TODO: Write an N PHY Table with ID 7, length 2, offset 0x110,
+               width 16, and data pointer gain */
+
+       b43_nphy_tx_cal_radio_setup(dev);
+       /* TODO: Call N PHY TX Cal PHY Setup */
+
+       phy6or5x = dev->phy.rev >= 6 ||
+               (dev->phy.rev == 5 && nphy->ipa2g_on &&
+               b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ);
+       if (phy6or5x) {
+               /* TODO */
+       }
+
+       b43_phy_write(dev, B43_NPHY_IQLOCAL_CMDGCTL, 0x8AA9);
+
+       if (1 /* FIXME: the band width is 20 MHz */)
+               freq = 2500;
+       else
+               freq = 5000;
+
+       if (nphy->mphase_cal_phase_id > 2)
+               ;/* TODO: Call N PHY Run Samples with (band width * 8),
+                       0xFFFF, 0, 1, 0 as arguments */
+       else
+               ;/* TODO: Call N PHY TX Tone with freq, 250, 1, 0 as arguments
+                       and save result as error */
+
+       if (error == 0) {
+               if (nphy->mphase_cal_phase_id > 2) {
+                       table = nphy->mphase_txcal_bestcoeffs;
+                       length = 11;
+                       if (dev->phy.rev < 3)
+                               length -= 2;
+               } else {
+                       if (!full && nphy->txiqlocal_coeffsvalid) {
+                               table = nphy->txiqlocal_bestc;
+                               length = 11;
+                               if (dev->phy.rev < 3)
+                                       length -= 2;
+                       } else {
+                               full = true;
+                               if (dev->phy.rev >= 3) {
+                                       table = tbl_tx_iqlo_cal_startcoefs_nphyrev3;
+                                       length = B43_NTAB_TX_IQLO_CAL_STARTCOEFS_REV3;
+                               } else {
+                                       table = tbl_tx_iqlo_cal_startcoefs;
+                                       length = B43_NTAB_TX_IQLO_CAL_STARTCOEFS;
+                               }
+                       }
+               }
+
+               /* TODO: Write an N PHY Table with ID 15, length from above,
+                       offset 64, width 16, and the data pointer from above */
+
+               if (full) {
+                       if (dev->phy.rev >= 3)
+                               max = B43_NTAB_TX_IQLO_CAL_CMDS_FULLCAL_REV3;
+                       else
+                               max = B43_NTAB_TX_IQLO_CAL_CMDS_FULLCAL;
+               } else {
+                       if (dev->phy.rev >= 3)
+                               max = B43_NTAB_TX_IQLO_CAL_CMDS_RECAL_REV3;
+                       else
+                               max = B43_NTAB_TX_IQLO_CAL_CMDS_RECAL;
+               }
+
+               if (mphase) {
+                       count = nphy->mphase_txcal_cmdidx;
+                       numb = min(max,
+                               (u16)(count + nphy->mphase_txcal_numcmds));
+               } else {
+                       count = 0;
+                       numb = max;
+               }
+
+               for (; count < numb; count++) {
+                       if (full) {
+                               if (dev->phy.rev >= 3)
+                                       cmd = tbl_tx_iqlo_cal_cmds_fullcal_nphyrev3[count];
+                               else
+                                       cmd = tbl_tx_iqlo_cal_cmds_fullcal[count];
+                       } else {
+                               if (dev->phy.rev >= 3)
+                                       cmd = tbl_tx_iqlo_cal_cmds_recal_nphyrev3[count];
+                               else
+                                       cmd = tbl_tx_iqlo_cal_cmds_recal[count];
+                       }
+
+                       core = (cmd & 0x3000) >> 12;
+                       type = (cmd & 0x0F00) >> 8;
+
+                       if (phy6or5x && updated[core] == 0) {
+                               b43_nphy_update_tx_cal_ladder(dev, core);
+                               updated[core] = 1;
+                       }
+
+                       tmp = (params[core].ncorr[type] << 8) | 0x66;
+                       b43_phy_write(dev, B43_NPHY_IQLOCAL_CMDNNUM, tmp);
+
+                       if (type == 1 || type == 3 || type == 4) {
+                               /* TODO: Read an N PHY Table with ID 15,
+                                       length 1, offset 69 + core,
+                                       width 16, and data pointer buffer */
+                               diq_start = buffer[0];
+                               buffer[0] = 0;
+                               /* TODO: Write an N PHY Table with ID 15,
+                                       length 1, offset 69 + core, width 16,
+                                       and data of 0 */
+                       }
+
+                       b43_phy_write(dev, B43_NPHY_IQLOCAL_CMD, cmd);
+                       for (i = 0; i < 2000; i++) {
+                               tmp = b43_phy_read(dev, B43_NPHY_IQLOCAL_CMD);
+                               if (tmp & 0xC000)
+                                       break;
+                               udelay(10);
+                       }
+
+                       /* TODO: Read an N PHY Table with ID 15,
+                               length table_length, offset 96, width 16,
+                               and data pointer buffer */
+                       /* TODO: Write an N PHY Table with ID 15,
+                               length table_length, offset 64, width 16,
+                               and data pointer buffer */
+
+                       if (type == 1 || type == 3 || type == 4)
+                               buffer[0] = diq_start;
+               }
+
+               if (mphase)
+                       nphy->mphase_txcal_cmdidx = (numb >= max) ? 0 : numb;
+
+               last = (dev->phy.rev < 3) ? 6 : 7;
+
+               if (!mphase || nphy->mphase_cal_phase_id == last) {
+                       /* TODO: Write an N PHY Table with ID 15, length 4,
+                               offset 96, width 16, and data pointer buffer */
+                       /* TODO: Read an N PHY Table with ID 15, length 4,
+                               offset 80, width 16, and data pointer buffer */
+                       if (dev->phy.rev < 3) {
+                               buffer[0] = 0;
+                               buffer[1] = 0;
+                               buffer[2] = 0;
+                               buffer[3] = 0;
+                       }
+                       /* TODO: Write an N PHY Table with ID 15, length 4,
+                               offset 88, width 16, and data pointer buffer */
+                       /* TODO: Read an N PHY Table with ID 15, length 2,
+                               offset 101, width 16, and data pointer buffer*/
+                       /* TODO: Write an N PHY Table with ID 15, length 2,
+                               offset 85, width 16, and data pointer buffer */
+                       /* TODO: Write an N PHY Table with ID 15, length 2,
+                               offset 93, width 16, and data pointer buffer */
+                       length = 11;
+                       if (dev->phy.rev < 3)
+                               length -= 2;
+                       /* TODO: Read an N PHY Table with ID 15, length length,
+                               offset 96, width 16, and data pointer
+                               nphy->txiqlocal_bestc */
+                       nphy->txiqlocal_coeffsvalid = true;
+                       /* TODO: Set nphy->txiqlocal_chanspec to
+                               the current channel */
+               } else {
+                       length = 11;
+                       if (dev->phy.rev < 3)
+                               length -= 2;
+                       /* TODO: Read an N PHY Table with ID 5, length length,
+                               offset 96, width 16, and data pointer
+                               nphy->mphase_txcal_bestcoeffs */
+               }
+
+               /* TODO: Call N PHY Stop Playback */
+               b43_phy_write(dev, B43_NPHY_IQLOCAL_CMDGCTL, 0);
+       }
+
+       /* TODO: Call N PHY TX Cal PHY Cleanup */
+       /* TODO: Write an N PHY Table with ID 7, length 2, offset 0x110,
+               width 16, and data from save */
+
+       if (dev->phy.rev < 2 && (!mphase || nphy->mphase_cal_phase_id == last))
+               b43_nphy_tx_iq_workaround(dev);
+
+       if (dev->phy.rev >= 4)
+               nphy->hang_avoid = avoid;
+
+       b43_nphy_stay_in_carrier_search(dev, false);
+
+       return error;
 }
 
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/CalRxIqRev2 */
+static int b43_nphy_rev2_cal_rx_iq(struct b43_wldev *dev,
+                       struct nphy_txgains target, u8 type, bool debug)
+{
+       struct b43_phy_n *nphy = dev->phy.n;
+       int i, j, index;
+       u8 rfctl[2];
+       u8 afectl_core;
+       u16 tmp[6];
+       u16 cur_hpf1, cur_hpf2, cur_lna;
+       u32 real, imag;
+       enum ieee80211_band band;
+
+       u8 use;
+       u16 cur_hpf;
+       u16 lna[3] = { 3, 3, 1 };
+       u16 hpf1[3] = { 7, 2, 0 };
+       u16 hpf2[3] = { 2, 0, 0 };
+       u32 power[3];
+       u16 gain_save[2];
+       u16 cal_gain[2];
+       struct nphy_iqcal_params cal_params[2];
+       struct nphy_iq_est est;
+       int ret = 0;
+       bool playtone = true;
+       int desired = 13;
+
+       b43_nphy_stay_in_carrier_search(dev, 1);
+
+       if (dev->phy.rev < 2)
+               ;/* TODO: Call N PHY Reapply TX Cal Coeffs */
+       /* TODO: Read an N PHY Table with ID 7, length 2, offset 0x110,
+               width 16, and data gain_save */
+       for (i = 0; i < 2; i++) {
+               b43_nphy_iq_cal_gain_params(dev, i, target, &cal_params[i]);
+               cal_gain[i] = cal_params[i].cal_gain;
+       }
+       /* TODO: Write an N PHY Table with ID 7, length 2, offset 0x110,
+               width 16, and data from cal_gain */
+
+       for (i = 0; i < 2; i++) {
+               if (i == 0) {
+                       rfctl[0] = B43_NPHY_RFCTL_INTC1;
+                       rfctl[1] = B43_NPHY_RFCTL_INTC2;
+                       afectl_core = B43_NPHY_AFECTL_C1;
+               } else {
+                       rfctl[0] = B43_NPHY_RFCTL_INTC2;
+                       rfctl[1] = B43_NPHY_RFCTL_INTC1;
+                       afectl_core = B43_NPHY_AFECTL_C2;
+               }
+
+               tmp[1] = b43_phy_read(dev, B43_NPHY_RFSEQCA);
+               tmp[2] = b43_phy_read(dev, afectl_core);
+               tmp[3] = b43_phy_read(dev, B43_NPHY_AFECTL_OVER);
+               tmp[4] = b43_phy_read(dev, rfctl[0]);
+               tmp[5] = b43_phy_read(dev, rfctl[1]);
+
+               b43_phy_maskset(dev, B43_NPHY_RFSEQCA,
+                               (u16)~B43_NPHY_RFSEQCA_RXDIS,
+                               ((1 - i) << B43_NPHY_RFSEQCA_RXDIS_SHIFT));
+               b43_phy_maskset(dev, B43_NPHY_RFSEQCA, ~B43_NPHY_RFSEQCA_TXEN,
+                               (1 - i));
+               b43_phy_set(dev, afectl_core, 0x0006);
+               b43_phy_set(dev, B43_NPHY_AFECTL_OVER, 0x0006);
+
+               band = b43_current_band(dev->wl);
+
+               if (nphy->rxcalparams & 0xFF000000) {
+                       if (band == IEEE80211_BAND_5GHZ)
+                               b43_phy_write(dev, rfctl[0], 0x140);
+                       else
+                               b43_phy_write(dev, rfctl[0], 0x110);
+               } else {
+                       if (band == IEEE80211_BAND_5GHZ)
+                               b43_phy_write(dev, rfctl[0], 0x180);
+                       else
+                               b43_phy_write(dev, rfctl[0], 0x120);
+               }
+
+               if (band == IEEE80211_BAND_5GHZ)
+                       b43_phy_write(dev, rfctl[1], 0x148);
+               else
+                       b43_phy_write(dev, rfctl[1], 0x114);
+
+               if (nphy->rxcalparams & 0x10000) {
+                       b43_radio_maskset(dev, B2055_C1_GENSPARE2, 0xFC,
+                                       (i + 1));
+                       b43_radio_maskset(dev, B2055_C2_GENSPARE2, 0xFC,
+                                       (2 - i));
+               }
+
+               for (j = 0; i < 4; j++) {
+                       if (j < 3) {
+                               cur_lna = lna[j];
+                               cur_hpf1 = hpf1[j];
+                               cur_hpf2 = hpf2[j];
+                       } else {
+                               if (power[1] > 10000) {
+                                       use = 1;
+                                       cur_hpf = cur_hpf1;
+                                       index = 2;
+                               } else {
+                                       if (power[0] > 10000) {
+                                               use = 1;
+                                               cur_hpf = cur_hpf1;
+                                               index = 1;
+                                       } else {
+                                               index = 0;
+                                               use = 2;
+                                               cur_hpf = cur_hpf2;
+                                       }
+                               }
+                               cur_lna = lna[index];
+                               cur_hpf1 = hpf1[index];
+                               cur_hpf2 = hpf2[index];
+                               cur_hpf += desired - hweight32(power[index]);
+                               cur_hpf = clamp_val(cur_hpf, 0, 10);
+                               if (use == 1)
+                                       cur_hpf1 = cur_hpf;
+                               else
+                                       cur_hpf2 = cur_hpf;
+                       }
+
+                       tmp[0] = ((cur_hpf2 << 8) | (cur_hpf1 << 4) |
+                                       (cur_lna << 2));
+                       /* TODO:Call N PHY RF Ctrl Override with 0x400, tmp[0],
+                               3, 0 as arguments */
+                       /* TODO: Call N PHY Force RF Seq with 2 as argument */
+                       /* TODO: Call N PHT Stop Playback */
+
+                       if (playtone) {
+                               /* TODO: Call N PHY TX Tone with 4000,
+                                       (nphy_rxcalparams & 0xffff), 0, 0
+                                       as arguments and save result as ret */
+                               playtone = false;
+                       } else {
+                               /* TODO: Call N PHY Run Samples with 160,
+                                       0xFFFF, 0, 0, 0 as arguments */
+                       }
+
+                       if (ret == 0) {
+                               if (j < 3) {
+                                       b43_nphy_rx_iq_est(dev, &est, 1024, 32,
+                                                                       false);
+                                       if (i == 0) {
+                                               real = est.i0_pwr;
+                                               imag = est.q0_pwr;
+                                       } else {
+                                               real = est.i1_pwr;
+                                               imag = est.q1_pwr;
+                                       }
+                                       power[i] = ((real + imag) / 1024) + 1;
+                               } else {
+                                       b43_nphy_calc_rx_iq_comp(dev, 1 << i);
+                               }
+                               /* TODO: Call N PHY Stop Playback */
+                       }
+
+                       if (ret != 0)
+                               break;
+               }
+
+               b43_radio_mask(dev, B2055_C1_GENSPARE2, 0xFC);
+               b43_radio_mask(dev, B2055_C2_GENSPARE2, 0xFC);
+               b43_phy_write(dev, rfctl[1], tmp[5]);
+               b43_phy_write(dev, rfctl[0], tmp[4]);
+               b43_phy_write(dev, B43_NPHY_AFECTL_OVER, tmp[3]);
+               b43_phy_write(dev, afectl_core, tmp[2]);
+               b43_phy_write(dev, B43_NPHY_RFSEQCA, tmp[1]);
+
+               if (ret != 0)
+                       break;
+       }
+
+       /* TODO: Call N PHY RF Ctrl Override with 0x400, 0, 3, 1 as arguments*/
+       /* TODO: Call N PHY Force RF Seq with 2 as argument */
+       /* TODO: Write an N PHY Table with ID 7, length 2, offset 0x110,
+               width 16, and data from gain_save */
+
+       b43_nphy_stay_in_carrier_search(dev, 0);
+
+       return ret;
+}
+
+static int b43_nphy_rev3_cal_rx_iq(struct b43_wldev *dev,
+                       struct nphy_txgains target, u8 type, bool debug)
+{
+       return -1;
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/CalRxIq */
+static int b43_nphy_cal_rx_iq(struct b43_wldev *dev,
+                       struct nphy_txgains target, u8 type, bool debug)
+{
+       if (dev->phy.rev >= 3)
+               return b43_nphy_rev3_cal_rx_iq(dev, target, type, debug);
+       else
+               return b43_nphy_rev2_cal_rx_iq(dev, target, type, debug);
+}
+
+/*
+ * Init N-PHY
+ * http://bcm-v4.sipsolutions.net/802.11/PHY/Init/N
+ */
 int b43_phy_initn(struct b43_wldev *dev)
 {
+       struct ssb_bus *bus = dev->dev->bus;
        struct b43_phy *phy = &dev->phy;
+       struct b43_phy_n *nphy = phy->n;
+       u8 tx_pwr_state;
+       struct nphy_txgains target;
        u16 tmp;
+       enum ieee80211_band tmp2;
+       bool do_rssi_cal;
+
+       u16 clip[2];
+       bool do_cal = false;
 
-       //TODO: Spectral management
+       if ((dev->phy.rev >= 3) &&
+          (bus->sprom.boardflags_lo & B43_BFL_EXTLNA) &&
+          (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)) {
+               chipco_set32(&dev->dev->bus->chipco, SSB_CHIPCO_CHIPCTL, 0x40);
+       }
+       nphy->deaf_count = 0;
        b43_nphy_tables_init(dev);
+       nphy->crsminpwr_adjusted = false;
+       nphy->noisevars_adjusted = false;
 
        /* Clear all overrides */
-       b43_phy_write(dev, B43_NPHY_RFCTL_OVER, 0);
+       if (dev->phy.rev >= 3) {
+               b43_phy_write(dev, B43_NPHY_TXF_40CO_B1S1, 0);
+               b43_phy_write(dev, B43_NPHY_RFCTL_OVER, 0);
+               b43_phy_write(dev, B43_NPHY_TXF_40CO_B1S0, 0);
+               b43_phy_write(dev, B43_NPHY_TXF_40CO_B32S1, 0);
+       } else {
+               b43_phy_write(dev, B43_NPHY_RFCTL_OVER, 0);
+       }
        b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, 0);
        b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, 0);
-       b43_phy_write(dev, B43_NPHY_RFCTL_INTC3, 0);
-       b43_phy_write(dev, B43_NPHY_RFCTL_INTC4, 0);
+       if (dev->phy.rev < 6) {
+               b43_phy_write(dev, B43_NPHY_RFCTL_INTC3, 0);
+               b43_phy_write(dev, B43_NPHY_RFCTL_INTC4, 0);
+       }
        b43_phy_mask(dev, B43_NPHY_RFSEQMODE,
                     ~(B43_NPHY_RFSEQMODE_CAOVER |
                       B43_NPHY_RFSEQMODE_TROVER));
+       if (dev->phy.rev >= 3)
+               b43_phy_write(dev, B43_NPHY_AFECTL_OVER1, 0);
        b43_phy_write(dev, B43_NPHY_AFECTL_OVER, 0);
 
-       tmp = (phy->rev < 2) ? 64 : 59;
-       b43_phy_maskset(dev, B43_NPHY_BPHY_CTL3,
-                       ~B43_NPHY_BPHY_CTL3_SCALE,
-                       tmp << B43_NPHY_BPHY_CTL3_SCALE_SHIFT);
-
+       if (dev->phy.rev <= 2) {
+               tmp = (dev->phy.rev == 2) ? 0x3B : 0x40;
+               b43_phy_maskset(dev, B43_NPHY_BPHY_CTL3,
+                               ~B43_NPHY_BPHY_CTL3_SCALE,
+                               tmp << B43_NPHY_BPHY_CTL3_SCALE_SHIFT);
+       }
        b43_phy_write(dev, B43_NPHY_AFESEQ_TX2RX_PUD_20M, 0x20);
        b43_phy_write(dev, B43_NPHY_AFESEQ_TX2RX_PUD_40M, 0x20);
 
-       b43_phy_write(dev, B43_NPHY_TXREALFD, 184);
-       b43_phy_write(dev, B43_NPHY_MIMO_CRSTXEXT, 200);
-       b43_phy_write(dev, B43_NPHY_PLOAD_CSENSE_EXTLEN, 80);
-       b43_phy_write(dev, B43_NPHY_C2_BCLIPBKOFF, 511);
+       if (bus->sprom.boardflags2_lo & 0x100 ||
+           (bus->boardinfo.vendor == PCI_VENDOR_ID_APPLE &&
+            bus->boardinfo.type == 0x8B))
+               b43_phy_write(dev, B43_NPHY_TXREALFD, 0xA0);
+       else
+               b43_phy_write(dev, B43_NPHY_TXREALFD, 0xB8);
+       b43_phy_write(dev, B43_NPHY_MIMO_CRSTXEXT, 0xC8);
+       b43_phy_write(dev, B43_NPHY_PLOAD_CSENSE_EXTLEN, 0x50);
+       b43_phy_write(dev, B43_NPHY_TXRIFS_FRDEL, 0x30);
 
-       //TODO MIMO-Config
-       //TODO Update TX/RX chain
+       /* TODO MIMO-Config */
+       /* TODO Update TX/RX chain */
 
        if (phy->rev < 2) {
                b43_phy_write(dev, B43_NPHY_DUP40_GFBL, 0xAA8);
                b43_phy_write(dev, B43_NPHY_DUP40_BL, 0x9A4);
        }
+
+       tmp2 = b43_current_band(dev->wl);
+       if ((nphy->ipa2g_on && tmp2 == IEEE80211_BAND_2GHZ) ||
+           (nphy->ipa5g_on && tmp2 == IEEE80211_BAND_5GHZ)) {
+               b43_phy_set(dev, B43_NPHY_PAPD_EN0, 0x1);
+               b43_phy_maskset(dev, B43_NPHY_EPS_TABLE_ADJ0, 0x007F,
+                               nphy->papd_epsilon_offset[0] << 7);
+               b43_phy_set(dev, B43_NPHY_PAPD_EN1, 0x1);
+               b43_phy_maskset(dev, B43_NPHY_EPS_TABLE_ADJ1, 0x007F,
+                               nphy->papd_epsilon_offset[1] << 7);
+               /* TODO N PHY IPA Set TX Dig Filters */
+       } else if (phy->rev >= 5) {
+               /* TODO N PHY Ext PA Set TX Dig Filters */
+       }
+
        b43_nphy_workarounds(dev);
-       b43_nphy_reset_cca(dev);
 
-       ssb_write32(dev->dev, SSB_TMSLOW,
-                   ssb_read32(dev->dev, SSB_TMSLOW) | B43_TMSLOW_MACPHYCLKEN);
+       /* Reset CCA, in init code it differs a little from standard way */
+       b43_nphy_bmac_clock_fgc(dev, 1);
+       tmp = b43_phy_read(dev, B43_NPHY_BBCFG);
+       b43_phy_write(dev, B43_NPHY_BBCFG, tmp | B43_NPHY_BBCFG_RSTCCA);
+       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_pa_override(dev, false);
        b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RX2TX);
        b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX);
+       b43_nphy_pa_override(dev, true);
+
+       b43_nphy_classifier(dev, 0, 0);
+       b43_nphy_read_clip_detection(dev, clip);
+       tx_pwr_state = nphy->txpwrctrl;
+       /* TODO N PHY TX power control with argument 0
+               (turning off power control) */
+       /* TODO Fix the TX Power Settings */
+       /* TODO N PHY TX Power Control Idle TSSI */
+       /* TODO N PHY TX Power Control Setup */
+
+       if (phy->rev >= 3) {
+               /* TODO */
+       } else {
+               /* TODO Write an N PHY table with ID 26, length 128, offset 192, width 32, and the data from Rev 2 TX Power Control Table */
+               /* TODO Write an N PHY table with ID 27, length 128, offset 192, width 32, and the data from Rev 2 TX Power Control Table */
+       }
+
+       if (nphy->phyrxchain != 3)
+               ;/* TODO N PHY RX Core Set State with phyrxchain as argument */
+       if (nphy->mphase_cal_phase_id > 0)
+               ;/* TODO PHY Periodic Calibration Multi-Phase Restart */
+
+       do_rssi_cal = false;
+       if (phy->rev >= 3) {
+               if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
+                       do_rssi_cal = (nphy->rssical_chanspec_2G == 0);
+               else
+                       do_rssi_cal = (nphy->rssical_chanspec_5G == 0);
+
+               if (do_rssi_cal)
+                       b43_nphy_rssi_cal(dev);
+               else
+                       b43_nphy_restore_rssi_cal(dev);
+       } else {
+               b43_nphy_rssi_cal(dev);
+       }
+
+       if (!((nphy->measure_hold & 0x6) != 0)) {
+               if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
+                       do_cal = (nphy->iqcal_chanspec_2G == 0);
+               else
+                       do_cal = (nphy->iqcal_chanspec_5G == 0);
+
+               if (nphy->mute)
+                       do_cal = false;
+
+               if (do_cal) {
+                       target = b43_nphy_get_tx_gains(dev);
+
+                       if (nphy->antsel_type == 2)
+                               ;/*TODO NPHY Superswitch Init with argument 1*/
+                       if (nphy->perical != 2) {
+                               b43_nphy_rssi_cal(dev);
+                               if (phy->rev >= 3) {
+                                       nphy->cal_orig_pwr_idx[0] =
+                                           nphy->txpwrindex[0].index_internal;
+                                       nphy->cal_orig_pwr_idx[1] =
+                                           nphy->txpwrindex[1].index_internal;
+                                       /* TODO N PHY Pre Calibrate TX Gain */
+                                       target = b43_nphy_get_tx_gains(dev);
+                               }
+                       }
+               }
+       }
+
+       if (!b43_nphy_cal_tx_iq_lo(dev, target, true, false)) {
+               if (b43_nphy_cal_rx_iq(dev, target, 2, 0) == 0)
+                       ;/* Call N PHY Save Cal */
+               else if (nphy->mphase_cal_phase_id == 0)
+                       ;/* N PHY Periodic Calibration with argument 3 */
+       } else {
+               b43_nphy_restore_cal(dev);
+       }
 
-       b43_phy_read(dev, B43_NPHY_CLASSCTL); /* dummy read */
-       //TODO read core1/2 clip1 thres regs
-
-       if (1 /* FIXME Band is 2.4GHz */)
-               b43_nphy_bphy_init(dev);
-       //TODO disable TX power control
-       //TODO Fix the TX power settings
-       //TODO Init periodic calibration with reason 3
-       b43_nphy_rssi_cal(dev, 2);
-       b43_nphy_rssi_cal(dev, 0);
-       b43_nphy_rssi_cal(dev, 1);
-       //TODO get TX gain
-       //TODO init superswitch
-       //TODO calibrate LO
-       //TODO idle TSSI TX pctl
-       //TODO TX power control power setup
-       //TODO table writes
-       //TODO TX power control coefficients
-       //TODO enable TX power control
-       //TODO control antenna selection
-       //TODO init radar detection
-       //TODO reset channel if changed
+       b43_nphy_tx_pwr_ctrl_coef_setup(dev);
+       /* TODO N PHY TX Power Control Enable with argument tx_pwr_state */
+       b43_phy_write(dev, B43_NPHY_TXMACIF_HOLDOFF, 0x0015);
+       b43_phy_write(dev, B43_NPHY_TXMACDELAY, 0x0320);
+       if (phy->rev >= 3 && phy->rev <= 6)
+               b43_phy_write(dev, B43_NPHY_PLOAD_CSENSE_EXTLEN, 0x0014);
+       b43_nphy_tx_lp_fbw(dev);
+       /* TODO N PHY Spur Workaround */
 
        b43err(dev->wl, "IEEE 802.11n devices are not supported, yet.\n");
        return 0;
index 1749aef4147d45891604e41439e46ec40232a44a..4572866756fc9f6b0f899356c28877659edd2ee7 100644 (file)
 #define B43_NPHY_C2_TXIQ_COMP_OFF              B43_PHY_N(0x088) /* Core 2 TX I/Q comp offset */
 #define B43_NPHY_C1_TXCTL                      B43_PHY_N(0x08B) /* Core 1 TX control */
 #define B43_NPHY_C2_TXCTL                      B43_PHY_N(0x08C) /* Core 2 TX control */
+#define B43_NPHY_AFECTL_OVER1                  B43_PHY_N(0x08F) /* AFE control override 1 */
 #define B43_NPHY_SCRAM_SIGCTL                  B43_PHY_N(0x090) /* Scram signal control */
 #define  B43_NPHY_SCRAM_SIGCTL_INITST          0x007F /* Initial state value */
 #define  B43_NPHY_SCRAM_SIGCTL_INITST_SHIFT    0
 #define B43_NPHY_TXPCTL_INIT                   B43_PHY_N(0x222) /* TX power controll init */
 #define  B43_NPHY_TXPCTL_INIT_PIDXI1           0x00FF /* Power index init 1 */
 #define  B43_NPHY_TXPCTL_INIT_PIDXI1_SHIFT     0
+#define B43_NPHY_PAPD_EN0                      B43_PHY_N(0x297) /* PAPD Enable0 TBD */
+#define B43_NPHY_EPS_TABLE_ADJ0                        B43_PHY_N(0x298) /* EPS Table Adj0 TBD */
+#define B43_NPHY_PAPD_EN1                      B43_PHY_N(0x29B) /* PAPD Enable1 TBD */
+#define B43_NPHY_EPS_TABLE_ADJ1                        B43_PHY_N(0x29C) /* EPS Table Adj1 TBD */
 
 
 
 
 struct b43_wldev;
 
+struct b43_phy_n_iq_comp {
+       s16 a0;
+       s16 b0;
+       s16 a1;
+       s16 b1;
+};
+
+struct b43_phy_n_rssical_cache {
+       u16 rssical_radio_regs_2G[2];
+       u16 rssical_phy_regs_2G[12];
+
+       u16 rssical_radio_regs_5G[2];
+       u16 rssical_phy_regs_5G[12];
+};
+
+struct b43_phy_n_cal_cache {
+       u16 txcal_radio_regs_2G[8];
+       u16 txcal_coeffs_2G[8];
+       struct b43_phy_n_iq_comp rxcal_coeffs_2G;
+
+       u16 txcal_radio_regs_5G[8];
+       u16 txcal_coeffs_5G[8];
+       struct b43_phy_n_iq_comp rxcal_coeffs_5G;
+};
+
+struct b43_phy_n_txpwrindex {
+       s8 index;
+       s8 index_internal;
+       s8 index_internal_save;
+       u16 AfectrlOverride;
+       u16 AfeCtrlDacGain;
+       u16 rad_gain;
+       u8 bbmult;
+       u16 iqcomp_a;
+       u16 iqcomp_b;
+       u16 locomp;
+};
+
 struct b43_phy_n {
-       //TODO lots of missing stuff
+       u8 antsel_type;
+       u8 cal_orig_pwr_idx[2];
+       u8 measure_hold;
+       u8 phyrxchain;
+       u8 perical;
+       u32 deaf_count;
+       u32 rxcalparams;
+       bool hang_avoid;
+       bool mute;
+       u16 papd_epsilon_offset[2];
+
+       u8 mphase_cal_phase_id;
+       u16 mphase_txcal_cmdidx;
+       u16 mphase_txcal_numcmds;
+       u16 mphase_txcal_bestcoeffs[11];
+
+       u8 txpwrctrl;
+       u16 txcal_bbmult;
+       u16 txiqlocal_bestc[11];
+       bool txiqlocal_coeffsvalid;
+       struct b43_phy_n_txpwrindex txpwrindex[2];
+
+       u16 tx_rx_cal_phy_saveregs[11];
+       u16 tx_rx_cal_radio_saveregs[22];
+
+       u16 rfctrl_intc1_save;
+       u16 rfctrl_intc2_save;
+
+       u16 classifier_state;
+       u16 clip_state[2];
+
+       bool ipa2g_on;
+       u8 iqcal_chanspec_2G;
+       u8 rssical_chanspec_2G;
+
+       bool ipa5g_on;
+       u8 iqcal_chanspec_5G;
+       u8 rssical_chanspec_5G;
+
+       struct b43_phy_n_rssical_cache rssical_cache;
+       struct b43_phy_n_cal_cache cal_cache;
+       bool crsminpwr_adjusted;
+       bool noisevars_adjusted;
 };
 
 
index 7dd649c9ddadcd2a91533395da4f06e9d7fb9c03..7b3c42f93a16217e0c36a1c2c20e40a9f2f93ab8 100644 (file)
@@ -55,8 +55,6 @@
 #define B43_PIO_MAX_NR_TXPACKETS       32
 
 
-#ifdef CONFIG_B43_PIO
-
 struct b43_pio_txpacket {
        /* Pointer to the TX queue we belong to. */
        struct b43_pio_txqueue *queue;
@@ -169,42 +167,4 @@ void b43_pio_rx(struct b43_pio_rxqueue *q);
 void b43_pio_tx_suspend(struct b43_wldev *dev);
 void b43_pio_tx_resume(struct b43_wldev *dev);
 
-
-#else /* CONFIG_B43_PIO */
-
-
-static inline int b43_pio_init(struct b43_wldev *dev)
-{
-       return 0;
-}
-static inline void b43_pio_free(struct b43_wldev *dev)
-{
-}
-static inline void b43_pio_stop(struct b43_wldev *dev)
-{
-}
-static inline int b43_pio_tx(struct b43_wldev *dev,
-                            struct sk_buff *skb)
-{
-       return 0;
-}
-static inline void b43_pio_handle_txstatus(struct b43_wldev *dev,
-                                          const struct b43_txstatus *status)
-{
-}
-static inline void b43_pio_get_tx_stats(struct b43_wldev *dev,
-                                       struct ieee80211_tx_queue_stats *stats)
-{
-}
-static inline void b43_pio_rx(struct b43_pio_rxqueue *q)
-{
-}
-static inline void b43_pio_tx_suspend(struct b43_wldev *dev)
-{
-}
-static inline void b43_pio_tx_resume(struct b43_wldev *dev)
-{
-}
-
-#endif /* CONFIG_B43_PIO */
 #endif /* B43_PIO_H_ */
index 4e2336315545a3de50b0418b1af0fb7a94908011..7dff853ab9624f988e10316d8d64153b1d0cba2e 100644 (file)
@@ -1336,7 +1336,7 @@ b43_nphy_get_chantabent(struct b43_wldev *dev, u8 channel)
 }
 
 
-const u8 b43_ntab_adjustpower0[] = {
+static const u8 b43_ntab_adjustpower0[] = {
        0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01,
        0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03,
        0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05,
@@ -1355,7 +1355,7 @@ const u8 b43_ntab_adjustpower0[] = {
        0x1E, 0x1E, 0x1E, 0x1E, 0x1F, 0x1F, 0x1F, 0x1F,
 };
 
-const u8 b43_ntab_adjustpower1[] = {
+static const u8 b43_ntab_adjustpower1[] = {
        0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01,
        0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03,
        0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05,
@@ -1374,11 +1374,11 @@ const u8 b43_ntab_adjustpower1[] = {
        0x1E, 0x1E, 0x1E, 0x1E, 0x1F, 0x1F, 0x1F, 0x1F,
 };
 
-const u16 b43_ntab_bdi[] = {
+static const u16 b43_ntab_bdi[] = {
        0x0070, 0x0126, 0x012C, 0x0246, 0x048D, 0x04D2,
 };
 
-const u32 b43_ntab_channelest[] = {
+static const u32 b43_ntab_channelest[] = {
        0x44444444, 0x44444444, 0x44444444, 0x44444444,
        0x44444444, 0x44444444, 0x44444444, 0x44444444,
        0x10101010, 0x10101010, 0x10101010, 0x10101010,
@@ -1405,7 +1405,7 @@ const u32 b43_ntab_channelest[] = {
        0x10101010, 0x10101010, 0x10101010, 0x10101010,
 };
 
-const u8 b43_ntab_estimatepowerlt0[] = {
+static const u8 b43_ntab_estimatepowerlt0[] = {
        0x50, 0x4F, 0x4E, 0x4D, 0x4C, 0x4B, 0x4A, 0x49,
        0x48, 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41,
        0x40, 0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39,
@@ -1416,7 +1416,7 @@ const u8 b43_ntab_estimatepowerlt0[] = {
        0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11,
 };
 
-const u8 b43_ntab_estimatepowerlt1[] = {
+static const u8 b43_ntab_estimatepowerlt1[] = {
        0x50, 0x4F, 0x4E, 0x4D, 0x4C, 0x4B, 0x4A, 0x49,
        0x48, 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41,
        0x40, 0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39,
@@ -1427,14 +1427,14 @@ const u8 b43_ntab_estimatepowerlt1[] = {
        0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11,
 };
 
-const u8 b43_ntab_framelookup[] = {
+static const u8 b43_ntab_framelookup[] = {
        0x02, 0x04, 0x14, 0x14, 0x03, 0x05, 0x16, 0x16,
        0x0A, 0x0C, 0x1C, 0x1C, 0x0B, 0x0D, 0x1E, 0x1E,
        0x06, 0x08, 0x18, 0x18, 0x07, 0x09, 0x1A, 0x1A,
        0x0E, 0x10, 0x20, 0x28, 0x0F, 0x11, 0x22, 0x2A,
 };
 
-const u32 b43_ntab_framestruct[] = {
+static const u32 b43_ntab_framestruct[] = {
        0x08004A04, 0x00100000, 0x01000A05, 0x00100020,
        0x09804506, 0x00100030, 0x09804507, 0x00100030,
        0x00000000, 0x00000000, 0x00000000, 0x00000000,
@@ -1645,7 +1645,7 @@ const u32 b43_ntab_framestruct[] = {
        0x00000000, 0x00000000, 0x00000000, 0x00000000,
 };
 
-const u32 b43_ntab_gainctl0[] = {
+static const u32 b43_ntab_gainctl0[] = {
        0x007F003F, 0x007E013F, 0x007D023E, 0x007C033E,
        0x007B043D, 0x007A053D, 0x0079063C, 0x0078073C,
        0x0077083B, 0x0076093B, 0x00750A3A, 0x00740B3A,
@@ -1680,7 +1680,7 @@ const u32 b43_ntab_gainctl0[] = {
        0x00030C01, 0x00020D01, 0x00010E00, 0x00000F00,
 };
 
-const u32 b43_ntab_gainctl1[] = {
+static const u32 b43_ntab_gainctl1[] = {
        0x007F003F, 0x007E013F, 0x007D023E, 0x007C033E,
        0x007B043D, 0x007A053D, 0x0079063C, 0x0078073C,
        0x0077083B, 0x0076093B, 0x00750A3A, 0x00740B3A,
@@ -1715,12 +1715,12 @@ const u32 b43_ntab_gainctl1[] = {
        0x00030C01, 0x00020D01, 0x00010E00, 0x00000F00,
 };
 
-const u32 b43_ntab_intlevel[] = {
+static const u32 b43_ntab_intlevel[] = {
        0x00802070, 0x0671188D, 0x0A60192C, 0x0A300E46,
        0x00C1188D, 0x080024D2, 0x00000070,
 };
 
-const u32 b43_ntab_iqlt0[] = {
+static const u32 b43_ntab_iqlt0[] = {
        0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
        0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
        0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
@@ -1755,7 +1755,7 @@ const u32 b43_ntab_iqlt0[] = {
        0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
 };
 
-const u32 b43_ntab_iqlt1[] = {
+static const u32 b43_ntab_iqlt1[] = {
        0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
        0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
        0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
@@ -1790,7 +1790,7 @@ const u32 b43_ntab_iqlt1[] = {
        0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
 };
 
-const u16 b43_ntab_loftlt0[] = {
+static const u16 b43_ntab_loftlt0[] = {
        0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
        0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103,
        0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
@@ -1815,7 +1815,7 @@ const u16 b43_ntab_loftlt0[] = {
        0x0002, 0x0103,
 };
 
-const u16 b43_ntab_loftlt1[] = {
+static const u16 b43_ntab_loftlt1[] = {
        0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
        0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103,
        0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
@@ -1840,7 +1840,7 @@ const u16 b43_ntab_loftlt1[] = {
        0x0002, 0x0103,
 };
 
-const u8 b43_ntab_mcs[] = {
+static const u8 b43_ntab_mcs[] = {
        0x00, 0x08, 0x0A, 0x10, 0x12, 0x19, 0x1A, 0x1C,
        0x40, 0x48, 0x4A, 0x50, 0x52, 0x59, 0x5A, 0x5C,
        0x80, 0x88, 0x8A, 0x90, 0x92, 0x99, 0x9A, 0x9C,
@@ -1859,7 +1859,7 @@ const u8 b43_ntab_mcs[] = {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 };
 
-const u32 b43_ntab_noisevar10[] = {
+static const u32 b43_ntab_noisevar10[] = {
        0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
        0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
        0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
@@ -1926,7 +1926,7 @@ const u32 b43_ntab_noisevar10[] = {
        0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
 };
 
-const u32 b43_ntab_noisevar11[] = {
+static const u32 b43_ntab_noisevar11[] = {
        0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
        0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
        0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
@@ -1993,7 +1993,7 @@ const u32 b43_ntab_noisevar11[] = {
        0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
 };
 
-const u16 b43_ntab_pilot[] = {
+static const u16 b43_ntab_pilot[] = {
        0xFF08, 0xFF08, 0xFF08, 0xFF08, 0xFF08, 0xFF08,
        0xFF08, 0xFF08, 0x80D5, 0x80D5, 0x80D5, 0x80D5,
        0x80D5, 0x80D5, 0x80D5, 0x80D5, 0xFF0A, 0xFF82,
@@ -2011,12 +2011,12 @@ const u16 b43_ntab_pilot[] = {
        0xF0A0, 0xF028, 0xFFFF, 0xFFFF,
 };
 
-const u32 b43_ntab_pilotlt[] = {
+static const u32 b43_ntab_pilotlt[] = {
        0x76540123, 0x62407351, 0x76543201, 0x76540213,
        0x76540123, 0x76430521,
 };
 
-const u32 b43_ntab_tdi20a0[] = {
+static const u32 b43_ntab_tdi20a0[] = {
        0x00091226, 0x000A1429, 0x000B56AD, 0x000C58B0,
        0x000D5AB3, 0x000E9CB6, 0x000F9EBA, 0x0000C13D,
        0x00020301, 0x00030504, 0x00040708, 0x0005090B,
@@ -2033,7 +2033,7 @@ const u32 b43_ntab_tdi20a0[] = {
        0x00000000, 0x00000000, 0x00000000,
 };
 
-const u32 b43_ntab_tdi20a1[] = {
+static const u32 b43_ntab_tdi20a1[] = {
        0x00014B26, 0x00028D29, 0x000393AD, 0x00049630,
        0x0005D833, 0x0006DA36, 0x00099C3A, 0x000A9E3D,
        0x000BC081, 0x000CC284, 0x000DC488, 0x000F068B,
@@ -2050,7 +2050,7 @@ const u32 b43_ntab_tdi20a1[] = {
        0x00000000, 0x00000000, 0x00000000,
 };
 
-const u32 b43_ntab_tdi40a0[] = {
+static const u32 b43_ntab_tdi40a0[] = {
        0x0011A346, 0x00136CCF, 0x0014F5D9, 0x001641E2,
        0x0017CB6B, 0x00195475, 0x001B2383, 0x001CAD0C,
        0x001E7616, 0x0000821F, 0x00020BA8, 0x0003D4B2,
@@ -2081,7 +2081,7 @@ const u32 b43_ntab_tdi40a0[] = {
        0x00000000, 0x00000000,
 };
 
-const u32 b43_ntab_tdi40a1[] = {
+static const u32 b43_ntab_tdi40a1[] = {
        0x001EDB36, 0x000129CA, 0x0002B353, 0x00047CDD,
        0x0005C8E6, 0x000791EF, 0x00091BF9, 0x000AAA07,
        0x000C3391, 0x000DFD1A, 0x00120923, 0x0013D22D,
@@ -2112,7 +2112,7 @@ const u32 b43_ntab_tdi40a1[] = {
        0x00000000, 0x00000000,
 };
 
-const u32 b43_ntab_tdtrn[] = {
+static const u32 b43_ntab_tdtrn[] = {
        0x061C061C, 0x0050EE68, 0xF592FE36, 0xFE5212F6,
        0x00000C38, 0xFE5212F6, 0xF592FE36, 0x0050EE68,
        0x061C061C, 0xEE680050, 0xFE36F592, 0x12F6FE52,
@@ -2291,7 +2291,7 @@ const u32 b43_ntab_tdtrn[] = {
        0xFA58FC00, 0x0B64FC7E, 0x0800F7B6, 0x00F006BE,
 };
 
-const u32 b43_ntab_tmap[] = {
+static const u32 b43_ntab_tmap[] = {
        0x8A88AA80, 0x8AAAAA8A, 0x8A8A8AA8, 0x00000888,
        0x88000000, 0x8A8A88AA, 0x8AA88888, 0x8888A8A8,
        0xF1111110, 0x11111111, 0x11F11111, 0x00000111,
@@ -2406,6 +2406,483 @@ const u32 b43_ntab_tmap[] = {
        0x00000000, 0x00000000, 0x00000000, 0x00000000,
 };
 
+const u32 b43_ntab_tx_gain_rev0_1_2[] = {
+       0x03cc2b44, 0x03cc2b42, 0x03cc2a44, 0x03cc2a42,
+       0x03cc2944, 0x03c82b44, 0x03c82b42, 0x03c82a44,
+       0x03c82a42, 0x03c82944, 0x03c82942, 0x03c82844,
+       0x03c82842, 0x03c42b44, 0x03c42b42, 0x03c42a44,
+       0x03c42a42, 0x03c42944, 0x03c42942, 0x03c42844,
+       0x03c42842, 0x03c42744, 0x03c42742, 0x03c42644,
+       0x03c42642, 0x03c42544, 0x03c42542, 0x03c42444,
+       0x03c42442, 0x03c02b44, 0x03c02b42, 0x03c02a44,
+       0x03c02a42, 0x03c02944, 0x03c02942, 0x03c02844,
+       0x03c02842, 0x03c02744, 0x03c02742, 0x03b02b44,
+       0x03b02b42, 0x03b02a44, 0x03b02a42, 0x03b02944,
+       0x03b02942, 0x03b02844, 0x03b02842, 0x03b02744,
+       0x03b02742, 0x03b02644, 0x03b02642, 0x03b02544,
+       0x03b02542, 0x03a02b44, 0x03a02b42, 0x03a02a44,
+       0x03a02a42, 0x03a02944, 0x03a02942, 0x03a02844,
+       0x03a02842, 0x03a02744, 0x03a02742, 0x03902b44,
+       0x03902b42, 0x03902a44, 0x03902a42, 0x03902944,
+       0x03902942, 0x03902844, 0x03902842, 0x03902744,
+       0x03902742, 0x03902644, 0x03902642, 0x03902544,
+       0x03902542, 0x03802b44, 0x03802b42, 0x03802a44,
+       0x03802a42, 0x03802944, 0x03802942, 0x03802844,
+       0x03802842, 0x03802744, 0x03802742, 0x03802644,
+       0x03802642, 0x03802544, 0x03802542, 0x03802444,
+       0x03802442, 0x03802344, 0x03802342, 0x03802244,
+       0x03802242, 0x03802144, 0x03802142, 0x03802044,
+       0x03802042, 0x03801f44, 0x03801f42, 0x03801e44,
+       0x03801e42, 0x03801d44, 0x03801d42, 0x03801c44,
+       0x03801c42, 0x03801b44, 0x03801b42, 0x03801a44,
+       0x03801a42, 0x03801944, 0x03801942, 0x03801844,
+       0x03801842, 0x03801744, 0x03801742, 0x03801644,
+       0x03801642, 0x03801544, 0x03801542, 0x03801444,
+       0x03801442, 0x03801344, 0x03801342, 0x00002b00,
+};
+
+const u32 b43_ntab_tx_gain_rev3plus_2ghz[] = {
+       0x1f410044, 0x1f410042, 0x1f410040, 0x1f41003e,
+       0x1f41003c, 0x1f41003b, 0x1f410039, 0x1f410037,
+       0x1e410044, 0x1e410042, 0x1e410040, 0x1e41003e,
+       0x1e41003c, 0x1e41003b, 0x1e410039, 0x1e410037,
+       0x1d410044, 0x1d410042, 0x1d410040, 0x1d41003e,
+       0x1d41003c, 0x1d41003b, 0x1d410039, 0x1d410037,
+       0x1c410044, 0x1c410042, 0x1c410040, 0x1c41003e,
+       0x1c41003c, 0x1c41003b, 0x1c410039, 0x1c410037,
+       0x1b410044, 0x1b410042, 0x1b410040, 0x1b41003e,
+       0x1b41003c, 0x1b41003b, 0x1b410039, 0x1b410037,
+       0x1a410044, 0x1a410042, 0x1a410040, 0x1a41003e,
+       0x1a41003c, 0x1a41003b, 0x1a410039, 0x1a410037,
+       0x19410044, 0x19410042, 0x19410040, 0x1941003e,
+       0x1941003c, 0x1941003b, 0x19410039, 0x19410037,
+       0x18410044, 0x18410042, 0x18410040, 0x1841003e,
+       0x1841003c, 0x1841003b, 0x18410039, 0x18410037,
+       0x17410044, 0x17410042, 0x17410040, 0x1741003e,
+       0x1741003c, 0x1741003b, 0x17410039, 0x17410037,
+       0x16410044, 0x16410042, 0x16410040, 0x1641003e,
+       0x1641003c, 0x1641003b, 0x16410039, 0x16410037,
+       0x15410044, 0x15410042, 0x15410040, 0x1541003e,
+       0x1541003c, 0x1541003b, 0x15410039, 0x15410037,
+       0x14410044, 0x14410042, 0x14410040, 0x1441003e,
+       0x1441003c, 0x1441003b, 0x14410039, 0x14410037,
+       0x13410044, 0x13410042, 0x13410040, 0x1341003e,
+       0x1341003c, 0x1341003b, 0x13410039, 0x13410037,
+       0x12410044, 0x12410042, 0x12410040, 0x1241003e,
+       0x1241003c, 0x1241003b, 0x12410039, 0x12410037,
+       0x11410044, 0x11410042, 0x11410040, 0x1141003e,
+       0x1141003c, 0x1141003b, 0x11410039, 0x11410037,
+       0x10410044, 0x10410042, 0x10410040, 0x1041003e,
+       0x1041003c, 0x1041003b, 0x10410039, 0x10410037,
+};
+
+const u32 b43_ntab_tx_gain_rev3_5ghz[] = {
+       0xcff70044, 0xcff70042, 0xcff70040, 0xcff7003e,
+       0xcff7003c, 0xcff7003b, 0xcff70039, 0xcff70037,
+       0xcef70044, 0xcef70042, 0xcef70040, 0xcef7003e,
+       0xcef7003c, 0xcef7003b, 0xcef70039, 0xcef70037,
+       0xcdf70044, 0xcdf70042, 0xcdf70040, 0xcdf7003e,
+       0xcdf7003c, 0xcdf7003b, 0xcdf70039, 0xcdf70037,
+       0xccf70044, 0xccf70042, 0xccf70040, 0xccf7003e,
+       0xccf7003c, 0xccf7003b, 0xccf70039, 0xccf70037,
+       0xcbf70044, 0xcbf70042, 0xcbf70040, 0xcbf7003e,
+       0xcbf7003c, 0xcbf7003b, 0xcbf70039, 0xcbf70037,
+       0xcaf70044, 0xcaf70042, 0xcaf70040, 0xcaf7003e,
+       0xcaf7003c, 0xcaf7003b, 0xcaf70039, 0xcaf70037,
+       0xc9f70044, 0xc9f70042, 0xc9f70040, 0xc9f7003e,
+       0xc9f7003c, 0xc9f7003b, 0xc9f70039, 0xc9f70037,
+       0xc8f70044, 0xc8f70042, 0xc8f70040, 0xc8f7003e,
+       0xc8f7003c, 0xc8f7003b, 0xc8f70039, 0xc8f70037,
+       0xc7f70044, 0xc7f70042, 0xc7f70040, 0xc7f7003e,
+       0xc7f7003c, 0xc7f7003b, 0xc7f70039, 0xc7f70037,
+       0xc6f70044, 0xc6f70042, 0xc6f70040, 0xc6f7003e,
+       0xc6f7003c, 0xc6f7003b, 0xc6f70039, 0xc6f70037,
+       0xc5f70044, 0xc5f70042, 0xc5f70040, 0xc5f7003e,
+       0xc5f7003c, 0xc5f7003b, 0xc5f70039, 0xc5f70037,
+       0xc4f70044, 0xc4f70042, 0xc4f70040, 0xc4f7003e,
+       0xc4f7003c, 0xc4f7003b, 0xc4f70039, 0xc4f70037,
+       0xc3f70044, 0xc3f70042, 0xc3f70040, 0xc3f7003e,
+       0xc3f7003c, 0xc3f7003b, 0xc3f70039, 0xc3f70037,
+       0xc2f70044, 0xc2f70042, 0xc2f70040, 0xc2f7003e,
+       0xc2f7003c, 0xc2f7003b, 0xc2f70039, 0xc2f70037,
+       0xc1f70044, 0xc1f70042, 0xc1f70040, 0xc1f7003e,
+       0xc1f7003c, 0xc1f7003b, 0xc1f70039, 0xc1f70037,
+       0xc0f70044, 0xc0f70042, 0xc0f70040, 0xc0f7003e,
+       0xc0f7003c, 0xc0f7003b, 0xc0f70039, 0xc0f70037,
+};
+
+const u32 b43_ntab_tx_gain_rev4_5ghz[] = {
+       0x2ff20044, 0x2ff20042, 0x2ff20040, 0x2ff2003e,
+       0x2ff2003c, 0x2ff2003b, 0x2ff20039, 0x2ff20037,
+       0x2ef20044, 0x2ef20042, 0x2ef20040, 0x2ef2003e,
+       0x2ef2003c, 0x2ef2003b, 0x2ef20039, 0x2ef20037,
+       0x2df20044, 0x2df20042, 0x2df20040, 0x2df2003e,
+       0x2df2003c, 0x2df2003b, 0x2df20039, 0x2df20037,
+       0x2cf20044, 0x2cf20042, 0x2cf20040, 0x2cf2003e,
+       0x2cf2003c, 0x2cf2003b, 0x2cf20039, 0x2cf20037,
+       0x2bf20044, 0x2bf20042, 0x2bf20040, 0x2bf2003e,
+       0x2bf2003c, 0x2bf2003b, 0x2bf20039, 0x2bf20037,
+       0x2af20044, 0x2af20042, 0x2af20040, 0x2af2003e,
+       0x2af2003c, 0x2af2003b, 0x2af20039, 0x2af20037,
+       0x29f20044, 0x29f20042, 0x29f20040, 0x29f2003e,
+       0x29f2003c, 0x29f2003b, 0x29f20039, 0x29f20037,
+       0x28f20044, 0x28f20042, 0x28f20040, 0x28f2003e,
+       0x28f2003c, 0x28f2003b, 0x28f20039, 0x28f20037,
+       0x27f20044, 0x27f20042, 0x27f20040, 0x27f2003e,
+       0x27f2003c, 0x27f2003b, 0x27f20039, 0x27f20037,
+       0x26f20044, 0x26f20042, 0x26f20040, 0x26f2003e,
+       0x26f2003c, 0x26f2003b, 0x26f20039, 0x26f20037,
+       0x25f20044, 0x25f20042, 0x25f20040, 0x25f2003e,
+       0x25f2003c, 0x25f2003b, 0x25f20039, 0x25f20037,
+       0x24f20044, 0x24f20042, 0x24f20040, 0x24f2003e,
+       0x24f2003c, 0x24f2003b, 0x24f20039, 0x24f20038,
+       0x23f20041, 0x23f20040, 0x23f2003f, 0x23f2003e,
+       0x23f2003c, 0x23f2003b, 0x23f20039, 0x23f20037,
+       0x22f20044, 0x22f20042, 0x22f20040, 0x22f2003e,
+       0x22f2003c, 0x22f2003b, 0x22f20039, 0x22f20037,
+       0x21f20044, 0x21f20042, 0x21f20040, 0x21f2003e,
+       0x21f2003c, 0x21f2003b, 0x21f20039, 0x21f20037,
+       0x20d20043, 0x20d20041, 0x20d2003e, 0x20d2003c,
+       0x20d2003a, 0x20d20038, 0x20d20036, 0x20d20034,
+};
+
+const u32 b43_ntab_tx_gain_rev5plus_5ghz[] = {
+       0x0f62004a, 0x0f620048, 0x0f620046, 0x0f620044,
+       0x0f620042, 0x0f620040, 0x0f62003e, 0x0f62003c,
+       0x0e620044, 0x0e620042, 0x0e620040, 0x0e62003e,
+       0x0e62003c, 0x0e62003d, 0x0e62003b, 0x0e62003a,
+       0x0d620043, 0x0d620041, 0x0d620040, 0x0d62003e,
+       0x0d62003d, 0x0d62003c, 0x0d62003b, 0x0d62003a,
+       0x0c620041, 0x0c620040, 0x0c62003f, 0x0c62003e,
+       0x0c62003c, 0x0c62003b, 0x0c620039, 0x0c620037,
+       0x0b620046, 0x0b620044, 0x0b620042, 0x0b620040,
+       0x0b62003e, 0x0b62003c, 0x0b62003b, 0x0b62003a,
+       0x0a620041, 0x0a620040, 0x0a62003e, 0x0a62003c,
+       0x0a62003b, 0x0a62003a, 0x0a620039, 0x0a620038,
+       0x0962003e, 0x0962003d, 0x0962003c, 0x0962003b,
+       0x09620039, 0x09620037, 0x09620035, 0x09620033,
+       0x08620044, 0x08620042, 0x08620040, 0x0862003e,
+       0x0862003c, 0x0862003b, 0x0862003a, 0x08620039,
+       0x07620043, 0x07620042, 0x07620040, 0x0762003f,
+       0x0762003d, 0x0762003b, 0x0762003a, 0x07620039,
+       0x0662003e, 0x0662003d, 0x0662003c, 0x0662003b,
+       0x06620039, 0x06620037, 0x06620035, 0x06620033,
+       0x05620046, 0x05620044, 0x05620042, 0x05620040,
+       0x0562003e, 0x0562003c, 0x0562003b, 0x05620039,
+       0x04620044, 0x04620042, 0x04620040, 0x0462003e,
+       0x0462003c, 0x0462003b, 0x04620039, 0x04620038,
+       0x0362003c, 0x0362003b, 0x0362003a, 0x03620039,
+       0x03620038, 0x03620037, 0x03620035, 0x03620033,
+       0x0262004c, 0x0262004a, 0x02620048, 0x02620047,
+       0x02620046, 0x02620044, 0x02620043, 0x02620042,
+       0x0162004a, 0x01620048, 0x01620046, 0x01620044,
+       0x01620043, 0x01620042, 0x01620041, 0x01620040,
+       0x00620042, 0x00620040, 0x0062003e, 0x0062003c,
+       0x0062003b, 0x00620039, 0x00620037, 0x00620035,
+};
+
+const u32 txpwrctrl_tx_gain_ipa[] = {
+       0x5ff7002d, 0x5ff7002b, 0x5ff7002a, 0x5ff70029,
+       0x5ff70028, 0x5ff70027, 0x5ff70026, 0x5ff70025,
+       0x5ef7002d, 0x5ef7002b, 0x5ef7002a, 0x5ef70029,
+       0x5ef70028, 0x5ef70027, 0x5ef70026, 0x5ef70025,
+       0x5df7002d, 0x5df7002b, 0x5df7002a, 0x5df70029,
+       0x5df70028, 0x5df70027, 0x5df70026, 0x5df70025,
+       0x5cf7002d, 0x5cf7002b, 0x5cf7002a, 0x5cf70029,
+       0x5cf70028, 0x5cf70027, 0x5cf70026, 0x5cf70025,
+       0x5bf7002d, 0x5bf7002b, 0x5bf7002a, 0x5bf70029,
+       0x5bf70028, 0x5bf70027, 0x5bf70026, 0x5bf70025,
+       0x5af7002d, 0x5af7002b, 0x5af7002a, 0x5af70029,
+       0x5af70028, 0x5af70027, 0x5af70026, 0x5af70025,
+       0x59f7002d, 0x59f7002b, 0x59f7002a, 0x59f70029,
+       0x59f70028, 0x59f70027, 0x59f70026, 0x59f70025,
+       0x58f7002d, 0x58f7002b, 0x58f7002a, 0x58f70029,
+       0x58f70028, 0x58f70027, 0x58f70026, 0x58f70025,
+       0x57f7002d, 0x57f7002b, 0x57f7002a, 0x57f70029,
+       0x57f70028, 0x57f70027, 0x57f70026, 0x57f70025,
+       0x56f7002d, 0x56f7002b, 0x56f7002a, 0x56f70029,
+       0x56f70028, 0x56f70027, 0x56f70026, 0x56f70025,
+       0x55f7002d, 0x55f7002b, 0x55f7002a, 0x55f70029,
+       0x55f70028, 0x55f70027, 0x55f70026, 0x55f70025,
+       0x54f7002d, 0x54f7002b, 0x54f7002a, 0x54f70029,
+       0x54f70028, 0x54f70027, 0x54f70026, 0x54f70025,
+       0x53f7002d, 0x53f7002b, 0x53f7002a, 0x53f70029,
+       0x53f70028, 0x53f70027, 0x53f70026, 0x53f70025,
+       0x52f7002d, 0x52f7002b, 0x52f7002a, 0x52f70029,
+       0x52f70028, 0x52f70027, 0x52f70026, 0x52f70025,
+       0x51f7002d, 0x51f7002b, 0x51f7002a, 0x51f70029,
+       0x51f70028, 0x51f70027, 0x51f70026, 0x51f70025,
+       0x50f7002d, 0x50f7002b, 0x50f7002a, 0x50f70029,
+       0x50f70028, 0x50f70027, 0x50f70026, 0x50f70025,
+};
+
+const u32 txpwrctrl_tx_gain_ipa_rev5[] = {
+       0x1ff7002d, 0x1ff7002b, 0x1ff7002a, 0x1ff70029,
+       0x1ff70028, 0x1ff70027, 0x1ff70026, 0x1ff70025,
+       0x1ef7002d, 0x1ef7002b, 0x1ef7002a, 0x1ef70029,
+       0x1ef70028, 0x1ef70027, 0x1ef70026, 0x1ef70025,
+       0x1df7002d, 0x1df7002b, 0x1df7002a, 0x1df70029,
+       0x1df70028, 0x1df70027, 0x1df70026, 0x1df70025,
+       0x1cf7002d, 0x1cf7002b, 0x1cf7002a, 0x1cf70029,
+       0x1cf70028, 0x1cf70027, 0x1cf70026, 0x1cf70025,
+       0x1bf7002d, 0x1bf7002b, 0x1bf7002a, 0x1bf70029,
+       0x1bf70028, 0x1bf70027, 0x1bf70026, 0x1bf70025,
+       0x1af7002d, 0x1af7002b, 0x1af7002a, 0x1af70029,
+       0x1af70028, 0x1af70027, 0x1af70026, 0x1af70025,
+       0x19f7002d, 0x19f7002b, 0x19f7002a, 0x19f70029,
+       0x19f70028, 0x19f70027, 0x19f70026, 0x19f70025,
+       0x18f7002d, 0x18f7002b, 0x18f7002a, 0x18f70029,
+       0x18f70028, 0x18f70027, 0x18f70026, 0x18f70025,
+       0x17f7002d, 0x17f7002b, 0x17f7002a, 0x17f70029,
+       0x17f70028, 0x17f70027, 0x17f70026, 0x17f70025,
+       0x16f7002d, 0x16f7002b, 0x16f7002a, 0x16f70029,
+       0x16f70028, 0x16f70027, 0x16f70026, 0x16f70025,
+       0x15f7002d, 0x15f7002b, 0x15f7002a, 0x15f70029,
+       0x15f70028, 0x15f70027, 0x15f70026, 0x15f70025,
+       0x14f7002d, 0x14f7002b, 0x14f7002a, 0x14f70029,
+       0x14f70028, 0x14f70027, 0x14f70026, 0x14f70025,
+       0x13f7002d, 0x13f7002b, 0x13f7002a, 0x13f70029,
+       0x13f70028, 0x13f70027, 0x13f70026, 0x13f70025,
+       0x12f7002d, 0x12f7002b, 0x12f7002a, 0x12f70029,
+       0x12f70028, 0x12f70027, 0x12f70026, 0x12f70025,
+       0x11f7002d, 0x11f7002b, 0x11f7002a, 0x11f70029,
+       0x11f70028, 0x11f70027, 0x11f70026, 0x11f70025,
+       0x10f7002d, 0x10f7002b, 0x10f7002a, 0x10f70029,
+       0x10f70028, 0x10f70027, 0x10f70026, 0x10f70025,
+};
+
+const u32 txpwrctrl_tx_gain_ipa_rev6[] = {
+       0x0ff7002d, 0x0ff7002b, 0x0ff7002a, 0x0ff70029,
+       0x0ff70028, 0x0ff70027, 0x0ff70026, 0x0ff70025,
+       0x0ef7002d, 0x0ef7002b, 0x0ef7002a, 0x0ef70029,
+       0x0ef70028, 0x0ef70027, 0x0ef70026, 0x0ef70025,
+       0x0df7002d, 0x0df7002b, 0x0df7002a, 0x0df70029,
+       0x0df70028, 0x0df70027, 0x0df70026, 0x0df70025,
+       0x0cf7002d, 0x0cf7002b, 0x0cf7002a, 0x0cf70029,
+       0x0cf70028, 0x0cf70027, 0x0cf70026, 0x0cf70025,
+       0x0bf7002d, 0x0bf7002b, 0x0bf7002a, 0x0bf70029,
+       0x0bf70028, 0x0bf70027, 0x0bf70026, 0x0bf70025,
+       0x0af7002d, 0x0af7002b, 0x0af7002a, 0x0af70029,
+       0x0af70028, 0x0af70027, 0x0af70026, 0x0af70025,
+       0x09f7002d, 0x09f7002b, 0x09f7002a, 0x09f70029,
+       0x09f70028, 0x09f70027, 0x09f70026, 0x09f70025,
+       0x08f7002d, 0x08f7002b, 0x08f7002a, 0x08f70029,
+       0x08f70028, 0x08f70027, 0x08f70026, 0x08f70025,
+       0x07f7002d, 0x07f7002b, 0x07f7002a, 0x07f70029,
+       0x07f70028, 0x07f70027, 0x07f70026, 0x07f70025,
+       0x06f7002d, 0x06f7002b, 0x06f7002a, 0x06f70029,
+       0x06f70028, 0x06f70027, 0x06f70026, 0x06f70025,
+       0x05f7002d, 0x05f7002b, 0x05f7002a, 0x05f70029,
+       0x05f70028, 0x05f70027, 0x05f70026, 0x05f70025,
+       0x04f7002d, 0x04f7002b, 0x04f7002a, 0x04f70029,
+       0x04f70028, 0x04f70027, 0x04f70026, 0x04f70025,
+       0x03f7002d, 0x03f7002b, 0x03f7002a, 0x03f70029,
+       0x03f70028, 0x03f70027, 0x03f70026, 0x03f70025,
+       0x02f7002d, 0x02f7002b, 0x02f7002a, 0x02f70029,
+       0x02f70028, 0x02f70027, 0x02f70026, 0x02f70025,
+       0x01f7002d, 0x01f7002b, 0x01f7002a, 0x01f70029,
+       0x01f70028, 0x01f70027, 0x01f70026, 0x01f70025,
+       0x00f7002d, 0x00f7002b, 0x00f7002a, 0x00f70029,
+       0x00f70028, 0x00f70027, 0x00f70026, 0x00f70025,
+};
+
+const u32 txpwrctrl_tx_gain_ipa_5g[] = {
+       0x7ff70035, 0x7ff70033, 0x7ff70032, 0x7ff70031,
+       0x7ff7002f, 0x7ff7002e, 0x7ff7002d, 0x7ff7002b,
+       0x7ff7002a, 0x7ff70029, 0x7ff70028, 0x7ff70027,
+       0x7ff70026, 0x7ff70024, 0x7ff70023, 0x7ff70022,
+       0x7ef70028, 0x7ef70027, 0x7ef70026, 0x7ef70025,
+       0x7ef70024, 0x7ef70023, 0x7df70028, 0x7df70027,
+       0x7df70026, 0x7df70025, 0x7df70024, 0x7df70023,
+       0x7df70022, 0x7cf70029, 0x7cf70028, 0x7cf70027,
+       0x7cf70026, 0x7cf70025, 0x7cf70023, 0x7cf70022,
+       0x7bf70029, 0x7bf70028, 0x7bf70026, 0x7bf70025,
+       0x7bf70024, 0x7bf70023, 0x7bf70022, 0x7bf70021,
+       0x7af70029, 0x7af70028, 0x7af70027, 0x7af70026,
+       0x7af70025, 0x7af70024, 0x7af70023, 0x7af70022,
+       0x79f70029, 0x79f70028, 0x79f70027, 0x79f70026,
+       0x79f70025, 0x79f70024, 0x79f70023, 0x79f70022,
+       0x78f70029, 0x78f70028, 0x78f70027, 0x78f70026,
+       0x78f70025, 0x78f70024, 0x78f70023, 0x78f70022,
+       0x77f70029, 0x77f70028, 0x77f70027, 0x77f70026,
+       0x77f70025, 0x77f70024, 0x77f70023, 0x77f70022,
+       0x76f70029, 0x76f70028, 0x76f70027, 0x76f70026,
+       0x76f70024, 0x76f70023, 0x76f70022, 0x76f70021,
+       0x75f70029, 0x75f70028, 0x75f70027, 0x75f70026,
+       0x75f70025, 0x75f70024, 0x75f70023, 0x74f70029,
+       0x74f70028, 0x74f70026, 0x74f70025, 0x74f70024,
+       0x74f70023, 0x74f70022, 0x73f70029, 0x73f70027,
+       0x73f70026, 0x73f70025, 0x73f70024, 0x73f70023,
+       0x73f70022, 0x72f70028, 0x72f70027, 0x72f70026,
+       0x72f70025, 0x72f70024, 0x72f70023, 0x72f70022,
+       0x71f70028, 0x71f70027, 0x71f70026, 0x71f70025,
+       0x71f70024, 0x71f70023, 0x70f70028, 0x70f70027,
+       0x70f70026, 0x70f70024, 0x70f70023, 0x70f70022,
+       0x70f70021, 0x70f70020, 0x70f70020, 0x70f7001f,
+};
+
+const u16 tbl_iqcal_gainparams[2][9][8] = {
+       {
+               { 0x000, 0, 0, 2, 0x69, 0x69, 0x69, 0x69 },
+               { 0x700, 7, 0, 0, 0x69, 0x69, 0x69, 0x69 },
+               { 0x710, 7, 1, 0, 0x68, 0x68, 0x68, 0x68 },
+               { 0x720, 7, 2, 0, 0x67, 0x67, 0x67, 0x67 },
+               { 0x730, 7, 3, 0, 0x66, 0x66, 0x66, 0x66 },
+               { 0x740, 7, 4, 0, 0x65, 0x65, 0x65, 0x65 },
+               { 0x741, 7, 4, 1, 0x65, 0x65, 0x65, 0x65 },
+               { 0x742, 7, 4, 2, 0x65, 0x65, 0x65, 0x65 },
+               { 0x743, 7, 4, 3, 0x65, 0x65, 0x65, 0x65 }
+       },
+       {
+               { 0x000, 7, 0, 0, 0x79, 0x79, 0x79, 0x79 },
+               { 0x700, 7, 0, 0, 0x79, 0x79, 0x79, 0x79 },
+               { 0x710, 7, 1, 0, 0x79, 0x79, 0x79, 0x79 },
+               { 0x720, 7, 2, 0, 0x78, 0x78, 0x78, 0x78 },
+               { 0x730, 7, 3, 0, 0x78, 0x78, 0x78, 0x78 },
+               { 0x740, 7, 4, 0, 0x78, 0x78, 0x78, 0x78 },
+               { 0x741, 7, 4, 1, 0x78, 0x78, 0x78, 0x78 },
+               { 0x742, 7, 4, 2, 0x78, 0x78, 0x78, 0x78 },
+               { 0x743, 7, 4, 3, 0x78, 0x78, 0x78, 0x78 }
+       }
+};
+
+const struct nphy_txiqcal_ladder ladder_lo[] = {
+       { 3, 0 },
+       { 4, 0 },
+       { 6, 0 },
+       { 9, 0 },
+       { 13, 0 },
+       { 18, 0 },
+       { 25, 0 },
+       { 25, 1 },
+       { 25, 2 },
+       { 25, 3 },
+       { 25, 4 },
+       { 25, 5 },
+       { 25, 6 },
+       { 25, 7 },
+       { 35, 7 },
+       { 50, 7 },
+       { 71, 7 },
+       { 100, 7 }
+};
+
+const struct nphy_txiqcal_ladder ladder_iq[] = {
+       { 3, 0 },
+       { 4, 0 },
+       { 6, 0 },
+       { 9, 0 },
+       { 13, 0 },
+       { 18, 0 },
+       { 25, 0 },
+       { 35, 0 },
+       { 50, 0 },
+       { 71, 0 },
+       { 100, 0 },
+       { 100, 1 },
+       { 100, 2 },
+       { 100, 3 },
+       { 100, 4 },
+       { 100, 5 },
+       { 100, 6 },
+       { 100, 7 }
+};
+
+const u16 loscale[] = {
+       256, 256, 271, 271,
+       287, 256, 256, 271,
+       271, 287, 287, 304,
+       304, 256, 256, 271,
+       271, 287, 287, 304,
+       304, 322, 322, 341,
+       341, 362, 362, 383,
+       383, 256, 256, 271,
+       271, 287, 287, 304,
+       304, 322, 322, 256,
+       256, 271, 271, 287,
+       287, 304, 304, 322,
+       322, 341, 341, 362,
+       362, 256, 256, 271,
+       271, 287, 287, 304,
+       304, 322, 322, 256,
+       256, 271, 271, 287,
+       287, 304, 304, 322,
+       322, 341, 341, 362,
+       362, 256, 256, 271,
+       271, 287, 287, 304,
+       304, 322, 322, 341,
+       341, 362, 362, 383,
+       383, 406, 406, 430,
+       430, 455, 455, 482,
+       482, 511, 511, 541,
+       541, 573, 573, 607,
+       607, 643, 643, 681,
+       681, 722, 722, 764,
+       764, 810, 810, 858,
+       858, 908, 908, 962,
+       962, 1019, 1019, 256
+};
+
+const u16 tbl_tx_iqlo_cal_loft_ladder_40[] = {
+       0x0200, 0x0300, 0x0400, 0x0700,
+       0x0900, 0x0c00, 0x1200, 0x1201,
+       0x1202, 0x1203, 0x1204, 0x1205,
+       0x1206, 0x1207, 0x1907, 0x2307,
+       0x3207, 0x4707
+};
+
+const u16 tbl_tx_iqlo_cal_loft_ladder_20[] = {
+       0x0300, 0x0500, 0x0700, 0x0900,
+       0x0d00, 0x1100, 0x1900, 0x1901,
+       0x1902, 0x1903, 0x1904, 0x1905,
+       0x1906, 0x1907, 0x2407, 0x3207,
+       0x4607, 0x6407
+};
+
+const u16 tbl_tx_iqlo_cal_iqimb_ladder_40[] = {
+       0x0100, 0x0200, 0x0400, 0x0700,
+       0x0900, 0x0c00, 0x1200, 0x1900,
+       0x2300, 0x3200, 0x4700, 0x4701,
+       0x4702, 0x4703, 0x4704, 0x4705,
+       0x4706, 0x4707
+};
+
+const u16 tbl_tx_iqlo_cal_iqimb_ladder_20[] = {
+       0x0200, 0x0300, 0x0600, 0x0900,
+       0x0d00, 0x1100, 0x1900, 0x2400,
+       0x3200, 0x4600, 0x6400, 0x6401,
+       0x6402, 0x6403, 0x6404, 0x6405,
+       0x6406, 0x6407
+};
+
+const u16 tbl_tx_iqlo_cal_startcoefs_nphyrev3[B43_NTAB_TX_IQLO_CAL_STARTCOEFS_REV3] = { };
+
+const u16 tbl_tx_iqlo_cal_startcoefs[B43_NTAB_TX_IQLO_CAL_STARTCOEFS] = { };
+
+const u16 tbl_tx_iqlo_cal_cmds_recal_nphyrev3[] = {
+       0x8423, 0x8323, 0x8073, 0x8256,
+       0x8045, 0x8223, 0x9423, 0x9323,
+       0x9073, 0x9256, 0x9045, 0x9223
+};
+
+const u16 tbl_tx_iqlo_cal_cmds_recal[] = {
+       0x8101, 0x8253, 0x8053, 0x8234,
+       0x8034, 0x9101, 0x9253, 0x9053,
+       0x9234, 0x9034
+};
+
+const u16 tbl_tx_iqlo_cal_cmds_fullcal[] = {
+       0x8123, 0x8264, 0x8086, 0x8245,
+       0x8056, 0x9123, 0x9264, 0x9086,
+       0x9245, 0x9056
+};
+
+const u16 tbl_tx_iqlo_cal_cmds_fullcal_nphyrev3[] = {
+       0x8434, 0x8334, 0x8084, 0x8267,
+       0x8056, 0x8234, 0x9434, 0x9334,
+       0x9084, 0x9267, 0x9056, 0x9234
+};
+
 static inline void assert_ntab_array_sizes(void)
 {
 #undef check
@@ -2474,3 +2951,51 @@ void b43_ntab_write(struct b43_wldev *dev, u32 offset, u32 value)
        /* Some compiletime assertions... */
        assert_ntab_array_sizes();
 }
+
+#define ntab_upload(dev, offset, data) do { \
+               unsigned int i;                                         \
+               for (i = 0; i < (offset##_SIZE); i++)                   \
+                       b43_ntab_write(dev, (offset) + i, (data)[i]);   \
+       } while (0)
+
+void b43_nphy_rev0_1_2_tables_init(struct b43_wldev *dev)
+{
+       /* Static tables */
+       ntab_upload(dev, B43_NTAB_FRAMESTRUCT, b43_ntab_framestruct);
+       ntab_upload(dev, B43_NTAB_FRAMELT, b43_ntab_framelookup);
+       ntab_upload(dev, B43_NTAB_TMAP, b43_ntab_tmap);
+       ntab_upload(dev, B43_NTAB_TDTRN, b43_ntab_tdtrn);
+       ntab_upload(dev, B43_NTAB_INTLEVEL, b43_ntab_intlevel);
+       ntab_upload(dev, B43_NTAB_PILOT, b43_ntab_pilot);
+       ntab_upload(dev, B43_NTAB_PILOTLT, b43_ntab_pilotlt);
+       ntab_upload(dev, B43_NTAB_TDI20A0, b43_ntab_tdi20a0);
+       ntab_upload(dev, B43_NTAB_TDI20A1, b43_ntab_tdi20a1);
+       ntab_upload(dev, B43_NTAB_TDI40A0, b43_ntab_tdi40a0);
+       ntab_upload(dev, B43_NTAB_TDI40A1, b43_ntab_tdi40a1);
+       ntab_upload(dev, B43_NTAB_BDI, b43_ntab_bdi);
+       ntab_upload(dev, B43_NTAB_CHANEST, b43_ntab_channelest);
+       ntab_upload(dev, B43_NTAB_MCS, b43_ntab_mcs);
+
+       /* Volatile tables */
+       ntab_upload(dev, B43_NTAB_NOISEVAR10, b43_ntab_noisevar10);
+       ntab_upload(dev, B43_NTAB_NOISEVAR11, b43_ntab_noisevar11);
+       ntab_upload(dev, B43_NTAB_C0_ESTPLT, b43_ntab_estimatepowerlt0);
+       ntab_upload(dev, B43_NTAB_C1_ESTPLT, b43_ntab_estimatepowerlt1);
+       ntab_upload(dev, B43_NTAB_C0_ADJPLT, b43_ntab_adjustpower0);
+       ntab_upload(dev, B43_NTAB_C1_ADJPLT, b43_ntab_adjustpower1);
+       ntab_upload(dev, B43_NTAB_C0_GAINCTL, b43_ntab_gainctl0);
+       ntab_upload(dev, B43_NTAB_C1_GAINCTL, b43_ntab_gainctl1);
+       ntab_upload(dev, B43_NTAB_C0_IQLT, b43_ntab_iqlt0);
+       ntab_upload(dev, B43_NTAB_C1_IQLT, b43_ntab_iqlt1);
+       ntab_upload(dev, B43_NTAB_C0_LOFEEDTH, b43_ntab_loftlt0);
+       ntab_upload(dev, B43_NTAB_C1_LOFEEDTH, b43_ntab_loftlt1);
+}
+
+void b43_nphy_rev3plus_tables_init(struct b43_wldev *dev)
+{
+       /* Static tables */
+       /* TODO */
+
+       /* Volatile tables */
+       /* TODO */
+}
index 4d498b053ec7d2b9597fe0d33e8dd0dda1f8b94e..51636d02f8b131b3bb42b58b00c3d032bbf5df8a 100644 (file)
@@ -46,6 +46,11 @@ struct b43_nphy_channeltab_entry {
 
 struct b43_wldev;
 
+struct nphy_txiqcal_ladder {
+       u8 percent;
+       u8 g_env;
+};
+
 /* Upload the default register value table.
  * If "ghz5" is true, we upload the 5Ghz table. Otherwise the 2.4Ghz
  * table is uploaded. If "ignore_uploadflag" is true, we upload any value
@@ -126,34 +131,46 @@ b43_nphy_get_chantabent(struct b43_wldev *dev, u8 channel);
 #define B43_NTAB_C1_LOFEEDTH           B43_NTAB16(0x1B, 0x1C0) /* Local Oscillator Feed Through Lookup Table Core 1 */
 #define B43_NTAB_C1_LOFEEDTH_SIZE      128
 
-void b43_ntab_write(struct b43_wldev *dev, u32 offset, u32 value);
+#define B43_NTAB_TX_IQLO_CAL_LOFT_LADDER_40_SIZE       18
+#define B43_NTAB_TX_IQLO_CAL_LOFT_LADDER_20_SIZE       18
+#define B43_NTAB_TX_IQLO_CAL_IQIMB_LADDER_40_SIZE      18
+#define B43_NTAB_TX_IQLO_CAL_IQIMB_LADDER_20_SIZE      18
+#define B43_NTAB_TX_IQLO_CAL_STARTCOEFS_REV3           11
+#define B43_NTAB_TX_IQLO_CAL_STARTCOEFS                        9
+#define B43_NTAB_TX_IQLO_CAL_CMDS_RECAL_REV3           12
+#define B43_NTAB_TX_IQLO_CAL_CMDS_RECAL                        10
+#define B43_NTAB_TX_IQLO_CAL_CMDS_FULLCAL              10
+#define B43_NTAB_TX_IQLO_CAL_CMDS_FULLCAL_REV3         12
 
-extern const u8 b43_ntab_adjustpower0[];
-extern const u8 b43_ntab_adjustpower1[];
-extern const u16 b43_ntab_bdi[];
-extern const u32 b43_ntab_channelest[];
-extern const u8 b43_ntab_estimatepowerlt0[];
-extern const u8 b43_ntab_estimatepowerlt1[];
-extern const u8 b43_ntab_framelookup[];
-extern const u32 b43_ntab_framestruct[];
-extern const u32 b43_ntab_gainctl0[];
-extern const u32 b43_ntab_gainctl1[];
-extern const u32 b43_ntab_intlevel[];
-extern const u32 b43_ntab_iqlt0[];
-extern const u32 b43_ntab_iqlt1[];
-extern const u16 b43_ntab_loftlt0[];
-extern const u16 b43_ntab_loftlt1[];
-extern const u8 b43_ntab_mcs[];
-extern const u32 b43_ntab_noisevar10[];
-extern const u32 b43_ntab_noisevar11[];
-extern const u16 b43_ntab_pilot[];
-extern const u32 b43_ntab_pilotlt[];
-extern const u32 b43_ntab_tdi20a0[];
-extern const u32 b43_ntab_tdi20a1[];
-extern const u32 b43_ntab_tdi40a0[];
-extern const u32 b43_ntab_tdi40a1[];
-extern const u32 b43_ntab_tdtrn[];
-extern const u32 b43_ntab_tmap[];
+void b43_ntab_write(struct b43_wldev *dev, u32 offset, u32 value);
 
+void b43_nphy_rev0_1_2_tables_init(struct b43_wldev *dev);
+void b43_nphy_rev3plus_tables_init(struct b43_wldev *dev);
+
+extern const u32 b43_ntab_tx_gain_rev0_1_2[];
+extern const u32 b43_ntab_tx_gain_rev3plus_2ghz[];
+extern const u32 b43_ntab_tx_gain_rev3_5ghz[];
+extern const u32 b43_ntab_tx_gain_rev4_5ghz[];
+extern const u32 b43_ntab_tx_gain_rev5plus_5ghz[];
+
+extern const u32 txpwrctrl_tx_gain_ipa[];
+extern const u32 txpwrctrl_tx_gain_ipa_rev5[];
+extern const u32 txpwrctrl_tx_gain_ipa_rev6[];
+extern const u32 txpwrctrl_tx_gain_ipa_5g[];
+extern const u16 tbl_iqcal_gainparams[2][9][8];
+extern const struct nphy_txiqcal_ladder ladder_lo[];
+extern const struct nphy_txiqcal_ladder ladder_iq[];
+extern const u16 loscale[];
+
+extern const u16 tbl_tx_iqlo_cal_loft_ladder_40[];
+extern const u16 tbl_tx_iqlo_cal_loft_ladder_20[];
+extern const u16 tbl_tx_iqlo_cal_iqimb_ladder_40[];
+extern const u16 tbl_tx_iqlo_cal_iqimb_ladder_20[];
+extern const u16 tbl_tx_iqlo_cal_startcoefs_nphyrev3[];
+extern const u16 tbl_tx_iqlo_cal_startcoefs[];
+extern const u16 tbl_tx_iqlo_cal_cmds_recal_nphyrev3[];
+extern const u16 tbl_tx_iqlo_cal_cmds_recal[];
+extern const u16 tbl_tx_iqlo_cal_cmds_fullcal[];
+extern const u16 tbl_tx_iqlo_cal_cmds_fullcal_nphyrev3[];
 
 #endif /* B43_TABLES_NPHY_H_ */
index 4a905b6a886bc88cd5c5742457278828dd9e6acc..874a64a6c6108b5a4d0fab650a91261e672b4281 100644 (file)
@@ -61,6 +61,8 @@ MODULE_AUTHOR("Michael Buesch");
 MODULE_LICENSE("GPL");
 
 MODULE_FIRMWARE(B43legacy_SUPPORTED_FIRMWARE_ID);
+MODULE_FIRMWARE("b43legacy/ucode2.fw");
+MODULE_FIRMWARE("b43legacy/ucode4.fw");
 
 #if defined(CONFIG_B43LEGACY_DMA) && defined(CONFIG_B43LEGACY_PIO)
 static int modparam_pio;
@@ -3361,7 +3363,7 @@ err_kfree_lo_control:
 }
 
 static int b43legacy_op_add_interface(struct ieee80211_hw *hw,
-                                     struct ieee80211_if_init_conf *conf)
+                                     struct ieee80211_vif *vif)
 {
        struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
        struct b43legacy_wldev *dev;
@@ -3370,23 +3372,23 @@ static int b43legacy_op_add_interface(struct ieee80211_hw *hw,
 
        /* TODO: allow WDS/AP devices to coexist */
 
-       if (conf->type != NL80211_IFTYPE_AP &&
-           conf->type != NL80211_IFTYPE_STATION &&
-           conf->type != NL80211_IFTYPE_WDS &&
-           conf->type != NL80211_IFTYPE_ADHOC)
+       if (vif->type != NL80211_IFTYPE_AP &&
+           vif->type != NL80211_IFTYPE_STATION &&
+           vif->type != NL80211_IFTYPE_WDS &&
+           vif->type != NL80211_IFTYPE_ADHOC)
                return -EOPNOTSUPP;
 
        mutex_lock(&wl->mutex);
        if (wl->operating)
                goto out_mutex_unlock;
 
-       b43legacydbg(wl, "Adding Interface type %d\n", conf->type);
+       b43legacydbg(wl, "Adding Interface type %d\n", vif->type);
 
        dev = wl->current_dev;
        wl->operating = 1;
-       wl->vif = conf->vif;
-       wl->if_type = conf->type;
-       memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN);
+       wl->vif = vif;
+       wl->if_type = vif->type;
+       memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
 
        spin_lock_irqsave(&wl->irq_lock, flags);
        b43legacy_adjust_opmode(dev);
@@ -3403,18 +3405,18 @@ static int b43legacy_op_add_interface(struct ieee80211_hw *hw,
 }
 
 static void b43legacy_op_remove_interface(struct ieee80211_hw *hw,
-                                         struct ieee80211_if_init_conf *conf)
+                                         struct ieee80211_vif *vif)
 {
        struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
        struct b43legacy_wldev *dev = wl->current_dev;
        unsigned long flags;
 
-       b43legacydbg(wl, "Removing Interface type %d\n", conf->type);
+       b43legacydbg(wl, "Removing Interface type %d\n", vif->type);
 
        mutex_lock(&wl->mutex);
 
        B43legacy_WARN_ON(!wl->operating);
-       B43legacy_WARN_ON(wl->vif != conf->vif);
+       B43legacy_WARN_ON(wl->vif != vif);
        wl->vif = NULL;
 
        wl->operating = 0;
@@ -3960,7 +3962,7 @@ static struct ssb_driver b43legacy_ssb_driver = {
 
 static void b43legacy_print_driverinfo(void)
 {
-       const char *feat_pci = "", *feat_leds = "", *feat_rfkill = "",
+       const char *feat_pci = "", *feat_leds = "",
                   *feat_pio = "", *feat_dma = "";
 
 #ifdef CONFIG_B43LEGACY_PCI_AUTOSELECT
@@ -3969,9 +3971,6 @@ static void b43legacy_print_driverinfo(void)
 #ifdef CONFIG_B43LEGACY_LEDS
        feat_leds = "L";
 #endif
-#ifdef CONFIG_B43LEGACY_RFKILL
-       feat_rfkill = "R";
-#endif
 #ifdef CONFIG_B43LEGACY_PIO
        feat_pio = "I";
 #endif
@@ -3979,9 +3978,9 @@ static void b43legacy_print_driverinfo(void)
        feat_dma = "D";
 #endif
        printk(KERN_INFO "Broadcom 43xx-legacy driver loaded "
-              "[ Features: %s%s%s%s%s, Firmware-ID: "
+              "[ Features: %s%s%s%s, Firmware-ID: "
               B43legacy_SUPPORTED_FIRMWARE_ID " ]\n",
-              feat_pci, feat_leds, feat_rfkill, feat_pio, feat_dma);
+              feat_pci, feat_leds, feat_pio, feat_dma);
 }
 
 static int __init b43legacy_init(void)
index ff9b5c882184a00e58316166a62fd5514ead0ae6..d70732819423d25d09627fa0bc371be5f6976896 100644 (file)
@@ -2618,6 +2618,15 @@ static irqreturn_t prism2_interrupt(int irq, void *dev_id)
        int events = 0;
        u16 ev;
 
+       /* Detect early interrupt before driver is fully configued */
+       if (!dev->base_addr) {
+               if (net_ratelimit()) {
+                       printk(KERN_DEBUG "%s: Interrupt, but dev not configured\n",
+                              dev->name);
+               }
+               return IRQ_HANDLED;
+       }
+
        iface = netdev_priv(dev);
        local = iface->local;
 
index 8fdd41f4b4f2121a65f70d322bfe3951d1e233e0..4d97ae37499bd7a64e9368c8d48d4d8c4bd0d8ca 100644 (file)
@@ -39,7 +39,7 @@ struct hostap_pci_priv {
 /* FIX: do we need mb/wmb/rmb with memory operations? */
 
 
-static struct pci_device_id prism2_pci_id_table[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(prism2_pci_id_table) = {
        /* Intersil Prism3 ISL3872 11Mb/s WLAN Controller */
        { 0x1260, 0x3872, PCI_ANY_ID, PCI_ANY_ID },
        /* Intersil Prism2.5 ISL3874 11Mb/s WLAN Controller */
index 0e5d51086a444bbb366ba2a24951fd8b4b8f88d2..fc04ccdc5befa36f3126c4e2a0b888b6d6d7b700 100644 (file)
@@ -60,7 +60,7 @@ struct hostap_plx_priv {
 
 #define PLXDEV(vendor,dev,str) { vendor, dev, PCI_ANY_ID, PCI_ANY_ID }
 
-static struct pci_device_id prism2_plx_id_table[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(prism2_plx_id_table) = {
        PLXDEV(0x10b7, 0x7770, "3Com AirConnect PCI 777A"),
        PLXDEV(0x111a, 0x1023, "Siemens SpeedStream SS1023"),
        PLXDEV(0x126c, 0x8030, "Nortel emobility"),
index 56afcf041f8156322989bf168122af8c6a0a95d1..9b72c45a77485a057a8ce284358636b1b75e48f4 100644 (file)
@@ -6585,7 +6585,7 @@ static void ipw2100_shutdown(struct pci_dev *pci_dev)
 
 #define IPW2100_DEV_ID(x) { PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, x }
 
-static struct pci_device_id ipw2100_pci_id_table[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(ipw2100_pci_id_table) = {
        IPW2100_DEV_ID(0x2520), /* IN 2100A mPCI 3A */
        IPW2100_DEV_ID(0x2521), /* IN 2100A mPCI 3B */
        IPW2100_DEV_ID(0x2524), /* IN 2100A mPCI 3B */
index 09ddd3e6bedc172127a6ea63f542dbba6928db81..63c2a7ade5fbabe392cbd832256e626fb97e6a52 100644 (file)
@@ -11524,7 +11524,7 @@ out:
 }
 
 /* PCI driver stuff */
-static struct pci_device_id card_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(card_ids) = {
        {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2701, 0, 0, 0},
        {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2702, 0, 0, 0},
        {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2711, 0, 0, 0},
index 8414178bcff4a58c2d6254ad1c0af496b71eb026..0db1fda94a6574805c786b455c03c6bdbfc6efba 100644 (file)
@@ -105,6 +105,7 @@ static struct iwl_lib_ops iwl1000_lib = {
        .load_ucode = iwl5000_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,
        .init_alive_start = iwl5000_init_alive_start,
        .alive_notify = iwl5000_alive_notify,
        .send_tx_power = iwl5000_send_tx_power,
@@ -140,7 +141,7 @@ static struct iwl_lib_ops iwl1000_lib = {
         },
 };
 
-static struct iwl_ops iwl1000_ops = {
+static const struct iwl_ops iwl1000_ops = {
        .ucode = &iwl5000_ucode,
        .lib = &iwl1000_lib,
        .hcmd = &iwl5000_hcmd,
@@ -173,7 +174,6 @@ struct iwl_cfg iwl1000_bgn_cfg = {
        .use_rts_for_ht = true, /* use rts/cts protection */
        .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
        .support_ct_kill_exit = true,
-       .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,
 };
 
 struct iwl_cfg iwl1000_bg_cfg = {
index 234891d8cc1080b5358b624cf992fbc6d43510a6..6cde661ce0bcb52be05315cf239c08b2b0cb94cf 100644 (file)
@@ -2804,7 +2804,7 @@ static struct iwl_hcmd_utils_ops iwl3945_hcmd_utils = {
        .rts_tx_cmd_flag = iwlcore_rts_tx_cmd_flag,
 };
 
-static struct iwl_ops iwl3945_ops = {
+static const struct iwl_ops iwl3945_ops = {
        .ucode = &iwl3945_ucode,
        .lib = &iwl3945_lib,
        .hcmd = &iwl3945_hcmd,
@@ -2849,7 +2849,7 @@ static struct iwl_cfg iwl3945_abg_cfg = {
        .broken_powersave = true,
 };
 
-struct pci_device_id iwl3945_hw_card_ids[] = {
+DEFINE_PCI_DEVICE_TABLE(iwl3945_hw_card_ids) = {
        {IWL_PCI_DEVICE(0x4222, 0x1005, iwl3945_bg_cfg)},
        {IWL_PCI_DEVICE(0x4222, 0x1034, iwl3945_bg_cfg)},
        {IWL_PCI_DEVICE(0x4222, 0x1044, iwl3945_bg_cfg)},
index 531fa125f5a60744b4c20f33bc61db4713394420..bc532ff4f88376fdb25af0a05146b6f046f339bf 100644 (file)
@@ -37,7 +37,7 @@
 #include <net/ieee80211_radiotap.h>
 
 /* Hardware specific file defines the PCI IDs table for that hardware module */
-extern struct pci_device_id iwl3945_hw_card_ids[];
+extern const struct pci_device_id iwl3945_hw_card_ids[];
 
 #include "iwl-csr.h"
 #include "iwl-prph.h"
@@ -226,7 +226,8 @@ extern void iwl3945_rx_replenish(void *data);
 extern void iwl3945_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
 extern unsigned int iwl3945_fill_beacon_frame(struct iwl_priv *priv,
                                        struct ieee80211_hdr *hdr,int left);
-extern void iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log);
+extern int iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
+                                      char **buf, bool display);
 extern void iwl3945_dump_nic_error_log(struct iwl_priv *priv);
 
 /*
index 9b4b8b5c757464f0f48e9455ed1ea23f0a418a4f..6a004abb5973205d241b8a8ca47d6979aca9402b 100644 (file)
@@ -2208,7 +2208,7 @@ static struct iwl_lib_ops iwl4965_lib = {
        },
 };
 
-static struct iwl_ops iwl4965_ops = {
+static const struct iwl_ops iwl4965_ops = {
        .ucode = &iwl4965_ucode,
        .lib = &iwl4965_lib,
        .hcmd = &iwl4965_hcmd,
@@ -2239,7 +2239,6 @@ struct iwl_cfg iwl4965_agn_cfg = {
        .broken_powersave = true,
        .led_compensation = 61,
        .chain_noise_num_beacons = IWL4965_CAL_NUM_BEACONS,
-       .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,
 };
 
 /* Module firmware */
index de45f308b7440a56024ea5b54491633c4628398f..c6120f0b8f98d0aabf48e4439501e099938e7c5f 100644 (file)
@@ -781,7 +781,7 @@ void iwl5000_txq_update_byte_cnt_tbl(struct iwl_priv *priv,
 
        scd_bc_tbl[txq_id].tfd_offset[write_ptr] = bc_ent;
 
-       if (txq->q.write_ptr < TFD_QUEUE_SIZE_BC_DUP)
+       if (write_ptr < TFD_QUEUE_SIZE_BC_DUP)
                scd_bc_tbl[txq_id].
                        tfd_offset[TFD_QUEUE_SIZE_MAX + write_ptr] = bc_ent;
 }
@@ -800,12 +800,12 @@ void iwl5000_txq_inval_byte_cnt_tbl(struct iwl_priv *priv,
        if (txq_id != IWL_CMD_QUEUE_NUM)
                sta_id = txq->cmd[read_ptr]->cmd.tx.sta_id;
 
-       bc_ent =  cpu_to_le16(1 | (sta_id << 12));
+       bc_ent = cpu_to_le16(1 | (sta_id << 12));
        scd_bc_tbl[txq_id].tfd_offset[read_ptr] = bc_ent;
 
-       if (txq->q.write_ptr < TFD_QUEUE_SIZE_BC_DUP)
+       if (read_ptr < TFD_QUEUE_SIZE_BC_DUP)
                scd_bc_tbl[txq_id].
-                       tfd_offset[TFD_QUEUE_SIZE_MAX + read_ptr] =  bc_ent;
+                       tfd_offset[TFD_QUEUE_SIZE_MAX + read_ptr] = bc_ent;
 }
 
 static int iwl5000_tx_queue_set_q2ratid(struct iwl_priv *priv, u16 ra_tid,
@@ -1466,6 +1466,7 @@ struct iwl_lib_ops iwl5000_lib = {
        .is_valid_rtc_data_addr = iwl5000_hw_valid_rtc_data_addr,
        .dump_nic_event_log = iwl_dump_nic_event_log,
        .dump_nic_error_log = iwl_dump_nic_error_log,
+       .dump_csr = iwl_dump_csr,
        .load_ucode = iwl5000_load_ucode,
        .init_alive_start = iwl5000_init_alive_start,
        .alive_notify = iwl5000_alive_notify,
@@ -1518,6 +1519,7 @@ static struct iwl_lib_ops iwl5150_lib = {
        .is_valid_rtc_data_addr = iwl5000_hw_valid_rtc_data_addr,
        .dump_nic_event_log = iwl_dump_nic_event_log,
        .dump_nic_error_log = iwl_dump_nic_error_log,
+       .dump_csr = iwl_dump_csr,
        .load_ucode = iwl5000_load_ucode,
        .init_alive_start = iwl5000_init_alive_start,
        .alive_notify = iwl5000_alive_notify,
@@ -1555,7 +1557,7 @@ static struct iwl_lib_ops iwl5150_lib = {
         },
 };
 
-static struct iwl_ops iwl5000_ops = {
+static const struct iwl_ops iwl5000_ops = {
        .ucode = &iwl5000_ucode,
        .lib = &iwl5000_lib,
        .hcmd = &iwl5000_hcmd,
@@ -1563,7 +1565,7 @@ static struct iwl_ops iwl5000_ops = {
        .led = &iwlagn_led_ops,
 };
 
-static struct iwl_ops iwl5150_ops = {
+static const struct iwl_ops iwl5150_ops = {
        .ucode = &iwl5000_ucode,
        .lib = &iwl5150_lib,
        .hcmd = &iwl5000_hcmd,
@@ -1600,7 +1602,6 @@ struct iwl_cfg iwl5300_agn_cfg = {
        .led_compensation = 51,
        .use_rts_for_ht = true, /* use rts/cts protection */
        .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
-       .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,
 };
 
 struct iwl_cfg iwl5100_bgn_cfg = {
@@ -1671,7 +1672,6 @@ struct iwl_cfg iwl5100_agn_cfg = {
        .led_compensation = 51,
        .use_rts_for_ht = true, /* use rts/cts protection */
        .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
-       .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,
 };
 
 struct iwl_cfg iwl5350_agn_cfg = {
@@ -1696,7 +1696,6 @@ struct iwl_cfg iwl5350_agn_cfg = {
        .led_compensation = 51,
        .use_rts_for_ht = true, /* use rts/cts protection */
        .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
-       .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,
 };
 
 struct iwl_cfg iwl5150_agn_cfg = {
@@ -1721,7 +1720,6 @@ struct iwl_cfg iwl5150_agn_cfg = {
        .led_compensation = 51,
        .use_rts_for_ht = true, /* use rts/cts protection */
        .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
-       .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,
 };
 
 struct iwl_cfg iwl5150_abg_cfg = {
index 74e5710492731cd668409a45889e75818387f2c8..a5a0ed4817a471562e77c9b5ab42193d0246f253 100644 (file)
@@ -215,6 +215,7 @@ static struct iwl_lib_ops iwl6000_lib = {
        .load_ucode = iwl5000_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,
        .init_alive_start = iwl5000_init_alive_start,
        .alive_notify = iwl5000_alive_notify,
        .send_tx_power = iwl5000_send_tx_power,
@@ -252,7 +253,7 @@ static struct iwl_lib_ops iwl6000_lib = {
         },
 };
 
-static struct iwl_ops iwl6000_ops = {
+static const struct iwl_ops iwl6000_ops = {
        .ucode = &iwl5000_ucode,
        .lib = &iwl6000_lib,
        .hcmd = &iwl5000_hcmd,
@@ -267,7 +268,7 @@ static struct iwl_hcmd_utils_ops iwl6050_hcmd_utils = {
        .calc_rssi = iwl5000_calc_rssi,
 };
 
-static struct iwl_ops iwl6050_ops = {
+static const struct iwl_ops iwl6050_ops = {
        .ucode = &iwl5000_ucode,
        .lib = &iwl6000_lib,
        .hcmd = &iwl5000_hcmd,
@@ -306,7 +307,6 @@ struct iwl_cfg iwl6000i_2agn_cfg = {
        .supports_idle = true,
        .adv_thermal_throttle = true,
        .support_ct_kill_exit = true,
-       .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,
 };
 
 struct iwl_cfg iwl6000i_2abg_cfg = {
@@ -395,7 +395,6 @@ struct iwl_cfg iwl6050_2agn_cfg = {
        .supports_idle = true,
        .adv_thermal_throttle = true,
        .support_ct_kill_exit = true,
-       .sm_ps_mode = WLAN_HT_CAP_SM_PS_DYNAMIC,
 };
 
 struct iwl_cfg iwl6050_2abg_cfg = {
@@ -455,7 +454,6 @@ struct iwl_cfg iwl6000_3agn_cfg = {
        .supports_idle = true,
        .adv_thermal_throttle = true,
        .support_ct_kill_exit = true,
-       .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED,
 };
 
 MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX));
index 1c9866daf81565007beb6ee596063702e4bf387f..344e99de4cab242798693831dcd48e3afefc7519 100644 (file)
@@ -657,6 +657,131 @@ static void iwl_bg_statistics_periodic(unsigned long data)
        iwl_send_statistics_request(priv, CMD_ASYNC, false);
 }
 
+
+static void iwl_print_cont_event_trace(struct iwl_priv *priv, u32 base,
+                                       u32 start_idx, u32 num_events,
+                                       u32 mode)
+{
+       u32 i;
+       u32 ptr;        /* SRAM byte address of log data */
+       u32 ev, time, data; /* event log data */
+       unsigned long reg_flags;
+
+       if (mode == 0)
+               ptr = base + (4 * sizeof(u32)) + (start_idx * 2 * sizeof(u32));
+       else
+               ptr = base + (4 * sizeof(u32)) + (start_idx * 3 * sizeof(u32));
+
+       /* Make sure device is powered up for SRAM reads */
+       spin_lock_irqsave(&priv->reg_lock, reg_flags);
+       if (iwl_grab_nic_access(priv)) {
+               spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
+               return;
+       }
+
+       /* Set starting address; reads will auto-increment */
+       _iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, ptr);
+       rmb();
+
+       /*
+        * "time" is actually "data" for mode 0 (no timestamp).
+        * place event id # at far right for easier visual parsing.
+        */
+       for (i = 0; i < num_events; i++) {
+               ev = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
+               time = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
+               if (mode == 0) {
+                       trace_iwlwifi_dev_ucode_cont_event(priv,
+                                                       0, time, ev);
+               } else {
+                       data = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
+                       trace_iwlwifi_dev_ucode_cont_event(priv,
+                                               time, data, ev);
+               }
+       }
+       /* Allow device to power down */
+       iwl_release_nic_access(priv);
+       spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
+}
+
+void iwl_continuous_event_trace(struct iwl_priv *priv)
+{
+       u32 capacity;   /* event log capacity in # entries */
+       u32 base;       /* SRAM byte address of event log header */
+       u32 mode;       /* 0 - no timestamp, 1 - timestamp recorded */
+       u32 num_wraps;  /* # times uCode wrapped to top of log */
+       u32 next_entry; /* index of next entry to be written by uCode */
+
+       if (priv->ucode_type == UCODE_INIT)
+               base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr);
+       else
+               base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
+       if (priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
+               capacity = iwl_read_targ_mem(priv, base);
+               num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32)));
+               mode = iwl_read_targ_mem(priv, base + (1 * sizeof(u32)));
+               next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32)));
+       } else
+               return;
+
+       if (num_wraps == priv->event_log.num_wraps) {
+               iwl_print_cont_event_trace(priv,
+                                      base, priv->event_log.next_entry,
+                                      next_entry - priv->event_log.next_entry,
+                                      mode);
+               priv->event_log.non_wraps_count++;
+       } else {
+               if ((num_wraps - priv->event_log.num_wraps) > 1)
+                       priv->event_log.wraps_more_count++;
+               else
+                       priv->event_log.wraps_once_count++;
+               trace_iwlwifi_dev_ucode_wrap_event(priv,
+                               num_wraps - priv->event_log.num_wraps,
+                               next_entry, priv->event_log.next_entry);
+               if (next_entry < priv->event_log.next_entry) {
+                       iwl_print_cont_event_trace(priv, base,
+                              priv->event_log.next_entry,
+                              capacity - priv->event_log.next_entry,
+                              mode);
+
+                       iwl_print_cont_event_trace(priv, base, 0,
+                               next_entry, mode);
+               } else {
+                       iwl_print_cont_event_trace(priv, base,
+                              next_entry, capacity - next_entry,
+                              mode);
+
+                       iwl_print_cont_event_trace(priv, base, 0,
+                               next_entry, mode);
+               }
+       }
+       priv->event_log.num_wraps = num_wraps;
+       priv->event_log.next_entry = next_entry;
+}
+
+/**
+ * iwl_bg_ucode_trace - Timer callback to log ucode event
+ *
+ * The timer is continually set to execute every
+ * UCODE_TRACE_PERIOD milliseconds after the last timer expired
+ * this function is to perform continuous uCode event logging operation
+ * if enabled
+ */
+static void iwl_bg_ucode_trace(unsigned long data)
+{
+       struct iwl_priv *priv = (struct iwl_priv *)data;
+
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+               return;
+
+       if (priv->event_log.ucode_trace) {
+               iwl_continuous_event_trace(priv);
+               /* Reschedule the timer to occur in UCODE_TRACE_PERIOD */
+               mod_timer(&priv->ucode_trace,
+                        jiffies + msecs_to_jiffies(UCODE_TRACE_PERIOD));
+       }
+}
+
 static void iwl_rx_beacon_notif(struct iwl_priv *priv,
                                struct iwl_rx_mem_buffer *rxb)
 {
@@ -689,12 +814,14 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv,
        u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags);
        unsigned long status = priv->status;
 
-       IWL_DEBUG_RF_KILL(priv, "Card state received: HW:%s SW:%s\n",
+       IWL_DEBUG_RF_KILL(priv, "Card state received: HW:%s SW:%s CT:%s\n",
                          (flags & HW_CARD_DISABLED) ? "Kill" : "On",
-                         (flags & SW_CARD_DISABLED) ? "Kill" : "On");
+                         (flags & SW_CARD_DISABLED) ? "Kill" : "On",
+                         (flags & CT_CARD_DISABLED) ?
+                         "Reached" : "Not reached");
 
        if (flags & (SW_CARD_DISABLED | HW_CARD_DISABLED |
-                    RF_CARD_DISABLED)) {
+                    CT_CARD_DISABLED)) {
 
                iwl_write32(priv, CSR_UCODE_DRV_GP1_SET,
                            CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
@@ -708,10 +835,10 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv,
                        iwl_write_direct32(priv, HBUS_TARG_MBX_C,
                                        HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED);
                }
-               if (flags & RF_CARD_DISABLED)
+               if (flags & CT_CARD_DISABLED)
                        iwl_tt_enter_ct_kill(priv);
        }
-       if (!(flags & RF_CARD_DISABLED))
+       if (!(flags & CT_CARD_DISABLED))
                iwl_tt_exit_ct_kill(priv);
 
        if (flags & HW_CARD_DISABLED)
@@ -1705,8 +1832,9 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv)
  * iwl_print_event_log - Dump error event log to syslog
  *
  */
-static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
-                               u32 num_events, u32 mode)
+static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
+                              u32 num_events, u32 mode,
+                              int pos, char **buf, size_t bufsz)
 {
        u32 i;
        u32 base;       /* SRAM byte address of event log header */
@@ -1716,7 +1844,7 @@ static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
        unsigned long reg_flags;
 
        if (num_events == 0)
-               return;
+               return pos;
        if (priv->ucode_type == UCODE_INIT)
                base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr);
        else
@@ -1744,27 +1872,44 @@ static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
                time = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
                if (mode == 0) {
                        /* data, ev */
-                       trace_iwlwifi_dev_ucode_event(priv, 0, time, ev);
-                       IWL_ERR(priv, "EVT_LOG:0x%08x:%04u\n", time, ev);
+                       if (bufsz) {
+                               pos += scnprintf(*buf + pos, bufsz - pos,
+                                               "EVT_LOG:0x%08x:%04u\n",
+                                               time, ev);
+                       } else {
+                               trace_iwlwifi_dev_ucode_event(priv, 0,
+                                       time, ev);
+                               IWL_ERR(priv, "EVT_LOG:0x%08x:%04u\n",
+                                       time, ev);
+                       }
                } else {
                        data = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
-                       IWL_ERR(priv, "EVT_LOGT:%010u:0x%08x:%04u\n",
+                       if (bufsz) {
+                               pos += scnprintf(*buf + pos, bufsz - pos,
+                                               "EVT_LOGT:%010u:0x%08x:%04u\n",
+                                                time, data, ev);
+                       } else {
+                               IWL_ERR(priv, "EVT_LOGT:%010u:0x%08x:%04u\n",
                                        time, data, ev);
-                       trace_iwlwifi_dev_ucode_event(priv, time, data, ev);
+                               trace_iwlwifi_dev_ucode_event(priv, time,
+                                       data, ev);
+                       }
                }
        }
 
        /* Allow device to power down */
        iwl_release_nic_access(priv);
        spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
+       return pos;
 }
 
 /**
  * iwl_print_last_event_logs - Dump the newest # of event log to syslog
  */
-static void iwl_print_last_event_logs(struct iwl_priv *priv, u32 capacity,
-                                     u32 num_wraps, u32 next_entry,
-                                     u32 size, u32 mode)
+static int iwl_print_last_event_logs(struct iwl_priv *priv, u32 capacity,
+                                   u32 num_wraps, u32 next_entry,
+                                   u32 size, u32 mode,
+                                   int pos, char **buf, size_t bufsz)
 {
        /*
         * display the newest DEFAULT_LOG_ENTRIES entries
@@ -1772,21 +1917,26 @@ static void iwl_print_last_event_logs(struct iwl_priv *priv, u32 capacity,
         */
        if (num_wraps) {
                if (next_entry < size) {
-                       iwl_print_event_log(priv,
-                                       capacity - (size - next_entry),
-                                       size - next_entry, mode);
-                       iwl_print_event_log(priv, 0,
-                                   next_entry, mode);
+                       pos = iwl_print_event_log(priv,
+                                               capacity - (size - next_entry),
+                                               size - next_entry, mode,
+                                               pos, buf, bufsz);
+                       pos = iwl_print_event_log(priv, 0,
+                                                 next_entry, mode,
+                                                 pos, buf, bufsz);
                } else
-                       iwl_print_event_log(priv, next_entry - size,
-                                   size, mode);
+                       pos = iwl_print_event_log(priv, next_entry - size,
+                                                 size, mode, pos, buf, bufsz);
        } else {
-               if (next_entry < size)
-                       iwl_print_event_log(priv, 0, next_entry, mode);
-               else
-                       iwl_print_event_log(priv, next_entry - size,
-                                           size, mode);
+               if (next_entry < size) {
+                       pos = iwl_print_event_log(priv, 0, next_entry,
+                                                 mode, pos, buf, bufsz);
+               } else {
+                       pos = iwl_print_event_log(priv, next_entry - size,
+                                                 size, mode, pos, buf, bufsz);
+               }
        }
+       return pos;
 }
 
 /* For sanity check only.  Actual size is determined by uCode, typ. 512 */
@@ -1794,7 +1944,8 @@ static void iwl_print_last_event_logs(struct iwl_priv *priv, u32 capacity,
 
 #define DEFAULT_DUMP_EVENT_LOG_ENTRIES (20)
 
-void iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log)
+int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
+                           char **buf, bool display)
 {
        u32 base;       /* SRAM byte address of event log header */
        u32 capacity;   /* event log capacity in # entries */
@@ -1802,6 +1953,8 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log)
        u32 num_wraps;  /* # times uCode wrapped to top of log */
        u32 next_entry; /* index of next entry to be written by uCode */
        u32 size;       /* # entries that we'll print */
+       int pos = 0;
+       size_t bufsz = 0;
 
        if (priv->ucode_type == UCODE_INIT)
                base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr);
@@ -1812,7 +1965,7 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log)
                IWL_ERR(priv,
                        "Invalid event log pointer 0x%08X for %s uCode\n",
                        base, (priv->ucode_type == UCODE_INIT) ? "Init" : "RT");
-               return;
+               return pos;
        }
 
        /* event log header */
@@ -1838,7 +1991,7 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log)
        /* bail out if nothing in log */
        if (size == 0) {
                IWL_ERR(priv, "Start IWL Event Log Dump: nothing in log\n");
-               return;
+               return pos;
        }
 
 #ifdef CONFIG_IWLWIFI_DEBUG
@@ -1853,6 +2006,15 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log)
                size);
 
 #ifdef CONFIG_IWLWIFI_DEBUG
+       if (display) {
+               if (full_log)
+                       bufsz = capacity * 48;
+               else
+                       bufsz = size * 48;
+               *buf = kmalloc(bufsz, GFP_KERNEL);
+               if (!*buf)
+                       return pos;
+       }
        if ((iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS) || full_log) {
                /*
                 * if uCode has wrapped back to top of log,
@@ -1860,17 +2022,22 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log)
                 * i.e the next one that uCode would fill.
                 */
                if (num_wraps)
-                       iwl_print_event_log(priv, next_entry,
-                                           capacity - next_entry, mode);
+                       pos = iwl_print_event_log(priv, next_entry,
+                                               capacity - next_entry, mode,
+                                               pos, buf, bufsz);
                /* (then/else) start at top of log */
-               iwl_print_event_log(priv, 0, next_entry, mode);
+               pos = iwl_print_event_log(priv, 0,
+                                         next_entry, mode, pos, buf, bufsz);
        } else
-               iwl_print_last_event_logs(priv, capacity, num_wraps,
-                                       next_entry, size, mode);
+               pos = iwl_print_last_event_logs(priv, capacity, num_wraps,
+                                               next_entry, size, mode,
+                                               pos, buf, bufsz);
 #else
-       iwl_print_last_event_logs(priv, capacity, num_wraps,
-                               next_entry, size, mode);
+       pos = iwl_print_last_event_logs(priv, capacity, num_wraps,
+                                       next_entry, size, mode,
+                                       pos, buf, bufsz);
 #endif
+       return pos;
 }
 
 /**
@@ -2456,6 +2623,10 @@ static int iwl_setup_mac(struct iwl_priv *priv)
                hw->flags |= IEEE80211_HW_SUPPORTS_PS |
                             IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
 
+       if (priv->cfg->sku & IWL_SKU_N)
+               hw->flags |= IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS |
+                            IEEE80211_HW_SUPPORTS_STATIC_SMPS;
+
        hw->sta_data_size = sizeof(struct iwl_station_priv);
        hw->wiphy->interface_modes =
                BIT(NL80211_IFTYPE_STATION) |
@@ -2784,6 +2955,9 @@ static int iwl_mac_ampdu_action(struct ieee80211_hw *hw,
                        return 0;
                else
                        return ret;
+       case IEEE80211_AMPDU_TX_OPERATIONAL:
+               /* do nothing */
+               return -EOPNOTSUPP;
        default:
                IWL_DEBUG_HT(priv, "unknown\n");
                return -EINVAL;
@@ -3126,6 +3300,10 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv)
        priv->statistics_periodic.data = (unsigned long)priv;
        priv->statistics_periodic.function = iwl_bg_statistics_periodic;
 
+       init_timer(&priv->ucode_trace);
+       priv->ucode_trace.data = (unsigned long)priv;
+       priv->ucode_trace.function = iwl_bg_ucode_trace;
+
        if (!priv->cfg->use_isr_legacy)
                tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
                        iwl_irq_tasklet, (unsigned long)priv);
@@ -3144,6 +3322,7 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv)
        cancel_delayed_work(&priv->alive_start);
        cancel_work_sync(&priv->beacon_update);
        del_timer_sync(&priv->statistics_periodic);
+       del_timer_sync(&priv->ucode_trace);
 }
 
 static void iwl_init_hw_rates(struct iwl_priv *priv,
@@ -3188,6 +3367,7 @@ static int iwl_init_drv(struct iwl_priv *priv)
        priv->band = IEEE80211_BAND_2GHZ;
 
        priv->iw_mode = NL80211_IFTYPE_STATION;
+       priv->current_ht_config.smps = IEEE80211_SMPS_STATIC;
 
        /* Choose which receivers/antennas to use */
        if (priv->cfg->ops->hcmd->set_rxon_chain)
@@ -3589,7 +3769,7 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev)
  *****************************************************************************/
 
 /* Hardware specific file defines the PCI IDs table for that hardware module */
-static struct pci_device_id iwl_hw_card_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
 #ifdef CONFIG_IWL4965
        {IWL_PCI_DEVICE(0x4229, PCI_ANY_ID, iwl4965_agn_cfg)},
        {IWL_PCI_DEVICE(0x4230, PCI_ANY_ID, iwl4965_agn_cfg)},
index 95a57b36a7eafef9a366409d4d7391e0c77861d2..dc61906290e81b92852ab845b96f661858a6d2dc 100644 (file)
@@ -414,7 +414,6 @@ static int iwl_sens_auto_corr_ofdm(struct iwl_priv *priv,
 /* Prepare a SENSITIVITY_CMD, send to uCode if values have changed */
 static int iwl_sensitivity_write(struct iwl_priv *priv)
 {
-       int ret = 0;
        struct iwl_sensitivity_cmd cmd ;
        struct iwl_sensitivity_data *data = NULL;
        struct iwl_host_cmd cmd_out = {
@@ -477,11 +476,7 @@ static int iwl_sensitivity_write(struct iwl_priv *priv)
        memcpy(&(priv->sensitivity_tbl[0]), &(cmd.table[0]),
               sizeof(u16)*HD_TABLE_SIZE);
 
-       ret = iwl_send_cmd(priv, &cmd_out);
-       if (ret)
-               IWL_ERR(priv, "SENSITIVITY_CMD failed\n");
-
-       return ret;
+       return iwl_send_cmd(priv, &cmd_out);
 }
 
 void iwl_init_sensitivity(struct iwl_priv *priv)
index e9150753192318721a1fe42ff13560b8cb820624..3320cce3d57b4391c1c9f17c33d732967440d3b4 100644 (file)
@@ -120,7 +120,6 @@ enum {
        CALIBRATION_COMPLETE_NOTIFICATION = 0x67,
 
        /* 802.11h related */
-       RADAR_NOTIFICATION = 0x70,      /* not used */
        REPLY_QUIET_CMD = 0x71,         /* not used */
        REPLY_CHANNEL_SWITCH = 0x72,
        CHANNEL_SWITCH_NOTIFICATION = 0x73,
@@ -2510,7 +2509,7 @@ struct iwl_card_state_notif {
 
 #define HW_CARD_DISABLED   0x01
 #define SW_CARD_DISABLED   0x02
-#define RF_CARD_DISABLED   0x04
+#define CT_CARD_DISABLED   0x04
 #define RXON_CARD_DISABLED 0x10
 
 struct iwl_ct_kill_config {
@@ -2984,7 +2983,7 @@ struct statistics_rx_ht_phy {
        __le32 agg_crc32_good;
        __le32 agg_mpdu_cnt;
        __le32 agg_cnt;
-       __le32 reserved2;
+       __le32 unsupport_mcs;
 } __attribute__ ((packed));
 
 #define INTERFERENCE_DATA_AVAILABLE      cpu_to_le32(1)
@@ -3087,8 +3086,8 @@ struct statistics_div {
 } __attribute__ ((packed));
 
 struct statistics_general {
-       __le32 temperature;
-       __le32 temperature_m;
+       __le32 temperature;   /* radio temperature */
+       __le32 temperature_m; /* for 5000 and up, this is radio voltage */
        struct statistics_dbg dbg;
        __le32 sleep_time;
        __le32 slots_out;
index 5461f105bd2dcb61971d17c64ef17c640c553c8b..5b56307a3812f6bc92a66935b2e427c0404bd5ac 100644 (file)
@@ -450,8 +450,6 @@ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv,
        if (priv->cfg->ht_greenfield_support)
                ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD;
        ht_info->cap |= IEEE80211_HT_CAP_SGI_20;
-       ht_info->cap |= (IEEE80211_HT_CAP_SM_PS &
-                            (priv->cfg->sm_ps_mode << 2));
        max_bit_rate = MAX_BIT_RATE_20_MHZ;
        if (priv->hw_params.ht40_channel & BIT(band)) {
                ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
@@ -636,7 +634,7 @@ EXPORT_SYMBOL(iwlcore_rts_tx_cmd_flag);
 
 static bool is_single_rx_stream(struct iwl_priv *priv)
 {
-       return !priv->current_ht_config.is_ht ||
+       return priv->current_ht_config.smps == IEEE80211_SMPS_STATIC ||
               priv->current_ht_config.single_chain_sufficient;
 }
 
@@ -1003,28 +1001,18 @@ static int iwl_get_active_rx_chain_count(struct iwl_priv *priv)
  */
 static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt)
 {
-       int idle_cnt = active_cnt;
-       bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status);
-
-       /* # Rx chains when idling and maybe trying to save power */
-       switch (priv->cfg->sm_ps_mode) {
-       case WLAN_HT_CAP_SM_PS_STATIC:
-               idle_cnt = (is_cam) ? active_cnt : IWL_NUM_IDLE_CHAINS_SINGLE;
-               break;
-       case WLAN_HT_CAP_SM_PS_DYNAMIC:
-               idle_cnt = (is_cam) ? IWL_NUM_IDLE_CHAINS_DUAL :
-                       IWL_NUM_IDLE_CHAINS_SINGLE;
-               break;
-       case WLAN_HT_CAP_SM_PS_DISABLED:
-               break;
-       case WLAN_HT_CAP_SM_PS_INVALID:
+       /* # Rx chains when idling, depending on SMPS mode */
+       switch (priv->current_ht_config.smps) {
+       case IEEE80211_SMPS_STATIC:
+       case IEEE80211_SMPS_DYNAMIC:
+               return IWL_NUM_IDLE_CHAINS_SINGLE;
+       case IEEE80211_SMPS_OFF:
+               return active_cnt;
        default:
-               IWL_ERR(priv, "invalid sm_ps mode %u\n",
-                       priv->cfg->sm_ps_mode);
-               WARN_ON(1);
-               break;
+               WARN(1, "invalid SMPS mode %d",
+                    priv->current_ht_config.smps);
+               return active_cnt;
        }
-       return idle_cnt;
 }
 
 /* up to 4 chains */
@@ -1363,7 +1351,9 @@ void iwl_irq_handle_error(struct iwl_priv *priv)
        clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
 
        priv->cfg->ops->lib->dump_nic_error_log(priv);
-       priv->cfg->ops->lib->dump_nic_event_log(priv, false);
+       if (priv->cfg->ops->lib->dump_csr)
+               priv->cfg->ops->lib->dump_csr(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);
@@ -2599,12 +2589,12 @@ int iwl_set_mode(struct iwl_priv *priv, int mode)
 EXPORT_SYMBOL(iwl_set_mode);
 
 int iwl_mac_add_interface(struct ieee80211_hw *hw,
-                                struct ieee80211_if_init_conf *conf)
+                                struct ieee80211_vif *vif)
 {
        struct iwl_priv *priv = hw->priv;
        unsigned long flags;
 
-       IWL_DEBUG_MAC80211(priv, "enter: type %d\n", conf->type);
+       IWL_DEBUG_MAC80211(priv, "enter: type %d\n", vif->type);
 
        if (priv->vif) {
                IWL_DEBUG_MAC80211(priv, "leave - vif != NULL\n");
@@ -2612,19 +2602,19 @@ int iwl_mac_add_interface(struct ieee80211_hw *hw,
        }
 
        spin_lock_irqsave(&priv->lock, flags);
-       priv->vif = conf->vif;
-       priv->iw_mode = conf->type;
+       priv->vif = vif;
+       priv->iw_mode = vif->type;
 
        spin_unlock_irqrestore(&priv->lock, flags);
 
        mutex_lock(&priv->mutex);
 
-       if (conf->mac_addr) {
-               IWL_DEBUG_MAC80211(priv, "Set %pM\n", conf->mac_addr);
-               memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN);
+       if (vif->addr) {
+               IWL_DEBUG_MAC80211(priv, "Set %pM\n", vif->addr);
+               memcpy(priv->mac_addr, vif->addr, ETH_ALEN);
        }
 
-       if (iwl_set_mode(priv, conf->type) == -EAGAIN)
+       if (iwl_set_mode(priv, vif->type) == -EAGAIN)
                /* we are not ready, will run again when ready */
                set_bit(STATUS_MODE_PENDING, &priv->status);
 
@@ -2636,7 +2626,7 @@ int iwl_mac_add_interface(struct ieee80211_hw *hw,
 EXPORT_SYMBOL(iwl_mac_add_interface);
 
 void iwl_mac_remove_interface(struct ieee80211_hw *hw,
-                                    struct ieee80211_if_init_conf *conf)
+                                    struct ieee80211_vif *vif)
 {
        struct iwl_priv *priv = hw->priv;
 
@@ -2649,7 +2639,7 @@ void iwl_mac_remove_interface(struct ieee80211_hw *hw,
                priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
                iwlcore_commit_rxon(priv);
        }
-       if (priv->vif == conf->vif) {
+       if (priv->vif == vif) {
                priv->vif = NULL;
                memset(priv->bssid, 0, ETH_ALEN);
        }
@@ -2689,6 +2679,21 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
                IWL_DEBUG_MAC80211(priv, "leave - scanning\n");
        }
 
+       if (changed & (IEEE80211_CONF_CHANGE_SMPS |
+                      IEEE80211_CONF_CHANGE_CHANNEL)) {
+               /* mac80211 uses static for non-HT which is what we want */
+               priv->current_ht_config.smps = conf->smps_mode;
+
+               /*
+                * Recalculate chain counts.
+                *
+                * If monitor mode is enabled then mac80211 will
+                * set up the SM PS mode to OFF if an HT channel is
+                * configured.
+                */
+               if (priv->cfg->ops->hcmd->set_rxon_chain)
+                       priv->cfg->ops->hcmd->set_rxon_chain(priv);
+       }
 
        /* during scanning mac80211 will delay channel setting until
         * scan finish with changed = 0
@@ -2785,10 +2790,6 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
                iwl_set_tx_power(priv, conf->power_level, false);
        }
 
-       /* call to ensure that 4965 rx_chain is set properly in monitor mode */
-       if (priv->cfg->ops->hcmd->set_rxon_chain)
-               priv->cfg->ops->hcmd->set_rxon_chain(priv);
-
        if (!iwl_is_ready(priv)) {
                IWL_DEBUG_MAC80211(priv, "leave - not ready\n");
                goto out;
@@ -3196,6 +3197,77 @@ void iwl_update_stats(struct iwl_priv *priv, bool is_tx, __le16 fc, u16 len)
 EXPORT_SYMBOL(iwl_update_stats);
 #endif
 
+const static char *get_csr_string(int cmd)
+{
+       switch (cmd) {
+               IWL_CMD(CSR_HW_IF_CONFIG_REG);
+               IWL_CMD(CSR_INT_COALESCING);
+               IWL_CMD(CSR_INT);
+               IWL_CMD(CSR_INT_MASK);
+               IWL_CMD(CSR_FH_INT_STATUS);
+               IWL_CMD(CSR_GPIO_IN);
+               IWL_CMD(CSR_RESET);
+               IWL_CMD(CSR_GP_CNTRL);
+               IWL_CMD(CSR_HW_REV);
+               IWL_CMD(CSR_EEPROM_REG);
+               IWL_CMD(CSR_EEPROM_GP);
+               IWL_CMD(CSR_OTP_GP_REG);
+               IWL_CMD(CSR_GIO_REG);
+               IWL_CMD(CSR_GP_UCODE_REG);
+               IWL_CMD(CSR_GP_DRIVER_REG);
+               IWL_CMD(CSR_UCODE_DRV_GP1);
+               IWL_CMD(CSR_UCODE_DRV_GP2);
+               IWL_CMD(CSR_LED_REG);
+               IWL_CMD(CSR_DRAM_INT_TBL_REG);
+               IWL_CMD(CSR_GIO_CHICKEN_BITS);
+               IWL_CMD(CSR_ANA_PLL_CFG);
+               IWL_CMD(CSR_HW_REV_WA_REG);
+               IWL_CMD(CSR_DBG_HPET_MEM_REG);
+       default:
+               return "UNKNOWN";
+
+       }
+}
+
+void iwl_dump_csr(struct iwl_priv *priv)
+{
+       int i;
+       u32 csr_tbl[] = {
+               CSR_HW_IF_CONFIG_REG,
+               CSR_INT_COALESCING,
+               CSR_INT,
+               CSR_INT_MASK,
+               CSR_FH_INT_STATUS,
+               CSR_GPIO_IN,
+               CSR_RESET,
+               CSR_GP_CNTRL,
+               CSR_HW_REV,
+               CSR_EEPROM_REG,
+               CSR_EEPROM_GP,
+               CSR_OTP_GP_REG,
+               CSR_GIO_REG,
+               CSR_GP_UCODE_REG,
+               CSR_GP_DRIVER_REG,
+               CSR_UCODE_DRV_GP1,
+               CSR_UCODE_DRV_GP2,
+               CSR_LED_REG,
+               CSR_DRAM_INT_TBL_REG,
+               CSR_GIO_CHICKEN_BITS,
+               CSR_ANA_PLL_CFG,
+               CSR_HW_REV_WA_REG,
+               CSR_DBG_HPET_MEM_REG
+       };
+       IWL_ERR(priv, "CSR values:\n");
+       IWL_ERR(priv, "(2nd byte of CSR_INT_COALESCING is "
+               "CSR_INT_PERIODIC_REG)\n");
+       for (i = 0; i <  ARRAY_SIZE(csr_tbl); i++) {
+               IWL_ERR(priv, "  %25s: 0X%08x\n",
+                       get_csr_string(csr_tbl[i]),
+                       iwl_read32(priv, csr_tbl[i]));
+       }
+}
+EXPORT_SYMBOL(iwl_dump_csr);
+
 #ifdef CONFIG_PM
 
 int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state)
index 27ca859e7453c250ca70aea6d64ce9820ae6f98d..8deb83bfe182bbadf0eee9db9c9cbc9788221437 100644 (file)
@@ -63,8 +63,6 @@
 #ifndef __iwl_core_h__
 #define __iwl_core_h__
 
-#include <generated/utsrelease.h>
-
 /************************
  * forward declarations *
  ************************/
@@ -72,7 +70,7 @@ struct iwl_host_cmd;
 struct iwl_cmd;
 
 
-#define IWLWIFI_VERSION UTS_RELEASE "-k"
+#define IWLWIFI_VERSION "in-tree:"
 #define DRV_COPYRIGHT  "Copyright(c) 2003-2009 Intel Corporation"
 #define DRV_AUTHOR     "<ilw@linux.intel.com>"
 
@@ -169,8 +167,10 @@ struct iwl_lib_ops {
        int (*is_valid_rtc_data_addr)(u32 addr);
        /* 1st ucode load */
        int (*load_ucode)(struct iwl_priv *priv);
-       void (*dump_nic_event_log)(struct iwl_priv *priv, bool full_log);
+       int (*dump_nic_event_log)(struct iwl_priv *priv,
+                                 bool full_log, char **buf, bool display);
        void (*dump_nic_error_log)(struct iwl_priv *priv);
+       void (*dump_csr)(struct iwl_priv *priv);
        int (*set_channel_switch)(struct iwl_priv *priv, u16 channel);
        /* power management */
        struct iwl_apm_ops apm_ops;
@@ -230,7 +230,6 @@ struct iwl_mod_params {
  * @chain_noise_num_beacons: number of beacons used to compute chain noise
  * @adv_thermal_throttle: support advance thermal throttle
  * @support_ct_kill_exit: support ct kill exit condition
- * @sm_ps_mode: spatial multiplexing power save mode
  * @support_wimax_coexist: support wimax/wifi co-exist
  *
  * We enable the driver to be backward compatible wrt API version. The
@@ -287,7 +286,6 @@ struct iwl_cfg {
        const bool supports_idle;
        bool adv_thermal_throttle;
        bool support_ct_kill_exit;
-       u8 sm_ps_mode;
        const bool support_wimax_coexist;
 };
 
@@ -332,9 +330,9 @@ int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb);
 int iwl_commit_rxon(struct iwl_priv *priv);
 int iwl_set_mode(struct iwl_priv *priv, int mode);
 int iwl_mac_add_interface(struct ieee80211_hw *hw,
-                                struct ieee80211_if_init_conf *conf);
+                         struct ieee80211_vif *vif);
 void iwl_mac_remove_interface(struct ieee80211_hw *hw,
-                                struct ieee80211_if_init_conf *conf);
+                             struct ieee80211_vif *vif);
 int iwl_mac_config(struct ieee80211_hw *hw, u32 changed);
 void iwl_config_ap(struct iwl_priv *priv);
 int iwl_mac_get_tx_stats(struct ieee80211_hw *hw,
@@ -581,7 +579,9 @@ int iwl_pci_resume(struct pci_dev *pdev);
 *  Error Handling Debugging
 ******************************************************/
 void iwl_dump_nic_error_log(struct iwl_priv *priv);
-void iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log);
+int iwl_dump_nic_event_log(struct iwl_priv *priv,
+                          bool full_log, char **buf, bool display);
+void iwl_dump_csr(struct iwl_priv *priv);
 #ifdef CONFIG_IWLWIFI_DEBUG
 void iwl_print_rx_config_cmd(struct iwl_priv *priv);
 #else
index d61293ab67c994752710b44b2a82beb07bbade42..58e0462cafa35744d84f4d252e1cb61f8d9d133e 100644 (file)
@@ -109,6 +109,8 @@ struct iwl_debugfs {
                struct dentry *file_power_save_status;
                struct dentry *file_clear_ucode_statistics;
                struct dentry *file_clear_traffic_statistics;
+               struct dentry *file_csr;
+               struct dentry *file_ucode_tracing;
        } dbgfs_debug_files;
        u32 sram_offset;
        u32 sram_len;
index 21e0f6699daf138854be2d36f831b405fb44f9e5..4a2ac9311ba8a8a8654a2e5958fe06ebc04d09d4 100644 (file)
@@ -125,7 +125,7 @@ static ssize_t iwl_dbgfs_tx_statistics_read(struct file *file,
                                                char __user *user_buf,
                                                size_t count, loff_t *ppos) {
 
-       struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+       struct iwl_priv *priv = file->private_data;
        char *buf;
        int pos = 0;
 
@@ -184,7 +184,7 @@ static ssize_t iwl_dbgfs_rx_statistics_read(struct file *file,
                                                char __user *user_buf,
                                                size_t count, loff_t *ppos) {
 
-       struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+       struct iwl_priv *priv = file->private_data;
        char *buf;
        int pos = 0;
        int cnt;
@@ -232,7 +232,7 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file,
        ssize_t ret;
        int i;
        int pos = 0;
-       struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+       struct iwl_priv *priv = file->private_data;
        size_t bufsz;
 
        /* default is to dump the entire data segment */
@@ -306,7 +306,7 @@ static ssize_t iwl_dbgfs_sram_write(struct file *file,
 static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf,
                                        size_t count, loff_t *ppos)
 {
-       struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+       struct iwl_priv *priv = file->private_data;
        struct iwl_station_entry *station;
        int max_sta = priv->hw_params.max_stations;
        char *buf;
@@ -376,7 +376,7 @@ static ssize_t iwl_dbgfs_nvm_read(struct file *file,
                                       loff_t *ppos)
 {
        ssize_t ret;
-       struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+       struct iwl_priv *priv = file->private_data;
        int pos = 0, ofs = 0, buf_size = 0;
        const u8 *ptr;
        char *buf;
@@ -420,6 +420,23 @@ static ssize_t iwl_dbgfs_nvm_read(struct file *file,
        return ret;
 }
 
+static ssize_t iwl_dbgfs_log_event_read(struct file *file,
+                                        char __user *user_buf,
+                                        size_t count, loff_t *ppos)
+{
+       struct iwl_priv *priv = file->private_data;
+       char *buf;
+       int pos = 0;
+       ssize_t ret = -ENOMEM;
+
+       pos = priv->cfg->ops->lib->dump_nic_event_log(priv, true, &buf, true);
+       if (pos && buf) {
+               ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+               kfree(buf);
+       }
+       return ret;
+}
+
 static ssize_t iwl_dbgfs_log_event_write(struct file *file,
                                        const char __user *user_buf,
                                        size_t count, loff_t *ppos)
@@ -436,7 +453,8 @@ static ssize_t iwl_dbgfs_log_event_write(struct file *file,
        if (sscanf(buf, "%d", &event_log_flag) != 1)
                return -EFAULT;
        if (event_log_flag == 1)
-               priv->cfg->ops->lib->dump_nic_event_log(priv, true);
+               priv->cfg->ops->lib->dump_nic_event_log(priv, true,
+                                                       NULL, false);
 
        return count;
 }
@@ -446,7 +464,7 @@ static ssize_t iwl_dbgfs_log_event_write(struct file *file,
 static ssize_t iwl_dbgfs_channels_read(struct file *file, char __user *user_buf,
                                       size_t count, loff_t *ppos)
 {
-       struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+       struct iwl_priv *priv = file->private_data;
        struct ieee80211_channel *channels = NULL;
        const struct ieee80211_supported_band *supp_band = NULL;
        int pos = 0, i, bufsz = PAGE_SIZE;
@@ -519,7 +537,7 @@ static ssize_t iwl_dbgfs_status_read(struct file *file,
                                                char __user *user_buf,
                                                size_t count, loff_t *ppos) {
 
-       struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+       struct iwl_priv *priv = file->private_data;
        char buf[512];
        int pos = 0;
        const size_t bufsz = sizeof(buf);
@@ -567,7 +585,7 @@ static ssize_t iwl_dbgfs_interrupt_read(struct file *file,
                                        char __user *user_buf,
                                        size_t count, loff_t *ppos) {
 
-       struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+       struct iwl_priv *priv = file->private_data;
        int pos = 0;
        int cnt = 0;
        char *buf;
@@ -654,7 +672,7 @@ static ssize_t iwl_dbgfs_interrupt_write(struct file *file,
 static ssize_t iwl_dbgfs_qos_read(struct file *file, char __user *user_buf,
                                       size_t count, loff_t *ppos)
 {
-       struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+       struct iwl_priv *priv = file->private_data;
        int pos = 0, i;
        char buf[256];
        const size_t bufsz = sizeof(buf);
@@ -677,7 +695,7 @@ static ssize_t iwl_dbgfs_qos_read(struct file *file, char __user *user_buf,
 static ssize_t iwl_dbgfs_led_read(struct file *file, char __user *user_buf,
                                  size_t count, loff_t *ppos)
 {
-       struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+       struct iwl_priv *priv = file->private_data;
        int pos = 0;
        char buf[256];
        const size_t bufsz = sizeof(buf);
@@ -703,7 +721,7 @@ static ssize_t iwl_dbgfs_thermal_throttling_read(struct file *file,
                                char __user *user_buf,
                                size_t count, loff_t *ppos)
 {
-       struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+       struct iwl_priv *priv = file->private_data;
        struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
        struct iwl_tt_restriction *restriction;
        char buf[100];
@@ -763,7 +781,7 @@ static ssize_t iwl_dbgfs_disable_ht40_read(struct file *file,
                                         char __user *user_buf,
                                         size_t count, loff_t *ppos)
 {
-       struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+       struct iwl_priv *priv = file->private_data;
        char buf[100];
        int pos = 0;
        const size_t bufsz = sizeof(buf);
@@ -820,7 +838,7 @@ static ssize_t iwl_dbgfs_sleep_level_override_read(struct file *file,
                                                   char __user *user_buf,
                                                   size_t count, loff_t *ppos)
 {
-       struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+       struct iwl_priv *priv = file->private_data;
        char buf[10];
        int pos, value;
        const size_t bufsz = sizeof(buf);
@@ -838,7 +856,7 @@ static ssize_t iwl_dbgfs_current_sleep_command_read(struct file *file,
                                                    char __user *user_buf,
                                                    size_t count, loff_t *ppos)
 {
-       struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+       struct iwl_priv *priv = file->private_data;
        char buf[200];
        int pos = 0, i;
        const size_t bufsz = sizeof(buf);
@@ -859,7 +877,7 @@ static ssize_t iwl_dbgfs_current_sleep_command_read(struct file *file,
 }
 
 DEBUGFS_READ_WRITE_FILE_OPS(sram);
-DEBUGFS_WRITE_FILE_OPS(log_event);
+DEBUGFS_READ_WRITE_FILE_OPS(log_event);
 DEBUGFS_READ_FILE_OPS(nvm);
 DEBUGFS_READ_FILE_OPS(stations);
 DEBUGFS_READ_FILE_OPS(channels);
@@ -976,7 +994,7 @@ static ssize_t iwl_dbgfs_tx_queue_read(struct file *file,
                                                char __user *user_buf,
                                                size_t count, loff_t *ppos) {
 
-       struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+       struct iwl_priv *priv = file->private_data;
        struct iwl_tx_queue *txq;
        struct iwl_queue *q;
        char *buf;
@@ -1022,7 +1040,7 @@ static ssize_t iwl_dbgfs_rx_queue_read(struct file *file,
                                                char __user *user_buf,
                                                size_t count, loff_t *ppos) {
 
-       struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+       struct iwl_priv *priv = file->private_data;
        struct iwl_rx_queue *rxq = &priv->rxq;
        char buf[256];
        int pos = 0;
@@ -1068,7 +1086,7 @@ static ssize_t iwl_dbgfs_ucode_rx_stats_read(struct file *file,
                                        char __user *user_buf,
                                        size_t count, loff_t *ppos)
 {
-       struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+       struct iwl_priv *priv = file->private_data;
        int pos = 0;
        char *buf;
        int bufsz = sizeof(struct statistics_rx_phy) * 20 +
@@ -1369,6 +1387,9 @@ static ssize_t iwl_dbgfs_ucode_rx_stats_read(struct file *file,
                         accum_ht->agg_mpdu_cnt);
        pos += scnprintf(buf + pos, bufsz - pos, "agg_cnt:\t\t%u\t\t\t%u\n",
                         le32_to_cpu(ht->agg_cnt), accum_ht->agg_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos, "unsupport_mcs:\t\t%u\t\t\t%u\n",
+                        le32_to_cpu(ht->unsupport_mcs),
+                        accum_ht->unsupport_mcs);
 
        ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
        kfree(buf);
@@ -1379,7 +1400,7 @@ static ssize_t iwl_dbgfs_ucode_tx_stats_read(struct file *file,
                                        char __user *user_buf,
                                        size_t count, loff_t *ppos)
 {
-       struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+       struct iwl_priv *priv = file->private_data;
        int pos = 0;
        char *buf;
        int bufsz = (sizeof(struct statistics_tx) * 24) + 250;
@@ -1521,7 +1542,7 @@ static ssize_t iwl_dbgfs_ucode_general_stats_read(struct file *file,
                                        char __user *user_buf,
                                        size_t count, loff_t *ppos)
 {
-       struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+       struct iwl_priv *priv = file->private_data;
        int pos = 0;
        char *buf;
        int bufsz = sizeof(struct statistics_general) * 4 + 250;
@@ -1612,7 +1633,7 @@ static ssize_t iwl_dbgfs_sensitivity_read(struct file *file,
                                        char __user *user_buf,
                                        size_t count, loff_t *ppos) {
 
-       struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+       struct iwl_priv *priv = file->private_data;
        int pos = 0;
        int cnt = 0;
        char *buf;
@@ -1693,7 +1714,7 @@ static ssize_t iwl_dbgfs_chain_noise_read(struct file *file,
                                        char __user *user_buf,
                                        size_t count, loff_t *ppos) {
 
-       struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+       struct iwl_priv *priv = file->private_data;
        int pos = 0;
        int cnt = 0;
        char *buf;
@@ -1751,7 +1772,7 @@ static ssize_t iwl_dbgfs_tx_power_read(struct file *file,
                                        char __user *user_buf,
                                        size_t count, loff_t *ppos) {
 
-       struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+       struct iwl_priv *priv = file->private_data;
        char buf[128];
        int pos = 0;
        ssize_t ret;
@@ -1802,7 +1823,7 @@ static ssize_t iwl_dbgfs_power_save_status_read(struct file *file,
                                                    char __user *user_buf,
                                                    size_t count, loff_t *ppos)
 {
-       struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+       struct iwl_priv *priv = file->private_data;
        char buf[60];
        int pos = 0;
        const size_t bufsz = sizeof(buf);
@@ -1845,6 +1866,80 @@ static ssize_t iwl_dbgfs_clear_ucode_statistics_write(struct file *file,
        return count;
 }
 
+static ssize_t iwl_dbgfs_csr_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 csr;
+
+       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", &csr) != 1)
+               return -EFAULT;
+
+       if (priv->cfg->ops->lib->dump_csr)
+               priv->cfg->ops->lib->dump_csr(priv);
+
+       return count;
+}
+
+static ssize_t iwl_dbgfs_ucode_tracing_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[128];
+       const size_t bufsz = sizeof(buf);
+       ssize_t ret;
+
+       pos += scnprintf(buf + pos, bufsz - pos, "ucode trace timer is %s\n",
+                       priv->event_log.ucode_trace ? "On" : "Off");
+       pos += scnprintf(buf + pos, bufsz - pos, "non_wraps_count:\t\t %u\n",
+                       priv->event_log.non_wraps_count);
+       pos += scnprintf(buf + pos, bufsz - pos, "wraps_once_count:\t\t %u\n",
+                       priv->event_log.wraps_once_count);
+       pos += scnprintf(buf + pos, bufsz - pos, "wraps_more_count:\t\t %u\n",
+                       priv->event_log.wraps_more_count);
+
+       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+       return ret;
+}
+
+static ssize_t iwl_dbgfs_ucode_tracing_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 trace;
+
+       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", &trace) != 1)
+               return -EFAULT;
+
+       if (trace) {
+               priv->event_log.ucode_trace = true;
+               /* schedule the ucode timer to occur in UCODE_TRACE_PERIOD */
+               mod_timer(&priv->ucode_trace,
+                       jiffies + msecs_to_jiffies(UCODE_TRACE_PERIOD));
+       } else {
+               priv->event_log.ucode_trace = false;
+               del_timer_sync(&priv->ucode_trace);
+       }
+
+       return count;
+}
+
 DEBUGFS_READ_FILE_OPS(rx_statistics);
 DEBUGFS_READ_FILE_OPS(tx_statistics);
 DEBUGFS_READ_WRITE_FILE_OPS(traffic_log);
@@ -1859,6 +1954,8 @@ DEBUGFS_READ_FILE_OPS(tx_power);
 DEBUGFS_READ_FILE_OPS(power_save_status);
 DEBUGFS_WRITE_FILE_OPS(clear_ucode_statistics);
 DEBUGFS_WRITE_FILE_OPS(clear_traffic_statistics);
+DEBUGFS_WRITE_FILE_OPS(csr);
+DEBUGFS_READ_WRITE_FILE_OPS(ucode_tracing);
 
 /*
  * Create the debugfs files and directories
@@ -1889,7 +1986,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
        DEBUGFS_ADD_DIR(debug, dbgfs->dir_drv);
        DEBUGFS_ADD_FILE(nvm, data, S_IRUSR);
        DEBUGFS_ADD_FILE(sram, data, S_IWUSR | S_IRUSR);
-       DEBUGFS_ADD_FILE(log_event, data, S_IWUSR);
+       DEBUGFS_ADD_FILE(log_event, data, S_IWUSR | S_IRUSR);
        DEBUGFS_ADD_FILE(stations, data, S_IRUSR);
        DEBUGFS_ADD_FILE(channels, data, S_IRUSR);
        DEBUGFS_ADD_FILE(status, data, S_IRUSR);
@@ -1909,12 +2006,14 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
        DEBUGFS_ADD_FILE(power_save_status, debug, S_IRUSR);
        DEBUGFS_ADD_FILE(clear_ucode_statistics, debug, S_IWUSR);
        DEBUGFS_ADD_FILE(clear_traffic_statistics, debug, S_IWUSR);
+       DEBUGFS_ADD_FILE(csr, debug, S_IWUSR);
        if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) {
                DEBUGFS_ADD_FILE(ucode_rx_stats, debug, S_IRUSR);
                DEBUGFS_ADD_FILE(ucode_tx_stats, debug, S_IRUSR);
                DEBUGFS_ADD_FILE(ucode_general_stats, debug, S_IRUSR);
                DEBUGFS_ADD_FILE(sensitivity, debug, S_IRUSR);
                DEBUGFS_ADD_FILE(chain_noise, debug, S_IRUSR);
+               DEBUGFS_ADD_FILE(ucode_tracing, debug, S_IWUSR | S_IRUSR);
        }
        DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal);
        DEBUGFS_ADD_BOOL(disable_chain_noise, rf,
@@ -1966,6 +2065,7 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv)
                        file_clear_ucode_statistics);
        DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.
                        file_clear_traffic_statistics);
+       DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_csr);
        if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) {
                DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.
                        file_ucode_rx_stats);
@@ -1977,6 +2077,8 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv)
                        file_sensitivity);
                DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.
                        file_chain_noise);
+               DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.
+                       file_ucode_tracing);
        }
        DEBUGFS_REMOVE(priv->dbgfs->dir_debug);
        DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_sensitivity);
index 3822cf53e36850003b1c636a20bbde21d2846e43..70f0e79c8e4a8226bd0e4b834af5c4a592db0789 100644 (file)
@@ -512,6 +512,7 @@ struct iwl_ht_config {
        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;
@@ -984,6 +985,32 @@ struct iwl_switch_rxon {
        __le16 channel;
 };
 
+/*
+ * schedule the timer to wake up every UCODE_TRACE_PERIOD milliseconds
+ * to perform continuous uCode event logging operation if enabled
+ */
+#define UCODE_TRACE_PERIOD (100)
+
+/*
+ * iwl_event_log: current uCode event log position
+ *
+ * @ucode_trace: enable/disable ucode continuous trace timer
+ * @num_wraps: how many times the event buffer wraps
+ * @next_entry:  the entry just before the next one that uCode would fill
+ * @non_wraps_count: counter for no wrap detected when dump ucode events
+ * @wraps_once_count: counter for wrap once detected when dump ucode events
+ * @wraps_more_count: counter for wrap more than once detected
+ *                   when dump ucode events
+ */
+struct iwl_event_log {
+       bool ucode_trace;
+       u32 num_wraps;
+       u32 next_entry;
+       int non_wraps_count;
+       int wraps_once_count;
+       int wraps_more_count;
+};
+
 struct iwl_priv {
 
        /* ieee device used by generic ieee processing code */
@@ -1261,6 +1288,7 @@ struct iwl_priv {
        u32 disable_tx_power_cal;
        struct work_struct run_time_calib_work;
        struct timer_list statistics_periodic;
+       struct timer_list ucode_trace;
        bool hw_ready;
        /*For 3945*/
 #define IWL_DEFAULT_TX_POWER 0x0F
@@ -1268,6 +1296,8 @@ struct iwl_priv {
        struct iwl3945_notif_statistics statistics_39;
 
        u32 sta_supp_rates;
+
+       struct iwl_event_log event_log;
 }; /*iwl_priv */
 
 static inline void iwl_txq_ctx_activate(struct iwl_priv *priv, int txq_id)
index 83cc4e500a96516ec3c0d4c3b65d60e54ca97a27..36580d8d8b8db4cbb6e5b38b2242d69ec8153045 100644 (file)
@@ -37,4 +37,6 @@ EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_iowrite32);
 EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_rx);
 EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_event);
 EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_error);
+EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_cont_event);
+EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_wrap_event);
 #endif
index d9c7363b1bbb0ec4d0f7e971c49eb7f625c40e5d..ff4d012ce2600dfbaf5ac7317138daa628e15880 100644 (file)
@@ -90,6 +90,50 @@ TRACE_EVENT(iwlwifi_dev_iowrite32,
        TP_printk("[%p] write io[%#x] = %#x)", __entry->priv, __entry->offs, __entry->val)
 );
 
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM iwlwifi_ucode
+
+TRACE_EVENT(iwlwifi_dev_ucode_cont_event,
+       TP_PROTO(struct iwl_priv *priv, u32 time, u32 data, u32 ev),
+       TP_ARGS(priv, time, data, ev),
+       TP_STRUCT__entry(
+               PRIV_ENTRY
+
+               __field(u32, time)
+               __field(u32, data)
+               __field(u32, ev)
+       ),
+       TP_fast_assign(
+               PRIV_ASSIGN;
+               __entry->time = time;
+               __entry->data = data;
+               __entry->ev = ev;
+       ),
+       TP_printk("[%p] EVT_LOGT:%010u:0x%08x:%04u",
+                 __entry->priv, __entry->time, __entry->data, __entry->ev)
+);
+
+TRACE_EVENT(iwlwifi_dev_ucode_wrap_event,
+       TP_PROTO(struct iwl_priv *priv, u32 wraps, u32 n_entry, u32 p_entry),
+       TP_ARGS(priv, wraps, n_entry, p_entry),
+       TP_STRUCT__entry(
+               PRIV_ENTRY
+
+               __field(u32, wraps)
+               __field(u32, n_entry)
+               __field(u32, p_entry)
+       ),
+       TP_fast_assign(
+               PRIV_ASSIGN;
+               __entry->wraps = wraps;
+               __entry->n_entry = n_entry;
+               __entry->p_entry = p_entry;
+       ),
+       TP_printk("[%p] wraps=#%02d n=0x%X p=0x%X",
+                 __entry->priv, __entry->wraps, __entry->n_entry,
+                 __entry->p_entry)
+);
+
 #undef TRACE_SYSTEM
 #define TRACE_SYSTEM iwlwifi
 
index 30e9ea6d54ecd8dc18f2fa4416cd581bfdaa67e8..87d684efe110efc24a121fe354abea6bb243420b 100644 (file)
@@ -58,7 +58,6 @@ const char *get_cmd_string(u8 cmd)
                IWL_CMD(COEX_PRIORITY_TABLE_CMD);
                IWL_CMD(COEX_MEDIUM_NOTIFICATION);
                IWL_CMD(COEX_EVENT_CMD);
-               IWL_CMD(RADAR_NOTIFICATION);
                IWL_CMD(REPLY_QUIET_CMD);
                IWL_CMD(REPLY_CHANNEL_SWITCH);
                IWL_CMD(CHANNEL_SWITCH_NOTIFICATION);
index f8e4e4b18d02bee66f711e29080c4cc2b8a6366a..10b0aa8024c435d017e0455265ea9e24663e71eb 100644 (file)
@@ -1518,8 +1518,9 @@ void iwl3945_dump_nic_error_log(struct iwl_priv *priv)
  * iwl3945_print_event_log - Dump error event log to syslog
  *
  */
-static void iwl3945_print_event_log(struct iwl_priv *priv, u32 start_idx,
-                               u32 num_events, u32 mode)
+static int iwl3945_print_event_log(struct iwl_priv *priv, u32 start_idx,
+                                 u32 num_events, u32 mode,
+                                 int pos, char **buf, size_t bufsz)
 {
        u32 i;
        u32 base;       /* SRAM byte address of event log header */
@@ -1529,7 +1530,7 @@ static void iwl3945_print_event_log(struct iwl_priv *priv, u32 start_idx,
        unsigned long reg_flags;
 
        if (num_events == 0)
-               return;
+               return pos;
 
        base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
 
@@ -1555,26 +1556,43 @@ static void iwl3945_print_event_log(struct iwl_priv *priv, u32 start_idx,
                time = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
                if (mode == 0) {
                        /* data, ev */
-                       IWL_ERR(priv, "0x%08x\t%04u\n", time, ev);
-                       trace_iwlwifi_dev_ucode_event(priv, 0, time, ev);
+                       if (bufsz) {
+                               pos += scnprintf(*buf + pos, bufsz - pos,
+                                               "0x%08x:%04u\n",
+                                               time, ev);
+                       } else {
+                               IWL_ERR(priv, "0x%08x\t%04u\n", time, ev);
+                               trace_iwlwifi_dev_ucode_event(priv, 0,
+                                                             time, ev);
+                       }
                } else {
                        data = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
-                       IWL_ERR(priv, "%010u\t0x%08x\t%04u\n", time, data, ev);
-                       trace_iwlwifi_dev_ucode_event(priv, time, data, ev);
+                       if (bufsz) {
+                               pos += scnprintf(*buf + pos, bufsz - pos,
+                                               "%010u:0x%08x:%04u\n",
+                                                time, data, ev);
+                       } else {
+                               IWL_ERR(priv, "%010u\t0x%08x\t%04u\n",
+                                       time, data, ev);
+                               trace_iwlwifi_dev_ucode_event(priv, time,
+                                                             data, ev);
+                       }
                }
        }
 
        /* Allow device to power down */
        iwl_release_nic_access(priv);
        spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
+       return pos;
 }
 
 /**
  * iwl3945_print_last_event_logs - Dump the newest # of event log to syslog
  */
-static void iwl3945_print_last_event_logs(struct iwl_priv *priv, u32 capacity,
+static int iwl3945_print_last_event_logs(struct iwl_priv *priv, u32 capacity,
                                      u32 num_wraps, u32 next_entry,
-                                     u32 size, u32 mode)
+                                     u32 size, u32 mode,
+                                     int pos, char **buf, size_t bufsz)
 {
        /*
         * display the newest DEFAULT_LOG_ENTRIES entries
@@ -1582,21 +1600,28 @@ static void iwl3945_print_last_event_logs(struct iwl_priv *priv, u32 capacity,
         */
        if (num_wraps) {
                if (next_entry < size) {
-                       iwl3945_print_event_log(priv,
-                                       capacity - (size - next_entry),
-                                       size - next_entry, mode);
-                       iwl3945_print_event_log(priv, 0,
-                                   next_entry, mode);
+                       pos = iwl3945_print_event_log(priv,
+                                            capacity - (size - next_entry),
+                                            size - next_entry, mode,
+                                            pos, buf, bufsz);
+                       pos = iwl3945_print_event_log(priv, 0,
+                                                     next_entry, mode,
+                                                     pos, buf, bufsz);
                } else
-                       iwl3945_print_event_log(priv, next_entry - size,
-                                   size, mode);
+                       pos = iwl3945_print_event_log(priv, next_entry - size,
+                                                     size, mode,
+                                                     pos, buf, bufsz);
        } else {
                if (next_entry < size)
-                       iwl3945_print_event_log(priv, 0, next_entry, mode);
+                       pos = iwl3945_print_event_log(priv, 0,
+                                                     next_entry, mode,
+                                                     pos, buf, bufsz);
                else
-                       iwl3945_print_event_log(priv, next_entry - size,
-                                           size, mode);
+                       pos = iwl3945_print_event_log(priv, next_entry - size,
+                                                     size, mode,
+                                                     pos, buf, bufsz);
        }
+       return pos;
 }
 
 /* For sanity check only.  Actual size is determined by uCode, typ. 512 */
@@ -1604,7 +1629,8 @@ static void iwl3945_print_last_event_logs(struct iwl_priv *priv, u32 capacity,
 
 #define DEFAULT_IWL3945_DUMP_EVENT_LOG_ENTRIES (20)
 
-void iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log)
+int iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
+                           char **buf, bool display)
 {
        u32 base;       /* SRAM byte address of event log header */
        u32 capacity;   /* event log capacity in # entries */
@@ -1612,11 +1638,13 @@ void iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log)
        u32 num_wraps;  /* # times uCode wrapped to top of log */
        u32 next_entry; /* index of next entry to be written by uCode */
        u32 size;       /* # entries that we'll print */
+       int pos = 0;
+       size_t bufsz = 0;
 
        base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
        if (!iwl3945_hw_valid_rtc_data_addr(base)) {
                IWL_ERR(priv, "Invalid event log pointer 0x%08X\n", base);
-               return;
+               return pos;
        }
 
        /* event log header */
@@ -1642,7 +1670,7 @@ void iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log)
        /* bail out if nothing in log */
        if (size == 0) {
                IWL_ERR(priv, "Start IWL Event Log Dump: nothing in log\n");
-               return;
+               return pos;
        }
 
 #ifdef CONFIG_IWLWIFI_DEBUG
@@ -1658,25 +1686,38 @@ void iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log)
                  size);
 
 #ifdef CONFIG_IWLWIFI_DEBUG
+       if (display) {
+               if (full_log)
+                       bufsz = capacity * 48;
+               else
+                       bufsz = size * 48;
+               *buf = kmalloc(bufsz, GFP_KERNEL);
+               if (!*buf)
+                       return pos;
+       }
        if ((iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS) || full_log) {
                /* if uCode has wrapped back to top of log,
                 * start at the oldest entry,
                 * i.e the next one that uCode would fill.
                 */
                if (num_wraps)
-                       iwl3945_print_event_log(priv, next_entry,
-                                   capacity - next_entry, mode);
+                       pos = iwl3945_print_event_log(priv, next_entry,
+                                               capacity - next_entry, mode,
+                                               pos, buf, bufsz);
 
                /* (then/else) start at top of log */
-               iwl3945_print_event_log(priv, 0, next_entry, mode);
+               pos = iwl3945_print_event_log(priv, 0, next_entry, mode,
+                                             pos, buf, bufsz);
        } else
-               iwl3945_print_last_event_logs(priv, capacity, num_wraps,
-                                       next_entry, size, mode);
+               pos = iwl3945_print_last_event_logs(priv, capacity, num_wraps,
+                                                   next_entry, size, mode,
+                                                   pos, buf, bufsz);
 #else
-       iwl3945_print_last_event_logs(priv, capacity, num_wraps,
-                               next_entry, size, mode);
+       pos = iwl3945_print_last_event_logs(priv, capacity, num_wraps,
+                                           next_entry, size, mode,
+                                           pos, buf, bufsz);
 #endif
-
+       return pos;
 }
 
 static void iwl3945_irq_tasklet(struct iwl_priv *priv)
index 842811142bef0c951eea272e93ac674fe21c76ae..79ffa3b98d73c687c968e2b815272a1843f6e0ba 100644 (file)
@@ -268,7 +268,7 @@ struct iwm_priv {
 
        struct sk_buff_head rx_list;
        struct list_head rx_tickets;
-       struct list_head rx_packets[IWM_RX_ID_HASH + 1];
+       struct list_head rx_packets[IWM_RX_ID_HASH];
        struct workqueue_struct *rx_wq;
        struct work_struct rx_worker;
 
index 6d6ed7485175a6f2d8f8d05793767e08c6f91c69..d32adeab68a38e98065d9338e0eb8bb38b0faefe 100644 (file)
@@ -868,36 +868,35 @@ static int iwm_mlme_mgt_frame(struct iwm_priv *iwm, u8 *buf,
        struct iwm_umac_notif_mgt_frame *mgt_frame =
                        (struct iwm_umac_notif_mgt_frame *)buf;
        struct ieee80211_mgmt *mgt = (struct ieee80211_mgmt *)mgt_frame->frame;
-       u8 *ie;
 
        IWM_HEXDUMP(iwm, DBG, MLME, "MGT: ", mgt_frame->frame,
                    le16_to_cpu(mgt_frame->len));
 
        if (ieee80211_is_assoc_req(mgt->frame_control)) {
-               ie = mgt->u.assoc_req.variable;;
-               iwm->req_ie_len =
-                               le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt);
+               iwm->req_ie_len = le16_to_cpu(mgt_frame->len)
+                                 - offsetof(struct ieee80211_mgmt,
+                                            u.assoc_req.variable);
                kfree(iwm->req_ie);
                iwm->req_ie = kmemdup(mgt->u.assoc_req.variable,
                                      iwm->req_ie_len, GFP_KERNEL);
        } else if (ieee80211_is_reassoc_req(mgt->frame_control)) {
-               ie = mgt->u.reassoc_req.variable;;
-               iwm->req_ie_len =
-                               le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt);
+               iwm->req_ie_len = le16_to_cpu(mgt_frame->len)
+                                 - offsetof(struct ieee80211_mgmt,
+                                            u.reassoc_req.variable);
                kfree(iwm->req_ie);
                iwm->req_ie = kmemdup(mgt->u.reassoc_req.variable,
                                      iwm->req_ie_len, GFP_KERNEL);
        } else if (ieee80211_is_assoc_resp(mgt->frame_control)) {
-               ie = mgt->u.assoc_resp.variable;;
-               iwm->resp_ie_len =
-                               le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt);
+               iwm->resp_ie_len = le16_to_cpu(mgt_frame->len)
+                                  - offsetof(struct ieee80211_mgmt,
+                                             u.assoc_resp.variable);
                kfree(iwm->resp_ie);
                iwm->resp_ie = kmemdup(mgt->u.assoc_resp.variable,
                                       iwm->resp_ie_len, GFP_KERNEL);
        } else if (ieee80211_is_reassoc_resp(mgt->frame_control)) {
-               ie = mgt->u.reassoc_resp.variable;;
-               iwm->resp_ie_len =
-                               le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt);
+               iwm->resp_ie_len = le16_to_cpu(mgt_frame->len)
+                                  - offsetof(struct ieee80211_mgmt,
+                                             u.reassoc_resp.variable);
                kfree(iwm->resp_ie);
                iwm->resp_ie = kmemdup(mgt->u.reassoc_resp.variable,
                                       iwm->resp_ie_len, GFP_KERNEL);
@@ -1534,6 +1533,33 @@ static void classify8023(struct sk_buff *skb)
        }
 }
 
+static void iwm_rx_process_amsdu(struct iwm_priv *iwm, struct sk_buff *skb)
+{
+       struct wireless_dev *wdev = iwm_to_wdev(iwm);
+       struct net_device *ndev = iwm_to_ndev(iwm);
+       struct sk_buff_head list;
+       struct sk_buff *frame;
+
+       IWM_HEXDUMP(iwm, DBG, RX, "A-MSDU: ", skb->data, skb->len);
+
+       __skb_queue_head_init(&list);
+       ieee80211_amsdu_to_8023s(skb, &list, ndev->dev_addr, wdev->iftype, 0);
+
+       while ((frame = __skb_dequeue(&list))) {
+               ndev->stats.rx_packets++;
+               ndev->stats.rx_bytes += frame->len;
+
+               frame->protocol = eth_type_trans(frame, ndev);
+               frame->ip_summed = CHECKSUM_NONE;
+               memset(frame->cb, 0, sizeof(frame->cb));
+
+               if (netif_rx_ni(frame) == NET_RX_DROP) {
+                       IWM_ERR(iwm, "Packet dropped\n");
+                       ndev->stats.rx_dropped++;
+               }
+       }
+}
+
 static void iwm_rx_process_packet(struct iwm_priv *iwm,
                                  struct iwm_rx_packet *packet,
                                  struct iwm_rx_ticket_node *ticket_node)
@@ -1548,25 +1574,34 @@ static void iwm_rx_process_packet(struct iwm_priv *iwm,
        switch (le16_to_cpu(ticket_node->ticket->action)) {
        case IWM_RX_TICKET_RELEASE:
                IWM_DBG_RX(iwm, DBG, "RELEASE packet\n");
-               classify8023(skb);
+
                iwm_rx_adjust_packet(iwm, packet, ticket_node);
+               skb->dev = iwm_to_ndev(iwm);
+               classify8023(skb);
+
+               if (le16_to_cpu(ticket_node->ticket->flags) &
+                   IWM_RX_TICKET_AMSDU_MSK) {
+                       iwm_rx_process_amsdu(iwm, skb);
+                       break;
+               }
+
                ret = ieee80211_data_to_8023(skb, ndev->dev_addr, wdev->iftype);
                if (ret < 0) {
                        IWM_DBG_RX(iwm, DBG, "Couldn't convert 802.11 header - "
                                   "%d\n", ret);
+                       kfree_skb(packet->skb);
                        break;
                }
 
                IWM_HEXDUMP(iwm, DBG, RX, "802.3: ", skb->data, skb->len);
 
-               skb->dev = iwm_to_ndev(iwm);
+               ndev->stats.rx_packets++;
+               ndev->stats.rx_bytes += skb->len;
+
                skb->protocol = eth_type_trans(skb, ndev);
                skb->ip_summed = CHECKSUM_NONE;
                memset(skb->cb, 0, sizeof(skb->cb));
 
-               ndev->stats.rx_packets++;
-               ndev->stats.rx_bytes += skb->len;
-
                if (netif_rx_ni(skb) == NET_RX_DROP) {
                        IWM_ERR(iwm, "Packet dropped\n");
                        ndev->stats.rx_dropped++;
index 30aa9d48d67e03ffad9c904f143ed6ff0c3ba355..0485c99575757841edb0f929205d4963c6d082a2 100644 (file)
@@ -37,3 +37,9 @@ config LIBERTAS_DEBUG
        depends on LIBERTAS
        ---help---
          Debugging support.
+
+config LIBERTAS_MESH
+       bool "Enable mesh support"
+       depends on LIBERTAS
+       help
+         This enables Libertas' MESH support, used by e.g. the OLPC people.
index b188cd97a053f8d9459eaf6db9038eb0057a7dbf..45e870e331175f30d47edc2ed85091bce1a924ed 100644 (file)
@@ -5,11 +5,11 @@ libertas-y += cmdresp.o
 libertas-y += debugfs.o
 libertas-y += ethtool.o
 libertas-y += main.o
-libertas-y += mesh.o
 libertas-y += rx.o
 libertas-y += scan.o
 libertas-y += tx.o
 libertas-y += wext.o
+libertas-$(CONFIG_LIBERTAS_MESH) += mesh.o
 
 usb8xxx-objs += if_usb.o
 libertas_cs-objs += if_cs.o
index 751067369ba84ec8506bbe7b087f3691ab3fd0cc..5e650f35841545313d160baf4e658d48bb83d2a8 100644 (file)
@@ -390,10 +390,8 @@ int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv,
        cmd.enablehwauto = cpu_to_le16(priv->enablehwauto);
        cmd.bitmap = lbs_rate_to_fw_bitmap(priv->cur_rate, priv->enablehwauto);
        ret = lbs_cmd_with_response(priv, CMD_802_11_RATE_ADAPT_RATESET, &cmd);
-       if (!ret && cmd_action == CMD_ACT_GET) {
-               priv->ratebitmap = le16_to_cpu(cmd.bitmap);
+       if (!ret && cmd_action == CMD_ACT_GET)
                priv->enablehwauto = le16_to_cpu(cmd.enablehwauto);
-       }
 
        lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
        return ret;
@@ -807,8 +805,7 @@ static int lbs_try_associate(struct lbs_private *priv,
        }
 
        /* Use short preamble only when both the BSS and firmware support it */
-       if ((priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) &&
-           (assoc_req->bss.capability & WLAN_CAPABILITY_SHORT_PREAMBLE))
+       if (assoc_req->bss.capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
                preamble = RADIO_PREAMBLE_SHORT;
 
        ret = lbs_set_radio(priv, preamble, 1);
@@ -939,8 +936,7 @@ static int lbs_adhoc_join(struct lbs_private *priv,
        }
 
        /* Use short preamble only when both the BSS and firmware support it */
-       if ((priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) &&
-           (bss->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)) {
+       if (bss->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) {
                lbs_deb_join("AdhocJoin: Short preamble\n");
                preamble = RADIO_PREAMBLE_SHORT;
        }
@@ -1049,7 +1045,7 @@ static int lbs_adhoc_start(struct lbs_private *priv,
        struct assoc_request *assoc_req)
 {
        struct cmd_ds_802_11_ad_hoc_start cmd;
-       u8 preamble = RADIO_PREAMBLE_LONG;
+       u8 preamble = RADIO_PREAMBLE_SHORT;
        size_t ratesize = 0;
        u16 tmpcap = 0;
        int ret = 0;
@@ -1057,11 +1053,6 @@ static int lbs_adhoc_start(struct lbs_private *priv,
 
        lbs_deb_enter(LBS_DEB_ASSOC);
 
-       if (priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) {
-               lbs_deb_join("ADHOC_START: Will use short preamble\n");
-               preamble = RADIO_PREAMBLE_SHORT;
-       }
-
        ret = lbs_set_radio(priv, preamble, 1);
        if (ret)
                goto out;
index 42611bea76a3e4805399294123c23837630e74b4..82371ef395241901d175ea73ed6dddfa755d5ff6 100644 (file)
@@ -143,19 +143,6 @@ int lbs_update_hw_spec(struct lbs_private *priv)
        lbs_deb_cmd("GET_HW_SPEC: hardware interface 0x%x, hardware spec 0x%04x\n",
                    cmd.hwifversion, cmd.version);
 
-       /* Determine mesh_fw_ver from fwrelease and fwcapinfo */
-       /* 5.0.16p0 9.0.0.p0 is known to NOT support any mesh */
-       /* 5.110.22 have mesh command with 0xa3 command id */
-       /* 10.0.0.p0 FW brings in mesh config command with different id */
-       /* Check FW version MSB and initialize mesh_fw_ver */
-       if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V5)
-               priv->mesh_fw_ver = MESH_FW_OLD;
-       else if ((MRVL_FW_MAJOR_REV(priv->fwrelease) >= MRVL_FW_V10) &&
-               (priv->fwcapinfo & MESH_CAPINFO_ENABLE_MASK))
-               priv->mesh_fw_ver = MESH_FW_NEW;
-       else
-               priv->mesh_fw_ver = MESH_NONE;
-
        /* Clamp region code to 8-bit since FW spec indicates that it should
         * only ever be 8-bit, even though the field size is 16-bit.  Some firmware
         * returns non-zero high 8 bits here.
@@ -855,9 +842,6 @@ int lbs_set_radio(struct lbs_private *priv, u8 preamble, u8 radio_on)
        if (priv->fwrelease < 0x09000000) {
                switch (preamble) {
                case RADIO_PREAMBLE_SHORT:
-                       if (!(priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE))
-                               goto out;
-                       /* Fall through */
                case RADIO_PREAMBLE_AUTO:
                case RADIO_PREAMBLE_LONG:
                        cmd.control = cpu_to_le16(preamble);
@@ -1011,6 +995,8 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
                ret = 0;
                break;
 
+#ifdef CONFIG_LIBERTAS_MESH
+
        case CMD_BT_ACCESS:
                ret = lbs_cmd_bt_access(cmdptr, cmd_action, pdata_buf);
                break;
@@ -1019,6 +1005,8 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
                ret = lbs_cmd_fwt_access(cmdptr, cmd_action, pdata_buf);
                break;
 
+#endif
+
        case CMD_802_11_BEACON_CTRL:
                ret = lbs_cmd_bcn_ctrl(priv, cmdptr, cmd_action);
                break;
@@ -1317,7 +1305,7 @@ int lbs_execute_next_command(struct lbs_private *priv)
                if ((priv->psmode != LBS802_11POWERMODECAM) &&
                    (priv->psstate == PS_STATE_FULL_POWER) &&
                    ((priv->connect_status == LBS_CONNECTED) ||
-                   (priv->mesh_connect_status == LBS_CONNECTED))) {
+                   lbs_mesh_connected(priv))) {
                        if (priv->secinfo.WPAenabled ||
                            priv->secinfo.WPA2enabled) {
                                /* check for valid WPA group keys */
index 2862748aef70778f11cc40335827bda66dad0161..cb4138a55fdf9057fe13a0b8e1ced435cf0f0572 100644 (file)
@@ -110,18 +110,6 @@ int lbs_set_snmp_mib(struct lbs_private *priv, u32 oid, u16 val);
 int lbs_get_snmp_mib(struct lbs_private *priv, u32 oid, u16 *out_val);
 
 
-/* Mesh related */
-
-int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action,
-                   struct cmd_ds_mesh_access *cmd);
-
-int lbs_mesh_config_send(struct lbs_private *priv,
-                        struct cmd_ds_mesh_config *cmd,
-                        uint16_t action, uint16_t type);
-
-int lbs_mesh_config(struct lbs_private *priv, uint16_t enable, uint16_t chan);
-
-
 /* Commands only used in wext.c, assoc. and scan.c */
 
 int lbs_set_power_adapt_cfg(struct lbs_private *priv, int enable, int8_t p0,
index 21d57690c20a0cb5d213a14447568d6fa1113fbc..0334a58820eed220d2000fc25fcf64ba7e0deeb8 100644 (file)
@@ -485,20 +485,8 @@ int lbs_process_event(struct lbs_private *priv, u32 event)
                break;
 
        case MACREG_INT_CODE_MESH_AUTO_STARTED:
-               /* Ignore spurious autostart events if autostart is disabled */
-               if (!priv->mesh_autostart_enabled) {
-                       lbs_pr_info("EVENT: MESH_AUTO_STARTED (ignoring)\n");
-                       break;
-               }
-               lbs_pr_info("EVENT: MESH_AUTO_STARTED\n");
-               priv->mesh_connect_status = LBS_CONNECTED;
-               if (priv->mesh_open) {
-                       netif_carrier_on(priv->mesh_dev);
-                       if (!priv->tx_pending_len)
-                               netif_wake_queue(priv->mesh_dev);
-               }
-               priv->mode = IW_MODE_ADHOC;
-               schedule_work(&priv->sync_channel);
+               /* Ignore spurious autostart events */
+               lbs_pr_info("EVENT: MESH_AUTO_STARTED (ignoring)\n");
                break;
 
        default:
index 6b6ea9f7bf5b37de87186a9db1248ab49b28c165..ea3f10ef4e0032c845a15cf973b1c9ffe925b504 100644 (file)
@@ -397,13 +397,6 @@ enum KEY_INFO_WPA {
        KEY_INFO_WPA_ENABLED = 0x04
 };
 
-/** mesh_fw_ver */
-enum _mesh_fw_ver {
-       MESH_NONE = 0, /* MESH is not supported */
-       MESH_FW_OLD,   /* MESH is supported in FW V5 */
-       MESH_FW_NEW,   /* MESH is supported in FW V10 and newer */
-};
-
 /* Default values for fwt commands. */
 #define FWT_DEFAULT_METRIC 0
 #define FWT_DEFAULT_DIR 1
index 05bb298dfae9a017be7458c8055d961e289e5de6..c348aff8f3092761bfea9a5e190325d651d6999f 100644 (file)
@@ -39,15 +39,14 @@ struct lbs_private {
 
        /* Mesh */
        struct net_device *mesh_dev; /* Virtual device */
+#ifdef CONFIG_LIBERTAS_MESH
        u32 mesh_connect_status;
        struct lbs_mesh_stats mstats;
        int mesh_open;
-       int mesh_fw_ver;
-       int mesh_autostart_enabled;
        uint16_t mesh_tlv;
        u8 mesh_ssid[IEEE80211_MAX_SSID_LEN + 1];
        u8 mesh_ssid_len;
-       struct work_struct sync_channel;
+#endif
 
        /* Monitor mode */
        struct net_device *rtap_net_dev;
@@ -176,9 +175,7 @@ struct lbs_private {
        struct bss_descriptor *networks;
        struct assoc_request * pending_assoc_req;
        struct assoc_request * in_progress_assoc_req;
-       u16 capability;
        uint16_t enablehwauto;
-       uint16_t ratebitmap;
 
        /* ADHOC */
        u16 beacon_period;
index 63d020374c2bda16b4176c7e5996628de2e7fedc..3804a58d7f4e8903cb8788457c8b99f8bd469419 100644 (file)
@@ -114,9 +114,11 @@ const struct ethtool_ops lbs_ethtool_ops = {
        .get_drvinfo = lbs_ethtool_get_drvinfo,
        .get_eeprom =  lbs_ethtool_get_eeprom,
        .get_eeprom_len = lbs_ethtool_get_eeprom_len,
+#ifdef CONFIG_LIBERTAS_MESH
        .get_sset_count = lbs_mesh_ethtool_get_sset_count,
        .get_ethtool_stats = lbs_mesh_ethtool_get_stats,
        .get_strings = lbs_mesh_ethtool_get_strings,
+#endif
        .get_wol = lbs_ethtool_get_wol,
        .set_wol = lbs_ethtool_set_wol,
 };
index c2975c8e2f211ff2f9cb64ac61db3e26f7d93862..60bde1233a302684c31f555d155ce46c31cf9d4f 100644 (file)
@@ -123,7 +123,7 @@ static ssize_t lbs_rtap_set(struct device *dev,
                if (priv->monitormode == monitor_mode)
                        return strlen(buf);
                if (!priv->monitormode) {
-                       if (priv->infra_open || priv->mesh_open)
+                       if (priv->infra_open || lbs_mesh_open(priv))
                                return -EBUSY;
                        if (priv->mode == IW_MODE_INFRA)
                                lbs_cmd_80211_deauthenticate(priv,
@@ -622,7 +622,7 @@ static int lbs_thread(void *data)
                                if (priv->connect_status == LBS_CONNECTED)
                                        netif_wake_queue(priv->dev);
                                if (priv->mesh_dev &&
-                                   priv->mesh_connect_status == LBS_CONNECTED)
+                                   lbs_mesh_connected(priv))
                                        netif_wake_queue(priv->mesh_dev);
                        }
                }
@@ -809,18 +809,6 @@ int lbs_exit_auto_deep_sleep(struct lbs_private *priv)
        return 0;
 }
 
-static void lbs_sync_channel_worker(struct work_struct *work)
-{
-       struct lbs_private *priv = container_of(work, struct lbs_private,
-               sync_channel);
-
-       lbs_deb_enter(LBS_DEB_MAIN);
-       if (lbs_update_channel(priv))
-               lbs_pr_info("Channel synchronization failed.");
-       lbs_deb_leave(LBS_DEB_MAIN);
-}
-
-
 static int lbs_init_adapter(struct lbs_private *priv)
 {
        size_t bufsize;
@@ -848,14 +836,12 @@ static int lbs_init_adapter(struct lbs_private *priv)
        memset(priv->current_addr, 0xff, ETH_ALEN);
 
        priv->connect_status = LBS_DISCONNECTED;
-       priv->mesh_connect_status = LBS_DISCONNECTED;
        priv->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
        priv->mode = IW_MODE_INFRA;
        priv->channel = DEFAULT_AD_HOC_CHANNEL;
        priv->mac_control = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON;
        priv->radio_on = 1;
        priv->enablehwauto = 1;
-       priv->capability = WLAN_CAPABILITY_SHORT_PREAMBLE;
        priv->psmode = LBS802_11POWERMODECAM;
        priv->psstate = PS_STATE_FULL_POWER;
        priv->is_deep_sleep = 0;
@@ -998,11 +984,6 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
        INIT_DELAYED_WORK(&priv->assoc_work, lbs_association_worker);
        INIT_DELAYED_WORK(&priv->scan_work, lbs_scan_worker);
        INIT_WORK(&priv->mcast_work, lbs_set_mcast_worker);
-       INIT_WORK(&priv->sync_channel, lbs_sync_channel_worker);
-
-       priv->mesh_open = 0;
-       sprintf(priv->mesh_ssid, "mesh");
-       priv->mesh_ssid_len = 4;
 
        priv->wol_criteria = 0xffffffff;
        priv->wol_gpio = 0xff;
@@ -1076,6 +1057,17 @@ void lbs_remove_card(struct lbs_private *priv)
 EXPORT_SYMBOL_GPL(lbs_remove_card);
 
 
+static int lbs_rtap_supported(struct lbs_private *priv)
+{
+       if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V5)
+               return 1;
+
+       /* newer firmware use a capability mask */
+       return ((MRVL_FW_MAJOR_REV(priv->fwrelease) >= MRVL_FW_V10) &&
+               (priv->fwcapinfo & MESH_CAPINFO_ENABLE_MASK));
+}
+
+
 int lbs_start_card(struct lbs_private *priv)
 {
        struct net_device *dev = priv->dev;
@@ -1095,12 +1087,14 @@ int lbs_start_card(struct lbs_private *priv)
 
        lbs_update_channel(priv);
 
+       lbs_init_mesh(priv);
+
        /*
         * While rtap isn't related to mesh, only mesh-enabled
         * firmware implements the rtap functionality via
         * CMD_802_11_MONITOR_MODE.
         */
-       if (lbs_init_mesh(priv)) {
+       if (lbs_rtap_supported(priv)) {
                if (device_create_file(&dev->dev, &dev_attr_lbs_rtap))
                        lbs_pr_err("cannot register lbs_rtap attribute\n");
        }
@@ -1134,7 +1128,9 @@ void lbs_stop_card(struct lbs_private *priv)
        netif_carrier_off(dev);
 
        lbs_debugfs_remove_one(priv);
-       if (lbs_deinit_mesh(priv))
+       lbs_deinit_mesh(priv);
+
+       if (lbs_rtap_supported(priv))
                device_remove_file(&dev->dev, &dev_attr_lbs_rtap);
 
        /* Delete the timeout of the currently processing command */
index 92b7a357a5e491d538477140d3f4f9855da99394..e385af1f458351faa38601318c7880c508f181f6 100644 (file)
@@ -1,4 +1,3 @@
-#include <linux/moduleparam.h>
 #include <linux/delay.h>
 #include <linux/etherdevice.h>
 #include <linux/netdevice.h>
@@ -197,7 +196,14 @@ int lbs_init_mesh(struct lbs_private *priv)
 
        lbs_deb_enter(LBS_DEB_MESH);
 
-       if (priv->mesh_fw_ver == MESH_FW_OLD) {
+       priv->mesh_connect_status = LBS_DISCONNECTED;
+
+       /* Determine mesh_fw_ver from fwrelease and fwcapinfo */
+       /* 5.0.16p0 9.0.0.p0 is known to NOT support any mesh */
+       /* 5.110.22 have mesh command with 0xa3 command id */
+       /* 10.0.0.p0 FW brings in mesh config command with different id */
+       /* Check FW version MSB and initialize mesh_fw_ver */
+       if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V5) {
                /* Enable mesh, if supported, and work out which TLV it uses.
                   0x100 + 291 is an unofficial value used in 5.110.20.pXX
                   0x100 + 37 is the official value used in 5.110.21.pXX
@@ -219,7 +225,9 @@ int lbs_init_mesh(struct lbs_private *priv)
                                            priv->channel))
                                priv->mesh_tlv = 0;
                }
-       } else if (priv->mesh_fw_ver == MESH_FW_NEW) {
+       } else
+       if ((MRVL_FW_MAJOR_REV(priv->fwrelease) >= MRVL_FW_V10) &&
+               (priv->fwcapinfo & MESH_CAPINFO_ENABLE_MASK)) {
                /* 10.0.0.pXX new firmwares should succeed with TLV
                 * 0x100+37; Do not invoke command with old TLV.
                 */
@@ -228,7 +236,12 @@ int lbs_init_mesh(struct lbs_private *priv)
                                    priv->channel))
                        priv->mesh_tlv = 0;
        }
+
+
        if (priv->mesh_tlv) {
+               sprintf(priv->mesh_ssid, "mesh");
+               priv->mesh_ssid_len = 4;
+
                lbs_add_mesh(priv);
 
                if (device_create_file(&dev->dev, &dev_attr_lbs_mesh))
@@ -416,10 +429,10 @@ struct net_device *lbs_mesh_set_dev(struct lbs_private *priv,
        struct net_device *dev, struct rxpd *rxpd)
 {
        if (priv->mesh_dev) {
-               if (priv->mesh_fw_ver == MESH_FW_OLD) {
+               if (priv->mesh_tlv == TLV_TYPE_OLD_MESH_ID) {
                        if (rxpd->rx_control & RxPD_MESH_FRAME)
                                dev = priv->mesh_dev;
-               } else if (priv->mesh_fw_ver == MESH_FW_NEW) {
+               } else if (priv->mesh_tlv == TLV_TYPE_MESH_ID) {
                        if (rxpd->u.bss.bss_num == MESH_IFACE_ID)
                                dev = priv->mesh_dev;
                }
@@ -432,9 +445,9 @@ void lbs_mesh_set_txpd(struct lbs_private *priv,
        struct net_device *dev, struct txpd *txpd)
 {
        if (dev == priv->mesh_dev) {
-               if (priv->mesh_fw_ver == MESH_FW_OLD)
+               if (priv->mesh_tlv == TLV_TYPE_OLD_MESH_ID)
                        txpd->tx_control |= cpu_to_le32(TxPD_MESH_FRAME);
-               else if (priv->mesh_fw_ver == MESH_FW_NEW)
+               else if (priv->mesh_tlv == TLV_TYPE_MESH_ID)
                        txpd->u.bss.bss_num = MESH_IFACE_ID;
        }
 }
@@ -538,7 +551,7 @@ static int __lbs_mesh_config_send(struct lbs_private *priv,
         * Command id is 0xac for v10 FW along with mesh interface
         * id in bits 14-13-12.
         */
-       if (priv->mesh_fw_ver == MESH_FW_NEW)
+       if (priv->mesh_tlv == TLV_TYPE_MESH_ID)
                command = CMD_MESH_CONFIG |
                          (MESH_IFACE_ID << MESH_IFACE_BIT_OFFSET);
 
index fea9b5d005fcb2bfe218b676c5f3eacd0f89d3a9..e2573303a328f63ac2e28f23f64739c0759d1017 100644 (file)
@@ -9,6 +9,8 @@
 #include <net/lib80211.h>
 
 
+#ifdef CONFIG_LIBERTAS_MESH
+
 /* Mesh statistics */
 struct lbs_mesh_stats {
        u32     fwd_bcast_cnt;          /* Fwd: Broadcast counter */
@@ -46,11 +48,20 @@ void lbs_mesh_set_txpd(struct lbs_private *priv,
 /* Command handling */
 
 struct cmd_ds_command;
+struct cmd_ds_mesh_access;
+struct cmd_ds_mesh_config;
 
 int lbs_cmd_bt_access(struct cmd_ds_command *cmd,
        u16 cmd_action, void *pdata_buf);
 int lbs_cmd_fwt_access(struct cmd_ds_command *cmd,
        u16 cmd_action, void *pdata_buf);
+int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action,
+                   struct cmd_ds_mesh_access *cmd);
+int lbs_mesh_config_send(struct lbs_private *priv,
+                        struct cmd_ds_mesh_config *cmd,
+                        uint16_t action, uint16_t type);
+int lbs_mesh_config(struct lbs_private *priv, uint16_t enable, uint16_t chan);
+
 
 
 /* Persistent configuration */
@@ -75,4 +86,25 @@ void lbs_mesh_ethtool_get_strings(struct net_device *dev,
        uint32_t stringset, uint8_t *s);
 
 
+/* Accessors */
+
+#define lbs_mesh_open(priv) (priv->mesh_open)
+#define lbs_mesh_connected(priv) (priv->mesh_connect_status == LBS_CONNECTED)
+
+#else
+
+#define lbs_init_mesh(priv)
+#define lbs_deinit_mesh(priv)
+#define lbs_add_mesh(priv)
+#define lbs_remove_mesh(priv)
+#define lbs_mesh_set_dev(priv, dev, rxpd) (dev)
+#define lbs_mesh_set_txpd(priv, dev, txpd)
+#define lbs_mesh_config(priv, enable, chan)
+#define lbs_mesh_open(priv) (0)
+#define lbs_mesh_connected(priv) (0)
+
+#endif
+
+
+
 #endif
index b0b1c7841500281eb7031554131aa8e713cdc3b4..220361e69cd3adc7a8a2f680457b49cec2711aaa 100644 (file)
@@ -635,7 +635,7 @@ out:
        if (priv->connect_status == LBS_CONNECTED && !priv->tx_pending_len)
                netif_wake_queue(priv->dev);
 
-       if (priv->mesh_dev && (priv->mesh_connect_status == LBS_CONNECTED) &&
+       if (priv->mesh_dev && lbs_mesh_connected(priv) &&
            !priv->tx_pending_len)
                netif_wake_queue(priv->mesh_dev);
 
index 315d1ce286caa1d4c0939ffa30304b4775e2b07d..52d244ea3d972809f7a528d8077dea7262879505 100644 (file)
@@ -198,7 +198,7 @@ void lbs_send_tx_feedback(struct lbs_private *priv, u32 try_count)
        if (priv->connect_status == LBS_CONNECTED)
                netif_wake_queue(priv->dev);
 
-       if (priv->mesh_dev && (priv->mesh_connect_status == LBS_CONNECTED))
+       if (priv->mesh_dev && lbs_mesh_connected(priv))
                netif_wake_queue(priv->mesh_dev);
 }
 EXPORT_SYMBOL_GPL(lbs_send_tx_feedback);
index 4b1aab593a84ea93fbfd7721d58004e65113fd26..71f88a08e0906200b6053fcb5875dbeed91da894 100644 (file)
@@ -192,7 +192,7 @@ static void copy_active_data_rates(struct lbs_private *priv, u8 *rates)
        lbs_deb_enter(LBS_DEB_WEXT);
 
        if ((priv->connect_status != LBS_CONNECTED) &&
-               (priv->mesh_connect_status != LBS_CONNECTED))
+               !lbs_mesh_connected(priv))
                memcpy(rates, lbs_bg_rates, MAX_RATES);
        else
                memcpy(rates, priv->curbssparams.rates, MAX_RATES);
@@ -298,6 +298,7 @@ static int lbs_get_nick(struct net_device *dev, struct iw_request_info *info,
        return 0;
 }
 
+#ifdef CONFIG_LIBERTAS_MESH
 static int mesh_get_nick(struct net_device *dev, struct iw_request_info *info,
                         struct iw_point *dwrq, char *extra)
 {
@@ -307,7 +308,7 @@ static int mesh_get_nick(struct net_device *dev, struct iw_request_info *info,
 
        /* Use nickname to indicate that mesh is on */
 
-       if (priv->mesh_connect_status == LBS_CONNECTED) {
+       if (lbs_mesh_connected(priv)) {
                strncpy(extra, "Mesh", 12);
                extra[12] = '\0';
                dwrq->length = strlen(extra);
@@ -321,6 +322,7 @@ static int mesh_get_nick(struct net_device *dev, struct iw_request_info *info,
        lbs_deb_leave(LBS_DEB_WEXT);
        return 0;
 }
+#endif
 
 static int lbs_set_rts(struct net_device *dev, struct iw_request_info *info,
                        struct iw_param *vwrq, char *extra)
@@ -422,6 +424,7 @@ static int lbs_get_mode(struct net_device *dev,
        return 0;
 }
 
+#ifdef CONFIG_LIBERTAS_MESH
 static int mesh_wlan_get_mode(struct net_device *dev,
                              struct iw_request_info *info, u32 * uwrq,
                              char *extra)
@@ -433,6 +436,7 @@ static int mesh_wlan_get_mode(struct net_device *dev,
        lbs_deb_leave(LBS_DEB_WEXT);
        return 0;
 }
+#endif
 
 static int lbs_get_txpow(struct net_device *dev,
                          struct iw_request_info *info,
@@ -863,7 +867,7 @@ static struct iw_statistics *lbs_get_wireless_stats(struct net_device *dev)
 
        /* If we're not associated, all quality values are meaningless */
        if ((priv->connect_status != LBS_CONNECTED) &&
-           (priv->mesh_connect_status != LBS_CONNECTED))
+           !lbs_mesh_connected(priv))
                goto out;
 
        /* Quality by RSSI */
@@ -1010,6 +1014,7 @@ out:
        return ret;
 }
 
+#ifdef CONFIG_LIBERTAS_MESH
 static int lbs_mesh_set_freq(struct net_device *dev,
                             struct iw_request_info *info,
                             struct iw_freq *fwrq, char *extra)
@@ -1061,6 +1066,7 @@ out:
        lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
        return ret;
 }
+#endif
 
 static int lbs_set_rate(struct net_device *dev, struct iw_request_info *info,
                  struct iw_param *vwrq, char *extra)
@@ -2108,6 +2114,7 @@ out:
        return ret;
 }
 
+#ifdef CONFIG_LIBERTAS_MESH
 static int lbs_mesh_get_essid(struct net_device *dev,
                              struct iw_request_info *info,
                              struct iw_point *dwrq, char *extra)
@@ -2161,6 +2168,7 @@ static int lbs_mesh_set_essid(struct net_device *dev,
        lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
        return ret;
 }
+#endif
 
 /**
  *  @brief Connect to the AP or Ad-hoc Network with specific bssid
@@ -2267,7 +2275,13 @@ static const iw_handler lbs_handler[] = {
        (iw_handler) lbs_get_encodeext,/* SIOCGIWENCODEEXT */
        (iw_handler) NULL,              /* SIOCSIWPMKSA */
 };
+struct iw_handler_def lbs_handler_def = {
+       .num_standard   = ARRAY_SIZE(lbs_handler),
+       .standard       = (iw_handler *) lbs_handler,
+       .get_wireless_stats = lbs_get_wireless_stats,
+};
 
+#ifdef CONFIG_LIBERTAS_MESH
 static const iw_handler mesh_wlan_handler[] = {
        (iw_handler) NULL,      /* SIOCSIWCOMMIT */
        (iw_handler) lbs_get_name,      /* SIOCGIWNAME */
@@ -2325,14 +2339,10 @@ static const iw_handler mesh_wlan_handler[] = {
        (iw_handler) lbs_get_encodeext,/* SIOCGIWENCODEEXT */
        (iw_handler) NULL,              /* SIOCSIWPMKSA */
 };
-struct iw_handler_def lbs_handler_def = {
-       .num_standard   = ARRAY_SIZE(lbs_handler),
-       .standard       = (iw_handler *) lbs_handler,
-       .get_wireless_stats = lbs_get_wireless_stats,
-};
 
 struct iw_handler_def mesh_handler_def = {
        .num_standard   = ARRAY_SIZE(mesh_wlan_handler),
        .standard       = (iw_handler *) mesh_wlan_handler,
        .get_wireless_stats = lbs_get_wireless_stats,
 };
+#endif
index 26a1abd5bb031c9b9c63565eaf1b9e298373d136..ba3eb0101d558b7247b36adc00449f414a2d9159 100644 (file)
@@ -318,14 +318,14 @@ static void lbtf_op_stop(struct ieee80211_hw *hw)
 }
 
 static int lbtf_op_add_interface(struct ieee80211_hw *hw,
-                       struct ieee80211_if_init_conf *conf)
+                       struct ieee80211_vif *vif)
 {
        struct lbtf_private *priv = hw->priv;
        if (priv->vif != NULL)
                return -EOPNOTSUPP;
 
-       priv->vif = conf->vif;
-       switch (conf->type) {
+       priv->vif = vif;
+       switch (vif->type) {
        case NL80211_IFTYPE_MESH_POINT:
        case NL80211_IFTYPE_AP:
                lbtf_set_mode(priv, LBTF_AP_MODE);
@@ -337,12 +337,12 @@ static int lbtf_op_add_interface(struct ieee80211_hw *hw,
                priv->vif = NULL;
                return -EOPNOTSUPP;
        }
-       lbtf_set_mac_address(priv, (u8 *) conf->mac_addr);
+       lbtf_set_mac_address(priv, (u8 *) vif->addr);
        return 0;
 }
 
 static void lbtf_op_remove_interface(struct ieee80211_hw *hw,
-                       struct ieee80211_if_init_conf *conf)
+                       struct ieee80211_vif *vif)
 {
        struct lbtf_private *priv = hw->priv;
 
index 88e41176e7fd243ee773adc492c3207f6faeb56b..84df3fcf37b393c35d4fac12ce948448a7191d12 100644 (file)
@@ -436,6 +436,38 @@ static bool hwsim_ps_rx_ok(struct mac80211_hwsim_data *data,
 }
 
 
+struct mac80211_hwsim_addr_match_data {
+       bool ret;
+       const u8 *addr;
+};
+
+static void mac80211_hwsim_addr_iter(void *data, u8 *mac,
+                                    struct ieee80211_vif *vif)
+{
+       struct mac80211_hwsim_addr_match_data *md = data;
+       if (memcmp(mac, md->addr, ETH_ALEN) == 0)
+               md->ret = true;
+}
+
+
+static bool mac80211_hwsim_addr_match(struct mac80211_hwsim_data *data,
+                                     const u8 *addr)
+{
+       struct mac80211_hwsim_addr_match_data md;
+
+       if (memcmp(addr, data->hw->wiphy->perm_addr, ETH_ALEN) == 0)
+               return true;
+
+       md.ret = false;
+       md.addr = addr;
+       ieee80211_iterate_active_interfaces_atomic(data->hw,
+                                                  mac80211_hwsim_addr_iter,
+                                                  &md);
+
+       return md.ret;
+}
+
+
 static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
                                    struct sk_buff *skb)
 {
@@ -488,8 +520,7 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
                if (nskb == NULL)
                        continue;
 
-               if (memcmp(hdr->addr1, data2->hw->wiphy->perm_addr,
-                          ETH_ALEN) == 0)
+               if (mac80211_hwsim_addr_match(data2, hdr->addr1))
                        ack = true;
                memcpy(IEEE80211_SKB_RXCB(nskb), &rx_status, sizeof(rx_status));
                ieee80211_rx_irqsafe(data2->hw, nskb);
@@ -553,24 +584,24 @@ static void mac80211_hwsim_stop(struct ieee80211_hw *hw)
 
 
 static int mac80211_hwsim_add_interface(struct ieee80211_hw *hw,
-                                       struct ieee80211_if_init_conf *conf)
+                                       struct ieee80211_vif *vif)
 {
        printk(KERN_DEBUG "%s:%s (type=%d mac_addr=%pM)\n",
-              wiphy_name(hw->wiphy), __func__, conf->type,
-              conf->mac_addr);
-       hwsim_set_magic(conf->vif);
+              wiphy_name(hw->wiphy), __func__, vif->type,
+              vif->addr);
+       hwsim_set_magic(vif);
        return 0;
 }
 
 
 static void mac80211_hwsim_remove_interface(
-       struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf)
+       struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 {
        printk(KERN_DEBUG "%s:%s (type=%d mac_addr=%pM)\n",
-              wiphy_name(hw->wiphy), __func__, conf->type,
-              conf->mac_addr);
-       hwsim_check_magic(conf->vif);
-       hwsim_clear_magic(conf->vif);
+              wiphy_name(hw->wiphy), __func__, vif->type,
+              vif->addr);
+       hwsim_check_magic(vif);
+       hwsim_clear_magic(vif);
 }
 
 
@@ -618,12 +649,26 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed)
 {
        struct mac80211_hwsim_data *data = hw->priv;
        struct ieee80211_conf *conf = &hw->conf;
-
-       printk(KERN_DEBUG "%s:%s (freq=%d idle=%d ps=%d)\n",
+       static const char *chantypes[4] = {
+               [NL80211_CHAN_NO_HT] = "noht",
+               [NL80211_CHAN_HT20] = "ht20",
+               [NL80211_CHAN_HT40MINUS] = "ht40-",
+               [NL80211_CHAN_HT40PLUS] = "ht40+",
+       };
+       static const char *smps_modes[IEEE80211_SMPS_NUM_MODES] = {
+               [IEEE80211_SMPS_AUTOMATIC] = "auto",
+               [IEEE80211_SMPS_OFF] = "off",
+               [IEEE80211_SMPS_STATIC] = "static",
+               [IEEE80211_SMPS_DYNAMIC] = "dynamic",
+       };
+
+       printk(KERN_DEBUG "%s:%s (freq=%d/%s idle=%d ps=%d smps=%s)\n",
               wiphy_name(hw->wiphy), __func__,
               conf->channel->center_freq,
+              chantypes[conf->channel_type],
               !!(conf->flags & IEEE80211_CONF_IDLE),
-              !!(conf->flags & IEEE80211_CONF_PS));
+              !!(conf->flags & IEEE80211_CONF_PS),
+              smps_modes[conf->smps_mode]);
 
        data->idle = !!(conf->flags & IEEE80211_CONF_IDLE);
 
@@ -827,6 +872,41 @@ static int mac80211_hwsim_testmode_cmd(struct ieee80211_hw *hw,
 }
 #endif
 
+static int mac80211_hwsim_ampdu_action(struct ieee80211_hw *hw,
+                                      struct ieee80211_vif *vif,
+                                      enum ieee80211_ampdu_mlme_action action,
+                                      struct ieee80211_sta *sta, u16 tid, u16 *ssn)
+{
+       switch (action) {
+       case IEEE80211_AMPDU_TX_START:
+               ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+               break;
+       case IEEE80211_AMPDU_TX_STOP:
+               ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+               break;
+       case IEEE80211_AMPDU_TX_OPERATIONAL:
+               break;
+       case IEEE80211_AMPDU_RX_START:
+       case IEEE80211_AMPDU_RX_STOP:
+               break;
+       default:
+               return -EOPNOTSUPP;
+       }
+
+       return 0;
+}
+
+static void mac80211_hwsim_flush(struct ieee80211_hw *hw, bool drop)
+{
+       /*
+        * In this special case, there's nothing we need to
+        * do because hwsim does transmission synchronously.
+        * In the future, when it does transmissions via
+        * userspace, we may need to do something.
+        */
+}
+
+
 static const struct ieee80211_ops mac80211_hwsim_ops =
 {
        .tx = mac80211_hwsim_tx,
@@ -841,6 +921,8 @@ static const struct ieee80211_ops mac80211_hwsim_ops =
        .set_tim = mac80211_hwsim_set_tim,
        .conf_tx = mac80211_hwsim_conf_tx,
        CFG80211_TESTMODE_CMD(mac80211_hwsim_testmode_cmd)
+       .ampdu_action = mac80211_hwsim_ampdu_action,
+       .flush = mac80211_hwsim_flush,
 };
 
 
@@ -1082,7 +1164,9 @@ static int __init init_mac80211_hwsim(void)
                        BIT(NL80211_IFTYPE_MESH_POINT);
 
                hw->flags = IEEE80211_HW_MFP_CAPABLE |
-                           IEEE80211_HW_SIGNAL_DBM;
+                           IEEE80211_HW_SIGNAL_DBM |
+                           IEEE80211_HW_SUPPORTS_STATIC_SMPS |
+                           IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS;
 
                /* ask mac80211 to reserve space for magic */
                hw->vif_data_size = sizeof(struct hwsim_vif_priv);
index 59f92105b0c24880980af6339f6589f469eefa52..68546ca0ba378b72a602ffd08e04eaafe958958c 100644 (file)
@@ -2,7 +2,7 @@
  * drivers/net/wireless/mwl8k.c
  * Driver for Marvell TOPDOG 802.11 Wireless cards
  *
- * Copyright (C) 2008-2009 Marvell Semiconductor Inc.
+ * Copyright (C) 2008, 2009, 2010 Marvell Semiconductor Inc.
  *
  * This file is licensed under the terms of the GNU General Public
  * License version 2.  This program is licensed "as is" without any
@@ -26,7 +26,7 @@
 
 #define MWL8K_DESC     "Marvell TOPDOG(R) 802.11 Wireless Network Driver"
 #define MWL8K_NAME     KBUILD_MODNAME
-#define MWL8K_VERSION  "0.10"
+#define MWL8K_VERSION  "0.12"
 
 /* Register definitions */
 #define MWL8K_HIU_GEN_PTR                      0x00000c10
@@ -92,8 +92,7 @@ struct mwl8k_device_info {
        char *part_name;
        char *helper_image;
        char *fw_image;
-       struct rxd_ops *rxd_ops;
-       u16 modes;
+       struct rxd_ops *ap_rxd_ops;
 };
 
 struct mwl8k_rx_queue {
@@ -126,28 +125,30 @@ struct mwl8k_tx_queue {
        struct sk_buff **skb;
 };
 
-/* Pointers to the firmware data and meta information about it.  */
-struct mwl8k_firmware {
-       /* Boot helper code */
-       struct firmware *helper;
+struct mwl8k_priv {
+       struct ieee80211_hw *hw;
+       struct pci_dev *pdev;
 
-       /* Microcode */
-       struct firmware *ucode;
-};
+       struct mwl8k_device_info *device_info;
 
-struct mwl8k_priv {
        void __iomem *sram;
        void __iomem *regs;
-       struct ieee80211_hw *hw;
 
-       struct pci_dev *pdev;
+       /* firmware */
+       struct firmware *fw_helper;
+       struct firmware *fw_ucode;
 
-       struct mwl8k_device_info *device_info;
+       /* hardware/firmware parameters */
        bool ap_fw;
        struct rxd_ops *rxd_ops;
-
-       /* firmware files and meta data */
-       struct mwl8k_firmware fw;
+       struct ieee80211_supported_band band_24;
+       struct ieee80211_channel channels_24[14];
+       struct ieee80211_rate rates_24[14];
+       struct ieee80211_supported_band band_50;
+       struct ieee80211_channel channels_50[4];
+       struct ieee80211_rate rates_50[9];
+       u32 ap_macids_supported;
+       u32 sta_macids_supported;
 
        /* firmware access */
        struct mutex fw_mutex;
@@ -161,9 +162,9 @@ struct mwl8k_priv {
        /* TX quiesce completion, protected by fw_mutex and tx_lock */
        struct completion *tx_wait;
 
-       struct ieee80211_vif *vif;
-
-       struct ieee80211_channel *current_channel;
+       /* List of interfaces.  */
+       u32 macids_used;
+       struct list_head vif_list;
 
        /* power management status cookie from firmware */
        u32 *cookie;
@@ -182,16 +183,15 @@ struct mwl8k_priv {
        struct mwl8k_rx_queue rxq[MWL8K_RX_QUEUES];
        struct mwl8k_tx_queue txq[MWL8K_TX_QUEUES];
 
-       /* PHY parameters */
-       struct ieee80211_supported_band band;
-       struct ieee80211_channel channels[14];
-       struct ieee80211_rate rates[14];
-
        bool radio_on;
        bool radio_short_preamble;
        bool sniffer_enabled;
        bool wmm_enabled;
 
+       struct work_struct sta_notify_worker;
+       spinlock_t sta_notify_list_lock;
+       struct list_head sta_notify_list;
+
        /* XXX need to convert this to handle multiple interfaces */
        bool capture_beacon;
        u8 capture_bssid[ETH_ALEN];
@@ -205,32 +205,33 @@ struct mwl8k_priv {
         */
        struct work_struct finalize_join_worker;
 
-       /* Tasklet to reclaim TX descriptors and buffers after tx */
-       struct tasklet_struct tx_reclaim_task;
+       /* Tasklet to perform TX reclaim.  */
+       struct tasklet_struct poll_tx_task;
+
+       /* Tasklet to perform RX.  */
+       struct tasklet_struct poll_rx_task;
 };
 
 /* Per interface specific private data */
 struct mwl8k_vif {
-       /* backpointer to parent config block */
-       struct mwl8k_priv *priv;
-
-       /* BSS config of AP or IBSS from mac80211*/
-       struct ieee80211_bss_conf bss_info;
-
-       /* BSSID of AP or IBSS */
-       u8      bssid[ETH_ALEN];
-       u8      mac_addr[ETH_ALEN];
+       struct list_head list;
+       struct ieee80211_vif *vif;
 
-        /* Index into station database.Returned by update_sta_db call */
-       u8      peer_id;
+       /* Firmware macid for this vif.  */
+       int macid;
 
-       /* Non AMPDU sequence number assigned by driver */
-       u16     seqno;
+       /* Non AMPDU sequence number assigned by driver */
+       u16 seqno;
 };
-
 #define MWL8K_VIF(_vif) ((struct mwl8k_vif *)&((_vif)->drv_priv))
 
-static const struct ieee80211_channel mwl8k_channels[] = {
+struct mwl8k_sta {
+       /* Index into station database. Returned by UPDATE_STADB.  */
+       u8 peer_id;
+};
+#define MWL8K_STA(_sta) ((struct mwl8k_sta *)&((_sta)->drv_priv))
+
+static const struct ieee80211_channel mwl8k_channels_24[] = {
        { .center_freq = 2412, .hw_value = 1, },
        { .center_freq = 2417, .hw_value = 2, },
        { .center_freq = 2422, .hw_value = 3, },
@@ -242,9 +243,12 @@ static const struct ieee80211_channel mwl8k_channels[] = {
        { .center_freq = 2452, .hw_value = 9, },
        { .center_freq = 2457, .hw_value = 10, },
        { .center_freq = 2462, .hw_value = 11, },
+       { .center_freq = 2467, .hw_value = 12, },
+       { .center_freq = 2472, .hw_value = 13, },
+       { .center_freq = 2484, .hw_value = 14, },
 };
 
-static const struct ieee80211_rate mwl8k_rates[] = {
+static const struct ieee80211_rate mwl8k_rates_24[] = {
        { .bitrate = 10, .hw_value = 2, },
        { .bitrate = 20, .hw_value = 4, },
        { .bitrate = 55, .hw_value = 11, },
@@ -261,8 +265,23 @@ static const struct ieee80211_rate mwl8k_rates[] = {
        { .bitrate = 720, .hw_value = 144, },
 };
 
-static const u8 mwl8k_rateids[12] = {
-       2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108,
+static const struct ieee80211_channel mwl8k_channels_50[] = {
+       { .center_freq = 5180, .hw_value = 36, },
+       { .center_freq = 5200, .hw_value = 40, },
+       { .center_freq = 5220, .hw_value = 44, },
+       { .center_freq = 5240, .hw_value = 48, },
+};
+
+static const struct ieee80211_rate mwl8k_rates_50[] = {
+       { .bitrate = 60, .hw_value = 12, },
+       { .bitrate = 90, .hw_value = 18, },
+       { .bitrate = 120, .hw_value = 24, },
+       { .bitrate = 180, .hw_value = 36, },
+       { .bitrate = 240, .hw_value = 48, },
+       { .bitrate = 360, .hw_value = 72, },
+       { .bitrate = 480, .hw_value = 96, },
+       { .bitrate = 540, .hw_value = 108, },
+       { .bitrate = 720, .hw_value = 144, },
 };
 
 /* Set or get info from Firmware */
@@ -278,6 +297,7 @@ static const u8 mwl8k_rateids[12] = {
 #define MWL8K_CMD_RADIO_CONTROL                0x001c
 #define MWL8K_CMD_RF_TX_POWER          0x001e
 #define MWL8K_CMD_RF_ANTENNA           0x0020
+#define MWL8K_CMD_SET_BEACON           0x0100          /* per-vif */
 #define MWL8K_CMD_SET_PRE_SCAN         0x0107
 #define MWL8K_CMD_SET_POST_SCAN                0x0108
 #define MWL8K_CMD_SET_RF_CHANNEL       0x010a
@@ -291,8 +311,10 @@ static const u8 mwl8k_rateids[12] = {
 #define MWL8K_CMD_MIMO_CONFIG          0x0125
 #define MWL8K_CMD_USE_FIXED_RATE       0x0126
 #define MWL8K_CMD_ENABLE_SNIFFER       0x0150
-#define MWL8K_CMD_SET_MAC_ADDR         0x0202
+#define MWL8K_CMD_SET_MAC_ADDR         0x0202          /* per-vif */
 #define MWL8K_CMD_SET_RATEADAPT_MODE   0x0203
+#define MWL8K_CMD_BSS_START            0x1100          /* per-vif */
+#define MWL8K_CMD_SET_NEW_STN          0x1111          /* per-vif */
 #define MWL8K_CMD_UPDATE_STADB         0x1123
 
 static const char *mwl8k_cmd_name(u16 cmd, char *buf, int bufsize)
@@ -310,6 +332,7 @@ static const char *mwl8k_cmd_name(u16 cmd, char *buf, int bufsize)
                MWL8K_CMDNAME(RADIO_CONTROL);
                MWL8K_CMDNAME(RF_TX_POWER);
                MWL8K_CMDNAME(RF_ANTENNA);
+               MWL8K_CMDNAME(SET_BEACON);
                MWL8K_CMDNAME(SET_PRE_SCAN);
                MWL8K_CMDNAME(SET_POST_SCAN);
                MWL8K_CMDNAME(SET_RF_CHANNEL);
@@ -325,6 +348,8 @@ static const char *mwl8k_cmd_name(u16 cmd, char *buf, int bufsize)
                MWL8K_CMDNAME(ENABLE_SNIFFER);
                MWL8K_CMDNAME(SET_MAC_ADDR);
                MWL8K_CMDNAME(SET_RATEADAPT_MODE);
+               MWL8K_CMDNAME(BSS_START);
+               MWL8K_CMDNAME(SET_NEW_STN);
                MWL8K_CMDNAME(UPDATE_STADB);
        default:
                snprintf(buf, bufsize, "0x%x", cmd);
@@ -355,8 +380,8 @@ static void mwl8k_release_fw(struct firmware **fw)
 
 static void mwl8k_release_firmware(struct mwl8k_priv *priv)
 {
-       mwl8k_release_fw(&priv->fw.ucode);
-       mwl8k_release_fw(&priv->fw.helper);
+       mwl8k_release_fw(&priv->fw_ucode);
+       mwl8k_release_fw(&priv->fw_helper);
 }
 
 /* Request fw image */
@@ -377,7 +402,7 @@ static int mwl8k_request_firmware(struct mwl8k_priv *priv)
        int rc;
 
        if (di->helper_image != NULL) {
-               rc = mwl8k_request_fw(priv, di->helper_image, &priv->fw.helper);
+               rc = mwl8k_request_fw(priv, di->helper_image, &priv->fw_helper);
                if (rc) {
                        printk(KERN_ERR "%s: Error requesting helper "
                               "firmware file %s\n", pci_name(priv->pdev),
@@ -386,24 +411,22 @@ static int mwl8k_request_firmware(struct mwl8k_priv *priv)
                }
        }
 
-       rc = mwl8k_request_fw(priv, di->fw_image, &priv->fw.ucode);
+       rc = mwl8k_request_fw(priv, di->fw_image, &priv->fw_ucode);
        if (rc) {
                printk(KERN_ERR "%s: Error requesting firmware file %s\n",
                       pci_name(priv->pdev), di->fw_image);
-               mwl8k_release_fw(&priv->fw.helper);
+               mwl8k_release_fw(&priv->fw_helper);
                return rc;
        }
 
        return 0;
 }
 
-MODULE_FIRMWARE("mwl8k/helper_8687.fw");
-MODULE_FIRMWARE("mwl8k/fmimage_8687.fw");
-
 struct mwl8k_cmd_pkt {
        __le16  code;
        __le16  length;
-       __le16  seq_num;
+       __u8    seq_num;
+       __u8    macid;
        __le16  result;
        char    payload[0];
 } __attribute__((packed));
@@ -461,6 +484,7 @@ static int mwl8k_load_fw_image(struct mwl8k_priv *priv,
 
        cmd->code = cpu_to_le16(MWL8K_CMD_CODE_DNLD);
        cmd->seq_num = 0;
+       cmd->macid = 0;
        cmd->result = 0;
 
        done = 0;
@@ -551,13 +575,12 @@ static int mwl8k_feed_fw_image(struct mwl8k_priv *priv,
 static int mwl8k_load_firmware(struct ieee80211_hw *hw)
 {
        struct mwl8k_priv *priv = hw->priv;
-       struct firmware *fw = priv->fw.ucode;
-       struct mwl8k_device_info *di = priv->device_info;
+       struct firmware *fw = priv->fw_ucode;
        int rc;
        int loops;
 
        if (!memcmp(fw->data, "\x01\x00\x00\x00", 4)) {
-               struct firmware *helper = priv->fw.helper;
+               struct firmware *helper = priv->fw_helper;
 
                if (helper == NULL) {
                        printk(KERN_ERR "%s: helper image needed but none "
@@ -584,10 +607,7 @@ static int mwl8k_load_firmware(struct ieee80211_hw *hw)
                return rc;
        }
 
-       if (di->modes & BIT(NL80211_IFTYPE_AP))
-               iowrite32(MWL8K_MODE_AP, priv->regs + MWL8K_HIU_GEN_PTR);
-       else
-               iowrite32(MWL8K_MODE_STA, priv->regs + MWL8K_HIU_GEN_PTR);
+       iowrite32(MWL8K_MODE_STA, priv->regs + MWL8K_HIU_GEN_PTR);
 
        loops = 500000;
        do {
@@ -610,91 +630,6 @@ static int mwl8k_load_firmware(struct ieee80211_hw *hw)
 }
 
 
-/*
- * Defines shared between transmission and reception.
- */
-/* HT control fields for firmware */
-struct ewc_ht_info {
-       __le16  control1;
-       __le16  control2;
-       __le16  control3;
-} __attribute__((packed));
-
-/* Firmware Station database operations */
-#define MWL8K_STA_DB_ADD_ENTRY         0
-#define MWL8K_STA_DB_MODIFY_ENTRY      1
-#define MWL8K_STA_DB_DEL_ENTRY         2
-#define MWL8K_STA_DB_FLUSH             3
-
-/* Peer Entry flags - used to define the type of the peer node */
-#define MWL8K_PEER_TYPE_ACCESSPOINT    2
-
-struct peer_capability_info {
-       /* Peer type - AP vs. STA.  */
-       __u8    peer_type;
-
-       /* Basic 802.11 capabilities from assoc resp.  */
-       __le16  basic_caps;
-
-       /* Set if peer supports 802.11n high throughput (HT).  */
-       __u8    ht_support;
-
-       /* Valid if HT is supported.  */
-       __le16  ht_caps;
-       __u8    extended_ht_caps;
-       struct ewc_ht_info      ewc_info;
-
-       /* Legacy rate table. Intersection of our rates and peer rates.  */
-       __u8    legacy_rates[12];
-
-       /* HT rate table. Intersection of our rates and peer rates.  */
-       __u8    ht_rates[16];
-       __u8    pad[16];
-
-       /* If set, interoperability mode, no proprietary extensions.  */
-       __u8    interop;
-       __u8    pad2;
-       __u8    station_id;
-       __le16  amsdu_enabled;
-} __attribute__((packed));
-
-/* Inline functions to manipulate QoS field in data descriptor.  */
-static inline u16 mwl8k_qos_setbit_eosp(u16 qos)
-{
-       u16 val_mask = 1 << 4;
-
-       /* End of Service Period Bit 4 */
-       return qos | val_mask;
-}
-
-static inline u16 mwl8k_qos_setbit_ack(u16 qos, u8 ack_policy)
-{
-       u16 val_mask = 0x3;
-       u8      shift = 5;
-       u16 qos_mask = ~(val_mask << shift);
-
-       /* Ack Policy Bit 5-6 */
-       return (qos & qos_mask) | ((ack_policy & val_mask) << shift);
-}
-
-static inline u16 mwl8k_qos_setbit_amsdu(u16 qos)
-{
-       u16 val_mask = 1 << 7;
-
-       /* AMSDU present Bit 7 */
-       return qos | val_mask;
-}
-
-static inline u16 mwl8k_qos_setbit_qlen(u16 qos, u8 len)
-{
-       u16 val_mask = 0xff;
-       u8      shift = 8;
-       u16 qos_mask = ~(val_mask << shift);
-
-       /* Queue Length Bits 8-15 */
-       return (qos & qos_mask) | ((len & val_mask) << shift);
-}
-
 /* DMA header used by firmware and hardware.  */
 struct mwl8k_dma_data {
        __le16 fwlen;
@@ -761,9 +696,9 @@ static inline void mwl8k_add_dma_header(struct sk_buff *skb)
 
 
 /*
- * Packet reception for 88w8366.
+ * Packet reception for 88w8366 AP firmware.
  */
-struct mwl8k_rxd_8366 {
+struct mwl8k_rxd_8366_ap {
        __le16 pkt_len;
        __u8 sq2;
        __u8 rate;
@@ -781,23 +716,23 @@ struct mwl8k_rxd_8366 {
        __u8 rx_ctrl;
 } __attribute__((packed));
 
-#define MWL8K_8366_RATE_INFO_MCS_FORMAT                0x80
-#define MWL8K_8366_RATE_INFO_40MHZ             0x40
-#define MWL8K_8366_RATE_INFO_RATEID(x)         ((x) & 0x3f)
+#define MWL8K_8366_AP_RATE_INFO_MCS_FORMAT     0x80
+#define MWL8K_8366_AP_RATE_INFO_40MHZ          0x40
+#define MWL8K_8366_AP_RATE_INFO_RATEID(x)      ((x) & 0x3f)
 
-#define MWL8K_8366_RX_CTRL_OWNED_BY_HOST       0x80
+#define MWL8K_8366_AP_RX_CTRL_OWNED_BY_HOST    0x80
 
-static void mwl8k_rxd_8366_init(void *_rxd, dma_addr_t next_dma_addr)
+static void mwl8k_rxd_8366_ap_init(void *_rxd, dma_addr_t next_dma_addr)
 {
-       struct mwl8k_rxd_8366 *rxd = _rxd;
+       struct mwl8k_rxd_8366_ap *rxd = _rxd;
 
        rxd->next_rxd_phys_addr = cpu_to_le32(next_dma_addr);
-       rxd->rx_ctrl = MWL8K_8366_RX_CTRL_OWNED_BY_HOST;
+       rxd->rx_ctrl = MWL8K_8366_AP_RX_CTRL_OWNED_BY_HOST;
 }
 
-static void mwl8k_rxd_8366_refill(void *_rxd, dma_addr_t addr, int len)
+static void mwl8k_rxd_8366_ap_refill(void *_rxd, dma_addr_t addr, int len)
 {
-       struct mwl8k_rxd_8366 *rxd = _rxd;
+       struct mwl8k_rxd_8366_ap *rxd = _rxd;
 
        rxd->pkt_len = cpu_to_le16(len);
        rxd->pkt_phys_addr = cpu_to_le32(addr);
@@ -806,12 +741,12 @@ static void mwl8k_rxd_8366_refill(void *_rxd, dma_addr_t addr, int len)
 }
 
 static int
-mwl8k_rxd_8366_process(void *_rxd, struct ieee80211_rx_status *status,
-                      __le16 *qos)
+mwl8k_rxd_8366_ap_process(void *_rxd, struct ieee80211_rx_status *status,
+                         __le16 *qos)
 {
-       struct mwl8k_rxd_8366 *rxd = _rxd;
+       struct mwl8k_rxd_8366_ap *rxd = _rxd;
 
-       if (!(rxd->rx_ctrl & MWL8K_8366_RX_CTRL_OWNED_BY_HOST))
+       if (!(rxd->rx_ctrl & MWL8K_8366_AP_RX_CTRL_OWNED_BY_HOST))
                return -1;
        rmb();
 
@@ -820,23 +755,29 @@ mwl8k_rxd_8366_process(void *_rxd, struct ieee80211_rx_status *status,
        status->signal = -rxd->rssi;
        status->noise = -rxd->noise_floor;
 
-       if (rxd->rate & MWL8K_8366_RATE_INFO_MCS_FORMAT) {
+       if (rxd->rate & MWL8K_8366_AP_RATE_INFO_MCS_FORMAT) {
                status->flag |= RX_FLAG_HT;
-               if (rxd->rate & MWL8K_8366_RATE_INFO_40MHZ)
+               if (rxd->rate & MWL8K_8366_AP_RATE_INFO_40MHZ)
                        status->flag |= RX_FLAG_40MHZ;
-               status->rate_idx = MWL8K_8366_RATE_INFO_RATEID(rxd->rate);
+               status->rate_idx = MWL8K_8366_AP_RATE_INFO_RATEID(rxd->rate);
        } else {
                int i;
 
-               for (i = 0; i < ARRAY_SIZE(mwl8k_rates); i++) {
-                       if (mwl8k_rates[i].hw_value == rxd->rate) {
+               for (i = 0; i < ARRAY_SIZE(mwl8k_rates_24); i++) {
+                       if (mwl8k_rates_24[i].hw_value == rxd->rate) {
                                status->rate_idx = i;
                                break;
                        }
                }
        }
 
-       status->band = IEEE80211_BAND_2GHZ;
+       if (rxd->channel > 14) {
+               status->band = IEEE80211_BAND_5GHZ;
+               if (!(status->flag & RX_FLAG_HT))
+                       status->rate_idx -= 5;
+       } else {
+               status->band = IEEE80211_BAND_2GHZ;
+       }
        status->freq = ieee80211_channel_to_frequency(rxd->channel);
 
        *qos = rxd->qos_control;
@@ -844,17 +785,17 @@ mwl8k_rxd_8366_process(void *_rxd, struct ieee80211_rx_status *status,
        return le16_to_cpu(rxd->pkt_len);
 }
 
-static struct rxd_ops rxd_8366_ops = {
-       .rxd_size       = sizeof(struct mwl8k_rxd_8366),
-       .rxd_init       = mwl8k_rxd_8366_init,
-       .rxd_refill     = mwl8k_rxd_8366_refill,
-       .rxd_process    = mwl8k_rxd_8366_process,
+static struct rxd_ops rxd_8366_ap_ops = {
+       .rxd_size       = sizeof(struct mwl8k_rxd_8366_ap),
+       .rxd_init       = mwl8k_rxd_8366_ap_init,
+       .rxd_refill     = mwl8k_rxd_8366_ap_refill,
+       .rxd_process    = mwl8k_rxd_8366_ap_process,
 };
 
 /*
- * Packet reception for 88w8687.
+ * Packet reception for STA firmware.
  */
-struct mwl8k_rxd_8687 {
+struct mwl8k_rxd_sta {
        __le16 pkt_len;
        __u8 link_quality;
        __u8 noise_level;
@@ -871,26 +812,26 @@ struct mwl8k_rxd_8687 {
        __u8 pad2[2];
 } __attribute__((packed));
 
-#define MWL8K_8687_RATE_INFO_SHORTPRE          0x8000
-#define MWL8K_8687_RATE_INFO_ANTSELECT(x)      (((x) >> 11) & 0x3)
-#define MWL8K_8687_RATE_INFO_RATEID(x)         (((x) >> 3) & 0x3f)
-#define MWL8K_8687_RATE_INFO_40MHZ             0x0004
-#define MWL8K_8687_RATE_INFO_SHORTGI           0x0002
-#define MWL8K_8687_RATE_INFO_MCS_FORMAT                0x0001
+#define MWL8K_STA_RATE_INFO_SHORTPRE           0x8000
+#define MWL8K_STA_RATE_INFO_ANTSELECT(x)       (((x) >> 11) & 0x3)
+#define MWL8K_STA_RATE_INFO_RATEID(x)          (((x) >> 3) & 0x3f)
+#define MWL8K_STA_RATE_INFO_40MHZ              0x0004
+#define MWL8K_STA_RATE_INFO_SHORTGI            0x0002
+#define MWL8K_STA_RATE_INFO_MCS_FORMAT         0x0001
 
-#define MWL8K_8687_RX_CTRL_OWNED_BY_HOST       0x02
+#define MWL8K_STA_RX_CTRL_OWNED_BY_HOST                0x02
 
-static void mwl8k_rxd_8687_init(void *_rxd, dma_addr_t next_dma_addr)
+static void mwl8k_rxd_sta_init(void *_rxd, dma_addr_t next_dma_addr)
 {
-       struct mwl8k_rxd_8687 *rxd = _rxd;
+       struct mwl8k_rxd_sta *rxd = _rxd;
 
        rxd->next_rxd_phys_addr = cpu_to_le32(next_dma_addr);
-       rxd->rx_ctrl = MWL8K_8687_RX_CTRL_OWNED_BY_HOST;
+       rxd->rx_ctrl = MWL8K_STA_RX_CTRL_OWNED_BY_HOST;
 }
 
-static void mwl8k_rxd_8687_refill(void *_rxd, dma_addr_t addr, int len)
+static void mwl8k_rxd_sta_refill(void *_rxd, dma_addr_t addr, int len)
 {
-       struct mwl8k_rxd_8687 *rxd = _rxd;
+       struct mwl8k_rxd_sta *rxd = _rxd;
 
        rxd->pkt_len = cpu_to_le16(len);
        rxd->pkt_phys_addr = cpu_to_le32(addr);
@@ -899,13 +840,13 @@ static void mwl8k_rxd_8687_refill(void *_rxd, dma_addr_t addr, int len)
 }
 
 static int
-mwl8k_rxd_8687_process(void *_rxd, struct ieee80211_rx_status *status,
+mwl8k_rxd_sta_process(void *_rxd, struct ieee80211_rx_status *status,
                       __le16 *qos)
 {
-       struct mwl8k_rxd_8687 *rxd = _rxd;
+       struct mwl8k_rxd_sta *rxd = _rxd;
        u16 rate_info;
 
-       if (!(rxd->rx_ctrl & MWL8K_8687_RX_CTRL_OWNED_BY_HOST))
+       if (!(rxd->rx_ctrl & MWL8K_STA_RX_CTRL_OWNED_BY_HOST))
                return -1;
        rmb();
 
@@ -915,19 +856,25 @@ mwl8k_rxd_8687_process(void *_rxd, struct ieee80211_rx_status *status,
 
        status->signal = -rxd->rssi;
        status->noise = -rxd->noise_level;
-       status->antenna = MWL8K_8687_RATE_INFO_ANTSELECT(rate_info);
-       status->rate_idx = MWL8K_8687_RATE_INFO_RATEID(rate_info);
+       status->antenna = MWL8K_STA_RATE_INFO_ANTSELECT(rate_info);
+       status->rate_idx = MWL8K_STA_RATE_INFO_RATEID(rate_info);
 
-       if (rate_info & MWL8K_8687_RATE_INFO_SHORTPRE)
+       if (rate_info & MWL8K_STA_RATE_INFO_SHORTPRE)
                status->flag |= RX_FLAG_SHORTPRE;
-       if (rate_info & MWL8K_8687_RATE_INFO_40MHZ)
+       if (rate_info & MWL8K_STA_RATE_INFO_40MHZ)
                status->flag |= RX_FLAG_40MHZ;
-       if (rate_info & MWL8K_8687_RATE_INFO_SHORTGI)
+       if (rate_info & MWL8K_STA_RATE_INFO_SHORTGI)
                status->flag |= RX_FLAG_SHORT_GI;
-       if (rate_info & MWL8K_8687_RATE_INFO_MCS_FORMAT)
+       if (rate_info & MWL8K_STA_RATE_INFO_MCS_FORMAT)
                status->flag |= RX_FLAG_HT;
 
-       status->band = IEEE80211_BAND_2GHZ;
+       if (rxd->channel > 14) {
+               status->band = IEEE80211_BAND_5GHZ;
+               if (!(status->flag & RX_FLAG_HT))
+                       status->rate_idx -= 5;
+       } else {
+               status->band = IEEE80211_BAND_2GHZ;
+       }
        status->freq = ieee80211_channel_to_frequency(rxd->channel);
 
        *qos = rxd->qos_control;
@@ -935,11 +882,11 @@ mwl8k_rxd_8687_process(void *_rxd, struct ieee80211_rx_status *status,
        return le16_to_cpu(rxd->pkt_len);
 }
 
-static struct rxd_ops rxd_8687_ops = {
-       .rxd_size       = sizeof(struct mwl8k_rxd_8687),
-       .rxd_init       = mwl8k_rxd_8687_init,
-       .rxd_refill     = mwl8k_rxd_8687_refill,
-       .rxd_process    = mwl8k_rxd_8687_process,
+static struct rxd_ops rxd_sta_ops = {
+       .rxd_size       = sizeof(struct mwl8k_rxd_sta),
+       .rxd_init       = mwl8k_rxd_sta_init,
+       .rxd_refill     = mwl8k_rxd_sta_refill,
+       .rxd_process    = mwl8k_rxd_sta_process,
 };
 
 
@@ -1153,16 +1100,18 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit)
  * Packet transmission.
  */
 
-/* Transmit packet ACK policy */
-#define MWL8K_TXD_ACK_POLICY_NORMAL            0
-#define MWL8K_TXD_ACK_POLICY_BLOCKACK          3
-
 #define MWL8K_TXD_STATUS_OK                    0x00000001
 #define MWL8K_TXD_STATUS_OK_RETRY              0x00000002
 #define MWL8K_TXD_STATUS_OK_MORE_RETRY         0x00000004
 #define MWL8K_TXD_STATUS_MULTICAST_TX          0x00000008
 #define MWL8K_TXD_STATUS_FW_OWNED              0x80000000
 
+#define MWL8K_QOS_QLEN_UNSPEC                  0xff00
+#define MWL8K_QOS_ACK_POLICY_MASK              0x0060
+#define MWL8K_QOS_ACK_POLICY_NORMAL            0x0000
+#define MWL8K_QOS_ACK_POLICY_BLOCKACK          0x0060
+#define MWL8K_QOS_EOSP                         0x0010
+
 struct mwl8k_tx_desc {
        __le32 status;
        __u8 data_rate;
@@ -1272,7 +1221,7 @@ static void mwl8k_dump_tx_rings(struct ieee80211_hw *hw)
 /*
  * Must be called with priv->fw_mutex held and tx queues stopped.
  */
-#define MWL8K_TX_WAIT_TIMEOUT_MS       1000
+#define MWL8K_TX_WAIT_TIMEOUT_MS       5000
 
 static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw)
 {
@@ -1316,8 +1265,8 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw)
                }
 
                if (priv->pending_tx_pkts < oldcount) {
-                       printk(KERN_NOTICE "%s: timeout waiting for tx "
-                              "rings to drain (%d -> %d pkts), retrying\n",
+                       printk(KERN_NOTICE "%s: waiting for tx rings "
+                              "to drain (%d -> %d pkts)\n",
                               wiphy_name(hw->wiphy), oldcount,
                               priv->pending_tx_pkts);
                        retry = 1;
@@ -1342,13 +1291,15 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw)
                     MWL8K_TXD_STATUS_OK_RETRY |                \
                     MWL8K_TXD_STATUS_OK_MORE_RETRY))
 
-static void mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int force)
+static int
+mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int limit, int force)
 {
        struct mwl8k_priv *priv = hw->priv;
        struct mwl8k_tx_queue *txq = priv->txq + index;
-       int wake = 0;
+       int processed;
 
-       while (txq->stats.len > 0) {
+       processed = 0;
+       while (txq->stats.len > 0 && limit--) {
                int tx;
                struct mwl8k_tx_desc *tx_desc;
                unsigned long addr;
@@ -1395,11 +1346,13 @@ static void mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int force)
 
                ieee80211_tx_status_irqsafe(hw, skb);
 
-               wake = 1;
+               processed++;
        }
 
-       if (wake && priv->radio_on && !mutex_is_locked(&priv->fw_mutex))
+       if (processed && priv->radio_on && !mutex_is_locked(&priv->fw_mutex))
                ieee80211_wake_queue(hw, index);
+
+       return processed;
 }
 
 /* must be called only when the card's transmit is completely halted */
@@ -1408,7 +1361,7 @@ static void mwl8k_txq_deinit(struct ieee80211_hw *hw, int index)
        struct mwl8k_priv *priv = hw->priv;
        struct mwl8k_tx_queue *txq = priv->txq + index;
 
-       mwl8k_txq_reclaim(hw, index, 1);
+       mwl8k_txq_reclaim(hw, index, INT_MAX, 1);
 
        kfree(txq->skb);
        txq->skb = NULL;
@@ -1446,11 +1399,9 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb)
        mwl8k_vif = MWL8K_VIF(tx_info->control.vif);
 
        if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
-               u16 seqno = mwl8k_vif->seqno;
-
                wh->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
-               wh->seq_ctrl |= cpu_to_le16(seqno << 4);
-               mwl8k_vif->seqno = seqno++ % 4096;
+               wh->seq_ctrl |= cpu_to_le16(mwl8k_vif->seqno);
+               mwl8k_vif->seqno += 0x10;
        }
 
        /* Setup firmware control bit fields for each frame type.  */
@@ -1459,24 +1410,17 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb)
        if (ieee80211_is_mgmt(wh->frame_control) ||
            ieee80211_is_ctl(wh->frame_control)) {
                txdatarate = 0;
-               qos = mwl8k_qos_setbit_eosp(qos);
-               /* Set Queue size to unspecified */
-               qos = mwl8k_qos_setbit_qlen(qos, 0xff);
+               qos |= MWL8K_QOS_QLEN_UNSPEC | MWL8K_QOS_EOSP;
        } else if (ieee80211_is_data(wh->frame_control)) {
                txdatarate = 1;
                if (is_multicast_ether_addr(wh->addr1))
                        txstatus |= MWL8K_TXD_STATUS_MULTICAST_TX;
 
-               /* Send pkt in an aggregate if AMPDU frame.  */
+               qos &= ~MWL8K_QOS_ACK_POLICY_MASK;
                if (tx_info->flags & IEEE80211_TX_CTL_AMPDU)
-                       qos = mwl8k_qos_setbit_ack(qos,
-                               MWL8K_TXD_ACK_POLICY_BLOCKACK);
+                       qos |= MWL8K_QOS_ACK_POLICY_BLOCKACK;
                else
-                       qos = mwl8k_qos_setbit_ack(qos,
-                               MWL8K_TXD_ACK_POLICY_NORMAL);
-
-               if (qos & IEEE80211_QOS_CONTROL_A_MSDU_PRESENT)
-                       qos = mwl8k_qos_setbit_amsdu(qos);
+                       qos |= MWL8K_QOS_ACK_POLICY_NORMAL;
        }
 
        dma = pci_map_single(priv->pdev, skb->data,
@@ -1503,7 +1447,10 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb)
        tx->pkt_phys_addr = cpu_to_le32(dma);
        tx->pkt_len = cpu_to_le16(skb->len);
        tx->rate_info = 0;
-       tx->peer_id = mwl8k_vif->peer_id;
+       if (!priv->ap_fw && tx_info->control.sta != NULL)
+               tx->peer_id = MWL8K_STA(tx_info->control.sta)->peer_id;
+       else
+               tx->peer_id = 0;
        wmb();
        tx->status = cpu_to_le32(MWL8K_TXD_STATUS_FW_OWNED | txstatus);
 
@@ -1656,6 +1603,56 @@ static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd)
        return rc;
 }
 
+static int mwl8k_post_pervif_cmd(struct ieee80211_hw *hw,
+                                struct ieee80211_vif *vif,
+                                struct mwl8k_cmd_pkt *cmd)
+{
+       if (vif != NULL)
+               cmd->macid = MWL8K_VIF(vif)->macid;
+       return mwl8k_post_cmd(hw, cmd);
+}
+
+/*
+ * Setup code shared between STA and AP firmware images.
+ */
+static void mwl8k_setup_2ghz_band(struct ieee80211_hw *hw)
+{
+       struct mwl8k_priv *priv = hw->priv;
+
+       BUILD_BUG_ON(sizeof(priv->channels_24) != sizeof(mwl8k_channels_24));
+       memcpy(priv->channels_24, mwl8k_channels_24, sizeof(mwl8k_channels_24));
+
+       BUILD_BUG_ON(sizeof(priv->rates_24) != sizeof(mwl8k_rates_24));
+       memcpy(priv->rates_24, mwl8k_rates_24, sizeof(mwl8k_rates_24));
+
+       priv->band_24.band = IEEE80211_BAND_2GHZ;
+       priv->band_24.channels = priv->channels_24;
+       priv->band_24.n_channels = ARRAY_SIZE(mwl8k_channels_24);
+       priv->band_24.bitrates = priv->rates_24;
+       priv->band_24.n_bitrates = ARRAY_SIZE(mwl8k_rates_24);
+
+       hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band_24;
+}
+
+static void mwl8k_setup_5ghz_band(struct ieee80211_hw *hw)
+{
+       struct mwl8k_priv *priv = hw->priv;
+
+       BUILD_BUG_ON(sizeof(priv->channels_50) != sizeof(mwl8k_channels_50));
+       memcpy(priv->channels_50, mwl8k_channels_50, sizeof(mwl8k_channels_50));
+
+       BUILD_BUG_ON(sizeof(priv->rates_50) != sizeof(mwl8k_rates_50));
+       memcpy(priv->rates_50, mwl8k_rates_50, sizeof(mwl8k_rates_50));
+
+       priv->band_50.band = IEEE80211_BAND_5GHZ;
+       priv->band_50.channels = priv->channels_50;
+       priv->band_50.n_channels = ARRAY_SIZE(mwl8k_channels_50);
+       priv->band_50.bitrates = priv->rates_50;
+       priv->band_50.n_bitrates = ARRAY_SIZE(mwl8k_rates_50);
+
+       hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &priv->band_50;
+}
+
 /*
  * CMD_GET_HW_SPEC (STA version).
  */
@@ -1678,6 +1675,89 @@ struct mwl8k_cmd_get_hw_spec_sta {
        __le32 total_rxd;
 } __attribute__((packed));
 
+#define MWL8K_CAP_MAX_AMSDU            0x20000000
+#define MWL8K_CAP_GREENFIELD           0x08000000
+#define MWL8K_CAP_AMPDU                        0x04000000
+#define MWL8K_CAP_RX_STBC              0x01000000
+#define MWL8K_CAP_TX_STBC              0x00800000
+#define MWL8K_CAP_SHORTGI_40MHZ                0x00400000
+#define MWL8K_CAP_SHORTGI_20MHZ                0x00200000
+#define MWL8K_CAP_RX_ANTENNA_MASK      0x000e0000
+#define MWL8K_CAP_TX_ANTENNA_MASK      0x0001c000
+#define MWL8K_CAP_DELAY_BA             0x00003000
+#define MWL8K_CAP_MIMO                 0x00000200
+#define MWL8K_CAP_40MHZ                        0x00000100
+#define MWL8K_CAP_BAND_MASK            0x00000007
+#define MWL8K_CAP_5GHZ                 0x00000004
+#define MWL8K_CAP_2GHZ4                        0x00000001
+
+static void
+mwl8k_set_ht_caps(struct ieee80211_hw *hw,
+                 struct ieee80211_supported_band *band, u32 cap)
+{
+       int rx_streams;
+       int tx_streams;
+
+       band->ht_cap.ht_supported = 1;
+
+       if (cap & MWL8K_CAP_MAX_AMSDU)
+               band->ht_cap.cap |= IEEE80211_HT_CAP_MAX_AMSDU;
+       if (cap & MWL8K_CAP_GREENFIELD)
+               band->ht_cap.cap |= IEEE80211_HT_CAP_GRN_FLD;
+       if (cap & MWL8K_CAP_AMPDU) {
+               hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION;
+               band->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
+               band->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE;
+       }
+       if (cap & MWL8K_CAP_RX_STBC)
+               band->ht_cap.cap |= IEEE80211_HT_CAP_RX_STBC;
+       if (cap & MWL8K_CAP_TX_STBC)
+               band->ht_cap.cap |= IEEE80211_HT_CAP_TX_STBC;
+       if (cap & MWL8K_CAP_SHORTGI_40MHZ)
+               band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
+       if (cap & MWL8K_CAP_SHORTGI_20MHZ)
+               band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_20;
+       if (cap & MWL8K_CAP_DELAY_BA)
+               band->ht_cap.cap |= IEEE80211_HT_CAP_DELAY_BA;
+       if (cap & MWL8K_CAP_40MHZ)
+               band->ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+
+       rx_streams = hweight32(cap & MWL8K_CAP_RX_ANTENNA_MASK);
+       tx_streams = hweight32(cap & MWL8K_CAP_TX_ANTENNA_MASK);
+
+       band->ht_cap.mcs.rx_mask[0] = 0xff;
+       if (rx_streams >= 2)
+               band->ht_cap.mcs.rx_mask[1] = 0xff;
+       if (rx_streams >= 3)
+               band->ht_cap.mcs.rx_mask[2] = 0xff;
+       band->ht_cap.mcs.rx_mask[4] = 0x01;
+       band->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
+
+       if (rx_streams != tx_streams) {
+               band->ht_cap.mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF;
+               band->ht_cap.mcs.tx_params |= (tx_streams - 1) <<
+                               IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT;
+       }
+}
+
+static void
+mwl8k_set_caps(struct ieee80211_hw *hw, u32 caps)
+{
+       struct mwl8k_priv *priv = hw->priv;
+
+       if ((caps & MWL8K_CAP_2GHZ4) || !(caps & MWL8K_CAP_BAND_MASK)) {
+               mwl8k_setup_2ghz_band(hw);
+               if (caps & MWL8K_CAP_MIMO)
+                       mwl8k_set_ht_caps(hw, &priv->band_24, caps);
+       }
+
+       if (caps & MWL8K_CAP_5GHZ) {
+               mwl8k_setup_5ghz_band(hw);
+               if (caps & MWL8K_CAP_MIMO)
+                       mwl8k_set_ht_caps(hw, &priv->band_50, caps);
+       }
+}
+
 static int mwl8k_cmd_get_hw_spec_sta(struct ieee80211_hw *hw)
 {
        struct mwl8k_priv *priv = hw->priv;
@@ -1708,6 +1788,9 @@ static int mwl8k_cmd_get_hw_spec_sta(struct ieee80211_hw *hw)
                priv->num_mcaddrs = le16_to_cpu(cmd->num_mcaddrs);
                priv->fw_rev = le32_to_cpu(cmd->fw_rev);
                priv->hw_rev = cmd->hw_rev;
+               mwl8k_set_caps(hw, le32_to_cpu(cmd->caps));
+               priv->ap_macids_supported = 0x00000000;
+               priv->sta_macids_supported = 0x00000001;
        }
 
        kfree(cmd);
@@ -1761,6 +1844,9 @@ static int mwl8k_cmd_get_hw_spec_ap(struct ieee80211_hw *hw)
                priv->num_mcaddrs = le16_to_cpu(cmd->num_mcaddrs);
                priv->fw_rev = le32_to_cpu(cmd->fw_rev);
                priv->hw_rev = cmd->hw_rev;
+               mwl8k_setup_2ghz_band(hw);
+               priv->ap_macids_supported = 0x000000ff;
+               priv->sta_macids_supported = 0x00000000;
 
                off = le32_to_cpu(cmd->wcbbase0) & 0xffff;
                iowrite32(cpu_to_le32(priv->txq[0].txd_dma), priv->sram + off);
@@ -1806,7 +1892,9 @@ struct mwl8k_cmd_set_hw_spec {
        __le32 total_rxd;
 } __attribute__((packed));
 
-#define MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT  0x00000080
+#define MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT          0x00000080
+#define MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_PROBERESP      0x00000020
+#define MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_BEACON         0x00000010
 
 static int mwl8k_cmd_set_hw_spec(struct ieee80211_hw *hw)
 {
@@ -1827,7 +1915,9 @@ static int mwl8k_cmd_set_hw_spec(struct ieee80211_hw *hw)
        cmd->num_tx_queues = cpu_to_le32(MWL8K_TX_QUEUES);
        for (i = 0; i < MWL8K_TX_QUEUES; i++)
                cmd->tx_queue_ptrs[i] = cpu_to_le32(priv->txq[i].txd_dma);
-       cmd->flags = cpu_to_le32(MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT);
+       cmd->flags = cpu_to_le32(MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT |
+                                MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_PROBERESP |
+                                MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_BEACON);
        cmd->num_tx_desc_per_queue = cpu_to_le32(MWL8K_TX_DESCS);
        cmd->total_rxd = cpu_to_le32(MWL8K_RX_DESCS);
 
@@ -1897,9 +1987,9 @@ __mwl8k_cmd_mac_multicast_adr(struct ieee80211_hw *hw, int allmulti,
 }
 
 /*
- * CMD_802_11_GET_STAT.
+ * CMD_GET_STAT.
  */
-struct mwl8k_cmd_802_11_get_stat {
+struct mwl8k_cmd_get_stat {
        struct mwl8k_cmd_pkt header;
        __le32 stats[64];
 } __attribute__((packed));
@@ -1909,10 +1999,10 @@ struct mwl8k_cmd_802_11_get_stat {
 #define MWL8K_STAT_FCS_ERROR   24
 #define MWL8K_STAT_RTS_SUCCESS 11
 
-static int mwl8k_cmd_802_11_get_stat(struct ieee80211_hw *hw,
-                               struct ieee80211_low_level_stats *stats)
+static int mwl8k_cmd_get_stat(struct ieee80211_hw *hw,
+                             struct ieee80211_low_level_stats *stats)
 {
-       struct mwl8k_cmd_802_11_get_stat *cmd;
+       struct mwl8k_cmd_get_stat *cmd;
        int rc;
 
        cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
@@ -1939,9 +2029,9 @@ static int mwl8k_cmd_802_11_get_stat(struct ieee80211_hw *hw,
 }
 
 /*
- * CMD_802_11_RADIO_CONTROL.
+ * CMD_RADIO_CONTROL.
  */
-struct mwl8k_cmd_802_11_radio_control {
+struct mwl8k_cmd_radio_control {
        struct mwl8k_cmd_pkt header;
        __le16 action;
        __le16 control;
@@ -1949,10 +2039,10 @@ struct mwl8k_cmd_802_11_radio_control {
 } __attribute__((packed));
 
 static int
-mwl8k_cmd_802_11_radio_control(struct ieee80211_hw *hw, bool enable, bool force)
+mwl8k_cmd_radio_control(struct ieee80211_hw *hw, bool enable, bool force)
 {
        struct mwl8k_priv *priv = hw->priv;
-       struct mwl8k_cmd_802_11_radio_control *cmd;
+       struct mwl8k_cmd_radio_control *cmd;
        int rc;
 
        if (enable == priv->radio_on && !force)
@@ -1977,36 +2067,32 @@ mwl8k_cmd_802_11_radio_control(struct ieee80211_hw *hw, bool enable, bool force)
        return rc;
 }
 
-static int mwl8k_cmd_802_11_radio_disable(struct ieee80211_hw *hw)
+static int mwl8k_cmd_radio_disable(struct ieee80211_hw *hw)
 {
-       return mwl8k_cmd_802_11_radio_control(hw, 0, 0);
+       return mwl8k_cmd_radio_control(hw, 0, 0);
 }
 
-static int mwl8k_cmd_802_11_radio_enable(struct ieee80211_hw *hw)
+static int mwl8k_cmd_radio_enable(struct ieee80211_hw *hw)
 {
-       return mwl8k_cmd_802_11_radio_control(hw, 1, 0);
+       return mwl8k_cmd_radio_control(hw, 1, 0);
 }
 
 static int
 mwl8k_set_radio_preamble(struct ieee80211_hw *hw, bool short_preamble)
 {
-       struct mwl8k_priv *priv;
-
-       if (hw == NULL || hw->priv == NULL)
-               return -EINVAL;
-       priv = hw->priv;
+       struct mwl8k_priv *priv = hw->priv;
 
        priv->radio_short_preamble = short_preamble;
 
-       return mwl8k_cmd_802_11_radio_control(hw, 1, 1);
+       return mwl8k_cmd_radio_control(hw, 1, 1);
 }
 
 /*
- * CMD_802_11_RF_TX_POWER.
+ * CMD_RF_TX_POWER.
  */
 #define MWL8K_TX_POWER_LEVEL_TOTAL     8
 
-struct mwl8k_cmd_802_11_rf_tx_power {
+struct mwl8k_cmd_rf_tx_power {
        struct mwl8k_cmd_pkt header;
        __le16 action;
        __le16 support_level;
@@ -2015,9 +2101,9 @@ struct mwl8k_cmd_802_11_rf_tx_power {
        __le16 power_level_list[MWL8K_TX_POWER_LEVEL_TOTAL];
 } __attribute__((packed));
 
-static int mwl8k_cmd_802_11_rf_tx_power(struct ieee80211_hw *hw, int dBm)
+static int mwl8k_cmd_rf_tx_power(struct ieee80211_hw *hw, int dBm)
 {
-       struct mwl8k_cmd_802_11_rf_tx_power *cmd;
+       struct mwl8k_cmd_rf_tx_power *cmd;
        int rc;
 
        cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
@@ -2068,6 +2154,36 @@ mwl8k_cmd_rf_antenna(struct ieee80211_hw *hw, int antenna, int mask)
        return rc;
 }
 
+/*
+ * CMD_SET_BEACON.
+ */
+struct mwl8k_cmd_set_beacon {
+       struct mwl8k_cmd_pkt header;
+       __le16 beacon_len;
+       __u8 beacon[0];
+};
+
+static int mwl8k_cmd_set_beacon(struct ieee80211_hw *hw,
+                               struct ieee80211_vif *vif, u8 *beacon, int len)
+{
+       struct mwl8k_cmd_set_beacon *cmd;
+       int rc;
+
+       cmd = kzalloc(sizeof(*cmd) + len, GFP_KERNEL);
+       if (cmd == NULL)
+               return -ENOMEM;
+
+       cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_BEACON);
+       cmd->header.length = cpu_to_le16(sizeof(*cmd) + len);
+       cmd->beacon_len = cpu_to_le16(len);
+       memcpy(cmd->beacon, beacon, len);
+
+       rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header);
+       kfree(cmd);
+
+       return rc;
+}
+
 /*
  * CMD_SET_PRE_SCAN.
  */
@@ -2103,7 +2219,7 @@ struct mwl8k_cmd_set_post_scan {
 } __attribute__((packed));
 
 static int
-mwl8k_cmd_set_post_scan(struct ieee80211_hw *hw, __u8 *mac)
+mwl8k_cmd_set_post_scan(struct ieee80211_hw *hw, const __u8 *mac)
 {
        struct mwl8k_cmd_set_post_scan *cmd;
        int rc;
@@ -2134,8 +2250,9 @@ struct mwl8k_cmd_set_rf_channel {
 } __attribute__((packed));
 
 static int mwl8k_cmd_set_rf_channel(struct ieee80211_hw *hw,
-                                   struct ieee80211_channel *channel)
+                                   struct ieee80211_conf *conf)
 {
+       struct ieee80211_channel *channel = conf->channel;
        struct mwl8k_cmd_set_rf_channel *cmd;
        int rc;
 
@@ -2147,10 +2264,19 @@ static int mwl8k_cmd_set_rf_channel(struct ieee80211_hw *hw,
        cmd->header.length = cpu_to_le16(sizeof(*cmd));
        cmd->action = cpu_to_le16(MWL8K_CMD_SET);
        cmd->current_channel = channel->hw_value;
+
        if (channel->band == IEEE80211_BAND_2GHZ)
-               cmd->channel_flags = cpu_to_le32(0x00000081);
-       else
-               cmd->channel_flags = cpu_to_le32(0x00000000);
+               cmd->channel_flags |= cpu_to_le32(0x00000001);
+       else if (channel->band == IEEE80211_BAND_5GHZ)
+               cmd->channel_flags |= cpu_to_le32(0x00000004);
+
+       if (conf->channel_type == NL80211_CHAN_NO_HT ||
+           conf->channel_type == NL80211_CHAN_HT20)
+               cmd->channel_flags |= cpu_to_le32(0x00000080);
+       else if (conf->channel_type == NL80211_CHAN_HT40MINUS)
+               cmd->channel_flags |= cpu_to_le32(0x000001900);
+       else if (conf->channel_type == NL80211_CHAN_HT40PLUS)
+               cmd->channel_flags |= cpu_to_le32(0x000000900);
 
        rc = mwl8k_post_cmd(hw, &cmd->header);
        kfree(cmd);
@@ -2159,27 +2285,75 @@ static int mwl8k_cmd_set_rf_channel(struct ieee80211_hw *hw,
 }
 
 /*
- * CMD_SET_SLOT.
+ * CMD_SET_AID.
  */
-struct mwl8k_cmd_set_slot {
-       struct mwl8k_cmd_pkt header;
-       __le16 action;
-       __u8 short_slot;
+#define MWL8K_FRAME_PROT_DISABLED                      0x00
+#define MWL8K_FRAME_PROT_11G                           0x07
+#define MWL8K_FRAME_PROT_11N_HT_40MHZ_ONLY             0x02
+#define MWL8K_FRAME_PROT_11N_HT_ALL                    0x06
+
+struct mwl8k_cmd_update_set_aid {
+       struct  mwl8k_cmd_pkt header;
+       __le16  aid;
+
+        /* AP's MAC address (BSSID) */
+       __u8    bssid[ETH_ALEN];
+       __le16  protection_mode;
+       __u8    supp_rates[14];
 } __attribute__((packed));
 
-static int mwl8k_cmd_set_slot(struct ieee80211_hw *hw, bool short_slot_time)
+static void legacy_rate_mask_to_array(u8 *rates, u32 mask)
 {
-       struct mwl8k_cmd_set_slot *cmd;
+       int i;
+       int j;
+
+       /*
+        * Clear nonstandard rates 4 and 13.
+        */
+       mask &= 0x1fef;
+
+       for (i = 0, j = 0; i < 14; i++) {
+               if (mask & (1 << i))
+                       rates[j++] = mwl8k_rates_24[i].hw_value;
+       }
+}
+
+static int
+mwl8k_cmd_set_aid(struct ieee80211_hw *hw,
+                 struct ieee80211_vif *vif, u32 legacy_rate_mask)
+{
+       struct mwl8k_cmd_update_set_aid *cmd;
+       u16 prot_mode;
        int rc;
 
        cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
        if (cmd == NULL)
                return -ENOMEM;
 
-       cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_SLOT);
+       cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_AID);
        cmd->header.length = cpu_to_le16(sizeof(*cmd));
-       cmd->action = cpu_to_le16(MWL8K_CMD_SET);
-       cmd->short_slot = short_slot_time;
+       cmd->aid = cpu_to_le16(vif->bss_conf.aid);
+       memcpy(cmd->bssid, vif->bss_conf.bssid, ETH_ALEN);
+
+       if (vif->bss_conf.use_cts_prot) {
+               prot_mode = MWL8K_FRAME_PROT_11G;
+       } else {
+               switch (vif->bss_conf.ht_operation_mode &
+                       IEEE80211_HT_OP_MODE_PROTECTION) {
+               case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ:
+                       prot_mode = MWL8K_FRAME_PROT_11N_HT_40MHZ_ONLY;
+                       break;
+               case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED:
+                       prot_mode = MWL8K_FRAME_PROT_11N_HT_ALL;
+                       break;
+               default:
+                       prot_mode = MWL8K_FRAME_PROT_DISABLED;
+                       break;
+               }
+       }
+       cmd->protection_mode = cpu_to_le16(prot_mode);
+
+       legacy_rate_mask_to_array(cmd->supp_rates, legacy_rate_mask);
 
        rc = mwl8k_post_cmd(hw, &cmd->header);
        kfree(cmd);
@@ -2188,29 +2362,32 @@ static int mwl8k_cmd_set_slot(struct ieee80211_hw *hw, bool short_slot_time)
 }
 
 /*
- * CMD_MIMO_CONFIG.
+ * CMD_SET_RATE.
  */
-struct mwl8k_cmd_mimo_config {
-       struct mwl8k_cmd_pkt header;
-       __le32 action;
-       __u8 rx_antenna_map;
-       __u8 tx_antenna_map;
+struct mwl8k_cmd_set_rate {
+       struct  mwl8k_cmd_pkt header;
+       __u8    legacy_rates[14];
+
+       /* Bitmap for supported MCS codes.  */
+       __u8    mcs_set[16];
+       __u8    reserved[16];
 } __attribute__((packed));
 
-static int mwl8k_cmd_mimo_config(struct ieee80211_hw *hw, __u8 rx, __u8 tx)
+static int
+mwl8k_cmd_set_rate(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+                  u32 legacy_rate_mask, u8 *mcs_rates)
 {
-       struct mwl8k_cmd_mimo_config *cmd;
+       struct mwl8k_cmd_set_rate *cmd;
        int rc;
 
        cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
        if (cmd == NULL)
                return -ENOMEM;
 
-       cmd->header.code = cpu_to_le16(MWL8K_CMD_MIMO_CONFIG);
+       cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_RATE);
        cmd->header.length = cpu_to_le16(sizeof(*cmd));
-       cmd->action = cpu_to_le32((u32)MWL8K_CMD_SET);
-       cmd->rx_antenna_map = rx;
-       cmd->tx_antenna_map = tx;
+       legacy_rate_mask_to_array(cmd->legacy_rates, legacy_rate_mask);
+       memcpy(cmd->mcs_set, mcs_rates, 16);
 
        rc = mwl8k_post_cmd(hw, &cmd->header);
        kfree(cmd);
@@ -2219,64 +2396,39 @@ static int mwl8k_cmd_mimo_config(struct ieee80211_hw *hw, __u8 rx, __u8 tx)
 }
 
 /*
- * CMD_ENABLE_SNIFFER.
+ * CMD_FINALIZE_JOIN.
  */
-struct mwl8k_cmd_enable_sniffer {
+#define MWL8K_FJ_BEACON_MAXLEN 128
+
+struct mwl8k_cmd_finalize_join {
        struct mwl8k_cmd_pkt header;
-       __le32 action;
+       __le32 sleep_interval;  /* Number of beacon periods to sleep */
+       __u8 beacon_data[MWL8K_FJ_BEACON_MAXLEN];
 } __attribute__((packed));
 
-static int mwl8k_enable_sniffer(struct ieee80211_hw *hw, bool enable)
+static int mwl8k_cmd_finalize_join(struct ieee80211_hw *hw, void *frame,
+                                  int framelen, int dtim)
 {
-       struct mwl8k_cmd_enable_sniffer *cmd;
+       struct mwl8k_cmd_finalize_join *cmd;
+       struct ieee80211_mgmt *payload = frame;
+       int payload_len;
        int rc;
 
        cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
        if (cmd == NULL)
                return -ENOMEM;
 
-       cmd->header.code = cpu_to_le16(MWL8K_CMD_ENABLE_SNIFFER);
+       cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_FINALIZE_JOIN);
        cmd->header.length = cpu_to_le16(sizeof(*cmd));
-       cmd->action = cpu_to_le32(!!enable);
-
-       rc = mwl8k_post_cmd(hw, &cmd->header);
-       kfree(cmd);
-
-       return rc;
-}
-
-/*
- * CMD_SET_MAC_ADDR.
- */
-struct mwl8k_cmd_set_mac_addr {
-       struct mwl8k_cmd_pkt header;
-       union {
-               struct {
-                       __le16 mac_type;
-                       __u8 mac_addr[ETH_ALEN];
-               } mbss;
-               __u8 mac_addr[ETH_ALEN];
-       };
-} __attribute__((packed));
-
-static int mwl8k_set_mac_addr(struct ieee80211_hw *hw, u8 *mac)
-{
-       struct mwl8k_priv *priv = hw->priv;
-       struct mwl8k_cmd_set_mac_addr *cmd;
-       int rc;
+       cmd->sleep_interval = cpu_to_le32(dtim ? dtim : 1);
 
-       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
-       if (cmd == NULL)
-               return -ENOMEM;
+       payload_len = framelen - ieee80211_hdrlen(payload->frame_control);
+       if (payload_len < 0)
+               payload_len = 0;
+       else if (payload_len > MWL8K_FJ_BEACON_MAXLEN)
+               payload_len = MWL8K_FJ_BEACON_MAXLEN;
 
-       cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_MAC_ADDR);
-       cmd->header.length = cpu_to_le16(sizeof(*cmd));
-       if (priv->ap_fw) {
-               cmd->mbss.mac_type = 0;
-               memcpy(cmd->mbss.mac_addr, mac, ETH_ALEN);
-       } else {
-               memcpy(cmd->mac_addr, mac, ETH_ALEN);
-       }
+       memcpy(cmd->beacon_data, &payload->u.beacon, payload_len);
 
        rc = mwl8k_post_cmd(hw, &cmd->header);
        kfree(cmd);
@@ -2284,29 +2436,29 @@ static int mwl8k_set_mac_addr(struct ieee80211_hw *hw, u8 *mac)
        return rc;
 }
 
-
 /*
- * CMD_SET_RATEADAPT_MODE.
+ * CMD_SET_RTS_THRESHOLD.
  */
-struct mwl8k_cmd_set_rate_adapt_mode {
+struct mwl8k_cmd_set_rts_threshold {
        struct mwl8k_cmd_pkt header;
        __le16 action;
-       __le16 mode;
+       __le16 threshold;
 } __attribute__((packed));
 
-static int mwl8k_cmd_setrateadaptmode(struct ieee80211_hw *hw, __u16 mode)
+static int
+mwl8k_cmd_set_rts_threshold(struct ieee80211_hw *hw, int rts_thresh)
 {
-       struct mwl8k_cmd_set_rate_adapt_mode *cmd;
+       struct mwl8k_cmd_set_rts_threshold *cmd;
        int rc;
 
        cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
        if (cmd == NULL)
                return -ENOMEM;
 
-       cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_RATEADAPT_MODE);
+       cmd->header.code = cpu_to_le16(MWL8K_CMD_RTS_THRESHOLD);
        cmd->header.length = cpu_to_le16(sizeof(*cmd));
        cmd->action = cpu_to_le16(MWL8K_CMD_SET);
-       cmd->mode = cpu_to_le16(mode);
+       cmd->threshold = cpu_to_le16(rts_thresh);
 
        rc = mwl8k_post_cmd(hw, &cmd->header);
        kfree(cmd);
@@ -2315,59 +2467,27 @@ static int mwl8k_cmd_setrateadaptmode(struct ieee80211_hw *hw, __u16 mode)
 }
 
 /*
- * CMD_SET_WMM_MODE.
- */
-struct mwl8k_cmd_set_wmm {
-       struct mwl8k_cmd_pkt header;
-       __le16 action;
-} __attribute__((packed));
-
-static int mwl8k_set_wmm(struct ieee80211_hw *hw, bool enable)
-{
-       struct mwl8k_priv *priv = hw->priv;
-       struct mwl8k_cmd_set_wmm *cmd;
-       int rc;
-
-       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
-       if (cmd == NULL)
-               return -ENOMEM;
-
-       cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_WMM_MODE);
-       cmd->header.length = cpu_to_le16(sizeof(*cmd));
-       cmd->action = cpu_to_le16(!!enable);
-
-       rc = mwl8k_post_cmd(hw, &cmd->header);
-       kfree(cmd);
-
-       if (!rc)
-               priv->wmm_enabled = enable;
-
-       return rc;
-}
-
-/*
- * CMD_SET_RTS_THRESHOLD.
+ * CMD_SET_SLOT.
  */
-struct mwl8k_cmd_rts_threshold {
+struct mwl8k_cmd_set_slot {
        struct mwl8k_cmd_pkt header;
        __le16 action;
-       __le16 threshold;
+       __u8 short_slot;
 } __attribute__((packed));
 
-static int mwl8k_rts_threshold(struct ieee80211_hw *hw,
-                              u16 action, u16 threshold)
+static int mwl8k_cmd_set_slot(struct ieee80211_hw *hw, bool short_slot_time)
 {
-       struct mwl8k_cmd_rts_threshold *cmd;
+       struct mwl8k_cmd_set_slot *cmd;
        int rc;
 
        cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
        if (cmd == NULL)
                return -ENOMEM;
 
-       cmd->header.code = cpu_to_le16(MWL8K_CMD_RTS_THRESHOLD);
+       cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_SLOT);
        cmd->header.length = cpu_to_le16(sizeof(*cmd));
-       cmd->action = cpu_to_le16(action);
-       cmd->threshold = cpu_to_le16(threshold);
+       cmd->action = cpu_to_le16(MWL8K_CMD_SET);
+       cmd->short_slot = short_slot_time;
 
        rc = mwl8k_post_cmd(hw, &cmd->header);
        kfree(cmd);
@@ -2426,9 +2546,9 @@ struct mwl8k_cmd_set_edca_params {
                                 MWL8K_SET_EDCA_AIFS)
 
 static int
-mwl8k_set_edca_params(struct ieee80211_hw *hw, __u8 qnum,
-               __u16 cw_min, __u16 cw_max,
-               __u8 aifs, __u16 txop)
+mwl8k_cmd_set_edca_params(struct ieee80211_hw *hw, __u8 qnum,
+                         __u16 cw_min, __u16 cw_max,
+                         __u8 aifs, __u16 txop)
 {
        struct mwl8k_priv *priv = hw->priv;
        struct mwl8k_cmd_set_edca_params *cmd;
@@ -2438,12 +2558,6 @@ mwl8k_set_edca_params(struct ieee80211_hw *hw, __u8 qnum,
        if (cmd == NULL)
                return -ENOMEM;
 
-       /*
-        * Queues 0 (BE) and 1 (BK) are swapped in hardware for
-        * this call.
-        */
-       qnum ^= !(qnum >> 1);
-
        cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_EDCA_PARAMS);
        cmd->header.length = cpu_to_le16(sizeof(*cmd));
        cmd->action = cpu_to_le16(MWL8K_SET_EDCA_ALL);
@@ -2467,170 +2581,259 @@ mwl8k_set_edca_params(struct ieee80211_hw *hw, __u8 qnum,
 }
 
 /*
- * CMD_FINALIZE_JOIN.
+ * CMD_SET_WMM_MODE.
  */
-#define MWL8K_FJ_BEACON_MAXLEN 128
-
-struct mwl8k_cmd_finalize_join {
+struct mwl8k_cmd_set_wmm_mode {
        struct mwl8k_cmd_pkt header;
-       __le32 sleep_interval;  /* Number of beacon periods to sleep */
-       __u8 beacon_data[MWL8K_FJ_BEACON_MAXLEN];
+       __le16 action;
 } __attribute__((packed));
 
-static int mwl8k_finalize_join(struct ieee80211_hw *hw, void *frame,
-                              int framelen, int dtim)
+static int mwl8k_cmd_set_wmm_mode(struct ieee80211_hw *hw, bool enable)
 {
-       struct mwl8k_cmd_finalize_join *cmd;
-       struct ieee80211_mgmt *payload = frame;
-       int payload_len;
+       struct mwl8k_priv *priv = hw->priv;
+       struct mwl8k_cmd_set_wmm_mode *cmd;
        int rc;
 
        cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
        if (cmd == NULL)
                return -ENOMEM;
 
-       cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_FINALIZE_JOIN);
+       cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_WMM_MODE);
        cmd->header.length = cpu_to_le16(sizeof(*cmd));
-       cmd->sleep_interval = cpu_to_le32(dtim ? dtim : 1);
-
-       payload_len = framelen - ieee80211_hdrlen(payload->frame_control);
-       if (payload_len < 0)
-               payload_len = 0;
-       else if (payload_len > MWL8K_FJ_BEACON_MAXLEN)
-               payload_len = MWL8K_FJ_BEACON_MAXLEN;
-
-       memcpy(cmd->beacon_data, &payload->u.beacon, payload_len);
+       cmd->action = cpu_to_le16(!!enable);
 
        rc = mwl8k_post_cmd(hw, &cmd->header);
        kfree(cmd);
 
+       if (!rc)
+               priv->wmm_enabled = enable;
+
        return rc;
 }
 
 /*
- * CMD_UPDATE_STADB.
+ * CMD_MIMO_CONFIG.
  */
-struct mwl8k_cmd_update_sta_db {
+struct mwl8k_cmd_mimo_config {
        struct mwl8k_cmd_pkt header;
+       __le32 action;
+       __u8 rx_antenna_map;
+       __u8 tx_antenna_map;
+} __attribute__((packed));
 
-       /* See STADB_ACTION_TYPE */
-       __le32  action;
+static int mwl8k_cmd_mimo_config(struct ieee80211_hw *hw, __u8 rx, __u8 tx)
+{
+       struct mwl8k_cmd_mimo_config *cmd;
+       int rc;
 
-       /* Peer MAC address */
-       __u8    peer_addr[ETH_ALEN];
+       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+       if (cmd == NULL)
+               return -ENOMEM;
 
-       __le32  reserved;
+       cmd->header.code = cpu_to_le16(MWL8K_CMD_MIMO_CONFIG);
+       cmd->header.length = cpu_to_le16(sizeof(*cmd));
+       cmd->action = cpu_to_le32((u32)MWL8K_CMD_SET);
+       cmd->rx_antenna_map = rx;
+       cmd->tx_antenna_map = tx;
 
-       /* Peer info - valid during add/update.  */
-       struct peer_capability_info     peer_info;
+       rc = mwl8k_post_cmd(hw, &cmd->header);
+       kfree(cmd);
+
+       return rc;
+}
+
+/*
+ * CMD_USE_FIXED_RATE (STA version).
+ */
+struct mwl8k_cmd_use_fixed_rate_sta {
+       struct mwl8k_cmd_pkt header;
+       __le32 action;
+       __le32 allow_rate_drop;
+       __le32 num_rates;
+       struct {
+               __le32 is_ht_rate;
+               __le32 enable_retry;
+               __le32 rate;
+               __le32 retry_count;
+       } rate_entry[8];
+       __le32 rate_type;
+       __le32 reserved1;
+       __le32 reserved2;
 } __attribute__((packed));
 
-static int mwl8k_cmd_update_sta_db(struct ieee80211_hw *hw,
-               struct ieee80211_vif *vif, __u32 action)
+#define MWL8K_USE_AUTO_RATE    0x0002
+#define MWL8K_UCAST_RATE       0
+
+static int mwl8k_cmd_use_fixed_rate_sta(struct ieee80211_hw *hw)
 {
-       struct mwl8k_vif *mv_vif = MWL8K_VIF(vif);
-       struct ieee80211_bss_conf *info = &mv_vif->bss_info;
-       struct mwl8k_cmd_update_sta_db *cmd;
-       struct peer_capability_info *peer_info;
+       struct mwl8k_cmd_use_fixed_rate_sta *cmd;
        int rc;
 
        cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
        if (cmd == NULL)
                return -ENOMEM;
 
-       cmd->header.code = cpu_to_le16(MWL8K_CMD_UPDATE_STADB);
+       cmd->header.code = cpu_to_le16(MWL8K_CMD_USE_FIXED_RATE);
        cmd->header.length = cpu_to_le16(sizeof(*cmd));
+       cmd->action = cpu_to_le32(MWL8K_USE_AUTO_RATE);
+       cmd->rate_type = cpu_to_le32(MWL8K_UCAST_RATE);
 
-       cmd->action = cpu_to_le32(action);
-       peer_info = &cmd->peer_info;
-       memcpy(cmd->peer_addr, mv_vif->bssid, ETH_ALEN);
+       rc = mwl8k_post_cmd(hw, &cmd->header);
+       kfree(cmd);
 
-       switch (action) {
-       case MWL8K_STA_DB_ADD_ENTRY:
-       case MWL8K_STA_DB_MODIFY_ENTRY:
-               /* Build peer_info block */
-               peer_info->peer_type = MWL8K_PEER_TYPE_ACCESSPOINT;
-               peer_info->basic_caps = cpu_to_le16(info->assoc_capability);
-               memcpy(peer_info->legacy_rates, mwl8k_rateids,
-                      sizeof(mwl8k_rateids));
-               peer_info->interop = 1;
-               peer_info->amsdu_enabled = 0;
-
-               rc = mwl8k_post_cmd(hw, &cmd->header);
-               if (rc == 0)
-                       mv_vif->peer_id = peer_info->station_id;
+       return rc;
+}
 
-               break;
+/*
+ * CMD_USE_FIXED_RATE (AP version).
+ */
+struct mwl8k_cmd_use_fixed_rate_ap {
+       struct mwl8k_cmd_pkt header;
+       __le32 action;
+       __le32 allow_rate_drop;
+       __le32 num_rates;
+       struct mwl8k_rate_entry_ap {
+               __le32 is_ht_rate;
+               __le32 enable_retry;
+               __le32 rate;
+               __le32 retry_count;
+       } rate_entry[4];
+       u8 multicast_rate;
+       u8 multicast_rate_type;
+       u8 management_rate;
+} __attribute__((packed));
 
-       case MWL8K_STA_DB_DEL_ENTRY:
-       case MWL8K_STA_DB_FLUSH:
-       default:
-               rc = mwl8k_post_cmd(hw, &cmd->header);
-               if (rc == 0)
-                       mv_vif->peer_id = 0;
-               break;
-       }
+static int
+mwl8k_cmd_use_fixed_rate_ap(struct ieee80211_hw *hw, int mcast, int mgmt)
+{
+       struct mwl8k_cmd_use_fixed_rate_ap *cmd;
+       int rc;
+
+       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+       if (cmd == NULL)
+               return -ENOMEM;
+
+       cmd->header.code = cpu_to_le16(MWL8K_CMD_USE_FIXED_RATE);
+       cmd->header.length = cpu_to_le16(sizeof(*cmd));
+       cmd->action = cpu_to_le32(MWL8K_USE_AUTO_RATE);
+       cmd->multicast_rate = mcast;
+       cmd->management_rate = mgmt;
+
+       rc = mwl8k_post_cmd(hw, &cmd->header);
        kfree(cmd);
 
        return rc;
 }
 
 /*
- * CMD_SET_AID.
+ * CMD_ENABLE_SNIFFER.
  */
-#define MWL8K_FRAME_PROT_DISABLED                      0x00
-#define MWL8K_FRAME_PROT_11G                           0x07
-#define MWL8K_FRAME_PROT_11N_HT_40MHZ_ONLY             0x02
-#define MWL8K_FRAME_PROT_11N_HT_ALL                    0x06
-
-struct mwl8k_cmd_update_set_aid {
-       struct  mwl8k_cmd_pkt header;
-       __le16  aid;
-
-        /* AP's MAC address (BSSID) */
-       __u8    bssid[ETH_ALEN];
-       __le16  protection_mode;
-       __u8    supp_rates[14];
+struct mwl8k_cmd_enable_sniffer {
+       struct mwl8k_cmd_pkt header;
+       __le32 action;
 } __attribute__((packed));
 
-static int mwl8k_cmd_set_aid(struct ieee80211_hw *hw,
-                                       struct ieee80211_vif *vif)
+static int mwl8k_cmd_enable_sniffer(struct ieee80211_hw *hw, bool enable)
 {
-       struct mwl8k_vif *mv_vif = MWL8K_VIF(vif);
-       struct ieee80211_bss_conf *info = &mv_vif->bss_info;
-       struct mwl8k_cmd_update_set_aid *cmd;
-       u16 prot_mode;
+       struct mwl8k_cmd_enable_sniffer *cmd;
        int rc;
 
        cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
        if (cmd == NULL)
                return -ENOMEM;
 
-       cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_AID);
+       cmd->header.code = cpu_to_le16(MWL8K_CMD_ENABLE_SNIFFER);
        cmd->header.length = cpu_to_le16(sizeof(*cmd));
-       cmd->aid = cpu_to_le16(info->aid);
+       cmd->action = cpu_to_le32(!!enable);
+
+       rc = mwl8k_post_cmd(hw, &cmd->header);
+       kfree(cmd);
 
-       memcpy(cmd->bssid, mv_vif->bssid, ETH_ALEN);
+       return rc;
+}
 
-       if (info->use_cts_prot) {
-               prot_mode = MWL8K_FRAME_PROT_11G;
+/*
+ * CMD_SET_MAC_ADDR.
+ */
+struct mwl8k_cmd_set_mac_addr {
+       struct mwl8k_cmd_pkt header;
+       union {
+               struct {
+                       __le16 mac_type;
+                       __u8 mac_addr[ETH_ALEN];
+               } mbss;
+               __u8 mac_addr[ETH_ALEN];
+       };
+} __attribute__((packed));
+
+#define MWL8K_MAC_TYPE_PRIMARY_CLIENT          0
+#define MWL8K_MAC_TYPE_SECONDARY_CLIENT                1
+#define MWL8K_MAC_TYPE_PRIMARY_AP              2
+#define MWL8K_MAC_TYPE_SECONDARY_AP            3
+
+static int mwl8k_cmd_set_mac_addr(struct ieee80211_hw *hw,
+                                 struct ieee80211_vif *vif, u8 *mac)
+{
+       struct mwl8k_priv *priv = hw->priv;
+       struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif);
+       struct mwl8k_cmd_set_mac_addr *cmd;
+       int mac_type;
+       int rc;
+
+       mac_type = MWL8K_MAC_TYPE_PRIMARY_AP;
+       if (vif != NULL && vif->type == NL80211_IFTYPE_STATION) {
+               if (mwl8k_vif->macid + 1 == ffs(priv->sta_macids_supported))
+                       mac_type = MWL8K_MAC_TYPE_PRIMARY_CLIENT;
+               else
+                       mac_type = MWL8K_MAC_TYPE_SECONDARY_CLIENT;
+       } else if (vif != NULL && vif->type == NL80211_IFTYPE_AP) {
+               if (mwl8k_vif->macid + 1 == ffs(priv->ap_macids_supported))
+                       mac_type = MWL8K_MAC_TYPE_PRIMARY_AP;
+               else
+                       mac_type = MWL8K_MAC_TYPE_SECONDARY_AP;
+       }
+
+       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+       if (cmd == NULL)
+               return -ENOMEM;
+
+       cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_MAC_ADDR);
+       cmd->header.length = cpu_to_le16(sizeof(*cmd));
+       if (priv->ap_fw) {
+               cmd->mbss.mac_type = cpu_to_le16(mac_type);
+               memcpy(cmd->mbss.mac_addr, mac, ETH_ALEN);
        } else {
-               switch (info->ht_operation_mode &
-                       IEEE80211_HT_OP_MODE_PROTECTION) {
-               case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ:
-                       prot_mode = MWL8K_FRAME_PROT_11N_HT_40MHZ_ONLY;
-                       break;
-               case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED:
-                       prot_mode = MWL8K_FRAME_PROT_11N_HT_ALL;
-                       break;
-               default:
-                       prot_mode = MWL8K_FRAME_PROT_DISABLED;
-                       break;
-               }
+               memcpy(cmd->mac_addr, mac, ETH_ALEN);
        }
-       cmd->protection_mode = cpu_to_le16(prot_mode);
 
-       memcpy(cmd->supp_rates, mwl8k_rateids, sizeof(mwl8k_rateids));
+       rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header);
+       kfree(cmd);
+
+       return rc;
+}
+
+/*
+ * CMD_SET_RATEADAPT_MODE.
+ */
+struct mwl8k_cmd_set_rate_adapt_mode {
+       struct mwl8k_cmd_pkt header;
+       __le16 action;
+       __le16 mode;
+} __attribute__((packed));
+
+static int mwl8k_cmd_set_rateadapt_mode(struct ieee80211_hw *hw, __u16 mode)
+{
+       struct mwl8k_cmd_set_rate_adapt_mode *cmd;
+       int rc;
+
+       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+       if (cmd == NULL)
+               return -ENOMEM;
+
+       cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_RATEADAPT_MODE);
+       cmd->header.length = cpu_to_le16(sizeof(*cmd));
+       cmd->action = cpu_to_le16(MWL8K_CMD_SET);
+       cmd->mode = cpu_to_le16(mode);
 
        rc = mwl8k_post_cmd(hw, &cmd->header);
        kfree(cmd);
@@ -2639,115 +2842,255 @@ static int mwl8k_cmd_set_aid(struct ieee80211_hw *hw,
 }
 
 /*
- * CMD_SET_RATE.
+ * CMD_BSS_START.
  */
-struct mwl8k_cmd_update_rateset {
-       struct  mwl8k_cmd_pkt header;
-       __u8    legacy_rates[14];
-
-       /* Bitmap for supported MCS codes.  */
-       __u8    mcs_set[16];
-       __u8    reserved[16];
+struct mwl8k_cmd_bss_start {
+       struct mwl8k_cmd_pkt header;
+       __le32 enable;
 } __attribute__((packed));
 
-static int mwl8k_update_rateset(struct ieee80211_hw *hw,
-               struct ieee80211_vif *vif)
+static int mwl8k_cmd_bss_start(struct ieee80211_hw *hw,
+                              struct ieee80211_vif *vif, int enable)
 {
-       struct mwl8k_cmd_update_rateset *cmd;
+       struct mwl8k_cmd_bss_start *cmd;
        int rc;
 
        cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
        if (cmd == NULL)
                return -ENOMEM;
 
-       cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_RATE);
+       cmd->header.code = cpu_to_le16(MWL8K_CMD_BSS_START);
        cmd->header.length = cpu_to_le16(sizeof(*cmd));
-       memcpy(cmd->legacy_rates, mwl8k_rateids, sizeof(mwl8k_rateids));
+       cmd->enable = cpu_to_le32(enable);
 
-       rc = mwl8k_post_cmd(hw, &cmd->header);
+       rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header);
        kfree(cmd);
 
        return rc;
 }
 
 /*
- * CMD_USE_FIXED_RATE.
+ * CMD_SET_NEW_STN.
  */
-#define MWL8K_RATE_TABLE_SIZE  8
-#define MWL8K_UCAST_RATE       0
-#define MWL8K_USE_AUTO_RATE    0x0002
+struct mwl8k_cmd_set_new_stn {
+       struct mwl8k_cmd_pkt header;
+       __le16 aid;
+       __u8 mac_addr[6];
+       __le16 stn_id;
+       __le16 action;
+       __le16 rsvd;
+       __le32 legacy_rates;
+       __u8 ht_rates[4];
+       __le16 cap_info;
+       __le16 ht_capabilities_info;
+       __u8 mac_ht_param_info;
+       __u8 rev;
+       __u8 control_channel;
+       __u8 add_channel;
+       __le16 op_mode;
+       __le16 stbc;
+       __u8 add_qos_info;
+       __u8 is_qos_sta;
+       __le32 fw_sta_ptr;
+} __attribute__((packed));
 
-struct mwl8k_rate_entry {
-       /* Set to 1 if HT rate, 0 if legacy.  */
-       __le32  is_ht_rate;
+#define MWL8K_STA_ACTION_ADD           0
+#define MWL8K_STA_ACTION_REMOVE                2
 
-       /* Set to 1 to use retry_count field.  */
-       __le32  enable_retry;
+static int mwl8k_cmd_set_new_stn_add(struct ieee80211_hw *hw,
+                                    struct ieee80211_vif *vif,
+                                    struct ieee80211_sta *sta)
+{
+       struct mwl8k_cmd_set_new_stn *cmd;
+       u32 rates;
+       int rc;
 
-       /* Specified legacy rate or MCS.  */
-       __le32  rate;
+       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+       if (cmd == NULL)
+               return -ENOMEM;
+
+       cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_NEW_STN);
+       cmd->header.length = cpu_to_le16(sizeof(*cmd));
+       cmd->aid = cpu_to_le16(sta->aid);
+       memcpy(cmd->mac_addr, sta->addr, ETH_ALEN);
+       cmd->stn_id = cpu_to_le16(sta->aid);
+       cmd->action = cpu_to_le16(MWL8K_STA_ACTION_ADD);
+       if (hw->conf.channel->band == IEEE80211_BAND_2GHZ)
+               rates = sta->supp_rates[IEEE80211_BAND_2GHZ];
+       else
+               rates = sta->supp_rates[IEEE80211_BAND_5GHZ] << 5;
+       cmd->legacy_rates = cpu_to_le32(rates);
+       if (sta->ht_cap.ht_supported) {
+               cmd->ht_rates[0] = sta->ht_cap.mcs.rx_mask[0];
+               cmd->ht_rates[1] = sta->ht_cap.mcs.rx_mask[1];
+               cmd->ht_rates[2] = sta->ht_cap.mcs.rx_mask[2];
+               cmd->ht_rates[3] = sta->ht_cap.mcs.rx_mask[3];
+               cmd->ht_capabilities_info = cpu_to_le16(sta->ht_cap.cap);
+               cmd->mac_ht_param_info = (sta->ht_cap.ampdu_factor & 3) |
+                       ((sta->ht_cap.ampdu_density & 7) << 2);
+               cmd->is_qos_sta = 1;
+       }
+
+       rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header);
+       kfree(cmd);
+
+       return rc;
+}
+
+static int mwl8k_cmd_set_new_stn_add_self(struct ieee80211_hw *hw,
+                                         struct ieee80211_vif *vif)
+{
+       struct mwl8k_cmd_set_new_stn *cmd;
+       int rc;
+
+       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+       if (cmd == NULL)
+               return -ENOMEM;
+
+       cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_NEW_STN);
+       cmd->header.length = cpu_to_le16(sizeof(*cmd));
+       memcpy(cmd->mac_addr, vif->addr, ETH_ALEN);
+
+       rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header);
+       kfree(cmd);
+
+       return rc;
+}
+
+static int mwl8k_cmd_set_new_stn_del(struct ieee80211_hw *hw,
+                                    struct ieee80211_vif *vif, u8 *addr)
+{
+       struct mwl8k_cmd_set_new_stn *cmd;
+       int rc;
 
-       /* Number of allowed retries.  */
-       __le32  retry_count;
+       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+       if (cmd == NULL)
+               return -ENOMEM;
+
+       cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_NEW_STN);
+       cmd->header.length = cpu_to_le16(sizeof(*cmd));
+       memcpy(cmd->mac_addr, addr, ETH_ALEN);
+       cmd->action = cpu_to_le16(MWL8K_STA_ACTION_REMOVE);
+
+       rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header);
+       kfree(cmd);
+
+       return rc;
+}
+
+/*
+ * CMD_UPDATE_STADB.
+ */
+struct ewc_ht_info {
+       __le16  control1;
+       __le16  control2;
+       __le16  control3;
 } __attribute__((packed));
 
-struct mwl8k_rate_table {
-       /* 1 to allow specified rate and below */
-       __le32  allow_rate_drop;
-       __le32  num_rates;
-       struct mwl8k_rate_entry rate_entry[MWL8K_RATE_TABLE_SIZE];
+struct peer_capability_info {
+       /* Peer type - AP vs. STA.  */
+       __u8    peer_type;
+
+       /* Basic 802.11 capabilities from assoc resp.  */
+       __le16  basic_caps;
+
+       /* Set if peer supports 802.11n high throughput (HT).  */
+       __u8    ht_support;
+
+       /* Valid if HT is supported.  */
+       __le16  ht_caps;
+       __u8    extended_ht_caps;
+       struct ewc_ht_info      ewc_info;
+
+       /* Legacy rate table. Intersection of our rates and peer rates.  */
+       __u8    legacy_rates[12];
+
+       /* HT rate table. Intersection of our rates and peer rates.  */
+       __u8    ht_rates[16];
+       __u8    pad[16];
+
+       /* If set, interoperability mode, no proprietary extensions.  */
+       __u8    interop;
+       __u8    pad2;
+       __u8    station_id;
+       __le16  amsdu_enabled;
 } __attribute__((packed));
 
-struct mwl8k_cmd_use_fixed_rate {
-       struct  mwl8k_cmd_pkt header;
+struct mwl8k_cmd_update_stadb {
+       struct mwl8k_cmd_pkt header;
+
+       /* See STADB_ACTION_TYPE */
        __le32  action;
-       struct mwl8k_rate_table rate_table;
 
-       /* Unicast, Broadcast or Multicast */
-       __le32  rate_type;
-       __le32  reserved1;
-       __le32  reserved2;
+       /* Peer MAC address */
+       __u8    peer_addr[ETH_ALEN];
+
+       __le32  reserved;
+
+       /* Peer info - valid during add/update.  */
+       struct peer_capability_info     peer_info;
 } __attribute__((packed));
 
-static int mwl8k_cmd_use_fixed_rate(struct ieee80211_hw *hw,
-       u32 action, u32 rate_type, struct mwl8k_rate_table *rate_table)
+#define MWL8K_STA_DB_MODIFY_ENTRY      1
+#define MWL8K_STA_DB_DEL_ENTRY         2
+
+/* Peer Entry flags - used to define the type of the peer node */
+#define MWL8K_PEER_TYPE_ACCESSPOINT    2
+
+static int mwl8k_cmd_update_stadb_add(struct ieee80211_hw *hw,
+                                     struct ieee80211_vif *vif,
+                                     struct ieee80211_sta *sta)
 {
-       struct mwl8k_cmd_use_fixed_rate *cmd;
-       int count;
+       struct mwl8k_cmd_update_stadb *cmd;
+       struct peer_capability_info *p;
+       u32 rates;
        int rc;
 
        cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
        if (cmd == NULL)
                return -ENOMEM;
 
-       cmd->header.code = cpu_to_le16(MWL8K_CMD_USE_FIXED_RATE);
+       cmd->header.code = cpu_to_le16(MWL8K_CMD_UPDATE_STADB);
        cmd->header.length = cpu_to_le16(sizeof(*cmd));
+       cmd->action = cpu_to_le32(MWL8K_STA_DB_MODIFY_ENTRY);
+       memcpy(cmd->peer_addr, sta->addr, ETH_ALEN);
+
+       p = &cmd->peer_info;
+       p->peer_type = MWL8K_PEER_TYPE_ACCESSPOINT;
+       p->basic_caps = cpu_to_le16(vif->bss_conf.assoc_capability);
+       p->ht_support = sta->ht_cap.ht_supported;
+       p->ht_caps = sta->ht_cap.cap;
+       p->extended_ht_caps = (sta->ht_cap.ampdu_factor & 3) |
+               ((sta->ht_cap.ampdu_density & 7) << 2);
+       if (hw->conf.channel->band == IEEE80211_BAND_2GHZ)
+               rates = sta->supp_rates[IEEE80211_BAND_2GHZ];
+       else
+               rates = sta->supp_rates[IEEE80211_BAND_5GHZ] << 5;
+       legacy_rate_mask_to_array(p->legacy_rates, rates);
+       memcpy(p->ht_rates, sta->ht_cap.mcs.rx_mask, 16);
+       p->interop = 1;
+       p->amsdu_enabled = 0;
 
-       cmd->action = cpu_to_le32(action);
-       cmd->rate_type = cpu_to_le32(rate_type);
+       rc = mwl8k_post_cmd(hw, &cmd->header);
+       kfree(cmd);
 
-       if (rate_table != NULL) {
-               /*
-                * Copy over each field manually so that endian
-                * conversion can be done.
-                */
-               cmd->rate_table.allow_rate_drop =
-                               cpu_to_le32(rate_table->allow_rate_drop);
-               cmd->rate_table.num_rates =
-                               cpu_to_le32(rate_table->num_rates);
-
-               for (count = 0; count < rate_table->num_rates; count++) {
-                       struct mwl8k_rate_entry *dst =
-                               &cmd->rate_table.rate_entry[count];
-                       struct mwl8k_rate_entry *src =
-                               &rate_table->rate_entry[count];
-
-                       dst->is_ht_rate = cpu_to_le32(src->is_ht_rate);
-                       dst->enable_retry = cpu_to_le32(src->enable_retry);
-                       dst->rate = cpu_to_le32(src->rate);
-                       dst->retry_count = cpu_to_le32(src->retry_count);
-               }
-       }
+       return rc ? rc : p->station_id;
+}
+
+static int mwl8k_cmd_update_stadb_del(struct ieee80211_hw *hw,
+                                     struct ieee80211_vif *vif, u8 *addr)
+{
+       struct mwl8k_cmd_update_stadb *cmd;
+       int rc;
+
+       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+       if (cmd == NULL)
+               return -ENOMEM;
+
+       cmd->header.code = cpu_to_le16(MWL8K_CMD_UPDATE_STADB);
+       cmd->header.length = cpu_to_le16(sizeof(*cmd));
+       cmd->action = cpu_to_le32(MWL8K_STA_DB_DEL_ENTRY);
+       memcpy(cmd->peer_addr, addr, ETH_ALEN);
 
        rc = mwl8k_post_cmd(hw, &cmd->header);
        kfree(cmd);
@@ -2766,31 +3109,81 @@ static irqreturn_t mwl8k_interrupt(int irq, void *dev_id)
        u32 status;
 
        status = ioread32(priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS);
-       iowrite32(~status, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS);
-
        if (!status)
                return IRQ_NONE;
 
-       if (status & MWL8K_A2H_INT_TX_DONE)
-               tasklet_schedule(&priv->tx_reclaim_task);
+       if (status & MWL8K_A2H_INT_TX_DONE) {
+               status &= ~MWL8K_A2H_INT_TX_DONE;
+               tasklet_schedule(&priv->poll_tx_task);
+       }
+
+       if (status & MWL8K_A2H_INT_RX_READY) {
+               status &= ~MWL8K_A2H_INT_RX_READY;
+               tasklet_schedule(&priv->poll_rx_task);
+       }
+
+       if (status)
+               iowrite32(~status, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS);
+
+       if (status & MWL8K_A2H_INT_OPC_DONE) {
+               if (priv->hostcmd_wait != NULL)
+                       complete(priv->hostcmd_wait);
+       }
+
+       if (status & MWL8K_A2H_INT_QUEUE_EMPTY) {
+               if (!mutex_is_locked(&priv->fw_mutex) &&
+                   priv->radio_on && priv->pending_tx_pkts)
+                       mwl8k_tx_start(priv);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static void mwl8k_tx_poll(unsigned long data)
+{
+       struct ieee80211_hw *hw = (struct ieee80211_hw *)data;
+       struct mwl8k_priv *priv = hw->priv;
+       int limit;
+       int i;
+
+       limit = 32;
+
+       spin_lock_bh(&priv->tx_lock);
+
+       for (i = 0; i < MWL8K_TX_QUEUES; i++)
+               limit -= mwl8k_txq_reclaim(hw, i, limit, 0);
+
+       if (!priv->pending_tx_pkts && priv->tx_wait != NULL) {
+               complete(priv->tx_wait);
+               priv->tx_wait = NULL;
+       }
+
+       spin_unlock_bh(&priv->tx_lock);
 
-       if (status & MWL8K_A2H_INT_RX_READY) {
-               while (rxq_process(hw, 0, 1))
-                       rxq_refill(hw, 0, 1);
+       if (limit) {
+               writel(~MWL8K_A2H_INT_TX_DONE,
+                      priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS);
+       } else {
+               tasklet_schedule(&priv->poll_tx_task);
        }
+}
 
-       if (status & MWL8K_A2H_INT_OPC_DONE) {
-               if (priv->hostcmd_wait != NULL)
-                       complete(priv->hostcmd_wait);
-       }
+static void mwl8k_rx_poll(unsigned long data)
+{
+       struct ieee80211_hw *hw = (struct ieee80211_hw *)data;
+       struct mwl8k_priv *priv = hw->priv;
+       int limit;
 
-       if (status & MWL8K_A2H_INT_QUEUE_EMPTY) {
-               if (!mutex_is_locked(&priv->fw_mutex) &&
-                   priv->radio_on && priv->pending_tx_pkts)
-                       mwl8k_tx_start(priv);
-       }
+       limit = 32;
+       limit -= rxq_process(hw, 0, limit);
+       limit -= rxq_refill(hw, 0, limit);
 
-       return IRQ_HANDLED;
+       if (limit) {
+               writel(~MWL8K_A2H_INT_RX_READY,
+                      priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS);
+       } else {
+               tasklet_schedule(&priv->poll_rx_task);
+       }
 }
 
 
@@ -2803,7 +3196,7 @@ static int mwl8k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
        int index = skb_get_queue_mapping(skb);
        int rc;
 
-       if (priv->current_channel == NULL) {
+       if (!priv->radio_on) {
                printk(KERN_DEBUG "%s: dropped TX frame since radio "
                       "disabled\n", wiphy_name(hw->wiphy));
                dev_kfree_skb(skb);
@@ -2828,19 +3221,20 @@ static int mwl8k_start(struct ieee80211_hw *hw)
                return -EIO;
        }
 
-       /* Enable tx reclaim tasklet */
-       tasklet_enable(&priv->tx_reclaim_task);
+       /* Enable TX reclaim and RX tasklets.  */
+       tasklet_enable(&priv->poll_tx_task);
+       tasklet_enable(&priv->poll_rx_task);
 
        /* Enable interrupts */
        iowrite32(MWL8K_A2H_EVENTS, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
 
        rc = mwl8k_fw_lock(hw);
        if (!rc) {
-               rc = mwl8k_cmd_802_11_radio_enable(hw);
+               rc = mwl8k_cmd_radio_enable(hw);
 
                if (!priv->ap_fw) {
                        if (!rc)
-                               rc = mwl8k_enable_sniffer(hw, 0);
+                               rc = mwl8k_cmd_enable_sniffer(hw, 0);
 
                        if (!rc)
                                rc = mwl8k_cmd_set_pre_scan(hw);
@@ -2851,10 +3245,10 @@ static int mwl8k_start(struct ieee80211_hw *hw)
                }
 
                if (!rc)
-                       rc = mwl8k_cmd_setrateadaptmode(hw, 0);
+                       rc = mwl8k_cmd_set_rateadapt_mode(hw, 0);
 
                if (!rc)
-                       rc = mwl8k_set_wmm(hw, 0);
+                       rc = mwl8k_cmd_set_wmm_mode(hw, 0);
 
                mwl8k_fw_unlock(hw);
        }
@@ -2862,7 +3256,8 @@ static int mwl8k_start(struct ieee80211_hw *hw)
        if (rc) {
                iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
                free_irq(priv->pdev->irq, hw);
-               tasklet_disable(&priv->tx_reclaim_task);
+               tasklet_disable(&priv->poll_tx_task);
+               tasklet_disable(&priv->poll_rx_task);
        }
 
        return rc;
@@ -2873,7 +3268,7 @@ static void mwl8k_stop(struct ieee80211_hw *hw)
        struct mwl8k_priv *priv = hw->priv;
        int i;
 
-       mwl8k_cmd_802_11_radio_disable(hw);
+       mwl8k_cmd_radio_disable(hw);
 
        ieee80211_stop_queues(hw);
 
@@ -2886,36 +3281,27 @@ static void mwl8k_stop(struct ieee80211_hw *hw)
        if (priv->beacon_skb != NULL)
                dev_kfree_skb(priv->beacon_skb);
 
-       /* Stop tx reclaim tasklet */
-       tasklet_disable(&priv->tx_reclaim_task);
+       /* Stop TX reclaim and RX tasklets.  */
+       tasklet_disable(&priv->poll_tx_task);
+       tasklet_disable(&priv->poll_rx_task);
 
        /* Return all skbs to mac80211 */
        for (i = 0; i < MWL8K_TX_QUEUES; i++)
-               mwl8k_txq_reclaim(hw, i, 1);
+               mwl8k_txq_reclaim(hw, i, INT_MAX, 1);
 }
 
 static int mwl8k_add_interface(struct ieee80211_hw *hw,
-                               struct ieee80211_if_init_conf *conf)
+                              struct ieee80211_vif *vif)
 {
        struct mwl8k_priv *priv = hw->priv;
        struct mwl8k_vif *mwl8k_vif;
-
-       /*
-        * We only support one active interface at a time.
-        */
-       if (priv->vif != NULL)
-               return -EBUSY;
-
-       /*
-        * We only support managed interfaces for now.
-        */
-       if (conf->type != NL80211_IFTYPE_STATION)
-               return -EINVAL;
+       u32 macids_supported;
+       int macid;
 
        /*
         * Reject interface creation if sniffer mode is active, as
         * STA operation is mutually exclusive with hardware sniffer
-        * mode.
+        * mode.  (Sniffer mode is only used on STA firmware.)
         */
        if (priv->sniffer_enabled) {
                printk(KERN_INFO "%s: unable to create STA "
@@ -2924,37 +3310,54 @@ static int mwl8k_add_interface(struct ieee80211_hw *hw,
                return -EINVAL;
        }
 
-       /* Clean out driver private area */
-       mwl8k_vif = MWL8K_VIF(conf->vif);
-       memset(mwl8k_vif, 0, sizeof(*mwl8k_vif));
 
-       /* Set and save the mac address */
-       mwl8k_set_mac_addr(hw, conf->mac_addr);
-       memcpy(mwl8k_vif->mac_addr, conf->mac_addr, ETH_ALEN);
+       switch (vif->type) {
+       case NL80211_IFTYPE_AP:
+               macids_supported = priv->ap_macids_supported;
+               break;
+       case NL80211_IFTYPE_STATION:
+               macids_supported = priv->sta_macids_supported;
+               break;
+       default:
+               return -EINVAL;
+       }
 
-       /* Back pointer to parent config block */
-       mwl8k_vif->priv = priv;
+       macid = ffs(macids_supported & ~priv->macids_used);
+       if (!macid--)
+               return -EBUSY;
 
-       /* Set Initial sequence number to zero */
+       /* Setup driver private area. */
+       mwl8k_vif = MWL8K_VIF(vif);
+       memset(mwl8k_vif, 0, sizeof(*mwl8k_vif));
+       mwl8k_vif->vif = vif;
+       mwl8k_vif->macid = macid;
        mwl8k_vif->seqno = 0;
 
-       priv->vif = conf->vif;
-       priv->current_channel = NULL;
+       /* Set the mac address.  */
+       mwl8k_cmd_set_mac_addr(hw, vif, vif->addr);
+
+       if (priv->ap_fw)
+               mwl8k_cmd_set_new_stn_add_self(hw, vif);
+
+       priv->macids_used |= 1 << mwl8k_vif->macid;
+       list_add_tail(&mwl8k_vif->list, &priv->vif_list);
 
        return 0;
 }
 
 static void mwl8k_remove_interface(struct ieee80211_hw *hw,
-                                  struct ieee80211_if_init_conf *conf)
+                                  struct ieee80211_vif *vif)
 {
        struct mwl8k_priv *priv = hw->priv;
+       struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif);
 
-       if (priv->vif == NULL)
-               return;
+       if (priv->ap_fw)
+               mwl8k_cmd_set_new_stn_del(hw, vif, vif->addr);
 
-       mwl8k_set_mac_addr(hw, "\x00\x00\x00\x00\x00\x00");
+       mwl8k_cmd_set_mac_addr(hw, vif, "\x00\x00\x00\x00\x00\x00");
 
-       priv->vif = NULL;
+       priv->macids_used &= ~(1 << mwl8k_vif->macid);
+       list_del(&mwl8k_vif->list);
 }
 
 static int mwl8k_config(struct ieee80211_hw *hw, u32 changed)
@@ -2964,8 +3367,7 @@ static int mwl8k_config(struct ieee80211_hw *hw, u32 changed)
        int rc;
 
        if (conf->flags & IEEE80211_CONF_IDLE) {
-               mwl8k_cmd_802_11_radio_disable(hw);
-               priv->current_channel = NULL;
+               mwl8k_cmd_radio_disable(hw);
                return 0;
        }
 
@@ -2973,19 +3375,17 @@ static int mwl8k_config(struct ieee80211_hw *hw, u32 changed)
        if (rc)
                return rc;
 
-       rc = mwl8k_cmd_802_11_radio_enable(hw);
+       rc = mwl8k_cmd_radio_enable(hw);
        if (rc)
                goto out;
 
-       rc = mwl8k_cmd_set_rf_channel(hw, conf->channel);
+       rc = mwl8k_cmd_set_rf_channel(hw, conf);
        if (rc)
                goto out;
 
-       priv->current_channel = conf->channel;
-
        if (conf->power_level > 18)
                conf->power_level = 18;
-       rc = mwl8k_cmd_802_11_rf_tx_power(hw, conf->power_level);
+       rc = mwl8k_cmd_rf_tx_power(hw, conf->power_level);
        if (rc)
                goto out;
 
@@ -3003,79 +3403,160 @@ out:
        return rc;
 }
 
-static void mwl8k_bss_info_changed(struct ieee80211_hw *hw,
-                                  struct ieee80211_vif *vif,
-                                  struct ieee80211_bss_conf *info,
-                                  u32 changed)
+static void
+mwl8k_bss_info_changed_sta(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+                          struct ieee80211_bss_conf *info, u32 changed)
 {
        struct mwl8k_priv *priv = hw->priv;
-       struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif);
+       u32 ap_legacy_rates;
+       u8 ap_mcs_rates[16];
        int rc;
 
-       if ((changed & BSS_CHANGED_ASSOC) == 0)
+       if (mwl8k_fw_lock(hw))
                return;
 
-       priv->capture_beacon = false;
-
-       rc = mwl8k_fw_lock(hw);
-       if (rc)
-               return;
+       /*
+        * No need to capture a beacon if we're no longer associated.
+        */
+       if ((changed & BSS_CHANGED_ASSOC) && !vif->bss_conf.assoc)
+               priv->capture_beacon = false;
 
-       if (info->assoc) {
-               memcpy(&mwl8k_vif->bss_info, info,
-                       sizeof(struct ieee80211_bss_conf));
+       /*
+        * Get the AP's legacy and MCS rates.
+        */
+       if (vif->bss_conf.assoc) {
+               struct ieee80211_sta *ap;
 
-               memcpy(mwl8k_vif->bssid, info->bssid, ETH_ALEN);
+               rcu_read_lock();
 
-               /* Install rates */
-               rc = mwl8k_update_rateset(hw, vif);
-               if (rc)
+               ap = ieee80211_find_sta(vif, vif->bss_conf.bssid);
+               if (ap == NULL) {
+                       rcu_read_unlock();
                        goto out;
+               }
+
+               if (hw->conf.channel->band == IEEE80211_BAND_2GHZ) {
+                       ap_legacy_rates = ap->supp_rates[IEEE80211_BAND_2GHZ];
+               } else {
+                       ap_legacy_rates =
+                               ap->supp_rates[IEEE80211_BAND_5GHZ] << 5;
+               }
+               memcpy(ap_mcs_rates, ap->ht_cap.mcs.rx_mask, 16);
 
-               /* Turn on rate adaptation */
-               rc = mwl8k_cmd_use_fixed_rate(hw, MWL8K_USE_AUTO_RATE,
-                       MWL8K_UCAST_RATE, NULL);
+               rcu_read_unlock();
+       }
+
+       if ((changed & BSS_CHANGED_ASSOC) && vif->bss_conf.assoc) {
+               rc = mwl8k_cmd_set_rate(hw, vif, ap_legacy_rates, ap_mcs_rates);
                if (rc)
                        goto out;
 
-               /* Set radio preamble */
-               rc = mwl8k_set_radio_preamble(hw, info->use_short_preamble);
+               rc = mwl8k_cmd_use_fixed_rate_sta(hw);
                if (rc)
                        goto out;
+       }
 
-               /* Set slot time */
-               rc = mwl8k_cmd_set_slot(hw, info->use_short_slot);
+       if (changed & BSS_CHANGED_ERP_PREAMBLE) {
+               rc = mwl8k_set_radio_preamble(hw,
+                               vif->bss_conf.use_short_preamble);
                if (rc)
                        goto out;
+       }
 
-               /* Update peer rate info */
-               rc = mwl8k_cmd_update_sta_db(hw, vif,
-                               MWL8K_STA_DB_MODIFY_ENTRY);
+       if (changed & BSS_CHANGED_ERP_SLOT) {
+               rc = mwl8k_cmd_set_slot(hw, vif->bss_conf.use_short_slot);
                if (rc)
                        goto out;
+       }
 
-               /* Set AID */
-               rc = mwl8k_cmd_set_aid(hw, vif);
+       if (vif->bss_conf.assoc &&
+           (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_ERP_CTS_PROT |
+                       BSS_CHANGED_HT))) {
+               rc = mwl8k_cmd_set_aid(hw, vif, ap_legacy_rates);
                if (rc)
                        goto out;
+       }
 
+       if (vif->bss_conf.assoc &&
+           (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_BEACON_INT))) {
                /*
                 * Finalize the join.  Tell rx handler to process
                 * next beacon from our BSSID.
                 */
-               memcpy(priv->capture_bssid, mwl8k_vif->bssid, ETH_ALEN);
+               memcpy(priv->capture_bssid, vif->bss_conf.bssid, ETH_ALEN);
                priv->capture_beacon = true;
-       } else {
-               rc = mwl8k_cmd_update_sta_db(hw, vif, MWL8K_STA_DB_DEL_ENTRY);
-               memset(&mwl8k_vif->bss_info, 0,
-                       sizeof(struct ieee80211_bss_conf));
-               memset(mwl8k_vif->bssid, 0, ETH_ALEN);
        }
 
 out:
        mwl8k_fw_unlock(hw);
 }
 
+static void
+mwl8k_bss_info_changed_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+                         struct ieee80211_bss_conf *info, u32 changed)
+{
+       int rc;
+
+       if (mwl8k_fw_lock(hw))
+               return;
+
+       if (changed & BSS_CHANGED_ERP_PREAMBLE) {
+               rc = mwl8k_set_radio_preamble(hw,
+                               vif->bss_conf.use_short_preamble);
+               if (rc)
+                       goto out;
+       }
+
+       if (changed & BSS_CHANGED_BASIC_RATES) {
+               int idx;
+               int rate;
+
+               /*
+                * Use lowest supported basic rate for multicasts
+                * and management frames (such as probe responses --
+                * beacons will always go out at 1 Mb/s).
+                */
+               idx = ffs(vif->bss_conf.basic_rates);
+               if (idx)
+                       idx--;
+
+               if (hw->conf.channel->band == IEEE80211_BAND_2GHZ)
+                       rate = mwl8k_rates_24[idx].hw_value;
+               else
+                       rate = mwl8k_rates_50[idx].hw_value;
+
+               mwl8k_cmd_use_fixed_rate_ap(hw, rate, rate);
+       }
+
+       if (changed & (BSS_CHANGED_BEACON_INT | BSS_CHANGED_BEACON)) {
+               struct sk_buff *skb;
+
+               skb = ieee80211_beacon_get(hw, vif);
+               if (skb != NULL) {
+                       mwl8k_cmd_set_beacon(hw, vif, skb->data, skb->len);
+                       kfree_skb(skb);
+               }
+       }
+
+       if (changed & BSS_CHANGED_BEACON_ENABLED)
+               mwl8k_cmd_bss_start(hw, vif, info->enable_beacon);
+
+out:
+       mwl8k_fw_unlock(hw);
+}
+
+static void
+mwl8k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+                      struct ieee80211_bss_conf *info, u32 changed)
+{
+       struct mwl8k_priv *priv = hw->priv;
+
+       if (!priv->ap_fw)
+               mwl8k_bss_info_changed_sta(hw, vif, info, changed);
+       else
+               mwl8k_bss_info_changed_ap(hw, vif, info, changed);
+}
+
 static u64 mwl8k_prepare_multicast(struct ieee80211_hw *hw,
                                   int mc_count, struct dev_addr_list *mclist)
 {
@@ -3105,7 +3586,7 @@ mwl8k_configure_filter_sniffer(struct ieee80211_hw *hw,
         * operation, so refuse to enable sniffer mode if a STA
         * interface is active.
         */
-       if (priv->vif != NULL) {
+       if (!list_empty(&priv->vif_list)) {
                if (net_ratelimit())
                        printk(KERN_INFO "%s: not enabling sniffer "
                               "mode because STA interface is active\n",
@@ -3114,7 +3595,7 @@ mwl8k_configure_filter_sniffer(struct ieee80211_hw *hw,
        }
 
        if (!priv->sniffer_enabled) {
-               if (mwl8k_enable_sniffer(hw, 1))
+               if (mwl8k_cmd_enable_sniffer(hw, 1))
                        return 0;
                priv->sniffer_enabled = true;
        }
@@ -3126,6 +3607,14 @@ mwl8k_configure_filter_sniffer(struct ieee80211_hw *hw,
        return 1;
 }
 
+static struct mwl8k_vif *mwl8k_first_vif(struct mwl8k_priv *priv)
+{
+       if (!list_empty(&priv->vif_list))
+               return list_entry(priv->vif_list.next, struct mwl8k_vif, list);
+
+       return NULL;
+}
+
 static void mwl8k_configure_filter(struct ieee80211_hw *hw,
                                   unsigned int changed_flags,
                                   unsigned int *total_flags,
@@ -3163,7 +3652,7 @@ static void mwl8k_configure_filter(struct ieee80211_hw *hw,
        }
 
        if (priv->sniffer_enabled) {
-               mwl8k_enable_sniffer(hw, 0);
+               mwl8k_cmd_enable_sniffer(hw, 0);
                priv->sniffer_enabled = false;
        }
 
@@ -3174,7 +3663,8 @@ static void mwl8k_configure_filter(struct ieee80211_hw *hw,
                         */
                        mwl8k_cmd_set_pre_scan(hw);
                } else {
-                       u8 *bssid;
+                       struct mwl8k_vif *mwl8k_vif;
+                       const u8 *bssid;
 
                        /*
                         * Enable the BSS filter.
@@ -3184,9 +3674,11 @@ static void mwl8k_configure_filter(struct ieee80211_hw *hw,
                         * (where the OUI part needs to be nonzero for
                         * the BSSID to be accepted by POST_SCAN).
                         */
-                       bssid = "\x01\x00\x00\x00\x00\x00";
-                       if (priv->vif != NULL)
-                               bssid = MWL8K_VIF(priv->vif)->bssid;
+                       mwl8k_vif = mwl8k_first_vif(priv);
+                       if (mwl8k_vif != NULL)
+                               bssid = mwl8k_vif->vif->bss_conf.bssid;
+                       else
+                               bssid = "\x01\x00\x00\x00\x00\x00";
 
                        mwl8k_cmd_set_post_scan(hw, bssid);
                }
@@ -3213,7 +3705,93 @@ static void mwl8k_configure_filter(struct ieee80211_hw *hw,
 
 static int mwl8k_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
 {
-       return mwl8k_rts_threshold(hw, MWL8K_CMD_SET, value);
+       return mwl8k_cmd_set_rts_threshold(hw, value);
+}
+
+struct mwl8k_sta_notify_item
+{
+       struct list_head list;
+       struct ieee80211_vif *vif;
+       enum sta_notify_cmd cmd;
+       struct ieee80211_sta sta;
+};
+
+static void
+mwl8k_do_sta_notify(struct ieee80211_hw *hw, struct mwl8k_sta_notify_item *s)
+{
+       struct mwl8k_priv *priv = hw->priv;
+
+       /*
+        * STA firmware uses UPDATE_STADB, AP firmware uses SET_NEW_STN.
+        */
+       if (!priv->ap_fw && s->cmd == STA_NOTIFY_ADD) {
+               int rc;
+
+               rc = mwl8k_cmd_update_stadb_add(hw, s->vif, &s->sta);
+               if (rc >= 0) {
+                       struct ieee80211_sta *sta;
+
+                       rcu_read_lock();
+                       sta = ieee80211_find_sta(s->vif, s->sta.addr);
+                       if (sta != NULL)
+                               MWL8K_STA(sta)->peer_id = rc;
+                       rcu_read_unlock();
+               }
+       } else if (!priv->ap_fw && s->cmd == STA_NOTIFY_REMOVE) {
+               mwl8k_cmd_update_stadb_del(hw, s->vif, s->sta.addr);
+       } else if (priv->ap_fw && s->cmd == STA_NOTIFY_ADD) {
+               mwl8k_cmd_set_new_stn_add(hw, s->vif, &s->sta);
+       } else if (priv->ap_fw && s->cmd == STA_NOTIFY_REMOVE) {
+               mwl8k_cmd_set_new_stn_del(hw, s->vif, s->sta.addr);
+       }
+}
+
+static void mwl8k_sta_notify_worker(struct work_struct *work)
+{
+       struct mwl8k_priv *priv =
+               container_of(work, struct mwl8k_priv, sta_notify_worker);
+       struct ieee80211_hw *hw = priv->hw;
+
+       spin_lock_bh(&priv->sta_notify_list_lock);
+       while (!list_empty(&priv->sta_notify_list)) {
+               struct mwl8k_sta_notify_item *s;
+
+               s = list_entry(priv->sta_notify_list.next,
+                              struct mwl8k_sta_notify_item, list);
+               list_del(&s->list);
+
+               spin_unlock_bh(&priv->sta_notify_list_lock);
+
+               mwl8k_do_sta_notify(hw, s);
+               kfree(s);
+
+               spin_lock_bh(&priv->sta_notify_list_lock);
+       }
+       spin_unlock_bh(&priv->sta_notify_list_lock);
+}
+
+static void
+mwl8k_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+                enum sta_notify_cmd cmd, struct ieee80211_sta *sta)
+{
+       struct mwl8k_priv *priv = hw->priv;
+       struct mwl8k_sta_notify_item *s;
+
+       if (cmd != STA_NOTIFY_ADD && cmd != STA_NOTIFY_REMOVE)
+               return;
+
+       s = kmalloc(sizeof(*s), GFP_ATOMIC);
+       if (s != NULL) {
+               s->vif = vif;
+               s->cmd = cmd;
+               s->sta = *sta;
+
+               spin_lock(&priv->sta_notify_list_lock);
+               list_add_tail(&s->list, &priv->sta_notify_list);
+               spin_unlock(&priv->sta_notify_list_lock);
+
+               ieee80211_queue_work(hw, &priv->sta_notify_worker);
+       }
 }
 
 static int mwl8k_conf_tx(struct ieee80211_hw *hw, u16 queue,
@@ -3225,14 +3803,14 @@ static int mwl8k_conf_tx(struct ieee80211_hw *hw, u16 queue,
        rc = mwl8k_fw_lock(hw);
        if (!rc) {
                if (!priv->wmm_enabled)
-                       rc = mwl8k_set_wmm(hw, 1);
+                       rc = mwl8k_cmd_set_wmm_mode(hw, 1);
 
                if (!rc)
-                       rc = mwl8k_set_edca_params(hw, queue,
-                                                  params->cw_min,
-                                                  params->cw_max,
-                                                  params->aifs,
-                                                  params->txop);
+                       rc = mwl8k_cmd_set_edca_params(hw, queue,
+                                                      params->cw_min,
+                                                      params->cw_max,
+                                                      params->aifs,
+                                                      params->txop);
 
                mwl8k_fw_unlock(hw);
        }
@@ -3261,7 +3839,23 @@ static int mwl8k_get_tx_stats(struct ieee80211_hw *hw,
 static int mwl8k_get_stats(struct ieee80211_hw *hw,
                           struct ieee80211_low_level_stats *stats)
 {
-       return mwl8k_cmd_802_11_get_stat(hw, stats);
+       return mwl8k_cmd_get_stat(hw, stats);
+}
+
+static int
+mwl8k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+                  enum ieee80211_ampdu_mlme_action action,
+                  struct ieee80211_sta *sta, u16 tid, u16 *ssn)
+{
+       switch (action) {
+       case IEEE80211_AMPDU_RX_START:
+       case IEEE80211_AMPDU_RX_STOP:
+               if (!(hw->flags & IEEE80211_HW_AMPDU_AGGREGATION))
+                       return -ENOTSUPP;
+               return 0;
+       default:
+               return -ENOTSUPP;
+       }
 }
 
 static const struct ieee80211_ops mwl8k_ops = {
@@ -3275,67 +3869,68 @@ static const struct ieee80211_ops mwl8k_ops = {
        .prepare_multicast      = mwl8k_prepare_multicast,
        .configure_filter       = mwl8k_configure_filter,
        .set_rts_threshold      = mwl8k_set_rts_threshold,
+       .sta_notify             = mwl8k_sta_notify,
        .conf_tx                = mwl8k_conf_tx,
        .get_tx_stats           = mwl8k_get_tx_stats,
        .get_stats              = mwl8k_get_stats,
+       .ampdu_action           = mwl8k_ampdu_action,
 };
 
-static void mwl8k_tx_reclaim_handler(unsigned long data)
-{
-       int i;
-       struct ieee80211_hw *hw = (struct ieee80211_hw *) data;
-       struct mwl8k_priv *priv = hw->priv;
-
-       spin_lock_bh(&priv->tx_lock);
-       for (i = 0; i < MWL8K_TX_QUEUES; i++)
-               mwl8k_txq_reclaim(hw, i, 0);
-
-       if (priv->tx_wait != NULL && !priv->pending_tx_pkts) {
-               complete(priv->tx_wait);
-               priv->tx_wait = NULL;
-       }
-       spin_unlock_bh(&priv->tx_lock);
-}
-
 static void mwl8k_finalize_join_worker(struct work_struct *work)
 {
        struct mwl8k_priv *priv =
                container_of(work, struct mwl8k_priv, finalize_join_worker);
        struct sk_buff *skb = priv->beacon_skb;
-       u8 dtim = MWL8K_VIF(priv->vif)->bss_info.dtim_period;
+       struct mwl8k_vif *mwl8k_vif;
 
-       mwl8k_finalize_join(priv->hw, skb->data, skb->len, dtim);
-       dev_kfree_skb(skb);
+       mwl8k_vif = mwl8k_first_vif(priv);
+       if (mwl8k_vif != NULL)
+               mwl8k_cmd_finalize_join(priv->hw, skb->data, skb->len,
+                                       mwl8k_vif->vif->bss_conf.dtim_period);
 
+       dev_kfree_skb(skb);
        priv->beacon_skb = NULL;
 }
 
 enum {
-       MWL8687 = 0,
+       MWL8363 = 0,
+       MWL8687,
        MWL8366,
 };
 
 static struct mwl8k_device_info mwl8k_info_tbl[] __devinitdata = {
-       {
+       [MWL8363] = {
+               .part_name      = "88w8363",
+               .helper_image   = "mwl8k/helper_8363.fw",
+               .fw_image       = "mwl8k/fmimage_8363.fw",
+       },
+       [MWL8687] = {
                .part_name      = "88w8687",
                .helper_image   = "mwl8k/helper_8687.fw",
                .fw_image       = "mwl8k/fmimage_8687.fw",
-               .rxd_ops        = &rxd_8687_ops,
-               .modes          = BIT(NL80211_IFTYPE_STATION),
        },
-       {
+       [MWL8366] = {
                .part_name      = "88w8366",
                .helper_image   = "mwl8k/helper_8366.fw",
                .fw_image       = "mwl8k/fmimage_8366.fw",
-               .rxd_ops        = &rxd_8366_ops,
-               .modes          = 0,
+               .ap_rxd_ops     = &rxd_8366_ap_ops,
        },
 };
 
+MODULE_FIRMWARE("mwl8k/helper_8363.fw");
+MODULE_FIRMWARE("mwl8k/fmimage_8363.fw");
+MODULE_FIRMWARE("mwl8k/helper_8687.fw");
+MODULE_FIRMWARE("mwl8k/fmimage_8687.fw");
+MODULE_FIRMWARE("mwl8k/helper_8366.fw");
+MODULE_FIRMWARE("mwl8k/fmimage_8366.fw");
+
 static DEFINE_PCI_DEVICE_TABLE(mwl8k_pci_id_table) = {
+       { PCI_VDEVICE(MARVELL, 0x2a0c), .driver_data = MWL8363, },
+       { PCI_VDEVICE(MARVELL, 0x2a24), .driver_data = MWL8363, },
        { PCI_VDEVICE(MARVELL, 0x2a2b), .driver_data = MWL8687, },
        { PCI_VDEVICE(MARVELL, 0x2a30), .driver_data = MWL8687, },
        { PCI_VDEVICE(MARVELL, 0x2a40), .driver_data = MWL8366, },
+       { PCI_VDEVICE(MARVELL, 0x2a43), .driver_data = MWL8366, },
        { },
 };
 MODULE_DEVICE_TABLE(pci, mwl8k_pci_id_table);
@@ -3354,6 +3949,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
                printed_version = 1;
        }
 
+
        rc = pci_enable_device(pdev);
        if (rc) {
                printk(KERN_ERR "%s: Cannot enable new PCI device\n",
@@ -3370,6 +3966,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
 
        pci_set_master(pdev);
 
+
        hw = ieee80211_alloc_hw(sizeof(*priv), &mwl8k_ops);
        if (hw == NULL) {
                printk(KERN_ERR "%s: ieee80211 alloc failed\n", MWL8K_NAME);
@@ -3377,17 +3974,14 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
                goto err_free_reg;
        }
 
+       SET_IEEE80211_DEV(hw, &pdev->dev);
+       pci_set_drvdata(pdev, hw);
+
        priv = hw->priv;
        priv->hw = hw;
        priv->pdev = pdev;
        priv->device_info = &mwl8k_info_tbl[id->driver_data];
-       priv->rxd_ops = priv->device_info->rxd_ops;
-       priv->sniffer_enabled = false;
-       priv->wmm_enabled = false;
-       priv->pending_tx_pkts = 0;
 
-       SET_IEEE80211_DEV(hw, &pdev->dev);
-       pci_set_drvdata(pdev, hw);
 
        priv->sram = pci_iomap(pdev, 0, 0x10000);
        if (priv->sram == NULL) {
@@ -3410,16 +4004,46 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
                }
        }
 
-       memcpy(priv->channels, mwl8k_channels, sizeof(mwl8k_channels));
-       priv->band.band = IEEE80211_BAND_2GHZ;
-       priv->band.channels = priv->channels;
-       priv->band.n_channels = ARRAY_SIZE(mwl8k_channels);
-       priv->band.bitrates = priv->rates;
-       priv->band.n_bitrates = ARRAY_SIZE(mwl8k_rates);
-       hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band;
 
-       BUILD_BUG_ON(sizeof(priv->rates) != sizeof(mwl8k_rates));
-       memcpy(priv->rates, mwl8k_rates, sizeof(mwl8k_rates));
+       /* Reset firmware and hardware */
+       mwl8k_hw_reset(priv);
+
+       /* Ask userland hotplug daemon for the device firmware */
+       rc = mwl8k_request_firmware(priv);
+       if (rc) {
+               printk(KERN_ERR "%s: Firmware files not found\n",
+                      wiphy_name(hw->wiphy));
+               goto err_stop_firmware;
+       }
+
+       /* Load firmware into hardware */
+       rc = mwl8k_load_firmware(hw);
+       if (rc) {
+               printk(KERN_ERR "%s: Cannot start firmware\n",
+                      wiphy_name(hw->wiphy));
+               goto err_stop_firmware;
+       }
+
+       /* Reclaim memory once firmware is successfully loaded */
+       mwl8k_release_firmware(priv);
+
+
+       if (priv->ap_fw) {
+               priv->rxd_ops = priv->device_info->ap_rxd_ops;
+               if (priv->rxd_ops == NULL) {
+                       printk(KERN_ERR "%s: Driver does not have AP "
+                              "firmware image support for this hardware\n",
+                              wiphy_name(hw->wiphy));
+                       goto err_stop_firmware;
+               }
+       } else {
+               priv->rxd_ops = &rxd_sta_ops;
+       }
+
+       priv->sniffer_enabled = false;
+       priv->wmm_enabled = false;
+       priv->pending_tx_pkts = 0;
+
 
        /*
         * Extra headroom is the size of the required DMA header
@@ -3432,33 +4056,40 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
 
        hw->queues = MWL8K_TX_QUEUES;
 
-       hw->wiphy->interface_modes = priv->device_info->modes;
-
        /* Set rssi and noise values to dBm */
        hw->flags |= IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM;
        hw->vif_data_size = sizeof(struct mwl8k_vif);
-       priv->vif = NULL;
+       hw->sta_data_size = sizeof(struct mwl8k_sta);
+
+       priv->macids_used = 0;
+       INIT_LIST_HEAD(&priv->vif_list);
 
        /* Set default radio state and preamble */
        priv->radio_on = 0;
        priv->radio_short_preamble = 0;
 
+       /* Station database handling */
+       INIT_WORK(&priv->sta_notify_worker, mwl8k_sta_notify_worker);
+       spin_lock_init(&priv->sta_notify_list_lock);
+       INIT_LIST_HEAD(&priv->sta_notify_list);
+
        /* Finalize join worker */
        INIT_WORK(&priv->finalize_join_worker, mwl8k_finalize_join_worker);
 
-       /* TX reclaim tasklet */
-       tasklet_init(&priv->tx_reclaim_task,
-                       mwl8k_tx_reclaim_handler, (unsigned long)hw);
-       tasklet_disable(&priv->tx_reclaim_task);
+       /* TX reclaim and RX tasklets.  */
+       tasklet_init(&priv->poll_tx_task, mwl8k_tx_poll, (unsigned long)hw);
+       tasklet_disable(&priv->poll_tx_task);
+       tasklet_init(&priv->poll_rx_task, mwl8k_rx_poll, (unsigned long)hw);
+       tasklet_disable(&priv->poll_rx_task);
 
        /* Power management cookie */
        priv->cookie = pci_alloc_consistent(priv->pdev, 4, &priv->cookie_dma);
        if (priv->cookie == NULL)
-               goto err_iounmap;
+               goto err_stop_firmware;
 
        rc = mwl8k_rxq_init(hw, 0);
        if (rc)
-               goto err_iounmap;
+               goto err_free_cookie;
        rxq_refill(hw, 0, INT_MAX);
 
        mutex_init(&priv->fw_mutex);
@@ -3478,7 +4109,8 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
 
        iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS);
        iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
-       iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_CLEAR_SEL);
+       iowrite32(MWL8K_A2H_INT_TX_DONE | MWL8K_A2H_INT_RX_READY,
+                 priv->regs + MWL8K_HIU_A2H_INTERRUPT_CLEAR_SEL);
        iowrite32(0xffffffff, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK);
 
        rc = request_irq(priv->pdev->irq, mwl8k_interrupt,
@@ -3489,31 +4121,9 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
                goto err_free_queues;
        }
 
-       /* Reset firmware and hardware */
-       mwl8k_hw_reset(priv);
-
-       /* Ask userland hotplug daemon for the device firmware */
-       rc = mwl8k_request_firmware(priv);
-       if (rc) {
-               printk(KERN_ERR "%s: Firmware files not found\n",
-                      wiphy_name(hw->wiphy));
-               goto err_free_irq;
-       }
-
-       /* Load firmware into hardware */
-       rc = mwl8k_load_firmware(hw);
-       if (rc) {
-               printk(KERN_ERR "%s: Cannot start firmware\n",
-                      wiphy_name(hw->wiphy));
-               goto err_stop_firmware;
-       }
-
-       /* Reclaim memory once firmware is successfully loaded */
-       mwl8k_release_firmware(priv);
-
        /*
         * Temporarily enable interrupts.  Initial firmware host
-        * commands use interrupts and avoids polling.  Disable
+        * commands use interrupts and avoid polling.  Disable
         * interrupts when done.
         */
        iowrite32(MWL8K_A2H_EVENTS, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
@@ -3529,22 +4139,29 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
        if (rc) {
                printk(KERN_ERR "%s: Cannot initialise firmware\n",
                       wiphy_name(hw->wiphy));
-               goto err_stop_firmware;
+               goto err_free_irq;
        }
 
+       hw->wiphy->interface_modes = 0;
+       if (priv->ap_macids_supported)
+               hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP);
+       if (priv->sta_macids_supported)
+               hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_STATION);
+
+
        /* Turn radio off */
-       rc = mwl8k_cmd_802_11_radio_disable(hw);
+       rc = mwl8k_cmd_radio_disable(hw);
        if (rc) {
                printk(KERN_ERR "%s: Cannot disable\n", wiphy_name(hw->wiphy));
-               goto err_stop_firmware;
+               goto err_free_irq;
        }
 
        /* Clear MAC address */
-       rc = mwl8k_set_mac_addr(hw, "\x00\x00\x00\x00\x00\x00");
+       rc = mwl8k_cmd_set_mac_addr(hw, NULL, "\x00\x00\x00\x00\x00\x00");
        if (rc) {
                printk(KERN_ERR "%s: Cannot clear MAC address\n",
                       wiphy_name(hw->wiphy));
-               goto err_stop_firmware;
+               goto err_free_irq;
        }
 
        /* Disable interrupts */
@@ -3555,7 +4172,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
        if (rc) {
                printk(KERN_ERR "%s: Cannot register device\n",
                       wiphy_name(hw->wiphy));
-               goto err_stop_firmware;
+               goto err_free_queues;
        }
 
        printk(KERN_INFO "%s: %s v%d, %pM, %s firmware %u.%u.%u.%u\n",
@@ -3567,10 +4184,6 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
 
        return 0;
 
-err_stop_firmware:
-       mwl8k_hw_reset(priv);
-       mwl8k_release_firmware(priv);
-
 err_free_irq:
        iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
        free_irq(priv->pdev->irq, hw);
@@ -3580,11 +4193,16 @@ err_free_queues:
                mwl8k_txq_deinit(hw, i);
        mwl8k_rxq_deinit(hw, 0);
 
-err_iounmap:
+err_free_cookie:
        if (priv->cookie != NULL)
                pci_free_consistent(priv->pdev, 4,
                                priv->cookie, priv->cookie_dma);
 
+err_stop_firmware:
+       mwl8k_hw_reset(priv);
+       mwl8k_release_firmware(priv);
+
+err_iounmap:
        if (priv->regs != NULL)
                pci_iounmap(pdev, priv->regs);
 
@@ -3622,15 +4240,16 @@ static void __devexit mwl8k_remove(struct pci_dev *pdev)
 
        ieee80211_unregister_hw(hw);
 
-       /* Remove tx reclaim tasklet */
-       tasklet_kill(&priv->tx_reclaim_task);
+       /* Remove TX reclaim and RX tasklets.  */
+       tasklet_kill(&priv->poll_tx_task);
+       tasklet_kill(&priv->poll_rx_task);
 
        /* Stop hardware */
        mwl8k_hw_reset(priv);
 
        /* Return all skbs to mac80211 */
        for (i = 0; i < MWL8K_TX_QUEUES; i++)
-               mwl8k_txq_reclaim(hw, i, 1);
+               mwl8k_txq_reclaim(hw, i, INT_MAX, 1);
 
        for (i = 0; i < MWL8K_TX_QUEUES; i++)
                mwl8k_txq_deinit(hw, i);
index c13a4c38341079a4d9ad08f825262300f46f3508..075f446b3139269cd0e492dd17fcba6c65fe19c8 100644 (file)
@@ -274,7 +274,7 @@ static void __devexit orinoco_nortel_remove_one(struct pci_dev *pdev)
        pci_disable_device(pdev);
 }
 
-static struct pci_device_id orinoco_nortel_id_table[] = {
+static DEFINE_PCI_DEVICE_TABLE(orinoco_nortel_id_table) = {
        /* Nortel emobility PCI */
        {0x126c, 0x8030, PCI_ANY_ID, PCI_ANY_ID,},
        /* Symbol LA-4123 PCI */
index fea7781948e7c34104e96b86d96ffee5e9e0addb..bda5317cc596038c91f2e966c94c69185c9a1ac6 100644 (file)
@@ -212,7 +212,7 @@ static void __devexit orinoco_pci_remove_one(struct pci_dev *pdev)
        pci_disable_device(pdev);
 }
 
-static struct pci_device_id orinoco_pci_id_table[] = {
+static DEFINE_PCI_DEVICE_TABLE(orinoco_pci_id_table) = {
        /* Intersil Prism 3 */
        {0x1260, 0x3872, PCI_ANY_ID, PCI_ANY_ID,},
        /* Intersil Prism 2.5 */
index 3f2942a1e4f5f2b990fd9a49ed4c3801b4755826..e0d5874ab42fb9090ccaad1fa3e39e882ce4acef 100644 (file)
@@ -310,7 +310,7 @@ static void __devexit orinoco_plx_remove_one(struct pci_dev *pdev)
        pci_disable_device(pdev);
 }
 
-static struct pci_device_id orinoco_plx_id_table[] = {
+static DEFINE_PCI_DEVICE_TABLE(orinoco_plx_id_table) = {
        {0x111a, 0x1023, PCI_ANY_ID, PCI_ANY_ID,},      /* Siemens SpeedStream SS1023 */
        {0x1385, 0x4100, PCI_ANY_ID, PCI_ANY_ID,},      /* Netgear MA301 */
        {0x15e8, 0x0130, PCI_ANY_ID, PCI_ANY_ID,},      /* Correga  - does this work? */
index d3452548cc719911b6015563353033fa7aaaf36b..88cbc7902aa0a1e5c31de5a6b66534babbed8561 100644 (file)
@@ -203,7 +203,7 @@ static void __devexit orinoco_tmd_remove_one(struct pci_dev *pdev)
        pci_disable_device(pdev);
 }
 
-static struct pci_device_id orinoco_tmd_id_table[] = {
+static DEFINE_PCI_DEVICE_TABLE(orinoco_tmd_id_table) = {
        {0x15e8, 0x0131, PCI_ANY_ID, PCI_ANY_ID,},      /* NDC and OEMs, e.g. pheecom */
        {0,},
 };
index 18012dbfb45dff585dbbadc0b0a0224f4d56812c..26428e4c9c60257a4dee119abc885cbb77fd8cd4 100644 (file)
@@ -216,7 +216,7 @@ static void p54_stop(struct ieee80211_hw *dev)
 }
 
 static int p54_add_interface(struct ieee80211_hw *dev,
-                            struct ieee80211_if_init_conf *conf)
+                            struct ieee80211_vif *vif)
 {
        struct p54_common *priv = dev->priv;
 
@@ -226,28 +226,28 @@ static int p54_add_interface(struct ieee80211_hw *dev,
                return -EOPNOTSUPP;
        }
 
-       priv->vif = conf->vif;
+       priv->vif = vif;
 
-       switch (conf->type) {
+       switch (vif->type) {
        case NL80211_IFTYPE_STATION:
        case NL80211_IFTYPE_ADHOC:
        case NL80211_IFTYPE_AP:
        case NL80211_IFTYPE_MESH_POINT:
-               priv->mode = conf->type;
+               priv->mode = vif->type;
                break;
        default:
                mutex_unlock(&priv->conf_mutex);
                return -EOPNOTSUPP;
        }
 
-       memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN);
+       memcpy(priv->mac_addr, vif->addr, ETH_ALEN);
        p54_setup_mac(priv);
        mutex_unlock(&priv->conf_mutex);
        return 0;
 }
 
 static void p54_remove_interface(struct ieee80211_hw *dev,
-                                struct ieee80211_if_init_conf *conf)
+                                struct ieee80211_vif *vif)
 {
        struct p54_common *priv = dev->priv;
 
index a72f7c2577de93222b50395fac0249ccdd3d33de..57c646598062c28e3b04aeef970192b780cde530 100644 (file)
@@ -31,7 +31,7 @@ MODULE_LICENSE("GPL");
 MODULE_ALIAS("prism54pci");
 MODULE_FIRMWARE("isl3886pci");
 
-static struct pci_device_id p54p_table[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(p54p_table) = {
        /* Intersil PRISM Duette/Prism GT Wireless LAN adapter */
        { PCI_DEVICE(0x1260, 0x3890) },
        /* 3COM 3CRWE154G72 Wireless LAN adapter */
index e4f2bb7368f27c598f7a40901f79028a83b5ab78..dc14420a9adc03e65f5541e0ef9851a44b791c17 100644 (file)
@@ -39,7 +39,7 @@ module_param(init_pcitm, int, 0);
  * driver_data
  * If you have an update for this please contact prism54-devel@prism54.org
  * The latest list can be found at http://prism54.org/supported_cards.php */
-static const struct pci_device_id prism54_id_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(prism54_id_tbl) = {
        /* Intersil PRISM Duette/Prism GT Wireless LAN adapter */
        {
         0x1260, 0x3890,
index 2ecbedb26e152c28e697ac8927be151934ee4144..305c106fdc1c442bce51bbf1c84f1a85fa8ed9ab 100644 (file)
@@ -2594,23 +2594,9 @@ end:
 /*
  * driver/device initialization
  */
-static int bcm4320a_early_init(struct usbnet *usbdev)
-{
-       /* bcm4320a doesn't handle configuration parameters well. Try
-        * set any and you get partially zeroed mac and broken device.
-        */
-
-       return 0;
-}
-
-static int bcm4320b_early_init(struct usbnet *usbdev)
+static void rndis_copy_module_params(struct usbnet *usbdev)
 {
        struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
-       char buf[8];
-
-       /* Early initialization settings, setting these won't have effect
-        * if called after generic_rndis_bind().
-        */
 
        priv->param_country[0] = modparam_country[0];
        priv->param_country[1] = modparam_country[1];
@@ -2652,6 +2638,32 @@ static int bcm4320b_early_init(struct usbnet *usbdev)
                priv->param_workaround_interval = 500;
        else
                priv->param_workaround_interval = modparam_workaround_interval;
+}
+
+static int bcm4320a_early_init(struct usbnet *usbdev)
+{
+       /* copy module parameters for bcm4320a so that iwconfig reports txpower
+        * and workaround parameter is copied to private structure correctly.
+        */
+       rndis_copy_module_params(usbdev);
+
+       /* bcm4320a doesn't handle configuration parameters well. Try
+        * set any and you get partially zeroed mac and broken device.
+        */
+
+       return 0;
+}
+
+static int bcm4320b_early_init(struct usbnet *usbdev)
+{
+       struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
+       char buf[8];
+
+       rndis_copy_module_params(usbdev);
+
+       /* Early initialization settings, setting these won't have effect
+        * if called after generic_rndis_bind().
+        */
 
        rndis_set_config_parameter_str(usbdev, "Country", priv->param_country);
        rndis_set_config_parameter_str(usbdev, "FrameBursting",
index bf60689aaabb02e72b58225f9a9fc82571412686..3ca824a91ad903a44ce7f583404c37bd44892fe0 100644 (file)
@@ -54,12 +54,12 @@ config RT61PCI
          When compiled as a module, this driver will be called rt61pci.
 
 config RT2800PCI_PCI
-       tristate
+       boolean
        depends on PCI
        default y
 
 config RT2800PCI_SOC
-       tristate
+       boolean
        depends on RALINK_RT288X || RALINK_RT305X
        default y
 
index e7f46405a418d5ecdacd60f9d92eeb910c5731b4..aa579eb8723fb55bc25227fbd7ca2ab570cc6286 100644 (file)
@@ -451,7 +451,7 @@ static void rt2400pci_config_channel(struct rt2x00_dev *rt2x00dev,
        /*
         * RF2420 chipset don't need any additional actions.
         */
-       if (rt2x00_rf(&rt2x00dev->chip, RF2420))
+       if (rt2x00_rf(rt2x00dev, RF2420))
                return;
 
        /*
@@ -1343,8 +1343,7 @@ static int rt2400pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
        rt2x00_set_chip_rf(rt2x00dev, value, reg);
        rt2x00_print_chip(rt2x00dev);
 
-       if (!rt2x00_rf(&rt2x00dev->chip, RF2420) &&
-           !rt2x00_rf(&rt2x00dev->chip, RF2421)) {
+       if (!rt2x00_rf(rt2x00dev, RF2420) && !rt2x00_rf(rt2x00dev, RF2421)) {
                ERROR(rt2x00dev, "Invalid RF chipset detected.\n");
                return -ENODEV;
        }
@@ -1643,7 +1642,7 @@ static const struct rt2x00_ops rt2400pci_ops = {
 /*
  * RT2400pci module information.
  */
-static struct pci_device_id rt2400pci_device_table[] = {
+static DEFINE_PCI_DEVICE_TABLE(rt2400pci_device_table) = {
        { PCI_DEVICE(0x1814, 0x0101), PCI_DEVICE_DATA(&rt2400pci_ops) },
        { 0, }
 };
index 408fcfc120f503a459f7e2fda05c514ff18bf71e..77ee1df7933fde2a715d2eab72f5e8a8e02d659a 100644 (file)
@@ -440,8 +440,7 @@ static void rt2500pci_config_ant(struct rt2x00_dev *rt2x00dev,
        /*
         * RT2525E and RT5222 need to flip TX I/Q
         */
-       if (rt2x00_rf(&rt2x00dev->chip, RF2525E) ||
-           rt2x00_rf(&rt2x00dev->chip, RF5222)) {
+       if (rt2x00_rf(rt2x00dev, RF2525E) || rt2x00_rf(rt2x00dev, RF5222)) {
                rt2x00_set_field8(&r2, BBP_R2_TX_IQ_FLIP, 1);
                rt2x00_set_field32(&reg, BBPCSR1_CCK_FLIP, 1);
                rt2x00_set_field32(&reg, BBPCSR1_OFDM_FLIP, 1);
@@ -449,7 +448,7 @@ static void rt2500pci_config_ant(struct rt2x00_dev *rt2x00dev,
                /*
                 * RT2525E does not need RX I/Q Flip.
                 */
-               if (rt2x00_rf(&rt2x00dev->chip, RF2525E))
+               if (rt2x00_rf(rt2x00dev, RF2525E))
                        rt2x00_set_field8(&r14, BBP_R14_RX_IQ_FLIP, 0);
        } else {
                rt2x00_set_field32(&reg, BBPCSR1_CCK_FLIP, 0);
@@ -475,14 +474,14 @@ static void rt2500pci_config_channel(struct rt2x00_dev *rt2x00dev,
         * Switch on tuning bits.
         * For RT2523 devices we do not need to update the R1 register.
         */
-       if (!rt2x00_rf(&rt2x00dev->chip, RF2523))
+       if (!rt2x00_rf(rt2x00dev, RF2523))
                rt2x00_set_field32(&rf->rf1, RF1_TUNER, 1);
        rt2x00_set_field32(&rf->rf3, RF3_TUNER, 1);
 
        /*
         * For RT2525 we should first set the channel to half band higher.
         */
-       if (rt2x00_rf(&rt2x00dev->chip, RF2525)) {
+       if (rt2x00_rf(rt2x00dev, RF2525)) {
                static const u32 vals[] = {
                        0x00080cbe, 0x00080d02, 0x00080d06, 0x00080d0a,
                        0x00080d0e, 0x00080d12, 0x00080d16, 0x00080d1a,
@@ -516,7 +515,7 @@ static void rt2500pci_config_channel(struct rt2x00_dev *rt2x00dev,
         * Switch off tuning bits.
         * For RT2523 devices we do not need to update the R1 register.
         */
-       if (!rt2x00_rf(&rt2x00dev->chip, RF2523)) {
+       if (!rt2x00_rf(rt2x00dev, RF2523)) {
                rt2x00_set_field32(&rf->rf1, RF1_TUNER, 0);
                rt2500pci_rf_write(rt2x00dev, 1, rf->rf1);
        }
@@ -640,7 +639,7 @@ static void rt2500pci_link_tuner(struct rt2x00_dev *rt2x00dev,
         * up to version C the link tuning should halt after 20
         * seconds while being associated.
         */
-       if (rt2x00_rev(&rt2x00dev->chip) < RT2560_VERSION_D &&
+       if (rt2x00_rev(rt2x00dev) < RT2560_VERSION_D &&
            rt2x00dev->intf_associated && count > 20)
                return;
 
@@ -650,7 +649,7 @@ static void rt2500pci_link_tuner(struct rt2x00_dev *rt2x00dev,
         * should go straight to dynamic CCA tuning when they
         * are not associated.
         */
-       if (rt2x00_rev(&rt2x00dev->chip) < RT2560_VERSION_D ||
+       if (rt2x00_rev(rt2x00dev) < RT2560_VERSION_D ||
            !rt2x00dev->intf_associated)
                goto dynamic_cca_tune;
 
@@ -1507,12 +1506,12 @@ static int rt2500pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
        rt2x00_set_chip_rf(rt2x00dev, value, reg);
        rt2x00_print_chip(rt2x00dev);
 
-       if (!rt2x00_rf(&rt2x00dev->chip, RF2522) &&
-           !rt2x00_rf(&rt2x00dev->chip, RF2523) &&
-           !rt2x00_rf(&rt2x00dev->chip, RF2524) &&
-           !rt2x00_rf(&rt2x00dev->chip, RF2525) &&
-           !rt2x00_rf(&rt2x00dev->chip, RF2525E) &&
-           !rt2x00_rf(&rt2x00dev->chip, RF5222)) {
+       if (!rt2x00_rf(rt2x00dev, RF2522) &&
+           !rt2x00_rf(rt2x00dev, RF2523) &&
+           !rt2x00_rf(rt2x00dev, RF2524) &&
+           !rt2x00_rf(rt2x00dev, RF2525) &&
+           !rt2x00_rf(rt2x00dev, RF2525E) &&
+           !rt2x00_rf(rt2x00dev, RF5222)) {
                ERROR(rt2x00dev, "Invalid RF chipset detected.\n");
                return -ENODEV;
        }
@@ -1744,22 +1743,22 @@ static int rt2500pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
        spec->supported_bands = SUPPORT_BAND_2GHZ;
        spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM;
 
-       if (rt2x00_rf(&rt2x00dev->chip, RF2522)) {
+       if (rt2x00_rf(rt2x00dev, RF2522)) {
                spec->num_channels = ARRAY_SIZE(rf_vals_bg_2522);
                spec->channels = rf_vals_bg_2522;
-       } else if (rt2x00_rf(&rt2x00dev->chip, RF2523)) {
+       } else if (rt2x00_rf(rt2x00dev, RF2523)) {
                spec->num_channels = ARRAY_SIZE(rf_vals_bg_2523);
                spec->channels = rf_vals_bg_2523;
-       } else if (rt2x00_rf(&rt2x00dev->chip, RF2524)) {
+       } else if (rt2x00_rf(rt2x00dev, RF2524)) {
                spec->num_channels = ARRAY_SIZE(rf_vals_bg_2524);
                spec->channels = rf_vals_bg_2524;
-       } else if (rt2x00_rf(&rt2x00dev->chip, RF2525)) {
+       } else if (rt2x00_rf(rt2x00dev, RF2525)) {
                spec->num_channels = ARRAY_SIZE(rf_vals_bg_2525);
                spec->channels = rf_vals_bg_2525;
-       } else if (rt2x00_rf(&rt2x00dev->chip, RF2525E)) {
+       } else if (rt2x00_rf(rt2x00dev, RF2525E)) {
                spec->num_channels = ARRAY_SIZE(rf_vals_bg_2525e);
                spec->channels = rf_vals_bg_2525e;
-       } else if (rt2x00_rf(&rt2x00dev->chip, RF5222)) {
+       } else if (rt2x00_rf(rt2x00dev, RF5222)) {
                spec->supported_bands |= SUPPORT_BAND_5GHZ;
                spec->num_channels = ARRAY_SIZE(rf_vals_5222);
                spec->channels = rf_vals_5222;
@@ -1941,7 +1940,7 @@ static const struct rt2x00_ops rt2500pci_ops = {
 /*
  * RT2500pci module information.
  */
-static struct pci_device_id rt2500pci_device_table[] = {
+static DEFINE_PCI_DEVICE_TABLE(rt2500pci_device_table) = {
        { PCI_DEVICE(0x1814, 0x0201), PCI_DEVICE_DATA(&rt2500pci_ops) },
        { 0, }
 };
index 83f2592c59def385091a81e5e070d184d7a0260e..9e6f865c57f22b377fb53e5f6e44ca0192cac515 100644 (file)
@@ -565,8 +565,7 @@ static void rt2500usb_config_ant(struct rt2x00_dev *rt2x00dev,
        /*
         * RT2525E and RT5222 need to flip TX I/Q
         */
-       if (rt2x00_rf(&rt2x00dev->chip, RF2525E) ||
-           rt2x00_rf(&rt2x00dev->chip, RF5222)) {
+       if (rt2x00_rf(rt2x00dev, RF2525E) || rt2x00_rf(rt2x00dev, RF5222)) {
                rt2x00_set_field8(&r2, BBP_R2_TX_IQ_FLIP, 1);
                rt2x00_set_field16(&csr5, PHY_CSR5_CCK_FLIP, 1);
                rt2x00_set_field16(&csr6, PHY_CSR6_OFDM_FLIP, 1);
@@ -574,7 +573,7 @@ static void rt2500usb_config_ant(struct rt2x00_dev *rt2x00dev,
                /*
                 * RT2525E does not need RX I/Q Flip.
                 */
-               if (rt2x00_rf(&rt2x00dev->chip, RF2525E))
+               if (rt2x00_rf(rt2x00dev, RF2525E))
                        rt2x00_set_field8(&r14, BBP_R14_RX_IQ_FLIP, 0);
        } else {
                rt2x00_set_field16(&csr5, PHY_CSR5_CCK_FLIP, 0);
@@ -598,7 +597,7 @@ static void rt2500usb_config_channel(struct rt2x00_dev *rt2x00dev,
        /*
         * For RT2525E we should first set the channel to half band higher.
         */
-       if (rt2x00_rf(&rt2x00dev->chip, RF2525E)) {
+       if (rt2x00_rf(rt2x00dev, RF2525E)) {
                static const u32 vals[] = {
                        0x000008aa, 0x000008ae, 0x000008ae, 0x000008b2,
                        0x000008b2, 0x000008b6, 0x000008b6, 0x000008ba,
@@ -793,7 +792,7 @@ static int rt2500usb_init_registers(struct rt2x00_dev *rt2x00dev)
        rt2x00_set_field16(&reg, MAC_CSR1_HOST_READY, 1);
        rt2500usb_register_write(rt2x00dev, MAC_CSR1, reg);
 
-       if (rt2x00_rev(&rt2x00dev->chip) >= RT2570_VERSION_C) {
+       if (rt2x00_rev(rt2x00dev) >= RT2570_VERSION_C) {
                rt2500usb_register_read(rt2x00dev, PHY_CSR2, &reg);
                rt2x00_set_field16(&reg, PHY_CSR2_LNA, 0);
        } else {
@@ -1411,19 +1410,18 @@ static int rt2500usb_init_eeprom(struct rt2x00_dev *rt2x00dev)
        rt2x00_set_chip(rt2x00dev, RT2570, value, reg);
        rt2x00_print_chip(rt2x00dev);
 
-       if (!rt2x00_check_rev(&rt2x00dev->chip, 0x000ffff0, 0) ||
-           rt2x00_check_rev(&rt2x00dev->chip, 0x0000000f, 0)) {
-
+       if (!rt2x00_check_rev(rt2x00dev, 0x000ffff0, 0) ||
+           rt2x00_check_rev(rt2x00dev, 0x0000000f, 0)) {
                ERROR(rt2x00dev, "Invalid RT chipset detected.\n");
                return -ENODEV;
        }
 
-       if (!rt2x00_rf(&rt2x00dev->chip, RF2522) &&
-           !rt2x00_rf(&rt2x00dev->chip, RF2523) &&
-           !rt2x00_rf(&rt2x00dev->chip, RF2524) &&
-           !rt2x00_rf(&rt2x00dev->chip, RF2525) &&
-           !rt2x00_rf(&rt2x00dev->chip, RF2525E) &&
-           !rt2x00_rf(&rt2x00dev->chip, RF5222)) {
+       if (!rt2x00_rf(rt2x00dev, RF2522) &&
+           !rt2x00_rf(rt2x00dev, RF2523) &&
+           !rt2x00_rf(rt2x00dev, RF2524) &&
+           !rt2x00_rf(rt2x00dev, RF2525) &&
+           !rt2x00_rf(rt2x00dev, RF2525E) &&
+           !rt2x00_rf(rt2x00dev, RF5222)) {
                ERROR(rt2x00dev, "Invalid RF chipset detected.\n");
                return -ENODEV;
        }
@@ -1667,22 +1665,22 @@ static int rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
        spec->supported_bands = SUPPORT_BAND_2GHZ;
        spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM;
 
-       if (rt2x00_rf(&rt2x00dev->chip, RF2522)) {
+       if (rt2x00_rf(rt2x00dev, RF2522)) {
                spec->num_channels = ARRAY_SIZE(rf_vals_bg_2522);
                spec->channels = rf_vals_bg_2522;
-       } else if (rt2x00_rf(&rt2x00dev->chip, RF2523)) {
+       } else if (rt2x00_rf(rt2x00dev, RF2523)) {
                spec->num_channels = ARRAY_SIZE(rf_vals_bg_2523);
                spec->channels = rf_vals_bg_2523;
-       } else if (rt2x00_rf(&rt2x00dev->chip, RF2524)) {
+       } else if (rt2x00_rf(rt2x00dev, RF2524)) {
                spec->num_channels = ARRAY_SIZE(rf_vals_bg_2524);
                spec->channels = rf_vals_bg_2524;
-       } else if (rt2x00_rf(&rt2x00dev->chip, RF2525)) {
+       } else if (rt2x00_rf(rt2x00dev, RF2525)) {
                spec->num_channels = ARRAY_SIZE(rf_vals_bg_2525);
                spec->channels = rf_vals_bg_2525;
-       } else if (rt2x00_rf(&rt2x00dev->chip, RF2525E)) {
+       } else if (rt2x00_rf(rt2x00dev, RF2525E)) {
                spec->num_channels = ARRAY_SIZE(rf_vals_bg_2525e);
                spec->channels = rf_vals_bg_2525e;
-       } else if (rt2x00_rf(&rt2x00dev->chip, RF5222)) {
+       } else if (rt2x00_rf(rt2x00dev, RF5222)) {
                spec->supported_bands |= SUPPORT_BAND_5GHZ;
                spec->num_channels = ARRAY_SIZE(rf_vals_5222);
                spec->channels = rf_vals_5222;
index 9deae41cb784ef342b64652363232e76acab4bc6..529a37364eb05cbbd3578df5b40acfc1610c5a26 100644 (file)
@@ -37,7 +37,7 @@
 #include <linux/module.h>
 
 #include "rt2x00.h"
-#if defined(CONFIG_RT2800USB) || defined(CONFIG_RT2800USB_MODULE)
+#if defined(CONFIG_RT2X00_LIB_USB) || defined(CONFIG_RT2X00_LIB_USB_MODULE)
 #include "rt2x00usb.h"
 #endif
 #include "rt2800lib.h"
@@ -220,8 +220,7 @@ void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev,
        /*
         * RT2880 and RT3052 don't support MCU requests.
         */
-       if (rt2x00_rt(&rt2x00dev->chip, RT2880) ||
-           rt2x00_rt(&rt2x00dev->chip, RT3052))
+       if (rt2x00_rt(rt2x00dev, RT2880) || rt2x00_rt(rt2x00dev, RT3052))
                return;
 
        mutex_lock(&rt2x00dev->csr_mutex);
@@ -246,6 +245,25 @@ void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev,
 }
 EXPORT_SYMBOL_GPL(rt2800_mcu_request);
 
+int rt2800_wait_wpdma_ready(struct rt2x00_dev *rt2x00dev)
+{
+       unsigned int i;
+       u32 reg;
+
+       for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+               rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, &reg);
+               if (!rt2x00_get_field32(reg, WPDMA_GLO_CFG_TX_DMA_BUSY) &&
+                   !rt2x00_get_field32(reg, WPDMA_GLO_CFG_RX_DMA_BUSY))
+                       return 0;
+
+               msleep(1);
+       }
+
+       ERROR(rt2x00dev, "WPDMA TX/RX busy, aborting.\n");
+       return -EACCES;
+}
+EXPORT_SYMBOL_GPL(rt2800_wait_wpdma_ready);
+
 #ifdef CONFIG_RT2X00_LIB_DEBUGFS
 const struct rt2x00debug rt2800_rt2x00debug = {
        .owner  = THIS_MODULE,
@@ -348,7 +366,7 @@ static int rt2800_blink_set(struct led_classdev *led_cdev,
        return 0;
 }
 
-void rt2800_init_led(struct rt2x00_dev *rt2x00dev,
+static void rt2800_init_led(struct rt2x00_dev *rt2x00dev,
                     struct rt2x00_led *led, enum led_type type)
 {
        led->rt2x00dev = rt2x00dev;
@@ -357,7 +375,6 @@ void rt2800_init_led(struct rt2x00_dev *rt2x00dev,
        led->led_dev.blink_set = rt2800_blink_set;
        led->flags = LED_INITIALIZED;
 }
-EXPORT_SYMBOL_GPL(rt2800_init_led);
 #endif /* CONFIG_RT2X00_LIB_LEDS */
 
 /*
@@ -806,12 +823,12 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
        unsigned int tx_pin;
        u8 bbp;
 
-       if ((rt2x00_rt(&rt2x00dev->chip, RT3070) ||
-            rt2x00_rt(&rt2x00dev->chip, RT3090)) &&
-           (rt2x00_rf(&rt2x00dev->chip, RF2020) ||
-            rt2x00_rf(&rt2x00dev->chip, RF3020) ||
-            rt2x00_rf(&rt2x00dev->chip, RF3021) ||
-            rt2x00_rf(&rt2x00dev->chip, RF3022)))
+       if ((rt2x00_rt(rt2x00dev, RT3070) ||
+            rt2x00_rt(rt2x00dev, RT3090)) &&
+           (rt2x00_rf(rt2x00dev, RF2020) ||
+            rt2x00_rf(rt2x00dev, RF3020) ||
+            rt2x00_rf(rt2x00dev, RF3021) ||
+            rt2x00_rf(rt2x00dev, RF3022)))
                rt2800_config_channel_rt3x(rt2x00dev, conf, rf, info);
        else
                rt2800_config_channel_rt2x(rt2x00dev, conf, rf, info);
@@ -878,7 +895,7 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
        rt2x00_set_field8(&bbp, BBP3_HT40_PLUS, conf_is_ht40_plus(conf));
        rt2800_bbp_write(rt2x00dev, 3, bbp);
 
-       if (rt2x00_rev(&rt2x00dev->chip) == RT2860C_VERSION) {
+       if (rt2x00_rev(rt2x00dev) == RT2860C_VERSION) {
                if (conf_is_ht40(conf)) {
                        rt2800_bbp_write(rt2x00dev, 69, 0x1a);
                        rt2800_bbp_write(rt2x00dev, 70, 0x0a);
@@ -1041,7 +1058,7 @@ static u8 rt2800_get_default_vgc(struct rt2x00_dev *rt2x00dev)
 {
        if (rt2x00dev->curr_band == IEEE80211_BAND_2GHZ) {
                if (rt2x00_intf_is_usb(rt2x00dev) &&
-                   rt2x00_rev(&rt2x00dev->chip) == RT3070_VERSION)
+                   rt2x00_rev(rt2x00dev) == RT3070_VERSION)
                        return 0x1c + (2 * rt2x00dev->lna_gain);
                else
                        return 0x2e + rt2x00dev->lna_gain;
@@ -1072,7 +1089,7 @@ EXPORT_SYMBOL_GPL(rt2800_reset_tuner);
 void rt2800_link_tuner(struct rt2x00_dev *rt2x00dev, struct link_qual *qual,
                       const u32 count)
 {
-       if (rt2x00_rev(&rt2x00dev->chip) == RT2860C_VERSION)
+       if (rt2x00_rev(rt2x00dev) == RT2860C_VERSION)
                return;
 
        /*
@@ -1121,7 +1138,7 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
 
        if (rt2x00_intf_is_usb(rt2x00dev)) {
                rt2800_register_write(rt2x00dev, USB_DMA_CFG, 0x00000000);
-#if defined(CONFIG_RT2800USB) || defined(CONFIG_RT2800USB_MODULE)
+#if defined(CONFIG_RT2X00_LIB_USB) || defined(CONFIG_RT2X00_LIB_USB_MODULE)
                rt2x00usb_vendor_request_sw(rt2x00dev, USB_DEVICE_MODE, 0,
                                            USB_MODE_RESET, REGISTER_TIMEOUT);
 #endif
@@ -1158,7 +1175,7 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
        rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
 
        if (rt2x00_intf_is_usb(rt2x00dev) &&
-           rt2x00_rev(&rt2x00dev->chip) == RT3070_VERSION) {
+           rt2x00_rev(rt2x00dev) == RT3070_VERSION) {
                rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000400);
                rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00000000);
                rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000000);
@@ -1185,8 +1202,8 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
 
        rt2800_register_read(rt2x00dev, MAX_LEN_CFG, &reg);
        rt2x00_set_field32(&reg, MAX_LEN_CFG_MAX_MPDU, AGGREGATION_SIZE);
-       if (rt2x00_rev(&rt2x00dev->chip) >= RT2880E_VERSION &&
-           rt2x00_rev(&rt2x00dev->chip) < RT3070_VERSION)
+       if (rt2x00_rev(rt2x00dev) >= RT2880E_VERSION &&
+           rt2x00_rev(rt2x00dev) < RT3070_VERSION)
                rt2x00_set_field32(&reg, MAX_LEN_CFG_MAX_PSDU, 2);
        else
                rt2x00_set_field32(&reg, MAX_LEN_CFG_MAX_PSDU, 1);
@@ -1465,22 +1482,22 @@ int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
        rt2800_bbp_write(rt2x00dev, 103, 0x00);
        rt2800_bbp_write(rt2x00dev, 105, 0x05);
 
-       if (rt2x00_rev(&rt2x00dev->chip) == RT2860C_VERSION) {
+       if (rt2x00_rev(rt2x00dev) == RT2860C_VERSION) {
                rt2800_bbp_write(rt2x00dev, 69, 0x16);
                rt2800_bbp_write(rt2x00dev, 73, 0x12);
        }
 
-       if (rt2x00_rev(&rt2x00dev->chip) > RT2860D_VERSION)
+       if (rt2x00_rev(rt2x00dev) > RT2860D_VERSION)
                rt2800_bbp_write(rt2x00dev, 84, 0x19);
 
        if (rt2x00_intf_is_usb(rt2x00dev) &&
-           rt2x00_rev(&rt2x00dev->chip) == RT3070_VERSION) {
+           rt2x00_rev(rt2x00dev) == RT3070_VERSION) {
                rt2800_bbp_write(rt2x00dev, 70, 0x0a);
                rt2800_bbp_write(rt2x00dev, 84, 0x99);
                rt2800_bbp_write(rt2x00dev, 105, 0x05);
        }
 
-       if (rt2x00_rt(&rt2x00dev->chip, RT3052)) {
+       if (rt2x00_rt(rt2x00dev, RT3052)) {
                rt2800_bbp_write(rt2x00dev, 31, 0x08);
                rt2800_bbp_write(rt2x00dev, 78, 0x0e);
                rt2800_bbp_write(rt2x00dev, 80, 0x08);
@@ -1566,13 +1583,13 @@ int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
        u8 bbp;
 
        if (rt2x00_intf_is_usb(rt2x00dev) &&
-           rt2x00_rev(&rt2x00dev->chip) != RT3070_VERSION)
+           rt2x00_rev(rt2x00dev) != RT3070_VERSION)
                return 0;
 
        if (rt2x00_intf_is_pci(rt2x00dev)) {
-               if (!rt2x00_rf(&rt2x00dev->chip, RF3020) &&
-                   !rt2x00_rf(&rt2x00dev->chip, RF3021) &&
-                   !rt2x00_rf(&rt2x00dev->chip, RF3022))
+               if (!rt2x00_rf(rt2x00dev, RF3020) &&
+                   !rt2x00_rf(rt2x00dev, RF3021) &&
+                   !rt2x00_rf(rt2x00dev, RF3022))
                        return 0;
        }
 
@@ -1737,7 +1754,7 @@ int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev)
                rt2x00_set_field16(&word, EEPROM_ANTENNA_RF_TYPE, RF2820);
                rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word);
                EEPROM(rt2x00dev, "Antenna: 0x%04x\n", word);
-       } else if (rt2x00_rev(&rt2x00dev->chip) < RT2883_VERSION) {
+       } else if (rt2x00_rev(rt2x00dev) < RT2883_VERSION) {
                /*
                 * There is a max of 2 RX streams for RT28x0 series
                 */
@@ -1839,17 +1856,15 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
        rt2x00_set_chip_rf(rt2x00dev, value, reg);
 
        if (rt2x00_intf_is_usb(rt2x00dev)) {
-               struct rt2x00_chip *chip = &rt2x00dev->chip;
-
                /*
                 * The check for rt2860 is not a typo, some rt2870 hardware
                 * identifies itself as rt2860 in the CSR register.
                 */
-               if (rt2x00_check_rev(chip, 0xfff00000, 0x28600000) ||
-                   rt2x00_check_rev(chip, 0xfff00000, 0x28700000) ||
-                   rt2x00_check_rev(chip, 0xfff00000, 0x28800000)) {
+               if (rt2x00_check_rev(rt2x00dev, 0xfff00000, 0x28600000) ||
+                   rt2x00_check_rev(rt2x00dev, 0xfff00000, 0x28700000) ||
+                   rt2x00_check_rev(rt2x00dev, 0xfff00000, 0x28800000)) {
                        rt2x00_set_chip_rt(rt2x00dev, RT2870);
-               } else if (rt2x00_check_rev(chip, 0xffff0000, 0x30700000)) {
+               } else if (rt2x00_check_rev(rt2x00dev, 0xffff0000, 0x30700000)) {
                        rt2x00_set_chip_rt(rt2x00dev, RT3070);
                } else {
                        ERROR(rt2x00dev, "Invalid RT chipset detected.\n");
@@ -1858,14 +1873,15 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
        }
        rt2x00_print_chip(rt2x00dev);
 
-       if (!rt2x00_rf(&rt2x00dev->chip, RF2820) &&
-           !rt2x00_rf(&rt2x00dev->chip, RF2850) &&
-           !rt2x00_rf(&rt2x00dev->chip, RF2720) &&
-           !rt2x00_rf(&rt2x00dev->chip, RF2750) &&
-           !rt2x00_rf(&rt2x00dev->chip, RF3020) &&
-           !rt2x00_rf(&rt2x00dev->chip, RF2020) &&
-           !rt2x00_rf(&rt2x00dev->chip, RF3021) &&
-           !rt2x00_rf(&rt2x00dev->chip, RF3022)) {
+       if (!rt2x00_rf(rt2x00dev, RF2820) &&
+           !rt2x00_rf(rt2x00dev, RF2850) &&
+           !rt2x00_rf(rt2x00dev, RF2720) &&
+           !rt2x00_rf(rt2x00dev, RF2750) &&
+           !rt2x00_rf(rt2x00dev, RF3020) &&
+           !rt2x00_rf(rt2x00dev, RF2020) &&
+           !rt2x00_rf(rt2x00dev, RF3021) &&
+           !rt2x00_rf(rt2x00dev, RF3022) &&
+           !rt2x00_rf(rt2x00dev, RF3052)) {
                ERROR(rt2x00dev, "Invalid RF chipset detected.\n");
                return -ENODEV;
        }
@@ -2013,7 +2029,6 @@ static const struct rf_channel rf_vals_302x[] = {
 
 int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
 {
-       struct rt2x00_chip *chip = &rt2x00dev->chip;
        struct hw_mode_spec *spec = &rt2x00dev->spec;
        struct channel_info *info;
        char *tx_power1;
@@ -2049,19 +2064,19 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
        spec->supported_bands = SUPPORT_BAND_2GHZ;
        spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM;
 
-       if (rt2x00_rf(chip, RF2820) ||
-           rt2x00_rf(chip, RF2720) ||
-           (rt2x00_intf_is_pci(rt2x00dev) && rt2x00_rf(chip, RF3052))) {
+       if (rt2x00_rf(rt2x00dev, RF2820) ||
+           rt2x00_rf(rt2x00dev, RF2720) ||
+           rt2x00_rf(rt2x00dev, RF3052)) {
                spec->num_channels = 14;
                spec->channels = rf_vals;
-       } else if (rt2x00_rf(chip, RF2850) || rt2x00_rf(chip, RF2750)) {
+       } else if (rt2x00_rf(rt2x00dev, RF2850) || rt2x00_rf(rt2x00dev, RF2750)) {
                spec->supported_bands |= SUPPORT_BAND_5GHZ;
                spec->num_channels = ARRAY_SIZE(rf_vals);
                spec->channels = rf_vals;
-       } else if (rt2x00_rf(chip, RF3020) ||
-                  rt2x00_rf(chip, RF2020) ||
-                  rt2x00_rf(chip, RF3021) ||
-                  rt2x00_rf(chip, RF3022)) {
+       } else if (rt2x00_rf(rt2x00dev, RF3020) ||
+                  rt2x00_rf(rt2x00dev, RF2020) ||
+                  rt2x00_rf(rt2x00dev, RF3021) ||
+                  rt2x00_rf(rt2x00dev, RF3022)) {
                spec->num_channels = ARRAY_SIZE(rf_vals_302x);
                spec->channels = rf_vals_302x;
        }
@@ -2069,7 +2084,7 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
        /*
         * Initialize HT information.
         */
-       if (!rt2x00_rf(chip, RF2020))
+       if (!rt2x00_rf(rt2x00dev, RF2020))
                spec->ht.ht_supported = true;
        else
                spec->ht.ht_supported = false;
index 535ce22f2ac8c6c20b8faa1d1932211d77e5c798..ebabeae62d1b9cabe6eae884cc1286e8697ed261 100644 (file)
@@ -114,8 +114,6 @@ void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev,
 extern const struct rt2x00debug rt2800_rt2x00debug;
 
 int rt2800_rfkill_poll(struct rt2x00_dev *rt2x00dev);
-void rt2800_init_led(struct rt2x00_dev *rt2x00dev,
-                    struct rt2x00_led *led, enum led_type type);
 int rt2800_config_shared_key(struct rt2x00_dev *rt2x00dev,
                             struct rt2x00lib_crypto *crypto,
                             struct ieee80211_key_conf *key);
@@ -139,6 +137,7 @@ void rt2800_link_tuner(struct rt2x00_dev *rt2x00dev, struct link_qual *qual,
 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_efuse_detect(struct rt2x00_dev *rt2x00dev);
 void rt2800_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev);
index dfc886fcb44de55e0265b92d91cc846f58836f5a..d64181cbc9cb0910b3888df8bab986aae02c7e61 100644 (file)
 #include "rt2800.h"
 #include "rt2800pci.h"
 
-#ifdef CONFIG_RT2800PCI_PCI_MODULE
-#define CONFIG_RT2800PCI_PCI
-#endif
-
-#ifdef CONFIG_RT2800PCI_WISOC_MODULE
-#define CONFIG_RT2800PCI_WISOC
-#endif
-
 /*
  * Allow hardware encryption to be disabled.
  */
@@ -87,7 +79,7 @@ static void rt2800pci_mcu_status(struct rt2x00_dev *rt2x00dev, const u8 token)
        rt2800_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0);
 }
 
-#ifdef CONFIG_RT2800PCI_WISOC
+#ifdef CONFIG_RT2800PCI_SOC
 static void rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev)
 {
        u32 *base_addr = (u32 *) KSEG1ADDR(0x1F040000); /* XXX for RT3052 */
@@ -98,7 +90,7 @@ static void rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev)
 static inline void rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev)
 {
 }
-#endif /* CONFIG_RT2800PCI_WISOC */
+#endif /* CONFIG_RT2800PCI_SOC */
 
 #ifdef CONFIG_RT2800PCI_PCI
 static void rt2800pci_eepromregister_read(struct eeprom_93cx6 *eeprom)
@@ -461,24 +453,6 @@ static void rt2800pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
        rt2800_register_write(rt2x00dev, INT_MASK_CSR, reg);
 }
 
-static int rt2800pci_wait_wpdma_ready(struct rt2x00_dev *rt2x00dev)
-{
-       unsigned int i;
-       u32 reg;
-
-       for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
-               rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, &reg);
-               if (!rt2x00_get_field32(reg, WPDMA_GLO_CFG_TX_DMA_BUSY) &&
-                   !rt2x00_get_field32(reg, WPDMA_GLO_CFG_RX_DMA_BUSY))
-                       return 0;
-
-               msleep(1);
-       }
-
-       ERROR(rt2x00dev, "WPDMA TX/RX busy, aborting.\n");
-       return -EACCES;
-}
-
 static int rt2800pci_enable_radio(struct rt2x00_dev *rt2x00dev)
 {
        u32 reg;
@@ -487,10 +461,10 @@ static int rt2800pci_enable_radio(struct rt2x00_dev *rt2x00dev)
        /*
         * Initialize all registers.
         */
-       if (unlikely(rt2800pci_wait_wpdma_ready(rt2x00dev) ||
+       if (unlikely(rt2800_wait_wpdma_ready(rt2x00dev) ||
                     rt2800pci_init_queues(rt2x00dev) ||
                     rt2800_init_registers(rt2x00dev) ||
-                    rt2800pci_wait_wpdma_ready(rt2x00dev) ||
+                    rt2800_wait_wpdma_ready(rt2x00dev) ||
                     rt2800_init_bbp(rt2x00dev) ||
                     rt2800_init_rfcsr(rt2x00dev)))
                return -EIO;
@@ -570,7 +544,7 @@ static void rt2800pci_disable_radio(struct rt2x00_dev *rt2x00dev)
        rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e00);
 
        /* Wait for DMA, ignore error */
-       rt2800pci_wait_wpdma_ready(rt2x00dev);
+       rt2800_wait_wpdma_ready(rt2x00dev);
 }
 
 static int rt2800pci_set_state(struct rt2x00_dev *rt2x00dev,
@@ -835,7 +809,6 @@ static void rt2800pci_fill_rxdone(struct queue_entry *entry,
                                  struct rxdone_entry_desc *rxdesc)
 {
        struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
-       struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
        struct queue_entry_priv_pci *entry_priv = entry->priv_data;
        __le32 *rxd = entry_priv->desc;
        __le32 *rxwi = (__le32 *)entry->skb->data;
@@ -883,10 +856,8 @@ static void rt2800pci_fill_rxdone(struct queue_entry *entry,
        if (rt2x00_get_field32(rxd3, RXD_W3_MY_BSS))
                rxdesc->dev_flags |= RXDONE_MY_BSS;
 
-       if (rt2x00_get_field32(rxd3, RXD_W3_L2PAD)) {
+       if (rt2x00_get_field32(rxd3, RXD_W3_L2PAD))
                rxdesc->dev_flags |= RXDONE_L2PAD;
-               skbdesc->flags |= SKBDESC_L2_PADDED;
-       }
 
        if (rt2x00_get_field32(rxwi1, RXWI_W1_SHORT_GI))
                rxdesc->flags |= RX_FLAG_SHORT_GI;
@@ -927,7 +898,6 @@ static void rt2800pci_fill_rxdone(struct queue_entry *entry,
         * Remove TXWI descriptor from start of buffer.
         */
        skb_pull(entry->skb, RXWI_DESC_SIZE);
-       skb_trim(entry->skb, rxdesc->size);
 }
 
 /*
@@ -1133,8 +1103,7 @@ static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev)
        /*
         * This device requires firmware.
         */
-       if (!rt2x00_rt(&rt2x00dev->chip, RT2880) &&
-           !rt2x00_rt(&rt2x00dev->chip, RT3052))
+       if (!rt2x00_rt(rt2x00dev, RT2880) && !rt2x00_rt(rt2x00dev, RT3052))
                __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags);
        __set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags);
        __set_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags);
@@ -1221,7 +1190,7 @@ static const struct rt2x00_ops rt2800pci_ops = {
 /*
  * RT2800pci module information.
  */
-static struct pci_device_id rt2800pci_device_table[] = {
+static DEFINE_PCI_DEVICE_TABLE(rt2800pci_device_table) = {
        { PCI_DEVICE(0x1462, 0x891a), PCI_DEVICE_DATA(&rt2800pci_ops) },
        { PCI_DEVICE(0x1432, 0x7708), PCI_DEVICE_DATA(&rt2800pci_ops) },
        { PCI_DEVICE(0x1432, 0x7727), PCI_DEVICE_DATA(&rt2800pci_ops) },
@@ -1255,7 +1224,7 @@ MODULE_DEVICE_TABLE(pci, rt2800pci_device_table);
 #endif /* CONFIG_RT2800PCI_PCI */
 MODULE_LICENSE("GPL");
 
-#ifdef CONFIG_RT2800PCI_WISOC
+#ifdef CONFIG_RT2800PCI_SOC
 #if defined(CONFIG_RALINK_RT288X)
 __rt2x00soc_probe(RT2880, &rt2800pci_ops);
 #elif defined(CONFIG_RALINK_RT305X)
@@ -1273,7 +1242,7 @@ static struct platform_driver rt2800soc_driver = {
        .suspend        = rt2x00soc_suspend,
        .resume         = rt2x00soc_resume,
 };
-#endif /* CONFIG_RT2800PCI_WISOC */
+#endif /* CONFIG_RT2800PCI_SOC */
 
 #ifdef CONFIG_RT2800PCI_PCI
 static struct pci_driver rt2800pci_driver = {
@@ -1290,7 +1259,7 @@ static int __init rt2800pci_init(void)
 {
        int ret = 0;
 
-#ifdef CONFIG_RT2800PCI_WISOC
+#ifdef CONFIG_RT2800PCI_SOC
        ret = platform_driver_register(&rt2800soc_driver);
        if (ret)
                return ret;
@@ -1298,7 +1267,7 @@ static int __init rt2800pci_init(void)
 #ifdef CONFIG_RT2800PCI_PCI
        ret = pci_register_driver(&rt2800pci_driver);
        if (ret) {
-#ifdef CONFIG_RT2800PCI_WISOC
+#ifdef CONFIG_RT2800PCI_SOC
                platform_driver_unregister(&rt2800soc_driver);
 #endif
                return ret;
@@ -1313,7 +1282,7 @@ static void __exit rt2800pci_exit(void)
 #ifdef CONFIG_RT2800PCI_PCI
        pci_unregister_driver(&rt2800pci_driver);
 #endif
-#ifdef CONFIG_RT2800PCI_WISOC
+#ifdef CONFIG_RT2800PCI_SOC
        platform_driver_unregister(&rt2800soc_driver);
 #endif
 }
index ab95346cf6a369102043018b2ee917910c44840d..82755cf8b73e015e979406bd2b37f09f5cabfcc3 100644 (file)
@@ -92,7 +92,7 @@ static bool rt2800usb_check_crc(const u8 *data, const size_t len)
 static int rt2800usb_check_firmware(struct rt2x00_dev *rt2x00dev,
                                    const u8 *data, const size_t len)
 {
-       u16 chipset = (rt2x00_rev(&rt2x00dev->chip) >> 16) & 0xffff;
+       u16 chipset = (rt2x00_rev(rt2x00dev) >> 16) & 0xffff;
        size_t offset = 0;
 
        /*
@@ -138,7 +138,7 @@ static int rt2800usb_load_firmware(struct rt2x00_dev *rt2x00dev,
        u32 reg;
        u32 offset;
        u32 length;
-       u16 chipset = (rt2x00_rev(&rt2x00dev->chip) >> 16) & 0xffff;
+       u16 chipset = (rt2x00_rev(rt2x00dev) >> 16) & 0xffff;
 
        /*
         * Check which section of the firmware we need.
@@ -248,24 +248,6 @@ static void rt2800usb_toggle_rx(struct rt2x00_dev *rt2x00dev,
        rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
 }
 
-static int rt2800usb_wait_wpdma_ready(struct rt2x00_dev *rt2x00dev)
-{
-       unsigned int i;
-       u32 reg;
-
-       for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
-               rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, &reg);
-               if (!rt2x00_get_field32(reg, WPDMA_GLO_CFG_TX_DMA_BUSY) &&
-                   !rt2x00_get_field32(reg, WPDMA_GLO_CFG_RX_DMA_BUSY))
-                       return 0;
-
-               msleep(1);
-       }
-
-       ERROR(rt2x00dev, "WPDMA TX/RX busy, aborting.\n");
-       return -EACCES;
-}
-
 static int rt2800usb_enable_radio(struct rt2x00_dev *rt2x00dev)
 {
        u32 reg;
@@ -274,7 +256,7 @@ static int rt2800usb_enable_radio(struct rt2x00_dev *rt2x00dev)
        /*
         * Initialize all registers.
         */
-       if (unlikely(rt2800usb_wait_wpdma_ready(rt2x00dev) ||
+       if (unlikely(rt2800_wait_wpdma_ready(rt2x00dev) ||
                     rt2800_init_registers(rt2x00dev) ||
                     rt2800_init_bbp(rt2x00dev) ||
                     rt2800_init_rfcsr(rt2x00dev)))
@@ -295,9 +277,7 @@ static int rt2800usb_enable_radio(struct rt2x00_dev *rt2x00dev)
 
        rt2800_register_read(rt2x00dev, USB_DMA_CFG, &reg);
        rt2x00_set_field32(&reg, USB_DMA_CFG_PHY_CLEAR, 0);
-       /* Don't use bulk in aggregation when working with USB 1.1 */
-       rt2x00_set_field32(&reg, USB_DMA_CFG_RX_BULK_AGG_EN,
-                          (rt2x00dev->rx->usb_maxpacket == 512));
+       rt2x00_set_field32(&reg, USB_DMA_CFG_RX_BULK_AGG_EN, 0);
        rt2x00_set_field32(&reg, USB_DMA_CFG_RX_BULK_AGG_TIMEOUT, 128);
        /*
         * Total room for RX frames in kilobytes, PBF might still exceed
@@ -346,7 +326,7 @@ static void rt2800usb_disable_radio(struct rt2x00_dev *rt2x00dev)
        rt2800_register_write(rt2x00dev, TX_PIN_CFG, 0);
 
        /* Wait for DMA, ignore error */
-       rt2800usb_wait_wpdma_ready(rt2x00dev);
+       rt2800_wait_wpdma_ready(rt2x00dev);
 
        rt2x00usb_disable_radio(rt2x00dev);
 }
@@ -573,41 +553,57 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry,
 {
        struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
        struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
-       __le32 *rxd = (__le32 *)entry->skb->data;
+       __le32 *rxi = (__le32 *)entry->skb->data;
        __le32 *rxwi;
-       u32 rxd0;
+       __le32 *rxd;
+       u32 rxi0;
        u32 rxwi0;
        u32 rxwi1;
        u32 rxwi2;
        u32 rxwi3;
+       u32 rxd0;
+       int rx_pkt_len;
+
+       /*
+        * RX frame format is :
+        * | RXINFO | RXWI | header | L2 pad | payload | pad | RXD | USB pad |
+        *          |<------------ rx_pkt_len -------------->|
+        */
+       rt2x00_desc_read(rxi, 0, &rxi0);
+       rx_pkt_len = rt2x00_get_field32(rxi0, RXINFO_W0_USB_DMA_RX_PKT_LEN);
+
+       rxwi = (__le32 *)(entry->skb->data + RXINFO_DESC_SIZE);
+
+       /*
+        * FIXME : we need to check for rx_pkt_len validity
+        */
+       rxd = (__le32 *)(entry->skb->data + RXINFO_DESC_SIZE + rx_pkt_len);
 
        /*
         * Copy descriptor to the skbdesc->desc buffer, making it safe from
         * moving of frame data in rt2x00usb.
         */
-       memcpy(skbdesc->desc, rxd, skbdesc->desc_len);
-       rxd = (__le32 *)skbdesc->desc;
-       rxwi = &rxd[RXINFO_DESC_SIZE / sizeof(__le32)];
+       memcpy(skbdesc->desc, rxi, skbdesc->desc_len);
 
        /*
         * It is now safe to read the descriptor on all architectures.
         */
-       rt2x00_desc_read(rxd, 0, &rxd0);
        rt2x00_desc_read(rxwi, 0, &rxwi0);
        rt2x00_desc_read(rxwi, 1, &rxwi1);
        rt2x00_desc_read(rxwi, 2, &rxwi2);
        rt2x00_desc_read(rxwi, 3, &rxwi3);
+       rt2x00_desc_read(rxd, 0, &rxd0);
 
-       if (rt2x00_get_field32(rxd0, RXINFO_W0_CRC_ERROR))
+       if (rt2x00_get_field32(rxd0, RXD_W0_CRC_ERROR))
                rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC;
 
        if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) {
                rxdesc->cipher = rt2x00_get_field32(rxwi0, RXWI_W0_UDF);
                rxdesc->cipher_status =
-                   rt2x00_get_field32(rxd0, RXINFO_W0_CIPHER_ERROR);
+                   rt2x00_get_field32(rxd0, RXD_W0_CIPHER_ERROR);
        }
 
-       if (rt2x00_get_field32(rxd0, RXINFO_W0_DECRYPTED)) {
+       if (rt2x00_get_field32(rxd0, RXD_W0_DECRYPTED)) {
                /*
                 * Hardware has stripped IV/EIV data from 802.11 frame during
                 * decryption. Unfortunately the descriptor doesn't contain
@@ -622,13 +618,11 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry,
                        rxdesc->flags |= RX_FLAG_MMIC_ERROR;
        }
 
-       if (rt2x00_get_field32(rxd0, RXINFO_W0_MY_BSS))
+       if (rt2x00_get_field32(rxd0, RXD_W0_MY_BSS))
                rxdesc->dev_flags |= RXDONE_MY_BSS;
 
-       if (rt2x00_get_field32(rxd0, RXINFO_W0_L2PAD)) {
+       if (rt2x00_get_field32(rxd0, RXD_W0_L2PAD))
                rxdesc->dev_flags |= RXDONE_L2PAD;
-               skbdesc->flags |= SKBDESC_L2_PADDED;
-       }
 
        if (rt2x00_get_field32(rxwi1, RXWI_W1_SHORT_GI))
                rxdesc->flags |= RX_FLAG_SHORT_GI;
@@ -663,7 +657,6 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry,
         * Remove RXWI descriptor from start of buffer.
         */
        skb_pull(entry->skb, skbdesc->desc_len);
-       skb_trim(entry->skb, rxdesc->size);
 }
 
 /*
index 1e4340a182ef2d68bea70ec0eea6c3980d1ba417..d1d8ae94b4d4757026f90867ca46cf1e3dbb37c8 100644 (file)
@@ -79,6 +79,8 @@
  */
 #define TXINFO_DESC_SIZE               ( 1 * sizeof(__le32) )
 #define RXINFO_DESC_SIZE               ( 1 * sizeof(__le32) )
+#define RXWI_DESC_SIZE                 ( 4 * sizeof(__le32) )
+#define RXD_DESC_SIZE                  ( 1 * sizeof(__le32) )
 
 /*
  * TX Info structure
 #define TXINFO_W0_USB_DMA_NEXT_VALID   FIELD32(0x40000000)
 #define TXINFO_W0_USB_DMA_TX_BURST     FIELD32(0x80000000)
 
+/*
+ * RX Info structure
+ */
+
+/*
+ * Word 0
+ */
+
+#define RXINFO_W0_USB_DMA_RX_PKT_LEN   FIELD32(0x0000ffff)
+
+/*
+ * RX WI structure
+ */
+
+/*
+ * Word0
+ */
+#define RXWI_W0_WIRELESS_CLI_ID                FIELD32(0x000000ff)
+#define RXWI_W0_KEY_INDEX              FIELD32(0x00000300)
+#define RXWI_W0_BSSID                  FIELD32(0x00001c00)
+#define RXWI_W0_UDF                    FIELD32(0x0000e000)
+#define RXWI_W0_MPDU_TOTAL_BYTE_COUNT  FIELD32(0x0fff0000)
+#define RXWI_W0_TID                    FIELD32(0xf0000000)
+
+/*
+ * Word1
+ */
+#define RXWI_W1_FRAG                   FIELD32(0x0000000f)
+#define RXWI_W1_SEQUENCE               FIELD32(0x0000fff0)
+#define RXWI_W1_MCS                    FIELD32(0x007f0000)
+#define RXWI_W1_BW                     FIELD32(0x00800000)
+#define RXWI_W1_SHORT_GI               FIELD32(0x01000000)
+#define RXWI_W1_STBC                   FIELD32(0x06000000)
+#define RXWI_W1_PHYMODE                        FIELD32(0xc0000000)
+
+/*
+ * Word2
+ */
+#define RXWI_W2_RSSI0                  FIELD32(0x000000ff)
+#define RXWI_W2_RSSI1                  FIELD32(0x0000ff00)
+#define RXWI_W2_RSSI2                  FIELD32(0x00ff0000)
+
+/*
+ * Word3
+ */
+#define RXWI_W3_SNR0                   FIELD32(0x000000ff)
+#define RXWI_W3_SNR1                   FIELD32(0x0000ff00)
+
 /*
  * RX descriptor format for RX Ring.
  */
  * AMSDU: rx with 802.3 header, not 802.11 header.
  */
 
-#define RXINFO_W0_BA                   FIELD32(0x00000001)
-#define RXINFO_W0_DATA                 FIELD32(0x00000002)
-#define RXINFO_W0_NULLDATA             FIELD32(0x00000004)
-#define RXINFO_W0_FRAG                 FIELD32(0x00000008)
-#define RXINFO_W0_UNICAST_TO_ME                FIELD32(0x00000010)
-#define RXINFO_W0_MULTICAST            FIELD32(0x00000020)
-#define RXINFO_W0_BROADCAST            FIELD32(0x00000040)
-#define RXINFO_W0_MY_BSS               FIELD32(0x00000080)
-#define RXINFO_W0_CRC_ERROR            FIELD32(0x00000100)
-#define RXINFO_W0_CIPHER_ERROR         FIELD32(0x00000600)
-#define RXINFO_W0_AMSDU                        FIELD32(0x00000800)
-#define RXINFO_W0_HTC                  FIELD32(0x00001000)
-#define RXINFO_W0_RSSI                 FIELD32(0x00002000)
-#define RXINFO_W0_L2PAD                        FIELD32(0x00004000)
-#define RXINFO_W0_AMPDU                        FIELD32(0x00008000)
-#define RXINFO_W0_DECRYPTED            FIELD32(0x00010000)
-#define RXINFO_W0_PLCP_RSSI            FIELD32(0x00020000)
-#define RXINFO_W0_CIPHER_ALG           FIELD32(0x00040000)
-#define RXINFO_W0_LAST_AMSDU           FIELD32(0x00080000)
-#define RXINFO_W0_PLCP_SIGNAL          FIELD32(0xfff00000)
+#define RXD_W0_BA                      FIELD32(0x00000001)
+#define RXD_W0_DATA                    FIELD32(0x00000002)
+#define RXD_W0_NULLDATA                        FIELD32(0x00000004)
+#define RXD_W0_FRAG                    FIELD32(0x00000008)
+#define RXD_W0_UNICAST_TO_ME           FIELD32(0x00000010)
+#define RXD_W0_MULTICAST               FIELD32(0x00000020)
+#define RXD_W0_BROADCAST               FIELD32(0x00000040)
+#define RXD_W0_MY_BSS                  FIELD32(0x00000080)
+#define RXD_W0_CRC_ERROR               FIELD32(0x00000100)
+#define RXD_W0_CIPHER_ERROR            FIELD32(0x00000600)
+#define RXD_W0_AMSDU                   FIELD32(0x00000800)
+#define RXD_W0_HTC                     FIELD32(0x00001000)
+#define RXD_W0_RSSI                    FIELD32(0x00002000)
+#define RXD_W0_L2PAD                   FIELD32(0x00004000)
+#define RXD_W0_AMPDU                   FIELD32(0x00008000)
+#define RXD_W0_DECRYPTED               FIELD32(0x00010000)
+#define RXD_W0_PLCP_RSSI               FIELD32(0x00020000)
+#define RXD_W0_CIPHER_ALG              FIELD32(0x00040000)
+#define RXD_W0_LAST_AMSDU              FIELD32(0x00080000)
+#define RXD_W0_PLCP_SIGNAL             FIELD32(0xfff00000)
 
 #endif /* RT2800USB_H */
index dcfc8c25d1a787491b749ba0b3ca5f770066b981..096da85a66fa51a4631731d08d7a65a7236ca811 100644 (file)
 #define GET_DURATION(__size, __rate)   (((__size) * 8 * 10) / (__rate))
 #define GET_DURATION_RES(__size, __rate)(((__size) * 8 * 10) % (__rate))
 
+/*
+ * Determine the number of L2 padding bytes required between the header and
+ * the payload.
+ */
+#define L2PAD_SIZE(__hdrlen)   (-(__hdrlen) & 3)
+
 /*
  * Determine the alignment requirement,
  * to make sure the 802.11 payload is padded to a 4-byte boundrary
@@ -937,25 +943,25 @@ static inline void rt2x00_print_chip(struct rt2x00_dev *rt2x00dev)
             rt2x00dev->chip.rt, rt2x00dev->chip.rf, rt2x00dev->chip.rev);
 }
 
-static inline char rt2x00_rt(const struct rt2x00_chip *chipset, const u16 chip)
+static inline char rt2x00_rt(struct rt2x00_dev *rt2x00dev, const u16 rt)
 {
-       return (chipset->rt == chip);
+       return (rt2x00dev->chip.rt == rt);
 }
 
-static inline char rt2x00_rf(const struct rt2x00_chip *chipset, const u16 chip)
+static inline char rt2x00_rf(struct rt2x00_dev *rt2x00dev, const u16 rf)
 {
-       return (chipset->rf == chip);
+       return (rt2x00dev->chip.rf == rf);
 }
 
-static inline u32 rt2x00_rev(const struct rt2x00_chip *chipset)
+static inline u32 rt2x00_rev(struct rt2x00_dev *rt2x00dev)
 {
-       return chipset->rev;
+       return rt2x00dev->chip.rev;
 }
 
-static inline bool rt2x00_check_rev(const struct rt2x00_chip *chipset,
+static inline bool rt2x00_check_rev(struct rt2x00_dev *rt2x00dev,
                                    const u32 mask, const u32 rev)
 {
-       return ((chipset->rev & mask) == rev);
+       return ((rt2x00dev->chip.rev & mask) == rev);
 }
 
 static inline void rt2x00_set_chip_intf(struct rt2x00_dev *rt2x00dev,
@@ -964,20 +970,20 @@ static inline void rt2x00_set_chip_intf(struct rt2x00_dev *rt2x00dev,
        rt2x00dev->chip.intf = intf;
 }
 
-static inline bool rt2x00_intf(const struct rt2x00_chip *chipset,
+static inline bool rt2x00_intf(struct rt2x00_dev *rt2x00dev,
                               enum rt2x00_chip_intf intf)
 {
-       return (chipset->intf == intf);
+       return (rt2x00dev->chip.intf == intf);
 }
 
 static inline bool rt2x00_intf_is_pci(struct rt2x00_dev *rt2x00dev)
 {
-       return rt2x00_intf(&rt2x00dev->chip, RT2X00_CHIP_INTF_PCI);
+       return rt2x00_intf(rt2x00dev, RT2X00_CHIP_INTF_PCI);
 }
 
 static inline bool rt2x00_intf_is_usb(struct rt2x00_dev *rt2x00dev)
 {
-       return rt2x00_intf(&rt2x00dev->chip, RT2X00_CHIP_INTF_USB);
+       return rt2x00_intf(rt2x00dev, RT2X00_CHIP_INTF_USB);
 }
 
 /**
@@ -1019,9 +1025,9 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb);
 int rt2x00mac_start(struct ieee80211_hw *hw);
 void rt2x00mac_stop(struct ieee80211_hw *hw);
 int rt2x00mac_add_interface(struct ieee80211_hw *hw,
-                           struct ieee80211_if_init_conf *conf);
+                           struct ieee80211_vif *vif);
 void rt2x00mac_remove_interface(struct ieee80211_hw *hw,
-                               struct ieee80211_if_init_conf *conf);
+                               struct ieee80211_vif *vif);
 int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed);
 void rt2x00mac_configure_filter(struct ieee80211_hw *hw,
                                unsigned int changed_flags,
index 265e66dba552c2e3d0188b6baad46c0a32a4d6fb..b93731b79903308d06031326061fde8cde71ac8d 100644 (file)
@@ -385,9 +385,6 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
        memset(&rxdesc, 0, sizeof(rxdesc));
        rt2x00dev->ops->lib->fill_rxdone(entry, &rxdesc);
 
-       /* Trim buffer to correct size */
-       skb_trim(entry->skb, rxdesc.size);
-
        /*
         * The data behind the ieee80211 header must be
         * aligned on a 4 byte boundary.
@@ -404,11 +401,16 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
            (rxdesc.flags & RX_FLAG_IV_STRIPPED))
                rt2x00crypto_rx_insert_iv(entry->skb, header_length,
                                          &rxdesc);
-       else if (rxdesc.dev_flags & RXDONE_L2PAD)
+       else if (header_length &&
+                (rxdesc.size > header_length) &&
+                (rxdesc.dev_flags & RXDONE_L2PAD))
                rt2x00queue_remove_l2pad(entry->skb, header_length);
        else
                rt2x00queue_align_payload(entry->skb, header_length);
 
+       /* Trim buffer to correct size */
+       skb_trim(entry->skb, rxdesc.size);
+
        /*
         * Check if the frame was received using HT. In that case,
         * the rate is the MCS index and should be passed to mac80211
index de549c244ed821a2ddbd3eefa070a21d60b3ee0f..00f1f939f1bbf4589dfe857cc7e552a3512ab6ed 100644 (file)
@@ -187,10 +187,10 @@ void rt2x00mac_stop(struct ieee80211_hw *hw)
 EXPORT_SYMBOL_GPL(rt2x00mac_stop);
 
 int rt2x00mac_add_interface(struct ieee80211_hw *hw,
-                           struct ieee80211_if_init_conf *conf)
+                           struct ieee80211_vif *vif)
 {
        struct rt2x00_dev *rt2x00dev = hw->priv;
-       struct rt2x00_intf *intf = vif_to_intf(conf->vif);
+       struct rt2x00_intf *intf = vif_to_intf(vif);
        struct data_queue *queue = rt2x00queue_get_queue(rt2x00dev, QID_BEACON);
        struct queue_entry *entry = NULL;
        unsigned int i;
@@ -203,7 +203,7 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw,
            !test_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags))
                return -ENODEV;
 
-       switch (conf->type) {
+       switch (vif->type) {
        case NL80211_IFTYPE_AP:
                /*
                 * We don't support mixed combinations of
@@ -263,7 +263,7 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw,
         * increase interface count and start initialization.
         */
 
-       if (conf->type == NL80211_IFTYPE_AP)
+       if (vif->type == NL80211_IFTYPE_AP)
                rt2x00dev->intf_ap_count++;
        else
                rt2x00dev->intf_sta_count++;
@@ -273,16 +273,16 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw,
        mutex_init(&intf->beacon_skb_mutex);
        intf->beacon = entry;
 
-       if (conf->type == NL80211_IFTYPE_AP)
-               memcpy(&intf->bssid, conf->mac_addr, ETH_ALEN);
-       memcpy(&intf->mac, conf->mac_addr, ETH_ALEN);
+       if (vif->type == NL80211_IFTYPE_AP)
+               memcpy(&intf->bssid, vif->addr, ETH_ALEN);
+       memcpy(&intf->mac, vif->addr, ETH_ALEN);
 
        /*
         * The MAC adddress must be configured after the device
         * has been initialized. Otherwise the device can reset
         * the MAC registers.
         */
-       rt2x00lib_config_intf(rt2x00dev, intf, conf->type, intf->mac, NULL);
+       rt2x00lib_config_intf(rt2x00dev, intf, vif->type, intf->mac, NULL);
 
        /*
         * Some filters depend on the current working mode. We can force
@@ -296,10 +296,10 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw,
 EXPORT_SYMBOL_GPL(rt2x00mac_add_interface);
 
 void rt2x00mac_remove_interface(struct ieee80211_hw *hw,
-                               struct ieee80211_if_init_conf *conf)
+                               struct ieee80211_vif *vif)
 {
        struct rt2x00_dev *rt2x00dev = hw->priv;
-       struct rt2x00_intf *intf = vif_to_intf(conf->vif);
+       struct rt2x00_intf *intf = vif_to_intf(vif);
 
        /*
         * Don't allow interfaces to be remove while
@@ -307,11 +307,11 @@ void rt2x00mac_remove_interface(struct ieee80211_hw *hw,
         * no interface is present.
         */
        if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) ||
-           (conf->type == NL80211_IFTYPE_AP && !rt2x00dev->intf_ap_count) ||
-           (conf->type != NL80211_IFTYPE_AP && !rt2x00dev->intf_sta_count))
+           (vif->type == NL80211_IFTYPE_AP && !rt2x00dev->intf_ap_count) ||
+           (vif->type != NL80211_IFTYPE_AP && !rt2x00dev->intf_sta_count))
                return;
 
-       if (conf->type == NL80211_IFTYPE_AP)
+       if (vif->type == NL80211_IFTYPE_AP)
                rt2x00dev->intf_ap_count--;
        else
                rt2x00dev->intf_sta_count--;
index 0feb4d0e4668910905cdd44f72eb3232e349c4f0..801be436cf1d1bf8f01f16bfd33c84a1ca72641e 100644 (file)
@@ -41,6 +41,9 @@ int rt2x00pci_regbusy_read(struct rt2x00_dev *rt2x00dev,
 {
        unsigned int i;
 
+       if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
+               return 0;
+
        for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
                rt2x00pci_register_read(rt2x00dev, offset, reg);
                if (!rt2x00_get_field32(*reg, field))
index 9915a09141ef294ea94bf70d1afea8ac2ae9c5cc..0b4801a14601fa85b9878a6b4d8d32983411ae43 100644 (file)
@@ -177,55 +177,45 @@ void rt2x00queue_align_payload(struct sk_buff *skb, unsigned int header_length)
 
 void rt2x00queue_insert_l2pad(struct sk_buff *skb, unsigned int header_length)
 {
-       struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
-       unsigned int frame_length = skb->len;
+       unsigned int payload_length = skb->len - header_length;
        unsigned int header_align = ALIGN_SIZE(skb, 0);
        unsigned int payload_align = ALIGN_SIZE(skb, header_length);
-       unsigned int l2pad = 4 - (payload_align - header_align);
+       unsigned int l2pad = payload_length ? L2PAD_SIZE(header_length) : 0;
 
-       if (header_align == payload_align) {
-               /*
-                * Both header and payload must be moved the same
-                * amount of bytes to align them properly. This means
-                * we don't use the L2 padding but just move the entire
-                * frame.
-                */
-               rt2x00queue_align_frame(skb);
-       } else if (!payload_align) {
-               /*
-                * Simple L2 padding, only the header needs to be moved,
-                * the payload is already properly aligned.
-                */
-               skb_push(skb, header_align);
-               memmove(skb->data, skb->data + header_align, frame_length);
-               skbdesc->flags |= SKBDESC_L2_PADDED;
-       } else {
-               /*
-                *
-                * Complicated L2 padding, both header and payload need
-                * to be moved. By default we only move to the start
-                * of the buffer, so our header alignment needs to be
-                * increased if there is not enough room for the header
-                * to be moved.
-                */
-               if (payload_align > header_align)
-                       header_align += 4;
+       /*
+        * Adjust the header alignment if the payload needs to be moved more
+        * than the header.
+        */
+       if (payload_align > header_align)
+               header_align += 4;
+
+       /* There is nothing to do if no alignment is needed */
+       if (!header_align)
+               return;
+
+       /* Reserve the amount of space needed in front of the frame */
+       skb_push(skb, header_align);
+
+       /*
+        * Move the header.
+        */
+       memmove(skb->data, skb->data + header_align, header_length);
 
-               skb_push(skb, header_align);
-               memmove(skb->data, skb->data + header_align, header_length);
+       /* Move the payload, if present and if required */
+       if (payload_length && payload_align)
                memmove(skb->data + header_length + l2pad,
                        skb->data + header_length + l2pad + payload_align,
-                       frame_length - header_length);
-               skbdesc->flags |= SKBDESC_L2_PADDED;
-       }
+                       payload_length);
+
+       /* Trim the skb to the correct size */
+       skb_trim(skb, header_length + l2pad + payload_length);
 }
 
 void rt2x00queue_remove_l2pad(struct sk_buff *skb, unsigned int header_length)
 {
-       struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
-       unsigned int l2pad = 4 - (header_length & 3);
+       unsigned int l2pad = L2PAD_SIZE(header_length);
 
-       if (!l2pad || (skbdesc->flags & SKBDESC_L2_PADDED))
+       if (!l2pad)
                return;
 
        memmove(skb->data + l2pad, skb->data, header_length);
@@ -346,7 +336,9 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
         * Header and alignment information.
         */
        txdesc->header_length = ieee80211_get_hdrlen_from_skb(entry->skb);
-       txdesc->l2pad = ALIGN_SIZE(entry->skb, txdesc->header_length);
+       if (test_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags) &&
+           (entry->skb->len > txdesc->header_length))
+               txdesc->l2pad = L2PAD_SIZE(txdesc->header_length);
 
        /*
         * Check whether this frame is to be acked.
@@ -387,10 +379,13 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
 
        /*
         * Beacons and probe responses require the tsf timestamp
-        * to be inserted into the frame.
+        * to be inserted into the frame, except for a frame that has been injected
+        * through a monitor interface. This latter is needed for testing a
+        * monitor interface.
         */
-       if (ieee80211_is_beacon(hdr->frame_control) ||
-           ieee80211_is_probe_resp(hdr->frame_control))
+       if ((ieee80211_is_beacon(hdr->frame_control) ||
+           ieee80211_is_probe_resp(hdr->frame_control)) &&
+           (!(tx_info->flags & IEEE80211_TX_CTL_INJECTED)))
                __set_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags);
 
        /*
index 70775e5ba1ac65ca13807a5f8428e231b27cebb2..c1e482bb37b36f18544d27eeaef8e41b6e1852be 100644 (file)
@@ -92,8 +92,6 @@ enum data_queue_qid {
  * @SKBDESC_DMA_MAPPED_TX: &skb_dma field has been mapped for TX
  * @SKBDESC_IV_STRIPPED: Frame contained a IV/EIV provided by
  *     mac80211 but was stripped for processing by the driver.
- * @SKBDESC_L2_PADDED: Payload has been padded for 4-byte alignment,
- *     the padded bytes are located between header and payload.
  * @SKBDESC_NOT_MAC80211: Frame didn't originate from mac80211,
  *     don't try to pass it back.
  */
@@ -101,8 +99,7 @@ enum skb_frame_desc_flags {
        SKBDESC_DMA_MAPPED_RX = 1 << 0,
        SKBDESC_DMA_MAPPED_TX = 1 << 1,
        SKBDESC_IV_STRIPPED = 1 << 2,
-       SKBDESC_L2_PADDED = 1 << 3,
-       SKBDESC_NOT_MAC80211 = 1 << 4,
+       SKBDESC_NOT_MAC80211 = 1 << 3,
 };
 
 /**
index 0ca589306d7172eec437fb5dfcfd088ee0351ff0..1f97a797bc418adbb55b657ff126756e4ba8bc68 100644 (file)
@@ -637,8 +637,7 @@ static void rt61pci_config_antenna_5x(struct rt2x00_dev *rt2x00dev,
        rt61pci_bbp_read(rt2x00dev, 4, &r4);
        rt61pci_bbp_read(rt2x00dev, 77, &r77);
 
-       rt2x00_set_field8(&r3, BBP_R3_SMART_MODE,
-                         rt2x00_rf(&rt2x00dev->chip, RF5325));
+       rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, rt2x00_rf(rt2x00dev, RF5325));
 
        /*
         * Configure the RX antenna.
@@ -684,8 +683,7 @@ static void rt61pci_config_antenna_2x(struct rt2x00_dev *rt2x00dev,
        rt61pci_bbp_read(rt2x00dev, 4, &r4);
        rt61pci_bbp_read(rt2x00dev, 77, &r77);
 
-       rt2x00_set_field8(&r3, BBP_R3_SMART_MODE,
-                         rt2x00_rf(&rt2x00dev->chip, RF2529));
+       rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, rt2x00_rf(rt2x00dev, RF2529));
        rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END,
                          !test_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags));
 
@@ -833,12 +831,11 @@ static void rt61pci_config_ant(struct rt2x00_dev *rt2x00dev,
 
        rt2x00pci_register_write(rt2x00dev, PHY_CSR0, reg);
 
-       if (rt2x00_rf(&rt2x00dev->chip, RF5225) ||
-           rt2x00_rf(&rt2x00dev->chip, RF5325))
+       if (rt2x00_rf(rt2x00dev, RF5225) || rt2x00_rf(rt2x00dev, RF5325))
                rt61pci_config_antenna_5x(rt2x00dev, ant);
-       else if (rt2x00_rf(&rt2x00dev->chip, RF2527))
+       else if (rt2x00_rf(rt2x00dev, RF2527))
                rt61pci_config_antenna_2x(rt2x00dev, ant);
-       else if (rt2x00_rf(&rt2x00dev->chip, RF2529)) {
+       else if (rt2x00_rf(rt2x00dev, RF2529)) {
                if (test_bit(CONFIG_DOUBLE_ANTENNA, &rt2x00dev->flags))
                        rt61pci_config_antenna_2x(rt2x00dev, ant);
                else
@@ -879,8 +876,7 @@ static void rt61pci_config_channel(struct rt2x00_dev *rt2x00dev,
        rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower));
        rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset);
 
-       smart = !(rt2x00_rf(&rt2x00dev->chip, RF5225) ||
-                 rt2x00_rf(&rt2x00dev->chip, RF2527));
+       smart = !(rt2x00_rf(rt2x00dev, RF5225) || rt2x00_rf(rt2x00dev, RF2527));
 
        rt61pci_bbp_read(rt2x00dev, 3, &r3);
        rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, smart);
@@ -2302,10 +2298,10 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
        rt2x00_set_chip_rf(rt2x00dev, value, reg);
        rt2x00_print_chip(rt2x00dev);
 
-       if (!rt2x00_rf(&rt2x00dev->chip, RF5225) &&
-           !rt2x00_rf(&rt2x00dev->chip, RF5325) &&
-           !rt2x00_rf(&rt2x00dev->chip, RF2527) &&
-           !rt2x00_rf(&rt2x00dev->chip, RF2529)) {
+       if (!rt2x00_rf(rt2x00dev, RF5225) &&
+           !rt2x00_rf(rt2x00dev, RF5325) &&
+           !rt2x00_rf(rt2x00dev, RF2527) &&
+           !rt2x00_rf(rt2x00dev, RF2529)) {
                ERROR(rt2x00dev, "Invalid RF chipset detected.\n");
                return -ENODEV;
        }
@@ -2360,7 +2356,7 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
         * the antenna settings should be gathered from the NIC
         * eeprom word.
         */
-       if (rt2x00_rf(&rt2x00dev->chip, RF2529) &&
+       if (rt2x00_rf(rt2x00dev, RF2529) &&
            !test_bit(CONFIG_DOUBLE_ANTENNA, &rt2x00dev->flags)) {
                rt2x00dev->default_ant.rx =
                    ANTENNA_A + rt2x00_get_field16(eeprom, EEPROM_NIC_RX_FIXED);
@@ -2571,8 +2567,7 @@ static int rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
                spec->channels = rf_vals_seq;
        }
 
-       if (rt2x00_rf(&rt2x00dev->chip, RF5225) ||
-           rt2x00_rf(&rt2x00dev->chip, RF5325)) {
+       if (rt2x00_rf(rt2x00dev, RF5225) || rt2x00_rf(rt2x00dev, RF5325)) {
                spec->supported_bands |= SUPPORT_BAND_5GHZ;
                spec->num_channels = ARRAY_SIZE(rf_vals_seq);
        }
@@ -2812,7 +2807,7 @@ static const struct rt2x00_ops rt61pci_ops = {
 /*
  * RT61pci module information.
  */
-static struct pci_device_id rt61pci_device_table[] = {
+static DEFINE_PCI_DEVICE_TABLE(rt61pci_device_table) = {
        /* RT2561s */
        { PCI_DEVICE(0x1814, 0x0301), PCI_DEVICE_DATA(&rt61pci_ops) },
        /* RT2561 v2 */
index ced3b6ab5e16f89ba4c794d2e131ef55929f362c..a02691294395e1163484b652f1ac0a137af5131c 100644 (file)
@@ -136,8 +136,8 @@ static void rt73usb_rf_write(struct rt2x00_dev *rt2x00dev,
                 * all others contain 20 bits.
                 */
                rt2x00_set_field32(&reg, PHY_CSR4_NUMBER_OF_BITS,
-                                  20 + (rt2x00_rf(&rt2x00dev->chip, RF5225) ||
-                                        rt2x00_rf(&rt2x00dev->chip, RF2527)));
+                                  20 + (rt2x00_rf(rt2x00dev, RF5225) ||
+                                        rt2x00_rf(rt2x00dev, RF2527)));
                rt2x00_set_field32(&reg, PHY_CSR4_IF_SELECT, 0);
                rt2x00_set_field32(&reg, PHY_CSR4_BUSY, 1);
 
@@ -741,11 +741,9 @@ static void rt73usb_config_ant(struct rt2x00_dev *rt2x00dev,
 
        rt2x00usb_register_write(rt2x00dev, PHY_CSR0, reg);
 
-       if (rt2x00_rf(&rt2x00dev->chip, RF5226) ||
-           rt2x00_rf(&rt2x00dev->chip, RF5225))
+       if (rt2x00_rf(rt2x00dev, RF5226) || rt2x00_rf(rt2x00dev, RF5225))
                rt73usb_config_antenna_5x(rt2x00dev, ant);
-       else if (rt2x00_rf(&rt2x00dev->chip, RF2528) ||
-                rt2x00_rf(&rt2x00dev->chip, RF2527))
+       else if (rt2x00_rf(rt2x00dev, RF2528) || rt2x00_rf(rt2x00dev, RF2527))
                rt73usb_config_antenna_2x(rt2x00dev, ant);
 }
 
@@ -779,8 +777,7 @@ static void rt73usb_config_channel(struct rt2x00_dev *rt2x00dev,
        rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower));
        rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset);
 
-       smart = !(rt2x00_rf(&rt2x00dev->chip, RF5225) ||
-                 rt2x00_rf(&rt2x00dev->chip, RF2527));
+       smart = !(rt2x00_rf(rt2x00dev, RF5225) || rt2x00_rf(rt2x00dev, RF2527));
 
        rt73usb_bbp_read(rt2x00dev, 3, &r3);
        rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, smart);
@@ -1210,8 +1207,7 @@ static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev)
        rt2x00usb_register_write(rt2x00dev, SEC_CSR5, 0x00000000);
 
        reg = 0x000023b0;
-       if (rt2x00_rf(&rt2x00dev->chip, RF5225) ||
-           rt2x00_rf(&rt2x00dev->chip, RF2527))
+       if (rt2x00_rf(rt2x00dev, RF5225) || rt2x00_rf(rt2x00dev, RF2527))
                rt2x00_set_field32(&reg, PHY_CSR1_RF_RPI, 1);
        rt2x00usb_register_write(rt2x00dev, PHY_CSR1, reg);
 
@@ -1827,16 +1823,16 @@ static int rt73usb_init_eeprom(struct rt2x00_dev *rt2x00dev)
        rt2x00_set_chip(rt2x00dev, RT2571, value, reg);
        rt2x00_print_chip(rt2x00dev);
 
-       if (!rt2x00_check_rev(&rt2x00dev->chip, 0x000ffff0, 0x25730) ||
-           rt2x00_check_rev(&rt2x00dev->chip, 0x0000000f, 0)) {
+       if (!rt2x00_check_rev(rt2x00dev, 0x000ffff0, 0x25730) ||
+           rt2x00_check_rev(rt2x00dev, 0x0000000f, 0)) {
                ERROR(rt2x00dev, "Invalid RT chipset detected.\n");
                return -ENODEV;
        }
 
-       if (!rt2x00_rf(&rt2x00dev->chip, RF5226) &&
-           !rt2x00_rf(&rt2x00dev->chip, RF2528) &&
-           !rt2x00_rf(&rt2x00dev->chip, RF5225) &&
-           !rt2x00_rf(&rt2x00dev->chip, RF2527)) {
+       if (!rt2x00_rf(rt2x00dev, RF5226) &&
+           !rt2x00_rf(rt2x00dev, RF2528) &&
+           !rt2x00_rf(rt2x00dev, RF5225) &&
+           !rt2x00_rf(rt2x00dev, RF2527)) {
                ERROR(rt2x00dev, "Invalid RF chipset detected.\n");
                return -ENODEV;
        }
@@ -2081,17 +2077,17 @@ static int rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
        spec->supported_bands = SUPPORT_BAND_2GHZ;
        spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM;
 
-       if (rt2x00_rf(&rt2x00dev->chip, RF2528)) {
+       if (rt2x00_rf(rt2x00dev, RF2528)) {
                spec->num_channels = ARRAY_SIZE(rf_vals_bg_2528);
                spec->channels = rf_vals_bg_2528;
-       } else if (rt2x00_rf(&rt2x00dev->chip, RF5226)) {
+       } else if (rt2x00_rf(rt2x00dev, RF5226)) {
                spec->supported_bands |= SUPPORT_BAND_5GHZ;
                spec->num_channels = ARRAY_SIZE(rf_vals_5226);
                spec->channels = rf_vals_5226;
-       } else if (rt2x00_rf(&rt2x00dev->chip, RF2527)) {
+       } else if (rt2x00_rf(rt2x00dev, RF2527)) {
                spec->num_channels = 14;
                spec->channels = rf_vals_5225_2527;
-       } else if (rt2x00_rf(&rt2x00dev->chip, RF5225)) {
+       } else if (rt2x00_rf(rt2x00dev, RF5225)) {
                spec->supported_bands |= SUPPORT_BAND_5GHZ;
                spec->num_channels = ARRAY_SIZE(rf_vals_5225_2527);
                spec->channels = rf_vals_5225_2527;
@@ -2354,6 +2350,7 @@ static struct usb_device_id rt73usb_device_table[] = {
        { USB_DEVICE(0x08dd, 0x0120), USB_DEVICE_DATA(&rt73usb_ops) },
        /* Buffalo */
        { USB_DEVICE(0x0411, 0x00d8), USB_DEVICE_DATA(&rt73usb_ops) },
+       { USB_DEVICE(0x0411, 0x00d9), USB_DEVICE_DATA(&rt73usb_ops) },
        { USB_DEVICE(0x0411, 0x00f4), USB_DEVICE_DATA(&rt73usb_ops) },
        { USB_DEVICE(0x0411, 0x0116), USB_DEVICE_DATA(&rt73usb_ops) },
        { USB_DEVICE(0x0411, 0x0119), USB_DEVICE_DATA(&rt73usb_ops) },
index 8721282a8185d05d7db2be8cf7301467cdd26a80..de3844fe06d84bfecde1cbb2d4db3e8c7b5dca94 100644 (file)
@@ -60,7 +60,6 @@ struct rtl8180_priv {
        struct rtl818x_csr __iomem *map;
        const struct rtl818x_rf_ops *rf;
        struct ieee80211_vif *vif;
-       int mode;
 
        /* rtl8180 driver specific */
        spinlock_t lock;
index 8a40a14399842c46b4dc9b845db79ce1141f1718..b9192bfcc5576168e306d4d768e9a0e4cf9f4185 100644 (file)
@@ -33,7 +33,7 @@ MODULE_AUTHOR("Andrea Merello <andreamrl@tiscali.it>");
 MODULE_DESCRIPTION("RTL8180 / RTL8185 PCI wireless driver");
 MODULE_LICENSE("GPL");
 
-static struct pci_device_id rtl8180_table[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(rtl8180_table) = {
        /* rtl8185 */
        { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8185) },
        { PCI_DEVICE(PCI_VENDOR_ID_BELKIN, 0x700f) },
@@ -82,8 +82,6 @@ static const struct ieee80211_channel rtl818x_channels[] = {
 };
 
 
-
-
 void rtl8180_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data)
 {
        struct rtl8180_priv *priv = dev->priv;
@@ -615,7 +613,6 @@ static int rtl8180_start(struct ieee80211_hw *dev)
        reg |= RTL818X_CMD_TX_ENABLE;
        rtl818x_iowrite8(priv, &priv->map->CMD, reg);
 
-       priv->mode = NL80211_IFTYPE_MONITOR;
        return 0;
 
  err_free_rings:
@@ -633,8 +630,6 @@ static void rtl8180_stop(struct ieee80211_hw *dev)
        u8 reg;
        int i;
 
-       priv->mode = NL80211_IFTYPE_UNSPECIFIED;
-
        rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0);
 
        reg = rtl818x_ioread8(priv, &priv->map->CMD);
@@ -657,38 +652,39 @@ static void rtl8180_stop(struct ieee80211_hw *dev)
 }
 
 static int rtl8180_add_interface(struct ieee80211_hw *dev,
-                                struct ieee80211_if_init_conf *conf)
+                                struct ieee80211_vif *vif)
 {
        struct rtl8180_priv *priv = dev->priv;
 
-       if (priv->mode != NL80211_IFTYPE_MONITOR)
-               return -EOPNOTSUPP;
+       /*
+        * We only support one active interface at a time.
+        */
+       if (priv->vif)
+               return -EBUSY;
 
-       switch (conf->type) {
+       switch (vif->type) {
        case NL80211_IFTYPE_STATION:
-               priv->mode = conf->type;
                break;
        default:
                return -EOPNOTSUPP;
        }
 
-       priv->vif = conf->vif;
+       priv->vif = vif;
 
        rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
        rtl818x_iowrite32(priv, (__le32 __iomem *)&priv->map->MAC[0],
-                         le32_to_cpu(*(__le32 *)conf->mac_addr));
+                         le32_to_cpu(*(__le32 *)vif->addr));
        rtl818x_iowrite16(priv, (__le16 __iomem *)&priv->map->MAC[4],
-                         le16_to_cpu(*(__le16 *)(conf->mac_addr + 4)));
+                         le16_to_cpu(*(__le16 *)(vif->addr + 4)));
        rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
 
        return 0;
 }
 
 static void rtl8180_remove_interface(struct ieee80211_hw *dev,
-                                    struct ieee80211_if_init_conf *conf)
+                                    struct ieee80211_vif *vif)
 {
        struct rtl8180_priv *priv = dev->priv;
-       priv->mode = NL80211_IFTYPE_MONITOR;
        priv->vif = NULL;
 }
 
index 6af0f3f71f3a4b6f01789da274a31fdbcba00897..6bb32112e65c16b8b3255b4cd45eb531ea0f4672 100644 (file)
@@ -92,7 +92,7 @@ struct rtl8187_priv {
        struct rtl818x_csr *map;
        const struct rtl818x_rf_ops *rf;
        struct ieee80211_vif *vif;
-       int mode;
+
        /* The mutex protects the TX loopback state.
         * Any attempt to set channels concurrently locks the device.
         */
index bc5726dd5fe49f5fc7582f4a94d6bce4402de7af..f336c63053c1a052bd31a146ef54cfc643a71812 100644 (file)
@@ -1018,31 +1018,30 @@ static void rtl8187_stop(struct ieee80211_hw *dev)
 }
 
 static int rtl8187_add_interface(struct ieee80211_hw *dev,
-                                struct ieee80211_if_init_conf *conf)
+                                struct ieee80211_vif *vif)
 {
        struct rtl8187_priv *priv = dev->priv;
        int i;
        int ret = -EOPNOTSUPP;
 
        mutex_lock(&priv->conf_mutex);
-       if (priv->mode != NL80211_IFTYPE_MONITOR)
+       if (priv->vif)
                goto exit;
 
-       switch (conf->type) {
+       switch (vif->type) {
        case NL80211_IFTYPE_STATION:
-               priv->mode = conf->type;
                break;
        default:
                goto exit;
        }
 
        ret = 0;
-       priv->vif = conf->vif;
+       priv->vif = vif;
 
        rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
        for (i = 0; i < ETH_ALEN; i++)
                rtl818x_iowrite8(priv, &priv->map->MAC[i],
-                                ((u8 *)conf->mac_addr)[i]);
+                                ((u8 *)vif->addr)[i]);
        rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
 
 exit:
@@ -1051,11 +1050,10 @@ exit:
 }
 
 static void rtl8187_remove_interface(struct ieee80211_hw *dev,
-                                    struct ieee80211_if_init_conf *conf)
+                                    struct ieee80211_vif *vif)
 {
        struct rtl8187_priv *priv = dev->priv;
        mutex_lock(&priv->conf_mutex);
-       priv->mode = NL80211_IFTYPE_MONITOR;
        priv->vif = NULL;
        mutex_unlock(&priv->conf_mutex);
 }
@@ -1365,7 +1363,6 @@ static int __devinit rtl8187_probe(struct usb_interface *intf,
        dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band;
 
 
-       priv->mode = NL80211_IFTYPE_MONITOR;
        dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
                     IEEE80211_HW_SIGNAL_DBM |
                     IEEE80211_HW_RX_INCLUDES_FCS;
index ded44c045eb24307a6377e18eec161a27247d922..f82aa8b4bdde588f95ff0ba812f7eed1f590dddc 100644 (file)
@@ -33,7 +33,7 @@ static void led_turn_on(struct work_struct *work)
        struct rtl8187_led *led = &priv->led_tx;
 
        /* Don't change the LED, when the device is down. */
-       if (priv->mode == NL80211_IFTYPE_UNSPECIFIED)
+       if (!priv->vif || priv->vif->type == NL80211_IFTYPE_UNSPECIFIED)
                return ;
 
        /* Skip if the LED is not registered. */
@@ -71,7 +71,7 @@ static void led_turn_off(struct work_struct *work)
        struct rtl8187_led *led = &priv->led_tx;
 
        /* Don't change the LED, when the device is down. */
-       if (priv->mode == NL80211_IFTYPE_UNSPECIFIED)
+       if (!priv->vif || priv->vif->type == NL80211_IFTYPE_UNSPECIFIED)
                return ;
 
        /* Skip if the LED is not registered. */
index 054533f7a12432554b424156ad4d2a436badca1f..6301578d15654e8cdccde6f3473fe7ff2417daf9 100644 (file)
@@ -247,6 +247,7 @@ struct wl1251_debugfs {
        struct dentry *rxpipe_tx_xfr_host_int_trig_rx_data;
 
        struct dentry *tx_queue_len;
+       struct dentry *tx_queue_status;
 
        struct dentry *retry_count;
        struct dentry *excessive_retries;
index acfa086dbfc5787d673b6e75ac2883dada80fc63..beff084040b569499efae9dc637a15bb25be3c34 100644 (file)
@@ -976,3 +976,72 @@ out:
        kfree(acx);
        return ret;
 }
+
+int wl1251_acx_ac_cfg(struct wl1251 *wl, u8 ac, u8 cw_min, u16 cw_max,
+                     u8 aifs, u16 txop)
+{
+       struct wl1251_acx_ac_cfg *acx;
+       int ret = 0;
+
+       wl1251_debug(DEBUG_ACX, "acx ac cfg %d cw_ming %d cw_max %d "
+                    "aifs %d txop %d", ac, cw_min, cw_max, aifs, txop);
+
+       acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+
+       if (!acx) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       acx->ac = ac;
+       acx->cw_min = cw_min;
+       acx->cw_max = cw_max;
+       acx->aifsn = aifs;
+       acx->txop_limit = txop;
+
+       ret = wl1251_cmd_configure(wl, ACX_AC_CFG, acx, sizeof(*acx));
+       if (ret < 0) {
+               wl1251_warning("acx ac cfg failed: %d", ret);
+               goto out;
+       }
+
+out:
+       kfree(acx);
+       return ret;
+}
+
+int wl1251_acx_tid_cfg(struct wl1251 *wl, u8 queue,
+                      enum wl1251_acx_channel_type type,
+                      u8 tsid, enum wl1251_acx_ps_scheme ps_scheme,
+                      enum wl1251_acx_ack_policy ack_policy)
+{
+       struct wl1251_acx_tid_cfg *acx;
+       int ret = 0;
+
+       wl1251_debug(DEBUG_ACX, "acx tid cfg %d type %d tsid %d "
+                    "ps_scheme %d ack_policy %d", queue, type, tsid,
+                    ps_scheme, ack_policy);
+
+       acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+
+       if (!acx) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       acx->queue = queue;
+       acx->type = type;
+       acx->tsid = tsid;
+       acx->ps_scheme = ps_scheme;
+       acx->ack_policy = ack_policy;
+
+       ret = wl1251_cmd_configure(wl, ACX_TID_CFG, acx, sizeof(*acx));
+       if (ret < 0) {
+               wl1251_warning("acx tid cfg failed: %d", ret);
+               goto out;
+       }
+
+out:
+       kfree(acx);
+       return ret;
+}
index 652371432cd81c109bc8ac48d3066c8eed81101b..26160c45784cbdae95eb253c1776b2dd796ca75c 100644 (file)
@@ -1166,6 +1166,87 @@ struct wl1251_acx_wr_tbtt_and_dtim {
        u8  padding;
 } __attribute__ ((packed));
 
+struct wl1251_acx_ac_cfg {
+       struct acx_header header;
+
+       /*
+        * Access Category - The TX queue's access category
+        * (refer to AccessCategory_enum)
+        */
+       u8 ac;
+
+       /*
+        * The contention window minimum size (in slots) for
+        * the access class.
+        */
+       u8 cw_min;
+
+       /*
+        * The contention window maximum size (in slots) for
+        * the access class.
+        */
+       u16 cw_max;
+
+       /* The AIF value (in slots) for the access class. */
+       u8 aifsn;
+
+       u8 reserved;
+
+       /* The TX Op Limit (in microseconds) for the access class. */
+       u16 txop_limit;
+} __attribute__ ((packed));
+
+
+enum wl1251_acx_channel_type {
+       CHANNEL_TYPE_DCF        = 0,
+       CHANNEL_TYPE_EDCF       = 1,
+       CHANNEL_TYPE_HCCA       = 2,
+};
+
+enum wl1251_acx_ps_scheme {
+       /* regular ps: simple sending of packets */
+       WL1251_ACX_PS_SCHEME_LEGACY     = 0,
+
+       /* sending a packet triggers a unscheduled apsd downstream */
+       WL1251_ACX_PS_SCHEME_UPSD_TRIGGER       = 1,
+
+       /* a pspoll packet will be sent before every data packet */
+       WL1251_ACX_PS_SCHEME_LEGACY_PSPOLL      = 2,
+
+       /* scheduled apsd mode */
+       WL1251_ACX_PS_SCHEME_SAPSD              = 3,
+};
+
+enum wl1251_acx_ack_policy {
+       WL1251_ACX_ACK_POLICY_LEGACY    = 0,
+       WL1251_ACX_ACK_POLICY_NO_ACK    = 1,
+       WL1251_ACX_ACK_POLICY_BLOCK     = 2,
+};
+
+struct wl1251_acx_tid_cfg {
+       struct acx_header header;
+
+       /* tx queue id number (0-7) */
+       u8 queue;
+
+       /* channel access type for the queue, enum wl1251_acx_channel_type */
+       u8 type;
+
+       /* EDCA: ac index (0-3), HCCA: traffic stream id (8-15) */
+       u8 tsid;
+
+       /* ps scheme of the specified queue, enum wl1251_acx_ps_scheme */
+       u8 ps_scheme;
+
+       /* the tx queue ack policy, enum wl1251_acx_ack_policy */
+       u8 ack_policy;
+
+       u8 padding[3];
+
+       /* not supported */
+       u32 apsdconf[2];
+} __attribute__ ((packed));
+
 /*************************************************************************
 
     Host Interrupt Register (WiLink -> Host)
@@ -1322,5 +1403,11 @@ int wl1251_acx_tsf_info(struct wl1251 *wl, u64 *mactime);
 int wl1251_acx_rate_policies(struct wl1251 *wl);
 int wl1251_acx_mem_cfg(struct wl1251 *wl);
 int wl1251_acx_wr_tbtt_and_dtim(struct wl1251 *wl, u16 tbtt, u8 dtim);
+int wl1251_acx_ac_cfg(struct wl1251 *wl, u8 ac, u8 cw_min, u16 cw_max,
+                     u8 aifs, u16 txop);
+int wl1251_acx_tid_cfg(struct wl1251 *wl, u8 queue,
+                      enum wl1251_acx_channel_type type,
+                      u8 tsid, enum wl1251_acx_ps_scheme ps_scheme,
+                      enum wl1251_acx_ack_policy ack_policy);
 
 #endif /* __WL1251_ACX_H__ */
index 770f260726bd52c7c85f7ad5cbd55abc44907030..0320b478bb3f0dfde1fc6cfbee04859fe9b01a35 100644 (file)
@@ -410,3 +410,86 @@ out:
        kfree(cmd);
        return ret;
 }
+
+int wl1251_cmd_scan(struct wl1251 *wl, u8 *ssid, size_t ssid_len,
+                   struct ieee80211_channel *channels[],
+                   unsigned int n_channels, unsigned int n_probes)
+{
+       struct wl1251_cmd_scan *cmd;
+       int i, ret = 0;
+
+       wl1251_debug(DEBUG_CMD, "cmd scan");
+
+       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+       if (!cmd)
+               return -ENOMEM;
+
+       cmd->params.rx_config_options = cpu_to_le32(CFG_RX_ALL_GOOD);
+       cmd->params.rx_filter_options = cpu_to_le32(CFG_RX_PRSP_EN |
+                                                   CFG_RX_MGMT_EN |
+                                                   CFG_RX_BCN_EN);
+       cmd->params.scan_options = 0;
+       cmd->params.num_channels = n_channels;
+       cmd->params.num_probe_requests = n_probes;
+       cmd->params.tx_rate = cpu_to_le16(1 << 1); /* 2 Mbps */
+       cmd->params.tid_trigger = 0;
+
+       for (i = 0; i < n_channels; i++) {
+               cmd->channels[i].min_duration =
+                       cpu_to_le32(WL1251_SCAN_MIN_DURATION);
+               cmd->channels[i].max_duration =
+                       cpu_to_le32(WL1251_SCAN_MAX_DURATION);
+               memset(&cmd->channels[i].bssid_lsb, 0xff, 4);
+               memset(&cmd->channels[i].bssid_msb, 0xff, 2);
+               cmd->channels[i].early_termination = 0;
+               cmd->channels[i].tx_power_att = 0;
+               cmd->channels[i].channel = channels[i]->hw_value;
+       }
+
+       cmd->params.ssid_len = ssid_len;
+       if (ssid)
+               memcpy(cmd->params.ssid, ssid, ssid_len);
+
+       ret = wl1251_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd));
+       if (ret < 0) {
+               wl1251_error("cmd scan failed: %d", ret);
+               goto out;
+       }
+
+       wl1251_mem_read(wl, wl->cmd_box_addr, cmd, sizeof(*cmd));
+
+       if (cmd->header.status != CMD_STATUS_SUCCESS) {
+               wl1251_error("cmd scan status wasn't success: %d",
+                            cmd->header.status);
+               ret = -EIO;
+               goto out;
+       }
+
+out:
+       kfree(cmd);
+       return ret;
+}
+
+int wl1251_cmd_trigger_scan_to(struct wl1251 *wl, u32 timeout)
+{
+       struct wl1251_cmd_trigger_scan_to *cmd;
+       int ret;
+
+       wl1251_debug(DEBUG_CMD, "cmd trigger scan to");
+
+       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+       if (!cmd)
+               return -ENOMEM;
+
+       cmd->timeout = timeout;
+
+       ret = wl1251_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd));
+       if (ret < 0) {
+               wl1251_error("cmd trigger scan to failed: %d", ret);
+               goto out;
+       }
+
+out:
+       kfree(cmd);
+       return ret;
+}
index dff798ad0ef52e4fd18859196864a0a836640bcd..4ad67cae94d2a6fedf57bb6c94d01276ab06ee84 100644 (file)
@@ -27,6 +27,8 @@
 
 #include "wl1251.h"
 
+#include <net/cfg80211.h>
+
 struct acx_header;
 
 int wl1251_cmd_send(struct wl1251 *wl, u16 type, void *buf, size_t buf_len);
@@ -43,6 +45,10 @@ int wl1251_cmd_read_memory(struct wl1251 *wl, u32 addr, void *answer,
                           size_t len);
 int wl1251_cmd_template_set(struct wl1251 *wl, u16 cmd_id,
                            void *buf, size_t buf_len);
+int wl1251_cmd_scan(struct wl1251 *wl, u8 *ssid, size_t ssid_len,
+                   struct ieee80211_channel *channels[],
+                   unsigned int n_channels, unsigned int n_probes);
+int wl1251_cmd_trigger_scan_to(struct wl1251 *wl, u32 timeout);
 
 /* unit ms */
 #define WL1251_COMMAND_TIMEOUT 2000
@@ -163,8 +169,12 @@ struct cmd_read_write_memory {
 #define CMDMBOX_HEADER_LEN 4
 #define CMDMBOX_INFO_ELEM_HEADER_LEN 4
 
+#define WL1251_SCAN_MIN_DURATION 30000
+#define WL1251_SCAN_MAX_DURATION 60000
+
+#define WL1251_SCAN_NUM_PROBES 3
 
-struct basic_scan_parameters {
+struct wl1251_scan_parameters {
        u32 rx_config_options;
        u32 rx_filter_options;
 
@@ -189,11 +199,11 @@ struct basic_scan_parameters {
 
        u8 tid_trigger;
        u8 ssid_len;
-       u32 ssid[8];
+       u8 ssid[32];
 
 } __attribute__ ((packed));
 
-struct basic_scan_channel_parameters {
+struct wl1251_scan_ch_parameters {
        u32 min_duration; /* in TU */
        u32 max_duration; /* in TU */
        u32 bssid_lsb;
@@ -213,11 +223,11 @@ struct basic_scan_channel_parameters {
 /* SCAN parameters */
 #define SCAN_MAX_NUM_OF_CHANNELS 16
 
-struct cmd_scan {
+struct wl1251_cmd_scan {
        struct wl1251_cmd_header header;
 
-       struct basic_scan_parameters params;
-       struct basic_scan_channel_parameters channels[SCAN_MAX_NUM_OF_CHANNELS];
+       struct wl1251_scan_parameters params;
+       struct wl1251_scan_ch_parameters channels[SCAN_MAX_NUM_OF_CHANNELS];
 } __attribute__ ((packed));
 
 enum {
index a00723059f83f3ef497d1649e082f36103a6d93e..0ccba57fb9fb9548eaceaf267481af256f9928d3 100644 (file)
@@ -237,6 +237,27 @@ static const struct file_operations tx_queue_len_ops = {
        .open = wl1251_open_file_generic,
 };
 
+static ssize_t tx_queue_status_read(struct file *file, char __user *userbuf,
+                                   size_t count, loff_t *ppos)
+{
+       struct wl1251 *wl = file->private_data;
+       char buf[3], status;
+       int len;
+
+       if (wl->tx_queue_stopped)
+               status = 's';
+       else
+               status = 'r';
+
+       len = scnprintf(buf, sizeof(buf), "%c\n", status);
+       return simple_read_from_buffer(userbuf, count, ppos, buf, len);
+}
+
+static const struct file_operations tx_queue_status_ops = {
+       .read = tx_queue_status_read,
+       .open = wl1251_open_file_generic,
+};
+
 static void wl1251_debugfs_delete_files(struct wl1251 *wl)
 {
        DEBUGFS_FWSTATS_DEL(tx, internal_desc_overflow);
@@ -331,6 +352,7 @@ static void wl1251_debugfs_delete_files(struct wl1251 *wl)
        DEBUGFS_FWSTATS_DEL(rxpipe, tx_xfr_host_int_trig_rx_data);
 
        DEBUGFS_DEL(tx_queue_len);
+       DEBUGFS_DEL(tx_queue_status);
        DEBUGFS_DEL(retry_count);
        DEBUGFS_DEL(excessive_retries);
 }
@@ -431,6 +453,7 @@ static int wl1251_debugfs_add_files(struct wl1251 *wl)
        DEBUGFS_FWSTATS_ADD(rxpipe, tx_xfr_host_int_trig_rx_data);
 
        DEBUGFS_ADD(tx_queue_len, wl->debugfs.rootdir);
+       DEBUGFS_ADD(tx_queue_status, wl->debugfs.rootdir);
        DEBUGFS_ADD(retry_count, wl->debugfs.rootdir);
        DEBUGFS_ADD(excessive_retries, wl->debugfs.rootdir);
 
index 5cb573383eeb4f78f937665adcee44014d38571c..5aad56ea71536fa1dbc5875d601f7bd76eaae961 100644 (file)
@@ -294,6 +294,11 @@ static int wl1251_hw_init_tx_queue_config(struct wl1251 *wl)
                        goto out;
        }
 
+       wl1251_acx_ac_cfg(wl, AC_BE, CWMIN_BE, CWMAX_BE, AIFS_DIFS, TXOP_BE);
+       wl1251_acx_ac_cfg(wl, AC_BK, CWMIN_BK, CWMAX_BK, AIFS_DIFS, TXOP_BK);
+       wl1251_acx_ac_cfg(wl, AC_VI, CWMIN_VI, CWMAX_VI, AIFS_DIFS, TXOP_VI);
+       wl1251_acx_ac_cfg(wl, AC_VO, CWMIN_VO, CWMAX_VO, AIFS_DIFS, TXOP_VO);
+
 out:
        kfree(config);
        return ret;
index b3b25ec885ea7489d19c3f6f3cd2d08d047e7217..269cefb3e7d43f20d96e3ca1902b1388fd5049e3 100644 (file)
 
 #include "wl1251.h"
 
+enum {
+       /* best effort/legacy */
+       AC_BE = 0,
+
+       /* background */
+       AC_BK = 1,
+
+       /* video */
+       AC_VI = 2,
+
+       /* voice */
+       AC_VO = 3,
+
+       /* broadcast dummy access category */
+       AC_BCAST = 4,
+
+       NUM_ACCESS_CATEGORIES = 4
+};
+
+/* following are defult values for the IE fields*/
+#define CWMIN_BK  15
+#define CWMIN_BE  15
+#define CWMIN_VI  7
+#define CWMIN_VO  3
+#define CWMAX_BK  1023
+#define CWMAX_BE  63
+#define CWMAX_VI  15
+#define CWMAX_VO  7
+
+/* slot number setting to start transmission at PIFS interval */
+#define AIFS_PIFS 1
+
+/*
+ * slot number setting to start transmission at DIFS interval - normal DCF
+ * access
+ */
+#define AIFS_DIFS 2
+
+#define AIFSN_BK  7
+#define AIFSN_BE  3
+#define AIFSN_VI  AIFS_PIFS
+#define AIFSN_VO  AIFS_PIFS
+#define TXOP_BK   0
+#define TXOP_BE   0
+#define TXOP_VI   3008
+#define TXOP_VO   1504
+
 int wl1251_hw_init_hwenc_config(struct wl1251 *wl);
 int wl1251_hw_init_templates_config(struct wl1251 *wl);
 int wl1251_hw_init_rx_config(struct wl1251 *wl, u32 config, u32 filter);
index 2f50a256efa5a00fa18b45e94ce9be3130f7628c..595f0f94d16ea03a6bc7eb8882b5a2429a1fe334 100644 (file)
@@ -395,6 +395,7 @@ static int wl1251_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
         * the queue here, otherwise the queue will get too long.
         */
        if (skb_queue_len(&wl->tx_queue) >= WL1251_TX_QUEUE_MAX_LENGTH) {
+               wl1251_debug(DEBUG_TX, "op_tx: tx_queue full, stop queues");
                ieee80211_stop_queues(wl->hw);
 
                /*
@@ -510,13 +511,13 @@ static void wl1251_op_stop(struct ieee80211_hw *hw)
 }
 
 static int wl1251_op_add_interface(struct ieee80211_hw *hw,
-                                  struct ieee80211_if_init_conf *conf)
+                                  struct ieee80211_vif *vif)
 {
        struct wl1251 *wl = hw->priv;
        int ret = 0;
 
        wl1251_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
-                    conf->type, conf->mac_addr);
+                    vif->type, vif->addr);
 
        mutex_lock(&wl->mutex);
        if (wl->vif) {
@@ -524,9 +525,9 @@ static int wl1251_op_add_interface(struct ieee80211_hw *hw,
                goto out;
        }
 
-       wl->vif = conf->vif;
+       wl->vif = vif;
 
-       switch (conf->type) {
+       switch (vif->type) {
        case NL80211_IFTYPE_STATION:
                wl->bss_type = BSS_TYPE_STA_BSS;
                break;
@@ -538,8 +539,8 @@ static int wl1251_op_add_interface(struct ieee80211_hw *hw,
                goto out;
        }
 
-       if (memcmp(wl->mac_addr, conf->mac_addr, ETH_ALEN)) {
-               memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN);
+       if (memcmp(wl->mac_addr, vif->addr, ETH_ALEN)) {
+               memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
                SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
                ret = wl1251_acx_station_id(wl);
                if (ret < 0)
@@ -552,7 +553,7 @@ out:
 }
 
 static void wl1251_op_remove_interface(struct ieee80211_hw *hw,
-                                        struct ieee80211_if_init_conf *conf)
+                                        struct ieee80211_vif *vif)
 {
        struct wl1251 *wl = hw->priv;
 
@@ -562,43 +563,25 @@ static void wl1251_op_remove_interface(struct ieee80211_hw *hw,
        mutex_unlock(&wl->mutex);
 }
 
-static int wl1251_build_null_data(struct wl1251 *wl)
+static int wl1251_build_qos_null_data(struct wl1251 *wl)
 {
-       struct wl12xx_null_data_template template;
+       struct ieee80211_qos_hdr template;
 
-       if (!is_zero_ether_addr(wl->bssid)) {
-               memcpy(template.header.da, wl->bssid, ETH_ALEN);
-               memcpy(template.header.bssid, wl->bssid, ETH_ALEN);
-       } else {
-               memset(template.header.da, 0xff, ETH_ALEN);
-               memset(template.header.bssid, 0xff, ETH_ALEN);
-       }
-
-       memcpy(template.header.sa, wl->mac_addr, ETH_ALEN);
-       template.header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_DATA |
-                                               IEEE80211_STYPE_NULLFUNC |
-                                               IEEE80211_FCTL_TODS);
-
-       return wl1251_cmd_template_set(wl, CMD_NULL_DATA, &template,
-                                      sizeof(template));
-
-}
-
-static int wl1251_build_ps_poll(struct wl1251 *wl, u16 aid)
-{
-       struct wl12xx_ps_poll_template template;
+       memset(&template, 0, sizeof(template));
 
-       memcpy(template.bssid, wl->bssid, ETH_ALEN);
-       memcpy(template.ta, wl->mac_addr, ETH_ALEN);
+       memcpy(template.addr1, wl->bssid, ETH_ALEN);
+       memcpy(template.addr2, wl->mac_addr, ETH_ALEN);
+       memcpy(template.addr3, wl->bssid, ETH_ALEN);
 
-       /* aid in PS-Poll has its two MSBs each set to 1 */
-       template.aid = cpu_to_le16(1 << 15 | 1 << 14 | aid);
+       template.frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
+                                            IEEE80211_STYPE_QOS_NULLFUNC |
+                                            IEEE80211_FCTL_TODS);
 
-       template.fc = cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL);
+       /* FIXME: not sure what priority to use here */
+       template.qos_ctrl = cpu_to_le16(0);
 
-       return wl1251_cmd_template_set(wl, CMD_PS_POLL, &template,
+       return wl1251_cmd_template_set(wl, CMD_QOS_NULL_DATA, &template,
                                       sizeof(template));
-
 }
 
 static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed)
@@ -640,20 +623,25 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed)
                 * through the bss_info_changed() hook.
                 */
                ret = wl1251_ps_set_mode(wl, STATION_POWER_SAVE_MODE);
+               if (ret < 0)
+                       goto out_sleep;
        } else if (!(conf->flags & IEEE80211_CONF_PS) &&
                   wl->psm_requested) {
                wl1251_debug(DEBUG_PSM, "psm disabled");
 
                wl->psm_requested = false;
 
-               if (wl->psm)
+               if (wl->psm) {
                        ret = wl1251_ps_set_mode(wl, STATION_ACTIVE_MODE);
+                       if (ret < 0)
+                               goto out_sleep;
+               }
        }
 
        if (conf->power_level != wl->power_level) {
                ret = wl1251_acx_tx_power(wl, conf->power_level);
                if (ret < 0)
-                       goto out;
+                       goto out_sleep;
 
                wl->power_level = conf->power_level;
        }
@@ -864,199 +852,61 @@ out:
        return ret;
 }
 
-static int wl1251_build_basic_rates(char *rates)
-{
-       u8 index = 0;
-
-       rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_1MB;
-       rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_2MB;
-       rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_5MB;
-       rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_11MB;
-
-       return index;
-}
-
-static int wl1251_build_extended_rates(char *rates)
+static int wl1251_op_hw_scan(struct ieee80211_hw *hw,
+                            struct cfg80211_scan_request *req)
 {
-       u8 index = 0;
-
-       rates[index++] = IEEE80211_OFDM_RATE_6MB;
-       rates[index++] = IEEE80211_OFDM_RATE_9MB;
-       rates[index++] = IEEE80211_OFDM_RATE_12MB;
-       rates[index++] = IEEE80211_OFDM_RATE_18MB;
-       rates[index++] = IEEE80211_OFDM_RATE_24MB;
-       rates[index++] = IEEE80211_OFDM_RATE_36MB;
-       rates[index++] = IEEE80211_OFDM_RATE_48MB;
-       rates[index++] = IEEE80211_OFDM_RATE_54MB;
-
-       return index;
-}
-
+       struct wl1251 *wl = hw->priv;
+       struct sk_buff *skb;
+       size_t ssid_len = 0;
+       u8 *ssid = NULL;
+       int ret;
 
-static int wl1251_build_probe_req(struct wl1251 *wl, u8 *ssid, size_t ssid_len)
-{
-       struct wl12xx_probe_req_template template;
-       struct wl12xx_ie_rates *rates;
-       char *ptr;
-       u16 size;
-
-       ptr = (char *)&template;
-       size = sizeof(struct ieee80211_header);
-
-       memset(template.header.da, 0xff, ETH_ALEN);
-       memset(template.header.bssid, 0xff, ETH_ALEN);
-       memcpy(template.header.sa, wl->mac_addr, ETH_ALEN);
-       template.header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ);
-
-       /* IEs */
-       /* SSID */
-       template.ssid.header.id = WLAN_EID_SSID;
-       template.ssid.header.len = ssid_len;
-       if (ssid_len && ssid)
-               memcpy(template.ssid.ssid, ssid, ssid_len);
-       size += sizeof(struct wl12xx_ie_header) + ssid_len;
-       ptr += size;
-
-       /* Basic Rates */
-       rates = (struct wl12xx_ie_rates *)ptr;
-       rates->header.id = WLAN_EID_SUPP_RATES;
-       rates->header.len = wl1251_build_basic_rates(rates->rates);
-       size += sizeof(struct wl12xx_ie_header) + rates->header.len;
-       ptr += sizeof(struct wl12xx_ie_header) + rates->header.len;
-
-       /* Extended rates */
-       rates = (struct wl12xx_ie_rates *)ptr;
-       rates->header.id = WLAN_EID_EXT_SUPP_RATES;
-       rates->header.len = wl1251_build_extended_rates(rates->rates);
-       size += sizeof(struct wl12xx_ie_header) + rates->header.len;
-
-       wl1251_dump(DEBUG_SCAN, "PROBE REQ: ", &template, size);
-
-       return wl1251_cmd_template_set(wl, CMD_PROBE_REQ, &template,
-                                     size);
-}
+       wl1251_debug(DEBUG_MAC80211, "mac80211 hw scan");
 
-static int wl1251_hw_scan(struct wl1251 *wl, u8 *ssid, size_t len,
-                         u8 active_scan, u8 high_prio, u8 num_channels,
-                         u8 probe_requests)
-{
-       struct wl1251_cmd_trigger_scan_to *trigger = NULL;
-       struct cmd_scan *params = NULL;
-       int i, ret;
-       u16 scan_options = 0;
-
-       if (wl->scanning)
-               return -EINVAL;
-
-       params = kzalloc(sizeof(*params), GFP_KERNEL);
-       if (!params)
-               return -ENOMEM;
-
-       params->params.rx_config_options = cpu_to_le32(CFG_RX_ALL_GOOD);
-       params->params.rx_filter_options =
-               cpu_to_le32(CFG_RX_PRSP_EN | CFG_RX_MGMT_EN | CFG_RX_BCN_EN);
-
-       /* High priority scan */
-       if (!active_scan)
-               scan_options |= SCAN_PASSIVE;
-       if (high_prio)
-               scan_options |= SCAN_PRIORITY_HIGH;
-       params->params.scan_options = scan_options;
-
-       params->params.num_channels = num_channels;
-       params->params.num_probe_requests = probe_requests;
-       params->params.tx_rate = cpu_to_le16(1 << 1); /* 2 Mbps */
-       params->params.tid_trigger = 0;
-
-       for (i = 0; i < num_channels; i++) {
-               params->channels[i].min_duration = cpu_to_le32(30000);
-               params->channels[i].max_duration = cpu_to_le32(60000);
-               memset(&params->channels[i].bssid_lsb, 0xff, 4);
-               memset(&params->channels[i].bssid_msb, 0xff, 2);
-               params->channels[i].early_termination = 0;
-               params->channels[i].tx_power_att = 0;
-               params->channels[i].channel = i + 1;
-               memset(params->channels[i].pad, 0, 3);
+       if (req->n_ssids) {
+               ssid = req->ssids[0].ssid;
+               ssid_len = req->ssids[0].ssid_len;
        }
 
-       for (i = num_channels; i < SCAN_MAX_NUM_OF_CHANNELS; i++)
-               memset(&params->channels[i], 0,
-                      sizeof(struct basic_scan_channel_parameters));
-
-       if (len && ssid) {
-               params->params.ssid_len = len;
-               memcpy(params->params.ssid, ssid, len);
-       } else {
-               params->params.ssid_len = 0;
-               memset(params->params.ssid, 0, 32);
-       }
+       mutex_lock(&wl->mutex);
 
-       ret = wl1251_build_probe_req(wl, ssid, len);
-       if (ret < 0) {
-               wl1251_error("PROBE request template failed");
+       if (wl->scanning) {
+               wl1251_debug(DEBUG_SCAN, "scan already in progress");
+               ret = -EINVAL;
                goto out;
        }
 
-       trigger = kzalloc(sizeof(*trigger), GFP_KERNEL);
-       if (!trigger)
+       ret = wl1251_ps_elp_wakeup(wl);
+       if (ret < 0)
                goto out;
 
-       trigger->timeout = 0;
-
-       ret = wl1251_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger,
-                             sizeof(*trigger));
-       if (ret < 0) {
-               wl1251_error("trigger scan to failed for hw scan");
+       skb = ieee80211_probereq_get(wl->hw, wl->vif, ssid, ssid_len,
+                                    req->ie, req->ie_len);
+       if (!skb) {
+               ret = -ENOMEM;
                goto out;
        }
 
-       wl1251_dump(DEBUG_SCAN, "SCAN: ", params, sizeof(*params));
-
-       wl->scanning = true;
+       ret = wl1251_cmd_template_set(wl, CMD_PROBE_REQ, skb->data,
+                                     skb->len);
+       dev_kfree_skb(skb);
+       if (ret < 0)
+               goto out_sleep;
 
-       ret = wl1251_cmd_send(wl, CMD_SCAN, params, sizeof(*params));
+       ret = wl1251_cmd_trigger_scan_to(wl, 0);
        if (ret < 0)
-               wl1251_error("SCAN failed");
+               goto out_sleep;
 
-       wl1251_mem_read(wl, wl->cmd_box_addr, params, sizeof(*params));
+       wl->scanning = true;
 
-       if (params->header.status != CMD_STATUS_SUCCESS) {
-               wl1251_error("TEST command answer error: %d",
-                            params->header.status);
+       ret = wl1251_cmd_scan(wl, ssid, ssid_len, req->channels,
+                             req->n_channels, WL1251_SCAN_NUM_PROBES);
+       if (ret < 0) {
                wl->scanning = false;
-               ret = -EIO;
-               goto out;
-       }
-
-out:
-       kfree(params);
-       return ret;
-
-}
-
-static int wl1251_op_hw_scan(struct ieee80211_hw *hw,
-                            struct cfg80211_scan_request *req)
-{
-       struct wl1251 *wl = hw->priv;
-       int ret;
-       u8 *ssid = NULL;
-       size_t ssid_len = 0;
-
-       wl1251_debug(DEBUG_MAC80211, "mac80211 hw scan");
-
-       if (req->n_ssids) {
-               ssid = req->ssids[0].ssid;
-               ssid_len = req->ssids[0].ssid_len;
+               goto out_sleep;
        }
 
-       mutex_lock(&wl->mutex);
-
-       ret = wl1251_ps_elp_wakeup(wl);
-       if (ret < 0)
-               goto out;
-
-       ret = wl1251_hw_scan(hw->priv, ssid, ssid_len, 1, 0, 13, 3);
-
+out_sleep:
        wl1251_ps_elp_sleep(wl);
 
 out:
@@ -1095,7 +945,7 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw,
 {
        enum wl1251_cmd_ps_mode mode;
        struct wl1251 *wl = hw->priv;
-       struct sk_buff *beacon;
+       struct sk_buff *beacon, *skb;
        int ret;
 
        wl1251_debug(DEBUG_MAC80211, "mac80211 bss info changed");
@@ -1109,7 +959,17 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw,
        if (changed & BSS_CHANGED_BSSID) {
                memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
 
-               ret = wl1251_build_null_data(wl);
+               skb = ieee80211_nullfunc_get(wl->hw, wl->vif);
+               if (!skb)
+                       goto out_sleep;
+
+               ret = wl1251_cmd_template_set(wl, CMD_NULL_DATA,
+                                             skb->data, skb->len);
+               dev_kfree_skb(skb);
+               if (ret < 0)
+                       goto out_sleep;
+
+               ret = wl1251_build_qos_null_data(wl);
                if (ret < 0)
                        goto out;
 
@@ -1130,7 +990,14 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw,
                                                          wl->dtim_period);
                        wl->aid = bss_conf->aid;
 
-                       ret = wl1251_build_ps_poll(wl, wl->aid);
+                       skb = ieee80211_pspoll_get(wl->hw, wl->vif);
+                       if (!skb)
+                               goto out_sleep;
+
+                       ret = wl1251_cmd_template_set(wl, CMD_PS_POLL,
+                                                     skb->data,
+                                                     skb->len);
+                       dev_kfree_skb(skb);
                        if (ret < 0)
                                goto out_sleep;
 
@@ -1176,7 +1043,7 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw,
                        ret = wl1251_acx_cts_protect(wl, CTSPROTECT_DISABLE);
                if (ret < 0) {
                        wl1251_warning("Set ctsprotect failed %d", ret);
-                       goto out;
+                       goto out_sleep;
                }
        }
 
@@ -1187,7 +1054,7 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw,
 
                if (ret < 0) {
                        dev_kfree_skb(beacon);
-                       goto out;
+                       goto out_sleep;
                }
 
                ret = wl1251_cmd_template_set(wl, CMD_PROBE_RESP, beacon->data,
@@ -1196,13 +1063,13 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw,
                dev_kfree_skb(beacon);
 
                if (ret < 0)
-                       goto out;
+                       goto out_sleep;
 
                ret = wl1251_join(wl, wl->bss_type, wl->beacon_int,
                                  wl->channel, wl->dtim_period);
 
                if (ret < 0)
-                       goto out;
+                       goto out_sleep;
        }
 
 out_sleep:
@@ -1273,6 +1140,48 @@ static struct ieee80211_channel wl1251_channels[] = {
        { .hw_value = 13, .center_freq = 2472},
 };
 
+static int wl1251_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
+                            const struct ieee80211_tx_queue_params *params)
+{
+       enum wl1251_acx_ps_scheme ps_scheme;
+       struct wl1251 *wl = hw->priv;
+       int ret;
+
+       mutex_lock(&wl->mutex);
+
+       wl1251_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
+
+       ret = wl1251_ps_elp_wakeup(wl);
+       if (ret < 0)
+               goto out;
+
+       ret = wl1251_acx_ac_cfg(wl, wl1251_tx_get_queue(queue),
+                               params->cw_min, params->cw_max,
+                               params->aifs, params->txop);
+       if (ret < 0)
+               goto out_sleep;
+
+       if (params->uapsd)
+               ps_scheme = WL1251_ACX_PS_SCHEME_UPSD_TRIGGER;
+       else
+               ps_scheme = WL1251_ACX_PS_SCHEME_LEGACY;
+
+       ret = wl1251_acx_tid_cfg(wl, wl1251_tx_get_queue(queue),
+                                CHANNEL_TYPE_EDCF,
+                                wl1251_tx_get_queue(queue), ps_scheme,
+                                WL1251_ACX_ACK_POLICY_LEGACY);
+       if (ret < 0)
+               goto out_sleep;
+
+out_sleep:
+       wl1251_ps_elp_sleep(wl);
+
+out:
+       mutex_unlock(&wl->mutex);
+
+       return ret;
+}
+
 /* can't be const, mac80211 writes to this */
 static struct ieee80211_supported_band wl1251_band_2ghz = {
        .channels = wl1251_channels,
@@ -1293,6 +1202,7 @@ static const struct ieee80211_ops wl1251_ops = {
        .hw_scan = wl1251_op_hw_scan,
        .bss_info_changed = wl1251_op_bss_info_changed,
        .set_rts_threshold = wl1251_op_set_rts_threshold,
+       .conf_tx = wl1251_op_conf_tx,
 };
 
 static int wl1251_register_hw(struct wl1251 *wl)
@@ -1332,12 +1242,15 @@ int wl1251_init_ieee80211(struct wl1251 *wl)
        wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
                IEEE80211_HW_NOISE_DBM |
                IEEE80211_HW_SUPPORTS_PS |
-               IEEE80211_HW_BEACON_FILTER;
+               IEEE80211_HW_BEACON_FILTER |
+               IEEE80211_HW_SUPPORTS_UAPSD;
 
        wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
        wl->hw->wiphy->max_scan_ssids = 1;
        wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1251_band_2ghz;
 
+       wl->hw->queues = 4;
+
        ret = wl1251_register_hw(wl);
        if (ret)
                goto out;
index 9931b197ff77c42c3d6aad6ce6964ff4d16a42b1..851dfb65e474eb80a916a802a42b5e0d38b42a20 100644 (file)
@@ -26,7 +26,8 @@
 #include "wl1251_cmd.h"
 #include "wl1251_io.h"
 
-#define WL1251_WAKEUP_TIMEOUT 2000
+/* in ms */
+#define WL1251_WAKEUP_TIMEOUT 100
 
 void wl1251_elp_work(struct work_struct *work)
 {
@@ -67,7 +68,7 @@ void wl1251_ps_elp_sleep(struct wl1251 *wl)
 
 int wl1251_ps_elp_wakeup(struct wl1251 *wl)
 {
-       unsigned long timeout;
+       unsigned long timeout, start;
        u32 elp_reg;
 
        if (!wl->elp)
@@ -75,6 +76,7 @@ int wl1251_ps_elp_wakeup(struct wl1251 *wl)
 
        wl1251_debug(DEBUG_PSM, "waking up chip from elp");
 
+       start = jiffies;
        timeout = jiffies + msecs_to_jiffies(WL1251_WAKEUP_TIMEOUT);
 
        wl1251_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_WAKE_UP);
@@ -95,8 +97,7 @@ int wl1251_ps_elp_wakeup(struct wl1251 *wl)
        }
 
        wl1251_debug(DEBUG_PSM, "wakeup time: %u ms",
-                    jiffies_to_msecs(jiffies) -
-                    (jiffies_to_msecs(timeout) - WL1251_WAKEUP_TIMEOUT));
+                    jiffies_to_msecs(jiffies - start));
 
        wl->elp = false;
 
index f84cc89cbffce2a54c93e37ef709e5aea29e8dab..b56732226cc09943638b976b0e4c95114ad7b15a 100644 (file)
@@ -126,7 +126,7 @@ static void wl1251_rx_body(struct wl1251 *wl,
        if (wl->rx_current_buffer)
                rx_packet_ring_addr += wl->data_path->rx_packet_ring_chunk_size;
 
-       skb = dev_alloc_skb(length);
+       skb = __dev_alloc_skb(length, GFP_KERNEL);
        if (!skb) {
                wl1251_error("Couldn't allocate RX frame");
                return;
index f859706158499703d9492851f33ba97f25f90552..c8223185efd28129325dc46d52760dba7d5d6732 100644 (file)
@@ -167,8 +167,7 @@ static int wl1251_tx_fill_hdr(struct wl1251 *wl, struct sk_buff *skb,
        tx_hdr->expiry_time = cpu_to_le32(1 << 16);
        tx_hdr->id = id;
 
-       /* FIXME: how to get the correct queue id? */
-       tx_hdr->xmit_queue = 0;
+       tx_hdr->xmit_queue = wl1251_tx_get_queue(skb_get_queue_mapping(skb));
 
        wl1251_tx_control(tx_hdr, control, fc);
        wl1251_tx_frag_block_num(tx_hdr);
@@ -220,6 +219,7 @@ static int wl1251_tx_send_packet(struct wl1251 *wl, struct sk_buff *skb,
                        /* align the buffer on a 4-byte boundary */
                        skb_reserve(skb, offset);
                        memmove(skb->data, src, skb->len);
+                       tx_hdr = (struct tx_double_buffer_desc *) skb->data;
                } else {
                        wl1251_info("No handler, fixme!");
                        return -EINVAL;
@@ -237,8 +237,9 @@ static int wl1251_tx_send_packet(struct wl1251 *wl, struct sk_buff *skb,
 
        wl1251_mem_write(wl, addr, skb->data, len);
 
-       wl1251_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u rate 0x%x",
-                    tx_hdr->id, skb, tx_hdr->length, tx_hdr->rate);
+       wl1251_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u rate 0x%x "
+                    "queue %d", tx_hdr->id, skb, tx_hdr->length,
+                    tx_hdr->rate, tx_hdr->xmit_queue);
 
        return 0;
 }
index 7c1c1665c81086f1a44966a55da55d4ddb8897f2..55856c6bb97a85b18f8a65810288f88a61f08ccf 100644 (file)
@@ -26,6 +26,7 @@
 #define __WL1251_TX_H__
 
 #include <linux/bitops.h>
+#include "wl1251_acx.h"
 
 /*
  *
@@ -209,6 +210,22 @@ struct tx_result {
        u8 done_2;
 } __attribute__ ((packed));
 
+static inline int wl1251_tx_get_queue(int queue)
+{
+       switch (queue) {
+       case 0:
+               return QOS_AC_VO;
+       case 1:
+               return QOS_AC_VI;
+       case 2:
+               return QOS_AC_BE;
+       case 3:
+               return QOS_AC_BK;
+       default:
+               return QOS_AC_BE;
+       }
+}
+
 void wl1251_tx_work(struct work_struct *work);
 void wl1251_tx_complete(struct wl1251 *wl);
 void wl1251_tx_flush(struct wl1251 *wl);
index 94359b1a861f2aa39e184590ac87045bcca54bf0..d0938db043b366320bce03cd3b09d47c0ec763e8 100644 (file)
@@ -107,10 +107,9 @@ enum {
                                  CFG_RX_CTL_EN | CFG_RX_BCN_EN |     \
                                  CFG_RX_AUTH_EN | CFG_RX_ASSOC_EN)
 
-#define WL1271_DEFAULT_BASIC_RATE_SET (CONF_TX_RATE_MASK_ALL)
-
 #define WL1271_FW_NAME "wl1271-fw.bin"
 #define WL1271_NVS_NAME "wl1271-nvs.bin"
+#define WL1271_NVS_LEN  468
 
 /*
  * Enable/disable 802.11a support for WL1273
@@ -276,6 +275,7 @@ struct wl1271_debugfs {
 
        struct dentry *retry_count;
        struct dentry *excessive_retries;
+       struct dentry *gpio_power;
 };
 
 #define NUM_TX_QUEUES              4
@@ -322,6 +322,17 @@ struct wl1271 {
        enum wl1271_state state;
        struct mutex mutex;
 
+#define WL1271_FLAG_STA_RATES_CHANGED  (0)
+#define WL1271_FLAG_STA_ASSOCIATED     (1)
+#define WL1271_FLAG_JOINED             (2)
+#define WL1271_FLAG_GPIO_POWER         (3)
+#define WL1271_FLAG_TX_QUEUE_STOPPED   (4)
+#define WL1271_FLAG_SCANNING           (5)
+#define WL1271_FLAG_IN_ELP             (6)
+#define WL1271_FLAG_PSM                (7)
+#define WL1271_FLAG_PSM_REQUESTED      (8)
+       unsigned long flags;
+
        struct wl1271_partition_set part;
 
        struct wl1271_chip chip;
@@ -359,7 +370,6 @@ struct wl1271 {
 
        /* Frames scheduled for transmission, not handled yet */
        struct sk_buff_head tx_queue;
-       bool tx_queue_stopped;
 
        struct work_struct tx_work;
 
@@ -387,14 +397,15 @@ struct wl1271 {
        u32 mbox_ptr[2];
 
        /* Are we currently scanning */
-       bool scanning;
        struct wl1271_scan scan;
 
        /* Our association ID */
        u16 aid;
 
        /* currently configured rate set */
+       u32 sta_rate_set;
        u32 basic_rate_set;
+       u32 rate_set;
 
        /* The current band */
        enum ieee80211_band band;
@@ -405,18 +416,9 @@ struct wl1271 {
        unsigned int rx_config;
        unsigned int rx_filter;
 
-       /* is firmware in elp mode */
-       bool elp;
-
        struct completion *elp_compl;
        struct delayed_work elp_work;
 
-       /* we can be in psm, but not in elp, we have to differentiate */
-       bool psm;
-
-       /* PSM mode requested */
-       bool psm_requested;
-
        /* retry counter for PSM entries */
        u8 psm_entry_retry;
 
@@ -435,9 +437,6 @@ struct wl1271 {
 
        struct ieee80211_vif *vif;
 
-       /* Used for a workaround to send disconnect before rejoining */
-       bool joined;
-
        /* Current chipset configuration */
        struct conf_drv_settings conf;
 
@@ -455,7 +454,9 @@ int wl1271_plt_stop(struct wl1271 *wl);
 
 #define WL1271_TX_QUEUE_MAX_LENGTH 20
 
-/* WL1271 needs a 200ms sleep after power on */
+/* WL1271 needs a 200ms sleep after power on, and a 20ms sleep before power
+   on in case is has been shut down shortly before */
+#define WL1271_PRE_POWER_ON_SLEEP 20 /* in miliseconds */
 #define WL1271_POWER_ON_SLEEP 200 /* in miliseconds */
 
 static inline bool wl1271_11a_enabled(void)
index 5cc89bbdac7abe11130df407361e65f20b93c3f3..0b34348434766db6eaa86c6555ae2a8704b376f1 100644 (file)
@@ -390,6 +390,35 @@ out:
        return ret;
 }
 
+int wl1271_acx_dco_itrim_params(struct wl1271 *wl)
+{
+       struct acx_dco_itrim_params *dco;
+       struct conf_itrim_settings *c = &wl->conf.itrim;
+       int ret;
+
+       wl1271_debug(DEBUG_ACX, "acx dco itrim parameters");
+
+       dco = kzalloc(sizeof(*dco), GFP_KERNEL);
+       if (!dco) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       dco->enable = c->enable;
+       dco->timeout = cpu_to_le32(c->timeout);
+
+       ret = wl1271_cmd_configure(wl, ACX_SET_DCO_ITRIM_PARAMS,
+                                  dco, sizeof(*dco));
+       if (ret < 0) {
+               wl1271_warning("failed to set dco itrim parameters: %d", ret);
+               goto out;
+       }
+
+out:
+       kfree(dco);
+       return ret;
+}
+
 int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, bool enable_filter)
 {
        struct acx_beacon_filter_option *beacon_filter = NULL;
@@ -758,10 +787,11 @@ int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats)
        return 0;
 }
 
-int wl1271_acx_rate_policies(struct wl1271 *wl, u32 enabled_rates)
+int wl1271_acx_rate_policies(struct wl1271 *wl)
 {
        struct acx_rate_policy *acx;
        struct conf_tx_rate_class *c = &wl->conf.tx.rc_conf;
+       int idx = 0;
        int ret = 0;
 
        wl1271_debug(DEBUG_ACX, "acx rate policies");
@@ -773,12 +803,21 @@ int wl1271_acx_rate_policies(struct wl1271 *wl, u32 enabled_rates)
                goto out;
        }
 
-       /* configure one default (one-size-fits-all) rate class */
-       acx->rate_class_cnt = cpu_to_le32(1);
-       acx->rate_class[0].enabled_rates = cpu_to_le32(enabled_rates);
-       acx->rate_class[0].short_retry_limit = c->short_retry_limit;
-       acx->rate_class[0].long_retry_limit = c->long_retry_limit;
-       acx->rate_class[0].aflags = c->aflags;
+       /* configure one basic rate class */
+       idx = ACX_TX_BASIC_RATE;
+       acx->rate_class[idx].enabled_rates = cpu_to_le32(wl->basic_rate_set);
+       acx->rate_class[idx].short_retry_limit = c->short_retry_limit;
+       acx->rate_class[idx].long_retry_limit = c->long_retry_limit;
+       acx->rate_class[idx].aflags = c->aflags;
+
+       /* configure one AP supported rate class */
+       idx = ACX_TX_AP_FULL_RATE;
+       acx->rate_class[idx].enabled_rates = cpu_to_le32(wl->rate_set);
+       acx->rate_class[idx].short_retry_limit = c->short_retry_limit;
+       acx->rate_class[idx].long_retry_limit = c->long_retry_limit;
+       acx->rate_class[idx].aflags = c->aflags;
+
+       acx->rate_class_cnt = cpu_to_le32(ACX_TX_RATE_POLICY_CNT);
 
        ret = wl1271_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx));
        if (ret < 0) {
@@ -1012,59 +1051,6 @@ out:
        return ret;
 }
 
-int wl1271_acx_smart_reflex(struct wl1271 *wl)
-{
-       struct acx_smart_reflex_state *sr_state = NULL;
-       struct acx_smart_reflex_config_params *sr_param = NULL;
-       int i, ret;
-
-       wl1271_debug(DEBUG_ACX, "acx smart reflex");
-
-       sr_param = kzalloc(sizeof(*sr_param), GFP_KERNEL);
-       if (!sr_param) {
-               ret = -ENOMEM;
-               goto out;
-       }
-
-       for (i = 0; i < CONF_SR_ERR_TBL_COUNT; i++) {
-               struct conf_mart_reflex_err_table *e =
-                       &(wl->conf.init.sr_err_tbl[i]);
-
-               sr_param->error_table[i].len = e->len;
-               sr_param->error_table[i].upper_limit = e->upper_limit;
-               memcpy(sr_param->error_table[i].values, e->values, e->len);
-       }
-
-       ret = wl1271_cmd_configure(wl, ACX_SET_SMART_REFLEX_PARAMS,
-                                  sr_param, sizeof(*sr_param));
-       if (ret < 0) {
-               wl1271_warning("failed to set smart reflex params: %d", ret);
-               goto out;
-       }
-
-       sr_state = kzalloc(sizeof(*sr_state), GFP_KERNEL);
-       if (!sr_state) {
-               ret = -ENOMEM;
-               goto out;
-       }
-
-       /* enable smart reflex */
-       sr_state->enable = wl->conf.init.sr_enable;
-
-       ret = wl1271_cmd_configure(wl, ACX_SET_SMART_REFLEX_STATE,
-                                  sr_state, sizeof(*sr_state));
-       if (ret < 0) {
-               wl1271_warning("failed to set smart reflex params: %d", ret);
-               goto out;
-       }
-
-out:
-       kfree(sr_state);
-       kfree(sr_param);
-       return ret;
-
-}
-
 int wl1271_acx_bet_enable(struct wl1271 *wl, bool enable)
 {
        struct wl1271_acx_bet_enable *acx = NULL;
@@ -1132,3 +1118,31 @@ out:
        kfree(acx);
        return ret;
 }
+
+int wl1271_acx_pm_config(struct wl1271 *wl)
+{
+       struct wl1271_acx_pm_config *acx = NULL;
+       struct  conf_pm_config_settings *c = &wl->conf.pm_config;
+       int ret = 0;
+
+       wl1271_debug(DEBUG_ACX, "acx pm config");
+
+       acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+       if (!acx) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       acx->host_clk_settling_time = cpu_to_le32(c->host_clk_settling_time);
+       acx->host_fast_wakeup_support = c->host_fast_wakeup_support;
+
+       ret = wl1271_cmd_configure(wl, ACX_PM_CONFIG, acx, sizeof(*acx));
+       if (ret < 0) {
+               wl1271_warning("acx pm config failed: %d", ret);
+               goto out;
+       }
+
+out:
+       kfree(acx);
+       return ret;
+}
index 2ce0a81285425cd0c451753e0501851c6b51d932..1bb63af64f0e5616bfe02013055249336f10b14b 100644 (file)
@@ -415,23 +415,12 @@ struct acx_bt_wlan_coex {
        u8 pad[3];
 } __attribute__ ((packed));
 
-struct acx_smart_reflex_state {
+struct acx_dco_itrim_params {
        struct acx_header header;
 
        u8 enable;
        u8 padding[3];
-} __attribute__ ((packed));
-
-struct smart_reflex_err_table {
-       u8 len;
-       s8 upper_limit;
-       s8 values[14];
-} __attribute__ ((packed));
-
-struct acx_smart_reflex_config_params {
-       struct acx_header header;
-
-       struct smart_reflex_err_table error_table[3];
+       __le32 timeout;
 } __attribute__ ((packed));
 
 #define PTA_ANTENNA_TYPE_DEF             (0)
@@ -837,6 +826,9 @@ struct acx_rate_class {
        u8 reserved;
 };
 
+#define ACX_TX_BASIC_RATE      0
+#define ACX_TX_AP_FULL_RATE    1
+#define ACX_TX_RATE_POLICY_CNT 2
 struct acx_rate_policy {
        struct acx_header header;
 
@@ -877,8 +869,8 @@ struct acx_tx_config_options {
        __le16 tx_compl_threshold;   /* number of packets */
 } __attribute__ ((packed));
 
-#define ACX_RX_MEM_BLOCKS     64
-#define ACX_TX_MIN_MEM_BLOCKS 64
+#define ACX_RX_MEM_BLOCKS     70
+#define ACX_TX_MIN_MEM_BLOCKS 40
 #define ACX_TX_DESCRIPTORS    32
 #define ACX_NUM_SSID_PROFILES 1
 
@@ -969,6 +961,13 @@ struct wl1271_acx_arp_filter {
                               used. */
 } __attribute__((packed));
 
+struct wl1271_acx_pm_config {
+       struct acx_header header;
+
+       __le32 host_clk_settling_time;
+       u8 host_fast_wakeup_support;
+       u8 padding[3];
+} __attribute__ ((packed));
 
 enum {
        ACX_WAKE_UP_CONDITIONS      = 0x0002,
@@ -1027,13 +1026,13 @@ enum {
        ACX_HT_BSS_OPERATION        = 0x0058,
        ACX_COEX_ACTIVITY           = 0x0059,
        ACX_SET_SMART_REFLEX_DEBUG  = 0x005A,
-       ACX_SET_SMART_REFLEX_STATE  = 0x005B,
-       ACX_SET_SMART_REFLEX_PARAMS = 0x005F,
+       ACX_SET_DCO_ITRIM_PARAMS    = 0x0061,
        DOT11_RX_MSDU_LIFE_TIME     = 0x1004,
        DOT11_CUR_TX_PWR            = 0x100D,
        DOT11_RX_DOT11_MODE         = 0x1012,
        DOT11_RTS_THRESHOLD         = 0x1013,
        DOT11_GROUP_ADDRESS_TBL     = 0x1014,
+       ACX_PM_CONFIG               = 0x1016,
 
        MAX_DOT11_IE = DOT11_GROUP_ADDRESS_TBL,
 
@@ -1056,6 +1055,7 @@ int wl1271_acx_group_address_tbl(struct wl1271 *wl, bool enable,
                                 void *mc_list, u32 mc_list_len);
 int wl1271_acx_service_period_timeout(struct wl1271 *wl);
 int wl1271_acx_rts_threshold(struct wl1271 *wl, u16 rts_threshold);
+int wl1271_acx_dco_itrim_params(struct wl1271 *wl);
 int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, bool enable_filter);
 int wl1271_acx_beacon_filter_table(struct wl1271 *wl);
 int wl1271_acx_conn_monit_params(struct wl1271 *wl);
@@ -1069,7 +1069,7 @@ int wl1271_acx_set_preamble(struct wl1271 *wl, enum acx_preamble_type preamble);
 int wl1271_acx_cts_protect(struct wl1271 *wl,
                           enum acx_ctsprotect_type ctsprotect);
 int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats);
-int wl1271_acx_rate_policies(struct wl1271 *wl, u32 enabled_rates);
+int wl1271_acx_rate_policies(struct wl1271 *wl);
 int wl1271_acx_ac_cfg(struct wl1271 *wl);
 int wl1271_acx_tid_cfg(struct wl1271 *wl);
 int wl1271_acx_frag_threshold(struct wl1271 *wl);
@@ -1081,5 +1081,6 @@ int wl1271_acx_smart_reflex(struct wl1271 *wl);
 int wl1271_acx_bet_enable(struct wl1271 *wl, bool enable);
 int wl1271_acx_arp_ip_filter(struct wl1271 *wl, bool enable, u8 *address,
                             u8 version);
+int wl1271_acx_pm_config(struct wl1271 *wl);
 
 #endif /* __WL1271_ACX_H__ */
index b7c96454cca3444147054d64797993662701600f..e803b876f3f03cb7efa71807024b3d2d44938f52 100644 (file)
@@ -225,9 +225,15 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
        if (nvs == NULL)
                return -ENODEV;
 
+       if (wl->nvs_len < WL1271_NVS_LEN)
+               return -EINVAL;
+
        nvs_ptr = nvs;
 
-       nvs_len = wl->nvs_len;
+       /* only the first part of the NVS needs to be uploaded */
+       nvs_len = WL1271_NVS_LEN;
+
+       /* FIXME: read init settings from the remaining part of the NVS */
 
        /* Update the device MAC address into the nvs */
        nvs[11] = wl->mac_addr[0];
index c3385b3d246cf988d3efb5d882a5d1c0e877ffd5..a74259bb596bb99cd10ee3bc84630907dbf70b0f 100644 (file)
@@ -209,6 +209,26 @@ int wl1271_cmd_general_parms(struct wl1271 *wl)
        gen_parms->tx_bip_fem_manufacturer = g->tx_bip_fem_manufacturer;
        gen_parms->settings = g->settings;
 
+       gen_parms->sr_state = g->sr_state;
+
+       memcpy(gen_parms->srf1,
+              g->srf1,
+              CONF_MAX_SMART_REFLEX_PARAMS);
+       memcpy(gen_parms->srf2,
+              g->srf2,
+              CONF_MAX_SMART_REFLEX_PARAMS);
+       memcpy(gen_parms->srf3,
+              g->srf3,
+              CONF_MAX_SMART_REFLEX_PARAMS);
+       memcpy(gen_parms->sr_debug_table,
+              g->sr_debug_table,
+              CONF_MAX_SMART_REFLEX_PARAMS);
+
+       gen_parms->sr_sen_n_p = g->sr_sen_n_p;
+       gen_parms->sr_sen_n_p_gain = g->sr_sen_n_p_gain;
+       gen_parms->sr_sen_nrn = g->sr_sen_nrn;
+       gen_parms->sr_sen_prn = g->sr_sen_prn;
+
        ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), 0);
        if (ret < 0)
                wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed");
@@ -253,6 +273,8 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl)
               CONF_NUMBER_OF_RATE_GROUPS);
        memcpy(radio_parms->tx_rate_limits_degraded, r->tx_rate_limits_degraded,
               CONF_NUMBER_OF_RATE_GROUPS);
+       memcpy(radio_parms->tx_rate_limits_extreme, r->tx_rate_limits_extreme,
+              CONF_NUMBER_OF_RATE_GROUPS);
 
        memcpy(radio_parms->tx_channel_limits_11b, r->tx_channel_limits_11b,
               CONF_NUMBER_OF_CHANNELS_2_4);
@@ -263,6 +285,11 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl)
        memcpy(radio_parms->tx_ibias, r->tx_ibias, CONF_NUMBER_OF_RATE_GROUPS);
 
        radio_parms->rx_fem_insertion_loss = r->rx_fem_insertion_loss;
+       radio_parms->degraded_low_to_normal_threshold =
+               r->degraded_low_to_normal_threshold;
+       radio_parms->degraded_normal_to_high_threshold =
+               r->degraded_normal_to_high_threshold;
+
 
        for (i = 0; i < CONF_NUMBER_OF_SUB_BANDS_5; i++)
                radio_parms->tx_ref_pd_voltage_5[i] =
@@ -275,6 +302,8 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl)
               r->tx_rate_limits_normal_5, CONF_NUMBER_OF_RATE_GROUPS);
        memcpy(radio_parms->tx_rate_limits_degraded_5,
               r->tx_rate_limits_degraded_5, CONF_NUMBER_OF_RATE_GROUPS);
+       memcpy(radio_parms->tx_rate_limits_extreme_5,
+              r->tx_rate_limits_extreme_5, CONF_NUMBER_OF_RATE_GROUPS);
        memcpy(radio_parms->tx_channel_limits_ofdm_5,
               r->tx_channel_limits_ofdm_5, CONF_NUMBER_OF_CHANNELS_5);
        memcpy(radio_parms->tx_pdv_rate_offsets_5, r->tx_pdv_rate_offsets_5,
@@ -283,6 +312,10 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl)
               CONF_NUMBER_OF_RATE_GROUPS);
        memcpy(radio_parms->rx_fem_insertion_loss_5,
               r->rx_fem_insertion_loss_5, CONF_NUMBER_OF_SUB_BANDS_5);
+       radio_parms->degraded_low_to_normal_threshold_5 =
+               r->degraded_low_to_normal_threshold_5;
+       radio_parms->degraded_normal_to_high_threshold_5 =
+               r->degraded_normal_to_high_threshold_5;
 
        wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ",
                    radio_parms, sizeof(*radio_parms));
@@ -311,19 +344,6 @@ int wl1271_cmd_join(struct wl1271 *wl)
                        do_cal = false;
        }
 
-       /* FIXME: This is a workaround, because with the current stack, we
-        * cannot know when we have disassociated.  So, if we have already
-        * joined, we disconnect before joining again. */
-       if (wl->joined) {
-               ret = wl1271_cmd_disconnect(wl);
-               if (ret < 0) {
-                       wl1271_error("failed to disconnect before rejoining");
-                       goto out;
-               }
-
-               wl->joined = false;
-       }
-
        join = kzalloc(sizeof(*join), GFP_KERNEL);
        if (!join) {
                ret = -ENOMEM;
@@ -388,8 +408,6 @@ int wl1271_cmd_join(struct wl1271 *wl)
                goto out_free;
        }
 
-       wl->joined = true;
-
        /*
         * ugly hack: we should wait for JOIN_EVENT_COMPLETE_ID but to
         * simplify locking we just sleep instead, for now
@@ -487,7 +505,7 @@ int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len)
        return 0;
 }
 
-int wl1271_cmd_data_path(struct wl1271 *wl, u8 channel, bool enable)
+int wl1271_cmd_data_path(struct wl1271 *wl, bool enable)
 {
        struct cmd_enabledisable_path *cmd;
        int ret;
@@ -501,7 +519,8 @@ int wl1271_cmd_data_path(struct wl1271 *wl, u8 channel, bool enable)
                goto out;
        }
 
-       cmd->channel = channel;
+       /* the channel here is only used for calibration, so hardcoded to 1 */
+       cmd->channel = 1;
 
        if (enable) {
                cmd_rx = CMD_ENABLE_RX;
@@ -514,22 +533,22 @@ int wl1271_cmd_data_path(struct wl1271 *wl, u8 channel, bool enable)
        ret = wl1271_cmd_send(wl, cmd_rx, cmd, sizeof(*cmd), 0);
        if (ret < 0) {
                wl1271_error("rx %s cmd for channel %d failed",
-                            enable ? "start" : "stop", channel);
+                            enable ? "start" : "stop", cmd->channel);
                goto out;
        }
 
        wl1271_debug(DEBUG_BOOT, "rx %s cmd channel %d",
-                    enable ? "start" : "stop", channel);
+                    enable ? "start" : "stop", cmd->channel);
 
        ret = wl1271_cmd_send(wl, cmd_tx, cmd, sizeof(*cmd), 0);
        if (ret < 0) {
                wl1271_error("tx %s cmd for channel %d failed",
-                            enable ? "start" : "stop", channel);
+                            enable ? "start" : "stop", cmd->channel);
                return ret;
        }
 
        wl1271_debug(DEBUG_BOOT, "tx %s cmd channel %d",
-                    enable ? "start" : "stop", channel);
+                    enable ? "start" : "stop", cmd->channel);
 
 out:
        kfree(cmd);
@@ -636,7 +655,7 @@ int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len,
        channels = wl->hw->wiphy->bands[ieee_band]->channels;
        n_ch = wl->hw->wiphy->bands[ieee_band]->n_channels;
 
-       if (wl->scanning)
+       if (test_bit(WL1271_FLAG_SCANNING, &wl->flags))
                return -EINVAL;
 
        params = kzalloc(sizeof(*params), GFP_KERNEL);
@@ -711,7 +730,7 @@ int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len,
 
        wl1271_dump(DEBUG_SCAN, "SCAN: ", params, sizeof(*params));
 
-       wl->scanning = true;
+       set_bit(WL1271_FLAG_SCANNING, &wl->flags);
        if (wl1271_11a_enabled()) {
                wl->scan.state = band;
                if (band == WL1271_SCAN_BAND_DUAL) {
@@ -729,7 +748,7 @@ int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len,
        ret = wl1271_cmd_send(wl, CMD_SCAN, params, sizeof(*params), 0);
        if (ret < 0) {
                wl1271_error("SCAN failed");
-               wl->scanning = false;
+               clear_bit(WL1271_FLAG_SCANNING, &wl->flags);
                goto out;
        }
 
index b4fa4acb922957c912d7461f0a49e5faf286e08f..09fe91297acfe7bd0e2ddaf2883b0520602db1ed 100644 (file)
@@ -37,7 +37,7 @@ int wl1271_cmd_join(struct wl1271 *wl);
 int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer);
 int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len);
 int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len);
-int wl1271_cmd_data_path(struct wl1271 *wl, u8 channel, bool enable);
+int wl1271_cmd_data_path(struct wl1271 *wl, bool enable);
 int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode);
 int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer,
                           size_t len);
@@ -437,6 +437,21 @@ struct wl1271_general_parms_cmd {
        u8 tx_bip_fem_autodetect;
        u8 tx_bip_fem_manufacturer;
        u8 settings;
+
+       u8 sr_state;
+
+       s8 srf1[CONF_MAX_SMART_REFLEX_PARAMS];
+       s8 srf2[CONF_MAX_SMART_REFLEX_PARAMS];
+       s8 srf3[CONF_MAX_SMART_REFLEX_PARAMS];
+
+       s8 sr_debug_table[CONF_MAX_SMART_REFLEX_PARAMS];
+
+       u8 sr_sen_n_p;
+       u8 sr_sen_n_p_gain;
+       u8 sr_sen_nrn;
+       u8 sr_sen_prn;
+
+       u8 padding[3];
 } __attribute__ ((packed));
 
 struct wl1271_radio_parms_cmd {
@@ -458,11 +473,12 @@ struct wl1271_radio_parms_cmd {
        /* Dynamic radio parameters */
        /* 2.4GHz */
        __le16 tx_ref_pd_voltage;
-       s8  tx_ref_power;
+       u8  tx_ref_power;
        s8  tx_offset_db;
 
        s8  tx_rate_limits_normal[CONF_NUMBER_OF_RATE_GROUPS];
        s8  tx_rate_limits_degraded[CONF_NUMBER_OF_RATE_GROUPS];
+       s8  tx_rate_limits_extreme[CONF_NUMBER_OF_RATE_GROUPS];
 
        s8  tx_channel_limits_11b[CONF_NUMBER_OF_CHANNELS_2_4];
        s8  tx_channel_limits_ofdm[CONF_NUMBER_OF_CHANNELS_2_4];
@@ -471,15 +487,19 @@ struct wl1271_radio_parms_cmd {
        u8  tx_ibias[CONF_NUMBER_OF_RATE_GROUPS];
        u8  rx_fem_insertion_loss;
 
-       u8 padding2;
+       u8  degraded_low_to_normal_threshold;
+       u8  degraded_normal_to_high_threshold;
+
+       u8  padding1; /* our own padding, not in ref driver */
 
        /* 5GHz */
        __le16 tx_ref_pd_voltage_5[CONF_NUMBER_OF_SUB_BANDS_5];
-       s8  tx_ref_power_5[CONF_NUMBER_OF_SUB_BANDS_5];
+       u8  tx_ref_power_5[CONF_NUMBER_OF_SUB_BANDS_5];
        s8  tx_offset_db_5[CONF_NUMBER_OF_SUB_BANDS_5];
 
        s8  tx_rate_limits_normal_5[CONF_NUMBER_OF_RATE_GROUPS];
        s8  tx_rate_limits_degraded_5[CONF_NUMBER_OF_RATE_GROUPS];
+       s8  tx_rate_limits_extreme_5[CONF_NUMBER_OF_RATE_GROUPS];
 
        s8  tx_channel_limits_ofdm_5[CONF_NUMBER_OF_CHANNELS_5];
        s8  tx_pdv_rate_offsets_5[CONF_NUMBER_OF_RATE_GROUPS];
@@ -488,7 +508,10 @@ struct wl1271_radio_parms_cmd {
        s8  tx_ibias_5[CONF_NUMBER_OF_RATE_GROUPS];
        s8  rx_fem_insertion_loss_5[CONF_NUMBER_OF_SUB_BANDS_5];
 
-       u8 padding3[2];
+       u8  degraded_low_to_normal_threshold_5;
+       u8  degraded_normal_to_high_threshold_5;
+
+       u8 padding2[2];
 } __attribute__ ((packed));
 
 struct wl1271_cmd_cal_channel_tune {
index 565373ede2652a4b711a5f6a5a233847ba79ec85..1993d63c214ed3a0a2613c83d5f95a7ccc03fded 100644 (file)
@@ -258,7 +258,8 @@ struct conf_rx_settings {
 #define CONF_TX_MAX_RATE_CLASSES       8
 
 #define CONF_TX_RATE_MASK_UNSPECIFIED  0
-#define CONF_TX_RATE_MASK_ALL          0x1eff
+#define CONF_TX_RATE_MASK_BASIC        (CONF_HW_BIT_RATE_1MBPS | \
+                                       CONF_HW_BIT_RATE_2MBPS)
 #define CONF_TX_RATE_RETRY_LIMIT       10
 
 struct conf_tx_rate_class {
@@ -722,31 +723,6 @@ struct conf_conn_settings {
        u8 psm_entry_retries;
 };
 
-#define CONF_SR_ERR_TBL_MAX_VALUES   14
-
-struct conf_mart_reflex_err_table {
-       /*
-        * Length of the error table values table.
-        *
-        * Range: 0 - CONF_SR_ERR_TBL_MAX_VALUES
-        */
-       u8 len;
-
-       /*
-        * Smart Reflex error table upper limit.
-        *
-        * Range: s8
-        */
-       s8 upper_limit;
-
-       /*
-        * Smart Reflex error table values.
-        *
-        * Range: s8
-        */
-       s8 values[CONF_SR_ERR_TBL_MAX_VALUES];
-};
-
 enum {
        CONF_REF_CLK_19_2_E,
        CONF_REF_CLK_26_E,
@@ -759,6 +735,9 @@ enum single_dual_band_enum {
        CONF_DUAL_BAND
 };
 
+
+#define CONF_MAX_SMART_REFLEX_PARAMS 16
+
 struct conf_general_parms {
        /*
         * RF Reference Clock type / speed
@@ -815,6 +794,20 @@ struct conf_general_parms {
         * Range: Unknown
         */
        u8 settings;
+
+       /* Smart reflex settings */
+       u8 sr_state;
+
+       s8 srf1[CONF_MAX_SMART_REFLEX_PARAMS];
+       s8 srf2[CONF_MAX_SMART_REFLEX_PARAMS];
+       s8 srf3[CONF_MAX_SMART_REFLEX_PARAMS];
+
+       s8 sr_debug_table[CONF_MAX_SMART_REFLEX_PARAMS];
+
+       u8 sr_sen_n_p;
+       u8 sr_sen_n_p_gain;
+       u8 sr_sen_nrn;
+       u8 sr_sen_prn;
 };
 
 #define CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE 15
@@ -847,12 +840,13 @@ struct conf_radio_parms {
         *
         * Range: unknown
         */
-       s16 tx_ref_pd_voltage;
-       s8  tx_ref_power;
+       u16 tx_ref_pd_voltage;
+       u8  tx_ref_power;
        s8  tx_offset_db;
 
        s8  tx_rate_limits_normal[CONF_NUMBER_OF_RATE_GROUPS];
        s8  tx_rate_limits_degraded[CONF_NUMBER_OF_RATE_GROUPS];
+       s8  tx_rate_limits_extreme[CONF_NUMBER_OF_RATE_GROUPS];
 
        s8  tx_channel_limits_11b[CONF_NUMBER_OF_CHANNELS_2_4];
        s8  tx_channel_limits_ofdm[CONF_NUMBER_OF_CHANNELS_2_4];
@@ -861,17 +855,22 @@ struct conf_radio_parms {
        u8  tx_ibias[CONF_NUMBER_OF_RATE_GROUPS];
        u8  rx_fem_insertion_loss;
 
+       u8  degraded_low_to_normal_threshold;
+       u8  degraded_normal_to_high_threshold;
+
+
        /*
         * Dynamic radio parameters for 5GHz
         *
         * Range: unknown
         */
-       s16 tx_ref_pd_voltage_5[CONF_NUMBER_OF_SUB_BANDS_5];
-       s8  tx_ref_power_5[CONF_NUMBER_OF_SUB_BANDS_5];
+       u16 tx_ref_pd_voltage_5[CONF_NUMBER_OF_SUB_BANDS_5];
+       u8  tx_ref_power_5[CONF_NUMBER_OF_SUB_BANDS_5];
        s8  tx_offset_db_5[CONF_NUMBER_OF_SUB_BANDS_5];
 
        s8  tx_rate_limits_normal_5[CONF_NUMBER_OF_RATE_GROUPS];
        s8  tx_rate_limits_degraded_5[CONF_NUMBER_OF_RATE_GROUPS];
+       s8  tx_rate_limits_extreme_5[CONF_NUMBER_OF_RATE_GROUPS];
 
        s8  tx_channel_limits_ofdm_5[CONF_NUMBER_OF_CHANNELS_5];
        s8  tx_pdv_rate_offsets_5[CONF_NUMBER_OF_RATE_GROUPS];
@@ -879,33 +878,46 @@ struct conf_radio_parms {
        /* FIXME: this is inconsistent with the types for 2.4GHz */
        s8  tx_ibias_5[CONF_NUMBER_OF_RATE_GROUPS];
        s8  rx_fem_insertion_loss_5[CONF_NUMBER_OF_SUB_BANDS_5];
-};
 
-#define CONF_SR_ERR_TBL_COUNT        3
+       u8  degraded_low_to_normal_threshold_5;
+       u8  degraded_normal_to_high_threshold_5;
+};
 
 struct conf_init_settings {
        /*
-        * Configure Smart Reflex error table values.
+        * Configure general parameters.
         */
-       struct conf_mart_reflex_err_table sr_err_tbl[CONF_SR_ERR_TBL_COUNT];
+       struct conf_general_parms genparam;
 
        /*
-        * Smart Reflex enable flag.
-        *
-        * Range: 1 - Smart Reflex enabled, 0 - Smart Reflex disabled
+        * Configure radio parameters.
         */
-       u8 sr_enable;
+       struct conf_radio_parms radioparam;
 
+};
+
+struct conf_itrim_settings {
+       /* enable dco itrim */
+       u8 enable;
+
+       /* moderation timeout in microsecs from the last TX */
+       u32 timeout;
+};
+
+struct conf_pm_config_settings {
        /*
-        * Configure general parameters.
+        * Host clock settling time
+        *
+        * Range: 0 - 30000 us
         */
-       struct conf_general_parms genparam;
+       u32 host_clk_settling_time;
 
        /*
-        * Configure radio parameters.
+        * Host fast wakeup support
+        *
+        * Range: true, false
         */
-       struct conf_radio_parms radioparam;
-
+       bool host_fast_wakeup_support;
 };
 
 struct conf_drv_settings {
@@ -914,6 +926,8 @@ struct conf_drv_settings {
        struct conf_tx_settings tx;
        struct conf_conn_settings conn;
        struct conf_init_settings init;
+       struct conf_itrim_settings itrim;
+       struct conf_pm_config_settings pm_config;
 };
 
 #endif
index c1805e5f8964c1eea83918f9867ea4c702675e53..8d7588ca68fd0c14adc8c6508d1ab5456b674cf9 100644 (file)
@@ -237,6 +237,64 @@ static const struct file_operations tx_queue_len_ops = {
        .open = wl1271_open_file_generic,
 };
 
+static ssize_t gpio_power_read(struct file *file, char __user *user_buf,
+                         size_t count, loff_t *ppos)
+{
+       struct wl1271 *wl = file->private_data;
+       bool state = test_bit(WL1271_FLAG_GPIO_POWER, &wl->flags);
+
+       int res;
+       char buf[10];
+
+       res = scnprintf(buf, sizeof(buf), "%d\n", state);
+
+       return simple_read_from_buffer(user_buf, count, ppos, buf, res);
+}
+
+static ssize_t gpio_power_write(struct file *file,
+                          const char __user *user_buf,
+                          size_t count, loff_t *ppos)
+{
+       struct wl1271 *wl = file->private_data;
+       char buf[10];
+       size_t len;
+       unsigned long value;
+       int ret;
+
+       mutex_lock(&wl->mutex);
+
+       len = min(count, sizeof(buf) - 1);
+       if (copy_from_user(buf, user_buf, len)) {
+               ret = -EFAULT;
+               goto out;
+       }
+       buf[len] = '\0';
+
+       ret = strict_strtoul(buf, 0, &value);
+       if (ret < 0) {
+               wl1271_warning("illegal value in gpio_power");
+               goto out;
+       }
+
+       if (value) {
+               wl->set_power(true);
+               set_bit(WL1271_FLAG_GPIO_POWER, &wl->flags);
+       } else {
+               wl->set_power(false);
+               clear_bit(WL1271_FLAG_GPIO_POWER, &wl->flags);
+       }
+
+out:
+       mutex_unlock(&wl->mutex);
+       return count;
+}
+
+static const struct file_operations gpio_power_ops = {
+       .read = gpio_power_read,
+       .write = gpio_power_write,
+       .open = wl1271_open_file_generic
+};
+
 static void wl1271_debugfs_delete_files(struct wl1271 *wl)
 {
        DEBUGFS_FWSTATS_DEL(tx, internal_desc_overflow);
@@ -333,6 +391,8 @@ static void wl1271_debugfs_delete_files(struct wl1271 *wl)
        DEBUGFS_DEL(tx_queue_len);
        DEBUGFS_DEL(retry_count);
        DEBUGFS_DEL(excessive_retries);
+
+       DEBUGFS_DEL(gpio_power);
 }
 
 static int wl1271_debugfs_add_files(struct wl1271 *wl)
@@ -434,6 +494,8 @@ static int wl1271_debugfs_add_files(struct wl1271 *wl)
        DEBUGFS_ADD(retry_count, wl->debugfs.rootdir);
        DEBUGFS_ADD(excessive_retries, wl->debugfs.rootdir);
 
+       DEBUGFS_ADD(gpio_power, wl->debugfs.rootdir);
+
 out:
        if (ret < 0)
                wl1271_debugfs_delete_files(wl);
index d13fdd99c85c515eea99dd128f8e8b8ecd606a31..0a145afc990592a20b5a1b976fb72616a0f9bdc4 100644 (file)
@@ -35,7 +35,7 @@ static int wl1271_event_scan_complete(struct wl1271 *wl,
        wl1271_debug(DEBUG_EVENT, "status: 0x%x",
                     mbox->scheduled_scan_status);
 
-       if (wl->scanning) {
+       if (test_bit(WL1271_FLAG_SCANNING, &wl->flags)) {
                if (wl->scan.state == WL1271_SCAN_BAND_DUAL) {
                        wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4,
                                                NULL, size);
@@ -43,7 +43,7 @@ static int wl1271_event_scan_complete(struct wl1271 *wl,
                         * to the wl1271_cmd_scan function that we are not
                         * scanning as it checks that.
                         */
-                       wl->scanning = false;
+                       clear_bit(WL1271_FLAG_SCANNING, &wl->flags);
                        wl1271_cmd_scan(wl, wl->scan.ssid, wl->scan.ssid_len,
                                                wl->scan.active,
                                                wl->scan.high_prio,
@@ -62,7 +62,7 @@ static int wl1271_event_scan_complete(struct wl1271 *wl,
                        mutex_unlock(&wl->mutex);
                        ieee80211_scan_completed(wl->hw, false);
                        mutex_lock(&wl->mutex);
-                       wl->scanning = false;
+                       clear_bit(WL1271_FLAG_SCANNING, &wl->flags);
                }
        }
        return 0;
@@ -78,7 +78,7 @@ static int wl1271_event_ps_report(struct wl1271 *wl,
 
        switch (mbox->ps_status) {
        case EVENT_ENTER_POWER_SAVE_FAIL:
-               if (!wl->psm) {
+               if (!test_bit(WL1271_FLAG_PSM, &wl->flags)) {
                        wl->psm_entry_retry = 0;
                        break;
                }
@@ -89,7 +89,6 @@ static int wl1271_event_ps_report(struct wl1271 *wl,
                } else {
                        wl1271_error("PSM entry failed, giving up.\n");
                        wl->psm_entry_retry = 0;
-                       *beacon_loss = true;
                }
                break;
        case EVENT_ENTER_POWER_SAVE_SUCCESS:
@@ -136,7 +135,8 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
         * filtering) is enabled. Without PSM, the stack will receive all
         * beacons and can detect beacon loss by itself.
         */
-       if (vector & BSS_LOSE_EVENT_ID && wl->psm) {
+       if (vector & BSS_LOSE_EVENT_ID &&
+           test_bit(WL1271_FLAG_PSM, &wl->flags)) {
                wl1271_debug(DEBUG_EVENT, "BSS_LOSE_EVENT");
 
                /* indicate to the stack, that beacons have been lost */
@@ -150,7 +150,7 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
                        return ret;
        }
 
-       if (beacon_loss) {
+       if (wl->vif && beacon_loss) {
                /* Obviously, it's dangerous to release the mutex while
                   we are holding many of the variables in the wl struct.
                   That's why it's done last in the function, and care must
@@ -184,7 +184,7 @@ void wl1271_event_mbox_config(struct wl1271 *wl)
                     wl->mbox_ptr[0], wl->mbox_ptr[1]);
 }
 
-int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num, bool do_ack)
+int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num)
 {
        struct event_mailbox mbox;
        int ret;
@@ -204,9 +204,7 @@ int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num, bool do_ack)
                return ret;
 
        /* then we let the firmware know it can go on...*/
-       if (do_ack)
-               wl1271_spi_write32(wl, ACX_REG_INTERRUPT_TRIG,
-                                  INTR_TRIG_EVENT_ACK);
+       wl1271_spi_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK);
 
        return 0;
 }
index 4e3f55ebb1a87eb88ba09630fb94ed5c5f404b3d..278f9206aa5623ad6d9b08a93b066bec8d97de91 100644 (file)
@@ -112,6 +112,6 @@ struct event_mailbox {
 
 int wl1271_event_unmask(struct wl1271 *wl);
 void wl1271_event_mbox_config(struct wl1271 *wl);
-int wl1271_event_handle(struct wl1271 *wl, u8 mbox, bool do_ack);
+int wl1271_event_handle(struct wl1271 *wl, u8 mbox);
 
 #endif
index 11249b436cf1745a2c93ab3db7df4ba4147f29d7..c9848eecb767f45648233a84e0ed79b7131ba9be 100644 (file)
@@ -229,6 +229,10 @@ int wl1271_hw_init(struct wl1271 *wl)
        if (ret < 0)
                goto out_free_memmap;
 
+       ret = wl1271_acx_dco_itrim_params(wl);
+       if (ret < 0)
+               goto out_free_memmap;
+
        /* Initialize connection monitoring thresholds */
        ret = wl1271_acx_conn_monit_params(wl);
        if (ret < 0)
@@ -280,12 +284,12 @@ int wl1271_hw_init(struct wl1271 *wl)
                goto out_free_memmap;
 
        /* Configure TX rate classes */
-       ret = wl1271_acx_rate_policies(wl, CONF_TX_RATE_MASK_ALL);
+       ret = wl1271_acx_rate_policies(wl);
        if (ret < 0)
                goto out_free_memmap;
 
        /* Enable data path */
-       ret = wl1271_cmd_data_path(wl, wl->channel, 1);
+       ret = wl1271_cmd_data_path(wl, 1);
        if (ret < 0)
                goto out_free_memmap;
 
@@ -299,8 +303,8 @@ int wl1271_hw_init(struct wl1271 *wl)
        if (ret < 0)
                goto out_free_memmap;
 
-       /* Configure smart reflex */
-       ret = wl1271_acx_smart_reflex(wl);
+       /* configure PM */
+       ret = wl1271_acx_pm_config(wl);
        if (ret < 0)
                goto out_free_memmap;
 
index b62c00ff42fe0c3a724e6030d93421b1ae75a8bf..e4867b895c43b67fdc25e8c56b8ab949c34fff90 100644 (file)
@@ -47,6 +47,8 @@
 #include "wl1271_cmd.h"
 #include "wl1271_boot.h"
 
+#define WL1271_BOOT_RETRIES 3
+
 static struct conf_drv_settings default_conf = {
        .sg = {
                .per_threshold               = 7500,
@@ -67,16 +69,17 @@ static struct conf_drv_settings default_conf = {
                .ps_poll_timeout             = 15,
                .upsd_timeout                = 15,
                .rts_threshold               = 2347,
-               .rx_cca_threshold            = 0xFFEF,
-               .irq_blk_threshold           = 0,
-               .irq_pkt_threshold           = USHORT_MAX,
-               .irq_timeout                 = 5,
+               .rx_cca_threshold            = 0,
+               .irq_blk_threshold           = 0xFFFF,
+               .irq_pkt_threshold           = 0,
+               .irq_timeout                 = 600,
                .queue_type                  = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
        },
        .tx = {
                .tx_energy_detection         = 0,
                .rc_conf                     = {
-                       .enabled_rates       = CONF_TX_RATE_MASK_UNSPECIFIED,
+                       .enabled_rates       = CONF_HW_BIT_RATE_1MBPS |
+                                              CONF_HW_BIT_RATE_2MBPS,
                        .short_retry_limit   = 10,
                        .long_retry_limit    = 10,
                        .aflags              = 0
@@ -172,8 +175,8 @@ static struct conf_drv_settings default_conf = {
                        }
                },
                .frag_threshold              = IEEE80211_MAX_FRAG_THRESHOLD,
-               .tx_compl_timeout            = 5,
-               .tx_compl_threshold          = 5
+               .tx_compl_timeout            = 700,
+               .tx_compl_threshold          = 4
        },
        .conn = {
                .wake_up_event               = CONF_WAKE_UP_EVENT_DTIM,
@@ -186,12 +189,12 @@ static struct conf_drv_settings default_conf = {
                                .rule        = CONF_BCN_RULE_PASS_ON_APPEARANCE,
                        }
                },
-               .synch_fail_thold            = 5,
+               .synch_fail_thold            = 10,
                .bss_lose_timeout            = 100,
                .beacon_rx_timeout           = 10000,
                .broadcast_timeout           = 20000,
                .rx_broadcast_in_ps          = 1,
-               .ps_poll_threshold           = 4,
+               .ps_poll_threshold           = 20,
                .sig_trigger_count           = 2,
                .sig_trigger = {
                        [0] = {
@@ -226,46 +229,35 @@ static struct conf_drv_settings default_conf = {
                .psm_entry_retries           = 3
        },
        .init = {
-               .sr_err_tbl = {
-                       [0] = {
-                               .len         = 7,
-                               .upper_limit = 0x03,
-                               .values      = {
-                                       0x18, 0x10, 0x05, 0xfb, 0xf0, 0xe8,
-                                       0x00 }
-                       },
-                       [1] = {
-                               .len         = 7,
-                               .upper_limit = 0x03,
-                               .values      = {
-                                       0x18, 0x10, 0x05, 0xf6, 0xf0, 0xe8,
-                                       0x00 }
-                       },
-                       [2] = {
-                               .len         = 7,
-                               .upper_limit = 0x03,
-                               .values      = {
-                                       0x18, 0x10, 0x05, 0xfb, 0xf0, 0xe8,
-                                       0x00 }
-                       }
-               },
-               .sr_enable                   = 1,
                .genparam                    = {
                        .ref_clk             = CONF_REF_CLK_38_4_E,
                        .settling_time       = 5,
                        .clk_valid_on_wakeup = 0,
                        .dc2dcmode           = 0,
                        .single_dual_band    = CONF_SINGLE_BAND,
-                       .tx_bip_fem_autodetect = 0,
+                       .tx_bip_fem_autodetect = 1,
                        .tx_bip_fem_manufacturer = 1,
                        .settings = 1,
+                       .sr_state = 1,
+                       .srf1 = { 0x07, 0x03, 0x18, 0x10, 0x05, 0xfb, 0xf0,
+                                 0xe8, 0, 0, 0, 0, 0, 0, 0, 0 },
+                       .srf2 = { 0x07, 0x03, 0x18, 0x10, 0x05, 0xfb, 0xf0,
+                                 0xe8, 0, 0, 0, 0, 0, 0, 0, 0 },
+                       .srf3 = { 0x07, 0x03, 0x18, 0x10, 0x05, 0xfb, 0xf0,
+                                 0xe8, 0, 0, 0, 0, 0, 0, 0, 0 },
+                       .sr_debug_table = { 0, 0, 0, 0, 0, 0, 0, 0,
+                                           0, 0, 0, 0, 0, 0, 0, 0 },
+                       .sr_sen_n_p = 0,
+                       .sr_sen_n_p_gain = 0,
+                       .sr_sen_nrn = 0,
+                       .sr_sen_prn = 0,
                },
                .radioparam = {
-                       .rx_trace_loss       = 10,
-                       .tx_trace_loss       = 10,
+                       .rx_trace_loss       = 0x24,
+                       .tx_trace_loss       = 0x0,
                        .rx_rssi_and_proc_compens = {
                                0xec, 0xf6, 0x00, 0x0c, 0x18, 0xf8,
-                               0xfc, 0x00, 0x08, 0x10, 0xf0, 0xf8,
+                               0xfc, 0x00, 0x80, 0x10, 0xf0, 0xf8,
                                0x00, 0x0a, 0x14 },
                        .rx_trace_loss_5     = { 0, 0, 0, 0, 0, 0, 0 },
                        .tx_trace_loss_5     = { 0, 0, 0, 0, 0, 0, 0 },
@@ -273,13 +265,15 @@ static struct conf_drv_settings default_conf = {
                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                0x00, 0x00, 0x00 },
-                       .tx_ref_pd_voltage   = 0x24e,
-                       .tx_ref_power        = 0x78,
+                       .tx_ref_pd_voltage   = 0x1a9,
+                       .tx_ref_power        = 0x80,
                        .tx_offset_db        = 0x0,
                        .tx_rate_limits_normal = {
-                               0x1e, 0x1f, 0x22, 0x24, 0x28, 0x29 },
+                               0x1d, 0x1f, 0x24, 0x28, 0x28, 0x29 },
                        .tx_rate_limits_degraded = {
-                               0x1b, 0x1c, 0x1e, 0x20, 0x24, 0x25 },
+                               0x19, 0x1f, 0x22, 0x23, 0x27, 0x28 },
+                       .tx_rate_limits_extreme = {
+                               0x19, 0x1c, 0x1e, 0x20, 0x24, 0x25 },
                        .tx_channel_limits_11b = {
                                0x22, 0x50, 0x50, 0x50, 0x50, 0x50,
                                0x50, 0x50, 0x50, 0x50, 0x22, 0x50,
@@ -289,10 +283,12 @@ static struct conf_drv_settings default_conf = {
                                0x50, 0x50, 0x50, 0x50, 0x20, 0x50,
                                0x20, 0x50 },
                        .tx_pdv_rate_offsets = {
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                               0x07, 0x08, 0x04, 0x02, 0x02, 0x00 },
                        .tx_ibias            = {
-                               0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x27 },
-                       .rx_fem_insertion_loss = 0x14,
+                               0x11, 0x11, 0x15, 0x11, 0x15, 0x0f },
+                       .rx_fem_insertion_loss = 0x0e,
+                       .degraded_low_to_normal_threshold = 0x1e,
+                       .degraded_normal_to_high_threshold = 0x2d,
                        .tx_ref_pd_voltage_5 = {
                                0x0190, 0x01a4, 0x01c3, 0x01d8,
                                0x020a, 0x021c },
@@ -304,6 +300,8 @@ static struct conf_drv_settings default_conf = {
                                0x1b, 0x1e, 0x21, 0x23, 0x27, 0x00 },
                        .tx_rate_limits_degraded_5 = {
                                0x1b, 0x1e, 0x21, 0x23, 0x27, 0x00 },
+                       .tx_rate_limits_extreme_5 = {
+                               0x1b, 0x1e, 0x21, 0x23, 0x27, 0x00 },
                        .tx_channel_limits_ofdm_5 = {
                                0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50,
                                0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50,
@@ -315,8 +313,18 @@ static struct conf_drv_settings default_conf = {
                        .tx_ibias_5          = {
                                0x10, 0x10, 0x10, 0x10, 0x10, 0x10 },
                        .rx_fem_insertion_loss_5 = {
-                               0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 }
+                               0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 },
+                       .degraded_low_to_normal_threshold_5 = 0x00,
+                       .degraded_normal_to_high_threshold_5 = 0x00
                }
+       },
+       .itrim = {
+               .enable = false,
+               .timeout = 50000,
+       },
+       .pm_config = {
+               .host_clk_settling_time = 5000,
+               .host_fast_wakeup_support = false
        }
 };
 
@@ -359,7 +367,7 @@ static int wl1271_plt_init(struct wl1271 *wl)
        if (ret < 0)
                return ret;
 
-       ret = wl1271_cmd_data_path(wl, wl->channel, 1);
+       ret = wl1271_cmd_data_path(wl, 1);
        if (ret < 0)
                return ret;
 
@@ -374,11 +382,13 @@ static void wl1271_disable_interrupts(struct wl1271 *wl)
 static void wl1271_power_off(struct wl1271 *wl)
 {
        wl->set_power(false);
+       clear_bit(WL1271_FLAG_GPIO_POWER, &wl->flags);
 }
 
 static void wl1271_power_on(struct wl1271 *wl)
 {
        wl->set_power(true);
+       set_bit(WL1271_FLAG_GPIO_POWER, &wl->flags);
 }
 
 static void wl1271_fw_status(struct wl1271 *wl,
@@ -447,14 +457,13 @@ static void wl1271_irq_work(struct work_struct *work)
        intr &= WL1271_INTR_MASK;
 
        if (intr & WL1271_ACX_INTR_EVENT_A) {
-               bool do_ack = (intr & WL1271_ACX_INTR_EVENT_B) ? false : true;
                wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
-               wl1271_event_handle(wl, 0, do_ack);
+               wl1271_event_handle(wl, 0);
        }
 
        if (intr & WL1271_ACX_INTR_EVENT_B) {
                wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
-               wl1271_event_handle(wl, 1, true);
+               wl1271_event_handle(wl, 1);
        }
 
        if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
@@ -614,6 +623,7 @@ static int wl1271_chip_wakeup(struct wl1271 *wl)
        struct wl1271_partition_set partition;
        int ret = 0;
 
+       msleep(WL1271_PRE_POWER_ON_SLEEP);
        wl1271_power_on(wl);
        msleep(WL1271_POWER_ON_SLEEP);
        wl1271_spi_reset(wl);
@@ -643,7 +653,7 @@ static int wl1271_chip_wakeup(struct wl1271 *wl)
 
                ret = wl1271_setup(wl);
                if (ret < 0)
-                       goto out_power_off;
+                       goto out;
                break;
        case CHIP_ID_1271_PG20:
                wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
@@ -651,38 +661,34 @@ static int wl1271_chip_wakeup(struct wl1271 *wl)
 
                ret = wl1271_setup(wl);
                if (ret < 0)
-                       goto out_power_off;
+                       goto out;
                break;
        default:
-               wl1271_error("unsupported chip id: 0x%x", wl->chip.id);
+               wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
                ret = -ENODEV;
-               goto out_power_off;
+               goto out;
        }
 
        if (wl->fw == NULL) {
                ret = wl1271_fetch_firmware(wl);
                if (ret < 0)
-                       goto out_power_off;
+                       goto out;
        }
 
        /* No NVS from netlink, try to get it from the filesystem */
        if (wl->nvs == NULL) {
                ret = wl1271_fetch_nvs(wl);
                if (ret < 0)
-                       goto out_power_off;
+                       goto out;
        }
 
-       goto out;
-
-out_power_off:
-       wl1271_power_off(wl);
-
 out:
        return ret;
 }
 
 int wl1271_plt_start(struct wl1271 *wl)
 {
+       int retries = WL1271_BOOT_RETRIES;
        int ret;
 
        mutex_lock(&wl->mutex);
@@ -696,35 +702,48 @@ int wl1271_plt_start(struct wl1271 *wl)
                goto out;
        }
 
-       wl->state = WL1271_STATE_PLT;
-
-       ret = wl1271_chip_wakeup(wl);
-       if (ret < 0)
-               goto out;
-
-       ret = wl1271_boot(wl);
-       if (ret < 0)
-               goto out_power_off;
-
-       wl1271_notice("firmware booted in PLT mode (%s)", wl->chip.fw_ver);
+       while (retries) {
+               retries--;
+               ret = wl1271_chip_wakeup(wl);
+               if (ret < 0)
+                       goto power_off;
 
-       ret = wl1271_plt_init(wl);
-       if (ret < 0)
-               goto out_irq_disable;
+               ret = wl1271_boot(wl);
+               if (ret < 0)
+                       goto power_off;
 
-       /* Make sure power saving is disabled */
-       ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
-       if (ret < 0)
-               goto out_irq_disable;
+               ret = wl1271_plt_init(wl);
+               if (ret < 0)
+                       goto irq_disable;
 
-       goto out;
+               /* Make sure power saving is disabled */
+               ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
+               if (ret < 0)
+                       goto irq_disable;
 
-out_irq_disable:
-       wl1271_disable_interrupts(wl);
+               wl->state = WL1271_STATE_PLT;
+               wl1271_notice("firmware booted in PLT mode (%s)",
+                             wl->chip.fw_ver);
+               goto out;
 
-out_power_off:
-       wl1271_power_off(wl);
+irq_disable:
+               wl1271_disable_interrupts(wl);
+               mutex_unlock(&wl->mutex);
+               /* Unlocking the mutex in the middle of handling is
+                  inherently unsafe. In this case we deem it safe to do,
+                  because we need to let any possibly pending IRQ out of
+                  the system (and while we are WL1271_STATE_OFF the IRQ
+                  work function will not do anything.) Also, any other
+                  possible concurrent operations will fail due to the
+                  current state, hence the wl1271 struct should be safe. */
+               cancel_work_sync(&wl->irq_work);
+               mutex_lock(&wl->mutex);
+power_off:
+               wl1271_power_off(wl);
+       }
 
+       wl1271_error("firmware boot in PLT mode failed despite %d retries",
+                    WL1271_BOOT_RETRIES);
 out:
        mutex_unlock(&wl->mutex);
 
@@ -762,7 +781,20 @@ out:
 static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 {
        struct wl1271 *wl = hw->priv;
+       struct ieee80211_conf *conf = &hw->conf;
+       struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
+       struct ieee80211_sta *sta = txinfo->control.sta;
+       unsigned long flags;
 
+       /* peek into the rates configured in the STA entry */
+       spin_lock_irqsave(&wl->wl_lock, flags);
+       if (sta && sta->supp_rates[conf->channel->band] != wl->sta_rate_set) {
+               wl->sta_rate_set = sta->supp_rates[conf->channel->band];
+               set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
+       }
+       spin_unlock_irqrestore(&wl->wl_lock, flags);
+
+       /* queue the packet */
        skb_queue_tail(&wl->tx_queue, skb);
 
        /*
@@ -784,7 +816,7 @@ static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
                 * protected. Maybe fix this by removing the stupid
                 * variable altogether and checking the real queue state?
                 */
-               wl->tx_queue_stopped = true;
+               set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
        }
 
        return NETDEV_TX_OK;
@@ -880,6 +912,7 @@ static struct notifier_block wl1271_dev_notifier = {
 static int wl1271_op_start(struct ieee80211_hw *hw)
 {
        struct wl1271 *wl = hw->priv;
+       int retries = WL1271_BOOT_RETRIES;
        int ret = 0;
 
        wl1271_debug(DEBUG_MAC80211, "mac80211 start");
@@ -893,30 +926,42 @@ static int wl1271_op_start(struct ieee80211_hw *hw)
                goto out;
        }
 
-       ret = wl1271_chip_wakeup(wl);
-       if (ret < 0)
-               goto out;
-
-       ret = wl1271_boot(wl);
-       if (ret < 0)
-               goto out_power_off;
-
-       ret = wl1271_hw_init(wl);
-       if (ret < 0)
-               goto out_irq_disable;
-
-       wl->state = WL1271_STATE_ON;
+       while (retries) {
+               retries--;
+               ret = wl1271_chip_wakeup(wl);
+               if (ret < 0)
+                       goto power_off;
 
-       wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
+               ret = wl1271_boot(wl);
+               if (ret < 0)
+                       goto power_off;
 
-       goto out;
+               ret = wl1271_hw_init(wl);
+               if (ret < 0)
+                       goto irq_disable;
 
-out_irq_disable:
-       wl1271_disable_interrupts(wl);
+               wl->state = WL1271_STATE_ON;
+               wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
+               goto out;
 
-out_power_off:
-       wl1271_power_off(wl);
+irq_disable:
+               wl1271_disable_interrupts(wl);
+               mutex_unlock(&wl->mutex);
+               /* Unlocking the mutex in the middle of handling is
+                  inherently unsafe. In this case we deem it safe to do,
+                  because we need to let any possibly pending IRQ out of
+                  the system (and while we are WL1271_STATE_OFF the IRQ
+                  work function will not do anything.) Also, any other
+                  possible concurrent operations will fail due to the
+                  current state, hence the wl1271 struct should be safe. */
+               cancel_work_sync(&wl->irq_work);
+               mutex_lock(&wl->mutex);
+power_off:
+               wl1271_power_off(wl);
+       }
 
+       wl1271_error("firmware boot failed despite %d retries",
+                    WL1271_BOOT_RETRIES);
 out:
        mutex_unlock(&wl->mutex);
 
@@ -944,11 +989,10 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
 
        WARN_ON(wl->state != WL1271_STATE_ON);
 
-       if (wl->scanning) {
+       if (test_and_clear_bit(WL1271_FLAG_SCANNING, &wl->flags)) {
                mutex_unlock(&wl->mutex);
                ieee80211_scan_completed(wl->hw, true);
                mutex_lock(&wl->mutex);
-               wl->scanning = false;
        }
 
        wl->state = WL1271_STATE_OFF;
@@ -973,10 +1017,7 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
        wl->band = IEEE80211_BAND_2GHZ;
 
        wl->rx_counter = 0;
-       wl->elp = false;
-       wl->psm = 0;
        wl->psm_entry_retry = 0;
-       wl->tx_queue_stopped = false;
        wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
        wl->tx_blocks_available = 0;
        wl->tx_results_count = 0;
@@ -986,7 +1027,9 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
        wl->tx_security_seq_32 = 0;
        wl->time_offset = 0;
        wl->session_counter = 0;
-       wl->joined = false;
+       wl->rate_set = CONF_TX_RATE_MASK_BASIC;
+       wl->sta_rate_set = 0;
+       wl->flags = 0;
 
        for (i = 0; i < NUM_TX_QUEUES; i++)
                wl->tx_blocks_freed[i] = 0;
@@ -996,13 +1039,13 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
 }
 
 static int wl1271_op_add_interface(struct ieee80211_hw *hw,
-                                  struct ieee80211_if_init_conf *conf)
+                                  struct ieee80211_vif *vif)
 {
        struct wl1271 *wl = hw->priv;
        int ret = 0;
 
        wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
-                    conf->type, conf->mac_addr);
+                    vif->type, vif->addr);
 
        mutex_lock(&wl->mutex);
        if (wl->vif) {
@@ -1010,9 +1053,9 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
                goto out;
        }
 
-       wl->vif = conf->vif;
+       wl->vif = vif;
 
-       switch (conf->type) {
+       switch (vif->type) {
        case NL80211_IFTYPE_STATION:
                wl->bss_type = BSS_TYPE_STA_BSS;
                break;
@@ -1032,7 +1075,7 @@ out:
 }
 
 static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
-                                        struct ieee80211_if_init_conf *conf)
+                                        struct ieee80211_vif *vif)
 {
        struct wl1271 *wl = hw->priv;
 
@@ -1109,6 +1152,51 @@ out:
 }
 #endif
 
+static int wl1271_join_channel(struct wl1271 *wl, int channel)
+{
+       int ret = 0;
+       /* we need to use a dummy BSSID for now */
+       static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
+                                                 0xad, 0xbe, 0xef };
+
+       /* the dummy join is not required for ad-hoc */
+       if (wl->bss_type == BSS_TYPE_IBSS)
+               goto out;
+
+       /* disable mac filter, so we hear everything */
+       wl->rx_config &= ~CFG_BSSID_FILTER_EN;
+
+       wl->channel = channel;
+       memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
+
+       ret = wl1271_cmd_join(wl);
+       if (ret < 0)
+               goto out;
+
+       set_bit(WL1271_FLAG_JOINED, &wl->flags);
+
+out:
+       return ret;
+}
+
+static int wl1271_unjoin_channel(struct wl1271 *wl)
+{
+       int ret;
+
+       /* to stop listening to a channel, we disconnect */
+       ret = wl1271_cmd_disconnect(wl);
+       if (ret < 0)
+               goto out;
+
+       clear_bit(WL1271_FLAG_JOINED, &wl->flags);
+       wl->channel = 0;
+       memset(wl->bssid, 0, ETH_ALEN);
+       wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
+
+out:
+       return ret;
+}
+
 static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
 {
        struct wl1271 *wl = hw->priv;
@@ -1117,10 +1205,11 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
 
        channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
 
-       wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d",
+       wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s",
                     channel,
                     conf->flags & IEEE80211_CONF_PS ? "on" : "off",
-                    conf->power_level);
+                    conf->power_level,
+                    conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use");
 
        mutex_lock(&wl->mutex);
 
@@ -1130,34 +1219,44 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
        if (ret < 0)
                goto out;
 
-       if (channel != wl->channel) {
-               /*
-                * We assume that the stack will configure the right channel
-                * before associating, so we don't need to send a join
-                * command here.  We will join the right channel when the
-                * BSSID changes
-                */
-               wl->channel = channel;
+       if (changed & IEEE80211_CONF_CHANGE_IDLE) {
+               if (conf->flags & IEEE80211_CONF_IDLE &&
+                   test_bit(WL1271_FLAG_JOINED, &wl->flags))
+                       wl1271_unjoin_channel(wl);
+               else if (!(conf->flags & IEEE80211_CONF_IDLE))
+                       wl1271_join_channel(wl, channel);
+
+               if (conf->flags & IEEE80211_CONF_IDLE) {
+                       wl->rate_set = CONF_TX_RATE_MASK_BASIC;
+                       wl->sta_rate_set = 0;
+                       wl1271_acx_rate_policies(wl);
+               }
        }
 
-       if (conf->flags & IEEE80211_CONF_PS && !wl->psm_requested) {
-               wl1271_info("psm enabled");
+       /* if the channel changes while joined, join again */
+       if (channel != wl->channel && test_bit(WL1271_FLAG_JOINED, &wl->flags))
+               wl1271_join_channel(wl, channel);
 
-               wl->psm_requested = true;
+       if (conf->flags & IEEE80211_CONF_PS &&
+           !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
+               set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
 
                /*
                 * We enter PSM only if we're already associated.
                 * If we're not, we'll enter it when joining an SSID,
                 * through the bss_info_changed() hook.
                 */
-               ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE);
+               if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
+                       wl1271_info("psm enabled");
+                       ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE);
+               }
        } else if (!(conf->flags & IEEE80211_CONF_PS) &&
-                  wl->psm_requested) {
+                  test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
                wl1271_info("psm disabled");
 
-               wl->psm_requested = false;
+               clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
 
-               if (wl->psm)
+               if (test_bit(WL1271_FLAG_PSM, &wl->flags))
                        ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE);
        }
 
@@ -1440,22 +1539,6 @@ out:
        return ret;
 }
 
-static u32 wl1271_enabled_rates_get(struct wl1271 *wl, u64 basic_rate_set)
-{
-       struct ieee80211_supported_band *band;
-       u32 enabled_rates = 0;
-       int bit;
-
-       band = wl->hw->wiphy->bands[wl->band];
-       for (bit = 0; bit < band->n_bitrates; bit++) {
-               if (basic_rate_set & 0x1)
-                       enabled_rates |= band->bitrates[bit].hw_value;
-               basic_rate_set >>= 1;
-       }
-
-       return enabled_rates;
-}
-
 static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
                                       struct ieee80211_vif *vif,
                                       struct ieee80211_bss_conf *bss_conf,
@@ -1473,9 +1556,68 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
        if (ret < 0)
                goto out;
 
+       if ((changed & BSS_CHANGED_BSSID) &&
+           /*
+            * Now we know the correct bssid, so we send a new join command
+            * and enable the BSSID filter
+            */
+           memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
+                       wl->rx_config |= CFG_BSSID_FILTER_EN;
+                       memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
+                       ret = wl1271_cmd_build_null_data(wl);
+                       if (ret < 0) {
+                               wl1271_warning("cmd buld null data failed %d",
+                                              ret);
+                               goto out_sleep;
+                       }
+                       ret = wl1271_cmd_join(wl);
+                       if (ret < 0) {
+                               wl1271_warning("cmd join failed %d", ret);
+                               goto out_sleep;
+                       }
+                       set_bit(WL1271_FLAG_JOINED, &wl->flags);
+       }
+
+       if (wl->bss_type == BSS_TYPE_IBSS) {
+               /* FIXME: This implements rudimentary ad-hoc support -
+                  proper templates are on the wish list and notification
+                  on when they change. This patch will update the templates
+                  on every call to this function. Also, the firmware will not
+                  answer to probe-requests as it does not have the proper
+                  SSID set in the JOIN command. The probe-response template
+                  is set nevertheless, as the FW will ASSERT without it */
+               struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
+
+               if (beacon) {
+                       struct ieee80211_hdr *hdr;
+                       ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
+                                                     beacon->data,
+                                                     beacon->len);
+
+                       if (ret < 0) {
+                               dev_kfree_skb(beacon);
+                               goto out_sleep;
+                       }
+
+                       hdr = (struct ieee80211_hdr *) beacon->data;
+                       hdr->frame_control = cpu_to_le16(
+                               IEEE80211_FTYPE_MGMT |
+                               IEEE80211_STYPE_PROBE_RESP);
+
+                       ret = wl1271_cmd_template_set(wl,
+                                                     CMD_TEMPL_PROBE_RESPONSE,
+                                                     beacon->data,
+                                                     beacon->len);
+                       dev_kfree_skb(beacon);
+                       if (ret < 0)
+                               goto out_sleep;
+               }
+       }
+
        if (changed & BSS_CHANGED_ASSOC) {
                if (bss_conf->assoc) {
                        wl->aid = bss_conf->aid;
+                       set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
 
                        /*
                         * with wl1271, we don't need to update the
@@ -1492,7 +1634,8 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
                                goto out_sleep;
 
                        /* If we want to go in PSM but we're not there yet */
-                       if (wl->psm_requested && !wl->psm) {
+                       if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
+                           !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
                                mode = STATION_POWER_SAVE_MODE;
                                ret = wl1271_ps_set_mode(wl, mode);
                                if (ret < 0)
@@ -1500,7 +1643,7 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
                        }
                } else {
                        /* use defaults when not associated */
-                       wl->basic_rate_set = WL1271_DEFAULT_BASIC_RATE_SET;
+                       clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
                        wl->aid = 0;
                }
 
@@ -1535,17 +1678,6 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
                }
        }
 
-       if (changed & BSS_CHANGED_BASIC_RATES) {
-               wl->basic_rate_set = wl1271_enabled_rates_get(
-                       wl, bss_conf->basic_rates);
-
-               ret = wl1271_acx_rate_policies(wl, wl->basic_rate_set);
-               if (ret < 0) {
-                       wl1271_warning("Set rate policies failed %d", ret);
-                       goto out_sleep;
-               }
-       }
-
 out_sleep:
        wl1271_ps_elp_sleep(wl);
 
@@ -1599,19 +1731,19 @@ static struct ieee80211_rate wl1271_rates[] = {
 
 /* can't be const, mac80211 writes to this */
 static struct ieee80211_channel wl1271_channels[] = {
-       { .hw_value = 1, .center_freq = 2412},
-       { .hw_value = 2, .center_freq = 2417},
-       { .hw_value = 3, .center_freq = 2422},
-       { .hw_value = 4, .center_freq = 2427},
-       { .hw_value = 5, .center_freq = 2432},
-       { .hw_value = 6, .center_freq = 2437},
-       { .hw_value = 7, .center_freq = 2442},
-       { .hw_value = 8, .center_freq = 2447},
-       { .hw_value = 9, .center_freq = 2452},
-       { .hw_value = 10, .center_freq = 2457},
-       { .hw_value = 11, .center_freq = 2462},
-       { .hw_value = 12, .center_freq = 2467},
-       { .hw_value = 13, .center_freq = 2472},
+       { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
+       { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
+       { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
+       { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
+       { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
+       { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
+       { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
+       { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
+       { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
+       { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
+       { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
+       { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
+       { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
 };
 
 /* can't be const, mac80211 writes to this */
@@ -1757,7 +1889,8 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
                IEEE80211_HW_BEACON_FILTER |
                IEEE80211_HW_SUPPORTS_PS;
 
-       wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
+       wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
+               BIT(NL80211_IFTYPE_ADHOC);
        wl->hw->wiphy->max_scan_ssids = 1;
        wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
 
@@ -1818,21 +1951,18 @@ static int __devinit wl1271_probe(struct spi_device *spi)
 
        INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
        wl->channel = WL1271_DEFAULT_CHANNEL;
-       wl->scanning = false;
        wl->default_key = 0;
        wl->rx_counter = 0;
        wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
        wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
-       wl->elp = false;
-       wl->psm = 0;
-       wl->psm_requested = false;
        wl->psm_entry_retry = 0;
-       wl->tx_queue_stopped = false;
        wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
-       wl->basic_rate_set = WL1271_DEFAULT_BASIC_RATE_SET;
+       wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
+       wl->rate_set = CONF_TX_RATE_MASK_BASIC;
+       wl->sta_rate_set = 0;
        wl->band = IEEE80211_BAND_2GHZ;
        wl->vif = NULL;
-       wl->joined = false;
+       wl->flags = 0;
 
        for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
                wl->tx_frames[i] = NULL;
index 507cd91d7eed3418a2c69e57fe98410b23031242..e407790f677131c2a38781b48dff31ab94bd3e63 100644 (file)
@@ -39,12 +39,13 @@ void wl1271_elp_work(struct work_struct *work)
 
        mutex_lock(&wl->mutex);
 
-       if (wl->elp || !wl->psm)
+       if (test_bit(WL1271_FLAG_IN_ELP, &wl->flags) ||
+           !test_bit(WL1271_FLAG_PSM, &wl->flags))
                goto out;
 
        wl1271_debug(DEBUG_PSM, "chip to elp");
        wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP);
-       wl->elp = true;
+       set_bit(WL1271_FLAG_IN_ELP, &wl->flags);
 
 out:
        mutex_unlock(&wl->mutex);
@@ -55,7 +56,7 @@ out:
 /* Routines to toggle sleep mode while in ELP */
 void wl1271_ps_elp_sleep(struct wl1271 *wl)
 {
-       if (wl->psm) {
+       if (test_bit(WL1271_FLAG_PSM, &wl->flags)) {
                cancel_delayed_work(&wl->elp_work);
                ieee80211_queue_delayed_work(wl->hw, &wl->elp_work,
                                        msecs_to_jiffies(ELP_ENTRY_DELAY));
@@ -70,7 +71,7 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl, bool chip_awake)
        u32 start_time = jiffies;
        bool pending = false;
 
-       if (!wl->elp)
+       if (!test_bit(WL1271_FLAG_IN_ELP, &wl->flags))
                return 0;
 
        wl1271_debug(DEBUG_PSM, "waking up chip from elp");
@@ -101,7 +102,7 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl, bool chip_awake)
                }
        }
 
-       wl->elp = false;
+       clear_bit(WL1271_FLAG_IN_ELP, &wl->flags);
 
        wl1271_debug(DEBUG_PSM, "wakeup time: %u ms",
                     jiffies_to_msecs(jiffies - start_time));
@@ -143,7 +144,7 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode)
                if (ret < 0)
                        return ret;
 
-               wl->psm = 1;
+               set_bit(WL1271_FLAG_PSM, &wl->flags);
                break;
        case STATION_ACTIVE_MODE:
        default:
@@ -166,7 +167,7 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode)
                if (ret < 0)
                        return ret;
 
-               wl->psm = 0;
+               clear_bit(WL1271_FLAG_PSM, &wl->flags);
                break;
        }
 
index 1f237389d1c771b9e88f29e58f9db3cce0ce4285..990960771528e423773a03f6c31d1a9b1caa6a4d 100644 (file)
 #define WL1271_SLV_REG_DATA            (REGISTERS_BASE + 0x0008)
 #define WL1271_SLV_REG_ADATA           (REGISTERS_BASE + 0x000c)
 #define WL1271_SLV_MEM_DATA            (REGISTERS_BASE + 0x0018)
-/*
- * Interrupt registers.
- * 64 bit interrupt sources registers ws ced.
- * sme interupts were removed and new ones were added.
- * Order was changed.
- */
-#define FIQ_MASK                       (REGISTERS_BASE + 0x0400)
-#define FIQ_MASK_L                     (REGISTERS_BASE + 0x0400)
-#define FIQ_MASK_H                     (REGISTERS_BASE + 0x0404)
-#define FIQ_MASK_SET                   (REGISTERS_BASE + 0x0408)
-#define FIQ_MASK_SET_L                 (REGISTERS_BASE + 0x0408)
-#define FIQ_MASK_SET_H                 (REGISTERS_BASE + 0x040C)
-#define FIQ_MASK_CLR                   (REGISTERS_BASE + 0x0410)
-#define FIQ_MASK_CLR_L                 (REGISTERS_BASE + 0x0410)
-#define FIQ_MASK_CLR_H                 (REGISTERS_BASE + 0x0414)
-#define IRQ_MASK                       (REGISTERS_BASE + 0x0418)
-#define IRQ_MASK_L                     (REGISTERS_BASE + 0x0418)
-#define IRQ_MASK_H                     (REGISTERS_BASE + 0x041C)
-#define IRQ_MASK_SET                   (REGISTERS_BASE + 0x0420)
-#define IRQ_MASK_SET_L                 (REGISTERS_BASE + 0x0420)
-#define IRQ_MASK_SET_H                 (REGISTERS_BASE + 0x0424)
-#define IRQ_MASK_CLR                   (REGISTERS_BASE + 0x0428)
-#define IRQ_MASK_CLR_L                 (REGISTERS_BASE + 0x0428)
-#define IRQ_MASK_CLR_H                 (REGISTERS_BASE + 0x042C)
-#define ECPU_MASK                      (REGISTERS_BASE + 0x0448)
-#define FIQ_STS_L                      (REGISTERS_BASE + 0x044C)
-#define FIQ_STS_H                      (REGISTERS_BASE + 0x0450)
-#define IRQ_STS_L                      (REGISTERS_BASE + 0x0454)
-#define IRQ_STS_H                      (REGISTERS_BASE + 0x0458)
-#define INT_STS_ND                     (REGISTERS_BASE + 0x0464)
-#define INT_STS_RAW_L                  (REGISTERS_BASE + 0x0464)
-#define INT_STS_RAW_H                  (REGISTERS_BASE + 0x0468)
-#define INT_STS_CLR                    (REGISTERS_BASE + 0x04B4)
-#define INT_STS_CLR_L                  (REGISTERS_BASE + 0x04B4)
-#define INT_STS_CLR_H                  (REGISTERS_BASE + 0x04B8)
-#define INT_ACK                        (REGISTERS_BASE + 0x046C)
-#define INT_ACK_L                      (REGISTERS_BASE + 0x046C)
-#define INT_ACK_H                      (REGISTERS_BASE + 0x0470)
-#define INT_TRIG                       (REGISTERS_BASE + 0x0474)
-#define INT_TRIG_L                     (REGISTERS_BASE + 0x0474)
-#define INT_TRIG_H                     (REGISTERS_BASE + 0x0478)
-#define HOST_STS_L                     (REGISTERS_BASE + 0x045C)
-#define HOST_STS_H                     (REGISTERS_BASE + 0x0460)
-#define HOST_MASK                      (REGISTERS_BASE + 0x0430)
-#define HOST_MASK_L                    (REGISTERS_BASE + 0x0430)
-#define HOST_MASK_H                    (REGISTERS_BASE + 0x0434)
-#define HOST_MASK_SET                  (REGISTERS_BASE + 0x0438)
-#define HOST_MASK_SET_L                (REGISTERS_BASE + 0x0438)
-#define HOST_MASK_SET_H                (REGISTERS_BASE + 0x043C)
-#define HOST_MASK_CLR                  (REGISTERS_BASE + 0x0440)
-#define HOST_MASK_CLR_L                (REGISTERS_BASE + 0x0440)
-#define HOST_MASK_CLR_H                (REGISTERS_BASE + 0x0444)
 
 #define ACX_REG_INTERRUPT_TRIG         (REGISTERS_BASE + 0x0474)
 #define ACX_REG_INTERRUPT_TRIG_H       (REGISTERS_BASE + 0x0478)
 
-/* Host Interrupts*/
-#define HINT_MASK                      (REGISTERS_BASE + 0x0494)
-#define HINT_MASK_SET                  (REGISTERS_BASE + 0x0498)
-#define HINT_MASK_CLR                  (REGISTERS_BASE + 0x049C)
-#define HINT_STS_ND_MASKED             (REGISTERS_BASE + 0x04A0)
-/*1150 spec calls this HINT_STS_RAW*/
-#define HINT_STS_ND                   (REGISTERS_BASE + 0x04B0)
-#define HINT_STS_CLR                   (REGISTERS_BASE + 0x04A4)
-#define HINT_ACK                       (REGISTERS_BASE + 0x04A8)
-#define HINT_TRIG                      (REGISTERS_BASE + 0x04AC)
-
 /*=============================================
   Host Interrupt Mask Register - 32bit (RW)
   ------------------------------------------
                                      | CFG_RX_PRSP_EN)
 
 
-/*===============================================
-  Phy regs
- ===============================================*/
-#define ACX_PHY_ADDR_REG                SBB_ADDR
-#define ACX_PHY_DATA_REG                SBB_DATA
-#define ACX_PHY_CTRL_REG                SBB_CTL
-#define ACX_PHY_REG_WR_MASK             0x00000001ul
-#define ACX_PHY_REG_RD_MASK             0x00000002ul
-
-
 /*===============================================
  EEPROM Read/Write Request 32bit RW
  ------------------------------------------
 #define ACX_CONT_WIND_MIN_MASK   0x0000007f
 #define ACX_CONT_WIND_MAX        0x03ff0000
 
-/*
- * Indirect slave register/memory registers
- * ----------------------------------------
- */
-#define HW_SLAVE_REG_ADDR_REG          0x00000004
-#define HW_SLAVE_REG_DATA_REG          0x00000008
-#define HW_SLAVE_REG_CTRL_REG          0x0000000c
-
-#define SLAVE_AUTO_INC                         0x00010000
-#define SLAVE_NO_AUTO_INC                      0x00000000
-#define SLAVE_HOST_LITTLE_ENDIAN       0x00000000
-
-#define HW_SLAVE_MEM_ADDR_REG          SLV_MEM_ADDR
-#define HW_SLAVE_MEM_DATA_REG          SLV_MEM_DATA
-#define HW_SLAVE_MEM_CTRL_REG          SLV_MEM_CTL
-#define HW_SLAVE_MEM_ENDIAN_REG                SLV_END_CTL
-
-#define HW_FUNC_EVENT_INT_EN           0x8000
-#define HW_FUNC_EVENT_MASK_REG         0x00000034
-
-#define ACX_MAC_TIMESTAMP_REG  (MAC_TIMESTAMP)
-
 /*===============================================
   HI_CFG Interface Configuration Register Values
   ------------------------------------------
@@ -647,10 +552,6 @@ b12-b0 - Supported Rate indicator bits as defined below.
 ******************************************************************************/
 
 
-#define TNETW1251_CHIP_ID_PG1_0         0x07010101
-#define TNETW1251_CHIP_ID_PG1_1         0x07020101
-#define TNETW1251_CHIP_ID_PG1_2                0x07030101
-
 /*************************************************************************
 
     Interrupt Trigger Register (Host -> WiLink)
index 02978a16e73232c87b5af0921ae1514ee54cdadc..ee9564aa6ecc0851bf5f3daabe05588935765286 100644 (file)
@@ -397,8 +397,7 @@ u16 wl1271_top_reg_read(struct wl1271 *wl, int addr)
        /* poll for data ready */
        do {
                val = wl1271_spi_read32(wl, OCP_DATA_READ);
-               timeout--;
-       } while (!(val & OCP_READY_MASK) && timeout);
+       } while (!(val & OCP_READY_MASK) && --timeout);
 
        if (!timeout) {
                wl1271_warning("Top register access timed out.");
index 00af065c77c20e14b5dc5f79dc86ef092054515d..a288cc317d7b076d51f63f7f51490c56fd30f5d6 100644 (file)
@@ -121,6 +121,11 @@ static int wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
        pad = pad - skb->len;
        tx_attr |= pad << TX_HW_ATTR_OFST_LAST_WORD_PAD;
 
+       /* if the packets are destined for AP (have a STA entry) send them
+          with AP rate policies, otherwise use default basic rates */
+       if (control->control.sta)
+               tx_attr |= ACX_TX_AP_FULL_RATE << TX_HW_ATTR_OFST_RATE_POLICY;
+
        desc->tx_attr = cpu_to_le16(tx_attr);
 
        wl1271_debug(DEBUG_TX, "tx_fill_hdr: pad: %d", pad);
@@ -214,18 +219,50 @@ static int wl1271_tx_frame(struct wl1271 *wl, struct sk_buff *skb)
        return ret;
 }
 
+static u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set)
+{
+       struct ieee80211_supported_band *band;
+       u32 enabled_rates = 0;
+       int bit;
+
+       band = wl->hw->wiphy->bands[wl->band];
+       for (bit = 0; bit < band->n_bitrates; bit++) {
+               if (rate_set & 0x1)
+                       enabled_rates |= band->bitrates[bit].hw_value;
+               rate_set >>= 1;
+       }
+
+       return enabled_rates;
+}
+
 void wl1271_tx_work(struct work_struct *work)
 {
        struct wl1271 *wl = container_of(work, struct wl1271, tx_work);
        struct sk_buff *skb;
        bool woken_up = false;
+       u32 sta_rates = 0;
        int ret;
 
+       /* check if the rates supported by the AP have changed */
+       if (unlikely(test_and_clear_bit(WL1271_FLAG_STA_RATES_CHANGED,
+                                       &wl->flags))) {
+               unsigned long flags;
+               spin_lock_irqsave(&wl->wl_lock, flags);
+               sta_rates = wl->sta_rate_set;
+               spin_unlock_irqrestore(&wl->wl_lock, flags);
+       }
+
        mutex_lock(&wl->mutex);
 
        if (unlikely(wl->state == WL1271_STATE_OFF))
                goto out;
 
+       /* if rates have changed, re-configure the rate policy */
+       if (unlikely(sta_rates)) {
+               wl->rate_set = wl1271_tx_enabled_rates_get(wl, sta_rates);
+               wl1271_acx_rate_policies(wl);
+       }
+
        while ((skb = skb_dequeue(&wl->tx_queue))) {
                if (!woken_up) {
                        ret = wl1271_ps_elp_wakeup(wl, false);
@@ -240,18 +277,18 @@ void wl1271_tx_work(struct work_struct *work)
                        wl1271_debug(DEBUG_TX, "tx_work: fw buffer full, "
                                     "stop queues");
                        ieee80211_stop_queues(wl->hw);
-                       wl->tx_queue_stopped = true;
+                       set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
                        skb_queue_head(&wl->tx_queue, skb);
                        goto out;
                } else if (ret < 0) {
                        dev_kfree_skb(skb);
                        goto out;
-               } else if (wl->tx_queue_stopped) {
+               } else if (test_and_clear_bit(WL1271_FLAG_TX_QUEUE_STOPPED,
+                                             &wl->flags)) {
                        /* firmware buffer has space, restart queues */
                        wl1271_debug(DEBUG_TX,
                                     "complete_packet: waking queues");
                        ieee80211_wake_queues(wl->hw);
-                       wl->tx_queue_stopped = false;
                }
        }
 
index f14deb0c8514171809b877fdb167e95cd623c23d..2d555cc3050868954f8cc86789f9fba4a0fbb1f1 100644 (file)
@@ -869,7 +869,7 @@ int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length)
 }
 
 static int zd_op_add_interface(struct ieee80211_hw *hw,
-                               struct ieee80211_if_init_conf *conf)
+                               struct ieee80211_vif *vif)
 {
        struct zd_mac *mac = zd_hw_mac(hw);
 
@@ -877,22 +877,22 @@ static int zd_op_add_interface(struct ieee80211_hw *hw,
        if (mac->type != NL80211_IFTYPE_UNSPECIFIED)
                return -EOPNOTSUPP;
 
-       switch (conf->type) {
+       switch (vif->type) {
        case NL80211_IFTYPE_MONITOR:
        case NL80211_IFTYPE_MESH_POINT:
        case NL80211_IFTYPE_STATION:
        case NL80211_IFTYPE_ADHOC:
-               mac->type = conf->type;
+               mac->type = vif->type;
                break;
        default:
                return -EOPNOTSUPP;
        }
 
-       return zd_write_mac_addr(&mac->chip, conf->mac_addr);
+       return zd_write_mac_addr(&mac->chip, vif->addr);
 }
 
 static void zd_op_remove_interface(struct ieee80211_hw *hw,
-                                   struct ieee80211_if_init_conf *conf)
+                                   struct ieee80211_vif *vif)
 {
        struct zd_mac *mac = zd_hw_mac(hw);
        mac->type = NL80211_IFTYPE_UNSPECIFIED;
index 72d3e437e1905f674548099f6d9bf22dcb8d1bff..442fc1117326bbaefdb11975c7166d8cf8387987 100644 (file)
@@ -1079,11 +1079,15 @@ static int eject_installer(struct usb_interface *intf)
        int r;
 
        /* Find bulk out endpoint */
-       endpoint = &iface_desc->endpoint[1].desc;
-       if (usb_endpoint_dir_out(endpoint) &&
-           usb_endpoint_xfer_bulk(endpoint)) {
-               bulk_out_ep = endpoint->bEndpointAddress;
-       } else {
+       for (r = 1; r >= 0; r--) {
+               endpoint = &iface_desc->endpoint[r].desc;
+               if (usb_endpoint_dir_out(endpoint) &&
+                   usb_endpoint_xfer_bulk(endpoint)) {
+                       bulk_out_ep = endpoint->bEndpointAddress;
+                       break;
+               }
+       }
+       if (r == -1) {
                dev_err(&udev->dev,
                        "zd1211rw: Could not find bulk out endpoint\n");
                return -ENODEV;
index 8c777ba4e2b39868676e267136efb6ec075b5799..f7fe1aa03b427eb51a46d725be69820f766c898d 100644 (file)
@@ -925,11 +925,7 @@ static int __devinit xemaclite_of_probe(struct of_device *ofdev,
        /* Set the MAC address in the EmacLite device */
        xemaclite_set_mac_address(lp, ndev->dev_addr);
 
-       dev_info(dev,
-                "MAC address is now %2x:%2x:%2x:%2x:%2x:%2x\n",
-                ndev->dev_addr[0], ndev->dev_addr[1],
-                ndev->dev_addr[2], ndev->dev_addr[3],
-                ndev->dev_addr[4], ndev->dev_addr[5]);
+       dev_info(dev, "MAC address is now %pM\n", ndev->dev_addr);
 
        ndev->netdev_ops = &xemaclite_netdev_ops;
        ndev->flags &= ~IFF_MULTICAST;
index 0f773a9a3ff22bfe11248caa788211cbd90450d7..8b231b30fd1230997bf3e3220ae76c57ac9b2837 100644 (file)
@@ -237,7 +237,7 @@ static const struct pci_id_info pci_id_tbl[] = {
        { }
 };
 
-static const struct pci_device_id yellowfin_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(yellowfin_pci_tbl) = {
        { 0x1000, 0x0702, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
        { 0x1000, 0x0701, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 },
        { }
index b232693378cd8b92c7f0a69f347c6f7f5174137d..a3ac4456e0b1ee9f00f86ba97c385099053400e4 100644 (file)
@@ -649,6 +649,7 @@ struct qeth_card_options {
        int performance_stats;
        int rx_sg_cb;
        enum qeth_ipa_isolation_modes isolation;
+       int sniffer;
 };
 
 /*
@@ -737,6 +738,7 @@ struct qeth_card {
        struct qeth_discipline discipline;
        atomic_t force_alloc_skb;
        struct service_level qeth_service_level;
+       struct qdio_ssqd_desc ssqd;
 };
 
 struct qeth_card_list_struct {
@@ -811,7 +813,8 @@ int qeth_send_ipa_cmd(struct qeth_card *, struct qeth_cmd_buffer *,
 struct qeth_cmd_buffer *qeth_get_ipacmd_buffer(struct qeth_card *,
                        enum qeth_ipa_cmds, enum qeth_prot_versions);
 int qeth_query_setadapterparms(struct qeth_card *);
-int qeth_check_qdio_errors(struct qdio_buffer *, unsigned int, const char *);
+int qeth_check_qdio_errors(struct qeth_card *, struct qdio_buffer *,
+               unsigned int, const char *);
 void qeth_queue_input_buffer(struct qeth_card *, int);
 struct sk_buff *qeth_core_get_next_skb(struct qeth_card *,
                struct qdio_buffer *, struct qdio_buffer_element **, int *,
index d34804d5ece14703a079ba1d2f4ac2ad6d619969..fa8a519218acc81f1b4af5e252d5cb8fc5beb4a6 100644 (file)
@@ -269,6 +269,7 @@ int qeth_realloc_buffer_pool(struct qeth_card *card, int bufcnt)
        card->qdio.init_pool.buf_count = bufcnt;
        return qeth_alloc_buffer_pool(card);
 }
+EXPORT_SYMBOL_GPL(qeth_realloc_buffer_pool);
 
 static int qeth_issue_next_read(struct qeth_card *card)
 {
@@ -350,8 +351,10 @@ static struct qeth_ipa_cmd *qeth_check_ipa_data(struct qeth_card *card,
        if (IS_IPA(iob->data)) {
                cmd = (struct qeth_ipa_cmd *) PDU_ENCAPSULATION(iob->data);
                if (IS_IPA_REPLY(cmd)) {
-                       if (cmd->hdr.command < IPA_CMD_SETCCID ||
-                           cmd->hdr.command > IPA_CMD_MODCCID)
+                       if (cmd->hdr.command != IPA_CMD_SETCCID &&
+                           cmd->hdr.command != IPA_CMD_DELCCID &&
+                           cmd->hdr.command != IPA_CMD_MODCCID &&
+                           cmd->hdr.command != IPA_CMD_SET_DIAG_ASS)
                                qeth_issue_ipa_msg(cmd,
                                                cmd->hdr.return_code, card);
                        return cmd;
@@ -1100,11 +1103,6 @@ static int qeth_setup_card(struct qeth_card *card)
        card->thread_running_mask = 0;
        INIT_WORK(&card->kernel_thread_starter, qeth_start_kernel_thread);
        INIT_LIST_HEAD(&card->ip_list);
-       card->ip_tbd_list = kmalloc(sizeof(struct list_head), GFP_KERNEL);
-       if (!card->ip_tbd_list) {
-               QETH_DBF_TEXT(SETUP, 0, "iptbdnom");
-               return -ENOMEM;
-       }
        INIT_LIST_HEAD(card->ip_tbd_list);
        INIT_LIST_HEAD(&card->cmd_waiter_list);
        init_waitqueue_head(&card->wait_q);
@@ -1138,21 +1136,30 @@ static struct qeth_card *qeth_alloc_card(void)
        QETH_DBF_TEXT(SETUP, 2, "alloccrd");
        card = kzalloc(sizeof(struct qeth_card), GFP_DMA|GFP_KERNEL);
        if (!card)
-               return NULL;
+               goto out;
        QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *));
-       if (qeth_setup_channel(&card->read)) {
-               kfree(card);
-               return NULL;
-       }
-       if (qeth_setup_channel(&card->write)) {
-               qeth_clean_channel(&card->read);
-               kfree(card);
-               return NULL;
+       card->ip_tbd_list = kmalloc(sizeof(struct list_head), GFP_KERNEL);
+       if (!card->ip_tbd_list) {
+               QETH_DBF_TEXT(SETUP, 0, "iptbdnom");
+               goto out_card;
        }
+       if (qeth_setup_channel(&card->read))
+               goto out_ip;
+       if (qeth_setup_channel(&card->write))
+               goto out_channel;
        card->options.layer2 = -1;
        card->qeth_service_level.seq_print = qeth_core_sl_print;
        register_service_level(&card->qeth_service_level);
        return card;
+
+out_channel:
+       qeth_clean_channel(&card->read);
+out_ip:
+       kfree(card->ip_tbd_list);
+out_card:
+       kfree(card);
+out:
+       return NULL;
 }
 
 static int qeth_determine_card_type(struct qeth_card *card)
@@ -1355,26 +1362,29 @@ static int qeth_read_conf_data(struct qeth_card *card, void **buffer,
        return ret;
 }
 
-static int qeth_get_unitaddr(struct qeth_card *card)
+static void qeth_configure_unitaddr(struct qeth_card *card, char *prcd)
 {
-       int length;
-       char *prcd;
-       int rc;
-
-       QETH_DBF_TEXT(SETUP, 2, "getunit");
-       rc = qeth_read_conf_data(card, (void **) &prcd, &length);
-       if (rc) {
-               QETH_DBF_MESSAGE(2, "%s qeth_read_conf_data returned %i\n",
-                       dev_name(&card->gdev->dev), rc);
-               return rc;
-       }
+       QETH_DBF_TEXT(SETUP, 2, "cfgunit");
        card->info.chpid = prcd[30];
        card->info.unit_addr2 = prcd[31];
        card->info.cula = prcd[63];
        card->info.guestlan = ((prcd[0x10] == _ascebc['V']) &&
                               (prcd[0x11] == _ascebc['M']));
-       kfree(prcd);
-       return 0;
+}
+
+static void qeth_configure_blkt_default(struct qeth_card *card, char *prcd)
+{
+       QETH_DBF_TEXT(SETUP, 2, "cfgblkt");
+
+       if (prcd[74] == 0xF0 && prcd[75] == 0xF0 && prcd[76] == 0xF5) {
+               card->info.blkt.time_total = 250;
+               card->info.blkt.inter_packet = 5;
+               card->info.blkt.inter_packet_jumbo = 15;
+       } else {
+               card->info.blkt.time_total = 0;
+               card->info.blkt.inter_packet = 0;
+               card->info.blkt.inter_packet_jumbo = 0;
+       }
 }
 
 static void qeth_init_tokens(struct qeth_card *card)
@@ -2573,8 +2583,8 @@ int qeth_query_setadapterparms(struct qeth_card *card)
 }
 EXPORT_SYMBOL_GPL(qeth_query_setadapterparms);
 
-int qeth_check_qdio_errors(struct qdio_buffer *buf, unsigned int qdio_error,
-               const char *dbftext)
+int qeth_check_qdio_errors(struct qeth_card *card, struct qdio_buffer *buf,
+               unsigned int qdio_error, const char *dbftext)
 {
        if (qdio_error) {
                QETH_DBF_TEXT(TRACE, 2, dbftext);
@@ -2584,7 +2594,11 @@ int qeth_check_qdio_errors(struct qdio_buffer *buf, unsigned int qdio_error,
                QETH_DBF_TEXT_(QERR, 2, " F14=%02X",
                               buf->element[14].flags & 0xff);
                QETH_DBF_TEXT_(QERR, 2, " qerr=%X", qdio_error);
-               return 1;
+               if ((buf->element[15].flags & 0xff) == 0x12) {
+                       card->stats.rx_dropped++;
+                       return 0;
+               } else
+                       return 1;
        }
        return 0;
 }
@@ -2667,7 +2681,7 @@ static int qeth_handle_send_error(struct qeth_card *card,
                        qdio_err = 1;
                }
        }
-       qeth_check_qdio_errors(buffer->buffer, qdio_err, "qouterr");
+       qeth_check_qdio_errors(card, buffer->buffer, qdio_err, "qouterr");
 
        if (!qdio_err)
                return QETH_SEND_ERROR_NONE;
@@ -3509,6 +3523,7 @@ void qeth_tx_timeout(struct net_device *dev)
 {
        struct qeth_card *card;
 
+       QETH_DBF_TEXT(TRACE, 4, "txtimeo");
        card = dev->ml_priv;
        card->stats.tx_errors++;
        qeth_schedule_recovery(card);
@@ -3847,9 +3862,7 @@ static int qeth_core_driver_group(const char *buf, struct device *root_dev,
 
 int qeth_core_hardsetup_card(struct qeth_card *card)
 {
-       struct qdio_ssqd_desc *ssqd;
        int retries = 0;
-       int mpno = 0;
        int rc;
 
        QETH_DBF_TEXT(SETUP, 2, "hrdsetup");
@@ -3882,31 +3895,6 @@ retriable:
                else
                        goto retry;
        }
-
-       rc = qeth_get_unitaddr(card);
-       if (rc) {
-               QETH_DBF_TEXT_(SETUP, 2, "2err%d", rc);
-               return rc;
-       }
-
-       ssqd = kmalloc(sizeof(struct qdio_ssqd_desc), GFP_KERNEL);
-       if (!ssqd) {
-               rc = -ENOMEM;
-               goto out;
-       }
-       rc = qdio_get_ssqd_desc(CARD_DDEV(card), ssqd);
-       if (rc == 0)
-               mpno = ssqd->pcnt;
-       kfree(ssqd);
-
-       if (mpno)
-               mpno = min(mpno - 1, QETH_MAX_PORTNO);
-       if (card->info.portno > mpno) {
-               QETH_DBF_MESSAGE(2, "Device %s does not offer port number %d"
-                       "\n.", CARD_BUS_ID(card), card->info.portno);
-               rc = -ENODEV;
-               goto out;
-       }
        qeth_init_tokens(card);
        qeth_init_func_level(card);
        rc = qeth_idx_activate_channel(&card->read, qeth_idx_read_cb);
@@ -3990,7 +3978,7 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card,
        struct qdio_buffer_element *element = *__element;
        int offset = *__offset;
        struct sk_buff *skb = NULL;
-       int skb_len;
+       int skb_len = 0;
        void *data_ptr;
        int data_len;
        int headroom = 0;
@@ -4009,20 +3997,24 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card,
        *hdr = element->addr + offset;
 
        offset += sizeof(struct qeth_hdr);
-       if (card->options.layer2) {
-               if (card->info.type == QETH_CARD_TYPE_OSN) {
-                       skb_len = (*hdr)->hdr.osn.pdu_length;
-                       headroom = sizeof(struct qeth_hdr);
-               } else {
-                       skb_len = (*hdr)->hdr.l2.pkt_length;
-               }
-       } else {
+       switch ((*hdr)->hdr.l2.id) {
+       case QETH_HEADER_TYPE_LAYER2:
+               skb_len = (*hdr)->hdr.l2.pkt_length;
+               break;
+       case QETH_HEADER_TYPE_LAYER3:
                skb_len = (*hdr)->hdr.l3.length;
                if ((card->info.link_type == QETH_LINK_TYPE_LANE_TR) ||
                    (card->info.link_type == QETH_LINK_TYPE_HSTR))
                        headroom = TR_HLEN;
                else
                        headroom = ETH_HLEN;
+               break;
+       case QETH_HEADER_TYPE_OSN:
+               skb_len = (*hdr)->hdr.osn.pdu_length;
+               headroom = sizeof(struct qeth_hdr);
+               break;
+       default:
+               break;
        }
 
        if (!skb_len)
@@ -4177,6 +4169,41 @@ void qeth_core_free_discipline(struct qeth_card *card)
        card->discipline.ccwgdriver = NULL;
 }
 
+static void qeth_determine_capabilities(struct qeth_card *card)
+{
+       int rc;
+       int length;
+       char *prcd;
+
+       QETH_DBF_TEXT(SETUP, 2, "detcapab");
+       rc = ccw_device_set_online(CARD_DDEV(card));
+       if (rc) {
+               QETH_DBF_TEXT_(SETUP, 2, "3err%d", rc);
+               goto out;
+       }
+
+
+       rc = qeth_read_conf_data(card, (void **) &prcd, &length);
+       if (rc) {
+               QETH_DBF_MESSAGE(2, "%s qeth_read_conf_data returned %i\n",
+                       dev_name(&card->gdev->dev), rc);
+               QETH_DBF_TEXT_(SETUP, 2, "5err%d", rc);
+               goto out_offline;
+       }
+       qeth_configure_unitaddr(card, prcd);
+       qeth_configure_blkt_default(card, prcd);
+       kfree(prcd);
+
+       rc = qdio_get_ssqd_desc(CARD_DDEV(card), &card->ssqd);
+       if (rc)
+               QETH_DBF_TEXT_(SETUP, 2, "6err%d", rc);
+
+out_offline:
+       ccw_device_set_offline(CARD_DDEV(card));
+out:
+       return;
+}
+
 static int qeth_core_probe_device(struct ccwgroup_device *gdev)
 {
        struct qeth_card *card;
@@ -4242,6 +4269,8 @@ static int qeth_core_probe_device(struct ccwgroup_device *gdev)
        write_lock_irqsave(&qeth_core_card_list.rwlock, flags);
        list_add_tail(&card->list, &qeth_core_card_list.list);
        write_unlock_irqrestore(&qeth_core_card_list.rwlock, flags);
+
+       qeth_determine_capabilities(card);
        return 0;
 
 err_card:
index 1ba51152f667889d54b7a6f37fc157a76cf01a82..104a3351e02b163519dfc34f2e885a681cc446fa 100644 (file)
@@ -156,6 +156,8 @@ enum qeth_ipa_return_codes {
        IPA_RC_IP_TABLE_FULL            = 0x0002,
        IPA_RC_UNKNOWN_ERROR            = 0x0003,
        IPA_RC_UNSUPPORTED_COMMAND      = 0x0004,
+       IPA_RC_TRACE_ALREADY_ACTIVE     = 0x0005,
+       IPA_RC_INVALID_FORMAT           = 0x0006,
        IPA_RC_DUP_IPV6_REMOTE          = 0x0008,
        IPA_RC_DUP_IPV6_HOME            = 0x0010,
        IPA_RC_UNREGISTERED_ADDR        = 0x0011,
@@ -196,6 +198,11 @@ enum qeth_ipa_return_codes {
        IPA_RC_INVALID_IP_VERSION2      = 0xf001,
        IPA_RC_FFFF                     = 0xffff
 };
+/* for DELIP */
+#define IPA_RC_IP_ADDRESS_NOT_DEFINED  IPA_RC_PRIMARY_ALREADY_DEFINED
+/* for SET_DIAGNOSTIC_ASSIST */
+#define IPA_RC_INVALID_SUBCMD          IPA_RC_IP_TABLE_FULL
+#define IPA_RC_HARDWARE_AUTH_ERROR     IPA_RC_UNKNOWN_ERROR
 
 /* IPA function flags; each flag marks availability of respective function */
 enum qeth_ipa_funcs {
@@ -246,6 +253,7 @@ enum qeth_ipa_setadp_cmd {
        IPA_SETADP_SET_SNMP_CONTROL             = 0x00000200L,
        IPA_SETADP_QUERY_CARD_INFO              = 0x00000400L,
        IPA_SETADP_SET_PROMISC_MODE             = 0x00000800L,
+       IPA_SETADP_SET_DIAG_ASSIST              = 0x00002000L,
        IPA_SETADP_SET_ACCESS_CONTROL           = 0x00010000L,
 };
 enum qeth_ipa_mac_ops {
@@ -424,6 +432,40 @@ struct qeth_create_destroy_address {
        __u8 unique_id[8];
 } __attribute__ ((packed));
 
+/* SET DIAGNOSTIC ASSIST IPA Command:   *************************************/
+
+enum qeth_diags_cmds {
+       QETH_DIAGS_CMD_QUERY    = 0x0001,
+       QETH_DIAGS_CMD_TRAP     = 0x0002,
+       QETH_DIAGS_CMD_TRACE    = 0x0004,
+       QETH_DIAGS_CMD_NOLOG    = 0x0008,
+       QETH_DIAGS_CMD_DUMP     = 0x0010,
+};
+
+enum qeth_diags_trace_types {
+       QETH_DIAGS_TYPE_HIPERSOCKET     = 0x02,
+};
+
+enum qeth_diags_trace_cmds {
+       QETH_DIAGS_CMD_TRACE_ENABLE     = 0x0001,
+       QETH_DIAGS_CMD_TRACE_DISABLE    = 0x0002,
+       QETH_DIAGS_CMD_TRACE_MODIFY     = 0x0004,
+       QETH_DIAGS_CMD_TRACE_REPLACE    = 0x0008,
+       QETH_DIAGS_CMD_TRACE_QUERY      = 0x0010,
+};
+
+struct qeth_ipacmd_diagass {
+       __u32  host_tod2;
+       __u32:32;
+       __u16  subcmd_len;
+       __u16:16;
+       __u32  subcmd;
+       __u8   type;
+       __u8   action;
+       __u16  options;
+       __u32:32;
+} __attribute__ ((packed));
+
 /* Header for each IPA command */
 struct qeth_ipacmd_hdr {
        __u8   command;
@@ -452,6 +494,7 @@ struct qeth_ipa_cmd {
                struct qeth_create_destroy_address      create_destroy_addr;
                struct qeth_ipacmd_setadpparms          setadapterparms;
                struct qeth_set_routing                 setrtg;
+               struct qeth_ipacmd_diagass              diagass;
        } data;
 } __attribute__ ((packed));
 
@@ -469,7 +512,6 @@ enum qeth_ipa_arp_return_codes {
        QETH_IPA_ARP_RC_Q_NO_DATA    = 0x0008,
 };
 
-
 extern char *qeth_get_ipa_msg(enum qeth_ipa_return_codes rc);
 extern char *qeth_get_ipa_cmd_name(enum qeth_ipa_cmds cmd);
 
index 9ff2b36fdc435cfa111882fb2eaac9a20f389587..88ae4357136a01e0f2fa8c1f04b604af069158a5 100644 (file)
@@ -118,7 +118,7 @@ static ssize_t qeth_dev_portno_store(struct device *dev,
 {
        struct qeth_card *card = dev_get_drvdata(dev);
        char *tmp;
-       unsigned int portno;
+       unsigned int portno, limit;
 
        if (!card)
                return -EINVAL;
@@ -128,9 +128,11 @@ static ssize_t qeth_dev_portno_store(struct device *dev,
                return -EPERM;
 
        portno = simple_strtoul(buf, &tmp, 16);
-       if (portno > QETH_MAX_PORTNO) {
+       if (portno > QETH_MAX_PORTNO)
+               return -EINVAL;
+       limit = (card->ssqd.pcnt ? card->ssqd.pcnt - 1 : card->ssqd.pcnt);
+       if (portno > limit)
                return -EINVAL;
-       }
 
        card->info.portno = portno;
        return count;
@@ -537,7 +539,7 @@ static ssize_t qeth_dev_blkt_total_store(struct device *dev,
        struct qeth_card *card = dev_get_drvdata(dev);
 
        return qeth_dev_blkt_store(card, buf, count,
-                                  &card->info.blkt.time_total, 1000);
+                                  &card->info.blkt.time_total, 5000);
 }
 
 
@@ -559,7 +561,7 @@ static ssize_t qeth_dev_blkt_inter_store(struct device *dev,
        struct qeth_card *card = dev_get_drvdata(dev);
 
        return qeth_dev_blkt_store(card, buf, count,
-                                  &card->info.blkt.inter_packet, 100);
+                                  &card->info.blkt.inter_packet, 1000);
 }
 
 static DEVICE_ATTR(inter, 0644, qeth_dev_blkt_inter_show,
@@ -580,7 +582,7 @@ static ssize_t qeth_dev_blkt_inter_jumbo_store(struct device *dev,
        struct qeth_card *card = dev_get_drvdata(dev);
 
        return qeth_dev_blkt_store(card, buf, count,
-                                  &card->info.blkt.inter_packet_jumbo, 100);
+                                  &card->info.blkt.inter_packet_jumbo, 1000);
 }
 
 static DEVICE_ATTR(inter_jumbo, 0644, qeth_dev_blkt_inter_jumbo_show,
index 0b763396d5d10962d53ac49b94051f5e7d2dd828..51fde6f2e0b8ab11affa238fd5adbfe815923ec8 100644 (file)
@@ -486,22 +486,14 @@ static int qeth_l2_send_setmac_cb(struct qeth_card *card,
                case IPA_RC_L2_DUP_MAC:
                case IPA_RC_L2_DUP_LAYER3_MAC:
                        dev_warn(&card->gdev->dev,
-                               "MAC address "
-                               "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x "
-                               "already exists\n",
-                               card->dev->dev_addr[0], card->dev->dev_addr[1],
-                               card->dev->dev_addr[2], card->dev->dev_addr[3],
-                               card->dev->dev_addr[4], card->dev->dev_addr[5]);
+                               "MAC address %pM already exists\n",
+                               card->dev->dev_addr);
                        break;
                case IPA_RC_L2_MAC_NOT_AUTH_BY_HYP:
                case IPA_RC_L2_MAC_NOT_AUTH_BY_ADP:
                        dev_warn(&card->gdev->dev,
-                               "MAC address "
-                               "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x "
-                               "is not authorized\n",
-                               card->dev->dev_addr[0], card->dev->dev_addr[1],
-                               card->dev->dev_addr[2], card->dev->dev_addr[3],
-                               card->dev->dev_addr[4], card->dev->dev_addr[5]);
+                               "MAC address %pM is not authorized\n",
+                               card->dev->dev_addr);
                        break;
                default:
                        break;
@@ -512,12 +504,8 @@ static int qeth_l2_send_setmac_cb(struct qeth_card *card,
                memcpy(card->dev->dev_addr, cmd->data.setdelmac.mac,
                       OSA_ADDR_LEN);
                dev_info(&card->gdev->dev,
-                       "MAC address %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x "
-                       "successfully registered on device %s\n",
-                       card->dev->dev_addr[0], card->dev->dev_addr[1],
-                       card->dev->dev_addr[2], card->dev->dev_addr[3],
-                       card->dev->dev_addr[4], card->dev->dev_addr[5],
-                       card->dev->name);
+                       "MAC address %pM successfully registered on device %s\n",
+                       card->dev->dev_addr, card->dev->name);
        }
        return 0;
 }
@@ -634,7 +622,7 @@ static void qeth_l2_set_multicast_list(struct net_device *dev)
        for (dm = dev->mc_list; dm; dm = dm->next)
                qeth_l2_add_mc(card, dm->da_addr, 0);
 
-       list_for_each_entry(ha, &dev->uc.list, list)
+       netdev_for_each_uc_addr(ha, dev)
                qeth_l2_add_mc(card, ha->addr, 1);
 
        spin_unlock_bh(&card->mclock);
@@ -781,7 +769,8 @@ static void qeth_l2_qdio_input_handler(struct ccw_device *ccwdev,
                index = i % QDIO_MAX_BUFFERS_PER_Q;
                buffer = &card->qdio.in_q->bufs[index];
                if (!(qdio_err &&
-                     qeth_check_qdio_errors(buffer->buffer, qdio_err, "qinerr")))
+                     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);
@@ -938,7 +927,6 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode)
        QETH_DBF_TEXT(SETUP, 2, "setonlin");
        QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *));
 
-       qeth_set_allowed_threads(card, QETH_RECOVER_THREAD, 1);
        recover_flag = card->state;
        rc = qeth_core_hardsetup_card(card);
        if (rc) {
index 321988fa9f7d514cadb0a3be82d7a09227a58b13..8447d233d0b33e97ef9e82511cecd1e08119a02f 100644 (file)
@@ -13,6 +13,8 @@
 
 #include "qeth_core.h"
 
+#define QETH_SNIFF_AVAIL       0x0008
+
 struct qeth_ipaddr {
        struct list_head entry;
        enum qeth_ip_types type;
index fd1b6ed3721f312800b2ec70c2ab6d6ebdcef38e..5475834ab916ba6dd08868bf3506877c17b55bee 100644 (file)
@@ -242,6 +242,8 @@ static int __qeth_l3_insert_ip_todo(struct qeth_card *card,
        struct qeth_ipaddr *tmp, *t;
        int found = 0;
 
+       if (card->options.sniffer)
+               return 0;
        list_for_each_entry_safe(tmp, t, card->ip_tbd_list, entry) {
                if ((addr->type == QETH_IP_TYPE_DEL_ALL_MC) &&
                    (tmp->type == QETH_IP_TYPE_DEL_ALL_MC))
@@ -457,6 +459,8 @@ static void qeth_l3_set_ip_addr_list(struct qeth_card *card)
        QETH_DBF_TEXT(TRACE, 2, "sdiplist");
        QETH_DBF_HEX(TRACE, 2, &card, sizeof(void *));
 
+       if (card->options.sniffer)
+               return;
        spin_lock_irqsave(&card->ip_lock, flags);
        tbd_list = card->ip_tbd_list;
        card->ip_tbd_list = kmalloc(sizeof(struct list_head), GFP_ATOMIC);
@@ -495,7 +499,7 @@ static void qeth_l3_set_ip_addr_list(struct qeth_card *card)
                        spin_unlock_irqrestore(&card->ip_lock, flags);
                        rc = qeth_l3_deregister_addr_entry(card, addr);
                        spin_lock_irqsave(&card->ip_lock, flags);
-                       if (!rc || (rc == IPA_RC_PRIMARY_ALREADY_DEFINED))
+                       if (!rc || (rc == IPA_RC_IP_ADDRESS_NOT_DEFINED))
                                kfree(addr);
                        else
                                list_add_tail(&addr->entry, &card->ip_list);
@@ -513,6 +517,8 @@ static void qeth_l3_clear_ip_list(struct qeth_card *card, int clean,
        unsigned long flags;
 
        QETH_DBF_TEXT(TRACE, 4, "clearip");
+       if (recover && card->options.sniffer)
+               return;
        spin_lock_irqsave(&card->ip_lock, flags);
        /* clear todo list */
        list_for_each_entry_safe(addr, tmp, card->ip_tbd_list, entry) {
@@ -1674,6 +1680,76 @@ static int qeth_l3_get_unique_id(struct qeth_card *card)
        return rc;
 }
 
+static int
+qeth_diags_trace_cb(struct qeth_card *card, struct qeth_reply *reply,
+                           unsigned long data)
+{
+       struct qeth_ipa_cmd        *cmd;
+       __u16 rc;
+
+       QETH_DBF_TEXT(SETUP, 2, "diastrcb");
+
+       cmd = (struct qeth_ipa_cmd *)data;
+       rc = cmd->hdr.return_code;
+       if (rc) {
+               QETH_DBF_TEXT_(TRACE, 2, "dxter%x", rc);
+               if (cmd->data.diagass.action == QETH_DIAGS_CMD_TRACE_ENABLE) {
+                       switch (rc) {
+                       case IPA_RC_HARDWARE_AUTH_ERROR:
+                               dev_warn(&card->gdev->dev, "The device is not "
+                                       "authorized to run as a HiperSockets "
+                                       "network traffic analyzer\n");
+                               break;
+                       case IPA_RC_TRACE_ALREADY_ACTIVE:
+                               dev_warn(&card->gdev->dev, "A HiperSockets "
+                                       "network traffic analyzer is already "
+                                       "active in the HiperSockets LAN\n");
+                               break;
+                       default:
+                               break;
+                       }
+               }
+               return 0;
+       }
+
+       switch (cmd->data.diagass.action) {
+       case QETH_DIAGS_CMD_TRACE_QUERY:
+               break;
+       case QETH_DIAGS_CMD_TRACE_DISABLE:
+               card->info.promisc_mode = SET_PROMISC_MODE_OFF;
+               dev_info(&card->gdev->dev, "The HiperSockets network traffic "
+                       "analyzer is deactivated\n");
+               break;
+       case QETH_DIAGS_CMD_TRACE_ENABLE:
+               card->info.promisc_mode = SET_PROMISC_MODE_ON;
+               dev_info(&card->gdev->dev, "The HiperSockets network traffic "
+                       "analyzer is activated\n");
+               break;
+       default:
+               QETH_DBF_MESSAGE(2, "Unknown sniffer action (0x%04x) on %s\n",
+                       cmd->data.diagass.action, QETH_CARD_IFNAME(card));
+       }
+
+       return 0;
+}
+
+static int
+qeth_diags_trace(struct qeth_card *card, enum qeth_diags_trace_cmds diags_cmd)
+{
+       struct qeth_cmd_buffer *iob;
+       struct qeth_ipa_cmd    *cmd;
+
+       QETH_DBF_TEXT(SETUP, 2, "diagtrac");
+
+       iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SET_DIAG_ASS, 0);
+       cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
+       cmd->data.diagass.subcmd_len = 16;
+       cmd->data.diagass.subcmd = QETH_DIAGS_CMD_TRACE;
+       cmd->data.diagass.type = QETH_DIAGS_TYPE_HIPERSOCKET;
+       cmd->data.diagass.action = diags_cmd;
+       return qeth_send_ipa_cmd(card, iob, qeth_diags_trace_cb, NULL);
+}
+
 static void qeth_l3_get_mac_for_ipm(__u32 ipm, char *mac,
                                struct net_device *dev)
 {
@@ -1951,7 +2027,10 @@ static inline __u16 qeth_l3_rebuild_skb(struct qeth_card *card,
                case QETH_CAST_ANYCAST:
                case QETH_CAST_NOCAST:
                default:
-                       skb->pkt_type = PACKET_HOST;
+                       if (card->options.sniffer)
+                               skb->pkt_type = PACKET_OTHERHOST;
+                       else
+                               skb->pkt_type = PACKET_HOST;
                        memcpy(tg_addr, card->dev->dev_addr,
                                card->dev->addr_len);
                }
@@ -2007,7 +2086,6 @@ static void qeth_l3_process_inbound_buffer(struct qeth_card *card,
        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;
@@ -2026,7 +2104,7 @@ static void qeth_l3_process_inbound_buffer(struct qeth_card *card,
                case QETH_HEADER_TYPE_LAYER3:
                        vlan_tag = qeth_l3_rebuild_skb(card, skb, hdr);
                        len = skb->len;
-                       if (vlan_tag)
+                       if (vlan_tag && !card->options.sniffer)
                                if (card->vlangrp)
                                        vlan_hwaccel_rx(skb, card->vlangrp,
                                                vlan_tag);
@@ -2037,6 +2115,16 @@ static void qeth_l3_process_inbound_buffer(struct qeth_card *card,
                        else
                                netif_rx(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;
                default:
                        dev_kfree_skb_any(skb);
                        QETH_DBF_TEXT(TRACE, 3, "inbunkno");
@@ -2118,6 +2206,9 @@ static int qeth_l3_stop_card(struct qeth_card *card, int recovery_mode)
        QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *));
 
        qeth_set_allowed_threads(card, 0, 1);
+       if (card->options.sniffer &&
+           (card->info.promisc_mode == SET_PROMISC_MODE_ON))
+               qeth_diags_trace(card, QETH_DIAGS_CMD_TRACE_DISABLE);
        if (card->read.state == CH_STATE_UP &&
            card->write.state == CH_STATE_UP &&
            (card->state == CARD_STATE_UP)) {
@@ -2162,6 +2253,36 @@ static int qeth_l3_stop_card(struct qeth_card *card, int recovery_mode)
        return rc;
 }
 
+/*
+ * test for and Switch promiscuous mode (on or off)
+ *  either for guestlan or HiperSocket Sniffer
+ */
+static void
+qeth_l3_handle_promisc_mode(struct qeth_card *card)
+{
+       struct net_device *dev = card->dev;
+
+       if (((dev->flags & IFF_PROMISC) &&
+            (card->info.promisc_mode == SET_PROMISC_MODE_ON)) ||
+           (!(dev->flags & IFF_PROMISC) &&
+            (card->info.promisc_mode == SET_PROMISC_MODE_OFF)))
+               return;
+
+       if (card->info.guestlan) {              /* Guestlan trace */
+               if (qeth_adp_supported(card, IPA_SETADP_SET_PROMISC_MODE))
+                       qeth_setadp_promisc_mode(card);
+       } else if (card->options.sniffer &&     /* HiperSockets trace */
+                  qeth_adp_supported(card, IPA_SETADP_SET_DIAG_ASSIST)) {
+               if (dev->flags & IFF_PROMISC) {
+                       QETH_DBF_TEXT(TRACE, 3, "+promisc");
+                       qeth_diags_trace(card, QETH_DIAGS_CMD_TRACE_ENABLE);
+               } else {
+                       QETH_DBF_TEXT(TRACE, 3, "-promisc");
+                       qeth_diags_trace(card, QETH_DIAGS_CMD_TRACE_DISABLE);
+               }
+       }
+}
+
 static void qeth_l3_set_multicast_list(struct net_device *dev)
 {
        struct qeth_card *card = dev->ml_priv;
@@ -2170,15 +2291,17 @@ static void qeth_l3_set_multicast_list(struct net_device *dev)
        if (qeth_threads_running(card, QETH_RECOVER_THREAD) &&
            (card->state != CARD_STATE_UP))
                return;
-       qeth_l3_delete_mc_addresses(card);
-       qeth_l3_add_multicast_ipv4(card);
+       if (!card->options.sniffer) {
+               qeth_l3_delete_mc_addresses(card);
+               qeth_l3_add_multicast_ipv4(card);
 #ifdef CONFIG_QETH_IPV6
-       qeth_l3_add_multicast_ipv6(card);
+               qeth_l3_add_multicast_ipv6(card);
 #endif
-       qeth_l3_set_ip_addr_list(card);
-       if (!qeth_adp_supported(card, IPA_SETADP_SET_PROMISC_MODE))
-               return;
-       qeth_setadp_promisc_mode(card);
+               qeth_l3_set_ip_addr_list(card);
+               if (!qeth_adp_supported(card, IPA_SETADP_SET_PROMISC_MODE))
+                       return;
+       }
+       qeth_l3_handle_promisc_mode(card);
 }
 
 static const char *qeth_l3_arp_get_error_cause(int *rc)
@@ -2778,8 +2901,9 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
        int nr_frags;
 
        if ((card->info.type == QETH_CARD_TYPE_IQD) &&
-           (skb->protocol != htons(ETH_P_IPV6)) &&
-           (skb->protocol != htons(ETH_P_IP)))
+           (((skb->protocol != htons(ETH_P_IPV6)) &&
+             (skb->protocol != htons(ETH_P_IP))) ||
+            card->options.sniffer))
                        goto tx_drop;
 
        if ((card->state != CARD_STATE_UP) || !card->lan_online) {
@@ -3155,7 +3279,7 @@ static void qeth_l3_qdio_input_handler(struct ccw_device *ccwdev,
                index = i % QDIO_MAX_BUFFERS_PER_Q;
                buffer = &card->qdio.in_q->bufs[index];
                if (!(qdio_err &&
-                     qeth_check_qdio_errors(buffer->buffer,
+                     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 */
@@ -3214,8 +3338,6 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode)
        QETH_DBF_TEXT(SETUP, 2, "setonlin");
        QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *));
 
-       qeth_set_allowed_threads(card, QETH_RECOVER_THREAD, 1);
-
        recover_flag = card->state;
        rc = qeth_core_hardsetup_card(card);
        if (rc) {
@@ -3250,20 +3372,22 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode)
                goto out_remove;
        } else
                card->lan_online = 1;
-       qeth_l3_set_large_send(card, card->options.large_send);
 
        rc = qeth_l3_setadapter_parms(card);
        if (rc)
                QETH_DBF_TEXT_(SETUP, 2, "2err%d", rc);
-       rc = qeth_l3_start_ipassists(card);
-       if (rc)
-               QETH_DBF_TEXT_(SETUP, 2, "3err%d", rc);
-       rc = qeth_l3_setrouting_v4(card);
-       if (rc)
-               QETH_DBF_TEXT_(SETUP, 2, "4err%d", rc);
-       rc = qeth_l3_setrouting_v6(card);
-       if (rc)
-               QETH_DBF_TEXT_(SETUP, 2, "5err%d", rc);
+       if (!card->options.sniffer) {
+               rc = qeth_l3_start_ipassists(card);
+               if (rc)
+                       QETH_DBF_TEXT_(SETUP, 2, "3err%d", rc);
+               qeth_l3_set_large_send(card, card->options.large_send);
+               rc = qeth_l3_setrouting_v4(card);
+               if (rc)
+                       QETH_DBF_TEXT_(SETUP, 2, "4err%d", rc);
+               rc = qeth_l3_setrouting_v6(card);
+               if (rc)
+                       QETH_DBF_TEXT_(SETUP, 2, "5err%d", rc);
+       }
        netif_tx_disable(card->dev);
 
        rc = qeth_init_qdio_queues(card);
index 3360b0941aa1b411dde221e4e1dc2f8f19f4a6de..3f08b11274aeede53cffa6822738ebd4f5ed1396 100644 (file)
@@ -319,6 +319,61 @@ static ssize_t qeth_l3_dev_checksum_store(struct device *dev,
 static DEVICE_ATTR(checksumming, 0644, qeth_l3_dev_checksum_show,
                qeth_l3_dev_checksum_store);
 
+static ssize_t qeth_l3_dev_sniffer_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct qeth_card *card = dev_get_drvdata(dev);
+
+       if (!card)
+               return -EINVAL;
+
+       return sprintf(buf, "%i\n", card->options.sniffer ? 1 : 0);
+}
+
+static ssize_t qeth_l3_dev_sniffer_store(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct qeth_card *card = dev_get_drvdata(dev);
+       int ret;
+       unsigned long i;
+
+       if (!card)
+               return -EINVAL;
+
+       if (card->info.type != QETH_CARD_TYPE_IQD)
+               return -EPERM;
+
+       if ((card->state != CARD_STATE_DOWN) &&
+           (card->state != CARD_STATE_RECOVER))
+               return -EPERM;
+
+       ret = strict_strtoul(buf, 16, &i);
+       if (ret)
+               return -EINVAL;
+       switch (i) {
+       case 0:
+               card->options.sniffer = i;
+               break;
+       case 1:
+               ret = qdio_get_ssqd_desc(CARD_DDEV(card), &card->ssqd);
+               if (card->ssqd.qdioac2 & QETH_SNIFF_AVAIL) {
+                       card->options.sniffer = i;
+                       if (card->qdio.init_pool.buf_count !=
+                                       QETH_IN_BUF_COUNT_MAX)
+                               qeth_realloc_buffer_pool(card,
+                                       QETH_IN_BUF_COUNT_MAX);
+                       break;
+               } else
+                       return -EPERM;
+       default:   /* fall through */
+               return -EINVAL;
+       }
+       return count;
+}
+
+static DEVICE_ATTR(sniffer, 0644, qeth_l3_dev_sniffer_show,
+               qeth_l3_dev_sniffer_store);
+
 static ssize_t qeth_l3_dev_large_send_show(struct device *dev,
                                struct device_attribute *attr, char *buf)
 {
@@ -373,6 +428,7 @@ static struct attribute *qeth_l3_device_attrs[] = {
        &dev_attr_broadcast_mode.attr,
        &dev_attr_canonical_macaddr.attr,
        &dev_attr_checksumming.attr,
+       &dev_attr_sniffer.attr,
        &dev_attr_large_send.attr,
        NULL,
 };
index 0d490c164db6c8a94527ebc01ddde62b9a0ee229..9086047c32d4b3c8181c67f658d1712b160bb68f 100644 (file)
@@ -482,15 +482,6 @@ struct ieee80211_header_data {
        u16 seq_ctrl;
 };
 
-struct ieee80211_hdr_3addr {
-       u16 frame_ctl;
-       u16 duration_id;
-       u8 addr1[ETH_ALEN];
-       u8 addr2[ETH_ALEN];
-       u8 addr3[ETH_ALEN];
-       u16 seq_ctl;
-} __attribute__ ((packed));
-
 struct ieee80211_hdr_4addr {
        u16 frame_ctl;
        u16 duration_id;
index c7c645af0ebb2a8627187394a6219cd979708cdd..a2150670ef56c5c196d42294ea2734c3cb043c4a 100644 (file)
@@ -203,7 +203,7 @@ inline void softmac_mgmt_xmit(struct sk_buff *skb, struct ieee80211_device *ieee
 
                        enqueue_mgmt(ieee,skb);
                }else{
-                       header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0]<<4);
+                       header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0]<<4);
 
                        if (ieee->seq_ctrl[0] == 0xFFF)
                                ieee->seq_ctrl[0] = 0;
@@ -220,7 +220,7 @@ inline void softmac_mgmt_xmit(struct sk_buff *skb, struct ieee80211_device *ieee
                spin_unlock_irqrestore(&ieee->lock, flags);
                spin_lock_irqsave(&ieee->mgmt_tx_lock, flags);
 
-               header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4);
+               header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0] << 4);
 
                if (ieee->seq_ctrl[0] == 0xFFF)
                        ieee->seq_ctrl[0] = 0;
@@ -246,7 +246,7 @@ inline void softmac_ps_mgmt_xmit(struct sk_buff *skb, struct ieee80211_device *i
 
        if(single){
 
-               header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4);
+               header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0] << 4);
 
                if (ieee->seq_ctrl[0] == 0xFFF)
                        ieee->seq_ctrl[0] = 0;
@@ -259,7 +259,7 @@ inline void softmac_ps_mgmt_xmit(struct sk_buff *skb, struct ieee80211_device *i
 
        }else{
 
-               header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4);
+               header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0] << 4);
 
                if (ieee->seq_ctrl[0] == 0xFFF)
                        ieee->seq_ctrl[0] = 0;
@@ -287,7 +287,7 @@ inline struct sk_buff *ieee80211_disassociate_skb(
                return NULL;
 
        disass = (struct ieee80211_disassoc_frame *) skb_put(skb,sizeof(struct ieee80211_disassoc_frame));
-       disass->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_DISASSOC);
+       disass->header.frame_control = cpu_to_le16(IEEE80211_STYPE_DISASSOC);
        disass->header.duration_id = 0;
 
        memcpy(disass->header.addr1, beacon->bssid, ETH_ALEN);
@@ -905,7 +905,7 @@ struct sk_buff* ieee80211_assoc_resp(struct ieee80211_device *ieee, u8 *dest)
        assoc = (struct ieee80211_assoc_response_frame *)
                skb_put(skb,sizeof(struct ieee80211_assoc_response_frame));
 
-       assoc->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP);
+       assoc->header.frame_control = cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP);
        memcpy(assoc->header.addr1, dest,ETH_ALEN);
        memcpy(assoc->header.addr3, ieee->dev->dev_addr, ETH_ALEN);
        memcpy(assoc->header.addr2, ieee->dev->dev_addr, ETH_ALEN);
@@ -981,7 +981,7 @@ struct sk_buff* ieee80211_null_func(struct ieee80211_device *ieee,short pwr)
        memcpy(hdr->addr2, ieee->dev->dev_addr, ETH_ALEN);
        memcpy(hdr->addr3, ieee->current_network.bssid, ETH_ALEN);
 
-       hdr->frame_ctl = cpu_to_le16(IEEE80211_FTYPE_DATA |
+       hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
                IEEE80211_STYPE_NULLFUNC | IEEE80211_FCTL_TODS |
                (pwr ? IEEE80211_FCTL_PM:0));
 
@@ -1084,7 +1084,7 @@ inline struct sk_buff *ieee80211_association_req(struct ieee80211_network *beaco
                skb_put(skb, sizeof(struct ieee80211_assoc_request_frame));
 
 
-       hdr->header.frame_ctl = IEEE80211_STYPE_ASSOC_REQ;
+       hdr->header.frame_control = IEEE80211_STYPE_ASSOC_REQ;
        hdr->header.duration_id= 37; //FIXME
        memcpy(hdr->header.addr1, beacon->bssid, ETH_ALEN);
        memcpy(hdr->header.addr2, ieee->dev->dev_addr, ETH_ALEN);
@@ -1786,11 +1786,11 @@ ieee80211_rx_frame_softmac(struct ieee80211_device *ieee, struct sk_buff *skb,
 
                tasklet_schedule(&ieee->ps_task);
 
-       if(WLAN_FC_GET_STYPE(header->frame_ctl) != IEEE80211_STYPE_PROBE_RESP &&
-               WLAN_FC_GET_STYPE(header->frame_ctl) != IEEE80211_STYPE_BEACON)
+       if (WLAN_FC_GET_STYPE(header->frame_control) != IEEE80211_STYPE_PROBE_RESP &&
+               WLAN_FC_GET_STYPE(header->frame_control) != IEEE80211_STYPE_BEACON)
                ieee->last_rx_ps_time = jiffies;
 
-       switch (WLAN_FC_GET_STYPE(header->frame_ctl)) {
+       switch (WLAN_FC_GET_STYPE(header->frame_control)) {
 
                case IEEE80211_STYPE_ASSOC_RESP:
                case IEEE80211_STYPE_REASSOC_RESP:
@@ -2064,7 +2064,7 @@ void ieee80211_rtl_wake_queue(struct ieee80211_device *ieee)
 
                        header = (struct ieee80211_hdr_3addr  *) skb->data;
 
-                       header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4);
+                       header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0] << 4);
 
                        if (ieee->seq_ctrl[0] == 0xFFF)
                                ieee->seq_ctrl[0] = 0;
index e0f13efdb15a16f15a3d89653cf579b76bfc6e84..1847f38b9f2282e8a00e44c691356566f6cde851 100644 (file)
@@ -1890,7 +1890,7 @@ rate)
        struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
        int mode;
        struct ieee80211_hdr_3addr  *h = (struct ieee80211_hdr_3addr  *) skb->data;
-       short morefrag = (h->frame_ctl) & IEEE80211_FCTL_MOREFRAGS;
+       short morefrag = (h->frame_control) & IEEE80211_FCTL_MOREFRAGS;
        unsigned long flags;
        int priority;
 
@@ -2158,7 +2158,7 @@ short rtl8180_tx(struct net_device *dev, u8* txbuf, int len, int priority,
                                TxDescDuration = ThisFrameTime + aSifsTime + AckTime;
                        }
 
-                       if(!(frag_hdr->frame_ctl & IEEE80211_FCTL_MOREFRAGS)) { //no more fragment
+                       if (!(frag_hdr->frame_control & IEEE80211_FCTL_MOREFRAGS)) {
                                // ThisFrame-ACK.
                                Duration = aSifsTime + AckTime;
                        } else { // One or more fragments remained.
index ac38902479657c2c56d8921ae646d3ef2b5e7c4a..0d22e3692fe56cd1114fb9fe80e28e0e09767043 100644 (file)
@@ -1194,9 +1194,7 @@ static const struct net_device_ops wl_netdev_ops =
     .ndo_stop               = &wl_adapter_close,
     .ndo_do_ioctl           = &wl_ioctl,
 
-#ifdef HAVE_TX_TIMEOUT
     .ndo_tx_timeout         = &wl_tx_timeout,
-#endif
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
     .ndo_poll_controller    = wl_poll,
@@ -1270,9 +1268,7 @@ struct net_device * wl_device_alloc( void )
     dev->stop               = &wl_adapter_close;
     dev->do_ioctl           = &wl_ioctl;
 
-#ifdef HAVE_TX_TIMEOUT
     dev->tx_timeout         = &wl_tx_timeout;
-#endif
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
     dev->poll_controller = wl_poll;
@@ -1280,9 +1276,7 @@ struct net_device * wl_device_alloc( void )
 
 #endif // (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,30))
 
-#ifdef HAVE_TX_TIMEOUT
     dev->watchdog_timeo     = TX_TIMEOUT;
-#endif
 
     dev->ethtool_ops       = &wl_ethtool_ops;
 
diff --git a/drivers/vhost/Kconfig b/drivers/vhost/Kconfig
new file mode 100644 (file)
index 0000000..9e93553
--- /dev/null
@@ -0,0 +1,11 @@
+config VHOST_NET
+       tristate "Host kernel accelerator for virtio net (EXPERIMENTAL)"
+       depends on NET && EVENTFD && (TUN || !TUN) && EXPERIMENTAL
+       ---help---
+         This kernel module can be loaded in host kernel to accelerate
+         guest networking with virtio_net. Not to be confused with virtio_net
+         module itself which needs to be loaded in guest kernel.
+
+         To compile this driver as a module, choose M here: the module will
+         be called vhost_net.
+
diff --git a/drivers/vhost/Makefile b/drivers/vhost/Makefile
new file mode 100644 (file)
index 0000000..72dd020
--- /dev/null
@@ -0,0 +1,2 @@
+obj-$(CONFIG_VHOST_NET) += vhost_net.o
+vhost_net-y := vhost.o net.o
diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
new file mode 100644 (file)
index 0000000..4c89283
--- /dev/null
@@ -0,0 +1,661 @@
+/* Copyright (C) 2009 Red Hat, Inc.
+ * Author: Michael S. Tsirkin <mst@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.
+ *
+ * virtio-net server in host kernel.
+ */
+
+#include <linux/compat.h>
+#include <linux/eventfd.h>
+#include <linux/vhost.h>
+#include <linux/virtio_net.h>
+#include <linux/mmu_context.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+#include <linux/rcupdate.h>
+#include <linux/file.h>
+
+#include <linux/net.h>
+#include <linux/if_packet.h>
+#include <linux/if_arp.h>
+#include <linux/if_tun.h>
+
+#include <net/sock.h>
+
+#include "vhost.h"
+
+/* Max number of bytes transferred before requeueing the job.
+ * Using this limit prevents one virtqueue from starving others. */
+#define VHOST_NET_WEIGHT 0x80000
+
+enum {
+       VHOST_NET_VQ_RX = 0,
+       VHOST_NET_VQ_TX = 1,
+       VHOST_NET_VQ_MAX = 2,
+};
+
+enum vhost_net_poll_state {
+       VHOST_NET_POLL_DISABLED = 0,
+       VHOST_NET_POLL_STARTED = 1,
+       VHOST_NET_POLL_STOPPED = 2,
+};
+
+struct vhost_net {
+       struct vhost_dev dev;
+       struct vhost_virtqueue vqs[VHOST_NET_VQ_MAX];
+       struct vhost_poll poll[VHOST_NET_VQ_MAX];
+       /* Tells us whether we are polling a socket for TX.
+        * We only do this when socket buffer fills up.
+        * Protected by tx vq lock. */
+       enum vhost_net_poll_state tx_poll_state;
+};
+
+/* Pop first len bytes from iovec. Return number of segments used. */
+static int move_iovec_hdr(struct iovec *from, struct iovec *to,
+                         size_t len, int iov_count)
+{
+       int seg = 0;
+       size_t size;
+       while (len && seg < iov_count) {
+               size = min(from->iov_len, len);
+               to->iov_base = from->iov_base;
+               to->iov_len = size;
+               from->iov_len -= size;
+               from->iov_base += size;
+               len -= size;
+               ++from;
+               ++to;
+               ++seg;
+       }
+       return seg;
+}
+
+/* Caller must have TX VQ lock */
+static void tx_poll_stop(struct vhost_net *net)
+{
+       if (likely(net->tx_poll_state != VHOST_NET_POLL_STARTED))
+               return;
+       vhost_poll_stop(net->poll + VHOST_NET_VQ_TX);
+       net->tx_poll_state = VHOST_NET_POLL_STOPPED;
+}
+
+/* Caller must have TX VQ lock */
+static void tx_poll_start(struct vhost_net *net, struct socket *sock)
+{
+       if (unlikely(net->tx_poll_state != VHOST_NET_POLL_STOPPED))
+               return;
+       vhost_poll_start(net->poll + VHOST_NET_VQ_TX, sock->file);
+       net->tx_poll_state = VHOST_NET_POLL_STARTED;
+}
+
+/* Expects to be always run from workqueue - which acts as
+ * read-size critical section for our kind of RCU. */
+static void handle_tx(struct vhost_net *net)
+{
+       struct vhost_virtqueue *vq = &net->dev.vqs[VHOST_NET_VQ_TX];
+       unsigned head, out, in, s;
+       struct msghdr msg = {
+               .msg_name = NULL,
+               .msg_namelen = 0,
+               .msg_control = NULL,
+               .msg_controllen = 0,
+               .msg_iov = vq->iov,
+               .msg_flags = MSG_DONTWAIT,
+       };
+       size_t len, total_len = 0;
+       int err, wmem;
+       size_t hdr_size;
+       struct socket *sock = rcu_dereference(vq->private_data);
+       if (!sock)
+               return;
+
+       wmem = atomic_read(&sock->sk->sk_wmem_alloc);
+       if (wmem >= sock->sk->sk_sndbuf)
+               return;
+
+       use_mm(net->dev.mm);
+       mutex_lock(&vq->mutex);
+       vhost_disable_notify(vq);
+
+       if (wmem < sock->sk->sk_sndbuf * 2)
+               tx_poll_stop(net);
+       hdr_size = vq->hdr_size;
+
+       for (;;) {
+               head = vhost_get_vq_desc(&net->dev, vq, vq->iov,
+                                        ARRAY_SIZE(vq->iov),
+                                        &out, &in,
+                                        NULL, NULL);
+               /* Nothing new?  Wait for eventfd to tell us they refilled. */
+               if (head == vq->num) {
+                       wmem = atomic_read(&sock->sk->sk_wmem_alloc);
+                       if (wmem >= sock->sk->sk_sndbuf * 3 / 4) {
+                               tx_poll_start(net, sock);
+                               set_bit(SOCK_ASYNC_NOSPACE, &sock->flags);
+                               break;
+                       }
+                       if (unlikely(vhost_enable_notify(vq))) {
+                               vhost_disable_notify(vq);
+                               continue;
+                       }
+                       break;
+               }
+               if (in) {
+                       vq_err(vq, "Unexpected descriptor format for TX: "
+                              "out %d, int %d\n", out, in);
+                       break;
+               }
+               /* Skip header. TODO: support TSO. */
+               s = move_iovec_hdr(vq->iov, vq->hdr, hdr_size, out);
+               msg.msg_iovlen = out;
+               len = iov_length(vq->iov, out);
+               /* Sanity check */
+               if (!len) {
+                       vq_err(vq, "Unexpected header len for TX: "
+                              "%zd expected %zd\n",
+                              iov_length(vq->hdr, s), hdr_size);
+                       break;
+               }
+               /* TODO: Check specific error and bomb out unless ENOBUFS? */
+               err = sock->ops->sendmsg(NULL, sock, &msg, len);
+               if (unlikely(err < 0)) {
+                       vhost_discard_vq_desc(vq);
+                       tx_poll_start(net, sock);
+                       break;
+               }
+               if (err != len)
+                       pr_err("Truncated TX packet: "
+                              " len %d != %zd\n", err, len);
+               vhost_add_used_and_signal(&net->dev, vq, head, 0);
+               total_len += len;
+               if (unlikely(total_len >= VHOST_NET_WEIGHT)) {
+                       vhost_poll_queue(&vq->poll);
+                       break;
+               }
+       }
+
+       mutex_unlock(&vq->mutex);
+       unuse_mm(net->dev.mm);
+}
+
+/* Expects to be always run from workqueue - which acts as
+ * read-size critical section for our kind of RCU. */
+static void handle_rx(struct vhost_net *net)
+{
+       struct vhost_virtqueue *vq = &net->dev.vqs[VHOST_NET_VQ_RX];
+       unsigned head, out, in, log, s;
+       struct vhost_log *vq_log;
+       struct msghdr msg = {
+               .msg_name = NULL,
+               .msg_namelen = 0,
+               .msg_control = NULL, /* FIXME: get and handle RX aux data. */
+               .msg_controllen = 0,
+               .msg_iov = vq->iov,
+               .msg_flags = MSG_DONTWAIT,
+       };
+
+       struct virtio_net_hdr hdr = {
+               .flags = 0,
+               .gso_type = VIRTIO_NET_HDR_GSO_NONE
+       };
+
+       size_t len, total_len = 0;
+       int err;
+       size_t hdr_size;
+       struct socket *sock = rcu_dereference(vq->private_data);
+       if (!sock || skb_queue_empty(&sock->sk->sk_receive_queue))
+               return;
+
+       use_mm(net->dev.mm);
+       mutex_lock(&vq->mutex);
+       vhost_disable_notify(vq);
+       hdr_size = vq->hdr_size;
+
+       vq_log = unlikely(vhost_has_feature(&net->dev, VHOST_F_LOG_ALL)) ?
+               vq->log : NULL;
+
+       for (;;) {
+               head = vhost_get_vq_desc(&net->dev, vq, vq->iov,
+                                        ARRAY_SIZE(vq->iov),
+                                        &out, &in,
+                                        vq_log, &log);
+               /* OK, now we need to know about added descriptors. */
+               if (head == vq->num) {
+                       if (unlikely(vhost_enable_notify(vq))) {
+                               /* They have slipped one in as we were
+                                * doing that: check again. */
+                               vhost_disable_notify(vq);
+                               continue;
+                       }
+                       /* Nothing new?  Wait for eventfd to tell us
+                        * they refilled. */
+                       break;
+               }
+               /* We don't need to be notified again. */
+               if (out) {
+                       vq_err(vq, "Unexpected descriptor format for RX: "
+                              "out %d, int %d\n",
+                              out, in);
+                       break;
+               }
+               /* Skip header. TODO: support TSO/mergeable rx buffers. */
+               s = move_iovec_hdr(vq->iov, vq->hdr, hdr_size, in);
+               msg.msg_iovlen = in;
+               len = iov_length(vq->iov, in);
+               /* Sanity check */
+               if (!len) {
+                       vq_err(vq, "Unexpected header len for RX: "
+                              "%zd expected %zd\n",
+                              iov_length(vq->hdr, s), hdr_size);
+                       break;
+               }
+               err = sock->ops->recvmsg(NULL, sock, &msg,
+                                        len, MSG_DONTWAIT | MSG_TRUNC);
+               /* TODO: Check specific error and bomb out unless EAGAIN? */
+               if (err < 0) {
+                       vhost_discard_vq_desc(vq);
+                       break;
+               }
+               /* TODO: Should check and handle checksum. */
+               if (err > len) {
+                       pr_err("Discarded truncated rx packet: "
+                              " len %d > %zd\n", err, len);
+                       vhost_discard_vq_desc(vq);
+                       continue;
+               }
+               len = err;
+               err = memcpy_toiovec(vq->hdr, (unsigned char *)&hdr, hdr_size);
+               if (err) {
+                       vq_err(vq, "Unable to write vnet_hdr at addr %p: %d\n",
+                              vq->iov->iov_base, err);
+                       break;
+               }
+               len += hdr_size;
+               vhost_add_used_and_signal(&net->dev, vq, head, len);
+               if (unlikely(vq_log))
+                       vhost_log_write(vq, vq_log, log, len);
+               total_len += len;
+               if (unlikely(total_len >= VHOST_NET_WEIGHT)) {
+                       vhost_poll_queue(&vq->poll);
+                       break;
+               }
+       }
+
+       mutex_unlock(&vq->mutex);
+       unuse_mm(net->dev.mm);
+}
+
+static void handle_tx_kick(struct work_struct *work)
+{
+       struct vhost_virtqueue *vq;
+       struct vhost_net *net;
+       vq = container_of(work, struct vhost_virtqueue, poll.work);
+       net = container_of(vq->dev, struct vhost_net, dev);
+       handle_tx(net);
+}
+
+static void handle_rx_kick(struct work_struct *work)
+{
+       struct vhost_virtqueue *vq;
+       struct vhost_net *net;
+       vq = container_of(work, struct vhost_virtqueue, poll.work);
+       net = container_of(vq->dev, struct vhost_net, dev);
+       handle_rx(net);
+}
+
+static void handle_tx_net(struct work_struct *work)
+{
+       struct vhost_net *net;
+       net = container_of(work, struct vhost_net, poll[VHOST_NET_VQ_TX].work);
+       handle_tx(net);
+}
+
+static void handle_rx_net(struct work_struct *work)
+{
+       struct vhost_net *net;
+       net = container_of(work, struct vhost_net, poll[VHOST_NET_VQ_RX].work);
+       handle_rx(net);
+}
+
+static int vhost_net_open(struct inode *inode, struct file *f)
+{
+       struct vhost_net *n = kmalloc(sizeof *n, GFP_KERNEL);
+       int r;
+       if (!n)
+               return -ENOMEM;
+       n->vqs[VHOST_NET_VQ_TX].handle_kick = handle_tx_kick;
+       n->vqs[VHOST_NET_VQ_RX].handle_kick = handle_rx_kick;
+       r = vhost_dev_init(&n->dev, n->vqs, VHOST_NET_VQ_MAX);
+       if (r < 0) {
+               kfree(n);
+               return r;
+       }
+
+       vhost_poll_init(n->poll + VHOST_NET_VQ_TX, handle_tx_net, POLLOUT);
+       vhost_poll_init(n->poll + VHOST_NET_VQ_RX, handle_rx_net, POLLIN);
+       n->tx_poll_state = VHOST_NET_POLL_DISABLED;
+
+       f->private_data = n;
+
+       return 0;
+}
+
+static void vhost_net_disable_vq(struct vhost_net *n,
+                                struct vhost_virtqueue *vq)
+{
+       if (!vq->private_data)
+               return;
+       if (vq == n->vqs + VHOST_NET_VQ_TX) {
+               tx_poll_stop(n);
+               n->tx_poll_state = VHOST_NET_POLL_DISABLED;
+       } else
+               vhost_poll_stop(n->poll + VHOST_NET_VQ_RX);
+}
+
+static void vhost_net_enable_vq(struct vhost_net *n,
+                               struct vhost_virtqueue *vq)
+{
+       struct socket *sock = vq->private_data;
+       if (!sock)
+               return;
+       if (vq == n->vqs + VHOST_NET_VQ_TX) {
+               n->tx_poll_state = VHOST_NET_POLL_STOPPED;
+               tx_poll_start(n, sock);
+       } else
+               vhost_poll_start(n->poll + VHOST_NET_VQ_RX, sock->file);
+}
+
+static struct socket *vhost_net_stop_vq(struct vhost_net *n,
+                                       struct vhost_virtqueue *vq)
+{
+       struct socket *sock;
+
+       mutex_lock(&vq->mutex);
+       sock = vq->private_data;
+       vhost_net_disable_vq(n, vq);
+       rcu_assign_pointer(vq->private_data, NULL);
+       mutex_unlock(&vq->mutex);
+       return sock;
+}
+
+static void vhost_net_stop(struct vhost_net *n, struct socket **tx_sock,
+                          struct socket **rx_sock)
+{
+       *tx_sock = vhost_net_stop_vq(n, n->vqs + VHOST_NET_VQ_TX);
+       *rx_sock = vhost_net_stop_vq(n, n->vqs + VHOST_NET_VQ_RX);
+}
+
+static void vhost_net_flush_vq(struct vhost_net *n, int index)
+{
+       vhost_poll_flush(n->poll + index);
+       vhost_poll_flush(&n->dev.vqs[index].poll);
+}
+
+static void vhost_net_flush(struct vhost_net *n)
+{
+       vhost_net_flush_vq(n, VHOST_NET_VQ_TX);
+       vhost_net_flush_vq(n, VHOST_NET_VQ_RX);
+}
+
+static int vhost_net_release(struct inode *inode, struct file *f)
+{
+       struct vhost_net *n = f->private_data;
+       struct socket *tx_sock;
+       struct socket *rx_sock;
+
+       vhost_net_stop(n, &tx_sock, &rx_sock);
+       vhost_net_flush(n);
+       vhost_dev_cleanup(&n->dev);
+       if (tx_sock)
+               fput(tx_sock->file);
+       if (rx_sock)
+               fput(rx_sock->file);
+       /* We do an extra flush before freeing memory,
+        * since jobs can re-queue themselves. */
+       vhost_net_flush(n);
+       kfree(n);
+       return 0;
+}
+
+static struct socket *get_raw_socket(int fd)
+{
+       struct {
+               struct sockaddr_ll sa;
+               char  buf[MAX_ADDR_LEN];
+       } uaddr;
+       int uaddr_len = sizeof uaddr, r;
+       struct socket *sock = sockfd_lookup(fd, &r);
+       if (!sock)
+               return ERR_PTR(-ENOTSOCK);
+
+       /* Parameter checking */
+       if (sock->sk->sk_type != SOCK_RAW) {
+               r = -ESOCKTNOSUPPORT;
+               goto err;
+       }
+
+       r = sock->ops->getname(sock, (struct sockaddr *)&uaddr.sa,
+                              &uaddr_len, 0);
+       if (r)
+               goto err;
+
+       if (uaddr.sa.sll_family != AF_PACKET) {
+               r = -EPFNOSUPPORT;
+               goto err;
+       }
+       return sock;
+err:
+       fput(sock->file);
+       return ERR_PTR(r);
+}
+
+static struct socket *get_tun_socket(int fd)
+{
+       struct file *file = fget(fd);
+       struct socket *sock;
+       if (!file)
+               return ERR_PTR(-EBADF);
+       sock = tun_get_socket(file);
+       if (IS_ERR(sock))
+               fput(file);
+       return sock;
+}
+
+static struct socket *get_socket(int fd)
+{
+       struct socket *sock;
+       /* special case to disable backend */
+       if (fd == -1)
+               return NULL;
+       sock = get_raw_socket(fd);
+       if (!IS_ERR(sock))
+               return sock;
+       sock = get_tun_socket(fd);
+       if (!IS_ERR(sock))
+               return sock;
+       return ERR_PTR(-ENOTSOCK);
+}
+
+static long vhost_net_set_backend(struct vhost_net *n, unsigned index, int fd)
+{
+       struct socket *sock, *oldsock;
+       struct vhost_virtqueue *vq;
+       int r;
+
+       mutex_lock(&n->dev.mutex);
+       r = vhost_dev_check_owner(&n->dev);
+       if (r)
+               goto err;
+
+       if (index >= VHOST_NET_VQ_MAX) {
+               r = -ENOBUFS;
+               goto err;
+       }
+       vq = n->vqs + index;
+       mutex_lock(&vq->mutex);
+
+       /* Verify that ring has been setup correctly. */
+       if (!vhost_vq_access_ok(vq)) {
+               r = -EFAULT;
+               goto err;
+       }
+       sock = get_socket(fd);
+       if (IS_ERR(sock)) {
+               r = PTR_ERR(sock);
+               goto err;
+       }
+
+       /* start polling new socket */
+       oldsock = vq->private_data;
+       if (sock == oldsock)
+               goto done;
+
+       vhost_net_disable_vq(n, vq);
+       rcu_assign_pointer(vq->private_data, sock);
+       vhost_net_enable_vq(n, vq);
+       mutex_unlock(&vq->mutex);
+done:
+       if (oldsock) {
+               vhost_net_flush_vq(n, index);
+               fput(oldsock->file);
+       }
+err:
+       mutex_unlock(&n->dev.mutex);
+       return r;
+}
+
+static long vhost_net_reset_owner(struct vhost_net *n)
+{
+       struct socket *tx_sock = NULL;
+       struct socket *rx_sock = NULL;
+       long err;
+       mutex_lock(&n->dev.mutex);
+       err = vhost_dev_check_owner(&n->dev);
+       if (err)
+               goto done;
+       vhost_net_stop(n, &tx_sock, &rx_sock);
+       vhost_net_flush(n);
+       err = vhost_dev_reset_owner(&n->dev);
+done:
+       mutex_unlock(&n->dev.mutex);
+       if (tx_sock)
+               fput(tx_sock->file);
+       if (rx_sock)
+               fput(rx_sock->file);
+       return err;
+}
+
+static int vhost_net_set_features(struct vhost_net *n, u64 features)
+{
+       size_t hdr_size = features & (1 << VHOST_NET_F_VIRTIO_NET_HDR) ?
+               sizeof(struct virtio_net_hdr) : 0;
+       int i;
+       mutex_lock(&n->dev.mutex);
+       if ((features & (1 << VHOST_F_LOG_ALL)) &&
+           !vhost_log_access_ok(&n->dev)) {
+               mutex_unlock(&n->dev.mutex);
+               return -EFAULT;
+       }
+       n->dev.acked_features = features;
+       smp_wmb();
+       for (i = 0; i < VHOST_NET_VQ_MAX; ++i) {
+               mutex_lock(&n->vqs[i].mutex);
+               n->vqs[i].hdr_size = hdr_size;
+               mutex_unlock(&n->vqs[i].mutex);
+       }
+       vhost_net_flush(n);
+       mutex_unlock(&n->dev.mutex);
+       return 0;
+}
+
+static long vhost_net_ioctl(struct file *f, unsigned int ioctl,
+                           unsigned long arg)
+{
+       struct vhost_net *n = f->private_data;
+       void __user *argp = (void __user *)arg;
+       u64 __user *featurep = argp;
+       struct vhost_vring_file backend;
+       u64 features;
+       int r;
+       switch (ioctl) {
+       case VHOST_NET_SET_BACKEND:
+               r = copy_from_user(&backend, argp, sizeof backend);
+               if (r < 0)
+                       return r;
+               return vhost_net_set_backend(n, backend.index, backend.fd);
+       case VHOST_GET_FEATURES:
+               features = VHOST_FEATURES;
+               return copy_to_user(featurep, &features, sizeof features);
+       case VHOST_SET_FEATURES:
+               r = copy_from_user(&features, featurep, sizeof features);
+               if (r < 0)
+                       return r;
+               if (features & ~VHOST_FEATURES)
+                       return -EOPNOTSUPP;
+               return vhost_net_set_features(n, features);
+       case VHOST_RESET_OWNER:
+               return vhost_net_reset_owner(n);
+       default:
+               mutex_lock(&n->dev.mutex);
+               r = vhost_dev_ioctl(&n->dev, ioctl, arg);
+               vhost_net_flush(n);
+               mutex_unlock(&n->dev.mutex);
+               return r;
+       }
+}
+
+#ifdef CONFIG_COMPAT
+static long vhost_net_compat_ioctl(struct file *f, unsigned int ioctl,
+                                  unsigned long arg)
+{
+       return vhost_net_ioctl(f, ioctl, (unsigned long)compat_ptr(arg));
+}
+#endif
+
+const static struct file_operations vhost_net_fops = {
+       .owner          = THIS_MODULE,
+       .release        = vhost_net_release,
+       .unlocked_ioctl = vhost_net_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl   = vhost_net_compat_ioctl,
+#endif
+       .open           = vhost_net_open,
+};
+
+static struct miscdevice vhost_net_misc = {
+       VHOST_NET_MINOR,
+       "vhost-net",
+       &vhost_net_fops,
+};
+
+int vhost_net_init(void)
+{
+       int r = vhost_init();
+       if (r)
+               goto err_init;
+       r = misc_register(&vhost_net_misc);
+       if (r)
+               goto err_reg;
+       return 0;
+err_reg:
+       vhost_cleanup();
+err_init:
+       return r;
+
+}
+module_init(vhost_net_init);
+
+void vhost_net_exit(void)
+{
+       misc_deregister(&vhost_net_misc);
+       vhost_cleanup();
+}
+module_exit(vhost_net_exit);
+
+MODULE_VERSION("0.0.1");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Michael S. Tsirkin");
+MODULE_DESCRIPTION("Host kernel accelerator for virtio net");
diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
new file mode 100644 (file)
index 0000000..c8c25db
--- /dev/null
@@ -0,0 +1,1098 @@
+/* Copyright (C) 2009 Red Hat, Inc.
+ * Copyright (C) 2006 Rusty Russell IBM Corporation
+ *
+ * Author: Michael S. Tsirkin <mst@redhat.com>
+ *
+ * Inspiration, some code, and most witty comments come from
+ * Documentation/lguest/lguest.c, by Rusty Russell
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.
+ *
+ * Generic code for virtio server in host kernel.
+ */
+
+#include <linux/eventfd.h>
+#include <linux/vhost.h>
+#include <linux/virtio_net.h>
+#include <linux/mm.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+#include <linux/rcupdate.h>
+#include <linux/poll.h>
+#include <linux/file.h>
+#include <linux/highmem.h>
+
+#include <linux/net.h>
+#include <linux/if_packet.h>
+#include <linux/if_arp.h>
+
+#include <net/sock.h>
+
+#include "vhost.h"
+
+enum {
+       VHOST_MEMORY_MAX_NREGIONS = 64,
+       VHOST_MEMORY_F_LOG = 0x1,
+};
+
+static struct workqueue_struct *vhost_workqueue;
+
+static void vhost_poll_func(struct file *file, wait_queue_head_t *wqh,
+                           poll_table *pt)
+{
+       struct vhost_poll *poll;
+       poll = container_of(pt, struct vhost_poll, table);
+
+       poll->wqh = wqh;
+       add_wait_queue(wqh, &poll->wait);
+}
+
+static int vhost_poll_wakeup(wait_queue_t *wait, unsigned mode, int sync,
+                            void *key)
+{
+       struct vhost_poll *poll;
+       poll = container_of(wait, struct vhost_poll, wait);
+       if (!((unsigned long)key & poll->mask))
+               return 0;
+
+       queue_work(vhost_workqueue, &poll->work);
+       return 0;
+}
+
+/* Init poll structure */
+void vhost_poll_init(struct vhost_poll *poll, work_func_t func,
+                    unsigned long mask)
+{
+       INIT_WORK(&poll->work, func);
+       init_waitqueue_func_entry(&poll->wait, vhost_poll_wakeup);
+       init_poll_funcptr(&poll->table, vhost_poll_func);
+       poll->mask = mask;
+}
+
+/* Start polling a file. We add ourselves to file's wait queue. The caller must
+ * keep a reference to a file until after vhost_poll_stop is called. */
+void vhost_poll_start(struct vhost_poll *poll, struct file *file)
+{
+       unsigned long mask;
+       mask = file->f_op->poll(file, &poll->table);
+       if (mask)
+               vhost_poll_wakeup(&poll->wait, 0, 0, (void *)mask);
+}
+
+/* Stop polling a file. After this function returns, it becomes safe to drop the
+ * file reference. You must also flush afterwards. */
+void vhost_poll_stop(struct vhost_poll *poll)
+{
+       remove_wait_queue(poll->wqh, &poll->wait);
+}
+
+/* Flush any work that has been scheduled. When calling this, don't hold any
+ * locks that are also used by the callback. */
+void vhost_poll_flush(struct vhost_poll *poll)
+{
+       flush_work(&poll->work);
+}
+
+void vhost_poll_queue(struct vhost_poll *poll)
+{
+       queue_work(vhost_workqueue, &poll->work);
+}
+
+static void vhost_vq_reset(struct vhost_dev *dev,
+                          struct vhost_virtqueue *vq)
+{
+       vq->num = 1;
+       vq->desc = NULL;
+       vq->avail = NULL;
+       vq->used = NULL;
+       vq->last_avail_idx = 0;
+       vq->avail_idx = 0;
+       vq->last_used_idx = 0;
+       vq->used_flags = 0;
+       vq->used_flags = 0;
+       vq->log_used = false;
+       vq->log_addr = -1ull;
+       vq->hdr_size = 0;
+       vq->private_data = NULL;
+       vq->log_base = NULL;
+       vq->error_ctx = NULL;
+       vq->error = NULL;
+       vq->kick = NULL;
+       vq->call_ctx = NULL;
+       vq->call = NULL;
+}
+
+long vhost_dev_init(struct vhost_dev *dev,
+                   struct vhost_virtqueue *vqs, int nvqs)
+{
+       int i;
+       dev->vqs = vqs;
+       dev->nvqs = nvqs;
+       mutex_init(&dev->mutex);
+       dev->log_ctx = NULL;
+       dev->log_file = NULL;
+       dev->memory = NULL;
+       dev->mm = NULL;
+
+       for (i = 0; i < dev->nvqs; ++i) {
+               dev->vqs[i].dev = dev;
+               mutex_init(&dev->vqs[i].mutex);
+               vhost_vq_reset(dev, dev->vqs + i);
+               if (dev->vqs[i].handle_kick)
+                       vhost_poll_init(&dev->vqs[i].poll,
+                                       dev->vqs[i].handle_kick,
+                                       POLLIN);
+       }
+       return 0;
+}
+
+/* Caller should have device mutex */
+long vhost_dev_check_owner(struct vhost_dev *dev)
+{
+       /* Are you the owner? If not, I don't think you mean to do that */
+       return dev->mm == current->mm ? 0 : -EPERM;
+}
+
+/* Caller should have device mutex */
+static long vhost_dev_set_owner(struct vhost_dev *dev)
+{
+       /* Is there an owner already? */
+       if (dev->mm)
+               return -EBUSY;
+       /* No owner, become one */
+       dev->mm = get_task_mm(current);
+       return 0;
+}
+
+/* Caller should have device mutex */
+long vhost_dev_reset_owner(struct vhost_dev *dev)
+{
+       struct vhost_memory *memory;
+
+       /* Restore memory to default empty mapping. */
+       memory = kmalloc(offsetof(struct vhost_memory, regions), GFP_KERNEL);
+       if (!memory)
+               return -ENOMEM;
+
+       vhost_dev_cleanup(dev);
+
+       memory->nregions = 0;
+       dev->memory = memory;
+       return 0;
+}
+
+/* Caller should have device mutex */
+void vhost_dev_cleanup(struct vhost_dev *dev)
+{
+       int i;
+       for (i = 0; i < dev->nvqs; ++i) {
+               if (dev->vqs[i].kick && dev->vqs[i].handle_kick) {
+                       vhost_poll_stop(&dev->vqs[i].poll);
+                       vhost_poll_flush(&dev->vqs[i].poll);
+               }
+               if (dev->vqs[i].error_ctx)
+                       eventfd_ctx_put(dev->vqs[i].error_ctx);
+               if (dev->vqs[i].error)
+                       fput(dev->vqs[i].error);
+               if (dev->vqs[i].kick)
+                       fput(dev->vqs[i].kick);
+               if (dev->vqs[i].call_ctx)
+                       eventfd_ctx_put(dev->vqs[i].call_ctx);
+               if (dev->vqs[i].call)
+                       fput(dev->vqs[i].call);
+               vhost_vq_reset(dev, dev->vqs + i);
+       }
+       if (dev->log_ctx)
+               eventfd_ctx_put(dev->log_ctx);
+       dev->log_ctx = NULL;
+       if (dev->log_file)
+               fput(dev->log_file);
+       dev->log_file = NULL;
+       /* No one will access memory at this point */
+       kfree(dev->memory);
+       dev->memory = NULL;
+       if (dev->mm)
+               mmput(dev->mm);
+       dev->mm = NULL;
+}
+
+static int log_access_ok(void __user *log_base, u64 addr, unsigned long sz)
+{
+       u64 a = addr / VHOST_PAGE_SIZE / 8;
+       /* Make sure 64 bit math will not overflow. */
+       if (a > ULONG_MAX - (unsigned long)log_base ||
+           a + (unsigned long)log_base > ULONG_MAX)
+               return -EFAULT;
+
+       return access_ok(VERIFY_WRITE, log_base + a,
+                        (sz + VHOST_PAGE_SIZE * 8 - 1) / VHOST_PAGE_SIZE / 8);
+}
+
+/* Caller should have vq mutex and device mutex. */
+static int vq_memory_access_ok(void __user *log_base, struct vhost_memory *mem,
+                              int log_all)
+{
+       int i;
+       for (i = 0; i < mem->nregions; ++i) {
+               struct vhost_memory_region *m = mem->regions + i;
+               unsigned long a = m->userspace_addr;
+               if (m->memory_size > ULONG_MAX)
+                       return 0;
+               else if (!access_ok(VERIFY_WRITE, (void __user *)a,
+                                   m->memory_size))
+                       return 0;
+               else if (log_all && !log_access_ok(log_base,
+                                                  m->guest_phys_addr,
+                                                  m->memory_size))
+                       return 0;
+       }
+       return 1;
+}
+
+/* Can we switch to this memory table? */
+/* Caller should have device mutex but not vq mutex */
+static int memory_access_ok(struct vhost_dev *d, struct vhost_memory *mem,
+                           int log_all)
+{
+       int i;
+       for (i = 0; i < d->nvqs; ++i) {
+               int ok;
+               mutex_lock(&d->vqs[i].mutex);
+               /* If ring is inactive, will check when it's enabled. */
+               if (d->vqs[i].private_data)
+                       ok = vq_memory_access_ok(d->vqs[i].log_base, mem,
+                                                log_all);
+               else
+                       ok = 1;
+               mutex_unlock(&d->vqs[i].mutex);
+               if (!ok)
+                       return 0;
+       }
+       return 1;
+}
+
+static int vq_access_ok(unsigned int num,
+                       struct vring_desc __user *desc,
+                       struct vring_avail __user *avail,
+                       struct vring_used __user *used)
+{
+       return access_ok(VERIFY_READ, desc, num * sizeof *desc) &&
+              access_ok(VERIFY_READ, avail,
+                        sizeof *avail + num * sizeof *avail->ring) &&
+              access_ok(VERIFY_WRITE, used,
+                       sizeof *used + num * sizeof *used->ring);
+}
+
+/* Can we log writes? */
+/* Caller should have device mutex but not vq mutex */
+int vhost_log_access_ok(struct vhost_dev *dev)
+{
+       return memory_access_ok(dev, dev->memory, 1);
+}
+
+/* Verify access for write logging. */
+/* Caller should have vq mutex and device mutex */
+static int vq_log_access_ok(struct vhost_virtqueue *vq, void __user *log_base)
+{
+       return vq_memory_access_ok(log_base, vq->dev->memory,
+                           vhost_has_feature(vq->dev, VHOST_F_LOG_ALL)) &&
+               (!vq->log_used || log_access_ok(log_base, vq->log_addr,
+                                       sizeof *vq->used +
+                                       vq->num * sizeof *vq->used->ring));
+}
+
+/* Can we start vq? */
+/* Caller should have vq mutex and device mutex */
+int vhost_vq_access_ok(struct vhost_virtqueue *vq)
+{
+       return vq_access_ok(vq->num, vq->desc, vq->avail, vq->used) &&
+               vq_log_access_ok(vq, vq->log_base);
+}
+
+static long vhost_set_memory(struct vhost_dev *d, struct vhost_memory __user *m)
+{
+       struct vhost_memory mem, *newmem, *oldmem;
+       unsigned long size = offsetof(struct vhost_memory, regions);
+       long r;
+       r = copy_from_user(&mem, m, size);
+       if (r)
+               return r;
+       if (mem.padding)
+               return -EOPNOTSUPP;
+       if (mem.nregions > VHOST_MEMORY_MAX_NREGIONS)
+               return -E2BIG;
+       newmem = kmalloc(size + mem.nregions * sizeof *m->regions, GFP_KERNEL);
+       if (!newmem)
+               return -ENOMEM;
+
+       memcpy(newmem, &mem, size);
+       r = copy_from_user(newmem->regions, m->regions,
+                          mem.nregions * sizeof *m->regions);
+       if (r) {
+               kfree(newmem);
+               return r;
+       }
+
+       if (!memory_access_ok(d, newmem, vhost_has_feature(d, VHOST_F_LOG_ALL)))
+               return -EFAULT;
+       oldmem = d->memory;
+       rcu_assign_pointer(d->memory, newmem);
+       synchronize_rcu();
+       kfree(oldmem);
+       return 0;
+}
+
+static int init_used(struct vhost_virtqueue *vq,
+                    struct vring_used __user *used)
+{
+       int r = put_user(vq->used_flags, &used->flags);
+       if (r)
+               return r;
+       return get_user(vq->last_used_idx, &used->idx);
+}
+
+static long vhost_set_vring(struct vhost_dev *d, int ioctl, void __user *argp)
+{
+       struct file *eventfp, *filep = NULL,
+                   *pollstart = NULL, *pollstop = NULL;
+       struct eventfd_ctx *ctx = NULL;
+       u32 __user *idxp = argp;
+       struct vhost_virtqueue *vq;
+       struct vhost_vring_state s;
+       struct vhost_vring_file f;
+       struct vhost_vring_addr a;
+       u32 idx;
+       long r;
+
+       r = get_user(idx, idxp);
+       if (r < 0)
+               return r;
+       if (idx > d->nvqs)
+               return -ENOBUFS;
+
+       vq = d->vqs + idx;
+
+       mutex_lock(&vq->mutex);
+
+       switch (ioctl) {
+       case VHOST_SET_VRING_NUM:
+               /* Resizing ring with an active backend?
+                * You don't want to do that. */
+               if (vq->private_data) {
+                       r = -EBUSY;
+                       break;
+               }
+               r = copy_from_user(&s, argp, sizeof s);
+               if (r < 0)
+                       break;
+               if (!s.num || s.num > 0xffff || (s.num & (s.num - 1))) {
+                       r = -EINVAL;
+                       break;
+               }
+               vq->num = s.num;
+               break;
+       case VHOST_SET_VRING_BASE:
+               /* Moving base with an active backend?
+                * You don't want to do that. */
+               if (vq->private_data) {
+                       r = -EBUSY;
+                       break;
+               }
+               r = copy_from_user(&s, argp, sizeof s);
+               if (r < 0)
+                       break;
+               if (s.num > 0xffff) {
+                       r = -EINVAL;
+                       break;
+               }
+               vq->last_avail_idx = s.num;
+               /* Forget the cached index value. */
+               vq->avail_idx = vq->last_avail_idx;
+               break;
+       case VHOST_GET_VRING_BASE:
+               s.index = idx;
+               s.num = vq->last_avail_idx;
+               r = copy_to_user(argp, &s, sizeof s);
+               break;
+       case VHOST_SET_VRING_ADDR:
+               r = copy_from_user(&a, argp, sizeof a);
+               if (r < 0)
+                       break;
+               if (a.flags & ~(0x1 << VHOST_VRING_F_LOG)) {
+                       r = -EOPNOTSUPP;
+                       break;
+               }
+               /* For 32bit, verify that the top 32bits of the user
+                  data are set to zero. */
+               if ((u64)(unsigned long)a.desc_user_addr != a.desc_user_addr ||
+                   (u64)(unsigned long)a.used_user_addr != a.used_user_addr ||
+                   (u64)(unsigned long)a.avail_user_addr != a.avail_user_addr) {
+                       r = -EFAULT;
+                       break;
+               }
+               if ((a.avail_user_addr & (sizeof *vq->avail->ring - 1)) ||
+                   (a.used_user_addr & (sizeof *vq->used->ring - 1)) ||
+                   (a.log_guest_addr & (sizeof *vq->used->ring - 1))) {
+                       r = -EINVAL;
+                       break;
+               }
+
+               /* We only verify access here if backend is configured.
+                * If it is not, we don't as size might not have been setup.
+                * We will verify when backend is configured. */
+               if (vq->private_data) {
+                       if (!vq_access_ok(vq->num,
+                               (void __user *)(unsigned long)a.desc_user_addr,
+                               (void __user *)(unsigned long)a.avail_user_addr,
+                               (void __user *)(unsigned long)a.used_user_addr)) {
+                               r = -EINVAL;
+                               break;
+                       }
+
+                       /* Also validate log access for used ring if enabled. */
+                       if ((a.flags & (0x1 << VHOST_VRING_F_LOG)) &&
+                           !log_access_ok(vq->log_base, a.log_guest_addr,
+                                          sizeof *vq->used +
+                                          vq->num * sizeof *vq->used->ring)) {
+                               r = -EINVAL;
+                               break;
+                       }
+               }
+
+               r = init_used(vq, (struct vring_used __user *)(unsigned long)
+                             a.used_user_addr);
+               if (r)
+                       break;
+               vq->log_used = !!(a.flags & (0x1 << VHOST_VRING_F_LOG));
+               vq->desc = (void __user *)(unsigned long)a.desc_user_addr;
+               vq->avail = (void __user *)(unsigned long)a.avail_user_addr;
+               vq->log_addr = a.log_guest_addr;
+               vq->used = (void __user *)(unsigned long)a.used_user_addr;
+               break;
+       case VHOST_SET_VRING_KICK:
+               r = copy_from_user(&f, argp, sizeof f);
+               if (r < 0)
+                       break;
+               eventfp = f.fd == -1 ? NULL : eventfd_fget(f.fd);
+               if (IS_ERR(eventfp))
+                       return PTR_ERR(eventfp);
+               if (eventfp != vq->kick) {
+                       pollstop = filep = vq->kick;
+                       pollstart = vq->kick = eventfp;
+               } else
+                       filep = eventfp;
+               break;
+       case VHOST_SET_VRING_CALL:
+               r = copy_from_user(&f, argp, sizeof f);
+               if (r < 0)
+                       break;
+               eventfp = f.fd == -1 ? NULL : eventfd_fget(f.fd);
+               if (IS_ERR(eventfp))
+                       return PTR_ERR(eventfp);
+               if (eventfp != vq->call) {
+                       filep = vq->call;
+                       ctx = vq->call_ctx;
+                       vq->call = eventfp;
+                       vq->call_ctx = eventfp ?
+                               eventfd_ctx_fileget(eventfp) : NULL;
+               } else
+                       filep = eventfp;
+               break;
+       case VHOST_SET_VRING_ERR:
+               r = copy_from_user(&f, argp, sizeof f);
+               if (r < 0)
+                       break;
+               eventfp = f.fd == -1 ? NULL : eventfd_fget(f.fd);
+               if (IS_ERR(eventfp))
+                       return PTR_ERR(eventfp);
+               if (eventfp != vq->error) {
+                       filep = vq->error;
+                       vq->error = eventfp;
+                       ctx = vq->error_ctx;
+                       vq->error_ctx = eventfp ?
+                               eventfd_ctx_fileget(eventfp) : NULL;
+               } else
+                       filep = eventfp;
+               break;
+       default:
+               r = -ENOIOCTLCMD;
+       }
+
+       if (pollstop && vq->handle_kick)
+               vhost_poll_stop(&vq->poll);
+
+       if (ctx)
+               eventfd_ctx_put(ctx);
+       if (filep)
+               fput(filep);
+
+       if (pollstart && vq->handle_kick)
+               vhost_poll_start(&vq->poll, vq->kick);
+
+       mutex_unlock(&vq->mutex);
+
+       if (pollstop && vq->handle_kick)
+               vhost_poll_flush(&vq->poll);
+       return r;
+}
+
+/* Caller must have device mutex */
+long vhost_dev_ioctl(struct vhost_dev *d, unsigned int ioctl, unsigned long arg)
+{
+       void __user *argp = (void __user *)arg;
+       struct file *eventfp, *filep = NULL;
+       struct eventfd_ctx *ctx = NULL;
+       u64 p;
+       long r;
+       int i, fd;
+
+       /* If you are not the owner, you can become one */
+       if (ioctl == VHOST_SET_OWNER) {
+               r = vhost_dev_set_owner(d);
+               goto done;
+       }
+
+       /* You must be the owner to do anything else */
+       r = vhost_dev_check_owner(d);
+       if (r)
+               goto done;
+
+       switch (ioctl) {
+       case VHOST_SET_MEM_TABLE:
+               r = vhost_set_memory(d, argp);
+               break;
+       case VHOST_SET_LOG_BASE:
+               r = copy_from_user(&p, argp, sizeof p);
+               if (r < 0)
+                       break;
+               if ((u64)(unsigned long)p != p) {
+                       r = -EFAULT;
+                       break;
+               }
+               for (i = 0; i < d->nvqs; ++i) {
+                       struct vhost_virtqueue *vq;
+                       void __user *base = (void __user *)(unsigned long)p;
+                       vq = d->vqs + i;
+                       mutex_lock(&vq->mutex);
+                       /* If ring is inactive, will check when it's enabled. */
+                       if (vq->private_data && !vq_log_access_ok(vq, base))
+                               r = -EFAULT;
+                       else
+                               vq->log_base = base;
+                       mutex_unlock(&vq->mutex);
+               }
+               break;
+       case VHOST_SET_LOG_FD:
+               r = get_user(fd, (int __user *)argp);
+               if (r < 0)
+                       break;
+               eventfp = fd == -1 ? NULL : eventfd_fget(fd);
+               if (IS_ERR(eventfp)) {
+                       r = PTR_ERR(eventfp);
+                       break;
+               }
+               if (eventfp != d->log_file) {
+                       filep = d->log_file;
+                       ctx = d->log_ctx;
+                       d->log_ctx = eventfp ?
+                               eventfd_ctx_fileget(eventfp) : NULL;
+               } else
+                       filep = eventfp;
+               for (i = 0; i < d->nvqs; ++i) {
+                       mutex_lock(&d->vqs[i].mutex);
+                       d->vqs[i].log_ctx = d->log_ctx;
+                       mutex_unlock(&d->vqs[i].mutex);
+               }
+               if (ctx)
+                       eventfd_ctx_put(ctx);
+               if (filep)
+                       fput(filep);
+               break;
+       default:
+               r = vhost_set_vring(d, ioctl, argp);
+               break;
+       }
+done:
+       return r;
+}
+
+static const struct vhost_memory_region *find_region(struct vhost_memory *mem,
+                                                    __u64 addr, __u32 len)
+{
+       struct vhost_memory_region *reg;
+       int i;
+       /* linear search is not brilliant, but we really have on the order of 6
+        * regions in practice */
+       for (i = 0; i < mem->nregions; ++i) {
+               reg = mem->regions + i;
+               if (reg->guest_phys_addr <= addr &&
+                   reg->guest_phys_addr + reg->memory_size - 1 >= addr)
+                       return reg;
+       }
+       return NULL;
+}
+
+/* TODO: This is really inefficient.  We need something like get_user()
+ * (instruction directly accesses the data, with an exception table entry
+ * returning -EFAULT). See Documentation/x86/exception-tables.txt.
+ */
+static int set_bit_to_user(int nr, void __user *addr)
+{
+       unsigned long log = (unsigned long)addr;
+       struct page *page;
+       void *base;
+       int bit = nr + (log % PAGE_SIZE) * 8;
+       int r;
+       r = get_user_pages_fast(log, 1, 1, &page);
+       if (r)
+               return r;
+       base = kmap_atomic(page, KM_USER0);
+       set_bit(bit, base);
+       kunmap_atomic(base, KM_USER0);
+       set_page_dirty_lock(page);
+       put_page(page);
+       return 0;
+}
+
+static int log_write(void __user *log_base,
+                    u64 write_address, u64 write_length)
+{
+       int r;
+       if (!write_length)
+               return 0;
+       write_address /= VHOST_PAGE_SIZE;
+       for (;;) {
+               u64 base = (u64)(unsigned long)log_base;
+               u64 log = base + write_address / 8;
+               int bit = write_address % 8;
+               if ((u64)(unsigned long)log != log)
+                       return -EFAULT;
+               r = set_bit_to_user(bit, (void __user *)(unsigned long)log);
+               if (r < 0)
+                       return r;
+               if (write_length <= VHOST_PAGE_SIZE)
+                       break;
+               write_length -= VHOST_PAGE_SIZE;
+               write_address += VHOST_PAGE_SIZE;
+       }
+       return r;
+}
+
+int vhost_log_write(struct vhost_virtqueue *vq, struct vhost_log *log,
+                   unsigned int log_num, u64 len)
+{
+       int i, r;
+
+       /* Make sure data written is seen before log. */
+       wmb();
+       for (i = 0; i < log_num; ++i) {
+               u64 l = min(log[i].len, len);
+               r = log_write(vq->log_base, log[i].addr, l);
+               if (r < 0)
+                       return r;
+               len -= l;
+               if (!len)
+                       return 0;
+       }
+       if (vq->log_ctx)
+               eventfd_signal(vq->log_ctx, 1);
+       /* Length written exceeds what we have stored. This is a bug. */
+       BUG();
+       return 0;
+}
+
+int translate_desc(struct vhost_dev *dev, u64 addr, u32 len,
+                  struct iovec iov[], int iov_size)
+{
+       const struct vhost_memory_region *reg;
+       struct vhost_memory *mem;
+       struct iovec *_iov;
+       u64 s = 0;
+       int ret = 0;
+
+       rcu_read_lock();
+
+       mem = rcu_dereference(dev->memory);
+       while ((u64)len > s) {
+               u64 size;
+               if (ret >= iov_size) {
+                       ret = -ENOBUFS;
+                       break;
+               }
+               reg = find_region(mem, addr, len);
+               if (!reg) {
+                       ret = -EFAULT;
+                       break;
+               }
+               _iov = iov + ret;
+               size = reg->memory_size - addr + reg->guest_phys_addr;
+               _iov->iov_len = min((u64)len, size);
+               _iov->iov_base = (void *)(unsigned long)
+                       (reg->userspace_addr + addr - reg->guest_phys_addr);
+               s += size;
+               addr += size;
+               ++ret;
+       }
+
+       rcu_read_unlock();
+       return ret;
+}
+
+/* Each buffer in the virtqueues is actually a chain of descriptors.  This
+ * function returns the next descriptor in the chain,
+ * or -1U if we're at the end. */
+static unsigned next_desc(struct vring_desc *desc)
+{
+       unsigned int next;
+
+       /* If this descriptor says it doesn't chain, we're done. */
+       if (!(desc->flags & VRING_DESC_F_NEXT))
+               return -1U;
+
+       /* Check they're not leading us off end of descriptors. */
+       next = desc->next;
+       /* Make sure compiler knows to grab that: we don't want it changing! */
+       /* We will use the result as an index in an array, so most
+        * architectures only need a compiler barrier here. */
+       read_barrier_depends();
+
+       return next;
+}
+
+static unsigned get_indirect(struct vhost_dev *dev, struct vhost_virtqueue *vq,
+                            struct iovec iov[], unsigned int iov_size,
+                            unsigned int *out_num, unsigned int *in_num,
+                            struct vhost_log *log, unsigned int *log_num,
+                            struct vring_desc *indirect)
+{
+       struct vring_desc desc;
+       unsigned int i = 0, count, found = 0;
+       int ret;
+
+       /* Sanity check */
+       if (indirect->len % sizeof desc) {
+               vq_err(vq, "Invalid length in indirect descriptor: "
+                      "len 0x%llx not multiple of 0x%zx\n",
+                      (unsigned long long)indirect->len,
+                      sizeof desc);
+               return -EINVAL;
+       }
+
+       ret = translate_desc(dev, indirect->addr, indirect->len, vq->indirect,
+                            ARRAY_SIZE(vq->indirect));
+       if (ret < 0) {
+               vq_err(vq, "Translation failure %d in indirect.\n", ret);
+               return ret;
+       }
+
+       /* We will use the result as an address to read from, so most
+        * architectures only need a compiler barrier here. */
+       read_barrier_depends();
+
+       count = indirect->len / sizeof desc;
+       /* Buffers are chained via a 16 bit next field, so
+        * we can have at most 2^16 of these. */
+       if (count > USHORT_MAX + 1) {
+               vq_err(vq, "Indirect buffer length too big: %d\n",
+                      indirect->len);
+               return -E2BIG;
+       }
+
+       do {
+               unsigned iov_count = *in_num + *out_num;
+               if (++found > count) {
+                       vq_err(vq, "Loop detected: last one at %u "
+                              "indirect size %u\n",
+                              i, count);
+                       return -EINVAL;
+               }
+               if (memcpy_fromiovec((unsigned char *)&desc, vq->indirect,
+                                    sizeof desc)) {
+                       vq_err(vq, "Failed indirect descriptor: idx %d, %zx\n",
+                              i, (size_t)indirect->addr + i * sizeof desc);
+                       return -EINVAL;
+               }
+               if (desc.flags & VRING_DESC_F_INDIRECT) {
+                       vq_err(vq, "Nested indirect descriptor: idx %d, %zx\n",
+                              i, (size_t)indirect->addr + i * sizeof desc);
+                       return -EINVAL;
+               }
+
+               ret = translate_desc(dev, desc.addr, desc.len, iov + iov_count,
+                                    iov_size - iov_count);
+               if (ret < 0) {
+                       vq_err(vq, "Translation failure %d indirect idx %d\n",
+                              ret, i);
+                       return ret;
+               }
+               /* If this is an input descriptor, increment that count. */
+               if (desc.flags & VRING_DESC_F_WRITE) {
+                       *in_num += ret;
+                       if (unlikely(log)) {
+                               log[*log_num].addr = desc.addr;
+                               log[*log_num].len = desc.len;
+                               ++*log_num;
+                       }
+               } else {
+                       /* If it's an output descriptor, they're all supposed
+                        * to come before any input descriptors. */
+                       if (*in_num) {
+                               vq_err(vq, "Indirect descriptor "
+                                      "has out after in: idx %d\n", i);
+                               return -EINVAL;
+                       }
+                       *out_num += ret;
+               }
+       } while ((i = next_desc(&desc)) != -1);
+       return 0;
+}
+
+/* This looks in the virtqueue and for the first available buffer, and converts
+ * it to an iovec for convenient access.  Since descriptors consist of some
+ * number of output then some number of input descriptors, it's actually two
+ * iovecs, but we pack them into one and note how many of each there were.
+ *
+ * This function returns the descriptor number found, or vq->num (which
+ * is never a valid descriptor number) if none was found. */
+unsigned vhost_get_vq_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq,
+                          struct iovec iov[], unsigned int iov_size,
+                          unsigned int *out_num, unsigned int *in_num,
+                          struct vhost_log *log, unsigned int *log_num)
+{
+       struct vring_desc desc;
+       unsigned int i, head, found = 0;
+       u16 last_avail_idx;
+       int ret;
+
+       /* Check it isn't doing very strange things with descriptor numbers. */
+       last_avail_idx = vq->last_avail_idx;
+       if (get_user(vq->avail_idx, &vq->avail->idx)) {
+               vq_err(vq, "Failed to access avail idx at %p\n",
+                      &vq->avail->idx);
+               return vq->num;
+       }
+
+       if ((u16)(vq->avail_idx - last_avail_idx) > vq->num) {
+               vq_err(vq, "Guest moved used index from %u to %u",
+                      last_avail_idx, vq->avail_idx);
+               return vq->num;
+       }
+
+       /* If there's nothing new since last we looked, return invalid. */
+       if (vq->avail_idx == last_avail_idx)
+               return vq->num;
+
+       /* Only get avail ring entries after they have been exposed by guest. */
+       rmb();
+
+       /* Grab the next descriptor number they're advertising, and increment
+        * the index we've seen. */
+       if (get_user(head, &vq->avail->ring[last_avail_idx % vq->num])) {
+               vq_err(vq, "Failed to read head: idx %d address %p\n",
+                      last_avail_idx,
+                      &vq->avail->ring[last_avail_idx % vq->num]);
+               return vq->num;
+       }
+
+       /* If their number is silly, that's an error. */
+       if (head >= vq->num) {
+               vq_err(vq, "Guest says index %u > %u is available",
+                      head, vq->num);
+               return vq->num;
+       }
+
+       /* When we start there are none of either input nor output. */
+       *out_num = *in_num = 0;
+       if (unlikely(log))
+               *log_num = 0;
+
+       i = head;
+       do {
+               unsigned iov_count = *in_num + *out_num;
+               if (i >= vq->num) {
+                       vq_err(vq, "Desc index is %u > %u, head = %u",
+                              i, vq->num, head);
+                       return vq->num;
+               }
+               if (++found > vq->num) {
+                       vq_err(vq, "Loop detected: last one at %u "
+                              "vq size %u head %u\n",
+                              i, vq->num, head);
+                       return vq->num;
+               }
+               ret = copy_from_user(&desc, vq->desc + i, sizeof desc);
+               if (ret) {
+                       vq_err(vq, "Failed to get descriptor: idx %d addr %p\n",
+                              i, vq->desc + i);
+                       return vq->num;
+               }
+               if (desc.flags & VRING_DESC_F_INDIRECT) {
+                       ret = get_indirect(dev, vq, iov, iov_size,
+                                          out_num, in_num,
+                                          log, log_num, &desc);
+                       if (ret < 0) {
+                               vq_err(vq, "Failure detected "
+                                      "in indirect descriptor at idx %d\n", i);
+                               return vq->num;
+                       }
+                       continue;
+               }
+
+               ret = translate_desc(dev, desc.addr, desc.len, iov + iov_count,
+                                    iov_size - iov_count);
+               if (ret < 0) {
+                       vq_err(vq, "Translation failure %d descriptor idx %d\n",
+                              ret, i);
+                       return vq->num;
+               }
+               if (desc.flags & VRING_DESC_F_WRITE) {
+                       /* If this is an input descriptor,
+                        * increment that count. */
+                       *in_num += ret;
+                       if (unlikely(log)) {
+                               log[*log_num].addr = desc.addr;
+                               log[*log_num].len = desc.len;
+                               ++*log_num;
+                       }
+               } else {
+                       /* If it's an output descriptor, they're all supposed
+                        * to come before any input descriptors. */
+                       if (*in_num) {
+                               vq_err(vq, "Descriptor has out after in: "
+                                      "idx %d\n", i);
+                               return vq->num;
+                       }
+                       *out_num += ret;
+               }
+       } while ((i = next_desc(&desc)) != -1);
+
+       /* On success, increment avail index. */
+       vq->last_avail_idx++;
+       return head;
+}
+
+/* Reverse the effect of vhost_get_vq_desc. Useful for error handling. */
+void vhost_discard_vq_desc(struct vhost_virtqueue *vq)
+{
+       vq->last_avail_idx--;
+}
+
+/* After we've used one of their buffers, we tell them about it.  We'll then
+ * want to notify the guest, using eventfd. */
+int vhost_add_used(struct vhost_virtqueue *vq, unsigned int head, int len)
+{
+       struct vring_used_elem *used;
+
+       /* The virtqueue contains a ring of used buffers.  Get a pointer to the
+        * next entry in that used ring. */
+       used = &vq->used->ring[vq->last_used_idx % vq->num];
+       if (put_user(head, &used->id)) {
+               vq_err(vq, "Failed to write used id");
+               return -EFAULT;
+       }
+       if (put_user(len, &used->len)) {
+               vq_err(vq, "Failed to write used len");
+               return -EFAULT;
+       }
+       /* Make sure buffer is written before we update index. */
+       wmb();
+       if (put_user(vq->last_used_idx + 1, &vq->used->idx)) {
+               vq_err(vq, "Failed to increment used idx");
+               return -EFAULT;
+       }
+       if (unlikely(vq->log_used)) {
+               /* Make sure data is seen before log. */
+               wmb();
+               log_write(vq->log_base, vq->log_addr + sizeof *vq->used->ring *
+                         (vq->last_used_idx % vq->num),
+                         sizeof *vq->used->ring);
+               log_write(vq->log_base, vq->log_addr, sizeof *vq->used->ring);
+               if (vq->log_ctx)
+                       eventfd_signal(vq->log_ctx, 1);
+       }
+       vq->last_used_idx++;
+       return 0;
+}
+
+/* This actually signals the guest, using eventfd. */
+void vhost_signal(struct vhost_dev *dev, struct vhost_virtqueue *vq)
+{
+       __u16 flags = 0;
+       if (get_user(flags, &vq->avail->flags)) {
+               vq_err(vq, "Failed to get flags");
+               return;
+       }
+
+       /* If they don't want an interrupt, don't signal, unless empty. */
+       if ((flags & VRING_AVAIL_F_NO_INTERRUPT) &&
+           (vq->avail_idx != vq->last_avail_idx ||
+            !vhost_has_feature(dev, VIRTIO_F_NOTIFY_ON_EMPTY)))
+               return;
+
+       /* Signal the Guest tell them we used something up. */
+       if (vq->call_ctx)
+               eventfd_signal(vq->call_ctx, 1);
+}
+
+/* And here's the combo meal deal.  Supersize me! */
+void vhost_add_used_and_signal(struct vhost_dev *dev,
+                              struct vhost_virtqueue *vq,
+                              unsigned int head, int len)
+{
+       vhost_add_used(vq, head, len);
+       vhost_signal(dev, vq);
+}
+
+/* OK, now we need to know about added descriptors. */
+bool vhost_enable_notify(struct vhost_virtqueue *vq)
+{
+       u16 avail_idx;
+       int r;
+       if (!(vq->used_flags & VRING_USED_F_NO_NOTIFY))
+               return false;
+       vq->used_flags &= ~VRING_USED_F_NO_NOTIFY;
+       r = put_user(vq->used_flags, &vq->used->flags);
+       if (r) {
+               vq_err(vq, "Failed to enable notification at %p: %d\n",
+                      &vq->used->flags, r);
+               return false;
+       }
+       /* They could have slipped one in as we were doing that: make
+        * sure it's written, then check again. */
+       mb();
+       r = get_user(avail_idx, &vq->avail->idx);
+       if (r) {
+               vq_err(vq, "Failed to check avail idx at %p: %d\n",
+                      &vq->avail->idx, r);
+               return false;
+       }
+
+       return avail_idx != vq->last_avail_idx;
+}
+
+/* We don't need to be notified again. */
+void vhost_disable_notify(struct vhost_virtqueue *vq)
+{
+       int r;
+       if (vq->used_flags & VRING_USED_F_NO_NOTIFY)
+               return;
+       vq->used_flags |= VRING_USED_F_NO_NOTIFY;
+       r = put_user(vq->used_flags, &vq->used->flags);
+       if (r)
+               vq_err(vq, "Failed to enable notification at %p: %d\n",
+                      &vq->used->flags, r);
+}
+
+int vhost_init(void)
+{
+       vhost_workqueue = create_singlethread_workqueue("vhost");
+       if (!vhost_workqueue)
+               return -ENOMEM;
+       return 0;
+}
+
+void vhost_cleanup(void)
+{
+       destroy_workqueue(vhost_workqueue);
+}
diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h
new file mode 100644 (file)
index 0000000..44591ba
--- /dev/null
@@ -0,0 +1,161 @@
+#ifndef _VHOST_H
+#define _VHOST_H
+
+#include <linux/eventfd.h>
+#include <linux/vhost.h>
+#include <linux/mm.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+#include <linux/poll.h>
+#include <linux/file.h>
+#include <linux/skbuff.h>
+#include <linux/uio.h>
+#include <linux/virtio_config.h>
+#include <linux/virtio_ring.h>
+
+struct vhost_device;
+
+enum {
+       /* Enough place for all fragments, head, and virtio net header. */
+       VHOST_NET_MAX_SG = MAX_SKB_FRAGS + 2,
+};
+
+/* Poll a file (eventfd or socket) */
+/* Note: there's nothing vhost specific about this structure. */
+struct vhost_poll {
+       poll_table                table;
+       wait_queue_head_t        *wqh;
+       wait_queue_t              wait;
+       /* struct which will handle all actual work. */
+       struct work_struct        work;
+       unsigned long             mask;
+};
+
+void vhost_poll_init(struct vhost_poll *poll, work_func_t func,
+                    unsigned long mask);
+void vhost_poll_start(struct vhost_poll *poll, struct file *file);
+void vhost_poll_stop(struct vhost_poll *poll);
+void vhost_poll_flush(struct vhost_poll *poll);
+void vhost_poll_queue(struct vhost_poll *poll);
+
+struct vhost_log {
+       u64 addr;
+       u64 len;
+};
+
+/* The virtqueue structure describes a queue attached to a device. */
+struct vhost_virtqueue {
+       struct vhost_dev *dev;
+
+       /* The actual ring of buffers. */
+       struct mutex mutex;
+       unsigned int num;
+       struct vring_desc __user *desc;
+       struct vring_avail __user *avail;
+       struct vring_used __user *used;
+       struct file *kick;
+       struct file *call;
+       struct file *error;
+       struct eventfd_ctx *call_ctx;
+       struct eventfd_ctx *error_ctx;
+       struct eventfd_ctx *log_ctx;
+
+       struct vhost_poll poll;
+
+       /* The routine to call when the Guest pings us, or timeout. */
+       work_func_t handle_kick;
+
+       /* Last available index we saw. */
+       u16 last_avail_idx;
+
+       /* Caches available index value from user. */
+       u16 avail_idx;
+
+       /* Last index we used. */
+       u16 last_used_idx;
+
+       /* Used flags */
+       u16 used_flags;
+
+       /* Log writes to used structure. */
+       bool log_used;
+       u64 log_addr;
+
+       struct iovec indirect[VHOST_NET_MAX_SG];
+       struct iovec iov[VHOST_NET_MAX_SG];
+       struct iovec hdr[VHOST_NET_MAX_SG];
+       size_t hdr_size;
+       /* We use a kind of RCU to access private pointer.
+        * All readers access it from workqueue, which makes it possible to
+        * flush the workqueue instead of synchronize_rcu. Therefore readers do
+        * not need to call rcu_read_lock/rcu_read_unlock: the beginning of
+        * work item execution acts instead of rcu_read_lock() and the end of
+        * work item execution acts instead of rcu_read_lock().
+        * Writers use virtqueue mutex. */
+       void *private_data;
+       /* Log write descriptors */
+       void __user *log_base;
+       struct vhost_log log[VHOST_NET_MAX_SG];
+};
+
+struct vhost_dev {
+       /* Readers use RCU to access memory table pointer
+        * log base pointer and features.
+        * Writers use mutex below.*/
+       struct vhost_memory *memory;
+       struct mm_struct *mm;
+       struct mutex mutex;
+       unsigned acked_features;
+       struct vhost_virtqueue *vqs;
+       int nvqs;
+       struct file *log_file;
+       struct eventfd_ctx *log_ctx;
+};
+
+long vhost_dev_init(struct vhost_dev *, struct vhost_virtqueue *vqs, int nvqs);
+long vhost_dev_check_owner(struct vhost_dev *);
+long vhost_dev_reset_owner(struct vhost_dev *);
+void vhost_dev_cleanup(struct vhost_dev *);
+long vhost_dev_ioctl(struct vhost_dev *, unsigned int ioctl, unsigned long arg);
+int vhost_vq_access_ok(struct vhost_virtqueue *vq);
+int vhost_log_access_ok(struct vhost_dev *);
+
+unsigned vhost_get_vq_desc(struct vhost_dev *, struct vhost_virtqueue *,
+                          struct iovec iov[], unsigned int iov_count,
+                          unsigned int *out_num, unsigned int *in_num,
+                          struct vhost_log *log, unsigned int *log_num);
+void vhost_discard_vq_desc(struct vhost_virtqueue *);
+
+int vhost_add_used(struct vhost_virtqueue *, unsigned int head, int len);
+void vhost_signal(struct vhost_dev *, struct vhost_virtqueue *);
+void vhost_add_used_and_signal(struct vhost_dev *, struct vhost_virtqueue *,
+                              unsigned int head, int len);
+void vhost_disable_notify(struct vhost_virtqueue *);
+bool vhost_enable_notify(struct vhost_virtqueue *);
+
+int vhost_log_write(struct vhost_virtqueue *vq, struct vhost_log *log,
+                   unsigned int log_num, u64 len);
+
+int vhost_init(void);
+void vhost_cleanup(void);
+
+#define vq_err(vq, fmt, ...) do {                                  \
+               pr_debug(pr_fmt(fmt), ##__VA_ARGS__);       \
+               if ((vq)->error_ctx)                               \
+                               eventfd_signal((vq)->error_ctx, 1);\
+       } while (0)
+
+enum {
+       VHOST_FEATURES = (1 << VIRTIO_F_NOTIFY_ON_EMPTY) |
+                        (1 << VIRTIO_RING_F_INDIRECT_DESC) |
+                        (1 << VHOST_F_LOG_ALL) |
+                        (1 << VHOST_NET_F_VIRTIO_NET_HDR),
+};
+
+static inline int vhost_has_feature(struct vhost_dev *dev, int bit)
+{
+       unsigned acked_features = rcu_dereference(dev->acked_features);
+       return acked_features & (1 << bit);
+}
+
+#endif
index fbd2ecde93e409ea9287d068d3f2322297c910cc..71929ee00d698b40f32d22b428e93b5f7dfcfbd4 100644 (file)
@@ -334,6 +334,30 @@ static bool vring_enable_cb(struct virtqueue *_vq)
        return true;
 }
 
+static void *vring_detach_unused_buf(struct virtqueue *_vq)
+{
+       struct vring_virtqueue *vq = to_vvq(_vq);
+       unsigned int i;
+       void *buf;
+
+       START_USE(vq);
+
+       for (i = 0; i < vq->vring.num; i++) {
+               if (!vq->data[i])
+                       continue;
+               /* detach_buf clears data, so grab it now. */
+               buf = vq->data[i];
+               detach_buf(vq, i);
+               END_USE(vq);
+               return buf;
+       }
+       /* That should have freed everything. */
+       BUG_ON(vq->num_free != vq->vring.num);
+
+       END_USE(vq);
+       return NULL;
+}
+
 irqreturn_t vring_interrupt(int irq, void *_vq)
 {
        struct vring_virtqueue *vq = to_vvq(_vq);
@@ -360,6 +384,7 @@ static struct virtqueue_ops vring_vq_ops = {
        .kick = vring_kick,
        .disable_cb = vring_disable_cb,
        .enable_cb = vring_enable_cb,
+       .detach_unused_buf = vring_detach_unused_buf,
 };
 
 struct virtqueue *vring_new_virtqueue(unsigned int num,
index 756f831cbdd557236057ede228bfdb9481559c97..d93080748a91877cb71a6450f5318cb8dcdbf6a8 100644 (file)
@@ -362,6 +362,7 @@ unifdef-y += uio.h
 unifdef-y += unistd.h
 unifdef-y += usbdevice_fs.h
 unifdef-y += utsname.h
+unifdef-y += vhost.h
 unifdef-y += videodev2.h
 unifdef-y += videodev.h
 unifdef-y += virtio_config.h
index 3db7767d2a175b9caf61ec4d98de415f7c24f6b6..c8c660a79f907657af7349fd78d0eb21099a88a0 100644 (file)
@@ -38,6 +38,7 @@ struct can_priv {
 
        enum can_state state;
        u32 ctrlmode;
+       u32 ctrlmode_supported;
 
        int restart_ms;
        struct timer_list restart_timer;
@@ -60,6 +61,21 @@ struct can_priv {
  */
 #define get_can_dlc(i) (min_t(__u8, (i), 8))
 
+/* Drop a given socketbuffer if it does not contain a valid CAN frame. */
+static inline int can_dropped_invalid_skb(struct net_device *dev,
+                                         struct sk_buff *skb)
+{
+       const struct can_frame *cf = (struct can_frame *)skb->data;
+
+       if (unlikely(skb->len != sizeof(*cf) || cf->can_dlc > 8)) {
+               kfree_skb(skb);
+               dev->stats.tx_dropped++;
+               return 1;
+       }
+
+       return 0;
+}
+
 struct net_device *alloc_candev(int sizeof_priv, unsigned int echo_skb_max);
 void free_candev(struct net_device *dev);
 
index 9ecbb7871c0ed039c036f999ea3d14047c29a381..c818335fbb132e6d2d7a82fd6638702c305a5f22 100644 (file)
@@ -80,6 +80,7 @@ struct can_ctrlmode {
 #define CAN_CTRLMODE_LOOPBACK  0x1     /* Loopback mode */
 #define CAN_CTRLMODE_LISTENONLY        0x2     /* Listen-only mode */
 #define CAN_CTRLMODE_3_SAMPLES 0x4     /* Triple sampling mode */
+#define CAN_CTRLMODE_ONE_SHOT  0x8     /* One-Shot mode */
 
 /*
  * CAN device statistics
index 163c840437d604ca9993b3fc70e3349a3fabd199..842701906ae9d2fbaa19d61f036542b146d0b210 100644 (file)
 #define IEEE80211_QOS_CTL_TID_MASK     0x000F
 #define IEEE80211_QOS_CTL_TAG1D_MASK   0x0007
 
+/* U-APSD queue for WMM IEs sent by AP */
+#define IEEE80211_WMM_IE_AP_QOSINFO_UAPSD      (1<<7)
+
+/* U-APSD queues for WMM IEs sent by STA */
+#define IEEE80211_WMM_IE_STA_QOSINFO_AC_VO     (1<<0)
+#define IEEE80211_WMM_IE_STA_QOSINFO_AC_VI     (1<<1)
+#define IEEE80211_WMM_IE_STA_QOSINFO_AC_BK     (1<<2)
+#define IEEE80211_WMM_IE_STA_QOSINFO_AC_BE     (1<<3)
+#define IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK   0x0f
+
+/* U-APSD max SP length for WMM IEs sent by STA */
+#define IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL    0x00
+#define IEEE80211_WMM_IE_STA_QOSINFO_SP_2      0x01
+#define IEEE80211_WMM_IE_STA_QOSINFO_SP_4      0x02
+#define IEEE80211_WMM_IE_STA_QOSINFO_SP_6      0x03
+#define IEEE80211_WMM_IE_STA_QOSINFO_SP_MASK   0x03
+#define IEEE80211_WMM_IE_STA_QOSINFO_SP_SHIFT  5
+
 struct ieee80211_hdr {
        __le16 frame_control;
        __le16 duration_id;
@@ -130,6 +148,25 @@ struct ieee80211_hdr {
        u8 addr4[6];
 } __attribute__ ((packed));
 
+struct ieee80211_hdr_3addr {
+       __le16 frame_control;
+       __le16 duration_id;
+       u8 addr1[6];
+       u8 addr2[6];
+       u8 addr3[6];
+       __le16 seq_ctrl;
+} __attribute__ ((packed));
+
+struct ieee80211_qos_hdr {
+       __le16 frame_control;
+       __le16 duration_id;
+       u8 addr1[6];
+       u8 addr2[6];
+       u8 addr3[6];
+       __le16 seq_ctrl;
+       __le16 qos_ctrl;
+} __attribute__ ((packed));
+
 /**
  * ieee80211_has_tods - check if IEEE80211_FCTL_TODS is set
  * @fc: frame control bytes in little-endian byteorder
@@ -707,6 +744,10 @@ struct ieee80211_mgmt {
                                        u8 action;
                                        u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN];
                                } __attribute__ ((packed)) sa_query;
+                               struct {
+                                       u8 action;
+                                       u8 smps_control;
+                               } __attribute__ ((packed)) ht_smps;
                        } u;
                } __attribute__ ((packed)) action;
        } u;
@@ -771,7 +812,10 @@ struct ieee80211_bar {
 /**
  * struct ieee80211_mcs_info - MCS information
  * @rx_mask: RX mask
- * @rx_highest: highest supported RX rate
+ * @rx_highest: highest supported RX rate. If set represents
+ *     the highest supported RX data rate in units of 1 Mbps.
+ *     If this field is 0 this value should not be used to
+ *     consider the highest RX data rate supported.
  * @tx_params: TX parameters
  */
 struct ieee80211_mcs_info {
@@ -824,6 +868,7 @@ struct ieee80211_ht_cap {
 #define IEEE80211_HT_CAP_LDPC_CODING           0x0001
 #define IEEE80211_HT_CAP_SUP_WIDTH_20_40       0x0002
 #define IEEE80211_HT_CAP_SM_PS                 0x000C
+#define                IEEE80211_HT_CAP_SM_PS_SHIFT    2
 #define IEEE80211_HT_CAP_GRN_FLD               0x0010
 #define IEEE80211_HT_CAP_SGI_20                        0x0020
 #define IEEE80211_HT_CAP_SGI_40                        0x0040
@@ -839,6 +884,7 @@ struct ieee80211_ht_cap {
 /* 802.11n HT capability AMPDU settings (for ampdu_params_info) */
 #define IEEE80211_HT_AMPDU_PARM_FACTOR         0x03
 #define IEEE80211_HT_AMPDU_PARM_DENSITY                0x1C
+#define                IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT   2
 
 /*
  * Maximum length of AMPDU that the STA can receive.
@@ -922,12 +968,17 @@ struct ieee80211_ht_info {
 #define IEEE80211_MAX_AMPDU_BUF 0x40
 
 
-/* Spatial Multiplexing Power Save Modes */
+/* Spatial Multiplexing Power Save Modes (for capability) */
 #define WLAN_HT_CAP_SM_PS_STATIC       0
 #define WLAN_HT_CAP_SM_PS_DYNAMIC      1
 #define WLAN_HT_CAP_SM_PS_INVALID      2
 #define WLAN_HT_CAP_SM_PS_DISABLED     3
 
+/* for SM power control field lower two bits */
+#define WLAN_HT_SMPS_CONTROL_DISABLED  0
+#define WLAN_HT_SMPS_CONTROL_STATIC    1
+#define WLAN_HT_SMPS_CONTROL_DYNAMIC   3
+
 /* Authentication algorithms */
 #define WLAN_AUTH_OPEN 0
 #define WLAN_AUTH_SHARED_KEY 1
@@ -1071,12 +1122,12 @@ enum ieee80211_eid {
        WLAN_EID_TIM = 5,
        WLAN_EID_IBSS_PARAMS = 6,
        WLAN_EID_CHALLENGE = 16,
-       /* 802.11d */
+
        WLAN_EID_COUNTRY = 7,
        WLAN_EID_HP_PARAMS = 8,
        WLAN_EID_HP_TABLE = 9,
        WLAN_EID_REQUEST = 10,
-       /* 802.11e */
+
        WLAN_EID_QBSS_LOAD = 11,
        WLAN_EID_EDCA_PARAM_SET = 12,
        WLAN_EID_TSPEC = 13,
@@ -1099,7 +1150,7 @@ enum ieee80211_eid {
        WLAN_EID_PREP = 69,
        WLAN_EID_PERR = 70,
        WLAN_EID_RANN = 49,     /* compatible with FreeBSD */
-       /* 802.11h */
+
        WLAN_EID_PWR_CONSTRAINT = 32,
        WLAN_EID_PWR_CAPABILITY = 33,
        WLAN_EID_TPC_REQUEST = 34,
@@ -1110,20 +1161,41 @@ enum ieee80211_eid {
        WLAN_EID_MEASURE_REPORT = 39,
        WLAN_EID_QUIET = 40,
        WLAN_EID_IBSS_DFS = 41,
-       /* 802.11g */
+
        WLAN_EID_ERP_INFO = 42,
        WLAN_EID_EXT_SUPP_RATES = 50,
-       /* 802.11n */
+
        WLAN_EID_HT_CAPABILITY = 45,
        WLAN_EID_HT_INFORMATION = 61,
-       /* 802.11i */
+
        WLAN_EID_RSN = 48,
-       WLAN_EID_TIMEOUT_INTERVAL = 56,
-       WLAN_EID_MMIE = 76 /* 802.11w */,
+       WLAN_EID_MMIE = 76,
        WLAN_EID_WPA = 221,
        WLAN_EID_GENERIC = 221,
        WLAN_EID_VENDOR_SPECIFIC = 221,
-       WLAN_EID_QOS_PARAMETER = 222
+       WLAN_EID_QOS_PARAMETER = 222,
+
+       WLAN_EID_AP_CHAN_REPORT = 51,
+       WLAN_EID_NEIGHBOR_REPORT = 52,
+       WLAN_EID_RCPI = 53,
+       WLAN_EID_BSS_AVG_ACCESS_DELAY = 63,
+       WLAN_EID_ANTENNA_INFO = 64,
+       WLAN_EID_RSNI = 65,
+       WLAN_EID_MEASUREMENT_PILOT_TX_INFO = 66,
+       WLAN_EID_BSS_AVAILABLE_CAPACITY = 67,
+       WLAN_EID_BSS_AC_ACCESS_DELAY = 68,
+       WLAN_EID_RRM_ENABLED_CAPABILITIES = 70,
+       WLAN_EID_MULTIPLE_BSSID = 71,
+
+       WLAN_EID_MOBILITY_DOMAIN = 54,
+       WLAN_EID_FAST_BSS_TRANSITION = 55,
+       WLAN_EID_TIMEOUT_INTERVAL = 56,
+       WLAN_EID_RIC_DATA = 57,
+       WLAN_EID_RIC_DESCRIPTOR = 75,
+
+       WLAN_EID_DSE_REGISTERED_LOCATION = 58,
+       WLAN_EID_SUPPORTED_REGULATORY_CLASSES = 59,
+       WLAN_EID_EXT_CHANSWITCH_ANN = 60,
 };
 
 /* Action category code */
@@ -1150,6 +1222,18 @@ enum ieee80211_spectrum_mgmt_actioncode {
        WLAN_ACTION_SPCT_CHL_SWITCH = 4,
 };
 
+/* HT action codes */
+enum ieee80211_ht_actioncode {
+       WLAN_HT_ACTION_NOTIFY_CHANWIDTH = 0,
+       WLAN_HT_ACTION_SMPS = 1,
+       WLAN_HT_ACTION_PSMP = 2,
+       WLAN_HT_ACTION_PCO_PHASE = 3,
+       WLAN_HT_ACTION_CSI = 4,
+       WLAN_HT_ACTION_NONCOMPRESSED_BF = 5,
+       WLAN_HT_ACTION_COMPRESSED_BF = 6,
+       WLAN_HT_ACTION_ASEL_IDX_FEEDBACK = 7,
+};
+
 /* Security key length */
 enum ieee80211_key_len {
        WLAN_KEY_LEN_WEP40 = 5,
index 3f5fd523b49d2281f6f0b8ed0193233bfd22a900..404abe00162c23026de3448ddcd3cd343962a5de 100644 (file)
@@ -86,4 +86,18 @@ struct tun_filter {
        __u8   addr[0][ETH_ALEN];
 };
 
+#ifdef __KERNEL__
+#if defined(CONFIG_TUN) || defined(CONFIG_TUN_MODULE)
+struct socket *tun_get_socket(struct file *);
+#else
+#include <linux/err.h>
+#include <linux/errno.h>
+struct file;
+struct socket;
+static inline struct socket *tun_get_socket(struct file *f)
+{
+       return ERR_PTR(-EINVAL);
+}
+#endif /* CONFIG_TUN */
+#endif /* __KERNEL__ */
 #endif /* __IF_TUN_H */
index 724c27e5d17355c0300294e30dbc52f6a19cc2dd..93fc2449af10e8dded6cbed23b4d979e4b5d10ef 100644 (file)
@@ -153,6 +153,7 @@ extern int sysctl_igmp_max_msf;
 struct ip_sf_socklist {
        unsigned int            sl_max;
        unsigned int            sl_count;
+       struct rcu_head         rcu;
        __be32                  sl_addr[0];
 };
 
@@ -170,6 +171,7 @@ struct ip_mc_socklist {
        struct ip_mreqn         multi;
        unsigned int            sfmode;         /* MCAST_{INCLUDE,EXCLUDE} */
        struct ip_sf_socklist   *sflist;
+       struct rcu_head         rcu;
 };
 
 struct ip_sf_list {
index b615649db129ea9add3ec53731ddad3f94ce1c0f..583c76f9c30fbef3a7427e5acf1e3159dfe65318 100644 (file)
@@ -84,6 +84,8 @@ struct in_addr {
 #define IP_ORIGDSTADDR       20
 #define IP_RECVORIGDSTADDR   IP_ORIGDSTADDR
 
+#define IP_MINTTL       21
+
 /* IP_MTU_DISCOVER values */
 #define IP_PMTUDISC_DONT               0       /* Never send DF frames */
 #define IP_PMTUDISC_WANT               1       /* Use per route hints  */
index b2304929434e27591a750ff7b8dbb066fa2b5759..cf257809771b9a538fbc969c3fcebefc0c386ec7 100644 (file)
@@ -89,6 +89,7 @@ static inline void ipv4_devconf_setall(struct in_device *in_dev)
 
 #define IN_DEV_LOG_MARTIANS(in_dev)    IN_DEV_ORCONF((in_dev), LOG_MARTIANS)
 #define IN_DEV_PROXY_ARP(in_dev)       IN_DEV_ORCONF((in_dev), PROXY_ARP)
+#define IN_DEV_PROXY_ARP_PVLAN(in_dev) IN_DEV_CONF_GET(in_dev, PROXY_ARP_PVLAN)
 #define IN_DEV_SHARED_MEDIA(in_dev)    IN_DEV_ORCONF((in_dev), SHARED_MEDIA)
 #define IN_DEV_TX_REDIRECTS(in_dev)    IN_DEV_ORCONF((in_dev), SEND_REDIRECTS)
 #define IN_DEV_SEC_REDIRECTS(in_dev)   IN_DEV_ORCONF((in_dev), \
index 7acb87a448726e91449ed1c9abee8611f04c94ac..d3e5e9da0c8206daea1d535871c8d9548b4962e7 100644 (file)
@@ -50,8 +50,7 @@ struct capi_ctr {
        u16  (*send_message)(struct capi_ctr *, struct sk_buff *skb);
        
        char *(*procinfo)(struct capi_ctr *);
-       int (*ctr_read_proc)(char *page, char **start, off_t off,
-                            int count, int *eof, struct capi_ctr *card);
+       const struct file_operations *proc_fops;
 
        /* filled in before calling ready callback */
        u8 manu[CAPI_MANUFACTURER_LEN];         /* CAPI_GET_MANUFACTURER */
index 7733585603f12894b95120b91bd7d9178919f1a7..ad7074ba81af33033f8d2d761bef8acb12699367 100644 (file)
@@ -36,6 +36,7 @@ enum llc_sockopts {
        LLC_OPT_BUSY_TMR_EXP,   /* busy state expire time (secs). */
        LLC_OPT_TX_WIN,         /* tx window size. */
        LLC_OPT_RX_WIN,         /* rx window size. */
+       LLC_OPT_PKTINFO,        /* ancillary packet information. */
        LLC_OPT_MAX
 };
 
@@ -70,6 +71,12 @@ enum llc_sockopts {
 #define LLC_SAP_RM     0xD4            /* Resource Management          */
 #define LLC_SAP_GLOBAL 0xFF            /* Global SAP.                  */
 
+struct llc_pktinfo {
+       int lpi_ifindex;
+       unsigned char lpi_sap;
+       unsigned char lpi_mac[IFHWADDRLEN];
+};
+
 #ifdef __KERNEL__
 #define LLC_SAP_DYN_START      0xC0
 #define LLC_SAP_DYN_STOP       0xDE
index adaf3c15e44974805c4444b4b2772e81496de4cd..8b5f7cc0fba6cd9f5f69f5521d00c788c2fe0dc9 100644 (file)
@@ -30,6 +30,7 @@
 #define HPET_MINOR             228
 #define FUSE_MINOR             229
 #define KVM_MINOR              232
+#define VHOST_NET_MINOR                233
 #define MISC_DYNAMIC_MINOR     255
 
 struct device;
index a3fccc85b1a0ef1732abd892963d639d8c9d93ad..93a32a5ca74f8c727b16df52bc1a3d947660cef3 100644 (file)
@@ -263,6 +263,11 @@ struct netdev_hw_addr_list {
        int                     count;
 };
 
+#define netdev_uc_count(dev) ((dev)->uc.count)
+#define netdev_uc_empty(dev) ((dev)->uc.count == 0)
+#define netdev_for_each_uc_addr(ha, dev) \
+       list_for_each_entry(ha, &dev->uc.list, list)
+
 struct hh_cache {
        struct hh_cache *hh_next;       /* Next entry                        */
        atomic_t        hh_refcnt;      /* number of users                   */
@@ -621,30 +626,21 @@ struct net_device_ops {
                                                   struct net_device *dev);
        u16                     (*ndo_select_queue)(struct net_device *dev,
                                                    struct sk_buff *skb);
-#define HAVE_CHANGE_RX_FLAGS
        void                    (*ndo_change_rx_flags)(struct net_device *dev,
                                                       int flags);
-#define HAVE_SET_RX_MODE
        void                    (*ndo_set_rx_mode)(struct net_device *dev);
-#define HAVE_MULTICAST
        void                    (*ndo_set_multicast_list)(struct net_device *dev);
-#define HAVE_SET_MAC_ADDR
        int                     (*ndo_set_mac_address)(struct net_device *dev,
                                                       void *addr);
-#define HAVE_VALIDATE_ADDR
        int                     (*ndo_validate_addr)(struct net_device *dev);
-#define HAVE_PRIVATE_IOCTL
        int                     (*ndo_do_ioctl)(struct net_device *dev,
                                                struct ifreq *ifr, int cmd);
-#define HAVE_SET_CONFIG
        int                     (*ndo_set_config)(struct net_device *dev,
                                                  struct ifmap *map);
-#define HAVE_CHANGE_MTU
        int                     (*ndo_change_mtu)(struct net_device *dev,
                                                  int new_mtu);
        int                     (*ndo_neigh_setup)(struct net_device *dev,
                                                   struct neigh_parms *);
-#define HAVE_TX_TIMEOUT
        void                    (*ndo_tx_timeout) (struct net_device *dev);
 
        struct net_device_stats* (*ndo_get_stats)(struct net_device *dev);
@@ -656,7 +652,6 @@ struct net_device_ops {
        void                    (*ndo_vlan_rx_kill_vid)(struct net_device *dev,
                                                        unsigned short vid);
 #ifdef CONFIG_NET_POLL_CONTROLLER
-#define HAVE_NETDEV_POLL
        void                    (*ndo_poll_controller)(struct net_device *dev);
 #endif
 #if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE)
@@ -1527,7 +1522,6 @@ extern int                netif_rx(struct sk_buff *skb);
 extern int             netif_rx_ni(struct sk_buff *skb);
 #define HAVE_NETIF_RECEIVE_SKB 1
 extern int             netif_receive_skb(struct sk_buff *skb);
-extern void            napi_gro_flush(struct napi_struct *napi);
 extern gro_result_t    dev_gro_receive(struct napi_struct *napi,
                                        struct sk_buff *skb);
 extern gro_result_t    napi_skb_finish(gro_result_t ret, struct sk_buff *skb);
index 2524267210d308894317f00e057c0d61bf81098d..a765ea89854989318d50d2371ad71dee60566048 100644 (file)
@@ -21,15 +21,20 @@ struct netpoll {
        __be32 local_ip, remote_ip;
        u16 local_port, remote_port;
        u8 remote_mac[ETH_ALEN];
+
+       struct list_head rx; /* rx_np list element */
 };
 
 struct netpoll_info {
        atomic_t refcnt;
+
        int rx_flags;
        spinlock_t rx_lock;
-       struct netpoll *rx_np; /* netpoll that registered an rx_hook */
+       struct list_head rx_np; /* netpolls that registered an rx_hook */
+
        struct sk_buff_head arp_tx; /* list of arp requests to reply to */
        struct sk_buff_head txq;
+
        struct delayed_work tx_work;
 };
 
@@ -51,7 +56,7 @@ static inline int netpoll_rx(struct sk_buff *skb)
        unsigned long flags;
        int ret = 0;
 
-       if (!npinfo || (!npinfo->rx_np && !npinfo->rx_flags))
+       if (!npinfo || (list_empty(&npinfo->rx_np) && !npinfo->rx_flags))
                return 0;
 
        spin_lock_irqsave(&npinfo->rx_lock, flags);
@@ -67,7 +72,7 @@ static inline int netpoll_rx_on(struct sk_buff *skb)
 {
        struct netpoll_info *npinfo = skb->dev->npinfo;
 
-       return npinfo && (npinfo->rx_np || npinfo->rx_flags);
+       return npinfo && (!list_empty(&npinfo->rx_np) || npinfo->rx_flags);
 }
 
 static inline int netpoll_receive_skb(struct sk_buff *skb)
index da8ea2e192736d66e07bfd6aa866bbf51a4dbb14..127a73015760ec4cb4b4b216e490c41cd77c07a1 100644 (file)
  * @NL80211_CMD_SET_WIPHY_NETNS: Set a wiphy's netns. Note that all devices
  *     associated with this wiphy must be down and will follow.
  *
+ * @NL80211_CMD_REMAIN_ON_CHANNEL: Request to remain awake on the specified
+ *     channel for the specified amount of time. This can be used to do
+ *     off-channel operations like transmit a Public Action frame and wait for
+ *     a response while being associated to an AP on another channel.
+ *     %NL80211_ATTR_WIPHY or %NL80211_ATTR_IFINDEX is used to specify which
+ *     radio is used. %NL80211_ATTR_WIPHY_FREQ is used to specify the
+ *     frequency for the operation and %NL80211_ATTR_WIPHY_CHANNEL_TYPE may be
+ *     optionally used to specify additional channel parameters.
+ *     %NL80211_ATTR_DURATION is used to specify the duration in milliseconds
+ *     to remain on the channel. This command is also used as an event to
+ *     notify when the requested duration starts (it may take a while for the
+ *     driver to schedule this time due to other concurrent needs for the
+ *     radio).
+ *     When called, this operation returns a cookie (%NL80211_ATTR_COOKIE)
+ *     that will be included with any events pertaining to this request;
+ *     the cookie is also used to cancel the request.
+ * @NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL: This command can be used to cancel a
+ *     pending remain-on-channel duration if the desired operation has been
+ *     completed prior to expiration of the originally requested duration.
+ *     %NL80211_ATTR_WIPHY or %NL80211_ATTR_IFINDEX is used to specify the
+ *     radio. The %NL80211_ATTR_COOKIE attribute must be given as well to
+ *     uniquely identify the request.
+ *     This command is also used as an event to notify when a requested
+ *     remain-on-channel duration has expired.
+ *
+ * @NL80211_CMD_SET_TX_BITRATE_MASK: Set the mask of rates to be used in TX
+ *     rate selection. %NL80211_ATTR_IFINDEX is used to specify the interface
+ *     and @NL80211_ATTR_TX_RATES the set of allowed rates.
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
@@ -353,6 +382,11 @@ enum nl80211_commands {
        NL80211_CMD_DEL_PMKSA,
        NL80211_CMD_FLUSH_PMKSA,
 
+       NL80211_CMD_REMAIN_ON_CHANNEL,
+       NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL,
+
+       NL80211_CMD_SET_TX_BITRATE_MASK,
+
        /* add new commands above here */
 
        /* used to define NL80211_CMD_MAX below */
@@ -402,6 +436,8 @@ enum nl80211_commands {
  * @NL80211_ATTR_WIPHY_RTS_THRESHOLD: RTS threshold (TX frames with length
  *     larger than or equal to this use RTS/CTS handshake); allowed range:
  *     0..65536, disable with (u32)-1; dot11RTSThreshold; u32
+ * @NL80211_ATTR_WIPHY_COVERAGE_CLASS: Coverage Class as defined by IEEE 802.11
+ *     section 7.3.2.9; dot11CoverageClass; u8
  *
  * @NL80211_ATTR_IFINDEX: network interface index of the device to operate on
  * @NL80211_ATTR_IFNAME: network interface name
@@ -606,6 +642,17 @@ enum nl80211_commands {
  * @NL80211_ATTR_MAX_NUM_PMKIDS: maximum number of PMKIDs a firmware can
  *     cache, a wiphy attribute.
  *
+ * @NL80211_ATTR_DURATION: Duration of an operation in milliseconds, u32.
+ *
+ * @NL80211_ATTR_COOKIE: Generic 64-bit cookie to identify objects.
+ *
+ * @NL80211_ATTR_TX_RATES: Nested set of attributes
+ *     (enum nl80211_tx_rate_attributes) describing TX rates per band. The
+ *     enum nl80211_band value is used as the index (nla_type() of the nested
+ *     data. If a band is not included, it will be configured to allow all
+ *     rates based on negotiated supported rates information. This attribute
+ *     is used with %NL80211_CMD_SET_TX_BITRATE_MASK.
+ *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
@@ -743,6 +790,14 @@ enum nl80211_attrs {
        NL80211_ATTR_PMKID,
        NL80211_ATTR_MAX_NUM_PMKIDS,
 
+       NL80211_ATTR_DURATION,
+
+       NL80211_ATTR_COOKIE,
+
+       NL80211_ATTR_WIPHY_COVERAGE_CLASS,
+
+       NL80211_ATTR_TX_RATES,
+
        /* add attributes here, update the policy in nl80211.c */
 
        __NL80211_ATTR_AFTER_LAST,
@@ -1323,13 +1378,20 @@ enum nl80211_channel_type {
  * @NL80211_BSS_BEACON_INTERVAL: beacon interval of the (I)BSS (u16)
  * @NL80211_BSS_CAPABILITY: capability field (CPU order, u16)
  * @NL80211_BSS_INFORMATION_ELEMENTS: binary attribute containing the
- *     raw information elements from the probe response/beacon (bin)
+ *     raw information elements from the probe response/beacon (bin);
+ *     if the %NL80211_BSS_BEACON_IES attribute is present, the IEs here are
+ *     from a Probe Response frame; otherwise they are from a Beacon frame.
+ *     However, if the driver does not indicate the source of the IEs, these
+ *     IEs may be from either frame subtype.
  * @NL80211_BSS_SIGNAL_MBM: signal strength of probe response/beacon
  *     in mBm (100 * dBm) (s32)
  * @NL80211_BSS_SIGNAL_UNSPEC: signal strength of the probe response/beacon
  *     in unspecified units, scaled to 0..100 (u8)
  * @NL80211_BSS_STATUS: status, if this BSS is "used"
  * @NL80211_BSS_SEEN_MS_AGO: age of this BSS entry in ms
+ * @NL80211_BSS_BEACON_IES: binary attribute containing the raw information
+ *     elements from a Beacon frame (bin); not present if no Beacon frame has
+ *     yet been received
  * @__NL80211_BSS_AFTER_LAST: internal
  * @NL80211_BSS_MAX: highest BSS attribute
  */
@@ -1345,6 +1407,7 @@ enum nl80211_bss {
        NL80211_BSS_SIGNAL_UNSPEC,
        NL80211_BSS_STATUS,
        NL80211_BSS_SEEN_MS_AGO,
+       NL80211_BSS_BEACON_IES,
 
        /* keep last */
        __NL80211_BSS_AFTER_LAST,
@@ -1442,4 +1505,33 @@ enum nl80211_key_attributes {
        NL80211_KEY_MAX = __NL80211_KEY_AFTER_LAST - 1
 };
 
+/**
+ * enum nl80211_tx_rate_attributes - TX rate set attributes
+ * @__NL80211_TXRATE_INVALID: invalid
+ * @NL80211_TXRATE_LEGACY: Legacy (non-MCS) rates allowed for TX rate selection
+ *     in an array of rates as defined in IEEE 802.11 7.3.2.2 (u8 values with
+ *     1 = 500 kbps) but without the IE length restriction (at most
+ *     %NL80211_MAX_SUPP_RATES in a single array).
+ * @__NL80211_TXRATE_AFTER_LAST: internal
+ * @NL80211_TXRATE_MAX: highest TX rate attribute
+ */
+enum nl80211_tx_rate_attributes {
+       __NL80211_TXRATE_INVALID,
+       NL80211_TXRATE_LEGACY,
+
+       /* keep last */
+       __NL80211_TXRATE_AFTER_LAST,
+       NL80211_TXRATE_MAX = __NL80211_TXRATE_AFTER_LAST - 1
+};
+
+/**
+ * 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)
+ */
+enum nl80211_band {
+       NL80211_BAND_2GHZ,
+       NL80211_BAND_5GHZ,
+};
+
 #endif /* __LINUX_NL80211_H */
index 05330fc5b436034aa1b361934e2180bd96266938..9590364fe8b53fa4082834c47ff64b322194fa47 100644 (file)
@@ -362,6 +362,8 @@ enum {
 #define RTAX_FEATURES RTAX_FEATURES
        RTAX_RTO_MIN,
 #define RTAX_RTO_MIN RTAX_RTO_MIN
+       RTAX_INITRWND,
+#define RTAX_INITRWND RTAX_INITRWND
        __RTAX_MAX
 };
 
diff --git a/include/linux/stmmac.h b/include/linux/stmmac.h
new file mode 100644 (file)
index 0000000..32bfd1a
--- /dev/null
@@ -0,0 +1,53 @@
+/*******************************************************************************
+
+  Header file for stmmac platform data
+
+  Copyright (C) 2009  STMicroelectronics Ltd
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
+*******************************************************************************/
+
+#ifndef __STMMAC_PLATFORM_DATA
+#define __STMMAC_PLATFORM_DATA
+
+/* platfrom data for platfrom device structure's platfrom_data field */
+
+/* Private data for the STM on-board ethernet driver */
+struct plat_stmmacenet_data {
+       int bus_id;
+       int pbl;
+       int has_gmac;
+       void (*fix_mac_speed)(void *priv, unsigned int speed);
+       void (*bus_setup)(unsigned long ioaddr);
+#ifdef CONFIG_STM_DRIVERS
+       struct stm_pad_config *pad_config;
+#endif
+       void *bsp_priv;
+};
+
+struct plat_stmmacphy_data {
+       int bus_id;
+       int phy_addr;
+       unsigned int phy_mask;
+       int interface;
+       int (*phy_reset)(void *priv);
+       void *priv;
+};
+#endif
+
index bd27fbc9db621eb6e96f365ed610d9a736cfcb3e..9f236cdcf3feb70b38135215b3eac00f4245e446 100644 (file)
@@ -483,6 +483,7 @@ enum
        NET_IPV4_CONF_ARP_NOTIFY=22,
        NET_IPV4_CONF_ACCEPT_LOCAL=23,
        NET_IPV4_CONF_SRC_VMARK=24,
+       NET_IPV4_CONF_PROXY_ARP_PVLAN=25,
        __NET_IPV4_CONF_MAX
 };
 
diff --git a/include/linux/vhost.h b/include/linux/vhost.h
new file mode 100644 (file)
index 0000000..e847f1e
--- /dev/null
@@ -0,0 +1,130 @@
+#ifndef _LINUX_VHOST_H
+#define _LINUX_VHOST_H
+/* Userspace interface for in-kernel virtio accelerators. */
+
+/* vhost is used to reduce the number of system calls involved in virtio.
+ *
+ * Existing virtio net code is used in the guest without modification.
+ *
+ * This header includes interface used by userspace hypervisor for
+ * device configuration.
+ */
+
+#include <linux/types.h>
+#include <linux/compiler.h>
+#include <linux/ioctl.h>
+#include <linux/virtio_config.h>
+#include <linux/virtio_ring.h>
+
+struct vhost_vring_state {
+       unsigned int index;
+       unsigned int num;
+};
+
+struct vhost_vring_file {
+       unsigned int index;
+       int fd; /* Pass -1 to unbind from file. */
+
+};
+
+struct vhost_vring_addr {
+       unsigned int index;
+       /* Option flags. */
+       unsigned int flags;
+       /* Flag values: */
+       /* Whether log address is valid. If set enables logging. */
+#define VHOST_VRING_F_LOG 0
+
+       /* Start of array of descriptors (virtually contiguous) */
+       __u64 desc_user_addr;
+       /* Used structure address. Must be 32 bit aligned */
+       __u64 used_user_addr;
+       /* Available structure address. Must be 16 bit aligned */
+       __u64 avail_user_addr;
+       /* Logging support. */
+       /* Log writes to used structure, at offset calculated from specified
+        * address. Address must be 32 bit aligned. */
+       __u64 log_guest_addr;
+};
+
+struct vhost_memory_region {
+       __u64 guest_phys_addr;
+       __u64 memory_size; /* bytes */
+       __u64 userspace_addr;
+       __u64 flags_padding; /* No flags are currently specified. */
+};
+
+/* All region addresses and sizes must be 4K aligned. */
+#define VHOST_PAGE_SIZE 0x1000
+
+struct vhost_memory {
+       __u32 nregions;
+       __u32 padding;
+       struct vhost_memory_region regions[0];
+};
+
+/* ioctls */
+
+#define VHOST_VIRTIO 0xAF
+
+/* Features bitmask for forward compatibility.  Transport bits are used for
+ * vhost specific features. */
+#define VHOST_GET_FEATURES     _IOR(VHOST_VIRTIO, 0x00, __u64)
+#define VHOST_SET_FEATURES     _IOW(VHOST_VIRTIO, 0x00, __u64)
+
+/* Set current process as the (exclusive) owner of this file descriptor.  This
+ * must be called before any other vhost command.  Further calls to
+ * VHOST_OWNER_SET fail until VHOST_OWNER_RESET is called. */
+#define VHOST_SET_OWNER _IO(VHOST_VIRTIO, 0x01)
+/* Give up ownership, and reset the device to default values.
+ * Allows subsequent call to VHOST_OWNER_SET to succeed. */
+#define VHOST_RESET_OWNER _IO(VHOST_VIRTIO, 0x02)
+
+/* Set up/modify memory layout */
+#define VHOST_SET_MEM_TABLE    _IOW(VHOST_VIRTIO, 0x03, struct vhost_memory)
+
+/* Write logging setup. */
+/* Memory writes can optionally be logged by setting bit at an offset
+ * (calculated from the physical address) from specified log base.
+ * The bit is set using an atomic 32 bit operation. */
+/* Set base address for logging. */
+#define VHOST_SET_LOG_BASE _IOW(VHOST_VIRTIO, 0x04, __u64)
+/* Specify an eventfd file descriptor to signal on log write. */
+#define VHOST_SET_LOG_FD _IOW(VHOST_VIRTIO, 0x07, int)
+
+/* Ring setup. */
+/* Set number of descriptors in ring. This parameter can not
+ * be modified while ring is running (bound to a device). */
+#define VHOST_SET_VRING_NUM _IOW(VHOST_VIRTIO, 0x10, struct vhost_vring_state)
+/* Set addresses for the ring. */
+#define VHOST_SET_VRING_ADDR _IOW(VHOST_VIRTIO, 0x11, struct vhost_vring_addr)
+/* Base value where queue looks for available descriptors */
+#define VHOST_SET_VRING_BASE _IOW(VHOST_VIRTIO, 0x12, struct vhost_vring_state)
+/* Get accessor: reads index, writes value in num */
+#define VHOST_GET_VRING_BASE _IOWR(VHOST_VIRTIO, 0x12, struct vhost_vring_state)
+
+/* The following ioctls use eventfd file descriptors to signal and poll
+ * for events. */
+
+/* Set eventfd to poll for added buffers */
+#define VHOST_SET_VRING_KICK _IOW(VHOST_VIRTIO, 0x20, struct vhost_vring_file)
+/* Set eventfd to signal when buffers have beed used */
+#define VHOST_SET_VRING_CALL _IOW(VHOST_VIRTIO, 0x21, struct vhost_vring_file)
+/* Set eventfd to signal an error */
+#define VHOST_SET_VRING_ERR _IOW(VHOST_VIRTIO, 0x22, struct vhost_vring_file)
+
+/* VHOST_NET specific defines */
+
+/* Attach virtio net ring to a raw socket, or tap device.
+ * The socket must be already bound to an ethernet device, this device will be
+ * used for transmit.  Pass fd -1 to unbind from the socket and the transmit
+ * device.  This can be used to stop the ring (e.g. for migration). */
+#define VHOST_NET_SET_BACKEND _IOW(VHOST_VIRTIO, 0x30, struct vhost_vring_file)
+
+/* Feature bits */
+/* Log all write descriptors. Can be changed while device is active. */
+#define VHOST_F_LOG_ALL 26
+/* vhost-net should add virtio_net_hdr for RX, and strip for TX packets. */
+#define VHOST_NET_F_VIRTIO_NET_HDR 27
+
+#endif
index 057a2e0107589763411cfeea1bd6e7e4b189a24c..f508c651e53dec96f7d27a840979fd80a42e0d10 100644 (file)
@@ -51,6 +51,9 @@ struct virtqueue {
  *     This re-enables callbacks; it returns "false" if there are pending
  *     buffers in the queue, to detect a possible race between the driver
  *     checking for more work, and enabling callbacks.
+ * @detach_unused_buf: detach first unused buffer
+ *     vq: the struct virtqueue we're talking about.
+ *     Returns NULL or the "data" token handed to add_buf
  *
  * Locking rules are straightforward: the driver is responsible for
  * locking.  No two operations may be invoked simultaneously, with the exception
@@ -71,6 +74,7 @@ struct virtqueue_ops {
 
        void (*disable_cb)(struct virtqueue *vq);
        bool (*enable_cb)(struct virtqueue *vq);
+       void *(*detach_unused_buf)(struct virtqueue *vq);
 };
 
 /**
index 0884b9a0f778df6d929ceafc219545d22538e9cf..2af52704e670590d9792a0d0a4b44e159e6104ef 100644 (file)
@@ -39,8 +39,8 @@
  * @IEEE80211_BAND_5GHZ: around 5GHz band (4.9-5.7)
  */
 enum ieee80211_band {
-       IEEE80211_BAND_2GHZ,
-       IEEE80211_BAND_5GHZ,
+       IEEE80211_BAND_2GHZ = NL80211_BAND_2GHZ,
+       IEEE80211_BAND_5GHZ = NL80211_BAND_5GHZ,
 
        /* keep last */
        IEEE80211_NUM_BANDS
@@ -626,8 +626,14 @@ enum cfg80211_signal_type {
  * @beacon_interval: the beacon interval as from the frame
  * @capability: the capability field in host byte order
  * @information_elements: the information elements (Note that there
- *     is no guarantee that these are well-formed!)
+ *     is no guarantee that these are well-formed!); this is a pointer to
+ *     either the beacon_ies or proberesp_ies depending on whether Probe
+ *     Response frame has been received
  * @len_information_elements: total length of the information elements
+ * @beacon_ies: the information elements from the last Beacon frame
+ * @len_beacon_ies: total length of the beacon_ies
+ * @proberesp_ies: the information elements from the last Probe Response frame
+ * @len_proberesp_ies: total length of the proberesp_ies
  * @signal: signal strength value (type depends on the wiphy's signal_type)
  * @free_priv: function pointer to free private data
  * @priv: private area for driver use, has at least wiphy->bss_priv_size bytes
@@ -641,6 +647,10 @@ struct cfg80211_bss {
        u16 capability;
        u8 *information_elements;
        size_t len_information_elements;
+       u8 *beacon_ies;
+       size_t len_beacon_ies;
+       u8 *proberesp_ies;
+       size_t len_proberesp_ies;
 
        s32 signal;
 
@@ -837,6 +847,7 @@ enum wiphy_params_flags {
        WIPHY_PARAM_RETRY_LONG          = 1 << 1,
        WIPHY_PARAM_FRAG_THRESHOLD      = 1 << 2,
        WIPHY_PARAM_RTS_THRESHOLD       = 1 << 3,
+       WIPHY_PARAM_COVERAGE_CLASS      = 1 << 4,
 };
 
 /**
@@ -856,20 +867,11 @@ enum tx_power_setting {
  * cfg80211_bitrate_mask - masks for bitrate control
  */
 struct cfg80211_bitrate_mask {
-/*
- * As discussed in Berlin, this struct really
- * should look like this:
-
        struct {
                u32 legacy;
-               u8 mcs[IEEE80211_HT_MCS_MASK_LEN];
+               /* TODO: add support for masking MCS rates; e.g.: */
+               /* u8 mcs[IEEE80211_HT_MCS_MASK_LEN]; */
        } control[IEEE80211_NUM_BANDS];
-
- * Since we can always fix in-kernel users, let's keep
- * it simpler for now:
- */
-       u32 fixed;   /* fixed bitrate, 0 == not fixed */
-       u32 maxrate; /* in kbps, 0 == no limit */
 };
 /**
  * struct cfg80211_pmksa - PMK Security Association
@@ -988,6 +990,15 @@ struct cfg80211_pmksa {
  *
  * @dump_survey: get site survey information.
  *
+ * @remain_on_channel: Request the driver to remain awake on the specified
+ *     channel for the specified duration to complete an off-channel
+ *     operation (e.g., public action frame exchange). When the driver is
+ *     ready on the requested channel, it must indicate this with an event
+ *     notification by calling cfg80211_ready_on_channel().
+ * @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.
+ *
  * @testmode_cmd: run a test mode command
  *
  * @set_pmksa: Cache a PMKID for a BSSID. This is mostly useful for fullmac
@@ -1123,6 +1134,16 @@ struct cfg80211_ops {
                             struct cfg80211_pmksa *pmksa);
        int     (*flush_pmksa)(struct wiphy *wiphy, struct net_device *netdev);
 
+       int     (*remain_on_channel)(struct wiphy *wiphy,
+                                    struct net_device *dev,
+                                    struct ieee80211_channel *chan,
+                                    enum nl80211_channel_type channel_type,
+                                    unsigned int duration,
+                                    u64 *cookie);
+       int     (*cancel_remain_on_channel)(struct wiphy *wiphy,
+                                           struct net_device *dev,
+                                           u64 cookie);
+
        /* some temporary stuff to finish wext */
        int     (*set_power_mgmt)(struct wiphy *wiphy, struct net_device *dev,
                                  bool enabled, int timeout);
@@ -1217,6 +1238,7 @@ struct wiphy {
        u8 retry_long;
        u32 frag_threshold;
        u32 rts_threshold;
+       u8 coverage_class;
 
        char fw_version[ETHTOOL_BUSINFO_LEN];
        u32 hw_version;
@@ -1578,7 +1600,7 @@ unsigned int ieee80211_hdrlen(__le16 fc);
  * @addr: the device MAC address
  * @iftype: the virtual interface type
  */
-int ieee80211_data_to_8023(struct sk_buff *skb, u8 *addr,
+int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
                           enum nl80211_iftype iftype);
 
 /**
@@ -1589,9 +1611,27 @@ int ieee80211_data_to_8023(struct sk_buff *skb, u8 *addr,
  * @bssid: the network bssid (used only for iftype STATION and ADHOC)
  * @qos: build 802.11 QoS data frame
  */
-int ieee80211_data_from_8023(struct sk_buff *skb, u8 *addr,
+int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr,
                             enum nl80211_iftype iftype, u8 *bssid, bool qos);
 
+/**
+ * ieee80211_amsdu_to_8023s - decode an IEEE 802.11n A-MSDU frame
+ *
+ * Decode an IEEE 802.11n A-MSDU frame and convert it to a list of
+ * 802.3 frames. The @list will be empty if the decode fails. The
+ * @skb is consumed after the function returns.
+ *
+ * @skb: The input IEEE 802.11n A-MSDU frame.
+ * @list: The output list of 802.3 frames. It must be allocated and
+ *     initialized by by the caller.
+ * @addr: The device MAC address.
+ * @iftype: The device interface type.
+ * @extra_headroom: The hardware extra headroom for SKBs in the @list.
+ */
+void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
+                             const u8 *addr, enum nl80211_iftype iftype,
+                             const unsigned int extra_headroom);
+
 /**
  * cfg80211_classify8021d - determine the 802.1p/1d tag for a data frame
  * @skb: the data frame
@@ -2129,5 +2169,45 @@ void cfg80211_roamed(struct net_device *dev, const u8 *bssid,
 void cfg80211_disconnected(struct net_device *dev, u16 reason,
                           u8 *ie, size_t ie_len, gfp_t gfp);
 
+/**
+ * cfg80211_ready_on_channel - notification of remain_on_channel start
+ * @dev: network device
+ * @cookie: the request cookie
+ * @chan: The current channel (from remain_on_channel request)
+ * @channel_type: Channel type
+ * @duration: Duration in milliseconds that the driver intents to remain on the
+ *     channel
+ * @gfp: allocation flags
+ */
+void cfg80211_ready_on_channel(struct net_device *dev, u64 cookie,
+                              struct ieee80211_channel *chan,
+                              enum nl80211_channel_type channel_type,
+                              unsigned int duration, gfp_t gfp);
+
+/**
+ * cfg80211_remain_on_channel_expired - remain_on_channel duration expired
+ * @dev: network device
+ * @cookie: the request cookie
+ * @chan: The current channel (from remain_on_channel request)
+ * @channel_type: Channel type
+ * @gfp: allocation flags
+ */
+void cfg80211_remain_on_channel_expired(struct net_device *dev,
+                                       u64 cookie,
+                                       struct ieee80211_channel *chan,
+                                       enum nl80211_channel_type channel_type,
+                                       gfp_t gfp);
+
+
+/**
+ * cfg80211_new_sta - notify userspace about station
+ *
+ * @dev: the netdev
+ * @mac_addr: the station's address
+ * @sinfo: the station information
+ * @gfp: allocation flags
+ */
+void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr,
+                     struct station_info *sinfo, gfp_t gfp);
 
 #endif /* __NET_CFG80211_H */
index 39c4a5963e12a8cece4cd7c4d2bd9a8ee192361d..ce078cda6b748a61eadfcf16315b84e8893aeded 100644 (file)
@@ -83,8 +83,6 @@ struct dst_entry {
         * (L1_CACHE_SIZE would be too much)
         */
 #ifdef CONFIG_64BIT
-       long                    __pad_to_align_refcnt[2];
-#else
        long                    __pad_to_align_refcnt[1];
 #endif
        /*
index dfa72d4e89071c01ee02044864411c46f4d5b2cb..15b3dfe9fce8334611ba4549e3d32353585e036d 100644 (file)
@@ -28,7 +28,7 @@ struct icmp_err {
   unsigned     fatal:1;
 };
 
-extern struct icmp_err icmp_err_convert[];
+extern const struct icmp_err icmp_err_convert[];
 #define ICMP_INC_STATS(net, field)     SNMP_INC_STATS((net)->mib.icmp_statistics, field)
 #define ICMP_INC_STATS_BH(net, field)  SNMP_INC_STATS_BH((net)->mib.icmp_statistics, field)
 #define ICMPMSGOUT_INC_STATS(net, field)       SNMP_INC_STATS((net)->mib.icmpmsg_statistics, field+256)
index bd4c53f75ac02576eacc0e5ea4da33704fe57d34..83fd34437cf1f3eb7509a35856573c3ede5b171c 100644 (file)
@@ -122,10 +122,12 @@ struct inet_sock {
        __be32                  inet_saddr;
        __s16                   uc_ttl;
        __u16                   cmsg_flags;
-       struct ip_options       *opt;
        __be16                  inet_sport;
        __u16                   inet_id;
+
+       struct ip_options       *opt;
        __u8                    tos;
+       __u8                    min_ttl;
        __u8                    mc_ttl;
        __u8                    pmtudisc;
        __u8                    recverr:1,
index 7940da1606e7514697d45bf8be3f93bede4ddb0b..5503b74ab170326ae34236ed8f8ffb9065d0e196 100644 (file)
@@ -16,6 +16,9 @@
 #include <linux/if_ether.h>
 #include <linux/list.h>
 #include <linux/spinlock.h>
+#include <linux/rculist_nulls.h>
+#include <linux/hash.h>
+#include <linux/jhash.h>
 
 #include <asm/atomic.h>
 
@@ -31,6 +34,12 @@ struct llc_addr {
 #define LLC_SAP_STATE_INACTIVE 1
 #define LLC_SAP_STATE_ACTIVE   2
 
+#define LLC_SK_DEV_HASH_BITS 6
+#define LLC_SK_DEV_HASH_ENTRIES (1<<LLC_SK_DEV_HASH_BITS)
+
+#define LLC_SK_LADDR_HASH_BITS 6
+#define LLC_SK_LADDR_HASH_ENTRIES (1<<LLC_SK_LADDR_HASH_BITS)
+
 /**
  * struct llc_sap - Defines the SAP component
  *
@@ -53,18 +62,38 @@ struct llc_sap {
                                     struct net_device *orig_dev);
        struct llc_addr  laddr;
        struct list_head node;
-       struct {
-               rwlock_t          lock;
-               struct hlist_head list;
-       } sk_list;
+       spinlock_t sk_lock;
+       int sk_count;
+       struct hlist_nulls_head sk_laddr_hash[LLC_SK_LADDR_HASH_ENTRIES];
+       struct hlist_head sk_dev_hash[LLC_SK_DEV_HASH_ENTRIES];
 };
 
+static inline
+struct hlist_head *llc_sk_dev_hash(struct llc_sap *sap, int ifindex)
+{
+       return &sap->sk_dev_hash[ifindex % LLC_SK_DEV_HASH_ENTRIES];
+}
+
+static inline
+u32 llc_sk_laddr_hashfn(struct llc_sap *sap, const struct llc_addr *laddr)
+{
+       return hash_32(jhash(laddr->mac, sizeof(laddr->mac), 0),
+                      LLC_SK_LADDR_HASH_BITS);
+}
+
+static inline
+struct hlist_nulls_head *llc_sk_laddr_hash(struct llc_sap *sap,
+                                          const struct llc_addr *laddr)
+{
+       return &sap->sk_laddr_hash[llc_sk_laddr_hashfn(sap, laddr)];
+}
+
 #define LLC_DEST_INVALID         0      /* Invalid LLC PDU type */
 #define LLC_DEST_SAP             1      /* Type 1 goes here */
 #define LLC_DEST_CONN            2      /* Type 2 goes here */
 
 extern struct list_head llc_sap_list;
-extern rwlock_t llc_sap_list_lock;
+extern spinlock_t llc_sap_list_lock;
 
 extern int llc_rcv(struct sk_buff *skb, struct net_device *dev,
                   struct packet_type *pt, struct net_device *orig_dev);
index e2374e34989f07d9c39d7bdf30c44266bc1f5ad0..2f97d8ddce924dbfc61f473896cacda3cfb70456 100644 (file)
@@ -76,6 +76,8 @@ struct llc_sock {
        u32                 rx_pdu_hdr;    /* used for saving header of last pdu
                                              received and caused sending FRMR.
                                              Used for resending FRMR */
+       u32                 cmsg_flags;
+       struct hlist_node   dev_hash_node;
 };
 
 static inline struct llc_sock *llc_sk(const struct sock *sk)
index 0bf369752274f39658ded037e961900895431058..c90047de4428583d7f836de64f11fdd3978966a4 100644 (file)
@@ -107,12 +107,14 @@ enum ieee80211_max_queues {
  *     2^n-1 in the range 1..32767]
  * @cw_max: maximum contention window [like @cw_min]
  * @txop: maximum burst time in units of 32 usecs, 0 meaning disabled
+ * @uapsd: is U-APSD mode enabled for the queue
  */
 struct ieee80211_tx_queue_params {
        u16 txop;
        u16 cw_min;
        u16 cw_max;
        u8 aifs;
+       bool uapsd;
 };
 
 /**
@@ -255,9 +257,6 @@ struct ieee80211_bss_conf {
  * @IEEE80211_TX_CTL_RATE_CTRL_PROBE: internal to mac80211, can be
  *     set by rate control algorithms to indicate probe rate, will
  *     be cleared for fragmented frames (except on the last fragment)
- * @IEEE80211_TX_INTFL_RCALGO: mac80211 internal flag, do not test or
- *     set this flag in the driver; indicates that the rate control
- *     algorithm was used and should be notified of TX status
  * @IEEE80211_TX_INTFL_NEED_TXPROCESSING: completely internal to mac80211,
  *     used to indicate that a pending frame requires TX processing before
  *     it can be sent out.
@@ -287,7 +286,6 @@ enum mac80211_tx_control_flags {
        IEEE80211_TX_STAT_AMPDU                 = BIT(10),
        IEEE80211_TX_STAT_AMPDU_NO_BACK         = BIT(11),
        IEEE80211_TX_CTL_RATE_CTRL_PROBE        = BIT(12),
-       IEEE80211_TX_INTFL_RCALGO               = BIT(13),
        IEEE80211_TX_INTFL_NEED_TXPROCESSING    = BIT(14),
        IEEE80211_TX_INTFL_RETRIED              = BIT(15),
        IEEE80211_TX_INTFL_DONT_ENCRYPT         = BIT(16),
@@ -571,7 +569,13 @@ struct ieee80211_rx_status {
  * @IEEE80211_CONF_MONITOR: there's a monitor interface present -- use this
  *     to determine for example whether to calculate timestamps for packets
  *     or not, do not use instead of filter flags!
- * @IEEE80211_CONF_PS: Enable 802.11 power save mode (managed mode only)
+ * @IEEE80211_CONF_PS: Enable 802.11 power save mode (managed mode only).
+ *     This is the power save mode defined by IEEE 802.11-2007 section 11.2,
+ *     meaning that the hardware still wakes up for beacons, is able to
+ *     transmit frames and receive the possible acknowledgment frames.
+ *     Not to be confused with hardware specific wakeup/sleep states,
+ *     driver is responsible for that. See the section "Powersave support"
+ *     for more.
  * @IEEE80211_CONF_IDLE: The device is running, but idle; if the flag is set
  *     the driver should be prepared to handle configuration requests but
  *     may turn the device off as much as possible. Typically, this flag will
@@ -595,8 +599,10 @@ enum ieee80211_conf_flags {
  * @IEEE80211_CONF_CHANGE_CHANNEL: the channel/channel_type changed
  * @IEEE80211_CONF_CHANGE_RETRY_LIMITS: retry limits changed
  * @IEEE80211_CONF_CHANGE_IDLE: Idle flag changed
+ * @IEEE80211_CONF_CHANGE_SMPS: Spatial multiplexing powersave mode changed
  */
 enum ieee80211_conf_changed {
+       IEEE80211_CONF_CHANGE_SMPS              = BIT(1),
        IEEE80211_CONF_CHANGE_LISTEN_INTERVAL   = BIT(2),
        IEEE80211_CONF_CHANGE_MONITOR           = BIT(3),
        IEEE80211_CONF_CHANGE_PS                = BIT(4),
@@ -606,6 +612,25 @@ enum ieee80211_conf_changed {
        IEEE80211_CONF_CHANGE_IDLE              = BIT(8),
 };
 
+/**
+ * enum ieee80211_smps_mode - spatial multiplexing power save mode
+ *
+ * @IEEE80211_SMPS_AUTOMATIC: automatic
+ * @IEEE80211_SMPS_OFF: off
+ * @IEEE80211_SMPS_STATIC: static
+ * @IEEE80211_SMPS_DYNAMIC: dynamic
+ * @IEEE80211_SMPS_NUM_MODES: internal, don't use
+ */
+enum ieee80211_smps_mode {
+       IEEE80211_SMPS_AUTOMATIC,
+       IEEE80211_SMPS_OFF,
+       IEEE80211_SMPS_STATIC,
+       IEEE80211_SMPS_DYNAMIC,
+
+       /* keep last */
+       IEEE80211_SMPS_NUM_MODES,
+};
+
 /**
  * struct ieee80211_conf - configuration of the device
  *
@@ -634,6 +659,10 @@ enum ieee80211_conf_changed {
  * @short_frame_max_tx_count: Maximum number of transmissions for a "short"
  *    frame, called "dot11ShortRetryLimit" in 802.11, but actually means the
  *    number of transmissions not the number of retries
+ *
+ * @smps_mode: spatial multiplexing powersave mode; note that
+ *     %IEEE80211_SMPS_STATIC is used when the device is not
+ *     configured for an HT channel
  */
 struct ieee80211_conf {
        u32 flags;
@@ -646,6 +675,7 @@ struct ieee80211_conf {
 
        struct ieee80211_channel *channel;
        enum nl80211_channel_type channel_type;
+       enum ieee80211_smps_mode smps_mode;
 };
 
 /**
@@ -657,12 +687,14 @@ struct ieee80211_conf {
  * @type: type of this virtual interface
  * @bss_conf: BSS configuration for this interface, either our own
  *     or the BSS we're associated to
+ * @addr: address of this interface
  * @drv_priv: data area for driver use, will always be aligned to
  *     sizeof(void *).
  */
 struct ieee80211_vif {
        enum nl80211_iftype type;
        struct ieee80211_bss_conf bss_conf;
+       u8 addr[ETH_ALEN];
        /* must be last */
        u8 drv_priv[0] __attribute__((__aligned__(sizeof(void *))));
 };
@@ -675,33 +707,6 @@ static inline bool ieee80211_vif_is_mesh(struct ieee80211_vif *vif)
        return false;
 }
 
-/**
- * struct ieee80211_if_init_conf - initial configuration of an interface
- *
- * @vif: pointer to a driver-use per-interface structure. The pointer
- *     itself is also used for various functions including
- *     ieee80211_beacon_get() and ieee80211_get_buffered_bc().
- * @type: one of &enum nl80211_iftype constants. Determines the type of
- *     added/removed interface.
- * @mac_addr: pointer to MAC address of the interface. This pointer is valid
- *     until the interface is removed (i.e. it cannot be used after
- *     remove_interface() callback was called for this interface).
- *
- * This structure is used in add_interface() and remove_interface()
- * callbacks of &struct ieee80211_hw.
- *
- * When you allow multiple interfaces to be added to your PHY, take care
- * that the hardware can actually handle multiple MAC addresses. However,
- * also take care that when there's no interface left with mac_addr != %NULL
- * you remove the MAC address from the device to avoid acknowledging packets
- * in pure monitor mode.
- */
-struct ieee80211_if_init_conf {
-       enum nl80211_iftype type;
-       struct ieee80211_vif *vif;
-       void *mac_addr;
-};
-
 /**
  * enum ieee80211_key_alg - key algorithm
  * @ALG_WEP: WEP40 or WEP104
@@ -926,6 +931,21 @@ enum ieee80211_tkip_key_type {
  * @IEEE80211_HW_BEACON_FILTER:
  *     Hardware supports dropping of irrelevant beacon frames to
  *     avoid waking up cpu.
+ *
+ * @IEEE80211_HW_SUPPORTS_STATIC_SMPS:
+ *     Hardware supports static spatial multiplexing powersave,
+ *     ie. can turn off all but one chain even on HT connections
+ *     that should be using more chains.
+ *
+ * @IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS:
+ *     Hardware supports dynamic spatial multiplexing powersave,
+ *     ie. can turn off all but one chain and then wake the rest
+ *     up as required after, for example, rts/cts handshake.
+ *
+ * @IEEE80211_HW_SUPPORTS_UAPSD:
+ *     Hardware supports Unscheduled Automatic Power Save Delivery
+ *     (U-APSD) in managed mode. The mode is configured with
+ *     conf_tx() operation.
  */
 enum ieee80211_hw_flags {
        IEEE80211_HW_HAS_RATE_CONTROL                   = 1<<0,
@@ -943,6 +963,9 @@ enum ieee80211_hw_flags {
        IEEE80211_HW_SUPPORTS_DYNAMIC_PS                = 1<<12,
        IEEE80211_HW_MFP_CAPABLE                        = 1<<13,
        IEEE80211_HW_BEACON_FILTER                      = 1<<14,
+       IEEE80211_HW_SUPPORTS_STATIC_SMPS               = 1<<15,
+       IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS              = 1<<16,
+       IEEE80211_HW_SUPPORTS_UAPSD                     = 1<<17,
 };
 
 /**
@@ -1121,18 +1144,24 @@ ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw,
  *
  * mac80211 has support for various powersave implementations.
  *
- * First, it can support hardware that handles all powersaving by
- * itself, such hardware should simply set the %IEEE80211_HW_SUPPORTS_PS
- * hardware flag. In that case, it will be told about the desired
- * powersave mode depending on the association status, and the driver
- * must take care of sending nullfunc frames when necessary, i.e. when
- * entering and leaving powersave mode. The driver is required to look at
- * the AID in beacons and signal to the AP that it woke up when it finds
- * traffic directed to it. This mode supports dynamic PS by simply
- * enabling/disabling PS.
- *
- * Additionally, such hardware may set the %IEEE80211_HW_SUPPORTS_DYNAMIC_PS
- * flag to indicate that it can support dynamic PS mode itself (see below).
+ * First, it can support hardware that handles all powersaving by itself,
+ * such hardware should simply set the %IEEE80211_HW_SUPPORTS_PS hardware
+ * flag. In that case, it will be told about the desired powersave mode
+ * with the %IEEE80211_CONF_PS flag depending on the association status.
+ * The hardware must take care of sending nullfunc frames when necessary,
+ * i.e. when entering and leaving powersave mode. The hardware is required
+ * to look at the AID in beacons and signal to the AP that it woke up when
+ * it finds traffic directed to it.
+ *
+ * %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.
+ *
+ * When PS is enabled, hardware needs to wakeup for beacons and receive the
+ * buffered multicast/broadcast frames after the beacon. Also it must be
+ * possible to send frames and receive the acknowledment frame.
  *
  * Other hardware designs cannot send nullfunc frames by themselves and also
  * need software support for parsing the TIM bitmap. This is also supported
@@ -1140,14 +1169,35 @@ ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw,
  * %IEEE80211_HW_PS_NULLFUNC_STACK flags. The hardware is of course still
  * required to pass up beacons. The hardware is still required to handle
  * waking up for multicast traffic; if it cannot the driver must handle that
- * as best as it can, mac80211 is too slow.
- *
- * Dynamic powersave mode is an extension to normal powersave mode in which
- * the hardware stays awake for a user-specified period of time after sending
- * a frame so that reply frames need not be buffered and therefore delayed
- * to the next wakeup. This can either be supported by hardware, in which case
- * the driver needs to look at the @dynamic_ps_timeout hardware configuration
- * value, or by the stack if all nullfunc handling is in the stack.
+ * as best as it can, mac80211 is too slow to do that.
+ *
+ * Dynamic powersave is an extension to normal powersave in which the
+ * hardware stays awake for a user-specified period of time after sending a
+ * frame so that reply frames need not be buffered and therefore delayed to
+ * the next wakeup. It's compromise of getting good enough latency when
+ * there's data traffic and still saving significantly power in idle
+ * periods.
+ *
+ * Dynamic powersave is supported by simply 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
+ * %IEEE80211_HW_SUPPORTS_DYNAMIC_PS flag to indicate that it can support
+ * dynamic PS mode itself. The driver needs to look at the
+ * @dynamic_ps_timeout hardware configuration value and use it that value
+ * whenever %IEEE80211_CONF_PS is set. In this case mac80211 will disable
+ * dynamic PS feature in stack and will just keep %IEEE80211_CONF_PS
+ * enabled whenever user has enabled powersave.
+ *
+ * Driver informs U-APSD client support by enabling
+ * %IEEE80211_HW_SUPPORTS_UAPSD flag. The mode is configured through the
+ * uapsd paramater in conf_tx() operation. Hardware needs to send the QoS
+ * Nullfunc frames and stay awake until the service period has ended. To
+ * utilize U-APSD, dynamic powersave is disabled for voip AC and all frames
+ * from that AC are transmitted with powersave enabled.
+ *
+ * Note: U-APSD client mode is not yet supported with
+ * %IEEE80211_HW_PS_NULLFUNC_STACK.
  */
 
 /**
@@ -1210,6 +1260,31 @@ ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw,
  * signal strength threshold checking.
  */
 
+/**
+ * DOC: Spatial multiplexing power save
+ *
+ * SMPS (Spatial multiplexing power save) is a mechanism to conserve
+ * power in an 802.11n implementation. For details on the mechanism
+ * and rationale, please refer to 802.11 (as amended by 802.11n-2009)
+ * "11.2.3 SM power save".
+ *
+ * The mac80211 implementation is capable of sending action frames
+ * to update the AP about the station's SMPS mode, and will instruct
+ * the driver to enter the specific mode. It will also announce the
+ * requested SMPS mode during the association handshake. Hardware
+ * support for this feature is required, and can be indicated by
+ * hardware flags.
+ *
+ * The default mode will be "automatic", which nl80211/cfg80211
+ * defines to be dynamic SMPS in (regular) powersave, and SMPS
+ * turned off otherwise.
+ *
+ * To support this feature, the driver must set the appropriate
+ * hardware support flags, and handle the SMPS flag to the config()
+ * operation. It will then with this mechanism be instructed to
+ * enter the requested SMPS mode while associated to an HT AP.
+ */
+
 /**
  * DOC: Frame filtering
  *
@@ -1347,7 +1422,7 @@ enum ieee80211_ampdu_mlme_action {
  *     When the device is started it should not have a MAC address
  *     to avoid acknowledging frames before a non-monitor device
  *     is added.
- *     Must be implemented.
+ *     Must be implemented and can sleep.
  *
  * @stop: Called after last netdevice attached to the hardware
  *     is disabled. This should turn off the hardware (at least
@@ -1355,7 +1430,7 @@ enum ieee80211_ampdu_mlme_action {
  *     May be called right after add_interface if that rejects
  *     an interface. If you added any work onto the mac80211 workqueue
  *     you should ensure to cancel it on this callback.
- *     Must be implemented.
+ *     Must be implemented and can sleep.
  *
  * @add_interface: Called when a netdevice attached to the hardware is
  *     enabled. Because it is not called for monitor mode devices, @start
@@ -1365,7 +1440,7 @@ enum ieee80211_ampdu_mlme_action {
  *     interface is given in the conf parameter.
  *     The callback may refuse to add an interface by returning a
  *     negative error code (which will be seen in userspace.)
- *     Must be implemented.
+ *     Must be implemented and can sleep.
  *
  * @remove_interface: Notifies a driver that an interface is going down.
  *     The @stop callback is called after this if it is the last interface
@@ -1374,19 +1449,20 @@ enum ieee80211_ampdu_mlme_action {
  *     must be cleared so the device no longer acknowledges packets,
  *     the mac_addr member of the conf structure is, however, set to the
  *     MAC address of the device going away.
- *     Hence, this callback must be implemented.
+ *     Hence, this callback must be implemented. It can sleep.
  *
  * @config: Handler for configuration requests. IEEE 802.11 code calls this
  *     function to change hardware configuration, e.g., channel.
  *     This function should never fail but returns a negative error code
- *     if it does.
+ *     if it does. The callback can sleep.
  *
  * @bss_info_changed: Handler for configuration requests related to BSS
  *     parameters that may vary during BSS's lifespan, and may affect low
  *     level driver (e.g. assoc/disassoc status, erp parameters).
  *     This function should not be used if no BSS has been set, unless
  *     for association indication. The @changed parameter indicates which
- *     of the bss parameters has changed when a call is made.
+ *     of the bss parameters has changed when a call is made. The callback
+ *     can sleep.
  *
  * @prepare_multicast: Prepare for multicast filter configuration.
  *     This callback is optional, and its return value is passed
@@ -1394,20 +1470,22 @@ enum ieee80211_ampdu_mlme_action {
  *
  * @configure_filter: Configure the device's RX filter.
  *     See the section "Frame filtering" for more information.
- *     This callback must be implemented.
+ *     This callback must be implemented and can sleep.
  *
  * @set_tim: Set TIM bit. mac80211 calls this function when a TIM bit
  *     must be set or cleared for a given STA. Must be atomic.
  *
  * @set_key: See the section "Hardware crypto acceleration"
- *     This callback can sleep, and is only called between add_interface
- *     and remove_interface calls, i.e. while the given virtual interface
+ *     This callback is only called between add_interface and
+ *     remove_interface calls, i.e. while the given virtual interface
  *     is enabled.
  *     Returns a negative error code if the key can't be added.
+ *     The callback can sleep.
  *
  * @update_tkip_key: See the section "Hardware crypto acceleration"
  *     This callback will be called in the context of Rx. Called for drivers
  *     which set IEEE80211_KEY_FLAG_TKIP_REQ_RX_P1_KEY.
+ *     The callback can sleep.
  *
  * @hw_scan: Ask the hardware to service the scan request, no need to start
  *     the scan state machine in stack. The scan must honour the channel
@@ -1421,21 +1499,28 @@ enum ieee80211_ampdu_mlme_action {
  *     When the scan finishes, ieee80211_scan_completed() must be called;
  *     note that it also must be called when the scan cannot finish due to
  *     any error unless this callback returned a negative error code.
+ *     The callback can sleep.
  *
  * @sw_scan_start: Notifier function that is called just before a software scan
  *     is started. Can be NULL, if the driver doesn't need this notification.
+ *     The callback can sleep.
  *
- * @sw_scan_complete: Notifier function that is called just after a software scan
- *     finished. Can be NULL, if the driver doesn't need this notification.
+ * @sw_scan_complete: Notifier function that is called just after a
+ *     software scan finished. Can be NULL, if the driver doesn't need
+ *     this notification.
+ *     The callback can sleep.
  *
  * @get_stats: Return low-level statistics.
  *     Returns zero if statistics are available.
+ *     The callback can sleep.
  *
  * @get_tkip_seq: If your device implements TKIP encryption in hardware this
  *     callback should be provided to read the TKIP transmit IVs (both IV32
  *     and IV16) for the given key from hardware.
+ *     The callback must be atomic.
  *
  * @set_rts_threshold: Configuration of RTS threshold (if device needs it)
+ *     The callback can sleep.
  *
  * @sta_notify: Notifies low level driver about addition, removal or power
  *     state transition of an associated station, AP,  IBSS/WDS/mesh peer etc.
@@ -1444,30 +1529,36 @@ enum ieee80211_ampdu_mlme_action {
  * @conf_tx: Configure TX queue parameters (EDCF (aifs, cw_min, cw_max),
  *     bursting) for a hardware TX queue.
  *     Returns a negative error code on failure.
+ *     The callback can sleep.
  *
  * @get_tx_stats: Get statistics of the current TX queue status. This is used
  *     to get number of currently queued packets (queue length), maximum queue
  *     size (limit), and total number of packets sent using each TX queue
  *     (count). The 'stats' pointer points to an array that has hw->queues
  *     items.
+ *     The callback must be atomic.
  *
  * @get_tsf: Get the current TSF timer value from firmware/hardware. Currently,
  *     this is only used for IBSS mode BSSID merging and debugging. Is not a
  *     required function.
+ *     The callback can sleep.
  *
  * @set_tsf: Set the TSF timer to the specified value in the firmware/hardware.
  *      Currently, this is only used for IBSS mode debugging. Is not a
  *     required function.
+ *     The callback can sleep.
  *
  * @reset_tsf: Reset the TSF timer and allow firmware/hardware to synchronize
  *     with other STAs in the IBSS. This is only used in IBSS mode. This
  *     function is optional if the firmware/hardware takes full care of
  *     TSF synchronization.
+ *     The callback can sleep.
  *
  * @tx_last_beacon: Determine whether the last IBSS beacon was sent by us.
  *     This is needed only for IBSS mode and the result of this function is
  *     used to determine whether to reply to Probe Requests.
  *     Returns non-zero if this device sent the last beacon.
+ *     The callback can sleep.
  *
  * @ampdu_action: Perform a certain A-MPDU action
  *     The RA/TID combination determines the destination and TID we want
@@ -1476,21 +1567,32 @@ enum ieee80211_ampdu_mlme_action {
  *     is the first frame we expect to perform the action on. Notice
  *     that TX/RX_STOP can pass NULL for this parameter.
  *     Returns a negative error code on failure.
+ *     The callback must be atomic.
  *
  * @rfkill_poll: Poll rfkill hardware state. If you need this, you also
  *     need to set wiphy->rfkill_poll to %true before registration,
  *     and need to call wiphy_rfkill_set_hw_state() in the callback.
+ *     The callback can sleep.
+ *
+ * @set_coverage_class: Set slot time for given coverage class as specified
+ *     in IEEE 802.11-2007 section 17.3.8.6 and modify ACK timeout
+ *     accordingly. This callback is not required and may sleep.
  *
  * @testmode_cmd: Implement a cfg80211 test mode command.
+ *     The callback can sleep.
+ *
+ * @flush: Flush all pending frames from the hardware queue, making sure
+ *     that the hardware queues are empty. If the parameter @drop is set
+ *     to %true, pending frames may be dropped. The callback can sleep.
  */
 struct ieee80211_ops {
        int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb);
        int (*start)(struct ieee80211_hw *hw);
        void (*stop)(struct ieee80211_hw *hw);
        int (*add_interface)(struct ieee80211_hw *hw,
-                            struct ieee80211_if_init_conf *conf);
+                            struct ieee80211_vif *vif);
        void (*remove_interface)(struct ieee80211_hw *hw,
-                                struct ieee80211_if_init_conf *conf);
+                                struct ieee80211_vif *vif);
        int (*config)(struct ieee80211_hw *hw, u32 changed);
        void (*bss_info_changed)(struct ieee80211_hw *hw,
                                 struct ieee80211_vif *vif,
@@ -1535,9 +1637,11 @@ struct ieee80211_ops {
                            struct ieee80211_sta *sta, u16 tid, u16 *ssn);
 
        void (*rfkill_poll)(struct ieee80211_hw *hw);
+       void (*set_coverage_class)(struct ieee80211_hw *hw, u8 coverage_class);
 #ifdef CONFIG_NL80211_TESTMODE
        int (*testmode_cmd)(struct ieee80211_hw *hw, void *data, int len);
 #endif
+       void (*flush)(struct ieee80211_hw *hw, bool drop);
 };
 
 /**
@@ -1777,7 +1881,7 @@ void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw,
 /**
  * ieee80211_beacon_get_tim - beacon generation function
  * @hw: pointer obtained from ieee80211_alloc_hw().
- * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf.
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback.
  * @tim_offset: pointer to variable that will receive the TIM IE offset.
  *     Set to 0 if invalid (in non-AP modes).
  * @tim_length: pointer to variable that will receive the TIM IE length,
@@ -1805,7 +1909,7 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
 /**
  * ieee80211_beacon_get - beacon generation function
  * @hw: pointer obtained from ieee80211_alloc_hw().
- * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf.
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback.
  *
  * See ieee80211_beacon_get_tim().
  */
@@ -1815,10 +1919,57 @@ static inline struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
        return ieee80211_beacon_get_tim(hw, vif, NULL, NULL);
 }
 
+/**
+ * ieee80211_pspoll_get - retrieve a PS Poll template
+ * @hw: pointer obtained from ieee80211_alloc_hw().
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback.
+ *
+ * Creates a PS Poll a template which can, for example, uploaded to
+ * hardware. The template must be updated after association so that correct
+ * AID, BSSID and MAC address is used.
+ *
+ * Note: Caller (or hardware) is responsible for setting the
+ * &IEEE80211_FCTL_PM bit.
+ */
+struct sk_buff *ieee80211_pspoll_get(struct ieee80211_hw *hw,
+                                    struct ieee80211_vif *vif);
+
+/**
+ * ieee80211_nullfunc_get - retrieve a nullfunc template
+ * @hw: pointer obtained from ieee80211_alloc_hw().
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback.
+ *
+ * Creates a Nullfunc template which can, for example, uploaded to
+ * hardware. The template must be updated after association so that correct
+ * BSSID and address is used.
+ *
+ * Note: Caller (or hardware) is responsible for setting the
+ * &IEEE80211_FCTL_PM bit as well as Duration and Sequence Control fields.
+ */
+struct sk_buff *ieee80211_nullfunc_get(struct ieee80211_hw *hw,
+                                      struct ieee80211_vif *vif);
+
+/**
+ * ieee80211_probereq_get - retrieve a Probe Request template
+ * @hw: pointer obtained from ieee80211_alloc_hw().
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback.
+ * @ssid: SSID buffer
+ * @ssid_len: length of SSID
+ * @ie: buffer containing all IEs except SSID for the template
+ * @ie_len: length of the IE buffer
+ *
+ * Creates a Probe Request template which can, for example, be uploaded to
+ * hardware.
+ */
+struct sk_buff *ieee80211_probereq_get(struct ieee80211_hw *hw,
+                                      struct ieee80211_vif *vif,
+                                      const u8 *ssid, size_t ssid_len,
+                                      const u8 *ie, size_t ie_len);
+
 /**
  * ieee80211_rts_get - RTS frame generation function
  * @hw: pointer obtained from ieee80211_alloc_hw().
- * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf.
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback.
  * @frame: pointer to the frame that is going to be protected by the RTS.
  * @frame_len: the frame length (in octets).
  * @frame_txctl: &struct ieee80211_tx_info of the frame.
@@ -1837,7 +1988,7 @@ void ieee80211_rts_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 /**
  * ieee80211_rts_duration - Get the duration field for an RTS frame
  * @hw: pointer obtained from ieee80211_alloc_hw().
- * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf.
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback.
  * @frame_len: the length of the frame that is going to be protected by the RTS.
  * @frame_txctl: &struct ieee80211_tx_info of the frame.
  *
@@ -1852,7 +2003,7 @@ __le16 ieee80211_rts_duration(struct ieee80211_hw *hw,
 /**
  * ieee80211_ctstoself_get - CTS-to-self frame generation function
  * @hw: pointer obtained from ieee80211_alloc_hw().
- * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf.
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback.
  * @frame: pointer to the frame that is going to be protected by the CTS-to-self.
  * @frame_len: the frame length (in octets).
  * @frame_txctl: &struct ieee80211_tx_info of the frame.
@@ -1872,7 +2023,7 @@ void ieee80211_ctstoself_get(struct ieee80211_hw *hw,
 /**
  * ieee80211_ctstoself_duration - Get the duration field for a CTS-to-self frame
  * @hw: pointer obtained from ieee80211_alloc_hw().
- * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf.
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback.
  * @frame_len: the length of the frame that is going to be protected by the CTS-to-self.
  * @frame_txctl: &struct ieee80211_tx_info of the frame.
  *
@@ -1888,7 +2039,7 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw,
 /**
  * ieee80211_generic_frame_duration - Calculate the duration field for a frame
  * @hw: pointer obtained from ieee80211_alloc_hw().
- * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf.
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback.
  * @frame_len: the length of the frame.
  * @rate: the rate at which the frame is going to be transmitted.
  *
@@ -1903,7 +2054,7 @@ __le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw,
 /**
  * ieee80211_get_buffered_bc - accessing buffered broadcast and multicast frames
  * @hw: pointer as obtained from ieee80211_alloc_hw().
- * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf.
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback.
  *
  * Function for accessing buffered broadcast and multicast frames. If
  * hardware/firmware does not implement buffering of broadcast/multicast
@@ -2071,7 +2222,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *sta, u16 tid);
 
 /**
  * ieee80211_start_tx_ba_cb - low level driver ready to aggregate.
- * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback
  * @ra: receiver address of the BA session recipient.
  * @tid: the TID to BA on.
  *
@@ -2082,7 +2233,7 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid);
 
 /**
  * ieee80211_start_tx_ba_cb_irqsafe - low level driver ready to aggregate.
- * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback
  * @ra: receiver address of the BA session recipient.
  * @tid: the TID to BA on.
  *
@@ -2110,7 +2261,7 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_sta *sta, u16 tid,
 
 /**
  * ieee80211_stop_tx_ba_cb - low level driver ready to stop aggregate.
- * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback
  * @ra: receiver address of the BA session recipient.
  * @tid: the desired TID to BA on.
  *
@@ -2121,7 +2272,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid);
 
 /**
  * ieee80211_stop_tx_ba_cb_irqsafe - low level driver ready to stop aggregate.
- * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback
  * @ra: receiver address of the BA session recipient.
  * @tid: the desired TID to BA on.
  *
@@ -2200,7 +2351,7 @@ void ieee80211_sta_block_awake(struct ieee80211_hw *hw,
 /**
  * ieee80211_beacon_loss - inform hardware does not receive beacons
  *
- * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf.
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback.
  *
  * When beacon filtering is enabled with IEEE80211_HW_BEACON_FILTERING and
  * IEEE80211_CONF_PS is set, the driver needs to inform whenever the
@@ -2234,8 +2385,12 @@ enum rate_control_changed {
  * @short_preamble: whether mac80211 will request short-preamble transmission
  *     if the selected rate supports it
  * @max_rate_idx: user-requested maximum rate (not MCS for now)
+ *     (deprecated; this will be removed once drivers get updated to use
+ *     rate_idx_mask)
+ * @rate_idx_mask: user-requested rate mask (not MCS for now)
  * @skb: the skb that will be transmitted, the control information in it needs
  *     to be filled in
+ * @ap: whether this frame is sent out in AP mode
  */
 struct ieee80211_tx_rate_control {
        struct ieee80211_hw *hw;
@@ -2245,6 +2400,8 @@ struct ieee80211_tx_rate_control {
        struct ieee80211_tx_rate reported_rate;
        bool rts, short_preamble;
        u8 max_rate_idx;
+       u32 rate_idx_mask;
+       bool ap;
 };
 
 struct rate_control_ops {
index 4c61cdce4e5fc3827af2d0d3064bf1bfd55718f6..35672b1cf44a3b76d258f84996c4abd779219fbc 100644 (file)
@@ -44,6 +44,7 @@ struct pep_sock {
        u8                      rx_fc;  /* RX flow control */
        u8                      tx_fc;  /* TX flow control */
        u8                      init_enable;    /* auto-enable at creation */
+       u8                      aligned;
 };
 
 static inline struct pep_sock *pep_sk(struct sock *sk)
@@ -77,6 +78,7 @@ static inline struct pnpipehdr *pnp_hdr(struct sk_buff *skb)
 
 enum {
        PNS_PIPE_DATA = 0x20,
+       PNS_PIPE_ALIGNED_DATA,
 
        PNS_PEP_CONNECT_REQ = 0x40,
        PNS_PEP_CONNECT_RESP,
@@ -138,6 +140,7 @@ enum {
        PN_PIPE_SB_NEGOTIATED_FC,
        PN_PIPE_SB_REQUIRED_FC_TX,
        PN_PIPE_SB_PREFERRED_FC_RX,
+       PN_PIPE_SB_ALIGNED_DATA,
 };
 
 /* Phonet pipe flow control models */
index 2d567265363e675f8a9101ad44a19c44f5d514e8..b6cdc33b39c1597a8b1059e0652d4cb5ae7bf889 100644 (file)
@@ -71,6 +71,7 @@ extern void qdisc_watchdog_cancel(struct qdisc_watchdog *wd);
 
 extern struct Qdisc_ops pfifo_qdisc_ops;
 extern struct Qdisc_ops bfifo_qdisc_ops;
+extern struct Qdisc_ops pfifo_head_drop_qdisc_ops;
 
 extern int fifo_set_limit(struct Qdisc *q, unsigned int limit);
 extern struct Qdisc *fifo_create_dflt(struct Qdisc *sch, struct Qdisc_ops *ops,
index c9b50ebd9ce9ea3cab54d14411a899b7df524150..99e6e19b57c2188ed0a592789e68e00c2d0a55f8 100644 (file)
@@ -45,6 +45,8 @@ struct request_sock_ops {
        void            (*send_reset)(struct sock *sk,
                                      struct sk_buff *skb);
        void            (*destructor)(struct request_sock *req);
+       void            (*syn_ack_timeout)(struct sock *sk,
+                                          struct request_sock *req);
 };
 
 /* struct request_sock - mini sock to represent a connection request
index dad558bc06fac639cbf2a0412e831df91b3dce24..67dc08eaaa457cf18d079a7e04807b96f774ebd5 100644 (file)
@@ -427,6 +427,25 @@ static inline struct sk_buff *qdisc_dequeue_head(struct Qdisc *sch)
        return __qdisc_dequeue_head(sch, &sch->q);
 }
 
+static inline unsigned int __qdisc_queue_drop_head(struct Qdisc *sch,
+                                             struct sk_buff_head *list)
+{
+       struct sk_buff *skb = __qdisc_dequeue_head(sch, list);
+
+       if (likely(skb != NULL)) {
+               unsigned int len = qdisc_pkt_len(skb);
+               kfree_skb(skb);
+               return len;
+       }
+
+       return 0;
+}
+
+static inline unsigned int qdisc_queue_drop_head(struct Qdisc *sch)
+{
+       return __qdisc_queue_drop_head(sch, &sch->q);
+}
+
 static inline struct sk_buff *__qdisc_dequeue_tail(struct Qdisc *sch,
                                                   struct sk_buff_head *list)
 {
index f0d756f2ac99773f573613d145752b2984dddd13..da02ee027d690ae2b5c09de74436a4c15acfc6ab 100644 (file)
@@ -32,7 +32,7 @@
  *  - name of entries.
  */
 struct snmp_mib {
-       char *name;
+       const char *name;
        int entry;
 };
 
index 34f5cc24d903332f9c29f2cb0484ade46dad0f54..87d164b9bd8f63784c4db0731297697cc06aafea 100644 (file)
@@ -400,6 +400,8 @@ extern int                  compat_tcp_setsockopt(struct sock *sk,
                                        int level, int optname,
                                        char __user *optval, unsigned int optlen);
 extern void                    tcp_set_keepalive(struct sock *sk, int val);
+extern void                    tcp_syn_ack_timeout(struct sock *sk,
+                                                   struct request_sock *req);
 extern int                     tcp_recvmsg(struct kiocb *iocb, struct sock *sk,
                                            struct msghdr *msg,
                                            size_t len, int nonblock, 
@@ -856,13 +858,6 @@ static inline void tcp_check_probe_timer(struct sock *sk)
                                          icsk->icsk_rto, TCP_RTO_MAX);
 }
 
-static inline void tcp_push_pending_frames(struct sock *sk)
-{
-       struct tcp_sock *tp = tcp_sk(sk);
-
-       __tcp_push_pending_frames(sk, tcp_current_mss(sk), tp->nonagle);
-}
-
 static inline void tcp_init_wl(struct tcp_sock *tp, u32 seq)
 {
        tp->snd_wl1 = seq;
@@ -972,7 +967,8 @@ static inline void tcp_sack_reset(struct tcp_options_received *rx_opt)
 /* Determine a window scaling and initial window to offer. */
 extern void tcp_select_initial_window(int __space, __u32 mss,
                                      __u32 *rcv_wnd, __u32 *window_clamp,
-                                     int wscale_ok, __u8 *rcv_wscale);
+                                     int wscale_ok, __u8 *rcv_wscale,
+                                     __u32 init_rcv_wnd);
 
 static inline int tcp_win_from_space(int space)
 {
@@ -1342,6 +1338,15 @@ static inline int tcp_write_queue_empty(struct sock *sk)
        return skb_queue_empty(&sk->sk_write_queue);
 }
 
+static inline void tcp_push_pending_frames(struct sock *sk)
+{
+       if (tcp_send_head(sk)) {
+               struct tcp_sock *tp = tcp_sk(sk);
+
+               __tcp_push_pending_frames(sk, tcp_current_mss(sk), tp->nonagle);
+       }
+}
+
 /* Start sequence of the highest skb with SACKed bit, valid only if
  * sacked > 0 or when the caller has ensured validity by itself.
  */
index 60c27706e7b99fcce2d7df451564ae4569d394f4..fcee547ca7e3f37d6fa3a5018ce95118f38c33a8 100644 (file)
@@ -1408,9 +1408,9 @@ extern int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr,
                            xfrm_address_t *saddr, u8 proto);
 extern int xfrm6_tunnel_register(struct xfrm6_tunnel *handler, unsigned short family);
 extern int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler, unsigned short family);
-extern __be32 xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr);
-extern void xfrm6_tunnel_free_spi(xfrm_address_t *saddr);
-extern __be32 xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr);
+extern __be32 xfrm6_tunnel_alloc_spi(struct net *net, xfrm_address_t *saddr);
+extern void xfrm6_tunnel_free_spi(struct net *net, xfrm_address_t *saddr);
+extern __be32 xfrm6_tunnel_spi_lookup(struct net *net, xfrm_address_t *saddr);
 extern int xfrm6_extract_output(struct xfrm_state *x, struct sk_buff *skb);
 extern int xfrm6_prepare_output(struct xfrm_state *x, struct sk_buff *skb);
 extern int xfrm6_output(struct sk_buff *skb);
index 3b8aeec4e32762c3066f8ec633ec0baed99e746e..af4aaa6c36f36c924d9a63da70f84e2b3459fca1 100644 (file)
@@ -681,24 +681,55 @@ static char *mac_address_string(char *buf, char *end, u8 *addr,
        char mac_addr[sizeof("xx:xx:xx:xx:xx:xx")];
        char *p = mac_addr;
        int i;
+       char separator;
+
+       if (fmt[1] == 'F') {            /* FDDI canonical format */
+               separator = '-';
+       } else {
+               separator = ':';
+       }
 
        for (i = 0; i < 6; i++) {
                p = pack_hex_byte(p, addr[i]);
                if (fmt[0] == 'M' && i != 5)
-                       *p++ = ':';
+                       *p++ = separator;
        }
        *p = '\0';
 
        return string(buf, end, mac_addr, spec);
 }
 
-static char *ip4_string(char *p, const u8 *addr, bool leading_zeros)
+static char *ip4_string(char *p, const u8 *addr, const char *fmt)
 {
        int i;
-
+       bool leading_zeros = (fmt[0] == 'i');
+       int index;
+       int step;
+
+       switch (fmt[2]) {
+       case 'h':
+#ifdef __BIG_ENDIAN
+               index = 0;
+               step = 1;
+#else
+               index = 3;
+               step = -1;
+#endif
+               break;
+       case 'l':
+               index = 3;
+               step = -1;
+               break;
+       case 'n':
+       case 'b':
+       default:
+               index = 0;
+               step = 1;
+               break;
+       }
        for (i = 0; i < 4; i++) {
                char temp[3];   /* hold each IP quad in reverse order */
-               int digits = put_dec_trunc(temp, addr[i]) - temp;
+               int digits = put_dec_trunc(temp, addr[index]) - temp;
                if (leading_zeros) {
                        if (digits < 3)
                                *p++ = '0';
@@ -710,6 +741,7 @@ static char *ip4_string(char *p, const u8 *addr, bool leading_zeros)
                        *p++ = temp[digits];
                if (i < 3)
                        *p++ = '.';
+               index += step;
        }
        *p = '\0';
 
@@ -789,7 +821,7 @@ static char *ip6_compressed_string(char *p, const char *addr)
        if (useIPv4) {
                if (needcolon)
                        *p++ = ':';
-               p = ip4_string(p, &in6.s6_addr[12], false);
+               p = ip4_string(p, &in6.s6_addr[12], "I4");
        }
        *p = '\0';
 
@@ -829,7 +861,7 @@ static char *ip4_addr_string(char *buf, char *end, const u8 *addr,
 {
        char ip4_addr[sizeof("255.255.255.255")];
 
-       ip4_string(ip4_addr, addr, fmt[0] == 'i');
+       ip4_string(ip4_addr, addr, fmt);
 
        return string(buf, end, ip4_addr, spec);
 }
@@ -896,12 +928,15 @@ static char *uuid_string(char *buf, char *end, const u8 *addr,
  * - 'M' For a 6-byte MAC address, it prints the address in the
  *       usual colon-separated hex notation
  * - 'm' For a 6-byte MAC address, it prints the hex address without colons
+ * - 'MF' For a 6-byte MAC FDDI address, it prints the address
+ *       with a dash-separated hex notation
  * - 'I' [46] for IPv4/IPv6 addresses printed in the usual way
  *       IPv4 uses dot-separated decimal without leading 0's (1.2.3.4)
  *       IPv6 uses colon separated network-order 16 bit hex with leading 0's
  * - 'i' [46] for 'raw' IPv4/IPv6 addresses
  *       IPv6 omits the colons (01020304...0f)
  *       IPv4 uses dot-separated decimal with leading 0's (010.123.045.006)
+ * - '[Ii]4[hnbl]' IPv4 addresses in host, network, big or little endian order
  * - 'I6c' for IPv6 addresses printed as specified by
  *       http://tools.ietf.org/html/draft-ietf-6man-text-addr-representation-00
  * - 'U' For a 16 byte UUID/GUID, it prints the UUID/GUID in the form
@@ -939,6 +974,7 @@ static char *pointer(const char *fmt, char *buf, char *end, void *ptr,
                return resource_string(buf, end, ptr, spec, fmt);
        case 'M':                       /* Colon separated: 00:01:02:03:04:05 */
        case 'm':                       /* Contiguous: 000102030405 */
+                                       /* [mM]F (FDDI, bit reversed) */
                return mac_address_string(buf, end, ptr, spec, fmt);
        case 'I':                       /* Formatted IP supported
                                         * 4:   1.2.3.4
index ded9081f40219d888e48e41d4b665a712a188d28..0777654147c9d0e3fd0b676771dc5052bcab9455 100644 (file)
@@ -5,6 +5,7 @@
 
 #include <linux/mm.h>
 #include <linux/mmu_context.h>
+#include <linux/module.h>
 #include <linux/sched.h>
 
 #include <asm/mmu_context.h>
@@ -37,6 +38,7 @@ void use_mm(struct mm_struct *mm)
        if (active_mm != mm)
                mmdrop(active_mm);
 }
+EXPORT_SYMBOL_GPL(use_mm);
 
 /*
  * unuse_mm
@@ -56,3 +58,4 @@ void unuse_mm(struct mm_struct *mm)
        enter_lazy_tlb(mm, tsk);
        task_unlock(tsk);
 }
+EXPORT_SYMBOL_GPL(unuse_mm);
index 33f90e7362cc6f2cd6fe2825edc5b5e7451da0a9..453512266ea1dd783dbc68f5e6b511dd64ec5ac5 100644 (file)
@@ -663,7 +663,7 @@ out:
        return err;
 }
 
-static int vlan_init_net(struct net *net)
+static int __net_init vlan_init_net(struct net *net)
 {
        struct vlan_net *vn = net_generic(net, vlan_net_id);
        int err;
@@ -675,7 +675,7 @@ static int vlan_init_net(struct net *net)
        return err;
 }
 
-static void vlan_exit_net(struct net *net)
+static void __net_exit vlan_exit_net(struct net *net)
 {
        vlan_proc_cleanup(net);
 }
index e75a2f3b10af7721610af6adf0c42e5c7fec2192..c0316e0ca6e854724ccb6dc07e1441dd697e7277 100644 (file)
@@ -14,6 +14,7 @@ int __vlan_hwaccel_rx(struct sk_buff *skb, struct vlan_group *grp,
        if (skb_bond_should_drop(skb))
                goto drop;
 
+       skb->skb_iif = skb->dev->ifindex;
        __vlan_hwaccel_put_tag(skb, vlan_tci);
        skb->dev = vlan_group_get_device(grp, vlan_tci & VLAN_VID_MASK);
 
@@ -85,6 +86,7 @@ vlan_gro_common(struct napi_struct *napi, struct vlan_group *grp,
        if (skb_bond_should_drop(skb))
                goto drop;
 
+       skb->skb_iif = skb->dev->ifindex;
        __vlan_hwaccel_put_tag(skb, vlan_tci);
        skb->dev = vlan_group_get_device(grp, vlan_tci & VLAN_VID_MASK);
 
index c1b92cab46c70d777f3b48b8307ad7cb877e258c..a9e1f1785614b6f5da4871d140067737d97d5c9e 100644 (file)
@@ -263,11 +263,10 @@ static int vlan_dev_hard_header(struct sk_buff *skb, struct net_device *dev,
                vhdr->h_vlan_TCI = htons(vlan_tci);
 
                /*
-                *  Set the protocol type. For a packet of type ETH_P_802_3 we
-                *  put the length in here instead. It is up to the 802.2
-                *  layer to carry protocol information.
+                *  Set the protocol type. For a packet of type ETH_P_802_3/2 we
+                *  put the length in here instead.
                 */
-               if (type != ETH_P_802_3)
+               if (type != ETH_P_802_3 && type != ETH_P_802_2)
                        vhdr->h_vlan_encapsulated_proto = htons(type);
                else
                        vhdr->h_vlan_encapsulated_proto = htons(len);
index 9ec1f057c03ab2d291813479a8f460f42424135c..afead353e215fc0028530b033ee9104c8bb51ca5 100644 (file)
@@ -140,7 +140,7 @@ void vlan_proc_cleanup(struct net *net)
  *     Create /proc/net/vlan entries
  */
 
-int vlan_proc_init(struct net *net)
+int __net_init vlan_proc_init(struct net *net)
 {
        struct vlan_net *vn = net_generic(net, vlan_net_id);
 
index 82e85abc303dde8ba0ff278d252c9ea4fd95a43b..cf3ae8b475728df8668ce90ce14f5622e65c2388 100644 (file)
@@ -4,7 +4,7 @@
 
 #include <linux/atm.h>
 #include <linux/atmdev.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 
 #include "signaling.h"
 #include "addr.h"
index 02cc7e71efea24e36fbe78a5e43ee6e7122f3b64..fc63526d8695cc4a629324334b41ef204eae38b9 100644 (file)
@@ -2,37 +2,35 @@
 
 /* Written 1995-2000 by Werner Almesberger, EPFL ICA */
 
-
 #include <linux/module.h>
 #include <linux/atm.h>
 #include <linux/atmdev.h>
 #include <linux/skbuff.h>
 #include <linux/sonet.h>
 #include <linux/bitops.h>
+#include <linux/errno.h>
 #include <asm/atomic.h>
-#include <asm/errno.h>
-
 
-int atm_charge(struct atm_vcc *vcc,int truesize)
+int atm_charge(struct atm_vcc *vcc, int truesize)
 {
-       atm_force_charge(vcc,truesize);
+       atm_force_charge(vcc, truesize);
        if (atomic_read(&sk_atm(vcc)->sk_rmem_alloc) <= sk_atm(vcc)->sk_rcvbuf)
                return 1;
-       atm_return(vcc,truesize);
+       atm_return(vcc, truesize);
        atomic_inc(&vcc->stats->rx_drop);
        return 0;
 }
+EXPORT_SYMBOL(atm_charge);
 
-
-struct sk_buff *atm_alloc_charge(struct atm_vcc *vcc,int pdu_size,
-    gfp_t gfp_flags)
+struct sk_buff *atm_alloc_charge(struct atm_vcc *vcc, int pdu_size,
+                                gfp_t gfp_flags)
 {
        struct sock *sk = sk_atm(vcc);
        int guess = atm_guess_pdu2truesize(pdu_size);
 
-       atm_force_charge(vcc,guess);
+       atm_force_charge(vcc, guess);
        if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf) {
-               struct sk_buff *skb = alloc_skb(pdu_size,gfp_flags);
+               struct sk_buff *skb = alloc_skb(pdu_size, gfp_flags);
 
                if (skb) {
                        atomic_add(skb->truesize-guess,
@@ -40,10 +38,11 @@ struct sk_buff *atm_alloc_charge(struct atm_vcc *vcc,int pdu_size,
                        return skb;
                }
        }
-       atm_return(vcc,guess);
+       atm_return(vcc, guess);
        atomic_inc(&vcc->stats->rx_drop);
        return NULL;
 }
+EXPORT_SYMBOL(atm_alloc_charge);
 
 
 /*
@@ -73,7 +72,6 @@ struct sk_buff *atm_alloc_charge(struct atm_vcc *vcc,int pdu_size,
  *      else *
  */
 
-
 int atm_pcr_goal(const struct atm_trafprm *tp)
 {
        if (tp->pcr && tp->pcr != ATM_MAX_PCR)
@@ -84,26 +82,20 @@ int atm_pcr_goal(const struct atm_trafprm *tp)
                return -tp->max_pcr;
        return 0;
 }
+EXPORT_SYMBOL(atm_pcr_goal);
 
-
-void sonet_copy_stats(struct k_sonet_stats *from,struct sonet_stats *to)
+void sonet_copy_stats(struct k_sonet_stats *from, struct sonet_stats *to)
 {
 #define __HANDLE_ITEM(i) to->i = atomic_read(&from->i)
        __SONET_ITEMS
 #undef __HANDLE_ITEM
 }
+EXPORT_SYMBOL(sonet_copy_stats);
 
-
-void sonet_subtract_stats(struct k_sonet_stats *from,struct sonet_stats *to)
+void sonet_subtract_stats(struct k_sonet_stats *from, struct sonet_stats *to)
 {
-#define __HANDLE_ITEM(i) atomic_sub(to->i,&from->i)
+#define __HANDLE_ITEM(i) atomic_sub(to->i, &from->i)
        __SONET_ITEMS
 #undef __HANDLE_ITEM
 }
-
-
-EXPORT_SYMBOL(atm_charge);
-EXPORT_SYMBOL(atm_alloc_charge);
-EXPORT_SYMBOL(atm_pcr_goal);
-EXPORT_SYMBOL(sonet_copy_stats);
 EXPORT_SYMBOL(sonet_subtract_stats);
index b5674dc2083d6766bbe4754d3951439fde141c0c..f693b78eb4678d79b8a4f4786a4fffba47461ade 100644 (file)
@@ -42,13 +42,14 @@ static ssize_t show_atmaddress(struct device *cdev,
 
        spin_lock_irqsave(&adev->lock, flags);
        list_for_each_entry(aaddr, &adev->local, entry) {
-               for(i = 0, j = 0; i < ATM_ESA_LEN; ++i, ++j) {
+               for (i = 0, j = 0; i < ATM_ESA_LEN; ++i, ++j) {
                        if (j == *fmt) {
                                pos += sprintf(pos, ".");
                                ++fmt;
                                j = 0;
                        }
-                       pos += sprintf(pos, "%02x", aaddr->addr.sas_addr.prv[i]);
+                       pos += sprintf(pos, "%02x",
+                                      aaddr->addr.sas_addr.prv[i]);
                }
                pos += sprintf(pos, "\n");
        }
@@ -78,17 +79,17 @@ static ssize_t show_link_rate(struct device *cdev,
 
        /* show the link rate, not the data rate */
        switch (adev->link_rate) {
-               case ATM_OC3_PCR:
-                       link_rate = 155520000;
-                       break;
-               case ATM_OC12_PCR:
-                       link_rate = 622080000;
-                       break;
-               case ATM_25_PCR:
-                       link_rate = 25600000;
-                       break;
-               default:
-                       link_rate = adev->link_rate * 8 * 53;
+       case ATM_OC3_PCR:
+               link_rate = 155520000;
+               break;
+       case ATM_OC12_PCR:
+               link_rate = 622080000;
+               break;
+       case ATM_25_PCR:
+               link_rate = 25600000;
+               break;
+       default:
+               link_rate = adev->link_rate * 8 * 53;
        }
        pos += sprintf(pos, "%d\n", link_rate);
 
index c9230c398697a75986b71b28263261e37fed2cee..4d64d87e7578a26aa6bd89bfa425dea14fb13f77 100644 (file)
@@ -6,6 +6,8 @@
  *          Eric Kinzie, 2006-2007, US Naval Research Laboratory
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
+
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -15,7 +17,7 @@
 #include <linux/etherdevice.h>
 #include <linux/rtnetlink.h>
 #include <linux/ip.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 #include <net/arp.h>
 #include <linux/atm.h>
 #include <linux/atmdev.h>
 
 #include "common.h"
 
-#ifdef SKB_DEBUG
 static void skb_debug(const struct sk_buff *skb)
 {
+#ifdef SKB_DEBUG
 #define NUM2PRINT 50
-       char buf[NUM2PRINT * 3 + 1];    /* 3 chars per byte */
-       int i = 0;
-       for (i = 0; i < skb->len && i < NUM2PRINT; i++) {
-               sprintf(buf + i * 3, "%2.2x ", 0xff & skb->data[i]);
-       }
-       printk(KERN_DEBUG "br2684: skb: %s\n", buf);
-}
-#else
-#define skb_debug(skb) do {} while (0)
+       print_hex_dump(KERN_DEBUG, "br2684: skb: ", DUMP_OFFSET,
+                      16, 1, skb->data, min(NUM2PRINT, skb->len), true);
 #endif
+}
 
 #define BR2684_ETHERTYPE_LEN   2
 #define BR2684_PAD_LEN         2
@@ -68,7 +64,7 @@ struct br2684_vcc {
        struct atm_vcc *atmvcc;
        struct net_device *device;
        /* keep old push, pop functions for chaining */
-       void (*old_push) (struct atm_vcc * vcc, struct sk_buff * skb);
+       void (*old_push)(struct atm_vcc *vcc, struct sk_buff *skb);
        void (*old_pop)(struct atm_vcc *vcc, struct sk_buff *skb);
        enum br2684_encaps encaps;
        struct list_head brvccs;
@@ -148,7 +144,7 @@ static void br2684_pop(struct atm_vcc *vcc, struct sk_buff *skb)
        struct br2684_vcc *brvcc = BR2684_VCC(vcc);
        struct net_device *net_dev = skb->dev;
 
-       pr_debug("br2684_pop(vcc %p ; net_dev %p )\n", vcc, net_dev);
+       pr_debug("(vcc %p ; net_dev %p )\n", vcc, net_dev);
        brvcc->old_pop(vcc, skb);
 
        if (!net_dev)
@@ -244,7 +240,7 @@ static netdev_tx_t br2684_start_xmit(struct sk_buff *skb,
        struct br2684_dev *brdev = BRPRIV(dev);
        struct br2684_vcc *brvcc;
 
-       pr_debug("br2684_start_xmit, skb_dst(skb)=%p\n", skb_dst(skb));
+       pr_debug("skb_dst(skb)=%p\n", skb_dst(skb));
        read_lock(&devs_lock);
        brvcc = pick_outgoing_vcc(skb, brdev);
        if (brvcc == NULL) {
@@ -300,7 +296,8 @@ static int br2684_setfilt(struct atm_vcc *atmvcc, void __user * arg)
                struct br2684_dev *brdev;
                read_lock(&devs_lock);
                brdev = BRPRIV(br2684_find_dev(&fs.ifspec));
-               if (brdev == NULL || list_empty(&brdev->brvccs) || brdev->brvccs.next != brdev->brvccs.prev)    /* >1 VCC */
+               if (brdev == NULL || list_empty(&brdev->brvccs) ||
+                   brdev->brvccs.next != brdev->brvccs.prev)   /* >1 VCC */
                        brvcc = NULL;
                else
                        brvcc = list_entry_brvcc(brdev->brvccs.next);
@@ -352,7 +349,7 @@ static void br2684_push(struct atm_vcc *atmvcc, struct sk_buff *skb)
        struct net_device *net_dev = brvcc->device;
        struct br2684_dev *brdev = BRPRIV(net_dev);
 
-       pr_debug("br2684_push\n");
+       pr_debug("\n");
 
        if (unlikely(skb == NULL)) {
                /* skb==NULL means VCC is being destroyed */
@@ -376,29 +373,25 @@ static void br2684_push(struct atm_vcc *atmvcc, struct sk_buff *skb)
                        __skb_trim(skb, skb->len - 4);
 
                /* accept packets that have "ipv[46]" in the snap header */
-               if ((skb->len >= (sizeof(llc_oui_ipv4)))
-                   &&
-                   (memcmp
-                    (skb->data, llc_oui_ipv4,
-                     sizeof(llc_oui_ipv4) - BR2684_ETHERTYPE_LEN) == 0)) {
-                       if (memcmp
-                           (skb->data + 6, ethertype_ipv6,
-                            sizeof(ethertype_ipv6)) == 0)
+               if ((skb->len >= (sizeof(llc_oui_ipv4))) &&
+                   (memcmp(skb->data, llc_oui_ipv4,
+                           sizeof(llc_oui_ipv4) - BR2684_ETHERTYPE_LEN) == 0)) {
+                       if (memcmp(skb->data + 6, ethertype_ipv6,
+                                  sizeof(ethertype_ipv6)) == 0)
                                skb->protocol = htons(ETH_P_IPV6);
-                       else if (memcmp
-                                (skb->data + 6, ethertype_ipv4,
-                                 sizeof(ethertype_ipv4)) == 0)
+                       else if (memcmp(skb->data + 6, ethertype_ipv4,
+                                       sizeof(ethertype_ipv4)) == 0)
                                skb->protocol = htons(ETH_P_IP);
                        else
                                goto error;
                        skb_pull(skb, sizeof(llc_oui_ipv4));
                        skb_reset_network_header(skb);
                        skb->pkt_type = PACKET_HOST;
-                       /*
-                        * Let us waste some time for checking the encapsulation.
-                        * Note, that only 7 char is checked so frames with a valid FCS
-                        * are also accepted (but FCS is not checked of course).
-                        */
+               /*
+                * Let us waste some time for checking the encapsulation.
+                * Note, that only 7 char is checked so frames with a valid FCS
+                * are also accepted (but FCS is not checked of course).
+                */
                } else if ((skb->len >= sizeof(llc_oui_pid_pad)) &&
                           (memcmp(skb->data, llc_oui_pid_pad, 7) == 0)) {
                        skb_pull(skb, sizeof(llc_oui_pid_pad));
@@ -479,8 +472,7 @@ static int br2684_regvcc(struct atm_vcc *atmvcc, void __user * arg)
        write_lock_irq(&devs_lock);
        net_dev = br2684_find_dev(&be.ifspec);
        if (net_dev == NULL) {
-               printk(KERN_ERR
-                      "br2684: tried to attach to non-existant device\n");
+               pr_err("tried to attach to non-existant device\n");
                err = -ENXIO;
                goto error;
        }
@@ -494,17 +486,16 @@ static int br2684_regvcc(struct atm_vcc *atmvcc, void __user * arg)
                err = -EEXIST;
                goto error;
        }
-       if (be.fcs_in != BR2684_FCSIN_NO || be.fcs_out != BR2684_FCSOUT_NO ||
-           be.fcs_auto || be.has_vpiid || be.send_padding || (be.encaps !=
-                                                              BR2684_ENCAPS_VC
-                                                              && be.encaps !=
-                                                              BR2684_ENCAPS_LLC)
-           || be.min_size != 0) {
+       if (be.fcs_in != BR2684_FCSIN_NO ||
+           be.fcs_out != BR2684_FCSOUT_NO ||
+           be.fcs_auto || be.has_vpiid || be.send_padding ||
+           (be.encaps != BR2684_ENCAPS_VC &&
+            be.encaps != BR2684_ENCAPS_LLC) ||
+           be.min_size != 0) {
                err = -EINVAL;
                goto error;
        }
-       pr_debug("br2684_regvcc vcc=%p, encaps=%d, brvcc=%p\n", atmvcc,
-                be.encaps, brvcc);
+       pr_debug("vcc=%p, encaps=%d, brvcc=%p\n", atmvcc, be.encaps, brvcc);
        if (list_empty(&brdev->brvccs) && !brdev->mac_was_set) {
                unsigned char *esi = atmvcc->dev->esi;
                if (esi[0] | esi[1] | esi[2] | esi[3] | esi[4] | esi[5])
@@ -541,7 +532,8 @@ static int br2684_regvcc(struct atm_vcc *atmvcc, void __user * arg)
        }
        __module_get(THIS_MODULE);
        return 0;
-      error:
+
+error:
        write_unlock_irq(&devs_lock);
        kfree(brvcc);
        return err;
@@ -587,7 +579,7 @@ static void br2684_setup_routed(struct net_device *netdev)
        INIT_LIST_HEAD(&brdev->brvccs);
 }
 
-static int br2684_create(void __user * arg)
+static int br2684_create(void __user *arg)
 {
        int err;
        struct net_device *netdev;
@@ -595,11 +587,10 @@ static int br2684_create(void __user * arg)
        struct atm_newif_br2684 ni;
        enum br2684_payload payload;
 
-       pr_debug("br2684_create\n");
+       pr_debug("\n");
 
-       if (copy_from_user(&ni, arg, sizeof ni)) {
+       if (copy_from_user(&ni, arg, sizeof ni))
                return -EFAULT;
-       }
 
        if (ni.media & BR2684_FLAG_ROUTED)
                payload = p_routed;
@@ -607,9 +598,8 @@ static int br2684_create(void __user * arg)
                payload = p_bridged;
        ni.media &= 0xffff;     /* strip flags */
 
-       if (ni.media != BR2684_MEDIA_ETHERNET || ni.mtu != 1500) {
+       if (ni.media != BR2684_MEDIA_ETHERNET || ni.mtu != 1500)
                return -EINVAL;
-       }
 
        netdev = alloc_netdev(sizeof(struct br2684_dev),
                              ni.ifname[0] ? ni.ifname : "nas%d",
@@ -624,7 +614,7 @@ static int br2684_create(void __user * arg)
        /* open, stop, do_ioctl ? */
        err = register_netdev(netdev);
        if (err < 0) {
-               printk(KERN_ERR "br2684_create: register_netdev failed\n");
+               pr_err("register_netdev failed\n");
                free_netdev(netdev);
                return err;
        }
index 64629c354343d6debd8a8c105ef5b86c7ca0456b..ebfa022008f79aff20202c2c13ae0b04ee117d81 100644 (file)
@@ -2,6 +2,8 @@
 
 /* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
+
 #include <linux/string.h>
 #include <linux/errno.h>
 #include <linux/kernel.h> /* for UINT_MAX */
 #include <linux/jhash.h>
 #include <net/route.h> /* for struct rtable and routing */
 #include <net/icmp.h> /* icmp_send */
-#include <asm/param.h> /* for HZ */
+#include <linux/param.h> /* for HZ */
+#include <linux/uaccess.h>
 #include <asm/byteorder.h> /* for htons etc. */
 #include <asm/system.h> /* save/restore_flags */
-#include <asm/uaccess.h>
 #include <asm/atomic.h>
 
 #include "common.h"
@@ -51,13 +53,13 @@ static int to_atmarpd(enum atmarp_ctrl_type type, int itf, __be32 ip)
        struct atmarp_ctrl *ctrl;
        struct sk_buff *skb;
 
-       pr_debug("to_atmarpd(%d)\n", type);
+       pr_debug("(%d)\n", type);
        if (!atmarpd)
                return -EUNATCH;
-       skb = alloc_skb(sizeof(struct atmarp_ctrl),GFP_ATOMIC);
+       skb = alloc_skb(sizeof(struct atmarp_ctrl), GFP_ATOMIC);
        if (!skb)
                return -ENOMEM;
-       ctrl = (struct atmarp_ctrl *) skb_put(skb,sizeof(struct atmarp_ctrl));
+       ctrl = (struct atmarp_ctrl *)skb_put(skb, sizeof(struct atmarp_ctrl));
        ctrl->type = type;
        ctrl->itf_num = itf;
        ctrl->ip = ip;
@@ -71,8 +73,7 @@ static int to_atmarpd(enum atmarp_ctrl_type type, int itf, __be32 ip)
 
 static void link_vcc(struct clip_vcc *clip_vcc, struct atmarp_entry *entry)
 {
-       pr_debug("link_vcc %p to entry %p (neigh %p)\n", clip_vcc, entry,
-               entry->neigh);
+       pr_debug("%p to entry %p (neigh %p)\n", clip_vcc, entry, entry->neigh);
        clip_vcc->entry = entry;
        clip_vcc->xoff = 0;     /* @@@ may overrun buffer by one packet */
        clip_vcc->next = entry->vccs;
@@ -86,7 +87,7 @@ static void unlink_clip_vcc(struct clip_vcc *clip_vcc)
        struct clip_vcc **walk;
 
        if (!entry) {
-               printk(KERN_CRIT "!clip_vcc->entry (clip_vcc %p)\n", clip_vcc);
+               pr_crit("!clip_vcc->entry (clip_vcc %p)\n", clip_vcc);
                return;
        }
        netif_tx_lock_bh(entry->neigh->dev);    /* block clip_start_xmit() */
@@ -106,13 +107,11 @@ static void unlink_clip_vcc(struct clip_vcc *clip_vcc)
                        error = neigh_update(entry->neigh, NULL, NUD_NONE,
                                             NEIGH_UPDATE_F_ADMIN);
                        if (error)
-                               printk(KERN_CRIT "unlink_clip_vcc: "
-                                      "neigh_update failed with %d\n", error);
+                               pr_crit("neigh_update failed with %d\n", error);
                        goto out;
                }
-       printk(KERN_CRIT "ATMARP: unlink_clip_vcc failed (entry %p, vcc "
-              "0x%p)\n", entry, clip_vcc);
-      out:
+       pr_crit("ATMARP: failed (entry %p, vcc 0x%p)\n", entry, clip_vcc);
+out:
        netif_tx_unlock_bh(entry->neigh->dev);
 }
 
@@ -127,7 +126,7 @@ static int neigh_check_cb(struct neighbour *n)
 
                if (cv->idle_timeout && time_after(jiffies, exp)) {
                        pr_debug("releasing vcc %p->%p of entry %p\n",
-                               cv, cv->vcc, entry);
+                                cv, cv->vcc, entry);
                        vcc_release_async(cv->vcc, -ETIMEDOUT);
                }
        }
@@ -139,7 +138,7 @@ static int neigh_check_cb(struct neighbour *n)
                struct sk_buff *skb;
 
                pr_debug("destruction postponed with ref %d\n",
-                       atomic_read(&n->refcnt));
+                        atomic_read(&n->refcnt));
 
                while ((skb = skb_dequeue(&n->arp_queue)) != NULL)
                        dev_kfree_skb(skb);
@@ -163,7 +162,7 @@ static int clip_arp_rcv(struct sk_buff *skb)
 {
        struct atm_vcc *vcc;
 
-       pr_debug("clip_arp_rcv\n");
+       pr_debug("\n");
        vcc = ATM_SKB(skb)->vcc;
        if (!vcc || !atm_charge(vcc, skb->truesize)) {
                dev_kfree_skb_any(skb);
@@ -188,7 +187,7 @@ static void clip_push(struct atm_vcc *vcc, struct sk_buff *skb)
 {
        struct clip_vcc *clip_vcc = CLIP_VCC(vcc);
 
-       pr_debug("clip push\n");
+       pr_debug("\n");
        if (!skb) {
                pr_debug("removing VCC %p\n", clip_vcc);
                if (clip_vcc->entry)
@@ -206,12 +205,12 @@ static void clip_push(struct atm_vcc *vcc, struct sk_buff *skb)
        }
        ATM_SKB(skb)->vcc = vcc;
        skb_reset_mac_header(skb);
-       if (!clip_vcc->encap
-           || skb->len < RFC1483LLC_LEN
-           || memcmp(skb->data, llc_oui, sizeof (llc_oui)))
+       if (!clip_vcc->encap ||
+           skb->len < RFC1483LLC_LEN ||
+           memcmp(skb->data, llc_oui, sizeof(llc_oui)))
                skb->protocol = htons(ETH_P_IP);
        else {
-               skb->protocol = ((__be16 *) skb->data)[3];
+               skb->protocol = ((__be16 *)skb->data)[3];
                skb_pull(skb, RFC1483LLC_LEN);
                if (skb->protocol == htons(ETH_P_ARP)) {
                        skb->dev->stats.rx_packets++;
@@ -239,7 +238,7 @@ static void clip_pop(struct atm_vcc *vcc, struct sk_buff *skb)
        int old;
        unsigned long flags;
 
-       pr_debug("clip_pop(vcc %p)\n", vcc);
+       pr_debug("(vcc %p)\n", vcc);
        clip_vcc->old_pop(vcc, skb);
        /* skb->dev == NULL in outbound ARP packets */
        if (!dev)
@@ -255,7 +254,7 @@ static void clip_pop(struct atm_vcc *vcc, struct sk_buff *skb)
 
 static void clip_neigh_solicit(struct neighbour *neigh, struct sk_buff *skb)
 {
-       pr_debug("clip_neigh_solicit (neigh %p, skb %p)\n", neigh, skb);
+       pr_debug("(neigh %p, skb %p)\n", neigh, skb);
        to_atmarpd(act_need, PRIV(neigh->dev)->number, NEIGH2ENTRY(neigh)->ip);
 }
 
@@ -284,7 +283,7 @@ static int clip_constructor(struct neighbour *neigh)
        struct in_device *in_dev;
        struct neigh_parms *parms;
 
-       pr_debug("clip_constructor (neigh %p, entry %p)\n", neigh, entry);
+       pr_debug("(neigh %p, entry %p)\n", neigh, entry);
        neigh->type = inet_addr_type(&init_net, entry->ip);
        if (neigh->type != RTN_UNICAST)
                return -EINVAL;
@@ -369,9 +368,9 @@ static netdev_tx_t clip_start_xmit(struct sk_buff *skb,
        int old;
        unsigned long flags;
 
-       pr_debug("clip_start_xmit (skb %p)\n", skb);
+       pr_debug("(skb %p)\n", skb);
        if (!skb_dst(skb)) {
-               printk(KERN_ERR "clip_start_xmit: skb_dst(skb) == NULL\n");
+               pr_err("skb_dst(skb) == NULL\n");
                dev_kfree_skb(skb);
                dev->stats.tx_dropped++;
                return NETDEV_TX_OK;
@@ -385,7 +384,7 @@ static netdev_tx_t clip_start_xmit(struct sk_buff *skb,
                        return 0;
                }
 #endif
-               printk(KERN_ERR "clip_start_xmit: NO NEIGHBOUR !\n");
+               pr_err("NO NEIGHBOUR !\n");
                dev_kfree_skb(skb);
                dev->stats.tx_dropped++;
                return NETDEV_TX_OK;
@@ -421,7 +420,7 @@ static netdev_tx_t clip_start_xmit(struct sk_buff *skb,
        pr_debug("atm_skb(%p)->vcc(%p)->dev(%p)\n", skb, vcc, vcc->dev);
        old = xchg(&entry->vccs->xoff, 1);      /* assume XOFF ... */
        if (old) {
-               printk(KERN_WARNING "clip_start_xmit: XOFF->XOFF transition\n");
+               pr_warning("XOFF->XOFF transition\n");
                return NETDEV_TX_OK;
        }
        dev->stats.tx_packets++;
@@ -456,7 +455,7 @@ static int clip_mkip(struct atm_vcc *vcc, int timeout)
        clip_vcc = kmalloc(sizeof(struct clip_vcc), GFP_KERNEL);
        if (!clip_vcc)
                return -ENOMEM;
-       pr_debug("mkip clip_vcc %p vcc %p\n", clip_vcc, vcc);
+       pr_debug("%p vcc %p\n", clip_vcc, vcc);
        clip_vcc->vcc = vcc;
        vcc->user_back = clip_vcc;
        set_bit(ATM_VF_IS_CLIP, &vcc->flags);
@@ -506,16 +505,16 @@ static int clip_setentry(struct atm_vcc *vcc, __be32 ip)
        struct rtable *rt;
 
        if (vcc->push != clip_push) {
-               printk(KERN_WARNING "clip_setentry: non-CLIP VCC\n");
+               pr_warning("non-CLIP VCC\n");
                return -EBADF;
        }
        clip_vcc = CLIP_VCC(vcc);
        if (!ip) {
                if (!clip_vcc->entry) {
-                       printk(KERN_ERR "hiding hidden ATMARP entry\n");
+                       pr_err("hiding hidden ATMARP entry\n");
                        return 0;
                }
-               pr_debug("setentry: remove\n");
+               pr_debug("remove\n");
                unlink_clip_vcc(clip_vcc);
                return 0;
        }
@@ -529,9 +528,9 @@ static int clip_setentry(struct atm_vcc *vcc, __be32 ip)
        entry = NEIGH2ENTRY(neigh);
        if (entry != clip_vcc->entry) {
                if (!clip_vcc->entry)
-                       pr_debug("setentry: add\n");
+                       pr_debug("add\n");
                else {
-                       pr_debug("setentry: update\n");
+                       pr_debug("update\n");
                        unlink_clip_vcc(clip_vcc);
                }
                link_vcc(clip_vcc, entry);
@@ -614,16 +613,16 @@ static int clip_device_event(struct notifier_block *this, unsigned long event,
 
        switch (event) {
        case NETDEV_UP:
-               pr_debug("clip_device_event NETDEV_UP\n");
+               pr_debug("NETDEV_UP\n");
                to_atmarpd(act_up, PRIV(dev)->number, 0);
                break;
        case NETDEV_GOING_DOWN:
-               pr_debug("clip_device_event NETDEV_DOWN\n");
+               pr_debug("NETDEV_DOWN\n");
                to_atmarpd(act_down, PRIV(dev)->number, 0);
                break;
        case NETDEV_CHANGE:
        case NETDEV_CHANGEMTU:
-               pr_debug("clip_device_event NETDEV_CHANGE*\n");
+               pr_debug("NETDEV_CHANGE*\n");
                to_atmarpd(act_change, PRIV(dev)->number, 0);
                break;
        }
@@ -645,7 +644,6 @@ static int clip_inet_event(struct notifier_block *this, unsigned long event,
        return clip_device_event(this, NETDEV_CHANGE, in_dev->dev);
 }
 
-
 static struct notifier_block clip_dev_notifier = {
        .notifier_call = clip_device_event,
 };
@@ -660,7 +658,7 @@ static struct notifier_block clip_inet_notifier = {
 
 static void atmarpd_close(struct atm_vcc *vcc)
 {
-       pr_debug("atmarpd_close\n");
+       pr_debug("\n");
 
        rtnl_lock();
        atmarpd = NULL;
@@ -671,7 +669,6 @@ static void atmarpd_close(struct atm_vcc *vcc)
        module_put(THIS_MODULE);
 }
 
-
 static struct atmdev_ops atmarpd_dev_ops = {
        .close = atmarpd_close
 };
@@ -693,11 +690,11 @@ static int atm_init_atmarp(struct atm_vcc *vcc)
                return -EADDRINUSE;
        }
 
-       mod_timer(&idle_timer, jiffies+CLIP_CHECK_INTERVAL*HZ);
+       mod_timer(&idle_timer, jiffies + CLIP_CHECK_INTERVAL * HZ);
 
        atmarpd = vcc;
-       set_bit(ATM_VF_META,&vcc->flags);
-       set_bit(ATM_VF_READY,&vcc->flags);
+       set_bit(ATM_VF_META, &vcc->flags);
+       set_bit(ATM_VF_READY, &vcc->flags);
            /* allow replies and avoid getting closed if signaling dies */
        vcc->dev = &atmarpd_dev;
        vcc_insert_socket(sk_atm(vcc));
@@ -950,8 +947,7 @@ static int __init atm_clip_init(void)
 
                p = proc_create("arp", S_IRUGO, atm_proc_root, &arp_seq_fops);
                if (!p) {
-                       printk(KERN_ERR "Unable to initialize "
-                              "/proc/net/atm/arp\n");
+                       pr_err("Unable to initialize /proc/net/atm/arp\n");
                        atm_clip_exit_noproc();
                        return -ENOMEM;
                }
index d61e051e0a3f047c4a0f3ea1cce56d4c176b1b4e..74d095a081e3ed0a667ab6805b2c361d51cf81d3 100644 (file)
@@ -2,6 +2,7 @@
 
 /* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
 
 #include <linux/module.h>
 #include <linux/kmod.h>
 #include <linux/bitops.h>
 #include <linux/init.h>
 #include <net/sock.h>          /* struct sock */
+#include <linux/uaccess.h>
+#include <linux/poll.h>
 
-#include <asm/uaccess.h>
 #include <asm/atomic.h>
-#include <asm/poll.h>
-
 
 #include "resources.h"         /* atm_find_dev */
 #include "common.h"            /* prototypes */
 #include "signaling.h"         /* for WAITING and sigd_attach */
 
 struct hlist_head vcc_hash[VCC_HTABLE_SIZE];
+EXPORT_SYMBOL(vcc_hash);
+
 DEFINE_RWLOCK(vcc_sklist_lock);
+EXPORT_SYMBOL(vcc_sklist_lock);
 
 static void __vcc_insert_socket(struct sock *sk)
 {
        struct atm_vcc *vcc = atm_sk(sk);
-       struct hlist_head *head = &vcc_hash[vcc->vci &
-                                       (VCC_HTABLE_SIZE - 1)];
+       struct hlist_head *head = &vcc_hash[vcc->vci & (VCC_HTABLE_SIZE - 1)];
        sk->sk_hash = vcc->vci & (VCC_HTABLE_SIZE - 1);
        sk_add_node(sk, head);
 }
@@ -48,6 +50,7 @@ void vcc_insert_socket(struct sock *sk)
        __vcc_insert_socket(sk);
        write_unlock_irq(&vcc_sklist_lock);
 }
+EXPORT_SYMBOL(vcc_insert_socket);
 
 static void vcc_remove_socket(struct sock *sk)
 {
@@ -56,37 +59,32 @@ static void vcc_remove_socket(struct sock *sk)
        write_unlock_irq(&vcc_sklist_lock);
 }
 
-
-static struct sk_buff *alloc_tx(struct atm_vcc *vcc,unsigned int size)
+static struct sk_buff *alloc_tx(struct atm_vcc *vcc, unsigned int size)
 {
        struct sk_buff *skb;
        struct sock *sk = sk_atm(vcc);
 
        if (sk_wmem_alloc_get(sk) && !atm_may_send(vcc, size)) {
                pr_debug("Sorry: wmem_alloc = %d, size = %d, sndbuf = %d\n",
-                       sk_wmem_alloc_get(sk), size,
-                       sk->sk_sndbuf);
+                        sk_wmem_alloc_get(sk), size, sk->sk_sndbuf);
                return NULL;
        }
        while (!(skb = alloc_skb(size, GFP_KERNEL)))
                schedule();
-       pr_debug("AlTx %d += %d\n", sk_wmem_alloc_get(sk), skb->truesize);
+       pr_debug("%d += %d\n", sk_wmem_alloc_get(sk), skb->truesize);
        atomic_add(skb->truesize, &sk->sk_wmem_alloc);
        return skb;
 }
 
-
-EXPORT_SYMBOL(vcc_hash);
-EXPORT_SYMBOL(vcc_sklist_lock);
-EXPORT_SYMBOL(vcc_insert_socket);
-
 static void vcc_sock_destruct(struct sock *sk)
 {
        if (atomic_read(&sk->sk_rmem_alloc))
-               printk(KERN_DEBUG "vcc_sock_destruct: rmem leakage (%d bytes) detected.\n", atomic_read(&sk->sk_rmem_alloc));
+               printk(KERN_DEBUG "%s: rmem leakage (%d bytes) detected.\n",
+                      __func__, atomic_read(&sk->sk_rmem_alloc));
 
        if (atomic_read(&sk->sk_wmem_alloc))
-               printk(KERN_DEBUG "vcc_sock_destruct: wmem leakage (%d bytes) detected.\n", atomic_read(&sk->sk_wmem_alloc));
+               printk(KERN_DEBUG "%s: wmem leakage (%d bytes) detected.\n",
+                      __func__, atomic_read(&sk->sk_wmem_alloc));
 }
 
 static void vcc_def_wakeup(struct sock *sk)
@@ -142,8 +140,8 @@ int vcc_create(struct net *net, struct socket *sock, int protocol, int family)
 
        vcc = atm_sk(sk);
        vcc->dev = NULL;
-       memset(&vcc->local,0,sizeof(struct sockaddr_atmsvc));
-       memset(&vcc->remote,0,sizeof(struct sockaddr_atmsvc));
+       memset(&vcc->local, 0, sizeof(struct sockaddr_atmsvc));
+       memset(&vcc->remote, 0, sizeof(struct sockaddr_atmsvc));
        vcc->qos.txtp.max_sdu = 1 << 16; /* for meta VCs */
        atomic_set(&sk->sk_wmem_alloc, 1);
        atomic_set(&sk->sk_rmem_alloc, 0);
@@ -156,7 +154,6 @@ int vcc_create(struct net *net, struct socket *sock, int protocol, int family)
        return 0;
 }
 
-
 static void vcc_destroy_socket(struct sock *sk)
 {
        struct atm_vcc *vcc = atm_sk(sk);
@@ -171,7 +168,7 @@ static void vcc_destroy_socket(struct sock *sk)
                        vcc->push(vcc, NULL); /* atmarpd has no push */
 
                while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) {
-                       atm_return(vcc,skb->truesize);
+                       atm_return(vcc, skb->truesize);
                        kfree_skb(skb);
                }
 
@@ -182,7 +179,6 @@ static void vcc_destroy_socket(struct sock *sk)
        vcc_remove_socket(sk);
 }
 
-
 int vcc_release(struct socket *sock)
 {
        struct sock *sk = sock->sk;
@@ -197,7 +193,6 @@ int vcc_release(struct socket *sock)
        return 0;
 }
 
-
 void vcc_release_async(struct atm_vcc *vcc, int reply)
 {
        struct sock *sk = sk_atm(vcc);
@@ -208,8 +203,6 @@ void vcc_release_async(struct atm_vcc *vcc, int reply)
        clear_bit(ATM_VF_WAITING, &vcc->flags);
        sk->sk_state_change(sk);
 }
-
-
 EXPORT_SYMBOL(vcc_release_async);
 
 
@@ -235,37 +228,37 @@ void atm_dev_release_vccs(struct atm_dev *dev)
        write_unlock_irq(&vcc_sklist_lock);
 }
 
-
-static int adjust_tp(struct atm_trafprm *tp,unsigned char aal)
+static int adjust_tp(struct atm_trafprm *tp, unsigned char aal)
 {
        int max_sdu;
 
-       if (!tp->traffic_class) return 0;
+       if (!tp->traffic_class)
+               return 0;
        switch (aal) {
-               case ATM_AAL0:
-                       max_sdu = ATM_CELL_SIZE-1;
-                       break;
-               case ATM_AAL34:
-                       max_sdu = ATM_MAX_AAL34_PDU;
-                       break;
-               default:
-                       printk(KERN_WARNING "ATM: AAL problems ... "
-                           "(%d)\n",aal);
-                       /* fall through */
-               case ATM_AAL5:
-                       max_sdu = ATM_MAX_AAL5_PDU;
+       case ATM_AAL0:
+               max_sdu = ATM_CELL_SIZE-1;
+               break;
+       case ATM_AAL34:
+               max_sdu = ATM_MAX_AAL34_PDU;
+               break;
+       default:
+               pr_warning("AAL problems ... (%d)\n", aal);
+               /* fall through */
+       case ATM_AAL5:
+               max_sdu = ATM_MAX_AAL5_PDU;
        }
-       if (!tp->max_sdu) tp->max_sdu = max_sdu;
-       else if (tp->max_sdu > max_sdu) return -EINVAL;
-       if (!tp->max_cdv) tp->max_cdv = ATM_MAX_CDV;
+       if (!tp->max_sdu)
+               tp->max_sdu = max_sdu;
+       else if (tp->max_sdu > max_sdu)
+               return -EINVAL;
+       if (!tp->max_cdv)
+               tp->max_cdv = ATM_MAX_CDV;
        return 0;
 }
 
-
 static int check_ci(const struct atm_vcc *vcc, short vpi, int vci)
 {
-       struct hlist_head *head = &vcc_hash[vci &
-                                       (VCC_HTABLE_SIZE - 1)];
+       struct hlist_head *head = &vcc_hash[vci & (VCC_HTABLE_SIZE - 1)];
        struct hlist_node *node;
        struct sock *s;
        struct atm_vcc *walk;
@@ -289,7 +282,6 @@ static int check_ci(const struct atm_vcc *vcc, short vpi, int vci)
        return 0;
 }
 
-
 static int find_ci(const struct atm_vcc *vcc, short *vpi, int *vci)
 {
        static short p;        /* poor man's per-device cache */
@@ -327,14 +319,13 @@ static int find_ci(const struct atm_vcc *vcc, short *vpi, int *vci)
                if ((c == ATM_NOT_RSV_VCI || *vci != ATM_VCI_ANY) &&
                    *vpi == ATM_VPI_ANY) {
                        p++;
-                       if (p >= 1 << vcc->dev->ci_range.vpi_bits) p = 0;
+                       if (p >= 1 << vcc->dev->ci_range.vpi_bits)
+                               p = 0;
                }
-       }
-       while (old_p != p || old_c != c);
+       } while (old_p != p || old_c != c);
        return -EADDRINUSE;
 }
 
-
 static int __vcc_connect(struct atm_vcc *vcc, struct atm_dev *dev, short vpi,
                         int vci)
 {
@@ -362,37 +353,46 @@ static int __vcc_connect(struct atm_vcc *vcc, struct atm_dev *dev, short vpi,
        __vcc_insert_socket(sk);
        write_unlock_irq(&vcc_sklist_lock);
        switch (vcc->qos.aal) {
-               case ATM_AAL0:
-                       error = atm_init_aal0(vcc);
-                       vcc->stats = &dev->stats.aal0;
-                       break;
-               case ATM_AAL34:
-                       error = atm_init_aal34(vcc);
-                       vcc->stats = &dev->stats.aal34;
-                       break;
-               case ATM_NO_AAL:
-                       /* ATM_AAL5 is also used in the "0 for default" case */
-                       vcc->qos.aal = ATM_AAL5;
-                       /* fall through */
-               case ATM_AAL5:
-                       error = atm_init_aal5(vcc);
-                       vcc->stats = &dev->stats.aal5;
-                       break;
-               default:
-                       error = -EPROTOTYPE;
+       case ATM_AAL0:
+               error = atm_init_aal0(vcc);
+               vcc->stats = &dev->stats.aal0;
+               break;
+       case ATM_AAL34:
+               error = atm_init_aal34(vcc);
+               vcc->stats = &dev->stats.aal34;
+               break;
+       case ATM_NO_AAL:
+               /* ATM_AAL5 is also used in the "0 for default" case */
+               vcc->qos.aal = ATM_AAL5;
+               /* fall through */
+       case ATM_AAL5:
+               error = atm_init_aal5(vcc);
+               vcc->stats = &dev->stats.aal5;
+               break;
+       default:
+               error = -EPROTOTYPE;
        }
-       if (!error) error = adjust_tp(&vcc->qos.txtp,vcc->qos.aal);
-       if (!error) error = adjust_tp(&vcc->qos.rxtp,vcc->qos.aal);
+       if (!error)
+               error = adjust_tp(&vcc->qos.txtp, vcc->qos.aal);
+       if (!error)
+               error = adjust_tp(&vcc->qos.rxtp, vcc->qos.aal);
        if (error)
                goto fail;
-       pr_debug("VCC %d.%d, AAL %d\n",vpi,vci,vcc->qos.aal);
-       pr_debug("  TX: %d, PCR %d..%d, SDU %d\n",vcc->qos.txtp.traffic_class,
-           vcc->qos.txtp.min_pcr,vcc->qos.txtp.max_pcr,vcc->qos.txtp.max_sdu);
-       pr_debug("  RX: %d, PCR %d..%d, SDU %d\n",vcc->qos.rxtp.traffic_class,
-           vcc->qos.rxtp.min_pcr,vcc->qos.rxtp.max_pcr,vcc->qos.rxtp.max_sdu);
+       pr_debug("VCC %d.%d, AAL %d\n", vpi, vci, vcc->qos.aal);
+       pr_debug("  TX: %d, PCR %d..%d, SDU %d\n",
+                vcc->qos.txtp.traffic_class,
+                vcc->qos.txtp.min_pcr,
+                vcc->qos.txtp.max_pcr,
+                vcc->qos.txtp.max_sdu);
+       pr_debug("  RX: %d, PCR %d..%d, SDU %d\n",
+                vcc->qos.rxtp.traffic_class,
+                vcc->qos.rxtp.min_pcr,
+                vcc->qos.rxtp.max_pcr,
+                vcc->qos.rxtp.max_sdu);
 
        if (dev->ops->open) {
-               if ((error = dev->ops->open(vcc)))
+               error = dev->ops->open(vcc);
+               if (error)
                        goto fail;
        }
        return 0;
@@ -406,14 +406,13 @@ fail_module_put:
        return error;
 }
 
-
 int vcc_connect(struct socket *sock, int itf, short vpi, int vci)
 {
        struct atm_dev *dev;
        struct atm_vcc *vcc = ATM_SD(sock);
        int error;
 
-       pr_debug("vcc_connect (vpi %d, vci %d)\n",vpi,vci);
+       pr_debug("(vpi %d, vci %d)\n", vpi, vci);
        if (sock->state == SS_CONNECTED)
                return -EISCONN;
        if (sock->state != SS_UNCONNECTED)
@@ -422,30 +421,33 @@ int vcc_connect(struct socket *sock, int itf, short vpi, int vci)
                return -EINVAL;
 
        if (vpi != ATM_VPI_UNSPEC && vci != ATM_VCI_UNSPEC)
-               clear_bit(ATM_VF_PARTIAL,&vcc->flags);
+               clear_bit(ATM_VF_PARTIAL, &vcc->flags);
        else
-               if (test_bit(ATM_VF_PARTIAL,&vcc->flags))
+               if (test_bit(ATM_VF_PARTIAL, &vcc->flags))
                        return -EINVAL;
-       pr_debug("vcc_connect (TX: cl %d,bw %d-%d,sdu %d; "
-           "RX: cl %d,bw %d-%d,sdu %d,AAL %s%d)\n",
-           vcc->qos.txtp.traffic_class,vcc->qos.txtp.min_pcr,
-           vcc->qos.txtp.max_pcr,vcc->qos.txtp.max_sdu,
-           vcc->qos.rxtp.traffic_class,vcc->qos.rxtp.min_pcr,
-           vcc->qos.rxtp.max_pcr,vcc->qos.rxtp.max_sdu,
-           vcc->qos.aal == ATM_AAL5 ? "" : vcc->qos.aal == ATM_AAL0 ? "" :
-           " ??? code ",vcc->qos.aal == ATM_AAL0 ? 0 : vcc->qos.aal);
+       pr_debug("(TX: cl %d,bw %d-%d,sdu %d; "
+                "RX: cl %d,bw %d-%d,sdu %d,AAL %s%d)\n",
+                vcc->qos.txtp.traffic_class, vcc->qos.txtp.min_pcr,
+                vcc->qos.txtp.max_pcr, vcc->qos.txtp.max_sdu,
+                vcc->qos.rxtp.traffic_class, vcc->qos.rxtp.min_pcr,
+                vcc->qos.rxtp.max_pcr, vcc->qos.rxtp.max_sdu,
+                vcc->qos.aal == ATM_AAL5 ? "" :
+                vcc->qos.aal == ATM_AAL0 ? "" : " ??? code ",
+                vcc->qos.aal == ATM_AAL0 ? 0 : vcc->qos.aal);
        if (!test_bit(ATM_VF_HASQOS, &vcc->flags))
                return -EBADFD;
        if (vcc->qos.txtp.traffic_class == ATM_ANYCLASS ||
            vcc->qos.rxtp.traffic_class == ATM_ANYCLASS)
                return -EINVAL;
        if (likely(itf != ATM_ITF_ANY)) {
-               dev = try_then_request_module(atm_dev_lookup(itf), "atm-device-%d", itf);
+               dev = try_then_request_module(atm_dev_lookup(itf),
+                                             "atm-device-%d", itf);
        } else {
                dev = NULL;
                mutex_lock(&atm_dev_mutex);
                if (!list_empty(&atm_devs)) {
-                       dev = list_entry(atm_devs.next, struct atm_dev, dev_list);
+                       dev = list_entry(atm_devs.next,
+                                        struct atm_dev, dev_list);
                        atm_dev_hold(dev);
                }
                mutex_unlock(&atm_dev_mutex);
@@ -458,13 +460,12 @@ int vcc_connect(struct socket *sock, int itf, short vpi, int vci)
                return error;
        }
        if (vpi == ATM_VPI_UNSPEC || vci == ATM_VCI_UNSPEC)
-               set_bit(ATM_VF_PARTIAL,&vcc->flags);
-       if (test_bit(ATM_VF_READY,&ATM_SD(sock)->flags))
+               set_bit(ATM_VF_PARTIAL, &vcc->flags);
+       if (test_bit(ATM_VF_READY, &ATM_SD(sock)->flags))
                sock->state = SS_CONNECTED;
        return 0;
 }
 
-
 int vcc_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
                size_t size, int flags)
 {
@@ -478,8 +479,8 @@ int vcc_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
        if (flags & ~MSG_DONTWAIT)              /* only handle MSG_DONTWAIT */
                return -EOPNOTSUPP;
        vcc = ATM_SD(sock);
-       if (test_bit(ATM_VF_RELEASED,&vcc->flags) ||
-           test_bit(ATM_VF_CLOSE,&vcc->flags) ||
+       if (test_bit(ATM_VF_RELEASED, &vcc->flags) ||
+           test_bit(ATM_VF_CLOSE, &vcc->flags) ||
            !test_bit(ATM_VF_READY, &vcc->flags))
                return 0;
 
@@ -497,13 +498,12 @@ int vcc_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
        if (error)
                return error;
        sock_recv_ts_and_drops(msg, sk, skb);
-       pr_debug("RcvM %d -= %d\n", atomic_read(&sk->sk_rmem_alloc), skb->truesize);
+       pr_debug("%d -= %d\n", atomic_read(&sk->sk_rmem_alloc), skb->truesize);
        atm_return(vcc, skb->truesize);
        skb_free_datagram(sk, skb);
        return copied;
 }
 
-
 int vcc_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m,
                size_t total_len)
 {
@@ -511,7 +511,7 @@ int vcc_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m,
        DEFINE_WAIT(wait);
        struct atm_vcc *vcc;
        struct sk_buff *skb;
-       int eff,error;
+       int eff, error;
        const void __user *buff;
        int size;
 
@@ -550,7 +550,7 @@ int vcc_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m,
        eff = (size+3) & ~3; /* align to word boundary */
        prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
        error = 0;
-       while (!(skb = alloc_tx(vcc,eff))) {
+       while (!(skb = alloc_tx(vcc, eff))) {
                if (m->msg_flags & MSG_DONTWAIT) {
                        error = -EAGAIN;
                        break;
@@ -560,9 +560,9 @@ int vcc_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m,
                        error = -ERESTARTSYS;
                        break;
                }
-               if (test_bit(ATM_VF_RELEASED,&vcc->flags) ||
-                   test_bit(ATM_VF_CLOSE,&vcc->flags) ||
-                   !test_bit(ATM_VF_READY,&vcc->flags)) {
+               if (test_bit(ATM_VF_RELEASED, &vcc->flags) ||
+                   test_bit(ATM_VF_CLOSE, &vcc->flags) ||
+                   !test_bit(ATM_VF_READY, &vcc->flags)) {
                        error = -EPIPE;
                        send_sig(SIGPIPE, current, 0);
                        break;
@@ -574,20 +574,20 @@ int vcc_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m,
                goto out;
        skb->dev = NULL; /* for paths shared with net_device interfaces */
        ATM_SKB(skb)->atm_options = vcc->atm_options;
-       if (copy_from_user(skb_put(skb,size),buff,size)) {
+       if (copy_from_user(skb_put(skb, size), buff, size)) {
                kfree_skb(skb);
                error = -EFAULT;
                goto out;
        }
-       if (eff != size) memset(skb->data+size,0,eff-size);
-       error = vcc->dev->ops->send(vcc,skb);
+       if (eff != size)
+               memset(skb->data + size, 0, eff-size);
+       error = vcc->dev->ops->send(vcc, skb);
        error = error ? error : size;
 out:
        release_sock(sk);
        return error;
 }
 
-
 unsigned int vcc_poll(struct file *file, struct socket *sock, poll_table *wait)
 {
        struct sock *sk = sock->sk;
@@ -623,8 +623,7 @@ unsigned int vcc_poll(struct file *file, struct socket *sock, poll_table *wait)
        return mask;
 }
 
-
-static int atm_change_qos(struct atm_vcc *vcc,struct atm_qos *qos)
+static int atm_change_qos(struct atm_vcc *vcc, struct atm_qos *qos)
 {
        int error;
 
@@ -636,25 +635,31 @@ static int atm_change_qos(struct atm_vcc *vcc,struct atm_qos *qos)
            qos->rxtp.traffic_class != vcc->qos.rxtp.traffic_class ||
            qos->txtp.traffic_class != vcc->qos.txtp.traffic_class)
                return -EINVAL;
-       error = adjust_tp(&qos->txtp,qos->aal);
-       if (!error) error = adjust_tp(&qos->rxtp,qos->aal);
-       if (error) return error;
-       if (!vcc->dev->ops->change_qos) return -EOPNOTSUPP;
+       error = adjust_tp(&qos->txtp, qos->aal);
+       if (!error)
+               error = adjust_tp(&qos->rxtp, qos->aal);
+       if (error)
+               return error;
+       if (!vcc->dev->ops->change_qos)
+               return -EOPNOTSUPP;
        if (sk_atm(vcc)->sk_family == AF_ATMPVC)
-               return vcc->dev->ops->change_qos(vcc,qos,ATM_MF_SET);
-       return svc_change_qos(vcc,qos);
+               return vcc->dev->ops->change_qos(vcc, qos, ATM_MF_SET);
+       return svc_change_qos(vcc, qos);
 }
 
-
 static int check_tp(const struct atm_trafprm *tp)
 {
        /* @@@ Should be merged with adjust_tp */
-       if (!tp->traffic_class || tp->traffic_class == ATM_ANYCLASS) return 0;
+       if (!tp->traffic_class || tp->traffic_class == ATM_ANYCLASS)
+               return 0;
        if (tp->traffic_class != ATM_UBR && !tp->min_pcr && !tp->pcr &&
-           !tp->max_pcr) return -EINVAL;
-       if (tp->min_pcr == ATM_MAX_PCR) return -EINVAL;
+           !tp->max_pcr)
+               return -EINVAL;
+       if (tp->min_pcr == ATM_MAX_PCR)
+               return -EINVAL;
        if (tp->min_pcr && tp->max_pcr && tp->max_pcr != ATM_MAX_PCR &&
-           tp->min_pcr > tp->max_pcr) return -EINVAL;
+           tp->min_pcr > tp->max_pcr)
+               return -EINVAL;
        /*
         * We allow pcr to be outside [min_pcr,max_pcr], because later
         * adjustment may still push it in the valid range.
@@ -662,7 +667,6 @@ static int check_tp(const struct atm_trafprm *tp)
        return 0;
 }
 
-
 static int check_qos(const struct atm_qos *qos)
 {
        int error;
@@ -672,9 +676,11 @@ static int check_qos(const struct atm_qos *qos)
        if (qos->txtp.traffic_class != qos->rxtp.traffic_class &&
            qos->txtp.traffic_class && qos->rxtp.traffic_class &&
            qos->txtp.traffic_class != ATM_ANYCLASS &&
-           qos->rxtp.traffic_class != ATM_ANYCLASS) return -EINVAL;
+           qos->rxtp.traffic_class != ATM_ANYCLASS)
+               return -EINVAL;
        error = check_tp(&qos->txtp);
-       if (error) return error;
+       if (error)
+               return error;
        return check_tp(&qos->rxtp);
 }
 
@@ -690,37 +696,41 @@ int vcc_setsockopt(struct socket *sock, int level, int optname,
 
        vcc = ATM_SD(sock);
        switch (optname) {
-               case SO_ATMQOS:
-                       {
-                               struct atm_qos qos;
-
-                               if (copy_from_user(&qos,optval,sizeof(qos)))
-                                       return -EFAULT;
-                               error = check_qos(&qos);
-                               if (error) return error;
-                               if (sock->state == SS_CONNECTED)
-                                       return atm_change_qos(vcc,&qos);
-                               if (sock->state != SS_UNCONNECTED)
-                                       return -EBADFD;
-                               vcc->qos = qos;
-                               set_bit(ATM_VF_HASQOS,&vcc->flags);
-                               return 0;
-                       }
-               case SO_SETCLP:
-                       if (get_user(value,(unsigned long __user *)optval))
-                               return -EFAULT;
-                       if (value) vcc->atm_options |= ATM_ATMOPT_CLP;
-                       else vcc->atm_options &= ~ATM_ATMOPT_CLP;
-                       return 0;
-               default:
-                       if (level == SOL_SOCKET) return -EINVAL;
-                       break;
+       case SO_ATMQOS:
+       {
+               struct atm_qos qos;
+
+               if (copy_from_user(&qos, optval, sizeof(qos)))
+                       return -EFAULT;
+               error = check_qos(&qos);
+               if (error)
+                       return error;
+               if (sock->state == SS_CONNECTED)
+                       return atm_change_qos(vcc, &qos);
+               if (sock->state != SS_UNCONNECTED)
+                       return -EBADFD;
+               vcc->qos = qos;
+               set_bit(ATM_VF_HASQOS, &vcc->flags);
+               return 0;
        }
-       if (!vcc->dev || !vcc->dev->ops->setsockopt) return -EINVAL;
-       return vcc->dev->ops->setsockopt(vcc,level,optname,optval,optlen);
+       case SO_SETCLP:
+               if (get_user(value, (unsigned long __user *)optval))
+                       return -EFAULT;
+               if (value)
+                       vcc->atm_options |= ATM_ATMOPT_CLP;
+               else
+                       vcc->atm_options &= ~ATM_ATMOPT_CLP;
+               return 0;
+       default:
+               if (level == SOL_SOCKET)
+                       return -EINVAL;
+               break;
+       }
+       if (!vcc->dev || !vcc->dev->ops->setsockopt)
+               return -EINVAL;
+       return vcc->dev->ops->setsockopt(vcc, level, optname, optval, optlen);
 }
 
-
 int vcc_getsockopt(struct socket *sock, int level, int optname,
                   char __user *optval, int __user *optlen)
 {
@@ -734,33 +744,33 @@ int vcc_getsockopt(struct socket *sock, int level, int optname,
 
        vcc = ATM_SD(sock);
        switch (optname) {
-               case SO_ATMQOS:
-                       if (!test_bit(ATM_VF_HASQOS,&vcc->flags))
-                               return -EINVAL;
-                       return copy_to_user(optval,&vcc->qos,sizeof(vcc->qos)) ?
-                           -EFAULT : 0;
-               case SO_SETCLP:
-                       return put_user(vcc->atm_options & ATM_ATMOPT_CLP ? 1 :
-                         0,(unsigned long __user *)optval) ? -EFAULT : 0;
-               case SO_ATMPVC:
-                       {
-                               struct sockaddr_atmpvc pvc;
-
-                               if (!vcc->dev ||
-                                   !test_bit(ATM_VF_ADDR,&vcc->flags))
-                                       return -ENOTCONN;
-                               pvc.sap_family = AF_ATMPVC;
-                               pvc.sap_addr.itf = vcc->dev->number;
-                               pvc.sap_addr.vpi = vcc->vpi;
-                               pvc.sap_addr.vci = vcc->vci;
-                               return copy_to_user(optval,&pvc,sizeof(pvc)) ?
-                                   -EFAULT : 0;
-                       }
-               default:
-                       if (level == SOL_SOCKET) return -EINVAL;
+       case SO_ATMQOS:
+               if (!test_bit(ATM_VF_HASQOS, &vcc->flags))
+                       return -EINVAL;
+               return copy_to_user(optval, &vcc->qos, sizeof(vcc->qos))
+                       ? -EFAULT : 0;
+       case SO_SETCLP:
+               return put_user(vcc->atm_options & ATM_ATMOPT_CLP ? 1 : 0,
+                               (unsigned long __user *)optval) ? -EFAULT : 0;
+       case SO_ATMPVC:
+       {
+               struct sockaddr_atmpvc pvc;
+
+               if (!vcc->dev || !test_bit(ATM_VF_ADDR, &vcc->flags))
+                       return -ENOTCONN;
+               pvc.sap_family = AF_ATMPVC;
+               pvc.sap_addr.itf = vcc->dev->number;
+               pvc.sap_addr.vpi = vcc->vpi;
+               pvc.sap_addr.vci = vcc->vci;
+               return copy_to_user(optval, &pvc, sizeof(pvc)) ? -EFAULT : 0;
+       }
+       default:
+               if (level == SOL_SOCKET)
+                       return -EINVAL;
                        break;
        }
-       if (!vcc->dev || !vcc->dev->ops->getsockopt) return -EINVAL;
+       if (!vcc->dev || !vcc->dev->ops->getsockopt)
+               return -EINVAL;
        return vcc->dev->ops->getsockopt(vcc, level, optname, optval, len);
 }
 
@@ -768,23 +778,27 @@ static int __init atm_init(void)
 {
        int error;
 
-       if ((error = proto_register(&vcc_proto, 0)) < 0)
+       error = proto_register(&vcc_proto, 0);
+       if (error < 0)
                goto out;
-
-       if ((error = atmpvc_init()) < 0) {
-               printk(KERN_ERR "atmpvc_init() failed with %d\n", error);
+       error = atmpvc_init();
+       if (error < 0) {
+               pr_err("atmpvc_init() failed with %d\n", error);
                goto out_unregister_vcc_proto;
        }
-       if ((error = atmsvc_init()) < 0) {
-               printk(KERN_ERR "atmsvc_init() failed with %d\n", error);
+       error = atmsvc_init();
+       if (error < 0) {
+               pr_err("atmsvc_init() failed with %d\n", error);
                goto out_atmpvc_exit;
        }
-       if ((error = atm_proc_init()) < 0) {
-               printk(KERN_ERR "atm_proc_init() failed with %d\n",error);
+       error = atm_proc_init();
+       if (error < 0) {
+               pr_err("atm_proc_init() failed with %d\n", error);
                goto out_atmsvc_exit;
        }
-       if ((error = atm_sysfs_init()) < 0) {
-               printk(KERN_ERR "atm_sysfs_init() failed with %d\n",error);
+       error = atm_sysfs_init();
+       if (error < 0) {
+               pr_err("atm_sysfs_init() failed with %d\n", error);
                goto out_atmproc_exit;
        }
 out:
index 2ea40995dced9b13b3c08a30e706082149b7dea6..62dc8bfe6fe727e53ea40c71e7cb00dc2952cb39 100644 (file)
@@ -3,6 +3,7 @@
 /* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
 /* 2003 John Levon  <levon@movementarian.org> */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
 
 #include <linux/module.h>
 #include <linux/kmod.h>
@@ -36,6 +37,7 @@ void register_atm_ioctl(struct atm_ioctl *ioctl)
        list_add_tail(&ioctl->list, &ioctl_list);
        mutex_unlock(&ioctl_mutex);
 }
+EXPORT_SYMBOL(register_atm_ioctl);
 
 void deregister_atm_ioctl(struct atm_ioctl *ioctl)
 {
@@ -43,129 +45,128 @@ void deregister_atm_ioctl(struct atm_ioctl *ioctl)
        list_del(&ioctl->list);
        mutex_unlock(&ioctl_mutex);
 }
-
-EXPORT_SYMBOL(register_atm_ioctl);
 EXPORT_SYMBOL(deregister_atm_ioctl);
 
-static int do_vcc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg, int compat)
+static int do_vcc_ioctl(struct socket *sock, unsigned int cmd,
+                       unsigned long arg, int compat)
 {
        struct sock *sk = sock->sk;
        struct atm_vcc *vcc;
        int error;
-       struct list_head * pos;
+       struct list_head *pos;
        void __user *argp = (void __user *)arg;
 
        vcc = ATM_SD(sock);
        switch (cmd) {
-               case SIOCOUTQ:
-                       if (sock->state != SS_CONNECTED ||
-                           !test_bit(ATM_VF_READY, &vcc->flags)) {
-                               error =  -EINVAL;
-                               goto done;
-                       }
-                       error = put_user(sk->sk_sndbuf - sk_wmem_alloc_get(sk),
-                                        (int __user *) argp) ? -EFAULT : 0;
+       case SIOCOUTQ:
+               if (sock->state != SS_CONNECTED ||
+                   !test_bit(ATM_VF_READY, &vcc->flags)) {
+                       error =  -EINVAL;
+                       goto done;
+               }
+               error = put_user(sk->sk_sndbuf - sk_wmem_alloc_get(sk),
+                                (int __user *)argp) ? -EFAULT : 0;
+               goto done;
+       case SIOCINQ:
+       {
+               struct sk_buff *skb;
+
+               if (sock->state != SS_CONNECTED) {
+                       error = -EINVAL;
                        goto done;
-               case SIOCINQ:
-                       {
-                               struct sk_buff *skb;
-
-                               if (sock->state != SS_CONNECTED) {
-                                       error = -EINVAL;
-                                       goto done;
-                               }
-                               skb = skb_peek(&sk->sk_receive_queue);
-                               error = put_user(skb ? skb->len : 0,
-                                                (int __user *)argp) ? -EFAULT : 0;
-                               goto done;
-                       }
-               case SIOCGSTAMP: /* borrowed from IP */
+               }
+               skb = skb_peek(&sk->sk_receive_queue);
+               error = put_user(skb ? skb->len : 0,
+                                (int __user *)argp) ? -EFAULT : 0;
+               goto done;
+       }
+       case SIOCGSTAMP: /* borrowed from IP */
 #ifdef CONFIG_COMPAT
-                       if (compat)
-                               error = compat_sock_get_timestamp(sk, argp);
-                       else
+               if (compat)
+                       error = compat_sock_get_timestamp(sk, argp);
+               else
 #endif
-                               error = sock_get_timestamp(sk, argp);
-                       goto done;
-               case SIOCGSTAMPNS: /* borrowed from IP */
+                       error = sock_get_timestamp(sk, argp);
+               goto done;
+       case SIOCGSTAMPNS: /* borrowed from IP */
 #ifdef CONFIG_COMPAT
-                       if (compat)
-                               error = compat_sock_get_timestampns(sk, argp);
-                       else
+               if (compat)
+                       error = compat_sock_get_timestampns(sk, argp);
+               else
 #endif
-                               error = sock_get_timestampns(sk, argp);
+                       error = sock_get_timestampns(sk, argp);
+               goto done;
+       case ATM_SETSC:
+               if (net_ratelimit())
+                       pr_warning("ATM_SETSC is obsolete; used by %s:%d\n",
+                                  current->comm, task_pid_nr(current));
+               error = 0;
+               goto done;
+       case ATMSIGD_CTRL:
+               if (!capable(CAP_NET_ADMIN)) {
+                       error = -EPERM;
                        goto done;
-               case ATM_SETSC:
-                       if (net_ratelimit())
-                               printk(KERN_WARNING "ATM_SETSC is obsolete; used by %s:%d\n",
-                                      current->comm, task_pid_nr(current));
-                       error = 0;
+               }
+               /*
+                * The user/kernel protocol for exchanging signalling
+                * info uses kernel pointers as opaque references,
+                * so the holder of the file descriptor can scribble
+                * on the kernel... so we should make sure that we
+                * have the same privileges that /proc/kcore needs
+                */
+               if (!capable(CAP_SYS_RAWIO)) {
+                       error = -EPERM;
                        goto done;
-               case ATMSIGD_CTRL:
-                       if (!capable(CAP_NET_ADMIN)) {
-                               error = -EPERM;
-                               goto done;
-                       }
-                       /*
-                        * The user/kernel protocol for exchanging signalling
-                        * info uses kernel pointers as opaque references,
-                        * so the holder of the file descriptor can scribble
-                        * on the kernel... so we should make sure that we
-                        * have the same privileges that /proc/kcore needs
-                        */
-                       if (!capable(CAP_SYS_RAWIO)) {
-                               error = -EPERM;
-                               goto done;
-                       }
+               }
 #ifdef CONFIG_COMPAT
-                       /* WTF? I don't even want to _think_ about making this
-                          work for 32-bit userspace. TBH I don't really want
-                          to think about it at all. dwmw2. */
-                       if (compat) {
-                               if (net_ratelimit())
-                                       printk(KERN_WARNING "32-bit task cannot be atmsigd\n");
-                               error = -EINVAL;
-                               goto done;
-                       }
+               /* WTF? I don't even want to _think_ about making this
+                  work for 32-bit userspace. TBH I don't really want
+                  to think about it at all. dwmw2. */
+               if (compat) {
+                       if (net_ratelimit())
+                               pr_warning("32-bit task cannot be atmsigd\n");
+                       error = -EINVAL;
+                       goto done;
+               }
 #endif
-                       error = sigd_attach(vcc);
-                       if (!error)
-                               sock->state = SS_CONNECTED;
+               error = sigd_attach(vcc);
+               if (!error)
+                       sock->state = SS_CONNECTED;
+               goto done;
+       case ATM_SETBACKEND:
+       case ATM_NEWBACKENDIF:
+       {
+               atm_backend_t backend;
+               error = get_user(backend, (atm_backend_t __user *)argp);
+               if (error)
                        goto done;
-               case ATM_SETBACKEND:
-               case ATM_NEWBACKENDIF:
-                       {
-                               atm_backend_t backend;
-                               error = get_user(backend, (atm_backend_t __user *) argp);
-                               if (error)
-                                       goto done;
-                               switch (backend) {
-                                       case ATM_BACKEND_PPP:
-                                               request_module("pppoatm");
-                                               break;
-                                       case ATM_BACKEND_BR2684:
-                                               request_module("br2684");
-                                               break;
-                               }
-                       }
-                       break;
-               case ATMMPC_CTRL:
-               case ATMMPC_DATA:
-                       request_module("mpoa");
-                       break;
-               case ATMARPD_CTRL:
-                       request_module("clip");
+               switch (backend) {
+               case ATM_BACKEND_PPP:
+                       request_module("pppoatm");
                        break;
-               case ATMLEC_CTRL:
-                       request_module("lec");
+               case ATM_BACKEND_BR2684:
+                       request_module("br2684");
                        break;
+               }
+               break;
+       }
+       case ATMMPC_CTRL:
+       case ATMMPC_DATA:
+               request_module("mpoa");
+               break;
+       case ATMARPD_CTRL:
+               request_module("clip");
+               break;
+       case ATMLEC_CTRL:
+               request_module("lec");
+               break;
        }
 
        error = -ENOIOCTLCMD;
 
        mutex_lock(&ioctl_mutex);
        list_for_each(pos, &ioctl_list) {
-               struct atm_ioctl * ic = list_entry(pos, struct atm_ioctl, list);
+               struct atm_ioctl *ic = list_entry(pos, struct atm_ioctl, list);
                if (try_module_get(ic->owner)) {
                        error = ic->ioctl(sock, cmd, arg);
                        module_put(ic->owner);
@@ -184,7 +185,6 @@ done:
        return error;
 }
 
-
 int vcc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 {
        return do_vcc_ioctl(sock, cmd, arg, 0);
@@ -287,8 +287,8 @@ static int do_atmif_sioc(struct socket *sock, unsigned int cmd,
        sioc = compat_alloc_user_space(sizeof(*sioc));
        sioc32 = compat_ptr(arg);
 
-       if (copy_in_user(&sioc->number, &sioc32->number, 2 * sizeof(int))
-           || get_user(data, &sioc32->arg))
+       if (copy_in_user(&sioc->number, &sioc32->number, 2 * sizeof(int)) ||
+           get_user(data, &sioc32->arg))
                return -EFAULT;
        datap = compat_ptr(data);
        if (put_user(datap, &sioc->arg))
index 42749b7b917cc7d97e3f97bd147e398543b4c3b7..5da5753157f9d8da1799e93649e52e9f258d85dd 100644 (file)
@@ -4,6 +4,8 @@
  * Marko Kiiskila <mkiiskila@yahoo.com>
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
+
 #include <linux/kernel.h>
 #include <linux/bitops.h>
 #include <linux/capability.h>
@@ -16,7 +18,7 @@
 #include <linux/skbuff.h>
 #include <linux/ip.h>
 #include <asm/byteorder.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 #include <net/arp.h>
 #include <net/dst.h>
 #include <linux/proc_fs.h>
@@ -85,17 +87,19 @@ static struct atm_vcc *lec_arp_resolve(struct lec_priv *priv,
                                       int is_rdesc,
                                       struct lec_arp_table **ret_entry);
 static void lec_arp_update(struct lec_priv *priv, const unsigned char *mac_addr,
-                          const unsigned char *atm_addr, unsigned long remoteflag,
+                          const unsigned char *atm_addr,
+                          unsigned long remoteflag,
                           unsigned int targetless_le_arp);
 static void lec_flush_complete(struct lec_priv *priv, unsigned long tran_id);
 static int lec_mcast_make(struct lec_priv *priv, struct atm_vcc *vcc);
 static void lec_set_flush_tran_id(struct lec_priv *priv,
                                  const unsigned char *atm_addr,
                                  unsigned long tran_id);
-static void lec_vcc_added(struct lec_priv *priv, const struct atmlec_ioc *ioc_data,
+static void lec_vcc_added(struct lec_priv *priv,
+                         const struct atmlec_ioc *ioc_data,
                          struct atm_vcc *vcc,
-                         void (*old_push) (struct atm_vcc *vcc,
-                                           struct sk_buff *skb));
+                         void (*old_push)(struct atm_vcc *vcc,
+                                          struct sk_buff *skb));
 static void lec_vcc_close(struct lec_priv *priv, struct atm_vcc *vcc);
 
 /* must be done under lec_arp_lock */
@@ -110,7 +114,6 @@ static inline void lec_arp_put(struct lec_arp_table *entry)
                kfree(entry);
 }
 
-
 static struct lane2_ops lane2_ops = {
        lane2_resolve,          /* resolve,             spec 3.1.3 */
        lane2_associate_req,    /* associate_req,       spec 3.1.4 */
@@ -148,7 +151,8 @@ static void lec_handle_bridge(struct sk_buff *skb, struct net_device *dev)
                mesg = (struct atmlec_msg *)skb2->data;
                mesg->type = l_topology_change;
                buff += 4;
-               mesg->content.normal.flag = *buff & 0x01;       /* 0x01 is topology change */
+               mesg->content.normal.flag = *buff & 0x01;
+                                       /* 0x01 is topology change */
 
                priv = netdev_priv(dev);
                atm_force_charge(priv->lecd, skb2->truesize);
@@ -242,7 +246,7 @@ lec_send(struct atm_vcc *vcc, struct sk_buff *skb)
 
 static void lec_tx_timeout(struct net_device *dev)
 {
-       printk(KERN_INFO "%s: tx timeout\n", dev->name);
+       pr_info("%s\n", dev->name);
        dev->trans_start = jiffies;
        netif_wake_queue(dev);
 }
@@ -261,14 +265,10 @@ static netdev_tx_t lec_start_xmit(struct sk_buff *skb,
        unsigned char rdesc[ETH_ALEN];  /* Token Ring route descriptor */
 #endif
        int is_rdesc;
-#if DUMP_PACKETS > 0
-       char buf[300];
-       int i = 0;
-#endif /* DUMP_PACKETS >0 */
 
-       pr_debug("lec_start_xmit called\n");
+       pr_debug("called\n");
        if (!priv->lecd) {
-               printk("%s:No lecd attached\n", dev->name);
+               pr_info("%s:No lecd attached\n", dev->name);
                dev->stats.tx_errors++;
                netif_stop_queue(dev);
                kfree_skb(skb);
@@ -276,8 +276,8 @@ static netdev_tx_t lec_start_xmit(struct sk_buff *skb,
        }
 
        pr_debug("skbuff head:%lx data:%lx tail:%lx end:%lx\n",
-               (long)skb->head, (long)skb->data, (long)skb_tail_pointer(skb),
-               (long)skb_end_pointer(skb));
+                (long)skb->head, (long)skb->data, (long)skb_tail_pointer(skb),
+                (long)skb_end_pointer(skb));
 #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
        if (memcmp(skb->data, bridge_ula_lec, sizeof(bridge_ula_lec)) == 0)
                lec_handle_bridge(skb, dev);
@@ -285,8 +285,7 @@ static netdev_tx_t lec_start_xmit(struct sk_buff *skb,
 
        /* Make sure we have room for lec_id */
        if (skb_headroom(skb) < 2) {
-
-               pr_debug("lec_start_xmit: reallocating skb\n");
+               pr_debug("reallocating skb\n");
                skb2 = skb_realloc_headroom(skb, LEC_HEADER_LEN);
                kfree_skb(skb);
                if (skb2 == NULL)
@@ -313,23 +312,17 @@ static netdev_tx_t lec_start_xmit(struct sk_buff *skb,
        }
 #endif
 
-#if DUMP_PACKETS > 0
-       printk("%s: send datalen:%ld lecid:%4.4x\n", dev->name,
-              skb->len, priv->lecid);
 #if DUMP_PACKETS >= 2
-       for (i = 0; i < skb->len && i < 99; i++) {
-               sprintf(buf + i * 3, "%2.2x ", 0xff & skb->data[i]);
-       }
+#define MAX_DUMP_SKB 99
 #elif DUMP_PACKETS >= 1
-       for (i = 0; i < skb->len && i < 30; i++) {
-               sprintf(buf + i * 3, "%2.2x ", 0xff & skb->data[i]);
-       }
+#define MAX_DUMP_SKB 30
+#endif
+#if DUMP_PACKETS >= 1
+       printk(KERN_DEBUG "%s: send datalen:%ld lecid:%4.4x\n",
+              dev->name, skb->len, priv->lecid);
+       print_hex_dump(KERN_DEBUG, "", DUMP_OFFSET, 16, 1,
+                      skb->data, min(skb->len, MAX_DUMP_SKB), true);
 #endif /* DUMP_PACKETS >= 1 */
-       if (i == skb->len)
-               printk("%s\n", buf);
-       else
-               printk("%s...\n", buf);
-#endif /* DUMP_PACKETS > 0 */
 
        /* Minimum ethernet-frame size */
 #ifdef CONFIG_TR
@@ -367,31 +360,28 @@ static netdev_tx_t lec_start_xmit(struct sk_buff *skb,
 #endif
        entry = NULL;
        vcc = lec_arp_resolve(priv, dst, is_rdesc, &entry);
-       pr_debug("%s:vcc:%p vcc_flags:%lx, entry:%p\n", dev->name,
-               vcc, vcc ? vcc->flags : 0, entry);
+       pr_debug("%s:vcc:%p vcc_flags:%lx, entry:%p\n",
+                dev->name, vcc, vcc ? vcc->flags : 0, entry);
        if (!vcc || !test_bit(ATM_VF_READY, &vcc->flags)) {
                if (entry && (entry->tx_wait.qlen < LEC_UNRES_QUE_LEN)) {
-                       pr_debug("%s:lec_start_xmit: queuing packet, ",
-                               dev->name);
-                       pr_debug("MAC address %pM\n", lec_h->h_dest);
+                       pr_debug("%s:queuing packet, MAC address %pM\n",
+                                dev->name, lec_h->h_dest);
                        skb_queue_tail(&entry->tx_wait, skb);
                } else {
-                       pr_debug
-                           ("%s:lec_start_xmit: tx queue full or no arp entry, dropping, ",
-                            dev->name);
-                       pr_debug("MAC address %pM\n", lec_h->h_dest);
+                       pr_debug("%s:tx queue full or no arp entry, dropping, MAC address: %pM\n",
+                                dev->name, lec_h->h_dest);
                        dev->stats.tx_dropped++;
                        dev_kfree_skb(skb);
                }
                goto out;
        }
 #if DUMP_PACKETS > 0
-       printk("%s:sending to vpi:%d vci:%d\n", dev->name, vcc->vpi, vcc->vci);
+       printk(KERN_DEBUG "%s:sending to vpi:%d vci:%d\n",
+              dev->name, vcc->vpi, vcc->vci);
 #endif /* DUMP_PACKETS > 0 */
 
        while (entry && (skb2 = skb_dequeue(&entry->tx_wait))) {
-               pr_debug("lec.c: emptying tx queue, ");
-               pr_debug("MAC address %pM\n", lec_h->h_dest);
+               pr_debug("emptying tx queue, MAC address %pM\n", lec_h->h_dest);
                lec_send(vcc, skb2);
        }
 
@@ -444,14 +434,12 @@ static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
        pr_debug("%s: msg from zeppelin:%d\n", dev->name, mesg->type);
        switch (mesg->type) {
        case l_set_mac_addr:
-               for (i = 0; i < 6; i++) {
+               for (i = 0; i < 6; i++)
                        dev->dev_addr[i] = mesg->content.normal.mac_addr[i];
-               }
                break;
        case l_del_mac_addr:
-               for (i = 0; i < 6; i++) {
+               for (i = 0; i < 6; i++)
                        dev->dev_addr[i] = 0;
-               }
                break;
        case l_addr_delete:
                lec_addr_delete(priv, mesg->content.normal.atm_addr,
@@ -477,10 +465,10 @@ static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
                               mesg->content.normal.atm_addr,
                               mesg->content.normal.flag,
                               mesg->content.normal.targetless_le_arp);
-               pr_debug("lec: in l_arp_update\n");
+               pr_debug("in l_arp_update\n");
                if (mesg->sizeoftlvs != 0) {    /* LANE2 3.1.5 */
-                       pr_debug("lec: LANE2 3.1.5, got tlvs, size %d\n",
-                               mesg->sizeoftlvs);
+                       pr_debug("LANE2 3.1.5, got tlvs, size %d\n",
+                                mesg->sizeoftlvs);
                        lane2_associate_ind(dev, mesg->content.normal.mac_addr,
                                            tmp, mesg->sizeoftlvs);
                }
@@ -499,13 +487,14 @@ static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
                priv->flush_timeout = (mesg->content.config.flush_timeout * HZ);
                priv->path_switching_delay =
                    (mesg->content.config.path_switching_delay * HZ);
-               priv->lane_version = mesg->content.config.lane_version; /* LANE2 */
+               priv->lane_version = mesg->content.config.lane_version;
+                                       /* LANE2 */
                priv->lane2_ops = NULL;
                if (priv->lane_version > 1)
                        priv->lane2_ops = &lane2_ops;
                if (dev_set_mtu(dev, mesg->content.config.mtu))
-                       printk("%s: change_mtu to %d failed\n", dev->name,
-                              mesg->content.config.mtu);
+                       pr_info("%s: change_mtu to %d failed\n",
+                               dev->name, mesg->content.config.mtu);
                priv->is_proxy = mesg->content.config.is_proxy;
                break;
        case l_flush_tran_id:
@@ -518,40 +507,35 @@ static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
                break;
        case l_should_bridge:
 #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
-               {
-                       pr_debug("%s: bridge zeppelin asks about %pM\n",
-                                dev->name, mesg->content.proxy.mac_addr);
+       {
+               pr_debug("%s: bridge zeppelin asks about %pM\n",
+                        dev->name, mesg->content.proxy.mac_addr);
 
-                       if (br_fdb_test_addr_hook == NULL)
-                               break;
+               if (br_fdb_test_addr_hook == NULL)
+                       break;
 
-                       if (br_fdb_test_addr_hook(dev,
-                                       mesg->content.proxy.mac_addr)) {
-                               /* hit from bridge table, send LE_ARP_RESPONSE */
-                               struct sk_buff *skb2;
-                               struct sock *sk;
-
-                               pr_debug
-                                   ("%s: entry found, responding to zeppelin\n",
-                                    dev->name);
-                               skb2 =
-                                   alloc_skb(sizeof(struct atmlec_msg),
-                                             GFP_ATOMIC);
-                               if (skb2 == NULL)
-                                       break;
-                               skb2->len = sizeof(struct atmlec_msg);
-                               skb_copy_to_linear_data(skb2, mesg,
-                                                       sizeof(*mesg));
-                               atm_force_charge(priv->lecd, skb2->truesize);
-                               sk = sk_atm(priv->lecd);
-                               skb_queue_tail(&sk->sk_receive_queue, skb2);
-                               sk->sk_data_ready(sk, skb2->len);
-                       }
+               if (br_fdb_test_addr_hook(dev, mesg->content.proxy.mac_addr)) {
+                       /* hit from bridge table, send LE_ARP_RESPONSE */
+                       struct sk_buff *skb2;
+                       struct sock *sk;
+
+                       pr_debug("%s: entry found, responding to zeppelin\n",
+                                dev->name);
+                       skb2 = alloc_skb(sizeof(struct atmlec_msg), GFP_ATOMIC);
+                       if (skb2 == NULL)
+                               break;
+                       skb2->len = sizeof(struct atmlec_msg);
+                       skb_copy_to_linear_data(skb2, mesg, sizeof(*mesg));
+                       atm_force_charge(priv->lecd, skb2->truesize);
+                       sk = sk_atm(priv->lecd);
+                       skb_queue_tail(&sk->sk_receive_queue, skb2);
+                       sk->sk_data_ready(sk, skb2->len);
                }
+       }
 #endif /* defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) */
                break;
        default:
-               printk("%s: Unknown message type %d\n", dev->name, mesg->type);
+               pr_info("%s: Unknown message type %d\n", dev->name, mesg->type);
                dev_kfree_skb(skb);
                return -EINVAL;
        }
@@ -572,14 +556,13 @@ static void lec_atm_close(struct atm_vcc *vcc)
        lec_arp_destroy(priv);
 
        if (skb_peek(&sk_atm(vcc)->sk_receive_queue))
-               printk("%s lec_atm_close: closing with messages pending\n",
-                      dev->name);
-       while ((skb = skb_dequeue(&sk_atm(vcc)->sk_receive_queue)) != NULL) {
+               pr_info("%s closing with messages pending\n", dev->name);
+       while ((skb = skb_dequeue(&sk_atm(vcc)->sk_receive_queue))) {
                atm_return(vcc, skb->truesize);
                dev_kfree_skb(skb);
        }
 
-       printk("%s: Shut down!\n", dev->name);
+       pr_info("%s: Shut down!\n", dev->name);
        module_put(THIS_MODULE);
 }
 
@@ -608,9 +591,8 @@ send_to_lecd(struct lec_priv *priv, atmlec_msg_type type,
        struct sk_buff *skb;
        struct atmlec_msg *mesg;
 
-       if (!priv || !priv->lecd) {
+       if (!priv || !priv->lecd)
                return -1;
-       }
        skb = alloc_skb(sizeof(struct atmlec_msg), GFP_ATOMIC);
        if (!skb)
                return -1;
@@ -633,7 +615,7 @@ send_to_lecd(struct lec_priv *priv, atmlec_msg_type type,
        sk->sk_data_ready(sk, skb->len);
 
        if (data != NULL) {
-               pr_debug("lec: about to send %d bytes of data\n", data->len);
+               pr_debug("about to send %d bytes of data\n", data->len);
                atm_force_charge(priv->lecd, data->truesize);
                skb_queue_tail(&sk->sk_receive_queue, data);
                sk->sk_data_ready(sk, skb->len);
@@ -691,36 +673,28 @@ static void lec_push(struct atm_vcc *vcc, struct sk_buff *skb)
        struct net_device *dev = (struct net_device *)vcc->proto_data;
        struct lec_priv *priv = netdev_priv(dev);
 
-#if DUMP_PACKETS >0
-       int i = 0;
-       char buf[300];
-
-       printk("%s: lec_push vcc vpi:%d vci:%d\n", dev->name,
-              vcc->vpi, vcc->vci);
+#if DUMP_PACKETS > 0
+       printk(KERN_DEBUG "%s: vcc vpi:%d vci:%d\n",
+              dev->name, vcc->vpi, vcc->vci);
 #endif
        if (!skb) {
                pr_debug("%s: null skb\n", dev->name);
                lec_vcc_close(priv, vcc);
                return;
        }
-#if DUMP_PACKETS > 0
-       printk("%s: rcv datalen:%ld lecid:%4.4x\n", dev->name,
-              skb->len, priv->lecid);
 #if DUMP_PACKETS >= 2
-       for (i = 0; i < skb->len && i < 99; i++) {
-               sprintf(buf + i * 3, "%2.2x ", 0xff & skb->data[i]);
-       }
+#define MAX_SKB_DUMP 99
 #elif DUMP_PACKETS >= 1
-       for (i = 0; i < skb->len && i < 30; i++) {
-               sprintf(buf + i * 3, "%2.2x ", 0xff & skb->data[i]);
-       }
-#endif /* DUMP_PACKETS >= 1 */
-       if (i == skb->len)
-               printk("%s\n", buf);
-       else
-               printk("%s...\n", buf);
+#define MAX_SKB_DUMP 30
+#endif
+#if DUMP_PACKETS > 0
+       printk(KERN_DEBUG "%s: rcv datalen:%ld lecid:%4.4x\n",
+              dev->name, skb->len, priv->lecid);
+       print_hex_dump(KERN_DEBUG, "", DUMP_OFFSET, 16, 1,
+                      skb->data, min(MAX_SKB_DUMP, skb->len), true);
 #endif /* DUMP_PACKETS > 0 */
-       if (memcmp(skb->data, lec_ctrl_magic, 4) == 0) {        /* Control frame, to daemon */
+       if (memcmp(skb->data, lec_ctrl_magic, 4) == 0) {
+                               /* Control frame, to daemon */
                struct sock *sk = sk_atm(vcc);
 
                pr_debug("%s: To daemon\n", dev->name);
@@ -778,9 +752,8 @@ static void lec_push(struct atm_vcc *vcc, struct sk_buff *skb)
                        dev_kfree_skb(skb);
                        return;
                }
-               if (!hlist_empty(&priv->lec_arp_empty_ones)) {
+               if (!hlist_empty(&priv->lec_arp_empty_ones))
                        lec_arp_check_empties(priv, vcc, skb);
-               }
                skb_pull(skb, 2);       /* skip lec_id */
 #ifdef CONFIG_TR
                if (priv->is_trdev)
@@ -801,7 +774,7 @@ static void lec_pop(struct atm_vcc *vcc, struct sk_buff *skb)
        struct net_device *dev = skb->dev;
 
        if (vpriv == NULL) {
-               printk("lec_pop(): vpriv = NULL!?!?!?\n");
+               pr_info("vpriv = NULL!?!?!?\n");
                return;
        }
 
@@ -822,15 +795,13 @@ static int lec_vcc_attach(struct atm_vcc *vcc, void __user *arg)
 
        /* Lecd must be up in this case */
        bytes_left = copy_from_user(&ioc_data, arg, sizeof(struct atmlec_ioc));
-       if (bytes_left != 0) {
-               printk
-                   ("lec: lec_vcc_attach, copy from user failed for %d bytes\n",
-                    bytes_left);
-       }
+       if (bytes_left != 0)
+               pr_info("copy from user failed for %d bytes\n", bytes_left);
        if (ioc_data.dev_num < 0 || ioc_data.dev_num >= MAX_LEC_ITF ||
            !dev_lec[ioc_data.dev_num])
                return -EINVAL;
-       if (!(vpriv = kmalloc(sizeof(struct lec_vcc_priv), GFP_KERNEL)))
+       vpriv = kmalloc(sizeof(struct lec_vcc_priv), GFP_KERNEL);
+       if (!vpriv)
                return -ENOMEM;
        vpriv->xoff = 0;
        vpriv->old_pop = vcc->pop;
@@ -921,9 +892,8 @@ static int lecd_attach(struct atm_vcc *vcc, int arg)
        priv->flush_timeout = (4 * HZ);
        priv->path_switching_delay = (6 * HZ);
 
-       if (dev_lec[i]->flags & IFF_UP) {
+       if (dev_lec[i]->flags & IFF_UP)
                netif_start_queue(dev_lec[i]);
-       }
        __module_get(THIS_MODULE);
        return i;
 }
@@ -1125,7 +1095,9 @@ static int lec_seq_show(struct seq_file *seq, void *v)
        else {
                struct lec_state *state = seq->private;
                struct net_device *dev = state->dev;
-               struct lec_arp_table *entry = hlist_entry(state->node, struct lec_arp_table, next);
+               struct lec_arp_table *entry = hlist_entry(state->node,
+                                                         struct lec_arp_table,
+                                                         next);
 
                seq_printf(seq, "%s ", dev->name);
                lec_info(seq, entry);
@@ -1199,13 +1171,13 @@ static int __init lane_module_init(void)
 
        p = proc_create("lec", S_IRUGO, atm_proc_root, &lec_seq_fops);
        if (!p) {
-               printk(KERN_ERR "Unable to initialize /proc/net/atm/lec\n");
+               pr_err("Unable to initialize /proc/net/atm/lec\n");
                return -ENOMEM;
        }
 #endif
 
        register_atm_ioctl(&lane_ioctl_ops);
-       printk("lec.c: " __DATE__ " " __TIME__ " initialized\n");
+       pr_info("lec.c: " __DATE__ " " __TIME__ " initialized\n");
        return 0;
 }
 
@@ -1294,13 +1266,13 @@ static int lane2_associate_req(struct net_device *dev, const u8 *lan_dst,
        struct lec_priv *priv = netdev_priv(dev);
 
        if (compare_ether_addr(lan_dst, dev->dev_addr))
-               return (0);     /* not our mac address */
+               return 0;       /* not our mac address */
 
        kfree(priv->tlvs);      /* NULL if there was no previous association */
 
        priv->tlvs = kmemdup(tlvs, sizeoftlvs, GFP_KERNEL);
        if (priv->tlvs == NULL)
-               return (0);
+               return 0;
        priv->sizeoftlvs = sizeoftlvs;
 
        skb = alloc_skb(sizeoftlvs, GFP_ATOMIC);
@@ -1310,12 +1282,12 @@ static int lane2_associate_req(struct net_device *dev, const u8 *lan_dst,
        skb_copy_to_linear_data(skb, tlvs, sizeoftlvs);
        retval = send_to_lecd(priv, l_associate_req, NULL, NULL, skb);
        if (retval != 0)
-               printk("lec.c: lane2_associate_req() failed\n");
+               pr_info("lec.c: lane2_associate_req() failed\n");
        /*
         * If the previous association has changed we must
         * somehow notify other LANE entities about the change
         */
-       return (1);
+       return 1;
 }
 
 /*
@@ -1348,12 +1320,12 @@ static void lane2_associate_ind(struct net_device *dev, const u8 *mac_addr,
        entry->sizeoftlvs = sizeoftlvs;
 #endif
 #if 0
-       printk("lec.c: lane2_associate_ind()\n");
-       printk("dump of tlvs, sizeoftlvs=%d\n", sizeoftlvs);
+       pr_info("\n");
+       pr_info("dump of tlvs, sizeoftlvs=%d\n", sizeoftlvs);
        while (i < sizeoftlvs)
-               printk("%02x ", tlvs[i++]);
+               pr_cont("%02x ", tlvs[i++]);
 
-       printk("\n");
+       pr_cont("\n");
 #endif
 
        /* tell MPOA about the TLVs we saw */
@@ -1373,15 +1345,15 @@ static void lane2_associate_ind(struct net_device *dev, const u8 *mac_addr,
 
 #include <linux/types.h>
 #include <linux/timer.h>
-#include <asm/param.h>
+#include <linux/param.h>
 #include <asm/atomic.h>
 #include <linux/inetdevice.h>
 #include <net/route.h>
 
 #if 0
-#define pr_debug(format,args...)
+#define pr_debug(format, args...)
 /*
-#define pr_debug printk
+  #define pr_debug printk
 */
 #endif
 #define DEBUG_ARP_TABLE 0
@@ -1395,7 +1367,7 @@ static void lec_arp_expire_arp(unsigned long data);
  * Arp table funcs
  */
 
-#define HASH(ch) (ch & (LEC_ARP_TABLE_SIZE -1))
+#define HASH(ch) (ch & (LEC_ARP_TABLE_SIZE - 1))
 
 /*
  * Initialization of arp-cache
@@ -1404,9 +1376,8 @@ static void lec_arp_init(struct lec_priv *priv)
 {
        unsigned short i;
 
-       for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
+       for (i = 0; i < LEC_ARP_TABLE_SIZE; i++)
                INIT_HLIST_HEAD(&priv->lec_arp_tables[i]);
-       }
        INIT_HLIST_HEAD(&priv->lec_arp_empty_ones);
        INIT_HLIST_HEAD(&priv->lec_no_forward);
        INIT_HLIST_HEAD(&priv->mcast_fwds);
@@ -1450,10 +1421,7 @@ lec_arp_add(struct lec_priv *priv, struct lec_arp_table *entry)
        tmp = &priv->lec_arp_tables[HASH(entry->mac_addr[ETH_ALEN - 1])];
        hlist_add_head(&entry->next, tmp);
 
-       pr_debug("LEC_ARP: Added entry:%2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n",
-               0xff & entry->mac_addr[0], 0xff & entry->mac_addr[1],
-               0xff & entry->mac_addr[2], 0xff & entry->mac_addr[3],
-               0xff & entry->mac_addr[4], 0xff & entry->mac_addr[5]);
+       pr_debug("Added entry:%pM\n", entry->mac_addr);
 }
 
 /*
@@ -1466,20 +1434,23 @@ lec_arp_remove(struct lec_priv *priv, struct lec_arp_table *to_remove)
        struct lec_arp_table *entry;
        int i, remove_vcc = 1;
 
-       if (!to_remove) {
+       if (!to_remove)
                return -1;
-       }
 
        hlist_del(&to_remove->next);
        del_timer(&to_remove->timer);
 
-       /* If this is the only MAC connected to this VCC, also tear down the VCC */
+       /*
+        * If this is the only MAC connected to this VCC,
+        * also tear down the VCC
+        */
        if (to_remove->status >= ESI_FLUSH_PENDING) {
                /*
                 * ESI_FLUSH_PENDING, ESI_FORWARD_DIRECT
                 */
                for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
-                       hlist_for_each_entry(entry, node, &priv->lec_arp_tables[i], next) {
+                       hlist_for_each_entry(entry, node,
+                                            &priv->lec_arp_tables[i], next) {
                                if (memcmp(to_remove->atm_addr,
                                           entry->atm_addr, ATM_ESA_LEN) == 0) {
                                        remove_vcc = 0;
@@ -1492,10 +1463,7 @@ lec_arp_remove(struct lec_priv *priv, struct lec_arp_table *to_remove)
        }
        skb_queue_purge(&to_remove->tx_wait);   /* FIXME: good place for this? */
 
-       pr_debug("LEC_ARP: Removed entry:%2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n",
-               0xff & to_remove->mac_addr[0], 0xff & to_remove->mac_addr[1],
-               0xff & to_remove->mac_addr[2], 0xff & to_remove->mac_addr[3],
-               0xff & to_remove->mac_addr[4], 0xff & to_remove->mac_addr[5]);
+       pr_debug("Removed entry:%pM\n", to_remove->mac_addr);
        return 0;
 }
 
@@ -1513,9 +1481,8 @@ static const char *get_status_string(unsigned char st)
                return "ESI_FLUSH_PENDING";
        case ESI_FORWARD_DIRECT:
                return "ESI_FORWARD_DIRECT";
-       default:
-               return "<UNKNOWN>";
        }
+       return "<UNKNOWN>";
 }
 
 static void dump_arp_table(struct lec_priv *priv)
@@ -1525,18 +1492,15 @@ static void dump_arp_table(struct lec_priv *priv)
        char buf[256];
        int i, j, offset;
 
-       printk("Dump %p:\n", priv);
+       pr_info("Dump %p:\n", priv);
        for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
-               hlist_for_each_entry(rulla, node, &priv->lec_arp_tables[i], next) {
+               hlist_for_each_entry(rulla, node,
+                                    &priv->lec_arp_tables[i], next) {
                        offset = 0;
                        offset += sprintf(buf, "%d: %p\n", i, rulla);
-                       offset += sprintf(buf + offset, "Mac:");
-                       for (j = 0; j < ETH_ALEN; j++) {
-                               offset += sprintf(buf + offset,
-                                                 "%2.2x ",
-                                                 rulla->mac_addr[j] & 0xff);
-                       }
-                       offset += sprintf(buf + offset, "Atm:");
+                       offset += sprintf(buf + offset, "Mac: %pM",
+                                         rulla->mac_addr);
+                       offset += sprintf(buf + offset, " Atm:");
                        for (j = 0; j < ATM_ESA_LEN; j++) {
                                offset += sprintf(buf + offset,
                                                  "%2.2x ",
@@ -1556,20 +1520,16 @@ static void dump_arp_table(struct lec_priv *priv)
                                    "Flags:%x, Packets_flooded:%x, Status: %s ",
                                    rulla->flags, rulla->packets_flooded,
                                    get_status_string(rulla->status));
-                       printk("%s\n", buf);
+                       pr_info("%s\n", buf);
                }
        }
 
        if (!hlist_empty(&priv->lec_no_forward))
-               printk("No forward\n");
+               pr_info("No forward\n");
        hlist_for_each_entry(rulla, node, &priv->lec_no_forward, next) {
                offset = 0;
-               offset += sprintf(buf + offset, "Mac:");
-               for (j = 0; j < ETH_ALEN; j++) {
-                       offset += sprintf(buf + offset, "%2.2x ",
-                                         rulla->mac_addr[j] & 0xff);
-               }
-               offset += sprintf(buf + offset, "Atm:");
+               offset += sprintf(buf + offset, "Mac: %pM", rulla->mac_addr);
+               offset += sprintf(buf + offset, " Atm:");
                for (j = 0; j < ATM_ESA_LEN; j++) {
                        offset += sprintf(buf + offset, "%2.2x ",
                                          rulla->atm_addr[j] & 0xff);
@@ -1586,19 +1546,15 @@ static void dump_arp_table(struct lec_priv *priv)
                                  "Flags:%x, Packets_flooded:%x, Status: %s ",
                                  rulla->flags, rulla->packets_flooded,
                                  get_status_string(rulla->status));
-               printk("%s\n", buf);
+               pr_info("%s\n", buf);
        }
 
        if (!hlist_empty(&priv->lec_arp_empty_ones))
-               printk("Empty ones\n");
+               pr_info("Empty ones\n");
        hlist_for_each_entry(rulla, node, &priv->lec_arp_empty_ones, next) {
                offset = 0;
-               offset += sprintf(buf + offset, "Mac:");
-               for (j = 0; j < ETH_ALEN; j++) {
-                       offset += sprintf(buf + offset, "%2.2x ",
-                                         rulla->mac_addr[j] & 0xff);
-               }
-               offset += sprintf(buf + offset, "Atm:");
+               offset += sprintf(buf + offset, "Mac: %pM", rulla->mac_addr);
+               offset += sprintf(buf + offset, " Atm:");
                for (j = 0; j < ATM_ESA_LEN; j++) {
                        offset += sprintf(buf + offset, "%2.2x ",
                                          rulla->atm_addr[j] & 0xff);
@@ -1615,19 +1571,15 @@ static void dump_arp_table(struct lec_priv *priv)
                                  "Flags:%x, Packets_flooded:%x, Status: %s ",
                                  rulla->flags, rulla->packets_flooded,
                                  get_status_string(rulla->status));
-               printk("%s", buf);
+               pr_info("%s", buf);
        }
 
        if (!hlist_empty(&priv->mcast_fwds))
-               printk("Multicast Forward VCCs\n");
+               pr_info("Multicast Forward VCCs\n");
        hlist_for_each_entry(rulla, node, &priv->mcast_fwds, next) {
                offset = 0;
-               offset += sprintf(buf + offset, "Mac:");
-               for (j = 0; j < ETH_ALEN; j++) {
-                       offset += sprintf(buf + offset, "%2.2x ",
-                                         rulla->mac_addr[j] & 0xff);
-               }
-               offset += sprintf(buf + offset, "Atm:");
+               offset += sprintf(buf + offset, "Mac: %pM", rulla->mac_addr);
+               offset += sprintf(buf + offset, " Atm:");
                for (j = 0; j < ATM_ESA_LEN; j++) {
                        offset += sprintf(buf + offset, "%2.2x ",
                                          rulla->atm_addr[j] & 0xff);
@@ -1644,7 +1596,7 @@ static void dump_arp_table(struct lec_priv *priv)
                                  "Flags:%x, Packets_flooded:%x, Status: %s ",
                                  rulla->flags, rulla->packets_flooded,
                                  get_status_string(rulla->status));
-               printk("%s\n", buf);
+               pr_info("%s\n", buf);
        }
 
 }
@@ -1670,14 +1622,16 @@ static void lec_arp_destroy(struct lec_priv *priv)
 
        spin_lock_irqsave(&priv->lec_arp_lock, flags);
        for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
-               hlist_for_each_entry_safe(entry, node, next, &priv->lec_arp_tables[i], next) {
+               hlist_for_each_entry_safe(entry, node, next,
+                                         &priv->lec_arp_tables[i], next) {
                        lec_arp_remove(priv, entry);
                        lec_arp_put(entry);
                }
                INIT_HLIST_HEAD(&priv->lec_arp_tables[i]);
        }
 
-       hlist_for_each_entry_safe(entry, node, next, &priv->lec_arp_empty_ones, next) {
+       hlist_for_each_entry_safe(entry, node, next,
+                                 &priv->lec_arp_empty_ones, next) {
                del_timer_sync(&entry->timer);
                lec_arp_clear_vccs(entry);
                hlist_del(&entry->next);
@@ -1685,7 +1639,8 @@ static void lec_arp_destroy(struct lec_priv *priv)
        }
        INIT_HLIST_HEAD(&priv->lec_arp_empty_ones);
 
-       hlist_for_each_entry_safe(entry, node, next, &priv->lec_no_forward, next) {
+       hlist_for_each_entry_safe(entry, node, next,
+                                 &priv->lec_no_forward, next) {
                del_timer_sync(&entry->timer);
                lec_arp_clear_vccs(entry);
                hlist_del(&entry->next);
@@ -1714,15 +1669,12 @@ static struct lec_arp_table *lec_arp_find(struct lec_priv *priv,
        struct hlist_head *head;
        struct lec_arp_table *entry;
 
-       pr_debug("LEC_ARP: lec_arp_find :%2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n",
-               mac_addr[0] & 0xff, mac_addr[1] & 0xff, mac_addr[2] & 0xff,
-               mac_addr[3] & 0xff, mac_addr[4] & 0xff, mac_addr[5] & 0xff);
+       pr_debug("%pM\n", mac_addr);
 
        head = &priv->lec_arp_tables[HASH(mac_addr[ETH_ALEN - 1])];
        hlist_for_each_entry(entry, node, head, next) {
-               if (!compare_ether_addr(mac_addr, entry->mac_addr)) {
+               if (!compare_ether_addr(mac_addr, entry->mac_addr))
                        return entry;
-               }
        }
        return NULL;
 }
@@ -1734,7 +1686,7 @@ static struct lec_arp_table *make_entry(struct lec_priv *priv,
 
        to_return = kzalloc(sizeof(struct lec_arp_table), GFP_ATOMIC);
        if (!to_return) {
-               printk("LEC: Arp entry kmalloc failed\n");
+               pr_info("LEC: Arp entry kmalloc failed\n");
                return NULL;
        }
        memcpy(to_return->mac_addr, mac_addr, ETH_ALEN);
@@ -1755,7 +1707,7 @@ static void lec_arp_expire_arp(unsigned long data)
 
        entry = (struct lec_arp_table *)data;
 
-       pr_debug("lec_arp_expire_arp\n");
+       pr_debug("\n");
        if (entry->status == ESI_ARP_PENDING) {
                if (entry->no_tries <= entry->priv->max_retry_count) {
                        if (entry->is_rdesc)
@@ -1779,10 +1731,10 @@ static void lec_arp_expire_vcc(unsigned long data)
 
        del_timer(&to_remove->timer);
 
-       pr_debug("LEC_ARP %p %p: lec_arp_expire_vcc vpi:%d vci:%d\n",
-               to_remove, priv,
-               to_remove->vcc ? to_remove->recv_vcc->vpi : 0,
-               to_remove->vcc ? to_remove->recv_vcc->vci : 0);
+       pr_debug("%p %p: vpi:%d vci:%d\n",
+                to_remove, priv,
+                to_remove->vcc ? to_remove->recv_vcc->vpi : 0,
+                to_remove->vcc ? to_remove->recv_vcc->vci : 0);
 
        spin_lock_irqsave(&priv->lec_arp_lock, flags);
        hlist_del(&to_remove->next);
@@ -1792,6 +1744,50 @@ static void lec_arp_expire_vcc(unsigned long data)
        lec_arp_put(to_remove);
 }
 
+static bool __lec_arp_check_expire(struct lec_arp_table *entry,
+                                  unsigned long now,
+                                  struct lec_priv *priv)
+{
+       unsigned long time_to_check;
+
+       if ((entry->flags) & LEC_REMOTE_FLAG && priv->topology_change)
+               time_to_check = priv->forward_delay_time;
+       else
+               time_to_check = priv->aging_time;
+
+       pr_debug("About to expire: %lx - %lx > %lx\n",
+                now, entry->last_used, time_to_check);
+       if (time_after(now, entry->last_used + time_to_check) &&
+           !(entry->flags & LEC_PERMANENT_FLAG) &&
+           !(entry->mac_addr[0] & 0x01)) {     /* LANE2: 7.1.20 */
+               /* Remove entry */
+               pr_debug("Entry timed out\n");
+               lec_arp_remove(priv, entry);
+               lec_arp_put(entry);
+       } else {
+               /* Something else */
+               if ((entry->status == ESI_VC_PENDING ||
+                    entry->status == ESI_ARP_PENDING) &&
+                   time_after_eq(now, entry->timestamp +
+                                      priv->max_unknown_frame_time)) {
+                       entry->timestamp = jiffies;
+                       entry->packets_flooded = 0;
+                       if (entry->status == ESI_VC_PENDING)
+                               send_to_lecd(priv, l_svc_setup,
+                                            entry->mac_addr,
+                                            entry->atm_addr,
+                                            NULL);
+               }
+               if (entry->status == ESI_FLUSH_PENDING &&
+                   time_after_eq(now, entry->timestamp +
+                                      priv->path_switching_delay)) {
+                       lec_arp_hold(entry);
+                       return true;
+               }
+       }
+
+       return false;
+}
 /*
  * Expire entries.
  * 1. Re-set timer
@@ -1816,62 +1812,28 @@ static void lec_arp_check_expire(struct work_struct *work)
        struct hlist_node *node, *next;
        struct lec_arp_table *entry;
        unsigned long now;
-       unsigned long time_to_check;
        int i;
 
-       pr_debug("lec_arp_check_expire %p\n", priv);
+       pr_debug("%p\n", priv);
        now = jiffies;
 restart:
        spin_lock_irqsave(&priv->lec_arp_lock, flags);
        for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
-               hlist_for_each_entry_safe(entry, node, next, &priv->lec_arp_tables[i], next) {
-                       if ((entry->flags) & LEC_REMOTE_FLAG &&
-                           priv->topology_change)
-                               time_to_check = priv->forward_delay_time;
-                       else
-                               time_to_check = priv->aging_time;
-
-                       pr_debug("About to expire: %lx - %lx > %lx\n",
-                               now, entry->last_used, time_to_check);
-                       if (time_after(now, entry->last_used + time_to_check)
-                           && !(entry->flags & LEC_PERMANENT_FLAG)
-                           && !(entry->mac_addr[0] & 0x01)) {  /* LANE2: 7.1.20 */
-                               /* Remove entry */
-                               pr_debug("LEC:Entry timed out\n");
-                               lec_arp_remove(priv, entry);
+               hlist_for_each_entry_safe(entry, node, next,
+                                         &priv->lec_arp_tables[i], next) {
+                       if (__lec_arp_check_expire(entry, now, priv)) {
+                               struct sk_buff *skb;
+                               struct atm_vcc *vcc = entry->vcc;
+
+                               spin_unlock_irqrestore(&priv->lec_arp_lock,
+                                                      flags);
+                               while ((skb = skb_dequeue(&entry->tx_wait)))
+                                       lec_send(vcc, skb);
+                               entry->last_used = jiffies;
+                               entry->status = ESI_FORWARD_DIRECT;
                                lec_arp_put(entry);
-                       } else {
-                               /* Something else */
-                               if ((entry->status == ESI_VC_PENDING ||
-                                    entry->status == ESI_ARP_PENDING)
-                                   && time_after_eq(now,
-                                                    entry->timestamp +
-                                                    priv->
-                                                    max_unknown_frame_time)) {
-                                       entry->timestamp = jiffies;
-                                       entry->packets_flooded = 0;
-                                       if (entry->status == ESI_VC_PENDING)
-                                               send_to_lecd(priv, l_svc_setup,
-                                                            entry->mac_addr,
-                                                            entry->atm_addr,
-                                                            NULL);
-                               }
-                               if (entry->status == ESI_FLUSH_PENDING
-                                   &&
-                                   time_after_eq(now, entry->timestamp +
-                                                 priv->path_switching_delay)) {
-                                       struct sk_buff *skb;
-                                       struct atm_vcc *vcc = entry->vcc;
-
-                                       lec_arp_hold(entry);
-                                       spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
-                                       while ((skb = skb_dequeue(&entry->tx_wait)) != NULL)
-                                               lec_send(vcc, skb);
-                                       entry->last_used = jiffies;
-                                       entry->status = ESI_FORWARD_DIRECT;
-                                       lec_arp_put(entry);
-                                       goto restart;
-                               }
+
+                               goto restart;
                        }
                }
        }
@@ -1885,7 +1847,8 @@ restart:
  *
  */
 static struct atm_vcc *lec_arp_resolve(struct lec_priv *priv,
-                                      const unsigned char *mac_to_find, int is_rdesc,
+                                      const unsigned char *mac_to_find,
+                                      int is_rdesc,
                                       struct lec_arp_table **ret_entry)
 {
        unsigned long flags;
@@ -1921,9 +1884,8 @@ static struct atm_vcc *lec_arp_resolve(struct lec_priv *priv,
                 * If the LE_ARP cache entry is still pending, reset count to 0
                 * so another LE_ARP request can be made for this frame.
                 */
-               if (entry->status == ESI_ARP_PENDING) {
+               if (entry->status == ESI_ARP_PENDING)
                        entry->no_tries = 0;
-               }
                /*
                 * Data direct VC not yet set up, check to see if the unknown
                 * frame count is greater than the limit. If the limit has
@@ -1934,7 +1896,7 @@ static struct atm_vcc *lec_arp_resolve(struct lec_priv *priv,
                    entry->packets_flooded <
                    priv->maximum_unknown_frame_count) {
                        entry->packets_flooded++;
-                       pr_debug("LEC_ARP: Flooding..\n");
+                       pr_debug("Flooding..\n");
                        found = priv->mcast_vcc;
                        goto out;
                }
@@ -1945,13 +1907,13 @@ static struct atm_vcc *lec_arp_resolve(struct lec_priv *priv,
                 */
                lec_arp_hold(entry);
                *ret_entry = entry;
-               pr_debug("lec: entry->status %d entry->vcc %p\n", entry->status,
-                       entry->vcc);
+               pr_debug("entry->status %d entry->vcc %p\n", entry->status,
+                        entry->vcc);
                found = NULL;
        } else {
                /* No matching entry was found */
                entry = make_entry(priv, mac_to_find);
-               pr_debug("LEC_ARP: Making entry\n");
+               pr_debug("Making entry\n");
                if (!entry) {
                        found = priv->mcast_vcc;
                        goto out;
@@ -1988,13 +1950,14 @@ lec_addr_delete(struct lec_priv *priv, const unsigned char *atm_addr,
        struct lec_arp_table *entry;
        int i;
 
-       pr_debug("lec_addr_delete\n");
+       pr_debug("\n");
        spin_lock_irqsave(&priv->lec_arp_lock, flags);
        for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
-               hlist_for_each_entry_safe(entry, node, next, &priv->lec_arp_tables[i], next) {
-                       if (!memcmp(atm_addr, entry->atm_addr, ATM_ESA_LEN)
-                           && (permanent ||
-                               !(entry->flags & LEC_PERMANENT_FLAG))) {
+               hlist_for_each_entry_safe(entry, node, next,
+                                         &priv->lec_arp_tables[i], next) {
+                       if (!memcmp(atm_addr, entry->atm_addr, ATM_ESA_LEN) &&
+                           (permanent ||
+                            !(entry->flags & LEC_PERMANENT_FLAG))) {
                                lec_arp_remove(priv, entry);
                                lec_arp_put(entry);
                        }
@@ -2019,10 +1982,8 @@ lec_arp_update(struct lec_priv *priv, const unsigned char *mac_addr,
        struct lec_arp_table *entry, *tmp;
        int i;
 
-       pr_debug("lec:%s", (targetless_le_arp) ? "targetless " : " ");
-       pr_debug("lec_arp_update mac:%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n",
-               mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3],
-               mac_addr[4], mac_addr[5]);
+       pr_debug("%smac:%pM\n",
+                (targetless_le_arp) ? "targetless " : "", mac_addr);
 
        spin_lock_irqsave(&priv->lec_arp_lock, flags);
        entry = lec_arp_find(priv, mac_addr);
@@ -2032,7 +1993,8 @@ lec_arp_update(struct lec_priv *priv, const unsigned char *mac_addr,
                                 * we have no entry in the cache. 7.1.30
                                 */
        if (!hlist_empty(&priv->lec_arp_empty_ones)) {
-               hlist_for_each_entry_safe(entry, node, next, &priv->lec_arp_empty_ones, next) {
+               hlist_for_each_entry_safe(entry, node, next,
+                                         &priv->lec_arp_empty_ones, next) {
                        if (memcmp(entry->atm_addr, atm_addr, ATM_ESA_LEN) == 0) {
                                hlist_del(&entry->next);
                                del_timer(&entry->timer);
@@ -2076,7 +2038,8 @@ lec_arp_update(struct lec_priv *priv, const unsigned char *mac_addr,
        memcpy(entry->atm_addr, atm_addr, ATM_ESA_LEN);
        del_timer(&entry->timer);
        for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
-               hlist_for_each_entry(tmp, node, &priv->lec_arp_tables[i], next) {
+               hlist_for_each_entry(tmp, node,
+                                    &priv->lec_arp_tables[i], next) {
                        if (entry != tmp &&
                            !memcmp(tmp->atm_addr, atm_addr, ATM_ESA_LEN)) {
                                /* Vcc to this host exists */
@@ -2121,14 +2084,13 @@ lec_vcc_added(struct lec_priv *priv, const struct atmlec_ioc *ioc_data,
        int i, found_entry = 0;
 
        spin_lock_irqsave(&priv->lec_arp_lock, flags);
+       /* Vcc for Multicast Forward. No timer, LANEv2 7.1.20 and 2.3.5.3 */
        if (ioc_data->receive == 2) {
-               /* Vcc for Multicast Forward. No timer, LANEv2 7.1.20 and 2.3.5.3 */
-
                pr_debug("LEC_ARP: Attaching mcast forward\n");
 #if 0
                entry = lec_arp_find(priv, bus_mac);
                if (!entry) {
-                       printk("LEC_ARP: Multicast entry not found!\n");
+                       pr_info("LEC_ARP: Multicast entry not found!\n");
                        goto out;
                }
                memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN);
@@ -2149,19 +2111,17 @@ lec_vcc_added(struct lec_priv *priv, const struct atmlec_ioc *ioc_data,
                 * Vcc which we don't want to make default vcc,
                 * attach it anyway.
                 */
-               pr_debug
-                   ("LEC_ARP:Attaching data direct, not default: "
-                    "%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n",
-                    ioc_data->atm_addr[0], ioc_data->atm_addr[1],
-                    ioc_data->atm_addr[2], ioc_data->atm_addr[3],
-                    ioc_data->atm_addr[4], ioc_data->atm_addr[5],
-                    ioc_data->atm_addr[6], ioc_data->atm_addr[7],
-                    ioc_data->atm_addr[8], ioc_data->atm_addr[9],
-                    ioc_data->atm_addr[10], ioc_data->atm_addr[11],
-                    ioc_data->atm_addr[12], ioc_data->atm_addr[13],
-                    ioc_data->atm_addr[14], ioc_data->atm_addr[15],
-                    ioc_data->atm_addr[16], ioc_data->atm_addr[17],
-                    ioc_data->atm_addr[18], ioc_data->atm_addr[19]);
+               pr_debug("LEC_ARP:Attaching data direct, not default: %2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n",
+                        ioc_data->atm_addr[0], ioc_data->atm_addr[1],
+                        ioc_data->atm_addr[2], ioc_data->atm_addr[3],
+                        ioc_data->atm_addr[4], ioc_data->atm_addr[5],
+                        ioc_data->atm_addr[6], ioc_data->atm_addr[7],
+                        ioc_data->atm_addr[8], ioc_data->atm_addr[9],
+                        ioc_data->atm_addr[10], ioc_data->atm_addr[11],
+                        ioc_data->atm_addr[12], ioc_data->atm_addr[13],
+                        ioc_data->atm_addr[14], ioc_data->atm_addr[15],
+                        ioc_data->atm_addr[16], ioc_data->atm_addr[17],
+                        ioc_data->atm_addr[18], ioc_data->atm_addr[19]);
                entry = make_entry(priv, bus_mac);
                if (entry == NULL)
                        goto out;
@@ -2177,29 +2137,28 @@ lec_vcc_added(struct lec_priv *priv, const struct atmlec_ioc *ioc_data,
                dump_arp_table(priv);
                goto out;
        }
-       pr_debug
-           ("LEC_ARP:Attaching data direct, default: "
-            "%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n",
-            ioc_data->atm_addr[0], ioc_data->atm_addr[1],
-            ioc_data->atm_addr[2], ioc_data->atm_addr[3],
-            ioc_data->atm_addr[4], ioc_data->atm_addr[5],
-            ioc_data->atm_addr[6], ioc_data->atm_addr[7],
-            ioc_data->atm_addr[8], ioc_data->atm_addr[9],
-            ioc_data->atm_addr[10], ioc_data->atm_addr[11],
-            ioc_data->atm_addr[12], ioc_data->atm_addr[13],
-            ioc_data->atm_addr[14], ioc_data->atm_addr[15],
-            ioc_data->atm_addr[16], ioc_data->atm_addr[17],
-            ioc_data->atm_addr[18], ioc_data->atm_addr[19]);
+       pr_debug("LEC_ARP:Attaching data direct, default: %2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n",
+                ioc_data->atm_addr[0], ioc_data->atm_addr[1],
+                ioc_data->atm_addr[2], ioc_data->atm_addr[3],
+                ioc_data->atm_addr[4], ioc_data->atm_addr[5],
+                ioc_data->atm_addr[6], ioc_data->atm_addr[7],
+                ioc_data->atm_addr[8], ioc_data->atm_addr[9],
+                ioc_data->atm_addr[10], ioc_data->atm_addr[11],
+                ioc_data->atm_addr[12], ioc_data->atm_addr[13],
+                ioc_data->atm_addr[14], ioc_data->atm_addr[15],
+                ioc_data->atm_addr[16], ioc_data->atm_addr[17],
+                ioc_data->atm_addr[18], ioc_data->atm_addr[19]);
        for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
-               hlist_for_each_entry(entry, node, &priv->lec_arp_tables[i], next) {
+               hlist_for_each_entry(entry, node,
+                                    &priv->lec_arp_tables[i], next) {
                        if (memcmp
                            (ioc_data->atm_addr, entry->atm_addr,
                             ATM_ESA_LEN) == 0) {
                                pr_debug("LEC_ARP: Attaching data direct\n");
                                pr_debug("Currently -> Vcc: %d, Rvcc:%d\n",
-                                       entry->vcc ? entry->vcc->vci : 0,
-                                       entry->recv_vcc ? entry->recv_vcc->
-                                       vci : 0);
+                                        entry->vcc ? entry->vcc->vci : 0,
+                                        entry->recv_vcc ? entry->recv_vcc->
+                                        vci : 0);
                                found_entry = 1;
                                del_timer(&entry->timer);
                                entry->vcc = vcc;
@@ -2271,19 +2230,21 @@ static void lec_flush_complete(struct lec_priv *priv, unsigned long tran_id)
        struct lec_arp_table *entry;
        int i;
 
-       pr_debug("LEC:lec_flush_complete %lx\n", tran_id);
+       pr_debug("%lx\n", tran_id);
 restart:
        spin_lock_irqsave(&priv->lec_arp_lock, flags);
        for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
-               hlist_for_each_entry(entry, node, &priv->lec_arp_tables[i], next) {
-                       if (entry->flush_tran_id == tran_id
-                           && entry->status == ESI_FLUSH_PENDING) {
+               hlist_for_each_entry(entry, node,
+                                    &priv->lec_arp_tables[i], next) {
+                       if (entry->flush_tran_id == tran_id &&
+                           entry->status == ESI_FLUSH_PENDING) {
                                struct sk_buff *skb;
                                struct atm_vcc *vcc = entry->vcc;
 
                                lec_arp_hold(entry);
-                               spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
-                               while ((skb = skb_dequeue(&entry->tx_wait)) != NULL)
+                               spin_unlock_irqrestore(&priv->lec_arp_lock,
+                                                      flags);
+                               while ((skb = skb_dequeue(&entry->tx_wait)))
                                        lec_send(vcc, skb);
                                entry->last_used = jiffies;
                                entry->status = ESI_FORWARD_DIRECT;
@@ -2308,11 +2269,12 @@ lec_set_flush_tran_id(struct lec_priv *priv,
 
        spin_lock_irqsave(&priv->lec_arp_lock, flags);
        for (i = 0; i < LEC_ARP_TABLE_SIZE; i++)
-               hlist_for_each_entry(entry, node, &priv->lec_arp_tables[i], next) {
+               hlist_for_each_entry(entry, node,
+                                    &priv->lec_arp_tables[i], next) {
                        if (!memcmp(atm_addr, entry->atm_addr, ATM_ESA_LEN)) {
                                entry->flush_tran_id = tran_id;
                                pr_debug("Set flush transaction id to %lx for %p\n",
-                                       tran_id, entry);
+                                        tran_id, entry);
                        }
                }
        spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
@@ -2328,7 +2290,8 @@ static int lec_mcast_make(struct lec_priv *priv, struct atm_vcc *vcc)
        struct lec_vcc_priv *vpriv;
        int err = 0;
 
-       if (!(vpriv = kmalloc(sizeof(struct lec_vcc_priv), GFP_KERNEL)))
+       vpriv = kmalloc(sizeof(struct lec_vcc_priv), GFP_KERNEL);
+       if (!vpriv)
                return -ENOMEM;
        vpriv->xoff = 0;
        vpriv->old_pop = vcc->pop;
@@ -2368,18 +2331,19 @@ static void lec_vcc_close(struct lec_priv *priv, struct atm_vcc *vcc)
        spin_lock_irqsave(&priv->lec_arp_lock, flags);
 
        for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
-               hlist_for_each_entry_safe(entry, node, next, &priv->lec_arp_tables[i], next) {
+               hlist_for_each_entry_safe(entry, node, next,
+                                         &priv->lec_arp_tables[i], next) {
                        if (vcc == entry->vcc) {
                                lec_arp_remove(priv, entry);
                                lec_arp_put(entry);
-                               if (priv->mcast_vcc == vcc) {
+                               if (priv->mcast_vcc == vcc)
                                        priv->mcast_vcc = NULL;
-                               }
                        }
                }
        }
 
-       hlist_for_each_entry_safe(entry, node, next, &priv->lec_arp_empty_ones, next) {
+       hlist_for_each_entry_safe(entry, node, next,
+                                 &priv->lec_arp_empty_ones, next) {
                if (entry->vcc == vcc) {
                        lec_arp_clear_vccs(entry);
                        del_timer(&entry->timer);
@@ -2388,7 +2352,8 @@ static void lec_vcc_close(struct lec_priv *priv, struct atm_vcc *vcc)
                }
        }
 
-       hlist_for_each_entry_safe(entry, node, next, &priv->lec_no_forward, next) {
+       hlist_for_each_entry_safe(entry, node, next,
+                                 &priv->lec_no_forward, next) {
                if (entry->recv_vcc == vcc) {
                        lec_arp_clear_vccs(entry);
                        del_timer(&entry->timer);
@@ -2429,14 +2394,16 @@ lec_arp_check_empties(struct lec_priv *priv,
                src = hdr->h_source;
 
        spin_lock_irqsave(&priv->lec_arp_lock, flags);
-       hlist_for_each_entry_safe(entry, node, next, &priv->lec_arp_empty_ones, next) {
+       hlist_for_each_entry_safe(entry, node, next,
+                                 &priv->lec_arp_empty_ones, next) {
                if (vcc == entry->vcc) {
                        del_timer(&entry->timer);
                        memcpy(entry->mac_addr, src, ETH_ALEN);
                        entry->status = ESI_FORWARD_DIRECT;
                        entry->last_used = jiffies;
                        /* We might have got an entry */
-                       if ((tmp = lec_arp_find(priv, src))) {
+                       tmp = lec_arp_find(priv, src);
+                       if (tmp) {
                                lec_arp_remove(priv, tmp);
                                lec_arp_put(tmp);
                        }
index 38a6cb0863f052d5557ee4938475a576bc64b632..a6521c8aa88b58b9ceedb410d5807cdff1cd9127 100644 (file)
@@ -1,3 +1,5 @@
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
+
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/timer.h>
@@ -13,8 +15,8 @@
 #include <net/sock.h>
 #include <linux/skbuff.h>
 #include <linux/ip.h>
+#include <linux/uaccess.h>
 #include <asm/byteorder.h>
-#include <asm/uaccess.h>
 #include <net/checksum.h>   /* for ip_fast_csum() */
 #include <net/arp.h>
 #include <net/dst.h>
  */
 
 #if 0
-#define dprintk printk   /* debug */
+#define dprintk(format, args...) \
+       printk(KERN_DEBUG "mpoa:%s: " format, __func__, ##args)
+#define dprintk_cont(format, args...) printk(KERN_CONT format, ##args)
 #else
-#define dprintk(format,args...)
+#define dprintk(format, args...)                                       \
+       do { if (0)                                                     \
+               printk(KERN_DEBUG "mpoa:%s: " format, __func__, ##args);\
+       } while (0)
+#define dprintk_cont(format, args...)                  \
+       do { if (0) printk(KERN_CONT format, ##args); } while (0)
 #endif
 
 #if 0
-#define ddprintk printk  /* more debug */
+#define ddprintk(format, args...) \
+       printk(KERN_DEBUG "mpoa:%s: " format, __func__, ##args)
+#define ddprintk_cont(format, args...) printk(KERN_CONT format, ##args)
 #else
-#define ddprintk(format,args...)
+#define ddprintk(format, args...)                                      \
+       do { if (0)                                                     \
+               printk(KERN_DEBUG "mpoa:%s: " format, __func__, ##args);\
+       } while (0)
+#define ddprintk_cont(format, args...)                 \
+       do { if (0) printk(KERN_CONT format, ##args); } while (0)
 #endif
 
-
-
 #define MPOA_TAG_LEN 4
 
 /* mpc_daemon -> kernel */
-static void MPOA_trigger_rcvd (struct k_message *msg, struct mpoa_client *mpc);
+static void MPOA_trigger_rcvd(struct k_message *msg, struct mpoa_client *mpc);
 static void MPOA_res_reply_rcvd(struct k_message *msg, struct mpoa_client *mpc);
 static void ingress_purge_rcvd(struct k_message *msg, struct mpoa_client *mpc);
 static void egress_purge_rcvd(struct k_message *msg, struct mpoa_client *mpc);
 static void mps_death(struct k_message *msg, struct mpoa_client *mpc);
-static void clean_up(struct k_message *msg, struct mpoa_client *mpc, int action);
-static void MPOA_cache_impos_rcvd(struct k_message *msg, struct mpoa_client *mpc);
-static void set_mpc_ctrl_addr_rcvd(struct k_message *mesg, struct mpoa_client *mpc);
-static void set_mps_mac_addr_rcvd(struct k_message *mesg, struct mpoa_client *mpc);
+static void clean_up(struct k_message *msg, struct mpoa_client *mpc,
+                    int action);
+static void MPOA_cache_impos_rcvd(struct k_message *msg,
+                                 struct mpoa_client *mpc);
+static void set_mpc_ctrl_addr_rcvd(struct k_message *mesg,
+                                  struct mpoa_client *mpc);
+static void set_mps_mac_addr_rcvd(struct k_message *mesg,
+                                 struct mpoa_client *mpc);
 
 static const uint8_t *copy_macs(struct mpoa_client *mpc,
                                const uint8_t *router_mac,
@@ -74,10 +92,11 @@ static int msg_from_mpoad(struct atm_vcc *vcc, struct sk_buff *skb);
 
 static void mpc_push(struct atm_vcc *vcc, struct sk_buff *skb);
 static netdev_tx_t mpc_send_packet(struct sk_buff *skb,
-                                        struct net_device *dev);
-static int mpoa_event_listener(struct notifier_block *mpoa_notifier, unsigned long event, void *dev);
+                                  struct net_device *dev);
+static int mpoa_event_listener(struct notifier_block *mpoa_notifier,
+                              unsigned long event, void *dev);
 static void mpc_timer_refresh(void);
-static void mpc_cache_check( unsigned long checking_time  );
+static void mpc_cache_check(unsigned long checking_time);
 
 static struct llc_snap_hdr llc_snap_mpoa_ctrl = {
        0xaa, 0xaa, 0x03,
@@ -167,7 +186,7 @@ struct atm_mpoa_qos *atm_mpoa_add_qos(__be32 dst_ip, struct atm_qos *qos)
 
        entry = kmalloc(sizeof(struct atm_mpoa_qos), GFP_KERNEL);
        if (entry == NULL) {
-               printk("mpoa: atm_mpoa_add_qos: out of memory\n");
+               pr_info("mpoa: out of memory\n");
                return entry;
        }
 
@@ -185,10 +204,9 @@ struct atm_mpoa_qos *atm_mpoa_search_qos(__be32 dst_ip)
        struct atm_mpoa_qos *qos;
 
        qos = qos_head;
-       while( qos != NULL ){
-               if(qos->ipaddr == dst_ip) {
+       while (qos) {
+               if (qos->ipaddr == dst_ip)
                        break;
-               }
                qos = qos->next;
        }
 
@@ -200,10 +218,10 @@ struct atm_mpoa_qos *atm_mpoa_search_qos(__be32 dst_ip)
  */
 int atm_mpoa_delete_qos(struct atm_mpoa_qos *entry)
 {
-
        struct atm_mpoa_qos *curr;
 
-       if (entry == NULL) return 0;
+       if (entry == NULL)
+               return 0;
        if (entry == qos_head) {
                qos_head = qos_head->next;
                kfree(entry);
@@ -234,9 +252,17 @@ void atm_mpoa_disp_qos(struct seq_file *m)
 
        while (qos != NULL) {
                seq_printf(m, "%pI4\n     %-7d %-7d %-7d %-7d %-7d\n     %-7d %-7d %-7d %-7d %-7d\n",
-                               &qos->ipaddr,
-                               qos->qos.txtp.max_pcr, qos->qos.txtp.pcr, qos->qos.txtp.min_pcr, qos->qos.txtp.max_cdv, qos->qos.txtp.max_sdu,
-                               qos->qos.rxtp.max_pcr, qos->qos.rxtp.pcr, qos->qos.rxtp.min_pcr, qos->qos.rxtp.max_cdv, qos->qos.rxtp.max_sdu);
+                          &qos->ipaddr,
+                          qos->qos.txtp.max_pcr,
+                          qos->qos.txtp.pcr,
+                          qos->qos.txtp.min_pcr,
+                          qos->qos.txtp.max_cdv,
+                          qos->qos.txtp.max_sdu,
+                          qos->qos.rxtp.max_pcr,
+                          qos->qos.rxtp.pcr,
+                          qos->qos.rxtp.min_pcr,
+                          qos->qos.rxtp.max_cdv,
+                          qos->qos.rxtp.max_sdu);
                qos = qos->next;
        }
 }
@@ -256,7 +282,7 @@ static struct mpoa_client *alloc_mpc(void)
 {
        struct mpoa_client *mpc;
 
-       mpc = kzalloc(sizeof (struct mpoa_client), GFP_KERNEL);
+       mpc = kzalloc(sizeof(struct mpoa_client), GFP_KERNEL);
        if (mpc == NULL)
                return NULL;
        rwlock_init(&mpc->ingress_lock);
@@ -266,7 +292,7 @@ static struct mpoa_client *alloc_mpc(void)
 
        mpc->parameters.mpc_p1 = MPC_P1;
        mpc->parameters.mpc_p2 = MPC_P2;
-       memset(mpc->parameters.mpc_p3,0,sizeof(mpc->parameters.mpc_p3));
+       memset(mpc->parameters.mpc_p3, 0, sizeof(mpc->parameters.mpc_p3));
        mpc->parameters.mpc_p4 = MPC_P4;
        mpc->parameters.mpc_p5 = MPC_P5;
        mpc->parameters.mpc_p6 = MPC_P6;
@@ -286,9 +312,9 @@ static struct mpoa_client *alloc_mpc(void)
 static void start_mpc(struct mpoa_client *mpc, struct net_device *dev)
 {
 
-       dprintk("mpoa: (%s) start_mpc:\n", mpc->dev->name);
+       dprintk("(%s)\n", mpc->dev->name);
        if (!dev->netdev_ops)
-               printk("mpoa: (%s) start_mpc  not starting\n", dev->name);
+               pr_info("(%s) not starting\n", dev->name);
        else {
                mpc->old_ops = dev->netdev_ops;
                mpc->new_ops = *mpc->old_ops;
@@ -300,14 +326,14 @@ static void start_mpc(struct mpoa_client *mpc, struct net_device *dev)
 static void stop_mpc(struct mpoa_client *mpc)
 {
        struct net_device *dev = mpc->dev;
-       dprintk("mpoa: (%s) stop_mpc:", mpc->dev->name);
+       dprintk("(%s)", mpc->dev->name);
 
        /* Lets not nullify lec device's dev->hard_start_xmit */
        if (dev->netdev_ops != &mpc->new_ops) {
-               dprintk(" mpc already stopped, not fatal\n");
+               dprintk_cont(" mpc already stopped, not fatal\n");
                return;
        }
-       dprintk("\n");
+       dprintk_cont("\n");
 
        dev->netdev_ops = mpc->old_ops;
        mpc->old_ops = NULL;
@@ -319,25 +345,18 @@ static const char *mpoa_device_type_string(char type) __attribute__ ((unused));
 
 static const char *mpoa_device_type_string(char type)
 {
-       switch(type) {
+       switch (type) {
        case NON_MPOA:
                return "non-MPOA device";
-               break;
        case MPS:
                return "MPS";
-               break;
        case MPC:
                return "MPC";
-               break;
        case MPS_AND_MPC:
                return "both MPS and MPC";
-               break;
-       default:
-               return "unspecified (non-MPOA) device";
-               break;
        }
 
-       return ""; /* not reached */
+       return "unspecified (non-MPOA) device";
 }
 
 /*
@@ -362,26 +381,28 @@ static void lane2_assoc_ind(struct net_device *dev, const u8 *mac_addr,
        struct mpoa_client *mpc;
 
        mpoa_device_type = number_of_mps_macs = 0; /* silence gcc */
-       dprintk("mpoa: (%s) lane2_assoc_ind: received TLV(s), ", dev->name);
+       dprintk("(%s) received TLV(s), ", dev->name);
        dprintk("total length of all TLVs %d\n", sizeoftlvs);
        mpc = find_mpc_by_lec(dev); /* Sampo-Fix: moved here from below */
        if (mpc == NULL) {
-               printk("mpoa: (%s) lane2_assoc_ind: no mpc\n", dev->name);
+               pr_info("(%s) no mpc\n", dev->name);
                return;
        }
        end_of_tlvs = tlvs + sizeoftlvs;
        while (end_of_tlvs - tlvs >= 5) {
-               type = (tlvs[0] << 24) | (tlvs[1] << 16) | (tlvs[2] << 8) | tlvs[3];
+               type = ((tlvs[0] << 24) | (tlvs[1] << 16) |
+                       (tlvs[2] << 8) | tlvs[3]);
                length = tlvs[4];
                tlvs += 5;
                dprintk("    type 0x%x length %02x\n", type, length);
                if (tlvs + length > end_of_tlvs) {
-                       printk("TLV value extends past its buffer, aborting parse\n");
+                       pr_info("TLV value extends past its buffer, aborting parse\n");
                        return;
                }
 
                if (type == 0) {
-                       printk("mpoa: (%s) lane2_assoc_ind: TLV type was 0, returning\n", dev->name);
+                       pr_info("mpoa: (%s) TLV type was 0, returning\n",
+                               dev->name);
                        return;
                }
 
@@ -391,39 +412,48 @@ static void lane2_assoc_ind(struct net_device *dev, const u8 *mac_addr,
                }
                mpoa_device_type = *tlvs++;
                number_of_mps_macs = *tlvs++;
-               dprintk("mpoa: (%s) MPOA device type '%s', ", dev->name, mpoa_device_type_string(mpoa_device_type));
+               dprintk("(%s) MPOA device type '%s', ",
+                       dev->name, mpoa_device_type_string(mpoa_device_type));
                if (mpoa_device_type == MPS_AND_MPC &&
                    length < (42 + number_of_mps_macs*ETH_ALEN)) { /* :) */
-                       printk("\nmpoa: (%s) lane2_assoc_ind: short MPOA Device Type TLV\n",
-                              dev->name);
+                       pr_info("(%s) short MPOA Device Type TLV\n",
+                               dev->name);
                        continue;
                }
-               if ((mpoa_device_type == MPS || mpoa_device_type == MPC)
-                   && length < 22 + number_of_mps_macs*ETH_ALEN) {
-                       printk("\nmpoa: (%s) lane2_assoc_ind: short MPOA Device Type TLV\n",
-                               dev->name);
+               if ((mpoa_device_type == MPS || mpoa_device_type == MPC) &&
+                   length < 22 + number_of_mps_macs*ETH_ALEN) {
+                       pr_info("(%s) short MPOA Device Type TLV\n", dev->name);
                        continue;
                }
-               if (mpoa_device_type != MPS && mpoa_device_type != MPS_AND_MPC) {
-                       dprintk("ignoring non-MPS device\n");
-                       if (mpoa_device_type == MPC) tlvs += 20;
+               if (mpoa_device_type != MPS &&
+                   mpoa_device_type != MPS_AND_MPC) {
+                       dprintk("ignoring non-MPS device ");
+                       if (mpoa_device_type == MPC)
+                               tlvs += 20;
                        continue;  /* we are only interested in MPSs */
                }
-               if (number_of_mps_macs == 0 && mpoa_device_type == MPS_AND_MPC) {
-                       printk("\nmpoa: (%s) lane2_assoc_ind: MPS_AND_MPC has zero MACs\n", dev->name);
+               if (number_of_mps_macs == 0 &&
+                   mpoa_device_type == MPS_AND_MPC) {
+                       pr_info("(%s) MPS_AND_MPC has zero MACs\n", dev->name);
                        continue;  /* someone should read the spec */
                }
-               dprintk("this MPS has %d MAC addresses\n", number_of_mps_macs);
+               dprintk_cont("this MPS has %d MAC addresses\n",
+                            number_of_mps_macs);
 
-               /* ok, now we can go and tell our daemon the control address of MPS */
+               /*
+                * ok, now we can go and tell our daemon
+                * the control address of MPS
+                */
                send_set_mps_ctrl_addr(tlvs, mpc);
 
-               tlvs = copy_macs(mpc, mac_addr, tlvs, number_of_mps_macs, mpoa_device_type);
-               if (tlvs == NULL) return;
+               tlvs = copy_macs(mpc, mac_addr, tlvs,
+                                number_of_mps_macs, mpoa_device_type);
+               if (tlvs == NULL)
+                       return;
        }
        if (end_of_tlvs - tlvs != 0)
-               printk("mpoa: (%s) lane2_assoc_ind: ignoring %Zd bytes of trailing TLV carbage\n",
-                      dev->name, end_of_tlvs - tlvs);
+               pr_info("(%s) ignoring %Zd bytes of trailing TLV garbage\n",
+                       dev->name, end_of_tlvs - tlvs);
        return;
 }
 
@@ -441,11 +471,12 @@ static const uint8_t *copy_macs(struct mpoa_client *mpc,
        num_macs = (mps_macs > 1) ? mps_macs : 1;
 
        if (mpc->number_of_mps_macs != num_macs) { /* need to reallocate? */
-               if (mpc->number_of_mps_macs != 0) kfree(mpc->mps_macs);
+               if (mpc->number_of_mps_macs != 0)
+                       kfree(mpc->mps_macs);
                mpc->number_of_mps_macs = 0;
-               mpc->mps_macs = kmalloc(num_macs*ETH_ALEN, GFP_KERNEL);
+               mpc->mps_macs = kmalloc(num_macs * ETH_ALEN, GFP_KERNEL);
                if (mpc->mps_macs == NULL) {
-                       printk("mpoa: (%s) copy_macs: out of mem\n", mpc->dev->name);
+                       pr_info("(%s) out of mem\n", mpc->dev->name);
                        return NULL;
                }
        }
@@ -478,24 +509,30 @@ static int send_via_shortcut(struct sk_buff *skb, struct mpoa_client *mpc)
        iph = (struct iphdr *)buff;
        ipaddr = iph->daddr;
 
-       ddprintk("mpoa: (%s) send_via_shortcut: ipaddr 0x%x\n", mpc->dev->name, ipaddr);
+       ddprintk("(%s) ipaddr 0x%x\n",
+                mpc->dev->name, ipaddr);
 
        entry = mpc->in_ops->get(ipaddr, mpc);
        if (entry == NULL) {
                entry = mpc->in_ops->add_entry(ipaddr, mpc);
-               if (entry != NULL) mpc->in_ops->put(entry);
+               if (entry != NULL)
+                       mpc->in_ops->put(entry);
                return 1;
        }
-       if (mpc->in_ops->cache_hit(entry, mpc) != OPEN){   /* threshold not exceeded or VCC not ready */
-               ddprintk("mpoa: (%s) send_via_shortcut: cache_hit: returns != OPEN\n", mpc->dev->name);
+       /* threshold not exceeded or VCC not ready */
+       if (mpc->in_ops->cache_hit(entry, mpc) != OPEN) {
+               ddprintk("(%s) cache_hit: returns != OPEN\n",
+                        mpc->dev->name);
                mpc->in_ops->put(entry);
                return 1;
        }
 
-       ddprintk("mpoa: (%s) send_via_shortcut: using shortcut\n", mpc->dev->name);
+       ddprintk("(%s) using shortcut\n",
+                mpc->dev->name);
        /* MPOA spec A.1.4, MPOA client must decrement IP ttl at least by one */
        if (iph->ttl <= 1) {
-               ddprintk("mpoa: (%s) send_via_shortcut: IP ttl = %u, using LANE\n", mpc->dev->name, iph->ttl);
+               ddprintk("(%s) IP ttl = %u, using LANE\n",
+                        mpc->dev->name, iph->ttl);
                mpc->in_ops->put(entry);
                return 1;
        }
@@ -504,15 +541,18 @@ static int send_via_shortcut(struct sk_buff *skb, struct mpoa_client *mpc)
        iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
 
        if (entry->ctrl_info.tag != 0) {
-               ddprintk("mpoa: (%s) send_via_shortcut: adding tag 0x%x\n", mpc->dev->name, entry->ctrl_info.tag);
+               ddprintk("(%s) adding tag 0x%x\n",
+                        mpc->dev->name, entry->ctrl_info.tag);
                tagged_llc_snap_hdr.tag = entry->ctrl_info.tag;
-               skb_pull(skb, ETH_HLEN);                       /* get rid of Eth header */
-               skb_push(skb, sizeof(tagged_llc_snap_hdr));    /* add LLC/SNAP header   */
+               skb_pull(skb, ETH_HLEN);        /* get rid of Eth header */
+               skb_push(skb, sizeof(tagged_llc_snap_hdr));
+                                               /* add LLC/SNAP header   */
                skb_copy_to_linear_data(skb, &tagged_llc_snap_hdr,
                                        sizeof(tagged_llc_snap_hdr));
        } else {
-               skb_pull(skb, ETH_HLEN);                        /* get rid of Eth header */
-               skb_push(skb, sizeof(struct llc_snap_hdr));     /* add LLC/SNAP header + tag  */
+               skb_pull(skb, ETH_HLEN);        /* get rid of Eth header */
+               skb_push(skb, sizeof(struct llc_snap_hdr));
+                                               /* add LLC/SNAP header + tag  */
                skb_copy_to_linear_data(skb, &llc_snap_mpoa_data,
                                        sizeof(struct llc_snap_hdr));
        }
@@ -537,8 +577,8 @@ static netdev_tx_t mpc_send_packet(struct sk_buff *skb,
        int i = 0;
 
        mpc = find_mpc_by_lec(dev); /* this should NEVER fail */
-       if(mpc == NULL) {
-               printk("mpoa: (%s) mpc_send_packet: no MPC found\n", dev->name);
+       if (mpc == NULL) {
+               pr_info("(%s) no MPC found\n", dev->name);
                goto non_ip;
        }
 
@@ -554,14 +594,15 @@ static netdev_tx_t mpc_send_packet(struct sk_buff *skb,
                goto non_ip;
 
        while (i < mpc->number_of_mps_macs) {
-               if (!compare_ether_addr(eth->h_dest, (mpc->mps_macs + i*ETH_ALEN)))
-                       if ( send_via_shortcut(skb, mpc) == 0 )           /* try shortcut */
-                               return NETDEV_TX_OK;                      /* success!     */
+               if (!compare_ether_addr(eth->h_dest,
+                                       (mpc->mps_macs + i*ETH_ALEN)))
+                       if (send_via_shortcut(skb, mpc) == 0) /* try shortcut */
+                               return NETDEV_TX_OK;
                i++;
        }
 
- non_ip:
-       return mpc->old_ops->ndo_start_xmit(skb,dev);
+non_ip:
+       return mpc->old_ops->ndo_start_xmit(skb, dev);
 }
 
 static int atm_mpoa_vcc_attach(struct atm_vcc *vcc, void __user *arg)
@@ -574,7 +615,8 @@ static int atm_mpoa_vcc_attach(struct atm_vcc *vcc, void __user *arg)
 
        bytes_left = copy_from_user(&ioc_data, arg, sizeof(struct atmmpc_ioc));
        if (bytes_left != 0) {
-               printk("mpoa: mpc_vcc_attach: Short read (missed %d bytes) from userland\n", bytes_left);
+               pr_info("mpoa:Short read (missed %d bytes) from userland\n",
+                       bytes_left);
                return -EFAULT;
        }
        ipaddr = ioc_data.ipaddr;
@@ -587,18 +629,20 @@ static int atm_mpoa_vcc_attach(struct atm_vcc *vcc, void __user *arg)
 
        if (ioc_data.type == MPC_SOCKET_INGRESS) {
                in_entry = mpc->in_ops->get(ipaddr, mpc);
-               if (in_entry == NULL || in_entry->entry_state < INGRESS_RESOLVED) {
-                       printk("mpoa: (%s) mpc_vcc_attach: did not find RESOLVED entry from ingress cache\n",
+               if (in_entry == NULL ||
+                   in_entry->entry_state < INGRESS_RESOLVED) {
+                       pr_info("(%s) did not find RESOLVED entry from ingress cache\n",
                                mpc->dev->name);
-                       if (in_entry != NULL) mpc->in_ops->put(in_entry);
+                       if (in_entry != NULL)
+                               mpc->in_ops->put(in_entry);
                        return -EINVAL;
                }
-               printk("mpoa: (%s) mpc_vcc_attach: attaching ingress SVC, entry = %pI4\n",
-                      mpc->dev->name, &in_entry->ctrl_info.in_dst_ip);
+               pr_info("(%s) attaching ingress SVC, entry = %pI4\n",
+                       mpc->dev->name, &in_entry->ctrl_info.in_dst_ip);
                in_entry->shortcut = vcc;
                mpc->in_ops->put(in_entry);
        } else {
-               printk("mpoa: (%s) mpc_vcc_attach: attaching egress SVC\n", mpc->dev->name);
+               pr_info("(%s) attaching egress SVC\n", mpc->dev->name);
        }
 
        vcc->proto_data = mpc->dev;
@@ -618,27 +662,27 @@ static void mpc_vcc_close(struct atm_vcc *vcc, struct net_device *dev)
 
        mpc = find_mpc_by_lec(dev);
        if (mpc == NULL) {
-               printk("mpoa: (%s) mpc_vcc_close: close for unknown MPC\n", dev->name);
+               pr_info("(%s) close for unknown MPC\n", dev->name);
                return;
        }
 
-       dprintk("mpoa: (%s) mpc_vcc_close:\n", dev->name);
+       dprintk("(%s)\n", dev->name);
        in_entry = mpc->in_ops->get_by_vcc(vcc, mpc);
        if (in_entry) {
-               dprintk("mpoa: (%s) mpc_vcc_close: ingress SVC closed ip = %pI4\n",
-                      mpc->dev->name, &in_entry->ctrl_info.in_dst_ip);
+               dprintk("(%s) ingress SVC closed ip = %pI4\n",
+                       mpc->dev->name, &in_entry->ctrl_info.in_dst_ip);
                in_entry->shortcut = NULL;
                mpc->in_ops->put(in_entry);
        }
        eg_entry = mpc->eg_ops->get_by_vcc(vcc, mpc);
        if (eg_entry) {
-               dprintk("mpoa: (%s) mpc_vcc_close: egress SVC closed\n", mpc->dev->name);
+               dprintk("(%s) egress SVC closed\n", mpc->dev->name);
                eg_entry->shortcut = NULL;
                mpc->eg_ops->put(eg_entry);
        }
 
        if (in_entry == NULL && eg_entry == NULL)
-               dprintk("mpoa: (%s) mpc_vcc_close:  unused vcc closed\n", dev->name);
+               dprintk("(%s) unused vcc closed\n", dev->name);
 
        return;
 }
@@ -652,18 +696,19 @@ static void mpc_push(struct atm_vcc *vcc, struct sk_buff *skb)
        __be32 tag;
        char *tmp;
 
-       ddprintk("mpoa: (%s) mpc_push:\n", dev->name);
+       ddprintk("(%s)\n", dev->name);
        if (skb == NULL) {
-               dprintk("mpoa: (%s) mpc_push: null skb, closing VCC\n", dev->name);
+               dprintk("(%s) null skb, closing VCC\n", dev->name);
                mpc_vcc_close(vcc, dev);
                return;
        }
 
        skb->dev = dev;
-       if (memcmp(skb->data, &llc_snap_mpoa_ctrl, sizeof(struct llc_snap_hdr)) == 0) {
+       if (memcmp(skb->data, &llc_snap_mpoa_ctrl,
+                  sizeof(struct llc_snap_hdr)) == 0) {
                struct sock *sk = sk_atm(vcc);
 
-               dprintk("mpoa: (%s) mpc_push: control packet arrived\n", dev->name);
+               dprintk("(%s) control packet arrived\n", dev->name);
                /* Pass control packets to daemon */
                skb_queue_tail(&sk->sk_receive_queue, skb);
                sk->sk_data_ready(sk, skb->len);
@@ -675,20 +720,22 @@ static void mpc_push(struct atm_vcc *vcc, struct sk_buff *skb)
 
        mpc = find_mpc_by_lec(dev);
        if (mpc == NULL) {
-               printk("mpoa: (%s) mpc_push: unknown MPC\n", dev->name);
+               pr_info("(%s) unknown MPC\n", dev->name);
                return;
        }
 
-       if (memcmp(skb->data, &llc_snap_mpoa_data_tagged, sizeof(struct llc_snap_hdr)) == 0) { /* MPOA tagged data */
-               ddprintk("mpoa: (%s) mpc_push: tagged data packet arrived\n", dev->name);
+       if (memcmp(skb->data, &llc_snap_mpoa_data_tagged,
+                  sizeof(struct llc_snap_hdr)) == 0) { /* MPOA tagged data */
+               ddprintk("(%s) tagged data packet arrived\n", dev->name);
 
-       } else if (memcmp(skb->data, &llc_snap_mpoa_data, sizeof(struct llc_snap_hdr)) == 0) { /* MPOA data */
-               printk("mpoa: (%s) mpc_push: non-tagged data packet arrived\n", dev->name);
-               printk("           mpc_push: non-tagged data unsupported, purging\n");
+       } else if (memcmp(skb->data, &llc_snap_mpoa_data,
+                         sizeof(struct llc_snap_hdr)) == 0) { /* MPOA data */
+               pr_info("(%s) Unsupported non-tagged data packet arrived.  Purging\n",
+                       dev->name);
                dev_kfree_skb_any(skb);
                return;
        } else {
-               printk("mpoa: (%s) mpc_push: garbage arrived, purging\n", dev->name);
+               pr_info("(%s) garbage arrived, purging\n", dev->name);
                dev_kfree_skb_any(skb);
                return;
        }
@@ -698,8 +745,8 @@ static void mpc_push(struct atm_vcc *vcc, struct sk_buff *skb)
 
        eg = mpc->eg_ops->get_by_tag(tag, mpc);
        if (eg == NULL) {
-               printk("mpoa: (%s) mpc_push: Didn't find egress cache entry, tag = %u\n",
-                      dev->name,tag);
+               pr_info("mpoa: (%s) Didn't find egress cache entry, tag = %u\n",
+                       dev->name, tag);
                purge_egress_shortcut(vcc, NULL);
                dev_kfree_skb_any(skb);
                return;
@@ -711,13 +758,15 @@ static void mpc_push(struct atm_vcc *vcc, struct sk_buff *skb)
         */
        if (eg->shortcut == NULL) {
                eg->shortcut = vcc;
-               printk("mpoa: (%s) mpc_push: egress SVC in use\n", dev->name);
+               pr_info("(%s) egress SVC in use\n", dev->name);
        }
 
-       skb_pull(skb, sizeof(struct llc_snap_hdr) + sizeof(tag)); /* get rid of LLC/SNAP header */
-       new_skb = skb_realloc_headroom(skb, eg->ctrl_info.DH_length); /* LLC/SNAP is shorter than MAC header :( */
+       skb_pull(skb, sizeof(struct llc_snap_hdr) + sizeof(tag));
+                                       /* get rid of LLC/SNAP header */
+       new_skb = skb_realloc_headroom(skb, eg->ctrl_info.DH_length);
+                                       /* LLC/SNAP is shorter than MAC header :( */
        dev_kfree_skb_any(skb);
-       if (new_skb == NULL){
+       if (new_skb == NULL) {
                mpc->eg_ops->put(eg);
                return;
        }
@@ -750,7 +799,7 @@ static struct atm_dev mpc_dev = {
        /* members not explicitly initialised will be 0 */
 };
 
-static int atm_mpoa_mpoad_attach (struct atm_vcc *vcc, int arg)
+static int atm_mpoa_mpoad_attach(struct atm_vcc *vcc, int arg)
 {
        struct mpoa_client *mpc;
        struct lec_priv *priv;
@@ -770,15 +819,16 @@ static int atm_mpoa_mpoad_attach (struct atm_vcc *vcc, int arg)
 
        mpc = find_mpc_by_itfnum(arg);
        if (mpc == NULL) {
-               dprintk("mpoa: mpoad_attach: allocating new mpc for itf %d\n", arg);
+               dprintk("allocating new mpc for itf %d\n", arg);
                mpc = alloc_mpc();
                if (mpc == NULL)
                        return -ENOMEM;
                mpc->dev_num = arg;
-               mpc->dev = find_lec_by_itfnum(arg); /* NULL if there was no lec */
+               mpc->dev = find_lec_by_itfnum(arg);
+                                       /* NULL if there was no lec */
        }
        if (mpc->mpoad_vcc) {
-               printk("mpoa: mpoad_attach: mpoad is already present for itf %d\n", arg);
+               pr_info("mpoad is already present for itf %d\n", arg);
                return -EADDRINUSE;
        }
 
@@ -794,8 +844,8 @@ static int atm_mpoa_mpoad_attach (struct atm_vcc *vcc, int arg)
        mpc->mpoad_vcc = vcc;
        vcc->dev = &mpc_dev;
        vcc_insert_socket(sk_atm(vcc));
-       set_bit(ATM_VF_META,&vcc->flags);
-       set_bit(ATM_VF_READY,&vcc->flags);
+       set_bit(ATM_VF_META, &vcc->flags);
+       set_bit(ATM_VF_READY, &vcc->flags);
 
        if (mpc->dev) {
                char empty[ATM_ESA_LEN];
@@ -805,7 +855,7 @@ static int atm_mpoa_mpoad_attach (struct atm_vcc *vcc, int arg)
                /* set address if mpcd e.g. gets killed and restarted.
                 * If we do not do it now we have to wait for the next LE_ARP
                 */
-               if ( memcmp(mpc->mps_ctrl_addr, empty, ATM_ESA_LEN) != 0 )
+               if (memcmp(mpc->mps_ctrl_addr, empty, ATM_ESA_LEN) != 0)
                        send_set_mps_ctrl_addr(mpc->mps_ctrl_addr, mpc);
        }
 
@@ -817,7 +867,7 @@ static void send_set_mps_ctrl_addr(const char *addr, struct mpoa_client *mpc)
 {
        struct k_message mesg;
 
-       memcpy (mpc->mps_ctrl_addr, addr, ATM_ESA_LEN);
+       memcpy(mpc->mps_ctrl_addr, addr, ATM_ESA_LEN);
 
        mesg.type = SET_MPS_CTRL_ADDR;
        memcpy(mesg.MPS_ctrl, addr, ATM_ESA_LEN);
@@ -833,11 +883,11 @@ static void mpoad_close(struct atm_vcc *vcc)
 
        mpc = find_mpc_by_vcc(vcc);
        if (mpc == NULL) {
-               printk("mpoa: mpoad_close: did not find MPC\n");
+               pr_info("did not find MPC\n");
                return;
        }
        if (!mpc->mpoad_vcc) {
-               printk("mpoa: mpoad_close: close for non-present mpoad\n");
+               pr_info("close for non-present mpoad\n");
                return;
        }
 
@@ -857,7 +907,7 @@ static void mpoad_close(struct atm_vcc *vcc)
                kfree_skb(skb);
        }
 
-       printk("mpoa: (%s) going down\n",
+       pr_info("(%s) going down\n",
                (mpc->dev) ? mpc->dev->name : "<unknown>");
        module_put(THIS_MODULE);
 
@@ -871,61 +921,61 @@ static int msg_from_mpoad(struct atm_vcc *vcc, struct sk_buff *skb)
 {
 
        struct mpoa_client *mpc = find_mpc_by_vcc(vcc);
-       struct k_message *mesg = (struct k_message*)skb->data;
+       struct k_message *mesg = (struct k_message *)skb->data;
        atomic_sub(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc);
 
        if (mpc == NULL) {
-               printk("mpoa: msg_from_mpoad: no mpc found\n");
+               pr_info("no mpc found\n");
                return 0;
        }
-       dprintk("mpoa: (%s) msg_from_mpoad:", (mpc->dev) ? mpc->dev->name : "<unknown>");
-       switch(mesg->type) {
+       dprintk("(%s)", mpc->dev ? mpc->dev->name : "<unknown>");
+       switch (mesg->type) {
        case MPOA_RES_REPLY_RCVD:
-               dprintk(" mpoa_res_reply_rcvd\n");
+               dprintk_cont("mpoa_res_reply_rcvd\n");
                MPOA_res_reply_rcvd(mesg, mpc);
                break;
        case MPOA_TRIGGER_RCVD:
-               dprintk(" mpoa_trigger_rcvd\n");
+               dprintk_cont("mpoa_trigger_rcvd\n");
                MPOA_trigger_rcvd(mesg, mpc);
                break;
        case INGRESS_PURGE_RCVD:
-               dprintk(" nhrp_purge_rcvd\n");
+               dprintk_cont("nhrp_purge_rcvd\n");
                ingress_purge_rcvd(mesg, mpc);
                break;
        case EGRESS_PURGE_RCVD:
-               dprintk(" egress_purge_reply_rcvd\n");
+               dprintk_cont("egress_purge_reply_rcvd\n");
                egress_purge_rcvd(mesg, mpc);
                break;
        case MPS_DEATH:
-               dprintk(" mps_death\n");
+               dprintk_cont("mps_death\n");
                mps_death(mesg, mpc);
                break;
        case CACHE_IMPOS_RCVD:
-               dprintk(" cache_impos_rcvd\n");
+               dprintk_cont("cache_impos_rcvd\n");
                MPOA_cache_impos_rcvd(mesg, mpc);
                break;
        case SET_MPC_CTRL_ADDR:
-               dprintk(" set_mpc_ctrl_addr\n");
+               dprintk_cont("set_mpc_ctrl_addr\n");
                set_mpc_ctrl_addr_rcvd(mesg, mpc);
                break;
        case SET_MPS_MAC_ADDR:
-               dprintk(" set_mps_mac_addr\n");
+               dprintk_cont("set_mps_mac_addr\n");
                set_mps_mac_addr_rcvd(mesg, mpc);
                break;
        case CLEAN_UP_AND_EXIT:
-               dprintk(" clean_up_and_exit\n");
+               dprintk_cont("clean_up_and_exit\n");
                clean_up(mesg, mpc, DIE);
                break;
        case RELOAD:
-               dprintk(" reload\n");
+               dprintk_cont("reload\n");
                clean_up(mesg, mpc, RELOAD);
                break;
        case SET_MPC_PARAMS:
-               dprintk(" set_mpc_params\n");
+               dprintk_cont("set_mpc_params\n");
                mpc->parameters = mesg->content.params;
                break;
        default:
-               dprintk(" unknown message %d\n", mesg->type);
+               dprintk_cont("unknown message %d\n", mesg->type);
                break;
        }
        kfree_skb(skb);
@@ -940,7 +990,7 @@ int msg_to_mpoad(struct k_message *mesg, struct mpoa_client *mpc)
        struct sock *sk;
 
        if (mpc == NULL || !mpc->mpoad_vcc) {
-               printk("mpoa: msg_to_mpoad: mesg %d to a non-existent mpoad\n", mesg->type);
+               pr_info("mesg %d to a non-existent mpoad\n", mesg->type);
                return -ENXIO;
        }
 
@@ -958,7 +1008,8 @@ int msg_to_mpoad(struct k_message *mesg, struct mpoa_client *mpc)
        return 0;
 }
 
-static int mpoa_event_listener(struct notifier_block *mpoa_notifier, unsigned long event, void *dev_ptr)
+static int mpoa_event_listener(struct notifier_block *mpoa_notifier,
+                              unsigned long event, void *dev_ptr)
 {
        struct net_device *dev;
        struct mpoa_client *mpc;
@@ -980,25 +1031,24 @@ static int mpoa_event_listener(struct notifier_block *mpoa_notifier, unsigned lo
                priv->lane2_ops->associate_indicator = lane2_assoc_ind;
                mpc = find_mpc_by_itfnum(priv->itfnum);
                if (mpc == NULL) {
-                       dprintk("mpoa: mpoa_event_listener: allocating new mpc for %s\n",
-                              dev->name);
+                       dprintk("allocating new mpc for %s\n", dev->name);
                        mpc = alloc_mpc();
                        if (mpc == NULL) {
-                               printk("mpoa: mpoa_event_listener: no new mpc");
+                               pr_info("no new mpc");
                                break;
                        }
                }
                mpc->dev_num = priv->itfnum;
                mpc->dev = dev;
                dev_hold(dev);
-               dprintk("mpoa: (%s) was initialized\n", dev->name);
+               dprintk("(%s) was initialized\n", dev->name);
                break;
        case NETDEV_UNREGISTER:
                /* the lec device was deallocated */
                mpc = find_mpc_by_lec(dev);
                if (mpc == NULL)
                        break;
-               dprintk("mpoa: device (%s) was deallocated\n", dev->name);
+               dprintk("device (%s) was deallocated\n", dev->name);
                stop_mpc(mpc);
                dev_put(mpc->dev);
                mpc->dev = NULL;
@@ -1008,9 +1058,8 @@ static int mpoa_event_listener(struct notifier_block *mpoa_notifier, unsigned lo
                mpc = find_mpc_by_lec(dev);
                if (mpc == NULL)
                        break;
-               if (mpc->mpoad_vcc != NULL) {
+               if (mpc->mpoad_vcc != NULL)
                        start_mpc(mpc, dev);
-               }
                break;
        case NETDEV_DOWN:
                /* the dev was ifconfig'ed down */
@@ -1020,9 +1069,8 @@ static int mpoa_event_listener(struct notifier_block *mpoa_notifier, unsigned lo
                mpc = find_mpc_by_lec(dev);
                if (mpc == NULL)
                        break;
-               if (mpc->mpoad_vcc != NULL) {
+               if (mpc->mpoad_vcc != NULL)
                        stop_mpc(mpc);
-               }
                break;
        case NETDEV_REBOOT:
        case NETDEV_CHANGE:
@@ -1049,7 +1097,7 @@ static void MPOA_trigger_rcvd(struct k_message *msg, struct mpoa_client *mpc)
        in_cache_entry *entry;
 
        entry = mpc->in_ops->get(dst_ip, mpc);
-       if(entry == NULL){
+       if (entry == NULL) {
                entry = mpc->in_ops->add_entry(dst_ip, mpc);
                entry->entry_state = INGRESS_RESOLVING;
                msg->type = SND_MPOA_RES_RQST;
@@ -1060,7 +1108,7 @@ static void MPOA_trigger_rcvd(struct k_message *msg, struct mpoa_client *mpc)
                return;
        }
 
-       if(entry->entry_state == INGRESS_INVALID){
+       if (entry->entry_state == INGRESS_INVALID) {
                entry->entry_state = INGRESS_RESOLVING;
                msg->type = SND_MPOA_RES_RQST;
                msg->content.in_info = entry->ctrl_info;
@@ -1070,7 +1118,7 @@ static void MPOA_trigger_rcvd(struct k_message *msg, struct mpoa_client *mpc)
                return;
        }
 
-       printk("mpoa: (%s) MPOA_trigger_rcvd: entry already in resolving state\n",
+       pr_info("(%s) entry already in resolving state\n",
                (mpc->dev) ? mpc->dev->name : "<unknown>");
        mpc->in_ops->put(entry);
        return;
@@ -1080,23 +1128,25 @@ static void MPOA_trigger_rcvd(struct k_message *msg, struct mpoa_client *mpc)
  * Things get complicated because we have to check if there's an egress
  * shortcut with suitable traffic parameters we could use.
  */
-static void check_qos_and_open_shortcut(struct k_message *msg, struct mpoa_client *client, in_cache_entry *entry)
+static void check_qos_and_open_shortcut(struct k_message *msg,
+                                       struct mpoa_client *client,
+                                       in_cache_entry *entry)
 {
        __be32 dst_ip = msg->content.in_info.in_dst_ip;
        struct atm_mpoa_qos *qos = atm_mpoa_search_qos(dst_ip);
        eg_cache_entry *eg_entry = client->eg_ops->get_by_src_ip(dst_ip, client);
 
-       if(eg_entry && eg_entry->shortcut){
-               if(eg_entry->shortcut->qos.txtp.traffic_class &
-                  msg->qos.txtp.traffic_class &
-                  (qos ? qos->qos.txtp.traffic_class : ATM_UBR | ATM_CBR)){
-                           if(eg_entry->shortcut->qos.txtp.traffic_class == ATM_UBR)
-                                   entry->shortcut = eg_entry->shortcut;
-                           else if(eg_entry->shortcut->qos.txtp.max_pcr > 0)
-                                   entry->shortcut = eg_entry->shortcut;
+       if (eg_entry && eg_entry->shortcut) {
+               if (eg_entry->shortcut->qos.txtp.traffic_class &
+                   msg->qos.txtp.traffic_class &
+                   (qos ? qos->qos.txtp.traffic_class : ATM_UBR | ATM_CBR)) {
+                       if (eg_entry->shortcut->qos.txtp.traffic_class == ATM_UBR)
+                               entry->shortcut = eg_entry->shortcut;
+                       else if (eg_entry->shortcut->qos.txtp.max_pcr > 0)
+                               entry->shortcut = eg_entry->shortcut;
                }
-               if(entry->shortcut){
-                       dprintk("mpoa: (%s) using egress SVC to reach %pI4\n",
+               if (entry->shortcut) {
+                       dprintk("(%s) using egress SVC to reach %pI4\n",
                                client->dev->name, &dst_ip);
                        client->eg_ops->put(eg_entry);
                        return;
@@ -1107,12 +1157,13 @@ static void check_qos_and_open_shortcut(struct k_message *msg, struct mpoa_clien
 
        /* No luck in the egress cache we must open an ingress SVC */
        msg->type = OPEN_INGRESS_SVC;
-       if (qos && (qos->qos.txtp.traffic_class == msg->qos.txtp.traffic_class))
-       {
+       if (qos &&
+           (qos->qos.txtp.traffic_class == msg->qos.txtp.traffic_class)) {
                msg->qos = qos->qos;
-               printk("mpoa: (%s) trying to get a CBR shortcut\n",client->dev->name);
-       }
-       else memset(&msg->qos,0,sizeof(struct atm_qos));
+               pr_info("(%s) trying to get a CBR shortcut\n",
+                       client->dev->name);
+       } else
+               memset(&msg->qos, 0, sizeof(struct atm_qos));
        msg_to_mpoad(msg, client);
        return;
 }
@@ -1122,17 +1173,19 @@ static void MPOA_res_reply_rcvd(struct k_message *msg, struct mpoa_client *mpc)
        __be32 dst_ip = msg->content.in_info.in_dst_ip;
        in_cache_entry *entry = mpc->in_ops->get(dst_ip, mpc);
 
-       dprintk("mpoa: (%s) MPOA_res_reply_rcvd: ip %pI4\n",
+       dprintk("(%s) ip %pI4\n",
                mpc->dev->name, &dst_ip);
-       ddprintk("mpoa: (%s) MPOA_res_reply_rcvd() entry = %p", mpc->dev->name, entry);
-       if(entry == NULL){
-               printk("\nmpoa: (%s) ARGH, received res. reply for an entry that doesn't exist.\n", mpc->dev->name);
+       ddprintk("(%s) entry = %p",
+                mpc->dev->name, entry);
+       if (entry == NULL) {
+               pr_info("(%s) ARGH, received res. reply for an entry that doesn't exist.\n",
+                       mpc->dev->name);
                return;
        }
-       ddprintk(" entry_state = %d ", entry->entry_state);
+       ddprintk_cont(" entry_state = %d ", entry->entry_state);
 
        if (entry->entry_state == INGRESS_RESOLVED) {
-               printk("\nmpoa: (%s) MPOA_res_reply_rcvd for RESOLVED entry!\n", mpc->dev->name);
+               pr_info("(%s) RESOLVED entry!\n", mpc->dev->name);
                mpc->in_ops->put(entry);
                return;
        }
@@ -1141,17 +1194,18 @@ static void MPOA_res_reply_rcvd(struct k_message *msg, struct mpoa_client *mpc)
        do_gettimeofday(&(entry->tv));
        do_gettimeofday(&(entry->reply_wait)); /* Used in refreshing func from now on */
        entry->refresh_time = 0;
-       ddprintk("entry->shortcut = %p\n", entry->shortcut);
+       ddprintk_cont("entry->shortcut = %p\n", entry->shortcut);
 
-       if(entry->entry_state == INGRESS_RESOLVING && entry->shortcut != NULL){
+       if (entry->entry_state == INGRESS_RESOLVING &&
+           entry->shortcut != NULL) {
                entry->entry_state = INGRESS_RESOLVED;
                mpc->in_ops->put(entry);
                return; /* Shortcut already open... */
        }
 
        if (entry->shortcut != NULL) {
-               printk("mpoa: (%s) MPOA_res_reply_rcvd: entry->shortcut != NULL, impossible!\n",
-                      mpc->dev->name);
+               pr_info("(%s) entry->shortcut != NULL, impossible!\n",
+                       mpc->dev->name);
                mpc->in_ops->put(entry);
                return;
        }
@@ -1170,14 +1224,14 @@ static void ingress_purge_rcvd(struct k_message *msg, struct mpoa_client *mpc)
        __be32 mask = msg->ip_mask;
        in_cache_entry *entry = mpc->in_ops->get_with_mask(dst_ip, mpc, mask);
 
-       if(entry == NULL){
-               printk("mpoa: (%s) ingress_purge_rcvd: purge for a non-existing entry, ip = %pI4\n",
-                      mpc->dev->name, &dst_ip);
+       if (entry == NULL) {
+               pr_info("(%s) purge for a non-existing entry, ip = %pI4\n",
+                       mpc->dev->name, &dst_ip);
                return;
        }
 
        do {
-               dprintk("mpoa: (%s) ingress_purge_rcvd: removing an ingress entry, ip = %pI4\n",
+               dprintk("(%s) removing an ingress entry, ip = %pI4\n",
                        mpc->dev->name, &dst_ip);
                write_lock_bh(&mpc->ingress_lock);
                mpc->in_ops->remove_entry(entry, mpc);
@@ -1195,7 +1249,8 @@ static void egress_purge_rcvd(struct k_message *msg, struct mpoa_client *mpc)
        eg_cache_entry *entry = mpc->eg_ops->get_by_cache_id(cache_id, mpc);
 
        if (entry == NULL) {
-               dprintk("mpoa: (%s) egress_purge_rcvd: purge for a non-existing entry\n", mpc->dev->name);
+               dprintk("(%s) purge for a non-existing entry\n",
+                       mpc->dev->name);
                return;
        }
 
@@ -1214,15 +1269,15 @@ static void purge_egress_shortcut(struct atm_vcc *vcc, eg_cache_entry *entry)
        struct k_message *purge_msg;
        struct sk_buff *skb;
 
-       dprintk("mpoa: purge_egress_shortcut: entering\n");
+       dprintk("entering\n");
        if (vcc == NULL) {
-               printk("mpoa: purge_egress_shortcut: vcc == NULL\n");
+               pr_info("vcc == NULL\n");
                return;
        }
 
        skb = alloc_skb(sizeof(struct k_message), GFP_ATOMIC);
        if (skb == NULL) {
-                printk("mpoa: purge_egress_shortcut: out of memory\n");
+               pr_info("out of memory\n");
                return;
        }
 
@@ -1238,7 +1293,7 @@ static void purge_egress_shortcut(struct atm_vcc *vcc, eg_cache_entry *entry)
        sk = sk_atm(vcc);
        skb_queue_tail(&sk->sk_receive_queue, skb);
        sk->sk_data_ready(sk, skb->len);
-       dprintk("mpoa: purge_egress_shortcut: exiting:\n");
+       dprintk("exiting\n");
 
        return;
 }
@@ -1247,14 +1302,14 @@ static void purge_egress_shortcut(struct atm_vcc *vcc, eg_cache_entry *entry)
  * Our MPS died. Tell our daemon to send NHRP data plane purge to each
  * of the egress shortcuts we have.
  */
-static void mps_death( struct k_message * msg, struct mpoa_client * mpc )
+static void mps_death(struct k_message *msg, struct mpoa_client *mpc)
 {
        eg_cache_entry *entry;
 
-       dprintk("mpoa: (%s) mps_death:\n", mpc->dev->name);
+       dprintk("(%s)\n", mpc->dev->name);
 
-       if(memcmp(msg->MPS_ctrl, mpc->mps_ctrl_addr, ATM_ESA_LEN)){
-               printk("mpoa: (%s) mps_death: wrong MPS\n", mpc->dev->name);
+       if (memcmp(msg->MPS_ctrl, mpc->mps_ctrl_addr, ATM_ESA_LEN)) {
+               pr_info("(%s) wrong MPS\n", mpc->dev->name);
                return;
        }
 
@@ -1273,20 +1328,21 @@ static void mps_death( struct k_message * msg, struct mpoa_client * mpc )
        return;
 }
 
-static void MPOA_cache_impos_rcvd( struct k_message * msg, struct mpoa_client * mpc)
+static void MPOA_cache_impos_rcvd(struct k_message *msg,
+                                 struct mpoa_client *mpc)
 {
        uint16_t holding_time;
        eg_cache_entry *entry = mpc->eg_ops->get_by_cache_id(msg->content.eg_info.cache_id, mpc);
 
        holding_time = msg->content.eg_info.holding_time;
-       dprintk("mpoa: (%s) MPOA_cache_impos_rcvd: entry = %p, holding_time = %u\n",
-              mpc->dev->name, entry, holding_time);
-       if(entry == NULL && holding_time) {
+       dprintk("(%s) entry = %p, holding_time = %u\n",
+               mpc->dev->name, entry, holding_time);
+       if (entry == NULL && holding_time) {
                entry = mpc->eg_ops->add_entry(msg, mpc);
                mpc->eg_ops->put(entry);
                return;
        }
-       if(holding_time){
+       if (holding_time) {
                mpc->eg_ops->update(entry, holding_time);
                return;
        }
@@ -1300,7 +1356,8 @@ static void MPOA_cache_impos_rcvd( struct k_message * msg, struct mpoa_client *
        return;
 }
 
-static void set_mpc_ctrl_addr_rcvd(struct k_message *mesg, struct mpoa_client *mpc)
+static void set_mpc_ctrl_addr_rcvd(struct k_message *mesg,
+                                  struct mpoa_client *mpc)
 {
        struct lec_priv *priv;
        int i, retval ;
@@ -1315,34 +1372,39 @@ static void set_mpc_ctrl_addr_rcvd(struct k_message *mesg, struct mpoa_client *m
        memcpy(&tlv[7], mesg->MPS_ctrl, ATM_ESA_LEN); /* MPC ctrl ATM addr */
        memcpy(mpc->our_ctrl_addr, mesg->MPS_ctrl, ATM_ESA_LEN);
 
-       dprintk("mpoa: (%s) setting MPC ctrl ATM address to ",
-              (mpc->dev) ? mpc->dev->name : "<unknown>");
+       dprintk("(%s) setting MPC ctrl ATM address to",
+               mpc->dev ? mpc->dev->name : "<unknown>");
        for (i = 7; i < sizeof(tlv); i++)
-               dprintk("%02x ", tlv[i]);
-       dprintk("\n");
+               dprintk_cont(" %02x", tlv[i]);
+       dprintk_cont("\n");
 
        if (mpc->dev) {
                priv = netdev_priv(mpc->dev);
-               retval = priv->lane2_ops->associate_req(mpc->dev, mpc->dev->dev_addr, tlv, sizeof(tlv));
+               retval = priv->lane2_ops->associate_req(mpc->dev,
+                                                       mpc->dev->dev_addr,
+                                                       tlv, sizeof(tlv));
                if (retval == 0)
-                       printk("mpoa: (%s) MPOA device type TLV association failed\n", mpc->dev->name);
+                       pr_info("(%s) MPOA device type TLV association failed\n",
+                               mpc->dev->name);
                retval = priv->lane2_ops->resolve(mpc->dev, NULL, 1, NULL, NULL);
                if (retval < 0)
-                       printk("mpoa: (%s) targetless LE_ARP request failed\n", mpc->dev->name);
+                       pr_info("(%s) targetless LE_ARP request failed\n",
+                               mpc->dev->name);
        }
 
        return;
 }
 
-static void set_mps_mac_addr_rcvd(struct k_message *msg, struct mpoa_client *client)
+static void set_mps_mac_addr_rcvd(struct k_message *msg,
+                                 struct mpoa_client *client)
 {
 
-       if(client->number_of_mps_macs)
+       if (client->number_of_mps_macs)
                kfree(client->mps_macs);
        client->number_of_mps_macs = 0;
        client->mps_macs = kmemdup(msg->MPS_ctrl, ETH_ALEN, GFP_KERNEL);
        if (client->mps_macs == NULL) {
-               printk("mpoa: set_mps_mac_addr_rcvd: out of memory\n");
+               pr_info("out of memory\n");
                return;
        }
        client->number_of_mps_macs = 1;
@@ -1363,11 +1425,11 @@ static void clean_up(struct k_message *msg, struct mpoa_client *mpc, int action)
        /* FIXME: This knows too much of the cache structure */
        read_lock_irq(&mpc->egress_lock);
        entry = mpc->eg_cache;
-       while (entry != NULL){
-                   msg->content.eg_info = entry->ctrl_info;
-                   dprintk("mpoa: cache_id %u\n", entry->ctrl_info.cache_id);
-                   msg_to_mpoad(msg, mpc);
-                   entry = entry->next;
+       while (entry != NULL) {
+               msg->content.eg_info = entry->ctrl_info;
+               dprintk("cache_id %u\n", entry->ctrl_info.cache_id);
+               msg_to_mpoad(msg, mpc);
+               entry = entry->next;
        }
        read_unlock_irq(&mpc->egress_lock);
 
@@ -1386,20 +1448,22 @@ static void mpc_timer_refresh(void)
        return;
 }
 
-static void mpc_cache_check( unsigned long checking_time  )
+static void mpc_cache_check(unsigned long checking_time)
 {
        struct mpoa_client *mpc = mpcs;
        static unsigned long previous_resolving_check_time;
        static unsigned long previous_refresh_time;
 
-       while( mpc != NULL ){
+       while (mpc != NULL) {
                mpc->in_ops->clear_count(mpc);
                mpc->eg_ops->clear_expired(mpc);
-               if(checking_time - previous_resolving_check_time > mpc->parameters.mpc_p4 * HZ ){
+               if (checking_time - previous_resolving_check_time >
+                   mpc->parameters.mpc_p4 * HZ) {
                        mpc->in_ops->check_resolving(mpc);
                        previous_resolving_check_time = checking_time;
                }
-               if(checking_time - previous_refresh_time > mpc->parameters.mpc_p5 * HZ ){
+               if (checking_time - previous_refresh_time >
+                   mpc->parameters.mpc_p5 * HZ) {
                        mpc->in_ops->refresh(mpc);
                        previous_refresh_time = checking_time;
                }
@@ -1410,7 +1474,8 @@ static void mpc_cache_check( unsigned long checking_time  )
        return;
 }
 
-static int atm_mpoa_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+static int atm_mpoa_ioctl(struct socket *sock, unsigned int cmd,
+                         unsigned long arg)
 {
        int err = 0;
        struct atm_vcc *vcc = ATM_SD(sock);
@@ -1422,21 +1487,20 @@ static int atm_mpoa_ioctl(struct socket *sock, unsigned int cmd, unsigned long a
                return -EPERM;
 
        switch (cmd) {
-               case ATMMPC_CTRL:
-                       err = atm_mpoa_mpoad_attach(vcc, (int)arg);
-                       if (err >= 0)
-                               sock->state = SS_CONNECTED;
-                       break;
-               case ATMMPC_DATA:
-                       err = atm_mpoa_vcc_attach(vcc, (void __user *)arg);
-                       break;
-               default:
-                       break;
+       case ATMMPC_CTRL:
+               err = atm_mpoa_mpoad_attach(vcc, (int)arg);
+               if (err >= 0)
+                       sock->state = SS_CONNECTED;
+               break;
+       case ATMMPC_DATA:
+               err = atm_mpoa_vcc_attach(vcc, (void __user *)arg);
+               break;
+       default:
+               break;
        }
        return err;
 }
 
-
 static struct atm_ioctl atm_ioctl_ops = {
        .owner  = THIS_MODULE,
        .ioctl  = atm_mpoa_ioctl,
@@ -1447,9 +1511,9 @@ static __init int atm_mpoa_init(void)
        register_atm_ioctl(&atm_ioctl_ops);
 
        if (mpc_proc_init() != 0)
-               printk(KERN_INFO "mpoa: failed to initialize /proc/mpoa\n");
+               pr_info("failed to initialize /proc/mpoa\n");
 
-       printk("mpc.c: " __DATE__ " " __TIME__ " initialized\n");
+       pr_info("mpc.c: " __DATE__ " " __TIME__ " initialized\n");
 
        return 0;
 }
@@ -1476,15 +1540,15 @@ static void __exit atm_mpoa_cleanup(void)
                        if (priv->lane2_ops != NULL)
                                priv->lane2_ops->associate_indicator = NULL;
                }
-               ddprintk("mpoa: cleanup_module: about to clear caches\n");
+               ddprintk("about to clear caches\n");
                mpc->in_ops->destroy_cache(mpc);
                mpc->eg_ops->destroy_cache(mpc);
-               ddprintk("mpoa: cleanup_module: caches cleared\n");
+               ddprintk("caches cleared\n");
                kfree(mpc->mps_macs);
                memset(mpc, 0, sizeof(struct mpoa_client));
-               ddprintk("mpoa: cleanup_module: about to kfree %p\n", mpc);
+               ddprintk("about to kfree %p\n", mpc);
                kfree(mpc);
-               ddprintk("mpoa: cleanup_module: next mpc is at %p\n", tmp);
+               ddprintk("next mpc is at %p\n", tmp);
                mpc = tmp;
        }
 
@@ -1492,7 +1556,7 @@ static void __exit atm_mpoa_cleanup(void)
        qos_head = NULL;
        while (qos != NULL) {
                nextqos = qos->next;
-               dprintk("mpoa: cleanup_module: freeing qos entry %p\n", qos);
+               dprintk("freeing qos entry %p\n", qos);
                kfree(qos);
                qos = nextqos;
        }
index 4504a4b339bb8fb66e4c2e743815462157984c95..4c141810eb6dc210935f9c12cba875e0912f318d 100644 (file)
  */
 
 #if 0
-#define dprintk printk    /* debug */
+#define dprintk(format, args...)                                       \
+       printk(KERN_DEBUG "mpoa:%s: " format, __FILE__, ##args)  /* debug */
 #else
-#define dprintk(format,args...)
+#define dprintk(format, args...)                                       \
+       do { if (0)                                                     \
+               printk(KERN_DEBUG "mpoa:%s: " format, __FILE__, ##args);\
+       } while (0)
 #endif
 
 #if 0
-#define ddprintk printk  /* more debug */
+#define ddprintk(format, args...)                                      \
+       printk(KERN_DEBUG "mpoa:%s: " format, __FILE__, ##args)  /* debug */
 #else
-#define ddprintk(format,args...)
+#define ddprintk(format, args...)                                      \
+       do { if (0)                                                     \
+               printk(KERN_DEBUG "mpoa:%s: " format, __FILE__, ##args);\
+       } while (0)
 #endif
 
 static in_cache_entry *in_cache_get(__be32 dst_ip,
@@ -29,8 +37,8 @@ static in_cache_entry *in_cache_get(__be32 dst_ip,
 
        read_lock_bh(&client->ingress_lock);
        entry = client->in_cache;
-       while(entry != NULL){
-               if( entry->ctrl_info.in_dst_ip == dst_ip ){
+       while (entry != NULL) {
+               if (entry->ctrl_info.in_dst_ip == dst_ip) {
                        atomic_inc(&entry->use);
                        read_unlock_bh(&client->ingress_lock);
                        return entry;
@@ -50,8 +58,8 @@ static in_cache_entry *in_cache_get_with_mask(__be32 dst_ip,
 
        read_lock_bh(&client->ingress_lock);
        entry = client->in_cache;
-       while(entry != NULL){
-               if((entry->ctrl_info.in_dst_ip & mask)  == (dst_ip & mask )){
+       while (entry != NULL) {
+               if ((entry->ctrl_info.in_dst_ip & mask) == (dst_ip & mask)) {
                        atomic_inc(&entry->use);
                        read_unlock_bh(&client->ingress_lock);
                        return entry;
@@ -65,14 +73,14 @@ static in_cache_entry *in_cache_get_with_mask(__be32 dst_ip,
 }
 
 static in_cache_entry *in_cache_get_by_vcc(struct atm_vcc *vcc,
-                                          struct mpoa_client *client )
+                                          struct mpoa_client *client)
 {
        in_cache_entry *entry;
 
        read_lock_bh(&client->ingress_lock);
        entry = client->in_cache;
-       while(entry != NULL){
-               if(entry->shortcut == vcc) {
+       while (entry != NULL) {
+               if (entry->shortcut == vcc) {
                        atomic_inc(&entry->use);
                        read_unlock_bh(&client->ingress_lock);
                        return entry;
@@ -90,14 +98,14 @@ static in_cache_entry *in_cache_add_entry(__be32 dst_ip,
        in_cache_entry *entry = kzalloc(sizeof(in_cache_entry), GFP_KERNEL);
 
        if (entry == NULL) {
-               printk("mpoa: mpoa_caches.c: new_in_cache_entry: out of memory\n");
+               pr_info("mpoa: mpoa_caches.c: new_in_cache_entry: out of memory\n");
                return NULL;
        }
 
-       dprintk("mpoa: mpoa_caches.c: adding an ingress entry, ip = %pI4\n", &dst_ip);
+       dprintk("adding an ingress entry, ip = %pI4\n", &dst_ip);
 
        atomic_set(&entry->use, 1);
-       dprintk("mpoa: mpoa_caches.c: new_in_cache_entry: about to lock\n");
+       dprintk("new_in_cache_entry: about to lock\n");
        write_lock_bh(&client->ingress_lock);
        entry->next = client->in_cache;
        entry->prev = NULL;
@@ -115,7 +123,7 @@ static in_cache_entry *in_cache_add_entry(__be32 dst_ip,
        atomic_inc(&entry->use);
 
        write_unlock_bh(&client->ingress_lock);
-       dprintk("mpoa: mpoa_caches.c: new_in_cache_entry: unlocked\n");
+       dprintk("new_in_cache_entry: unlocked\n");
 
        return entry;
 }
@@ -126,39 +134,41 @@ static int cache_hit(in_cache_entry *entry, struct mpoa_client *mpc)
        struct k_message msg;
 
        entry->count++;
-       if(entry->entry_state == INGRESS_RESOLVED && entry->shortcut != NULL)
+       if (entry->entry_state == INGRESS_RESOLVED && entry->shortcut != NULL)
                return OPEN;
 
-       if(entry->entry_state == INGRESS_REFRESHING){
-               if(entry->count > mpc->parameters.mpc_p1){
+       if (entry->entry_state == INGRESS_REFRESHING) {
+               if (entry->count > mpc->parameters.mpc_p1) {
                        msg.type = SND_MPOA_RES_RQST;
                        msg.content.in_info = entry->ctrl_info;
                        memcpy(msg.MPS_ctrl, mpc->mps_ctrl_addr, ATM_ESA_LEN);
                        qos = atm_mpoa_search_qos(entry->ctrl_info.in_dst_ip);
-                       if (qos != NULL) msg.qos = qos->qos;
+                       if (qos != NULL)
+                               msg.qos = qos->qos;
                        msg_to_mpoad(&msg, mpc);
                        do_gettimeofday(&(entry->reply_wait));
                        entry->entry_state = INGRESS_RESOLVING;
                }
-               if(entry->shortcut != NULL)
+               if (entry->shortcut != NULL)
                        return OPEN;
                return CLOSED;
        }
 
-       if(entry->entry_state == INGRESS_RESOLVING && entry->shortcut != NULL)
+       if (entry->entry_state == INGRESS_RESOLVING && entry->shortcut != NULL)
                return OPEN;
 
-       ifentry->count > mpc->parameters.mpc_p1 &&
-           entry->entry_state == INGRESS_INVALID){
-               dprintk("mpoa: (%s) mpoa_caches.c: threshold exceeded for ip %pI4, sending MPOA res req\n",
+       if (entry->count > mpc->parameters.mpc_p1 &&
+           entry->entry_state == INGRESS_INVALID) {
+               dprintk("(%s) threshold exceeded for ip %pI4, sending MPOA res req\n",
                        mpc->dev->name, &entry->ctrl_info.in_dst_ip);
                entry->entry_state = INGRESS_RESOLVING;
-               msg.type =  SND_MPOA_RES_RQST;
-               memcpy(msg.MPS_ctrl, mpc->mps_ctrl_addr, ATM_ESA_LEN );
+               msg.type = SND_MPOA_RES_RQST;
+               memcpy(msg.MPS_ctrl, mpc->mps_ctrl_addr, ATM_ESA_LEN);
                msg.content.in_info = entry->ctrl_info;
                qos = atm_mpoa_search_qos(entry->ctrl_info.in_dst_ip);
-               if (qos != NULL) msg.qos = qos->qos;
-               msg_to_mpoad( &msg, mpc);
+               if (qos != NULL)
+                       msg.qos = qos->qos;
+               msg_to_mpoad(&msg, mpc);
                do_gettimeofday(&(entry->reply_wait));
        }
 
@@ -185,7 +195,7 @@ static void in_cache_remove_entry(in_cache_entry *entry,
        struct k_message msg;
 
        vcc = entry->shortcut;
-       dprintk("mpoa: mpoa_caches.c: removing an ingress entry, ip = %pI4\n",
+       dprintk("removing an ingress entry, ip = %pI4\n",
                &entry->ctrl_info.in_dst_ip);
 
        if (entry->prev != NULL)
@@ -195,14 +205,15 @@ static void in_cache_remove_entry(in_cache_entry *entry,
        if (entry->next != NULL)
                entry->next->prev = entry->prev;
        client->in_ops->put(entry);
-       if(client->in_cache == NULL && client->eg_cache == NULL){
+       if (client->in_cache == NULL && client->eg_cache == NULL) {
                msg.type = STOP_KEEP_ALIVE_SM;
-               msg_to_mpoad(&msg,client);
+               msg_to_mpoad(&msg, client);
        }
 
        /* Check if the egress side still uses this VCC */
        if (vcc != NULL) {
-               eg_cache_entry *eg_entry = client->eg_ops->get_by_vcc(vcc, client);
+               eg_cache_entry *eg_entry = client->eg_ops->get_by_vcc(vcc,
+                                                                     client);
                if (eg_entry != NULL) {
                        client->eg_ops->put(eg_entry);
                        return;
@@ -213,7 +224,6 @@ static void in_cache_remove_entry(in_cache_entry *entry,
        return;
 }
 
-
 /* Call this every MPC-p2 seconds... Not exactly correct solution,
    but an easy one... */
 static void clear_count_and_expired(struct mpoa_client *client)
@@ -225,12 +235,12 @@ static void clear_count_and_expired(struct mpoa_client *client)
 
        write_lock_bh(&client->ingress_lock);
        entry = client->in_cache;
-       while(entry != NULL){
-               entry->count=0;
+       while (entry != NULL) {
+               entry->count = 0;
                next_entry = entry->next;
-               if((now.tv_sec - entry->tv.tv_sec)
-                  > entry->ctrl_info.holding_time){
-                       dprintk("mpoa: mpoa_caches.c: holding time expired, ip = %pI4\n",
+               if ((now.tv_sec - entry->tv.tv_sec)
+                  > entry->ctrl_info.holding_time) {
+                       dprintk("holding time expired, ip = %pI4\n",
                                &entry->ctrl_info.in_dst_ip);
                        client->in_ops->remove_entry(entry, client);
                }
@@ -250,33 +260,38 @@ static void check_resolving_entries(struct mpoa_client *client)
        struct timeval now;
        struct k_message msg;
 
-       do_gettimeofday( &now );
+       do_gettimeofday(&now);
 
        read_lock_bh(&client->ingress_lock);
        entry = client->in_cache;
-       while( entry != NULL ){
-               if(entry->entry_state == INGRESS_RESOLVING){
-                       if(now.tv_sec - entry->hold_down.tv_sec < client->parameters.mpc_p6){
-                               entry = entry->next;                      /* Entry in hold down */
+       while (entry != NULL) {
+               if (entry->entry_state == INGRESS_RESOLVING) {
+                       if ((now.tv_sec - entry->hold_down.tv_sec) <
+                           client->parameters.mpc_p6) {
+                               entry = entry->next;    /* Entry in hold down */
                                continue;
                        }
-                       if( (now.tv_sec - entry->reply_wait.tv_sec) >
-                           entry->retry_time ){
-                               entry->retry_time = MPC_C1*( entry->retry_time );
-                               if(entry->retry_time > client->parameters.mpc_p5){
-                                       /* Retry time maximum exceeded, put entry in hold down. */
+                       if ((now.tv_sec - entry->reply_wait.tv_sec) >
+                           entry->retry_time) {
+                               entry->retry_time = MPC_C1 * (entry->retry_time);
+                               /*
+                                * Retry time maximum exceeded,
+                                * put entry in hold down.
+                                */
+                               if (entry->retry_time > client->parameters.mpc_p5) {
                                        do_gettimeofday(&(entry->hold_down));
                                        entry->retry_time = client->parameters.mpc_p4;
                                        entry = entry->next;
                                        continue;
                                }
                                /* Ask daemon to send a resolution request. */
-                               memset(&(entry->hold_down),0,sizeof(struct timeval));
+                               memset(&(entry->hold_down), 0, sizeof(struct timeval));
                                msg.type = SND_MPOA_RES_RTRY;
                                memcpy(msg.MPS_ctrl, client->mps_ctrl_addr, ATM_ESA_LEN);
                                msg.content.in_info = entry->ctrl_info;
                                qos = atm_mpoa_search_qos(entry->ctrl_info.in_dst_ip);
-                               if (qos != NULL) msg.qos = qos->qos;
+                               if (qos != NULL)
+                                       msg.qos = qos->qos;
                                msg_to_mpoad(&msg, client);
                                do_gettimeofday(&(entry->reply_wait));
                        }
@@ -292,16 +307,17 @@ static void refresh_entries(struct mpoa_client *client)
        struct timeval now;
        struct in_cache_entry *entry = client->in_cache;
 
-       ddprintk("mpoa: mpoa_caches.c: refresh_entries\n");
+       ddprintk("refresh_entries\n");
        do_gettimeofday(&now);
 
        read_lock_bh(&client->ingress_lock);
-       while( entry != NULL ){
-               if( entry->entry_state == INGRESS_RESOLVED ){
-                       if(!(entry->refresh_time))
-                               entry->refresh_time = (2*(entry->ctrl_info.holding_time))/3;
-                       if( (now.tv_sec - entry->reply_wait.tv_sec) > entry->refresh_time ){
-                               dprintk("mpoa: mpoa_caches.c: refreshing an entry.\n");
+       while (entry != NULL) {
+               if (entry->entry_state == INGRESS_RESOLVED) {
+                       if (!(entry->refresh_time))
+                               entry->refresh_time = (2 * (entry->ctrl_info.holding_time))/3;
+                       if ((now.tv_sec - entry->reply_wait.tv_sec) >
+                           entry->refresh_time) {
+                               dprintk("refreshing an entry.\n");
                                entry->entry_state = INGRESS_REFRESHING;
 
                        }
@@ -314,21 +330,22 @@ static void refresh_entries(struct mpoa_client *client)
 static void in_destroy_cache(struct mpoa_client *mpc)
 {
        write_lock_irq(&mpc->ingress_lock);
-       while(mpc->in_cache != NULL)
+       while (mpc->in_cache != NULL)
                mpc->in_ops->remove_entry(mpc->in_cache, mpc);
        write_unlock_irq(&mpc->ingress_lock);
 
        return;
 }
 
-static eg_cache_entry *eg_cache_get_by_cache_id(__be32 cache_id, struct mpoa_client *mpc)
+static eg_cache_entry *eg_cache_get_by_cache_id(__be32 cache_id,
+                                               struct mpoa_client *mpc)
 {
        eg_cache_entry *entry;
 
        read_lock_irq(&mpc->egress_lock);
        entry = mpc->eg_cache;
-       while(entry != NULL){
-               if(entry->ctrl_info.cache_id == cache_id){
+       while (entry != NULL) {
+               if (entry->ctrl_info.cache_id == cache_id) {
                        atomic_inc(&entry->use);
                        read_unlock_irq(&mpc->egress_lock);
                        return entry;
@@ -348,7 +365,7 @@ static eg_cache_entry *eg_cache_get_by_tag(__be32 tag, struct mpoa_client *mpc)
 
        read_lock_irqsave(&mpc->egress_lock, flags);
        entry = mpc->eg_cache;
-       while (entry != NULL){
+       while (entry != NULL) {
                if (entry->ctrl_info.tag == tag) {
                        atomic_inc(&entry->use);
                        read_unlock_irqrestore(&mpc->egress_lock, flags);
@@ -362,14 +379,15 @@ static eg_cache_entry *eg_cache_get_by_tag(__be32 tag, struct mpoa_client *mpc)
 }
 
 /* This can be called from any context since it saves CPU flags */
-static eg_cache_entry *eg_cache_get_by_vcc(struct atm_vcc *vcc, struct mpoa_client *mpc)
+static eg_cache_entry *eg_cache_get_by_vcc(struct atm_vcc *vcc,
+                                          struct mpoa_client *mpc)
 {
        unsigned long flags;
        eg_cache_entry *entry;
 
        read_lock_irqsave(&mpc->egress_lock, flags);
        entry = mpc->eg_cache;
-       while (entry != NULL){
+       while (entry != NULL) {
                if (entry->shortcut == vcc) {
                        atomic_inc(&entry->use);
                        read_unlock_irqrestore(&mpc->egress_lock, flags);
@@ -382,14 +400,15 @@ static eg_cache_entry *eg_cache_get_by_vcc(struct atm_vcc *vcc, struct mpoa_clie
        return NULL;
 }
 
-static eg_cache_entry *eg_cache_get_by_src_ip(__be32 ipaddr, struct mpoa_client *mpc)
+static eg_cache_entry *eg_cache_get_by_src_ip(__be32 ipaddr,
+                                             struct mpoa_client *mpc)
 {
        eg_cache_entry *entry;
 
        read_lock_irq(&mpc->egress_lock);
        entry = mpc->eg_cache;
-       while(entry != NULL){
-               if(entry->latest_ip_addr == ipaddr) {
+       while (entry != NULL) {
+               if (entry->latest_ip_addr == ipaddr) {
                        atomic_inc(&entry->use);
                        read_unlock_irq(&mpc->egress_lock);
                        return entry;
@@ -421,7 +440,7 @@ static void eg_cache_remove_entry(eg_cache_entry *entry,
        struct k_message msg;
 
        vcc = entry->shortcut;
-       dprintk("mpoa: mpoa_caches.c: removing an egress entry.\n");
+       dprintk("removing an egress entry.\n");
        if (entry->prev != NULL)
                entry->prev->next = entry->next;
        else
@@ -429,9 +448,9 @@ static void eg_cache_remove_entry(eg_cache_entry *entry,
        if (entry->next != NULL)
                entry->next->prev = entry->prev;
        client->eg_ops->put(entry);
-       if(client->in_cache == NULL && client->eg_cache == NULL){
+       if (client->in_cache == NULL && client->eg_cache == NULL) {
                msg.type = STOP_KEEP_ALIVE_SM;
-               msg_to_mpoad(&msg,client);
+               msg_to_mpoad(&msg, client);
        }
 
        /* Check if the ingress side still uses this VCC */
@@ -447,20 +466,21 @@ static void eg_cache_remove_entry(eg_cache_entry *entry,
        return;
 }
 
-static eg_cache_entry *eg_cache_add_entry(struct k_message *msg, struct mpoa_client *client)
+static eg_cache_entry *eg_cache_add_entry(struct k_message *msg,
+                                         struct mpoa_client *client)
 {
        eg_cache_entry *entry = kzalloc(sizeof(eg_cache_entry), GFP_KERNEL);
 
        if (entry == NULL) {
-               printk("mpoa: mpoa_caches.c: new_eg_cache_entry: out of memory\n");
+               pr_info("out of memory\n");
                return NULL;
        }
 
-       dprintk("mpoa: mpoa_caches.c: adding an egress entry, ip = %pI4, this should be our IP\n",
+       dprintk("adding an egress entry, ip = %pI4, this should be our IP\n",
                &msg->content.eg_info.eg_dst_ip);
 
        atomic_set(&entry->use, 1);
-       dprintk("mpoa: mpoa_caches.c: new_eg_cache_entry: about to lock\n");
+       dprintk("new_eg_cache_entry: about to lock\n");
        write_lock_irq(&client->egress_lock);
        entry->next = client->eg_cache;
        entry->prev = NULL;
@@ -472,18 +492,18 @@ static eg_cache_entry *eg_cache_add_entry(struct k_message *msg, struct mpoa_cli
        entry->ctrl_info = msg->content.eg_info;
        do_gettimeofday(&(entry->tv));
        entry->entry_state = EGRESS_RESOLVED;
-       dprintk("mpoa: mpoa_caches.c: new_eg_cache_entry cache_id %lu\n", ntohl(entry->ctrl_info.cache_id));
-       dprintk("mpoa: mpoa_caches.c: mps_ip = %pI4\n",
-               &entry->ctrl_info.mps_ip);
+       dprintk("new_eg_cache_entry cache_id %u\n",
+               ntohl(entry->ctrl_info.cache_id));
+       dprintk("mps_ip = %pI4\n", &entry->ctrl_info.mps_ip);
        atomic_inc(&entry->use);
 
        write_unlock_irq(&client->egress_lock);
-       dprintk("mpoa: mpoa_caches.c: new_eg_cache_entry: unlocked\n");
+       dprintk("new_eg_cache_entry: unlocked\n");
 
        return entry;
 }
 
-static void update_eg_cache_entry(eg_cache_entry * entry, uint16_t holding_time)
+static void update_eg_cache_entry(eg_cache_entry *entry, uint16_t holding_time)
 {
        do_gettimeofday(&(entry->tv));
        entry->entry_state = EGRESS_RESOLVED;
@@ -502,13 +522,14 @@ static void clear_expired(struct mpoa_client *client)
 
        write_lock_irq(&client->egress_lock);
        entry = client->eg_cache;
-       while(entry != NULL){
+       while (entry != NULL) {
                next_entry = entry->next;
-               if((now.tv_sec - entry->tv.tv_sec)
-                  > entry->ctrl_info.holding_time){
+               if ((now.tv_sec - entry->tv.tv_sec)
+                  > entry->ctrl_info.holding_time) {
                        msg.type = SND_EGRESS_PURGE;
                        msg.content.eg_info = entry->ctrl_info;
-                       dprintk("mpoa: mpoa_caches.c: egress_cache: holding time expired, cache_id = %lu.\n",ntohl(entry->ctrl_info.cache_id));
+                       dprintk("egress_cache: holding time expired, cache_id = %u.\n",
+                               ntohl(entry->ctrl_info.cache_id));
                        msg_to_mpoad(&msg, client);
                        client->eg_ops->remove_entry(entry, client);
                }
@@ -522,7 +543,7 @@ static void clear_expired(struct mpoa_client *client)
 static void eg_destroy_cache(struct mpoa_client *mpc)
 {
        write_lock_irq(&mpc->egress_lock);
-       while(mpc->eg_cache != NULL)
+       while (mpc->eg_cache != NULL)
                mpc->eg_ops->remove_entry(mpc->eg_cache, mpc);
        write_unlock_irq(&mpc->egress_lock);
 
@@ -530,7 +551,6 @@ static void eg_destroy_cache(struct mpoa_client *mpc)
 }
 
 
-
 static struct in_cache_ops ingress_ops = {
        in_cache_add_entry,               /* add_entry       */
        in_cache_get,                     /* get             */
index 1a0f5ccea9c4494cad2c29755863f7dd0559e540..b9bdb98427e4475151685c016c395f92bfd66240 100644 (file)
@@ -1,3 +1,4 @@
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
 
 #ifdef CONFIG_PROC_FS
 #include <linux/errno.h>
@@ -8,7 +9,7 @@
 #include <linux/proc_fs.h>
 #include <linux/time.h>
 #include <linux/seq_file.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 #include <linux/atmmpc.h>
 #include <linux/atm.h>
 #include "mpc.h"
  */
 
 #if 1
-#define dprintk printk   /* debug */
+#define dprintk(format, args...)                                       \
+       printk(KERN_DEBUG "mpoa:%s: " format, __FILE__, ##args)  /* debug */
 #else
-#define dprintk(format,args...)
+#define dprintk(format, args...)                                       \
+       do { if (0)                                                     \
+               printk(KERN_DEBUG "mpoa:%s: " format, __FILE__, ##args);\
+       } while (0)
+#endif
+
+#if 0
+#define ddprintk(format, args...)                                      \
+       printk(KERN_DEBUG "mpoa:%s: " format, __FILE__, ##args)  /* debug */
+#else
+#define ddprintk(format, args...)                                      \
+       do { if (0)                                                     \
+               printk(KERN_DEBUG "mpoa:%s: " format, __FILE__, ##args);\
+       } while (0)
 #endif
 
 #define STAT_FILE_NAME "mpc"     /* Our statistic file's name */
@@ -51,42 +66,37 @@ static const struct file_operations mpc_file_operations = {
 /*
  * Returns the state of an ingress cache entry as a string
  */
-static const char *ingress_state_string(int state){
-       switch(state) {
+static const char *ingress_state_string(int state)
+{
+       switch (state) {
        case INGRESS_RESOLVING:
                return "resolving  ";
-               break;
        case INGRESS_RESOLVED:
                return "resolved   ";
-               break;
        case INGRESS_INVALID:
                return "invalid    ";
-               break;
        case INGRESS_REFRESHING:
                return "refreshing ";
-               break;
-       default:
-              return "";
        }
+
+       return "";
 }
 
 /*
  * Returns the state of an egress cache entry as a string
  */
-static const char *egress_state_string(int state){
-       switch(state) {
+static const char *egress_state_string(int state)
+{
+       switch (state) {
        case EGRESS_RESOLVED:
                return "resolved   ";
-               break;
        case EGRESS_PURGE:
                return "purge      ";
-               break;
        case EGRESS_INVALID:
                return "invalid    ";
-               break;
-       default:
-              return "";
        }
+
+       return "";
 }
 
 /*
@@ -123,7 +133,6 @@ static void mpc_stop(struct seq_file *m, void *v)
 static int mpc_show(struct seq_file *m, void *v)
 {
        struct mpoa_client *mpc = v;
-       unsigned char *temp;
        int i;
        in_cache_entry *in_entry;
        eg_cache_entry *eg_entry;
@@ -140,15 +149,17 @@ static int mpc_show(struct seq_file *m, void *v)
        do_gettimeofday(&now);
 
        for (in_entry = mpc->in_cache; in_entry; in_entry = in_entry->next) {
-               temp = (unsigned char *)&in_entry->ctrl_info.in_dst_ip;
-               sprintf(ip_string,"%d.%d.%d.%d", temp[0], temp[1], temp[2], temp[3]);
+               sprintf(ip_string, "%pI4", &in_entry->ctrl_info.in_dst_ip);
                seq_printf(m, "%-16s%s%-14lu%-12u",
-                             ip_string,
-                             ingress_state_string(in_entry->entry_state),
-                             in_entry->ctrl_info.holding_time-(now.tv_sec-in_entry->tv.tv_sec),
-                             in_entry->packets_fwded);
+                          ip_string,
+                          ingress_state_string(in_entry->entry_state),
+                          in_entry->ctrl_info.holding_time -
+                          (now.tv_sec-in_entry->tv.tv_sec),
+                          in_entry->packets_fwded);
                if (in_entry->shortcut)
-                       seq_printf(m, "   %-3d  %-3d",in_entry->shortcut->vpi,in_entry->shortcut->vci);
+                       seq_printf(m, "   %-3d  %-3d",
+                                  in_entry->shortcut->vpi,
+                                  in_entry->shortcut->vci);
                seq_printf(m, "\n");
        }
 
@@ -156,21 +167,23 @@ static int mpc_show(struct seq_file *m, void *v)
        seq_printf(m, "Egress Entries:\nIngress MPC ATM addr\nCache-id        State      Holding time  Packets recvd  Latest IP addr   VPI VCI\n");
        for (eg_entry = mpc->eg_cache; eg_entry; eg_entry = eg_entry->next) {
                unsigned char *p = eg_entry->ctrl_info.in_MPC_data_ATM_addr;
-               for(i = 0; i < ATM_ESA_LEN; i++)
+               for (i = 0; i < ATM_ESA_LEN; i++)
                        seq_printf(m, "%02x", p[i]);
                seq_printf(m, "\n%-16lu%s%-14lu%-15u",
                           (unsigned long)ntohl(eg_entry->ctrl_info.cache_id),
                           egress_state_string(eg_entry->entry_state),
-                          (eg_entry->ctrl_info.holding_time-(now.tv_sec-eg_entry->tv.tv_sec)),
+                          (eg_entry->ctrl_info.holding_time -
+                           (now.tv_sec-eg_entry->tv.tv_sec)),
                           eg_entry->packets_rcvd);
 
                /* latest IP address */
-               temp = (unsigned char *)&eg_entry->latest_ip_addr;
-               sprintf(ip_string, "%d.%d.%d.%d", temp[0], temp[1], temp[2], temp[3]);
+               sprintf(ip_string, "%pI4", &eg_entry->latest_ip_addr);
                seq_printf(m, "%-16s", ip_string);
 
                if (eg_entry->shortcut)
-                       seq_printf(m, " %-3d %-3d",eg_entry->shortcut->vpi,eg_entry->shortcut->vci);
+                       seq_printf(m, " %-3d %-3d",
+                                  eg_entry->shortcut->vpi,
+                                  eg_entry->shortcut->vci);
                seq_printf(m, "\n");
        }
        seq_printf(m, "\n");
@@ -258,12 +271,9 @@ static int parse_qos(const char *buff)
        qos.rxtp.max_pcr = rx_pcr;
        qos.rxtp.max_sdu = rx_sdu;
        qos.aal = ATM_AAL5;
-       dprintk("mpoa: mpoa_proc.c: parse_qos(): setting qos paramameters to tx=%d,%d rx=%d,%d\n",
-               qos.txtp.max_pcr,
-               qos.txtp.max_sdu,
-               qos.rxtp.max_pcr,
-               qos.rxtp.max_sdu
-               );
+       dprintk("parse_qos(): setting qos paramameters to tx=%d,%d rx=%d,%d\n",
+               qos.txtp.max_pcr, qos.txtp.max_sdu,
+               qos.rxtp.max_pcr, qos.rxtp.max_sdu);
 
        atm_mpoa_add_qos(ipaddr, &qos);
        return 1;
@@ -278,7 +288,7 @@ int mpc_proc_init(void)
 
        p = proc_create(STAT_FILE_NAME, 0, atm_proc_root, &mpc_file_operations);
        if (!p) {
-               printk(KERN_ERR "Unable to initialize /proc/atm/%s\n", STAT_FILE_NAME);
+               pr_err("Unable to initialize /proc/atm/%s\n", STAT_FILE_NAME);
                return -ENOMEM;
        }
        return 0;
@@ -289,10 +299,9 @@ int mpc_proc_init(void)
  */
 void mpc_proc_clean(void)
 {
-       remove_proc_entry(STAT_FILE_NAME,atm_proc_root);
+       remove_proc_entry(STAT_FILE_NAME, atm_proc_root);
 }
 
-
 #endif /* CONFIG_PROC_FS */
 
 
index 0af84cd4f65bdba5c70888e4aa6ce01cb54cd41b..400839273c67503e6fa4207c2d2949a5f99e351f 100644 (file)
@@ -33,6 +33,8 @@
  * These hooks are not yet available in ppp_generic
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
+
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/skbuff.h>
@@ -132,7 +134,7 @@ static void pppoatm_unassign_vcc(struct atm_vcc *atmvcc)
 static void pppoatm_push(struct atm_vcc *atmvcc, struct sk_buff *skb)
 {
        struct pppoatm_vcc *pvcc = atmvcc_to_pvcc(atmvcc);
-       pr_debug("pppoatm push\n");
+       pr_debug("\n");
        if (skb == NULL) {                      /* VCC was closed */
                pr_debug("removing ATMPPP VCC %p\n", pvcc);
                pppoatm_unassign_vcc(atmvcc);
@@ -165,17 +167,17 @@ static void pppoatm_push(struct atm_vcc *atmvcc, struct sk_buff *skb)
                        pvcc->chan.mtu += LLC_LEN;
                        break;
                }
-               pr_debug("Couldn't autodetect yet "
-                   "(skb: %02X %02X %02X %02X %02X %02X)\n",
-                   skb->data[0], skb->data[1], skb->data[2],
-                   skb->data[3], skb->data[4], skb->data[5]);
+               pr_debug("Couldn't autodetect yet (skb: %02X %02X %02X %02X %02X %02X)\n",
+                        skb->data[0], skb->data[1], skb->data[2],
+                        skb->data[3], skb->data[4], skb->data[5]);
                goto error;
        case e_vc:
                break;
        }
        ppp_input(&pvcc->chan, skb);
        return;
-    error:
+
+error:
        kfree_skb(skb);
        ppp_input_error(&pvcc->chan, 0);
 }
@@ -194,7 +196,7 @@ static int pppoatm_send(struct ppp_channel *chan, struct sk_buff *skb)
 {
        struct pppoatm_vcc *pvcc = chan_to_pvcc(chan);
        ATM_SKB(skb)->vcc = pvcc->atmvcc;
-       pr_debug("pppoatm_send (skb=0x%p, vcc=0x%p)\n", skb, pvcc->atmvcc);
+       pr_debug("(skb=0x%p, vcc=0x%p)\n", skb, pvcc->atmvcc);
        if (skb->data[0] == '\0' && (pvcc->flags & SC_COMP_PROT))
                (void) skb_pull(skb, 1);
        switch (pvcc->encaps) {         /* LLC encapsulation needed */
@@ -208,7 +210,8 @@ static int pppoatm_send(struct ppp_channel *chan, struct sk_buff *skb)
                                goto nospace;
                        }
                        kfree_skb(skb);
-                       if ((skb = n) == NULL)
+                       skb = n;
+                       if (skb == NULL)
                                return DROP_PACKET;
                } else if (!atm_may_send(pvcc->atmvcc, skb->truesize))
                        goto nospace;
@@ -226,11 +229,11 @@ static int pppoatm_send(struct ppp_channel *chan, struct sk_buff *skb)
 
        atomic_add(skb->truesize, &sk_atm(ATM_SKB(skb)->vcc)->sk_wmem_alloc);
        ATM_SKB(skb)->atm_options = ATM_SKB(skb)->vcc->atm_options;
-       pr_debug("atm_skb(%p)->vcc(%p)->dev(%p)\n", skb, ATM_SKB(skb)->vcc,
-           ATM_SKB(skb)->vcc->dev);
+       pr_debug("atm_skb(%p)->vcc(%p)->dev(%p)\n",
+                skb, ATM_SKB(skb)->vcc, ATM_SKB(skb)->vcc->dev);
        return ATM_SKB(skb)->vcc->send(ATM_SKB(skb)->vcc, skb)
            ? DROP_PACKET : 1;
-    nospace:
+nospace:
        /*
         * We don't have space to send this SKB now, but we might have
         * already applied SC_COMP_PROT compression, so may need to undo
@@ -289,7 +292,8 @@ static int pppoatm_assign_vcc(struct atm_vcc *atmvcc, void __user *arg)
            (be.encaps == e_vc ? 0 : LLC_LEN);
        pvcc->wakeup_tasklet = tasklet_proto;
        pvcc->wakeup_tasklet.data = (unsigned long) &pvcc->chan;
-       if ((err = ppp_register_channel(&pvcc->chan)) != 0) {
+       err = ppp_register_channel(&pvcc->chan);
+       if (err != 0) {
                kfree(pvcc);
                return err;
        }
index ab8419a324b61556de9f353b8d6d6569704803ab..476779d845ebd1a7b6f676473554c32a72439317 100644 (file)
 #include <linux/init.h> /* for __init */
 #include <net/net_namespace.h>
 #include <net/atmclip.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
+#include <linux/param.h> /* for HZ */
 #include <asm/atomic.h>
-#include <asm/param.h> /* for HZ */
 #include "resources.h"
 #include "common.h" /* atm_proc_init prototype */
 #include "signaling.h" /* to get sigd - ugly too */
 
-static ssize_t proc_dev_atm_read(struct file *file,char __user *buf,size_t count,
-    loff_t *pos);
+static ssize_t proc_dev_atm_read(struct file *file, char __user *buf,
+                                size_t count, loff_t *pos);
 
 static const struct file_operations proc_atm_dev_ops = {
        .owner =        THIS_MODULE,
@@ -43,9 +43,9 @@ static void add_stats(struct seq_file *seq, const char *aal,
   const struct k_atm_aal_stats *stats)
 {
        seq_printf(seq, "%s ( %d %d %d %d %d )", aal,
-           atomic_read(&stats->tx),atomic_read(&stats->tx_err),
-           atomic_read(&stats->rx),atomic_read(&stats->rx_err),
-           atomic_read(&stats->rx_drop));
+                  atomic_read(&stats->tx), atomic_read(&stats->tx_err),
+                  atomic_read(&stats->rx), atomic_read(&stats->rx_err),
+                  atomic_read(&stats->rx_drop));
 }
 
 static void atm_dev_info(struct seq_file *seq, const struct atm_dev *dev)
@@ -151,8 +151,8 @@ static void *vcc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 
 static void pvc_info(struct seq_file *seq, struct atm_vcc *vcc)
 {
-       static const char *const class_name[] =
-               {"off","UBR","CBR","VBR","ABR"};
+       static const char *const class_name[] = {
+               "off", "UBR", "CBR", "VBR", "ABR"};
        static const char *const aal_name[] = {
                "---",  "1",    "2",    "3/4",  /*  0- 3 */
                "???",  "5",    "???",  "???",  /*  4- 7 */
@@ -160,11 +160,12 @@ static void pvc_info(struct seq_file *seq, struct atm_vcc *vcc)
                "???",  "0",    "???",  "???"}; /* 12-15 */
 
        seq_printf(seq, "%3d %3d %5d %-3s %7d %-5s %7d %-6s",
-           vcc->dev->number,vcc->vpi,vcc->vci,
-           vcc->qos.aal >= ARRAY_SIZE(aal_name) ? "err" :
-           aal_name[vcc->qos.aal],vcc->qos.rxtp.min_pcr,
-           class_name[vcc->qos.rxtp.traffic_class],vcc->qos.txtp.min_pcr,
-           class_name[vcc->qos.txtp.traffic_class]);
+                  vcc->dev->number, vcc->vpi, vcc->vci,
+                  vcc->qos.aal >= ARRAY_SIZE(aal_name) ? "err" :
+                  aal_name[vcc->qos.aal], vcc->qos.rxtp.min_pcr,
+                  class_name[vcc->qos.rxtp.traffic_class],
+                  vcc->qos.txtp.min_pcr,
+                  class_name[vcc->qos.txtp.traffic_class]);
        if (test_bit(ATM_VF_IS_CLIP, &vcc->flags)) {
                struct clip_vcc *clip_vcc = CLIP_VCC(vcc);
                struct net_device *dev;
@@ -195,19 +196,20 @@ static void vcc_info(struct seq_file *seq, struct atm_vcc *vcc)
                seq_printf(seq, "%3d %3d %5d ", vcc->dev->number, vcc->vpi,
                        vcc->vci);
        switch (sk->sk_family) {
-               case AF_ATMPVC:
-                       seq_printf(seq, "PVC");
-                       break;
-               case AF_ATMSVC:
-                       seq_printf(seq, "SVC");
-                       break;
-               default:
-                       seq_printf(seq, "%3d", sk->sk_family);
+       case AF_ATMPVC:
+               seq_printf(seq, "PVC");
+               break;
+       case AF_ATMSVC:
+               seq_printf(seq, "SVC");
+               break;
+       default:
+               seq_printf(seq, "%3d", sk->sk_family);
        }
-       seq_printf(seq, " %04lx  %5d %7d/%7d %7d/%7d [%d]\n", vcc->flags, sk->sk_err,
-                 sk_wmem_alloc_get(sk), sk->sk_sndbuf,
-                 sk_rmem_alloc_get(sk), sk->sk_rcvbuf,
-                 atomic_read(&sk->sk_refcnt));
+       seq_printf(seq, " %04lx  %5d %7d/%7d %7d/%7d [%d]\n",
+                  vcc->flags, sk->sk_err,
+                  sk_wmem_alloc_get(sk), sk->sk_sndbuf,
+                  sk_rmem_alloc_get(sk), sk->sk_rcvbuf,
+                  atomic_read(&sk->sk_refcnt));
 }
 
 static void svc_info(struct seq_file *seq, struct atm_vcc *vcc)
@@ -376,32 +378,35 @@ static ssize_t proc_dev_atm_read(struct file *file, char __user *buf,
        unsigned long page;
        int length;
 
-       if (count == 0) return 0;
+       if (count == 0)
+               return 0;
        page = get_zeroed_page(GFP_KERNEL);
-       if (!page) return -ENOMEM;
+       if (!page)
+               return -ENOMEM;
        dev = PDE(file->f_path.dentry->d_inode)->data;
        if (!dev->ops->proc_read)
                length = -EINVAL;
        else {
-               length = dev->ops->proc_read(dev,pos,(char *) page);
-               if (length > count) length = -EINVAL;
+               length = dev->ops->proc_read(dev, pos, (char *)page);
+               if (length > count)
+                       length = -EINVAL;
        }
        if (length >= 0) {
-               if (copy_to_user(buf,(char *) page,length)) length = -EFAULT;
+               if (copy_to_user(buf, (char *)page, length))
+                       length = -EFAULT;
                (*pos)++;
        }
        free_page(page);
        return length;
 }
 
-
 struct proc_dir_entry *atm_proc_root;
 EXPORT_SYMBOL(atm_proc_root);
 
 
 int atm_proc_dev_register(struct atm_dev *dev)
 {
-       int digits,num;
+       int digits, num;
        int error;
 
        /* No proc info */
@@ -410,26 +415,28 @@ int atm_proc_dev_register(struct atm_dev *dev)
 
        error = -ENOMEM;
        digits = 0;
-       for (num = dev->number; num; num /= 10) digits++;
-       if (!digits) digits++;
+       for (num = dev->number; num; num /= 10)
+               digits++;
+       if (!digits)
+               digits++;
 
        dev->proc_name = kmalloc(strlen(dev->type) + digits + 2, GFP_KERNEL);
        if (!dev->proc_name)
                goto err_out;
-       sprintf(dev->proc_name,"%s:%d",dev->type, dev->number);
+       sprintf(dev->proc_name, "%s:%d", dev->type, dev->number);
 
        dev->proc_entry = proc_create_data(dev->proc_name, 0, atm_proc_root,
                                           &proc_atm_dev_ops, dev);
        if (!dev->proc_entry)
                goto err_free_name;
        return 0;
+
 err_free_name:
        kfree(dev->proc_name);
 err_out:
        return error;
 }
 
-
 void atm_proc_dev_deregister(struct atm_dev *dev)
 {
        if (!dev->ops->proc_read)
index 8d74e62b0d79f93e63cabde5474b0d9f13d4bd04..437ee70c5e629e3fcf8cbd4cdb3ac5f737802b23 100644 (file)
 #include "common.h"            /* common for PVCs and SVCs */
 
 
-static int pvc_shutdown(struct socket *sock,int how)
+static int pvc_shutdown(struct socket *sock, int how)
 {
        return 0;
 }
 
-
-static int pvc_bind(struct socket *sock,struct sockaddr *sockaddr,
-    int sockaddr_len)
+static int pvc_bind(struct socket *sock, struct sockaddr *sockaddr,
+                   int sockaddr_len)
 {
        struct sock *sk = sock->sk;
        struct sockaddr_atmpvc *addr;
        struct atm_vcc *vcc;
        int error;
 
-       if (sockaddr_len != sizeof(struct sockaddr_atmpvc)) return -EINVAL;
-       addr = (struct sockaddr_atmpvc *) sockaddr;
-       if (addr->sap_family != AF_ATMPVC) return -EAFNOSUPPORT;
+       if (sockaddr_len != sizeof(struct sockaddr_atmpvc))
+               return -EINVAL;
+       addr = (struct sockaddr_atmpvc *)sockaddr;
+       if (addr->sap_family != AF_ATMPVC)
+               return -EAFNOSUPPORT;
        lock_sock(sk);
        vcc = ATM_SD(sock);
        if (!test_bit(ATM_VF_HASQOS, &vcc->flags)) {
                error = -EBADFD;
                goto out;
        }
-       if (test_bit(ATM_VF_PARTIAL,&vcc->flags)) {
-               if (vcc->vpi != ATM_VPI_UNSPEC) addr->sap_addr.vpi = vcc->vpi;
-               if (vcc->vci != ATM_VCI_UNSPEC) addr->sap_addr.vci = vcc->vci;
+       if (test_bit(ATM_VF_PARTIAL, &vcc->flags)) {
+               if (vcc->vpi != ATM_VPI_UNSPEC)
+                       addr->sap_addr.vpi = vcc->vpi;
+               if (vcc->vci != ATM_VCI_UNSPEC)
+                       addr->sap_addr.vci = vcc->vci;
        }
        error = vcc_connect(sock, addr->sap_addr.itf, addr->sap_addr.vpi,
                            addr->sap_addr.vci);
@@ -51,11 +54,10 @@ out:
        return error;
 }
 
-
-static int pvc_connect(struct socket *sock,struct sockaddr *sockaddr,
-    int sockaddr_len,int flags)
+static int pvc_connect(struct socket *sock, struct sockaddr *sockaddr,
+                      int sockaddr_len, int flags)
 {
-       return pvc_bind(sock,sockaddr,sockaddr_len);
+       return pvc_bind(sock, sockaddr, sockaddr_len);
 }
 
 static int pvc_setsockopt(struct socket *sock, int level, int optname,
@@ -70,7 +72,6 @@ static int pvc_setsockopt(struct socket *sock, int level, int optname,
        return error;
 }
 
-
 static int pvc_getsockopt(struct socket *sock, int level, int optname,
                          char __user *optval, int __user *optlen)
 {
@@ -83,16 +84,16 @@ static int pvc_getsockopt(struct socket *sock, int level, int optname,
        return error;
 }
 
-
-static int pvc_getname(struct socket *sock,struct sockaddr *sockaddr,
-    int *sockaddr_len,int peer)
+static int pvc_getname(struct socket *sock, struct sockaddr *sockaddr,
+                      int *sockaddr_len, int peer)
 {
        struct sockaddr_atmpvc *addr;
        struct atm_vcc *vcc = ATM_SD(sock);
 
-       if (!vcc->dev || !test_bit(ATM_VF_ADDR,&vcc->flags)) return -ENOTCONN;
+       if (!vcc->dev || !test_bit(ATM_VF_ADDR, &vcc->flags))
+               return -ENOTCONN;
        *sockaddr_len = sizeof(struct sockaddr_atmpvc);
-       addr = (struct sockaddr_atmpvc *) sockaddr;
+       addr = (struct sockaddr_atmpvc *)sockaddr;
        addr->sap_family = AF_ATMPVC;
        addr->sap_addr.itf = vcc->dev->number;
        addr->sap_addr.vpi = vcc->vpi;
@@ -100,7 +101,6 @@ static int pvc_getname(struct socket *sock,struct sockaddr *sockaddr,
        return 0;
 }
 
-
 static const struct proto_ops pvc_proto_ops = {
        .family =       PF_ATMPVC,
        .owner =        THIS_MODULE,
@@ -137,7 +137,6 @@ static int pvc_create(struct net *net, struct socket *sock, int protocol,
        return vcc_create(net, sock, protocol, PF_ATMPVC);
 }
 
-
 static const struct net_proto_family pvc_family_ops = {
        .family = PF_ATMPVC,
        .create = pvc_create,
index cbfcc71a17b149e9a1729232f99022c22be87d12..d0c4bd047dc453990d45cead53fcdbb57b27fc25 100644 (file)
@@ -2,6 +2,7 @@
 
 /* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
 
 #include <linux/module.h>
 #include <linux/atmdev.h>
@@ -17,7 +18,7 @@
  * SKB == NULL indicates that the link is being closed
  */
 
-static void atm_push_raw(struct atm_vcc *vcc,struct sk_buff *skb)
+static void atm_push_raw(struct atm_vcc *vcc, struct sk_buff *skb)
 {
        if (skb) {
                struct sock *sk = sk_atm(vcc);
@@ -27,36 +28,33 @@ static void atm_push_raw(struct atm_vcc *vcc,struct sk_buff *skb)
        }
 }
 
-
-static void atm_pop_raw(struct atm_vcc *vcc,struct sk_buff *skb)
+static void atm_pop_raw(struct atm_vcc *vcc, struct sk_buff *skb)
 {
        struct sock *sk = sk_atm(vcc);
 
-       pr_debug("APopR (%d) %d -= %d\n", vcc->vci,
-               sk_wmem_alloc_get(sk), skb->truesize);
+       pr_debug("(%d) %d -= %d\n",
+                vcc->vci, sk_wmem_alloc_get(sk), skb->truesize);
        atomic_sub(skb->truesize, &sk->sk_wmem_alloc);
        dev_kfree_skb_any(skb);
        sk->sk_write_space(sk);
 }
 
-
-static int atm_send_aal0(struct atm_vcc *vcc,struct sk_buff *skb)
+static int atm_send_aal0(struct atm_vcc *vcc, struct sk_buff *skb)
 {
        /*
         * Note that if vpi/vci are _ANY or _UNSPEC the below will
         * still work
         */
        if (!capable(CAP_NET_ADMIN) &&
-           (((u32 *) skb->data)[0] & (ATM_HDR_VPI_MASK | ATM_HDR_VCI_MASK)) !=
-           ((vcc->vpi << ATM_HDR_VPI_SHIFT) | (vcc->vci << ATM_HDR_VCI_SHIFT)))
-           {
+           (((u32 *)skb->data)[0] & (ATM_HDR_VPI_MASK | ATM_HDR_VCI_MASK)) !=
+           ((vcc->vpi << ATM_HDR_VPI_SHIFT) |
+            (vcc->vci << ATM_HDR_VCI_SHIFT))) {
                kfree_skb(skb);
                return -EADDRNOTAVAIL;
        }
-       return vcc->dev->ops->send(vcc,skb);
+       return vcc->dev->ops->send(vcc, skb);
 }
 
-
 int atm_init_aal0(struct atm_vcc *vcc)
 {
        vcc->push = atm_push_raw;
@@ -66,7 +64,6 @@ int atm_init_aal0(struct atm_vcc *vcc)
        return 0;
 }
 
-
 int atm_init_aal34(struct atm_vcc *vcc)
 {
        vcc->push = atm_push_raw;
@@ -76,7 +73,6 @@ int atm_init_aal34(struct atm_vcc *vcc)
        return 0;
 }
 
-
 int atm_init_aal5(struct atm_vcc *vcc)
 {
        vcc->push = atm_push_raw;
@@ -85,6 +81,4 @@ int atm_init_aal5(struct atm_vcc *vcc)
        vcc->send = vcc->dev->ops->send;
        return 0;
 }
-
-
 EXPORT_SYMBOL(atm_init_aal5);
index 56b7322ff461c0dc9ebc652a85320cc249b4b8e8..447ed89205d8e4ef5a43e7614de049838e69056d 100644 (file)
@@ -7,6 +7,7 @@
  * 2002/01 - don't free the whole struct sock on sk->destruct time,
  *          use the default destruct function initialized by sock_init_data */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
 
 #include <linux/ctype.h>
 #include <linux/string.h>
@@ -70,7 +71,7 @@ struct atm_dev *atm_dev_lookup(int number)
        mutex_unlock(&atm_dev_mutex);
        return dev;
 }
-
+EXPORT_SYMBOL(atm_dev_lookup);
 
 struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops,
                                 int number, unsigned long *flags)
@@ -79,13 +80,13 @@ struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops,
 
        dev = __alloc_atm_dev(type);
        if (!dev) {
-               printk(KERN_ERR "atm_dev_register: no space for dev %s\n",
-                   type);
+               pr_err("no space for dev %s\n", type);
                return NULL;
        }
        mutex_lock(&atm_dev_mutex);
        if (number != -1) {
-               if ((inuse = __atm_dev_lookup(number))) {
+               inuse = __atm_dev_lookup(number);
+               if (inuse) {
                        atm_dev_put(inuse);
                        mutex_unlock(&atm_dev_mutex);
                        kfree(dev);
@@ -109,16 +110,12 @@ struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops,
        atomic_set(&dev->refcnt, 1);
 
        if (atm_proc_dev_register(dev) < 0) {
-               printk(KERN_ERR "atm_dev_register: "
-                      "atm_proc_dev_register failed for dev %s\n",
-                      type);
+               pr_err("atm_proc_dev_register failed for dev %s\n", type);
                goto out_fail;
        }
 
        if (atm_register_sysfs(dev) < 0) {
-               printk(KERN_ERR "atm_dev_register: "
-                      "atm_register_sysfs failed for dev %s\n",
-                      type);
+               pr_err("atm_register_sysfs failed for dev %s\n", type);
                atm_proc_dev_deregister(dev);
                goto out_fail;
        }
@@ -134,7 +131,7 @@ out_fail:
        dev = NULL;
        goto out;
 }
-
+EXPORT_SYMBOL(atm_dev_register);
 
 void atm_dev_deregister(struct atm_dev *dev)
 {
@@ -156,7 +153,7 @@ void atm_dev_deregister(struct atm_dev *dev)
 
        atm_dev_put(dev);
 }
-
+EXPORT_SYMBOL(atm_dev_deregister);
 
 static void copy_aal_stats(struct k_atm_aal_stats *from,
     struct atm_aal_stats *to)
@@ -166,7 +163,6 @@ static void copy_aal_stats(struct k_atm_aal_stats *from,
 #undef __HANDLE_ITEM
 }
 
-
 static void subtract_aal_stats(struct k_atm_aal_stats *from,
     struct atm_aal_stats *to)
 {
@@ -175,8 +171,8 @@ static void subtract_aal_stats(struct k_atm_aal_stats *from,
 #undef __HANDLE_ITEM
 }
 
-
-static int fetch_stats(struct atm_dev *dev, struct atm_dev_stats __user *arg, int zero)
+static int fetch_stats(struct atm_dev *dev, struct atm_dev_stats __user *arg,
+                      int zero)
 {
        struct atm_dev_stats tmp;
        int error = 0;
@@ -194,7 +190,6 @@ static int fetch_stats(struct atm_dev *dev, struct atm_dev_stats __user *arg, in
        return error ? -EFAULT : 0;
 }
 
-
 int atm_dev_ioctl(unsigned int cmd, void __user *arg, int compat)
 {
        void __user *buf;
@@ -210,50 +205,49 @@ int atm_dev_ioctl(unsigned int cmd, void __user *arg, int compat)
 #endif
 
        switch (cmd) {
-               case ATM_GETNAMES:
-
-                       if (compat) {
+       case ATM_GETNAMES:
+               if (compat) {
 #ifdef CONFIG_COMPAT
-                               struct compat_atm_iobuf __user *ciobuf = arg;
-                               compat_uptr_t cbuf;
-                               iobuf_len = &ciobuf->length;
-                               if (get_user(cbuf, &ciobuf->buffer))
-                                       return -EFAULT;
-                               buf = compat_ptr(cbuf);
+                       struct compat_atm_iobuf __user *ciobuf = arg;
+                       compat_uptr_t cbuf;
+                       iobuf_len = &ciobuf->length;
+                       if (get_user(cbuf, &ciobuf->buffer))
+                               return -EFAULT;
+                       buf = compat_ptr(cbuf);
 #endif
-                       } else {
-                               struct atm_iobuf __user *iobuf = arg;
-                               iobuf_len = &iobuf->length;
-                               if (get_user(buf, &iobuf->buffer))
-                                       return -EFAULT;
-                       }
-                       if (get_user(len, iobuf_len))
+               } else {
+                       struct atm_iobuf __user *iobuf = arg;
+                       iobuf_len = &iobuf->length;
+                       if (get_user(buf, &iobuf->buffer))
                                return -EFAULT;
-                       mutex_lock(&atm_dev_mutex);
-                       list_for_each(p, &atm_devs)
-                               size += sizeof(int);
-                       if (size > len) {
-                               mutex_unlock(&atm_dev_mutex);
-                               return -E2BIG;
-                       }
-                       tmp_buf = kmalloc(size, GFP_ATOMIC);
-                       if (!tmp_buf) {
-                               mutex_unlock(&atm_dev_mutex);
-                               return -ENOMEM;
-                       }
-                       tmp_p = tmp_buf;
-                       list_for_each(p, &atm_devs) {
-                               dev = list_entry(p, struct atm_dev, dev_list);
-                               *tmp_p++ = dev->number;
-                       }
+               }
+               if (get_user(len, iobuf_len))
+                       return -EFAULT;
+               mutex_lock(&atm_dev_mutex);
+               list_for_each(p, &atm_devs)
+                       size += sizeof(int);
+               if (size > len) {
                        mutex_unlock(&atm_dev_mutex);
-                       error = ((copy_to_user(buf, tmp_buf, size)) ||
-                                       put_user(size, iobuf_len))
-                                               ? -EFAULT : 0;
-                       kfree(tmp_buf);
-                       return error;
-               default:
-                       break;
+                       return -E2BIG;
+               }
+               tmp_buf = kmalloc(size, GFP_ATOMIC);
+               if (!tmp_buf) {
+                       mutex_unlock(&atm_dev_mutex);
+                       return -ENOMEM;
+               }
+               tmp_p = tmp_buf;
+               list_for_each(p, &atm_devs) {
+                       dev = list_entry(p, struct atm_dev, dev_list);
+                       *tmp_p++ = dev->number;
+               }
+               mutex_unlock(&atm_dev_mutex);
+               error = ((copy_to_user(buf, tmp_buf, size)) ||
+                        put_user(size, iobuf_len))
+                       ? -EFAULT : 0;
+               kfree(tmp_buf);
+               return error;
+       default:
+               break;
        }
 
        if (compat) {
@@ -282,166 +276,167 @@ int atm_dev_ioctl(unsigned int cmd, void __user *arg, int compat)
                if (get_user(number, &sioc->number))
                        return -EFAULT;
        }
-       if (!(dev = try_then_request_module(atm_dev_lookup(number),
-                                           "atm-device-%d", number)))
+
+       dev = try_then_request_module(atm_dev_lookup(number), "atm-device-%d",
+                                     number);
+       if (!dev)
                return -ENODEV;
 
        switch (cmd) {
-               case ATM_GETTYPE:
-                       size = strlen(dev->type) + 1;
-                       if (copy_to_user(buf, dev->type, size)) {
-                               error = -EFAULT;
-                               goto done;
-                       }
-                       break;
-               case ATM_GETESI:
-                       size = ESI_LEN;
-                       if (copy_to_user(buf, dev->esi, size)) {
-                               error = -EFAULT;
-                               goto done;
-                       }
-                       break;
-               case ATM_SETESI:
-                       {
-                               int i;
-
-                               for (i = 0; i < ESI_LEN; i++)
-                                       if (dev->esi[i]) {
-                                               error = -EEXIST;
-                                               goto done;
-                                       }
-                       }
-                       /* fall through */
-               case ATM_SETESIF:
-                       {
-                               unsigned char esi[ESI_LEN];
-
-                               if (!capable(CAP_NET_ADMIN)) {
-                                       error = -EPERM;
-                                       goto done;
-                               }
-                               if (copy_from_user(esi, buf, ESI_LEN)) {
-                                       error = -EFAULT;
-                                       goto done;
-                               }
-                               memcpy(dev->esi, esi, ESI_LEN);
-                               error =  ESI_LEN;
-                               goto done;
-                       }
-               case ATM_GETSTATZ:
-                       if (!capable(CAP_NET_ADMIN)) {
-                               error = -EPERM;
-                               goto done;
-                       }
-                       /* fall through */
-               case ATM_GETSTAT:
-                       size = sizeof(struct atm_dev_stats);
-                       error = fetch_stats(dev, buf, cmd == ATM_GETSTATZ);
-                       if (error)
-                               goto done;
-                       break;
-               case ATM_GETCIRANGE:
-                       size = sizeof(struct atm_cirange);
-                       if (copy_to_user(buf, &dev->ci_range, size)) {
-                               error = -EFAULT;
-                               goto done;
-                       }
-                       break;
-               case ATM_GETLINKRATE:
-                       size = sizeof(int);
-                       if (copy_to_user(buf, &dev->link_rate, size)) {
-                               error = -EFAULT;
-                               goto done;
-                       }
-                       break;
-               case ATM_RSTADDR:
-                       if (!capable(CAP_NET_ADMIN)) {
-                               error = -EPERM;
-                               goto done;
-                       }
-                       atm_reset_addr(dev, ATM_ADDR_LOCAL);
-                       break;
-               case ATM_ADDADDR:
-               case ATM_DELADDR:
-               case ATM_ADDLECSADDR:
-               case ATM_DELLECSADDR:
-                       if (!capable(CAP_NET_ADMIN)) {
-                               error = -EPERM;
-                               goto done;
-                       }
-                       {
-                               struct sockaddr_atmsvc addr;
-
-                               if (copy_from_user(&addr, buf, sizeof(addr))) {
-                                       error = -EFAULT;
-                                       goto done;
-                               }
-                               if (cmd == ATM_ADDADDR || cmd == ATM_ADDLECSADDR)
-                                       error = atm_add_addr(dev, &addr,
-                                                            (cmd == ATM_ADDADDR ?
-                                                             ATM_ADDR_LOCAL : ATM_ADDR_LECS));
-                               else
-                                       error = atm_del_addr(dev, &addr,
-                                                            (cmd == ATM_DELADDR ?
-                                                             ATM_ADDR_LOCAL : ATM_ADDR_LECS));
+       case ATM_GETTYPE:
+               size = strlen(dev->type) + 1;
+               if (copy_to_user(buf, dev->type, size)) {
+                       error = -EFAULT;
+                       goto done;
+               }
+               break;
+       case ATM_GETESI:
+               size = ESI_LEN;
+               if (copy_to_user(buf, dev->esi, size)) {
+                       error = -EFAULT;
+                       goto done;
+               }
+               break;
+       case ATM_SETESI:
+       {
+               int i;
+
+               for (i = 0; i < ESI_LEN; i++)
+                       if (dev->esi[i]) {
+                               error = -EEXIST;
                                goto done;
                        }
-               case ATM_GETADDR:
-               case ATM_GETLECSADDR:
-                       error = atm_get_addr(dev, buf, len,
-                                            (cmd == ATM_GETADDR ?
+       }
+       /* fall through */
+       case ATM_SETESIF:
+       {
+               unsigned char esi[ESI_LEN];
+
+               if (!capable(CAP_NET_ADMIN)) {
+                       error = -EPERM;
+                       goto done;
+               }
+               if (copy_from_user(esi, buf, ESI_LEN)) {
+                       error = -EFAULT;
+                       goto done;
+               }
+               memcpy(dev->esi, esi, ESI_LEN);
+               error =  ESI_LEN;
+               goto done;
+       }
+       case ATM_GETSTATZ:
+               if (!capable(CAP_NET_ADMIN)) {
+                       error = -EPERM;
+                       goto done;
+               }
+               /* fall through */
+       case ATM_GETSTAT:
+               size = sizeof(struct atm_dev_stats);
+               error = fetch_stats(dev, buf, cmd == ATM_GETSTATZ);
+               if (error)
+                       goto done;
+               break;
+       case ATM_GETCIRANGE:
+               size = sizeof(struct atm_cirange);
+               if (copy_to_user(buf, &dev->ci_range, size)) {
+                       error = -EFAULT;
+                       goto done;
+               }
+               break;
+       case ATM_GETLINKRATE:
+               size = sizeof(int);
+               if (copy_to_user(buf, &dev->link_rate, size)) {
+                       error = -EFAULT;
+                       goto done;
+               }
+               break;
+       case ATM_RSTADDR:
+               if (!capable(CAP_NET_ADMIN)) {
+                       error = -EPERM;
+                       goto done;
+               }
+               atm_reset_addr(dev, ATM_ADDR_LOCAL);
+               break;
+       case ATM_ADDADDR:
+       case ATM_DELADDR:
+       case ATM_ADDLECSADDR:
+       case ATM_DELLECSADDR:
+       {
+               struct sockaddr_atmsvc addr;
+
+               if (!capable(CAP_NET_ADMIN)) {
+                       error = -EPERM;
+                       goto done;
+               }
+
+               if (copy_from_user(&addr, buf, sizeof(addr))) {
+                       error = -EFAULT;
+                       goto done;
+               }
+               if (cmd == ATM_ADDADDR || cmd == ATM_ADDLECSADDR)
+                       error = atm_add_addr(dev, &addr,
+                                            (cmd == ATM_ADDADDR ?
                                              ATM_ADDR_LOCAL : ATM_ADDR_LECS));
-                       if (error < 0)
-                               goto done;
-                       size = error;
-                       /* may return 0, but later on size == 0 means "don't
-                          write the length" */
-                       error = put_user(size, sioc_len)
-                               ? -EFAULT : 0;
+               else
+                       error = atm_del_addr(dev, &addr,
+                                            (cmd == ATM_DELADDR ?
+                                             ATM_ADDR_LOCAL : ATM_ADDR_LECS));
+               goto done;
+       }
+       case ATM_GETADDR:
+       case ATM_GETLECSADDR:
+               error = atm_get_addr(dev, buf, len,
+                                    (cmd == ATM_GETADDR ?
+                                     ATM_ADDR_LOCAL : ATM_ADDR_LECS));
+               if (error < 0)
+                       goto done;
+               size = error;
+               /* may return 0, but later on size == 0 means "don't
+                  write the length" */
+               error = put_user(size, sioc_len) ? -EFAULT : 0;
+               goto done;
+       case ATM_SETLOOP:
+               if (__ATM_LM_XTRMT((int) (unsigned long) buf) &&
+                   __ATM_LM_XTLOC((int) (unsigned long) buf) >
+                   __ATM_LM_XTRMT((int) (unsigned long) buf)) {
+                       error = -EINVAL;
                        goto done;
-               case ATM_SETLOOP:
-                       if (__ATM_LM_XTRMT((int) (unsigned long) buf) &&
-                           __ATM_LM_XTLOC((int) (unsigned long) buf) >
-                           __ATM_LM_XTRMT((int) (unsigned long) buf)) {
+               }
+               /* fall through */
+       case ATM_SETCIRANGE:
+       case SONET_GETSTATZ:
+       case SONET_SETDIAG:
+       case SONET_CLRDIAG:
+       case SONET_SETFRAMING:
+               if (!capable(CAP_NET_ADMIN)) {
+                       error = -EPERM;
+                       goto done;
+               }
+               /* fall through */
+       default:
+               if (compat) {
+#ifdef CONFIG_COMPAT
+                       if (!dev->ops->compat_ioctl) {
                                error = -EINVAL;
                                goto done;
                        }
-                       /* fall through */
-               case ATM_SETCIRANGE:
-               case SONET_GETSTATZ:
-               case SONET_SETDIAG:
-               case SONET_CLRDIAG:
-               case SONET_SETFRAMING:
-                       if (!capable(CAP_NET_ADMIN)) {
-                               error = -EPERM;
-                               goto done;
-                       }
-                       /* fall through */
-               default:
-                       if (compat) {
-#ifdef CONFIG_COMPAT
-                               if (!dev->ops->compat_ioctl) {
-                                       error = -EINVAL;
-                                       goto done;
-                               }
-                               size = dev->ops->compat_ioctl(dev, cmd, buf);
+                       size = dev->ops->compat_ioctl(dev, cmd, buf);
 #endif
-                       } else {
-                               if (!dev->ops->ioctl) {
-                                       error = -EINVAL;
-                                       goto done;
-                               }
-                               size = dev->ops->ioctl(dev, cmd, buf);
-                       }
-                       if (size < 0) {
-                               error = (size == -ENOIOCTLCMD ? -EINVAL : size);
+               } else {
+                       if (!dev->ops->ioctl) {
+                               error = -EINVAL;
                                goto done;
                        }
+                       size = dev->ops->ioctl(dev, cmd, buf);
+               }
+               if (size < 0) {
+                       error = (size == -ENOIOCTLCMD ? -EINVAL : size);
+                       goto done;
+               }
        }
 
        if (size)
-               error = put_user(size, sioc_len)
-                       ? -EFAULT : 0;
+               error = put_user(size, sioc_len) ? -EFAULT : 0;
        else
                error = 0;
 done:
@@ -449,7 +444,7 @@ done:
        return error;
 }
 
-static __inline__ void *dev_get_idx(loff_t left)
+static inline void *dev_get_idx(loff_t left)
 {
        struct list_head *p;
 
@@ -478,8 +473,3 @@ void *atm_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos)
                ? atm_devs.next : ((struct list_head *)v)->next;
        return (v == &atm_devs) ? NULL : v;
 }
-
-
-EXPORT_SYMBOL(atm_dev_register);
-EXPORT_SYMBOL(atm_dev_deregister);
-EXPORT_SYMBOL(atm_dev_lookup);
index 22992140052290a92ef783a0ed6bbb9b5eafd861..ad1d28ae512bcfc66a89f693c4e855ad0580783f 100644 (file)
@@ -2,6 +2,7 @@
 
 /* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
 
 #include <linux/errno.h>       /* error codes */
 #include <linux/kernel.h>      /* printk */
@@ -17,7 +18,6 @@
 #include "resources.h"
 #include "signaling.h"
 
-
 #undef WAIT_FOR_DEMON          /* #define this if system calls on SVC sockets
                                   should block until the demon runs.
                                   Danger: may cause nasty hangs if the demon
@@ -28,60 +28,59 @@ struct atm_vcc *sigd = NULL;
 static DECLARE_WAIT_QUEUE_HEAD(sigd_sleep);
 #endif
 
-
 static void sigd_put_skb(struct sk_buff *skb)
 {
 #ifdef WAIT_FOR_DEMON
-       DECLARE_WAITQUEUE(wait,current);
+       DECLARE_WAITQUEUE(wait, current);
 
-       add_wait_queue(&sigd_sleep,&wait);
+       add_wait_queue(&sigd_sleep, &wait);
        while (!sigd) {
                set_current_state(TASK_UNINTERRUPTIBLE);
-               pr_debug("atmsvc: waiting for signaling demon...\n");
+               pr_debug("atmsvc: waiting for signaling daemon...\n");
                schedule();
        }
        current->state = TASK_RUNNING;
-       remove_wait_queue(&sigd_sleep,&wait);
+       remove_wait_queue(&sigd_sleep, &wait);
 #else
        if (!sigd) {
-               pr_debug("atmsvc: no signaling demon\n");
+               pr_debug("atmsvc: no signaling daemon\n");
                kfree_skb(skb);
                return;
        }
 #endif
-       atm_force_charge(sigd,skb->truesize);
-       skb_queue_tail(&sk_atm(sigd)->sk_receive_queue,skb);
+       atm_force_charge(sigd, skb->truesize);
+       skb_queue_tail(&sk_atm(sigd)->sk_receive_queue, skb);
        sk_atm(sigd)->sk_data_ready(sk_atm(sigd), skb->len);
 }
 
-
-static void modify_qos(struct atm_vcc *vcc,struct atmsvc_msg *msg)
+static void modify_qos(struct atm_vcc *vcc, struct atmsvc_msg *msg)
 {
        struct sk_buff *skb;
 
-       if (test_bit(ATM_VF_RELEASED,&vcc->flags) ||
-           !test_bit(ATM_VF_READY,&vcc->flags))
+       if (test_bit(ATM_VF_RELEASED, &vcc->flags) ||
+           !test_bit(ATM_VF_READY, &vcc->flags))
                return;
        msg->type = as_error;
-       if (!vcc->dev->ops->change_qos) msg->reply = -EOPNOTSUPP;
+       if (!vcc->dev->ops->change_qos)
+               msg->reply = -EOPNOTSUPP;
        else {
                /* should lock VCC */
-               msg->reply = vcc->dev->ops->change_qos(vcc,&msg->qos,
-                   msg->reply);
-               if (!msg->reply) msg->type = as_okay;
+               msg->reply = vcc->dev->ops->change_qos(vcc, &msg->qos,
+                                                      msg->reply);
+               if (!msg->reply)
+                       msg->type = as_okay;
        }
        /*
         * Should probably just turn around the old skb. But the, the buffer
         * space accounting needs to follow the change too. Maybe later.
         */
-       while (!(skb = alloc_skb(sizeof(struct atmsvc_msg),GFP_KERNEL)))
+       while (!(skb = alloc_skb(sizeof(struct atmsvc_msg), GFP_KERNEL)))
                schedule();
-       *(struct atmsvc_msg *) skb_put(skb,sizeof(struct atmsvc_msg)) = *msg;
+       *(struct atmsvc_msg *)skb_put(skb, sizeof(struct atmsvc_msg)) = *msg;
        sigd_put_skb(skb);
 }
 
-
-static int sigd_send(struct atm_vcc *vcc,struct sk_buff *skb)
+static int sigd_send(struct atm_vcc *vcc, struct sk_buff *skb)
 {
        struct atmsvc_msg *msg;
        struct atm_vcc *session_vcc;
@@ -90,69 +89,68 @@ static int sigd_send(struct atm_vcc *vcc,struct sk_buff *skb)
        msg = (struct atmsvc_msg *) skb->data;
        atomic_sub(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc);
        vcc = *(struct atm_vcc **) &msg->vcc;
-       pr_debug("sigd_send %d (0x%lx)\n",(int) msg->type,
-         (unsigned long) vcc);
+       pr_debug("%d (0x%lx)\n", (int)msg->type, (unsigned long)vcc);
        sk = sk_atm(vcc);
 
        switch (msg->type) {
-               case as_okay:
-                       sk->sk_err = -msg->reply;
-                       clear_bit(ATM_VF_WAITING, &vcc->flags);
-                       if (!*vcc->local.sas_addr.prv &&
-                           !*vcc->local.sas_addr.pub) {
-                               vcc->local.sas_family = AF_ATMSVC;
-                               memcpy(vcc->local.sas_addr.prv,
-                                   msg->local.sas_addr.prv,ATM_ESA_LEN);
-                               memcpy(vcc->local.sas_addr.pub,
-                                   msg->local.sas_addr.pub,ATM_E164_LEN+1);
-                       }
-                       session_vcc = vcc->session ? vcc->session : vcc;
-                       if (session_vcc->vpi || session_vcc->vci) break;
-                       session_vcc->itf = msg->pvc.sap_addr.itf;
-                       session_vcc->vpi = msg->pvc.sap_addr.vpi;
-                       session_vcc->vci = msg->pvc.sap_addr.vci;
-                       if (session_vcc->vpi || session_vcc->vci)
-                               session_vcc->qos = msg->qos;
-                       break;
-               case as_error:
-                       clear_bit(ATM_VF_REGIS,&vcc->flags);
-                       clear_bit(ATM_VF_READY,&vcc->flags);
-                       sk->sk_err = -msg->reply;
-                       clear_bit(ATM_VF_WAITING, &vcc->flags);
+       case as_okay:
+               sk->sk_err = -msg->reply;
+               clear_bit(ATM_VF_WAITING, &vcc->flags);
+               if (!*vcc->local.sas_addr.prv && !*vcc->local.sas_addr.pub) {
+                       vcc->local.sas_family = AF_ATMSVC;
+                       memcpy(vcc->local.sas_addr.prv,
+                              msg->local.sas_addr.prv, ATM_ESA_LEN);
+                       memcpy(vcc->local.sas_addr.pub,
+                              msg->local.sas_addr.pub, ATM_E164_LEN + 1);
+               }
+               session_vcc = vcc->session ? vcc->session : vcc;
+               if (session_vcc->vpi || session_vcc->vci)
                        break;
-               case as_indicate:
-                       vcc = *(struct atm_vcc **) &msg->listen_vcc;
-                       sk = sk_atm(vcc);
-                       pr_debug("as_indicate!!!\n");
-                       lock_sock(sk);
-                       if (sk_acceptq_is_full(sk)) {
-                               sigd_enq(NULL,as_reject,vcc,NULL,NULL);
-                               dev_kfree_skb(skb);
-                               goto as_indicate_complete;
-                       }
-                       sk->sk_ack_backlog++;
-                       skb_queue_tail(&sk->sk_receive_queue, skb);
-                       pr_debug("waking sk->sk_sleep 0x%p\n", sk->sk_sleep);
-                       sk->sk_state_change(sk);
+               session_vcc->itf = msg->pvc.sap_addr.itf;
+               session_vcc->vpi = msg->pvc.sap_addr.vpi;
+               session_vcc->vci = msg->pvc.sap_addr.vci;
+               if (session_vcc->vpi || session_vcc->vci)
+                       session_vcc->qos = msg->qos;
+               break;
+       case as_error:
+               clear_bit(ATM_VF_REGIS, &vcc->flags);
+               clear_bit(ATM_VF_READY, &vcc->flags);
+               sk->sk_err = -msg->reply;
+               clear_bit(ATM_VF_WAITING, &vcc->flags);
+               break;
+       case as_indicate:
+               vcc = *(struct atm_vcc **)&msg->listen_vcc;
+               sk = sk_atm(vcc);
+               pr_debug("as_indicate!!!\n");
+               lock_sock(sk);
+               if (sk_acceptq_is_full(sk)) {
+                       sigd_enq(NULL, as_reject, vcc, NULL, NULL);
+                       dev_kfree_skb(skb);
+                       goto as_indicate_complete;
+               }
+               sk->sk_ack_backlog++;
+               skb_queue_tail(&sk->sk_receive_queue, skb);
+               pr_debug("waking sk->sk_sleep 0x%p\n", sk->sk_sleep);
+               sk->sk_state_change(sk);
 as_indicate_complete:
-                       release_sock(sk);
-                       return 0;
-               case as_close:
-                       set_bit(ATM_VF_RELEASED,&vcc->flags);
-                       vcc_release_async(vcc, msg->reply);
-                       goto out;
-               case as_modify:
-                       modify_qos(vcc,msg);
-                       break;
-               case as_addparty:
-               case as_dropparty:
-                       sk->sk_err_soft = msg->reply;   /* < 0 failure, otherwise ep_ref */
-                       clear_bit(ATM_VF_WAITING, &vcc->flags);
-                       break;
-               default:
-                       printk(KERN_ALERT "sigd_send: bad message type %d\n",
-                           (int) msg->type);
-                       return -EINVAL;
+               release_sock(sk);
+               return 0;
+       case as_close:
+               set_bit(ATM_VF_RELEASED, &vcc->flags);
+               vcc_release_async(vcc, msg->reply);
+               goto out;
+       case as_modify:
+               modify_qos(vcc, msg);
+               break;
+       case as_addparty:
+       case as_dropparty:
+               sk->sk_err_soft = msg->reply;
+                                       /* < 0 failure, otherwise ep_ref */
+               clear_bit(ATM_VF_WAITING, &vcc->flags);
+               break;
+       default:
+               pr_alert("bad message type %d\n", (int)msg->type);
+               return -EINVAL;
        }
        sk->sk_state_change(sk);
 out:
@@ -160,48 +158,52 @@ out:
        return 0;
 }
 
-
-void sigd_enq2(struct atm_vcc *vcc,enum atmsvc_msg_type type,
-    struct atm_vcc *listen_vcc,const struct sockaddr_atmpvc *pvc,
-    const struct sockaddr_atmsvc *svc,const struct atm_qos *qos,int reply)
+void sigd_enq2(struct atm_vcc *vcc, enum atmsvc_msg_type type,
+              struct atm_vcc *listen_vcc, const struct sockaddr_atmpvc *pvc,
+              const struct sockaddr_atmsvc *svc, const struct atm_qos *qos,
+              int reply)
 {
        struct sk_buff *skb;
        struct atmsvc_msg *msg;
        static unsigned session = 0;
 
-       pr_debug("sigd_enq %d (0x%p)\n",(int) type,vcc);
-       while (!(skb = alloc_skb(sizeof(struct atmsvc_msg),GFP_KERNEL)))
+       pr_debug("%d (0x%p)\n", (int)type, vcc);
+       while (!(skb = alloc_skb(sizeof(struct atmsvc_msg), GFP_KERNEL)))
                schedule();
-       msg = (struct atmsvc_msg *) skb_put(skb,sizeof(struct atmsvc_msg));
-       memset(msg,0,sizeof(*msg));
+       msg = (struct atmsvc_msg *)skb_put(skb, sizeof(struct atmsvc_msg));
+       memset(msg, 0, sizeof(*msg));
        msg->type = type;
        *(struct atm_vcc **) &msg->vcc = vcc;
        *(struct atm_vcc **) &msg->listen_vcc = listen_vcc;
        msg->reply = reply;
-       if (qos) msg->qos = *qos;
-       if (vcc) msg->sap = vcc->sap;
-       if (svc) msg->svc = *svc;
-       if (vcc) msg->local = vcc->local;
-       if (pvc) msg->pvc = *pvc;
+       if (qos)
+               msg->qos = *qos;
+       if (vcc)
+               msg->sap = vcc->sap;
+       if (svc)
+               msg->svc = *svc;
+       if (vcc)
+               msg->local = vcc->local;
+       if (pvc)
+               msg->pvc = *pvc;
        if (vcc) {
                if (type == as_connect && test_bit(ATM_VF_SESSION, &vcc->flags))
                        msg->session = ++session;
                        /* every new pmp connect gets the next session number */
        }
        sigd_put_skb(skb);
-       if (vcc) set_bit(ATM_VF_REGIS,&vcc->flags);
+       if (vcc)
+               set_bit(ATM_VF_REGIS, &vcc->flags);
 }
 
-
-void sigd_enq(struct atm_vcc *vcc,enum atmsvc_msg_type type,
-    struct atm_vcc *listen_vcc,const struct sockaddr_atmpvc *pvc,
-    const struct sockaddr_atmsvc *svc)
+void sigd_enq(struct atm_vcc *vcc, enum atmsvc_msg_type type,
+             struct atm_vcc *listen_vcc, const struct sockaddr_atmpvc *pvc,
+             const struct sockaddr_atmsvc *svc)
 {
-       sigd_enq2(vcc,type,listen_vcc,pvc,svc,vcc ? &vcc->qos : NULL,0);
+       sigd_enq2(vcc, type, listen_vcc, pvc, svc, vcc ? &vcc->qos : NULL, 0);
        /* other ISP applications may use "reply" */
 }
 
-
 static void purge_vcc(struct atm_vcc *vcc)
 {
        if (sk_atm(vcc)->sk_family == PF_ATMSVC &&
@@ -212,21 +214,20 @@ static void purge_vcc(struct atm_vcc *vcc)
        }
 }
 
-
 static void sigd_close(struct atm_vcc *vcc)
 {
        struct hlist_node *node;
        struct sock *s;
        int i;
 
-       pr_debug("sigd_close\n");
+       pr_debug("\n");
        sigd = NULL;
        if (skb_peek(&sk_atm(vcc)->sk_receive_queue))
-               printk(KERN_ERR "sigd_close: closing with requests pending\n");
+               pr_err("closing with requests pending\n");
        skb_queue_purge(&sk_atm(vcc)->sk_receive_queue);
 
        read_lock(&vcc_sklist_lock);
-       for(i = 0; i < VCC_HTABLE_SIZE; ++i) {
+       for (i = 0; i < VCC_HTABLE_SIZE; ++i) {
                struct hlist_head *head = &vcc_hash[i];
 
                sk_for_each(s, node, head) {
@@ -238,13 +239,11 @@ static void sigd_close(struct atm_vcc *vcc)
        read_unlock(&vcc_sklist_lock);
 }
 
-
 static struct atmdev_ops sigd_dev_ops = {
        .close = sigd_close,
        .send = sigd_send
 };
 
-
 static struct atm_dev sigd_dev = {
        .ops =          &sigd_dev_ops,
        .type =         "sig",
@@ -252,16 +251,16 @@ static struct atm_dev sigd_dev = {
        .lock =         __SPIN_LOCK_UNLOCKED(sigd_dev.lock)
 };
 
-
 int sigd_attach(struct atm_vcc *vcc)
 {
-       if (sigd) return -EADDRINUSE;
-       pr_debug("sigd_attach\n");
+       if (sigd)
+               return -EADDRINUSE;
+       pr_debug("\n");
        sigd = vcc;
        vcc->dev = &sigd_dev;
        vcc_insert_socket(sk_atm(vcc));
-       set_bit(ATM_VF_META,&vcc->flags);
-       set_bit(ATM_VF_READY,&vcc->flags);
+       set_bit(ATM_VF_META, &vcc->flags);
+       set_bit(ATM_VF_READY, &vcc->flags);
 #ifdef WAIT_FOR_DEMON
        wake_up(&sigd_sleep);
 #endif
index 66e1d9b3e5deee4a2793d1d064e5ee78f0a5dd81..3ba9a45a51acaffd9b26ddb9f2c5115429de6fc4 100644 (file)
@@ -2,6 +2,7 @@
 
 /* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
 
 #include <linux/string.h>
 #include <linux/net.h>         /* struct socket, struct proto_ops */
 #include <linux/atmdev.h>
 #include <linux/bitops.h>
 #include <net/sock.h>          /* for sock_no_* */
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 
 #include "resources.h"
 #include "common.h"            /* common for PVCs and SVCs */
 #include "signaling.h"
 #include "addr.h"
 
-static int svc_create(struct net *net, struct socket *sock, int protocol, int kern);
+static int svc_create(struct net *net, struct socket *sock, int protocol,
+                     int kern);
 
 /*
  * Note: since all this is still nicely synchronized with the signaling demon,
@@ -34,25 +36,25 @@ static int svc_create(struct net *net, struct socket *sock, int protocol, int ke
  */
 
 
-static int svc_shutdown(struct socket *sock,int how)
+static int svc_shutdown(struct socket *sock, int how)
 {
        return 0;
 }
 
-
 static void svc_disconnect(struct atm_vcc *vcc)
 {
        DEFINE_WAIT(wait);
        struct sk_buff *skb;
        struct sock *sk = sk_atm(vcc);
 
-       pr_debug("svc_disconnect %p\n",vcc);
-       if (test_bit(ATM_VF_REGIS,&vcc->flags)) {
+       pr_debug("%p\n", vcc);
+       if (test_bit(ATM_VF_REGIS, &vcc->flags)) {
                prepare_to_wait(sk->sk_sleep, &wait, TASK_UNINTERRUPTIBLE);
-               sigd_enq(vcc,as_close,NULL,NULL,NULL);
-               while (!test_bit(ATM_VF_RELEASED,&vcc->flags) && sigd) {
+               sigd_enq(vcc, as_close, NULL, NULL, NULL);
+               while (!test_bit(ATM_VF_RELEASED, &vcc->flags) && sigd) {
                        schedule();
-                       prepare_to_wait(sk->sk_sleep, &wait, TASK_UNINTERRUPTIBLE);
+                       prepare_to_wait(sk->sk_sleep, &wait,
+                                       TASK_UNINTERRUPTIBLE);
                }
                finish_wait(sk->sk_sleep, &wait);
        }
@@ -61,35 +63,35 @@ static void svc_disconnect(struct atm_vcc *vcc)
        while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) {
                atm_return(vcc, skb->truesize);
                pr_debug("LISTEN REL\n");
-               sigd_enq2(NULL,as_reject,vcc,NULL,NULL,&vcc->qos,0);
+               sigd_enq2(NULL, as_reject, vcc, NULL, NULL, &vcc->qos, 0);
                dev_kfree_skb(skb);
        }
        clear_bit(ATM_VF_REGIS, &vcc->flags);
        /* ... may retry later */
 }
 
-
 static int svc_release(struct socket *sock)
 {
        struct sock *sk = sock->sk;
        struct atm_vcc *vcc;
 
-       if (sk)  {
+       if (sk) {
                vcc = ATM_SD(sock);
-               pr_debug("svc_release %p\n", vcc);
+               pr_debug("%p\n", vcc);
                clear_bit(ATM_VF_READY, &vcc->flags);
-               /* VCC pointer is used as a reference, so we must not free it
-                  (thereby subjecting it to re-use) before all pending connections
-                  are closed */
+               /*
+                * VCC pointer is used as a reference,
+                * so we must not free it (thereby subjecting it to re-use)
+                * before all pending connections are closed
+                */
                svc_disconnect(vcc);
                vcc_release(sock);
        }
        return 0;
 }
 
-
-static int svc_bind(struct socket *sock,struct sockaddr *sockaddr,
-    int sockaddr_len)
+static int svc_bind(struct socket *sock, struct sockaddr *sockaddr,
+                   int sockaddr_len)
 {
        DEFINE_WAIT(wait);
        struct sock *sk = sock->sk;
@@ -114,38 +116,37 @@ static int svc_bind(struct socket *sock,struct sockaddr *sockaddr,
                error = -EAFNOSUPPORT;
                goto out;
        }
-       clear_bit(ATM_VF_BOUND,&vcc->flags);
+       clear_bit(ATM_VF_BOUND, &vcc->flags);
            /* failing rebind will kill old binding */
        /* @@@ check memory (de)allocation on rebind */
-       if (!test_bit(ATM_VF_HASQOS,&vcc->flags)) {
+       if (!test_bit(ATM_VF_HASQOS, &vcc->flags)) {
                error = -EBADFD;
                goto out;
        }
        vcc->local = *addr;
        set_bit(ATM_VF_WAITING, &vcc->flags);
        prepare_to_wait(sk->sk_sleep, &wait, TASK_UNINTERRUPTIBLE);
-       sigd_enq(vcc,as_bind,NULL,NULL,&vcc->local);
+       sigd_enq(vcc, as_bind, NULL, NULL, &vcc->local);
        while (test_bit(ATM_VF_WAITING, &vcc->flags) && sigd) {
                schedule();
                prepare_to_wait(sk->sk_sleep, &wait, TASK_UNINTERRUPTIBLE);
        }
        finish_wait(sk->sk_sleep, &wait);
-       clear_bit(ATM_VF_REGIS,&vcc->flags); /* doesn't count */
+       clear_bit(ATM_VF_REGIS, &vcc->flags); /* doesn't count */
        if (!sigd) {
                error = -EUNATCH;
                goto out;
        }
        if (!sk->sk_err)
-               set_bit(ATM_VF_BOUND,&vcc->flags);
+               set_bit(ATM_VF_BOUND, &vcc->flags);
        error = -sk->sk_err;
 out:
        release_sock(sk);
        return error;
 }
 
-
-static int svc_connect(struct socket *sock,struct sockaddr *sockaddr,
-    int sockaddr_len,int flags)
+static int svc_connect(struct socket *sock, struct sockaddr *sockaddr,
+                      int sockaddr_len, int flags)
 {
        DEFINE_WAIT(wait);
        struct sock *sk = sock->sk;
@@ -153,7 +154,7 @@ static int svc_connect(struct socket *sock,struct sockaddr *sockaddr,
        struct atm_vcc *vcc = ATM_SD(sock);
        int error;
 
-       pr_debug("svc_connect %p\n",vcc);
+       pr_debug("%p\n", vcc);
        lock_sock(sk);
        if (sockaddr_len != sizeof(struct sockaddr_atmsvc)) {
                error = -EINVAL;
@@ -201,7 +202,7 @@ static int svc_connect(struct socket *sock,struct sockaddr *sockaddr,
                vcc->remote = *addr;
                set_bit(ATM_VF_WAITING, &vcc->flags);
                prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
-               sigd_enq(vcc,as_connect,NULL,NULL,&vcc->remote);
+               sigd_enq(vcc, as_connect, NULL, NULL, &vcc->remote);
                if (flags & O_NONBLOCK) {
                        finish_wait(sk->sk_sleep, &wait);
                        sock->state = SS_CONNECTING;
@@ -212,7 +213,8 @@ static int svc_connect(struct socket *sock,struct sockaddr *sockaddr,
                while (test_bit(ATM_VF_WAITING, &vcc->flags) && sigd) {
                        schedule();
                        if (!signal_pending(current)) {
-                               prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
+                               prepare_to_wait(sk->sk_sleep, &wait,
+                                               TASK_INTERRUPTIBLE);
                                continue;
                        }
                        pr_debug("*ABORT*\n");
@@ -228,20 +230,22 @@ static int svc_connect(struct socket *sock,struct sockaddr *sockaddr,
                         *   Kernel <--okay---- Demon
                         *   Kernel <--close--- Demon
                         */
-                       sigd_enq(vcc,as_close,NULL,NULL,NULL);
+                       sigd_enq(vcc, as_close, NULL, NULL, NULL);
                        while (test_bit(ATM_VF_WAITING, &vcc->flags) && sigd) {
-                               prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
+                               prepare_to_wait(sk->sk_sleep, &wait,
+                                               TASK_INTERRUPTIBLE);
                                schedule();
                        }
                        if (!sk->sk_err)
-                               while (!test_bit(ATM_VF_RELEASED,&vcc->flags)
-                                   && sigd) {
-                                       prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
+                               while (!test_bit(ATM_VF_RELEASED, &vcc->flags) &&
+                                      sigd) {
+                                       prepare_to_wait(sk->sk_sleep, &wait,
+                                                       TASK_INTERRUPTIBLE);
                                        schedule();
                                }
-                       clear_bit(ATM_VF_REGIS,&vcc->flags);
-                       clear_bit(ATM_VF_RELEASED,&vcc->flags);
-                       clear_bit(ATM_VF_CLOSE,&vcc->flags);
+                       clear_bit(ATM_VF_REGIS, &vcc->flags);
+                       clear_bit(ATM_VF_RELEASED, &vcc->flags);
+                       clear_bit(ATM_VF_CLOSE, &vcc->flags);
                            /* we're gone now but may connect later */
                        error = -EINTR;
                        break;
@@ -269,37 +273,37 @@ static int svc_connect(struct socket *sock,struct sockaddr *sockaddr,
 /*
  * #endif
  */
-       if (!(error = vcc_connect(sock, vcc->itf, vcc->vpi, vcc->vci)))
+       error = vcc_connect(sock, vcc->itf, vcc->vpi, vcc->vci);
+       if (!error)
                sock->state = SS_CONNECTED;
        else
-               (void) svc_disconnect(vcc);
+               (void)svc_disconnect(vcc);
 out:
        release_sock(sk);
        return error;
 }
 
-
-static int svc_listen(struct socket *sock,int backlog)
+static int svc_listen(struct socket *sock, int backlog)
 {
        DEFINE_WAIT(wait);
        struct sock *sk = sock->sk;
        struct atm_vcc *vcc = ATM_SD(sock);
        int error;
 
-       pr_debug("svc_listen %p\n",vcc);
+       pr_debug("%p\n", vcc);
        lock_sock(sk);
        /* let server handle listen on unbound sockets */
-       if (test_bit(ATM_VF_SESSION,&vcc->flags)) {
+       if (test_bit(ATM_VF_SESSION, &vcc->flags)) {
                error = -EINVAL;
                goto out;
        }
        if (test_bit(ATM_VF_LISTEN, &vcc->flags)) {
                error = -EADDRINUSE;
                goto out;
-        }
+       }
        set_bit(ATM_VF_WAITING, &vcc->flags);
        prepare_to_wait(sk->sk_sleep, &wait, TASK_UNINTERRUPTIBLE);
-       sigd_enq(vcc,as_listen,NULL,NULL,&vcc->local);
+       sigd_enq(vcc, as_listen, NULL, NULL, &vcc->local);
        while (test_bit(ATM_VF_WAITING, &vcc->flags) && sigd) {
                schedule();
                prepare_to_wait(sk->sk_sleep, &wait, TASK_UNINTERRUPTIBLE);
@@ -309,7 +313,7 @@ static int svc_listen(struct socket *sock,int backlog)
                error = -EUNATCH;
                goto out;
        }
-       set_bit(ATM_VF_LISTEN,&vcc->flags);
+       set_bit(ATM_VF_LISTEN, &vcc->flags);
        vcc_insert_socket(sk);
        sk->sk_max_ack_backlog = backlog > 0 ? backlog : ATM_BACKLOG_DEFAULT;
        error = -sk->sk_err;
@@ -318,8 +322,7 @@ out:
        return error;
 }
 
-
-static int svc_accept(struct socket *sock,struct socket *newsock,int flags)
+static int svc_accept(struct socket *sock, struct socket *newsock, int flags)
 {
        struct sock *sk = sock->sk;
        struct sk_buff *skb;
@@ -336,15 +339,16 @@ static int svc_accept(struct socket *sock,struct socket *newsock,int flags)
 
        new_vcc = ATM_SD(newsock);
 
-       pr_debug("svc_accept %p -> %p\n",old_vcc,new_vcc);
+       pr_debug("%p -> %p\n", old_vcc, new_vcc);
        while (1) {
                DEFINE_WAIT(wait);
 
                prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
                while (!(skb = skb_dequeue(&sk->sk_receive_queue)) &&
                       sigd) {
-                       if (test_bit(ATM_VF_RELEASED,&old_vcc->flags)) break;
-                       if (test_bit(ATM_VF_CLOSE,&old_vcc->flags)) {
+                       if (test_bit(ATM_VF_RELEASED, &old_vcc->flags))
+                               break;
+                       if (test_bit(ATM_VF_CLOSE, &old_vcc->flags)) {
                                error = -sk->sk_err;
                                break;
                        }
@@ -359,7 +363,8 @@ static int svc_accept(struct socket *sock,struct socket *newsock,int flags)
                                error = -ERESTARTSYS;
                                break;
                        }
-                       prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
+                       prepare_to_wait(sk->sk_sleep, &wait,
+                                       TASK_INTERRUPTIBLE);
                }
                finish_wait(sk->sk_sleep, &wait);
                if (error)
@@ -368,31 +373,34 @@ static int svc_accept(struct socket *sock,struct socket *newsock,int flags)
                        error = -EUNATCH;
                        goto out;
                }
-               msg = (struct atmsvc_msg *) skb->data;
+               msg = (struct atmsvc_msg *)skb->data;
                new_vcc->qos = msg->qos;
-               set_bit(ATM_VF_HASQOS,&new_vcc->flags);
+               set_bit(ATM_VF_HASQOS, &new_vcc->flags);
                new_vcc->remote = msg->svc;
                new_vcc->local = msg->local;
                new_vcc->sap = msg->sap;
                error = vcc_connect(newsock, msg->pvc.sap_addr.itf,
-                                   msg->pvc.sap_addr.vpi, msg->pvc.sap_addr.vci);
+                                   msg->pvc.sap_addr.vpi,
+                                   msg->pvc.sap_addr.vci);
                dev_kfree_skb(skb);
                sk->sk_ack_backlog--;
                if (error) {
-                       sigd_enq2(NULL,as_reject,old_vcc,NULL,NULL,
-                           &old_vcc->qos,error);
+                       sigd_enq2(NULL, as_reject, old_vcc, NULL, NULL,
+                                 &old_vcc->qos, error);
                        error = error == -EAGAIN ? -EBUSY : error;
                        goto out;
                }
                /* wait should be short, so we ignore the non-blocking flag */
                set_bit(ATM_VF_WAITING, &new_vcc->flags);
-               prepare_to_wait(sk_atm(new_vcc)->sk_sleep, &wait, TASK_UNINTERRUPTIBLE);
-               sigd_enq(new_vcc,as_accept,old_vcc,NULL,NULL);
+               prepare_to_wait(sk_atm(new_vcc)->sk_sleep, &wait,
+                               TASK_UNINTERRUPTIBLE);
+               sigd_enq(new_vcc, as_accept, old_vcc, NULL, NULL);
                while (test_bit(ATM_VF_WAITING, &new_vcc->flags) && sigd) {
                        release_sock(sk);
                        schedule();
                        lock_sock(sk);
-                       prepare_to_wait(sk_atm(new_vcc)->sk_sleep, &wait, TASK_UNINTERRUPTIBLE);
+                       prepare_to_wait(sk_atm(new_vcc)->sk_sleep, &wait,
+                                       TASK_UNINTERRUPTIBLE);
                }
                finish_wait(sk_atm(new_vcc)->sk_sleep, &wait);
                if (!sigd) {
@@ -412,39 +420,37 @@ out:
        return error;
 }
 
-
-static int svc_getname(struct socket *sock,struct sockaddr *sockaddr,
-    int *sockaddr_len,int peer)
+static int svc_getname(struct socket *sock, struct sockaddr *sockaddr,
+                      int *sockaddr_len, int peer)
 {
        struct sockaddr_atmsvc *addr;
 
        *sockaddr_len = sizeof(struct sockaddr_atmsvc);
        addr = (struct sockaddr_atmsvc *) sockaddr;
-       memcpy(addr,peer ? &ATM_SD(sock)->remote : &ATM_SD(sock)->local,
-           sizeof(struct sockaddr_atmsvc));
+       memcpy(addr, peer ? &ATM_SD(sock)->remote : &ATM_SD(sock)->local,
+              sizeof(struct sockaddr_atmsvc));
        return 0;
 }
 
-
-int svc_change_qos(struct atm_vcc *vcc,struct atm_qos *qos)
+int svc_change_qos(struct atm_vcc *vcc, struct atm_qos *qos)
 {
        struct sock *sk = sk_atm(vcc);
        DEFINE_WAIT(wait);
 
        set_bit(ATM_VF_WAITING, &vcc->flags);
        prepare_to_wait(sk->sk_sleep, &wait, TASK_UNINTERRUPTIBLE);
-       sigd_enq2(vcc,as_modify,NULL,NULL,&vcc->local,qos,0);
+       sigd_enq2(vcc, as_modify, NULL, NULL, &vcc->local, qos, 0);
        while (test_bit(ATM_VF_WAITING, &vcc->flags) &&
               !test_bit(ATM_VF_RELEASED, &vcc->flags) && sigd) {
                schedule();
                prepare_to_wait(sk->sk_sleep, &wait, TASK_UNINTERRUPTIBLE);
        }
        finish_wait(sk->sk_sleep, &wait);
-       if (!sigd) return -EUNATCH;
+       if (!sigd)
+               return -EUNATCH;
        return -sk->sk_err;
 }
 
-
 static int svc_setsockopt(struct socket *sock, int level, int optname,
                          char __user *optval, unsigned int optlen)
 {
@@ -454,37 +460,35 @@ static int svc_setsockopt(struct socket *sock, int level, int optname,
 
        lock_sock(sk);
        switch (optname) {
-               case SO_ATMSAP:
-                       if (level != SOL_ATM || optlen != sizeof(struct atm_sap)) {
-                               error = -EINVAL;
-                               goto out;
-                       }
-                       if (copy_from_user(&vcc->sap, optval, optlen)) {
-                               error = -EFAULT;
-                               goto out;
-                       }
-                       set_bit(ATM_VF_HASSAP, &vcc->flags);
-                       break;
-               case SO_MULTIPOINT:
-                       if (level != SOL_ATM || optlen != sizeof(int)) {
-                               error = -EINVAL;
-                               goto out;
-                       }
-                       if (get_user(value, (int __user *) optval)) {
-                               error = -EFAULT;
-                               goto out;
-                       }
-                       if (value == 1) {
-                               set_bit(ATM_VF_SESSION, &vcc->flags);
-                       } else if (value == 0) {
-                               clear_bit(ATM_VF_SESSION, &vcc->flags);
-                       } else {
-                               error = -EINVAL;
-                       }
-                       break;
-               default:
-                       error = vcc_setsockopt(sock, level, optname,
-                                              optval, optlen);
+       case SO_ATMSAP:
+               if (level != SOL_ATM || optlen != sizeof(struct atm_sap)) {
+                       error = -EINVAL;
+                       goto out;
+               }
+               if (copy_from_user(&vcc->sap, optval, optlen)) {
+                       error = -EFAULT;
+                       goto out;
+               }
+               set_bit(ATM_VF_HASSAP, &vcc->flags);
+               break;
+       case SO_MULTIPOINT:
+               if (level != SOL_ATM || optlen != sizeof(int)) {
+                       error = -EINVAL;
+                       goto out;
+               }
+               if (get_user(value, (int __user *)optval)) {
+                       error = -EFAULT;
+                       goto out;
+               }
+               if (value == 1)
+                       set_bit(ATM_VF_SESSION, &vcc->flags);
+               else if (value == 0)
+                       clear_bit(ATM_VF_SESSION, &vcc->flags);
+               else
+                       error = -EINVAL;
+               break;
+       default:
+               error = vcc_setsockopt(sock, level, optname, optval, optlen);
        }
 
 out:
@@ -492,9 +496,8 @@ out:
        return error;
 }
 
-
-static int svc_getsockopt(struct socket *sock,int level,int optname,
-    char __user *optval,int __user *optlen)
+static int svc_getsockopt(struct socket *sock, int level, int optname,
+                         char __user *optval, int __user *optlen)
 {
        struct sock *sk = sock->sk;
        int error = 0, len;
@@ -521,7 +524,6 @@ out:
        return error;
 }
 
-
 static int svc_addparty(struct socket *sock, struct sockaddr *sockaddr,
                        int sockaddr_len, int flags)
 {
@@ -540,7 +542,7 @@ static int svc_addparty(struct socket *sock, struct sockaddr *sockaddr,
                error = -EINPROGRESS;
                goto out;
        }
-       pr_debug("svc_addparty added wait queue\n");
+       pr_debug("added wait queue\n");
        while (test_bit(ATM_VF_WAITING, &vcc->flags) && sigd) {
                schedule();
                prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
@@ -552,7 +554,6 @@ out:
        return error;
 }
 
-
 static int svc_dropparty(struct socket *sock, int ep_ref)
 {
        DEFINE_WAIT(wait);
@@ -579,7 +580,6 @@ out:
        return error;
 }
 
-
 static int svc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 {
        int error, ep_ref;
@@ -587,29 +587,31 @@ static int svc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
        struct atm_vcc *vcc = ATM_SD(sock);
 
        switch (cmd) {
-               case ATM_ADDPARTY:
-                       if (!test_bit(ATM_VF_SESSION, &vcc->flags))
-                               return -EINVAL;
-                       if (copy_from_user(&sa, (void __user *) arg, sizeof(sa)))
-                               return -EFAULT;
-                       error = svc_addparty(sock, (struct sockaddr *) &sa, sizeof(sa), 0);
-                       break;
-               case ATM_DROPPARTY:
-                       if (!test_bit(ATM_VF_SESSION, &vcc->flags))
-                               return -EINVAL;
-                       if (copy_from_user(&ep_ref, (void __user *) arg, sizeof(int)))
-                               return -EFAULT;
-                       error = svc_dropparty(sock, ep_ref);
-                       break;
-               default:
-                       error = vcc_ioctl(sock, cmd, arg);
+       case ATM_ADDPARTY:
+               if (!test_bit(ATM_VF_SESSION, &vcc->flags))
+                       return -EINVAL;
+               if (copy_from_user(&sa, (void __user *) arg, sizeof(sa)))
+                       return -EFAULT;
+               error = svc_addparty(sock, (struct sockaddr *)&sa, sizeof(sa),
+                                    0);
+               break;
+       case ATM_DROPPARTY:
+               if (!test_bit(ATM_VF_SESSION, &vcc->flags))
+                       return -EINVAL;
+               if (copy_from_user(&ep_ref, (void __user *) arg, sizeof(int)))
+                       return -EFAULT;
+               error = svc_dropparty(sock, ep_ref);
+               break;
+       default:
+               error = vcc_ioctl(sock, cmd, arg);
        }
 
        return error;
 }
 
 #ifdef CONFIG_COMPAT
-static int svc_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+static int svc_compat_ioctl(struct socket *sock, unsigned int cmd,
+                           unsigned long arg)
 {
        /* The definition of ATM_ADDPARTY uses the size of struct atm_iobuf.
           But actually it takes a struct sockaddr_atmsvc, which doesn't need
@@ -660,13 +662,13 @@ static int svc_create(struct net *net, struct socket *sock, int protocol,
 
        sock->ops = &svc_proto_ops;
        error = vcc_create(net, sock, protocol, AF_ATMSVC);
-       if (error) return error;
+       if (error)
+               return error;
        ATM_SD(sock)->local.sas_family = AF_ATMSVC;
        ATM_SD(sock)->remote.sas_family = AF_ATMSVC;
        return 0;
 }
 
-
 static const struct net_proto_family svc_family_ops = {
        .family = PF_ATMSVC,
        .create = svc_create,
index 97f8d68d574daf16880a08b4396d7e1c604c7c93..3487cfe74aecad8d69f007db8e23537226ff3d3a 100644 (file)
@@ -21,7 +21,8 @@
 */
 
 #include <linux/module.h>
-
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
@@ -516,33 +517,37 @@ static char *cmtp_procinfo(struct capi_ctr *ctrl)
        return "CAPI Message Transport Protocol";
 }
 
-static int cmtp_ctr_read_proc(char *page, char **start, off_t off, int count, int *eof, struct capi_ctr *ctrl)
+static int cmtp_proc_show(struct seq_file *m, void *v)
 {
+       struct capi_ctr *ctrl = m->private;
        struct cmtp_session *session = ctrl->driverdata;
        struct cmtp_application *app;
        struct list_head *p, *n;
-       int len = 0;
 
-       len += sprintf(page + len, "%s\n\n", cmtp_procinfo(ctrl));
-       len += sprintf(page + len, "addr %s\n", session->name);
-       len += sprintf(page + len, "ctrl %d\n", session->num);
+       seq_printf(m, "%s\n\n", cmtp_procinfo(ctrl));
+       seq_printf(m, "addr %s\n", session->name);
+       seq_printf(m, "ctrl %d\n", session->num);
 
        list_for_each_safe(p, n, &session->applications) {
                app = list_entry(p, struct cmtp_application, list);
-               len += sprintf(page + len, "appl %d -> %d\n", app->appl, app->mapping);
+               seq_printf(m, "appl %d -> %d\n", app->appl, app->mapping);
        }
 
-       if (off + count >= len)
-               *eof = 1;
-
-       if (len < off)
-               return 0;
-
-       *start = page + off;
+       return 0;
+}
 
-       return ((count < len - off) ? count : len - off);
+static int cmtp_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, cmtp_proc_show, PDE(inode)->data);
 }
 
+static const struct file_operations cmtp_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = cmtp_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
 
 int cmtp_attach_device(struct cmtp_session *session)
 {
@@ -582,7 +587,7 @@ int cmtp_attach_device(struct cmtp_session *session)
        session->ctrl.send_message  = cmtp_send_message;
 
        session->ctrl.procinfo      = cmtp_procinfo;
-       session->ctrl.ctr_read_proc = cmtp_ctr_read_proc;
+       session->ctrl.proc_fops = &cmtp_proc_fops;
 
        if (attach_capi_ctr(&session->ctrl) < 0) {
                BT_ERR("Can't attach new controller");
index a2cbe61f6e653842215699ced523d7a0c6b6dfc0..7bc0604069c78f29443739f90997977d1b880d79 100644 (file)
@@ -467,7 +467,7 @@ int br_del_if(struct net_bridge *br, struct net_device *dev)
        return 0;
 }
 
-void br_net_exit(struct net *net)
+void __net_exit br_net_exit(struct net *net)
 {
        struct net_device *dev;
        LIST_HEAD(list);
index 51adc4c2b86036cbccde3024d27482e9ad8b94d4..702be5a2c956fd3e14ed8b7caadf3a3a9a07fbf1 100644 (file)
@@ -77,8 +77,8 @@ static int stats_timer __read_mostly = 1;
 module_param(stats_timer, int, S_IRUGO);
 MODULE_PARM_DESC(stats_timer, "enable timer for statistics (default:on)");
 
-HLIST_HEAD(can_rx_dev_list);
-static struct dev_rcv_lists can_rx_alldev_list;
+/* receive filters subscribed for 'all' CAN devices */
+struct dev_rcv_lists can_rx_alldev_list;
 static DEFINE_SPINLOCK(can_rcvlists_lock);
 
 static struct kmem_cache *rcv_cache __read_mostly;
@@ -292,28 +292,10 @@ EXPORT_SYMBOL(can_send);
 
 static struct dev_rcv_lists *find_dev_rcv_lists(struct net_device *dev)
 {
-       struct dev_rcv_lists *d = NULL;
-       struct hlist_node *n;
-
-       /*
-        * find receive list for this device
-        *
-        * The hlist_for_each_entry*() macros curse through the list
-        * using the pointer variable n and set d to the containing
-        * struct in each list iteration.  Therefore, after list
-        * iteration, d is unmodified when the list is empty, and it
-        * points to last list element, when the list is non-empty
-        * but no match in the loop body is found.  I.e. d is *not*
-        * NULL when no match is found.  We can, however, use the
-        * cursor variable n to decide if a match was found.
-        */
-
-       hlist_for_each_entry_rcu(d, n, &can_rx_dev_list, list) {
-               if (d->dev == dev)
-                       break;
-       }
-
-       return n ? d : NULL;
+       if (!dev)
+               return &can_rx_alldev_list;
+       else
+               return (struct dev_rcv_lists *)dev->ml_priv;
 }
 
 /**
@@ -433,6 +415,9 @@ int can_rx_register(struct net_device *dev, canid_t can_id, canid_t mask,
 
        /* insert new receiver  (dev,canid,mask) -> (func,data) */
 
+       if (dev && dev->type != ARPHRD_CAN)
+               return -ENODEV;
+
        r = kmem_cache_alloc(rcv_cache, GFP_KERNEL);
        if (!r)
                return -ENOMEM;
@@ -467,16 +452,6 @@ int can_rx_register(struct net_device *dev, canid_t can_id, canid_t mask,
 }
 EXPORT_SYMBOL(can_rx_register);
 
-/*
- * can_rx_delete_device - rcu callback for dev_rcv_lists structure removal
- */
-static void can_rx_delete_device(struct rcu_head *rp)
-{
-       struct dev_rcv_lists *d = container_of(rp, struct dev_rcv_lists, rcu);
-
-       kfree(d);
-}
-
 /*
  * can_rx_delete_receiver - rcu callback for single receiver entry removal
  */
@@ -506,6 +481,9 @@ void can_rx_unregister(struct net_device *dev, canid_t can_id, canid_t mask,
        struct hlist_node *next;
        struct dev_rcv_lists *d;
 
+       if (dev && dev->type != ARPHRD_CAN)
+               return;
+
        spin_lock(&can_rcvlists_lock);
 
        d = find_dev_rcv_lists(dev);
@@ -541,7 +519,6 @@ void can_rx_unregister(struct net_device *dev, canid_t can_id, canid_t mask,
                       "dev %s, id %03X, mask %03X\n",
                       DNAME(dev), can_id, mask);
                r = NULL;
-               d = NULL;
                goto out;
        }
 
@@ -552,10 +529,10 @@ void can_rx_unregister(struct net_device *dev, canid_t can_id, canid_t mask,
                can_pstats.rcv_entries--;
 
        /* remove device structure requested by NETDEV_UNREGISTER */
-       if (d->remove_on_zero_entries && !d->entries)
-               hlist_del_rcu(&d->list);
-       else
-               d = NULL;
+       if (d->remove_on_zero_entries && !d->entries) {
+               kfree(d);
+               dev->ml_priv = NULL;
+       }
 
  out:
        spin_unlock(&can_rcvlists_lock);
@@ -563,10 +540,6 @@ void can_rx_unregister(struct net_device *dev, canid_t can_id, canid_t mask,
        /* schedule the receiver item for deletion */
        if (r)
                call_rcu(&r->rcu, can_rx_delete_receiver);
-
-       /* schedule the device structure for deletion */
-       if (d)
-               call_rcu(&d->rcu, can_rx_delete_device);
 }
 EXPORT_SYMBOL(can_rx_unregister);
 
@@ -780,48 +753,35 @@ static int can_notifier(struct notifier_block *nb, unsigned long msg,
 
        case NETDEV_REGISTER:
 
-               /*
-                * create new dev_rcv_lists for this device
-                *
-                * N.B. zeroing the struct is the correct initialization
-                * for the embedded hlist_head structs.
-                * Another list type, e.g. list_head, would require
-                * explicit initialization.
-                */
-
+               /* create new dev_rcv_lists for this device */
                d = kzalloc(sizeof(*d), GFP_KERNEL);
                if (!d) {
                        printk(KERN_ERR
                               "can: allocation of receive list failed\n");
                        return NOTIFY_DONE;
                }
-               d->dev = dev;
-
-               spin_lock(&can_rcvlists_lock);
-               hlist_add_head_rcu(&d->list, &can_rx_dev_list);
-               spin_unlock(&can_rcvlists_lock);
+               BUG_ON(dev->ml_priv);
+               dev->ml_priv = d;
 
                break;
 
        case NETDEV_UNREGISTER:
                spin_lock(&can_rcvlists_lock);
 
-               d = find_dev_rcv_lists(dev);
+               d = dev->ml_priv;
                if (d) {
-                       if (d->entries) {
+                       if (d->entries)
                                d->remove_on_zero_entries = 1;
-                               d = NULL;
-                       } else
-                               hlist_del_rcu(&d->list);
+                       else {
+                               kfree(d);
+                               dev->ml_priv = NULL;
+                       }
                } else
                        printk(KERN_ERR "can: notifier: receive list not "
                               "found for dev %s\n", dev->name);
 
                spin_unlock(&can_rcvlists_lock);
 
-               if (d)
-                       call_rcu(&d->rcu, can_rx_delete_device);
-
                break;
        }
 
@@ -853,21 +813,13 @@ static __init int can_init(void)
 {
        printk(banner);
 
+       memset(&can_rx_alldev_list, 0, sizeof(can_rx_alldev_list));
+
        rcv_cache = kmem_cache_create("can_receiver", sizeof(struct receiver),
                                      0, 0, NULL);
        if (!rcv_cache)
                return -ENOMEM;
 
-       /*
-        * Insert can_rx_alldev_list for reception on all devices.
-        * This struct is zero initialized which is correct for the
-        * embedded hlist heads, the dev pointer, and the entries counter.
-        */
-
-       spin_lock(&can_rcvlists_lock);
-       hlist_add_head_rcu(&can_rx_alldev_list.list, &can_rx_dev_list);
-       spin_unlock(&can_rcvlists_lock);
-
        if (stats_timer) {
                /* the statistics are updated every second (timer triggered) */
                setup_timer(&can_stattimer, can_stat_update, 0);
@@ -887,8 +839,7 @@ static __init int can_init(void)
 
 static __exit void can_exit(void)
 {
-       struct dev_rcv_lists *d;
-       struct hlist_node *n, *next;
+       struct net_device *dev;
 
        if (stats_timer)
                del_timer(&can_stattimer);
@@ -900,14 +851,19 @@ static __exit void can_exit(void)
        unregister_netdevice_notifier(&can_netdev_notifier);
        sock_unregister(PF_CAN);
 
-       /* remove can_rx_dev_list */
-       spin_lock(&can_rcvlists_lock);
-       hlist_del(&can_rx_alldev_list.list);
-       hlist_for_each_entry_safe(d, n, next, &can_rx_dev_list, list) {
-               hlist_del(&d->list);
-               kfree(d);
+       /* remove created dev_rcv_lists from still registered CAN devices */
+       rcu_read_lock();
+       for_each_netdev_rcu(&init_net, dev) {
+               if (dev->type == ARPHRD_CAN && dev->ml_priv){
+
+                       struct dev_rcv_lists *d = dev->ml_priv;
+
+                       BUG_ON(d->entries);
+                       kfree(d);
+                       dev->ml_priv = NULL;
+               }
        }
-       spin_unlock(&can_rcvlists_lock);
+       rcu_read_unlock();
 
        rcu_barrier(); /* Wait for completion of call_rcu()'s */
 
index 18f91e37cc30656308f84f109f6b7bff00771d92..34253b84e30f03ea8c5b1aa4de452897309a84c5 100644 (file)
@@ -63,10 +63,8 @@ struct receiver {
 
 enum { RX_ERR, RX_ALL, RX_FIL, RX_INV, RX_EFF, RX_MAX };
 
+/* per device receive filters linked at dev->ml_priv */
 struct dev_rcv_lists {
-       struct hlist_node list;
-       struct rcu_head rcu;
-       struct net_device *dev;
        struct hlist_head rx[RX_MAX];
        struct hlist_head rx_sff[0x800];
        int remove_on_zero_entries;
index 9b9ad29be5670a2ac47e3a041e7bf216d1ec711c..f4265cc9c3fbee335f16f467ac7f0a197e43977c 100644 (file)
@@ -45,6 +45,7 @@
 #include <linux/proc_fs.h>
 #include <linux/list.h>
 #include <linux/rcupdate.h>
+#include <linux/if_arp.h>
 #include <linux/can/core.h>
 
 #include "af_can.h"
@@ -84,6 +85,9 @@ static const char rx_list_name[][8] = {
        [RX_EFF] = "rx_eff",
 };
 
+/* receive filters subscribed for 'all' CAN devices */
+extern struct dev_rcv_lists can_rx_alldev_list;
+
 /*
  * af_can statistics stuff
  */
@@ -190,10 +194,6 @@ void can_stat_update(unsigned long data)
 
 /*
  * proc read functions
- *
- * From known use-cases we expect about 10 entries in a receive list to be
- * printed in the proc_fs. So PAGE_SIZE is definitely enough space here.
- *
  */
 
 static void can_print_rcvlist(struct seq_file *m, struct hlist_head *rx_list,
@@ -202,7 +202,6 @@ static void can_print_rcvlist(struct seq_file *m, struct hlist_head *rx_list,
        struct receiver *r;
        struct hlist_node *n;
 
-       rcu_read_lock();
        hlist_for_each_entry_rcu(r, n, rx_list, list) {
                char *fmt = (r->can_id & CAN_EFF_FLAG)?
                        "   %-5s  %08X  %08x  %08x  %08x  %8ld  %s\n" :
@@ -212,7 +211,6 @@ static void can_print_rcvlist(struct seq_file *m, struct hlist_head *rx_list,
                                (unsigned long)r->func, (unsigned long)r->data,
                                r->matches, r->ident);
        }
-       rcu_read_unlock();
 }
 
 static void can_print_recv_banner(struct seq_file *m)
@@ -346,24 +344,39 @@ static const struct file_operations can_version_proc_fops = {
        .release        = single_release,
 };
 
+static inline void can_rcvlist_proc_show_one(struct seq_file *m, int idx,
+                                            struct net_device *dev,
+                                            struct dev_rcv_lists *d)
+{
+       if (!hlist_empty(&d->rx[idx])) {
+               can_print_recv_banner(m);
+               can_print_rcvlist(m, &d->rx[idx], dev);
+       } else
+               seq_printf(m, "  (%s: no entry)\n", DNAME(dev));
+
+}
+
 static int can_rcvlist_proc_show(struct seq_file *m, void *v)
 {
        /* double cast to prevent GCC warning */
        int idx = (int)(long)m->private;
+       struct net_device *dev;
        struct dev_rcv_lists *d;
-       struct hlist_node *n;
 
        seq_printf(m, "\nreceive list '%s':\n", rx_list_name[idx]);
 
        rcu_read_lock();
-       hlist_for_each_entry_rcu(d, n, &can_rx_dev_list, list) {
 
-               if (!hlist_empty(&d->rx[idx])) {
-                       can_print_recv_banner(m);
-                       can_print_rcvlist(m, &d->rx[idx], d->dev);
-               } else
-                       seq_printf(m, "  (%s: no entry)\n", DNAME(d->dev));
+       /* receive list for 'all' CAN devices (dev == NULL) */
+       d = &can_rx_alldev_list;
+       can_rcvlist_proc_show_one(m, idx, NULL, d);
+
+       /* receive list for registered CAN devices */
+       for_each_netdev_rcu(&init_net, dev) {
+               if (dev->type == ARPHRD_CAN && dev->ml_priv)
+                       can_rcvlist_proc_show_one(m, idx, dev, dev->ml_priv);
        }
+
        rcu_read_unlock();
 
        seq_putc(m, '\n');
@@ -383,34 +396,50 @@ static const struct file_operations can_rcvlist_proc_fops = {
        .release        = single_release,
 };
 
+static inline void can_rcvlist_sff_proc_show_one(struct seq_file *m,
+                                                struct net_device *dev,
+                                                struct dev_rcv_lists *d)
+{
+       int i;
+       int all_empty = 1;
+
+       /* check wether at least one list is non-empty */
+       for (i = 0; i < 0x800; i++)
+               if (!hlist_empty(&d->rx_sff[i])) {
+                       all_empty = 0;
+                       break;
+               }
+
+       if (!all_empty) {
+               can_print_recv_banner(m);
+               for (i = 0; i < 0x800; i++) {
+                       if (!hlist_empty(&d->rx_sff[i]))
+                               can_print_rcvlist(m, &d->rx_sff[i], dev);
+               }
+       } else
+               seq_printf(m, "  (%s: no entry)\n", DNAME(dev));
+}
+
 static int can_rcvlist_sff_proc_show(struct seq_file *m, void *v)
 {
+       struct net_device *dev;
        struct dev_rcv_lists *d;
-       struct hlist_node *n;
 
        /* RX_SFF */
        seq_puts(m, "\nreceive list 'rx_sff':\n");
 
        rcu_read_lock();
-       hlist_for_each_entry_rcu(d, n, &can_rx_dev_list, list) {
-               int i, all_empty = 1;
-               /* check wether at least one list is non-empty */
-               for (i = 0; i < 0x800; i++)
-                       if (!hlist_empty(&d->rx_sff[i])) {
-                               all_empty = 0;
-                               break;
-                       }
-
-               if (!all_empty) {
-                       can_print_recv_banner(m);
-                       for (i = 0; i < 0x800; i++) {
-                               if (!hlist_empty(&d->rx_sff[i]))
-                                       can_print_rcvlist(m, &d->rx_sff[i],
-                                                         d->dev);
-                       }
-               } else
-                       seq_printf(m, "  (%s: no entry)\n", DNAME(d->dev));
+
+       /* sff receive list for 'all' CAN devices (dev == NULL) */
+       d = &can_rx_alldev_list;
+       can_rcvlist_sff_proc_show_one(m, NULL, d);
+
+       /* sff receive list for registered CAN devices */
+       for_each_netdev_rcu(&init_net, dev) {
+               if (dev->type == ARPHRD_CAN && dev->ml_priv)
+                       can_rcvlist_sff_proc_show_one(m, dev, dev->ml_priv);
        }
+
        rcu_read_unlock();
 
        seq_putc(m, '\n');
index be9924f60ec34bafa135916455595e794a7fe86c..2cba5c521e564d97c789a05715d150020331aa5b 100644 (file)
@@ -1853,6 +1853,14 @@ gso:
 
                skb->next = nskb->next;
                nskb->next = NULL;
+
+               /*
+                * If device doesnt need nskb->dst, release it right now while
+                * its hot in this cpu cache
+                */
+               if (dev->priv_flags & IFF_XMIT_DST_RELEASE)
+                       skb_dst_drop(nskb);
+
                rc = ops->ndo_start_xmit(nskb, dev);
                if (unlikely(rc != NETDEV_TX_OK)) {
                        if (rc & ~NETDEV_TX_MASK)
@@ -1974,6 +1982,21 @@ static inline int __dev_xmit_skb(struct sk_buff *skb, struct Qdisc *q,
        return rc;
 }
 
+/*
+ * Returns true if either:
+ *     1. skb has frag_list and the device doesn't support FRAGLIST, or
+ *     2. skb is fragmented and the device does not support SG, or if
+ *        at least one of fragments is in highmem and device does not
+ *        support DMA from it.
+ */
+static inline int skb_needs_linearize(struct sk_buff *skb,
+                                     struct net_device *dev)
+{
+       return (skb_has_frags(skb) && !(dev->features & NETIF_F_FRAGLIST)) ||
+              (skb_shinfo(skb)->nr_frags && (!(dev->features & NETIF_F_SG) ||
+                                             illegal_highdma(dev, skb)));
+}
+
 /**
  *     dev_queue_xmit - transmit a buffer
  *     @skb: buffer to transmit
@@ -2010,18 +2033,8 @@ int dev_queue_xmit(struct sk_buff *skb)
        if (netif_needs_gso(dev, skb))
                goto gso;
 
-       if (skb_has_frags(skb) &&
-           !(dev->features & NETIF_F_FRAGLIST) &&
-           __skb_linearize(skb))
-               goto out_kfree_skb;
-
-       /* Fragmented skb is linearized if device does not support SG,
-        * or if at least one of fragments is in highmem and device
-        * does not support DMA from it.
-        */
-       if (skb_shinfo(skb)->nr_frags &&
-           (!(dev->features & NETIF_F_SG) || illegal_highdma(dev, skb)) &&
-           __skb_linearize(skb))
+       /* Convert a paged skb to linear, if required */
+       if (skb_needs_linearize(skb, dev) && __skb_linearize(skb))
                goto out_kfree_skb;
 
        /* If packet is not checksummed and device does not support
@@ -2422,6 +2435,7 @@ int netif_receive_skb(struct sk_buff *skb)
        struct packet_type *ptype, *pt_prev;
        struct net_device *orig_dev;
        struct net_device *null_or_orig;
+       struct net_device *null_or_bond;
        int ret = NET_RX_DROP;
        __be16 type;
 
@@ -2487,12 +2501,24 @@ ncls:
        if (!skb)
                goto out;
 
+       /*
+        * Make sure frames received on VLAN interfaces stacked on
+        * bonding interfaces still make their way to any base bonding
+        * device that may have registered for a specific ptype.  The
+        * handler may have to adjust skb->dev and orig_dev.
+        */
+       null_or_bond = NULL;
+       if ((skb->dev->priv_flags & IFF_802_1Q_VLAN) &&
+           (vlan_dev_real_dev(skb->dev)->priv_flags & IFF_BONDING)) {
+               null_or_bond = vlan_dev_real_dev(skb->dev);
+       }
+
        type = skb->protocol;
        list_for_each_entry_rcu(ptype,
                        &ptype_base[ntohs(type) & PTYPE_HASH_MASK], list) {
-               if (ptype->type == type &&
-                   (ptype->dev == null_or_orig || ptype->dev == skb->dev ||
-                    ptype->dev == orig_dev)) {
+               if (ptype->type == type && (ptype->dev == null_or_orig ||
+                    ptype->dev == skb->dev || ptype->dev == orig_dev ||
+                    ptype->dev == null_or_bond)) {
                        if (pt_prev)
                                ret = deliver_skb(skb, pt_prev, orig_dev);
                        pt_prev = ptype;
@@ -2561,7 +2587,7 @@ out:
        return netif_receive_skb(skb);
 }
 
-void napi_gro_flush(struct napi_struct *napi)
+static void napi_gro_flush(struct napi_struct *napi)
 {
        struct sk_buff *skb, *next;
 
@@ -2574,7 +2600,6 @@ 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)
 {
@@ -3185,7 +3210,7 @@ static void dev_seq_printf_stats(struct seq_file *seq, struct net_device *dev)
 {
        const struct net_device_stats *stats = dev_get_stats(dev);
 
-       seq_printf(seq, "%6s:%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu "
+       seq_printf(seq, "%6s: %7lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu "
                   "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
                   dev->name, stats->rx_bytes, stats->rx_packets,
                   stats->rx_errors,
@@ -3640,10 +3665,10 @@ void __dev_set_rx_mode(struct net_device *dev)
                /* Unicast addresses changes may only happen under the rtnl,
                 * therefore calling __dev_set_promiscuity here is safe.
                 */
-               if (dev->uc.count > 0 && !dev->uc_promisc) {
+               if (!netdev_uc_empty(dev) && !dev->uc_promisc) {
                        __dev_set_promiscuity(dev, 1);
                        dev->uc_promisc = 1;
-               } else if (dev->uc.count == 0 && dev->uc_promisc) {
+               } else if (netdev_uc_empty(dev) && dev->uc_promisc) {
                        __dev_set_promiscuity(dev, -1);
                        dev->uc_promisc = 0;
                }
index 02a3b2c69c1e9ab7b4dde84f0f70e6dc131de676..9a24377146bf0dc25163e96bfb3c9b6c0701ab40 100644 (file)
@@ -708,7 +708,7 @@ static struct notifier_block fib_rules_notifier = {
        .notifier_call = fib_rules_event,
 };
 
-static int fib_rules_net_init(struct net *net)
+static int __net_init fib_rules_net_init(struct net *net)
 {
        INIT_LIST_HEAD(&net->rules_ops);
        spin_lock_init(&net->rules_mod_lock);
index f35377b643e4e50623d09d3e8e1d2726dda9a0dd..f2efd72da799063e12f1b83096fa0661c8df7a8a 100644 (file)
@@ -2417,8 +2417,7 @@ EXPORT_SYMBOL(neigh_seq_stop);
 
 static void *neigh_stat_seq_start(struct seq_file *seq, loff_t *pos)
 {
-       struct proc_dir_entry *pde = seq->private;
-       struct neigh_table *tbl = pde->data;
+       struct neigh_table *tbl = seq->private;
        int cpu;
 
        if (*pos == 0)
@@ -2435,8 +2434,7 @@ static void *neigh_stat_seq_start(struct seq_file *seq, loff_t *pos)
 
 static void *neigh_stat_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 {
-       struct proc_dir_entry *pde = seq->private;
-       struct neigh_table *tbl = pde->data;
+       struct neigh_table *tbl = seq->private;
        int cpu;
 
        for (cpu = *pos; cpu < nr_cpu_ids; ++cpu) {
@@ -2455,8 +2453,7 @@ static void neigh_stat_seq_stop(struct seq_file *seq, void *v)
 
 static int neigh_stat_seq_show(struct seq_file *seq, void *v)
 {
-       struct proc_dir_entry *pde = seq->private;
-       struct neigh_table *tbl = pde->data;
+       struct neigh_table *tbl = seq->private;
        struct neigh_statistics *st = v;
 
        if (v == SEQ_START_TOKEN) {
@@ -2501,7 +2498,7 @@ static int neigh_stat_seq_open(struct inode *inode, struct file *file)
 
        if (!ret) {
                struct seq_file *sf = file->private_data;
-               sf->private = PDE(inode);
+               sf->private = PDE(inode)->data;
        }
        return ret;
 };
index 0b4d0d35ef40fd1e9899e911cd4e6ff873b96407..7aa6972537658375031c81dd41e31171b0f69084 100644 (file)
@@ -407,11 +407,24 @@ static void arp_reply(struct sk_buff *skb)
        __be32 sip, tip;
        unsigned char *sha;
        struct sk_buff *send_skb;
-       struct netpoll *np = NULL;
+       struct netpoll *np, *tmp;
+       unsigned long flags;
+       int hits = 0;
+
+       if (list_empty(&npinfo->rx_np))
+               return;
+
+       /* Before checking the packet, we do some early
+          inspection whether this is interesting at all */
+       spin_lock_irqsave(&npinfo->rx_lock, flags);
+       list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) {
+               if (np->dev == skb->dev)
+                       hits++;
+       }
+       spin_unlock_irqrestore(&npinfo->rx_lock, flags);
 
-       if (npinfo->rx_np && npinfo->rx_np->dev == skb->dev)
-               np = npinfo->rx_np;
-       if (!np)
+       /* No netpoll struct is using this dev */
+       if (!hits)
                return;
 
        /* No arp on this interface */
@@ -437,77 +450,91 @@ static void arp_reply(struct sk_buff *skb)
        arp_ptr += skb->dev->addr_len;
        memcpy(&sip, arp_ptr, 4);
        arp_ptr += 4;
-       /* if we actually cared about dst hw addr, it would get copied here */
+       /* If we actually cared about dst hw addr,
+          it would get copied here */
        arp_ptr += skb->dev->addr_len;
        memcpy(&tip, arp_ptr, 4);
 
        /* Should we ignore arp? */
-       if (tip != np->local_ip ||
-           ipv4_is_loopback(tip) || ipv4_is_multicast(tip))
+       if (ipv4_is_loopback(tip) || ipv4_is_multicast(tip))
                return;
 
        size = arp_hdr_len(skb->dev);
-       send_skb = find_skb(np, size + LL_ALLOCATED_SPACE(np->dev),
-                           LL_RESERVED_SPACE(np->dev));
 
-       if (!send_skb)
-               return;
-
-       skb_reset_network_header(send_skb);
-       arp = (struct arphdr *) skb_put(send_skb, size);
-       send_skb->dev = skb->dev;
-       send_skb->protocol = htons(ETH_P_ARP);
+       spin_lock_irqsave(&npinfo->rx_lock, flags);
+       list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) {
+               if (tip != np->local_ip)
+                       continue;
 
-       /* Fill the device header for the ARP frame */
-       if (dev_hard_header(send_skb, skb->dev, ptype,
-                           sha, np->dev->dev_addr,
-                           send_skb->len) < 0) {
-               kfree_skb(send_skb);
-               return;
-       }
+               send_skb = find_skb(np, size + LL_ALLOCATED_SPACE(np->dev),
+                                   LL_RESERVED_SPACE(np->dev));
+               if (!send_skb)
+                       continue;
 
-       /*
-        * Fill out the arp protocol part.
-        *
-        * we only support ethernet device type,
-        * which (according to RFC 1390) should always equal 1 (Ethernet).
-        */
+               skb_reset_network_header(send_skb);
+               arp = (struct arphdr *) skb_put(send_skb, size);
+               send_skb->dev = skb->dev;
+               send_skb->protocol = htons(ETH_P_ARP);
 
-       arp->ar_hrd = htons(np->dev->type);
-       arp->ar_pro = htons(ETH_P_IP);
-       arp->ar_hln = np->dev->addr_len;
-       arp->ar_pln = 4;
-       arp->ar_op = htons(type);
+               /* Fill the device header for the ARP frame */
+               if (dev_hard_header(send_skb, skb->dev, ptype,
+                                   sha, np->dev->dev_addr,
+                                   send_skb->len) < 0) {
+                       kfree_skb(send_skb);
+                       continue;
+               }
 
-       arp_ptr=(unsigned char *)(arp + 1);
-       memcpy(arp_ptr, np->dev->dev_addr, np->dev->addr_len);
-       arp_ptr += np->dev->addr_len;
-       memcpy(arp_ptr, &tip, 4);
-       arp_ptr += 4;
-       memcpy(arp_ptr, sha, np->dev->addr_len);
-       arp_ptr += np->dev->addr_len;
-       memcpy(arp_ptr, &sip, 4);
+               /*
+                * Fill out the arp protocol part.
+                *
+                * we only support ethernet device type,
+                * which (according to RFC 1390) should
+                * always equal 1 (Ethernet).
+                */
 
-       netpoll_send_skb(np, send_skb);
+               arp->ar_hrd = htons(np->dev->type);
+               arp->ar_pro = htons(ETH_P_IP);
+               arp->ar_hln = np->dev->addr_len;
+               arp->ar_pln = 4;
+               arp->ar_op = htons(type);
+
+               arp_ptr = (unsigned char *)(arp + 1);
+               memcpy(arp_ptr, np->dev->dev_addr, np->dev->addr_len);
+               arp_ptr += np->dev->addr_len;
+               memcpy(arp_ptr, &tip, 4);
+               arp_ptr += 4;
+               memcpy(arp_ptr, sha, np->dev->addr_len);
+               arp_ptr += np->dev->addr_len;
+               memcpy(arp_ptr, &sip, 4);
+
+               netpoll_send_skb(np, send_skb);
+
+               /* If there are several rx_hooks for the same address,
+                  we're fine by sending a single reply */
+               break;
+       }
+       spin_unlock_irqrestore(&npinfo->rx_lock, flags);
 }
 
 int __netpoll_rx(struct sk_buff *skb)
 {
        int proto, len, ulen;
+       int hits = 0;
        struct iphdr *iph;
        struct udphdr *uh;
-       struct netpoll_info *npi = skb->dev->npinfo;
-       struct netpoll *np = npi->rx_np;
+       struct netpoll_info *npinfo = skb->dev->npinfo;
+       struct netpoll *np, *tmp;
 
-       if (!np)
+       if (list_empty(&npinfo->rx_np))
                goto out;
+
        if (skb->dev->type != ARPHRD_ETHER)
                goto out;
 
        /* check if netpoll clients need ARP */
        if (skb->protocol == htons(ETH_P_ARP) &&
            atomic_read(&trapped)) {
-               skb_queue_tail(&npi->arp_tx, skb);
+               skb_queue_tail(&npinfo->arp_tx, skb);
                return 1;
        }
 
@@ -551,16 +578,23 @@ int __netpoll_rx(struct sk_buff *skb)
                goto out;
        if (checksum_udp(skb, uh, ulen, iph->saddr, iph->daddr))
                goto out;
-       if (np->local_ip && np->local_ip != iph->daddr)
-               goto out;
-       if (np->remote_ip && np->remote_ip != iph->saddr)
-               goto out;
-       if (np->local_port && np->local_port != ntohs(uh->dest))
-               goto out;
 
-       np->rx_hook(np, ntohs(uh->source),
-                   (char *)(uh+1),
-                   ulen - sizeof(struct udphdr));
+       list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) {
+               if (np->local_ip && np->local_ip != iph->daddr)
+                       continue;
+               if (np->remote_ip && np->remote_ip != iph->saddr)
+                       continue;
+               if (np->local_port && np->local_port != ntohs(uh->dest))
+                       continue;
+
+               np->rx_hook(np, ntohs(uh->source),
+                              (char *)(uh+1),
+                              ulen - sizeof(struct udphdr));
+               hits++;
+       }
+
+       if (!hits)
+               goto out;
 
        kfree_skb(skb);
        return 1;
@@ -684,6 +718,7 @@ int netpoll_setup(struct netpoll *np)
        struct net_device *ndev = NULL;
        struct in_device *in_dev;
        struct netpoll_info *npinfo;
+       struct netpoll *npe, *tmp;
        unsigned long flags;
        int err;
 
@@ -704,7 +739,7 @@ int netpoll_setup(struct netpoll *np)
                }
 
                npinfo->rx_flags = 0;
-               npinfo->rx_np = NULL;
+               INIT_LIST_HEAD(&npinfo->rx_np);
 
                spin_lock_init(&npinfo->rx_lock);
                skb_queue_head_init(&npinfo->arp_tx);
@@ -785,7 +820,7 @@ int netpoll_setup(struct netpoll *np)
        if (np->rx_hook) {
                spin_lock_irqsave(&npinfo->rx_lock, flags);
                npinfo->rx_flags |= NETPOLL_RX_ENABLED;
-               npinfo->rx_np = np;
+               list_add_tail(&np->rx, &npinfo->rx_np);
                spin_unlock_irqrestore(&npinfo->rx_lock, flags);
        }
 
@@ -801,9 +836,16 @@ int netpoll_setup(struct netpoll *np)
        return 0;
 
  release:
-       if (!ndev->npinfo)
+       if (!ndev->npinfo) {
+               spin_lock_irqsave(&npinfo->rx_lock, flags);
+               list_for_each_entry_safe(npe, tmp, &npinfo->rx_np, rx) {
+                       npe->dev = NULL;
+               }
+               spin_unlock_irqrestore(&npinfo->rx_lock, flags);
+
                kfree(npinfo);
-       np->dev = NULL;
+       }
+
        dev_put(ndev);
        return err;
 }
@@ -823,10 +865,11 @@ void netpoll_cleanup(struct netpoll *np)
        if (np->dev) {
                npinfo = np->dev->npinfo;
                if (npinfo) {
-                       if (npinfo->rx_np == np) {
+                       if (!list_empty(&npinfo->rx_np)) {
                                spin_lock_irqsave(&npinfo->rx_lock, flags);
-                               npinfo->rx_np = NULL;
-                               npinfo->rx_flags &= ~NETPOLL_RX_ENABLED;
+                               list_del(&np->rx);
+                               if (list_empty(&npinfo->rx_np))
+                                       npinfo->rx_flags &= ~NETPOLL_RX_ENABLED;
                                spin_unlock_irqrestore(&npinfo->rx_lock, flags);
                        }
 
index 794bcb897ff000eeff119df41e72864958b304d3..62f3878a6010645aa273617b2659abab84eae5b9 100644 (file)
@@ -1386,7 +1386,7 @@ static struct notifier_block rtnetlink_dev_notifier = {
 };
 
 
-static int rtnetlink_net_init(struct net *net)
+static int __net_init rtnetlink_net_init(struct net *net)
 {
        struct sock *sk;
        sk = netlink_kernel_create(net, NETLINK_ROUTE, RTNLGRP_MAX,
@@ -1397,7 +1397,7 @@ static int rtnetlink_net_init(struct net *net)
        return 0;
 }
 
-static void rtnetlink_net_exit(struct net *net)
+static void __net_exit rtnetlink_net_exit(struct net *net)
 {
        netlink_kernel_release(net->rtnl);
        net->rtnl = NULL;
index e1f6f225f012eaa513ba556c8833fb85a5b5f575..ceef50bd131b4ea1b2b54ad758496a04060fcdba 100644 (file)
@@ -741,7 +741,7 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
                struct timeval tm;
        } v;
 
-       unsigned int lv = sizeof(int);
+       int lv = sizeof(int);
        int len;
 
        if (get_user(len, optlen))
@@ -2140,13 +2140,13 @@ int sock_prot_inuse_get(struct net *net, struct proto *prot)
 }
 EXPORT_SYMBOL_GPL(sock_prot_inuse_get);
 
-static int sock_inuse_init_net(struct net *net)
+static int __net_init sock_inuse_init_net(struct net *net)
 {
        net->core.inuse = alloc_percpu(struct prot_inuse);
        return net->core.inuse ? 0 : -ENOMEM;
 }
 
-static void sock_inuse_exit_net(struct net *net)
+static void __net_exit sock_inuse_exit_net(struct net *net)
 {
        free_percpu(net->core.inuse);
 }
index dad7bc4878e0eb08631e821f94e89a6066b372cc..b195c4feaa0ae3390fefad4d06e50d43f08acf83 100644 (file)
@@ -996,7 +996,7 @@ static struct inet_protosw dccp_v4_protosw = {
        .flags          = INET_PROTOSW_ICSK,
 };
 
-static int dccp_v4_init_net(struct net *net)
+static int __net_init dccp_v4_init_net(struct net *net)
 {
        int err;
 
@@ -1005,7 +1005,7 @@ static int dccp_v4_init_net(struct net *net)
        return err;
 }
 
-static void dccp_v4_exit_net(struct net *net)
+static void __net_exit dccp_v4_exit_net(struct net *net)
 {
        inet_ctl_sock_destroy(net->dccp.v4_ctl_sk);
 }
index baf05cf43c2879068f86f63abeedfcffb2d30218..1aec6349e8582e5f0d7e7110ec0f857419575e4e 100644 (file)
@@ -1189,7 +1189,7 @@ static struct inet_protosw dccp_v6_protosw = {
        .flags          = INET_PROTOSW_ICSK,
 };
 
-static int dccp_v6_init_net(struct net *net)
+static int __net_init dccp_v6_init_net(struct net *net)
 {
        int err;
 
@@ -1198,7 +1198,7 @@ static int dccp_v6_init_net(struct net *net)
        return err;
 }
 
-static void dccp_v6_exit_net(struct net *net)
+static void __net_exit dccp_v6_exit_net(struct net *net)
 {
        inet_ctl_sock_destroy(net->dccp.v6_ctl_sk);
 }
index dd3db88f8f0a84659017d1c548b6729344a6da8a..205a1c12f3c0475f4c15bd59064e21c3be7b93e9 100644 (file)
@@ -73,8 +73,8 @@ __setup("ether=", netdev_boot_setup);
  * @len:   packet length (<= skb->len)
  *
  *
- * Set the protocol type. For a packet of type ETH_P_802_3 we put the length
- * in here instead. It is up to the 802.2 layer to carry protocol information.
+ * Set the protocol type. For a packet of type ETH_P_802_3/2 we put the length
+ * in here instead.
  */
 int eth_header(struct sk_buff *skb, struct net_device *dev,
               unsigned short type,
@@ -82,7 +82,7 @@ int eth_header(struct sk_buff *skb, struct net_device *dev,
 {
        struct ethhdr *eth = (struct ethhdr *)skb_push(skb, ETH_HLEN);
 
-       if (type != ETH_P_802_3)
+       if (type != ETH_P_802_3 && type != ETH_P_802_2)
                eth->h_proto = htons(type);
        else
                eth->h_proto = htons(len);
index c95cd93acf29beaca13215100c458c1923babbd8..1940b4df76992b810916cc2e9f96b19898979b83 100644 (file)
@@ -70,6 +70,7 @@
  *                                     bonding can change the skb before
  *                                     sending (e.g. insert 8021q tag).
  *             Harald Welte    :       convert to make use of jenkins hash
+ *             Jesper D. Brouer:       Proxy ARP PVLAN RFC 3069 support.
  */
 
 #include <linux/module.h>
@@ -524,12 +525,15 @@ int arp_bind_neighbour(struct dst_entry *dst)
 /*
  * Check if we can use proxy ARP for this path
  */
-
-static inline int arp_fwd_proxy(struct in_device *in_dev, struct rtable *rt)
+static inline int arp_fwd_proxy(struct in_device *in_dev,
+                               struct net_device *dev, struct rtable *rt)
 {
        struct in_device *out_dev;
        int imi, omi = -1;
 
+       if (rt->u.dst.dev == dev)
+               return 0;
+
        if (!IN_DEV_PROXY_ARP(in_dev))
                return 0;
 
@@ -547,6 +551,43 @@ static inline int arp_fwd_proxy(struct in_device *in_dev, struct rtable *rt)
        return (omi != imi && omi != -1);
 }
 
+/*
+ * Check for RFC3069 proxy arp private VLAN (allow to send back to same dev)
+ *
+ * RFC3069 supports proxy arp replies back to the same interface.  This
+ * is done to support (ethernet) switch features, like RFC 3069, where
+ * the individual ports are not allowed to communicate with each
+ * other, BUT they are allowed to talk to the upstream router.  As
+ * described in RFC 3069, it is possible to allow these hosts to
+ * communicate through the upstream router, by proxy_arp'ing.
+ *
+ * RFC 3069: "VLAN Aggregation for Efficient IP Address Allocation"
+ *
+ *  This technology is known by different names:
+ *    In RFC 3069 it is called VLAN Aggregation.
+ *    Cisco and Allied Telesyn call it Private VLAN.
+ *    Hewlett-Packard call it Source-Port filtering or port-isolation.
+ *    Ericsson call it MAC-Forced Forwarding (RFC Draft).
+ *
+ */
+static inline int arp_fwd_pvlan(struct in_device *in_dev,
+                               struct net_device *dev, struct rtable *rt,
+                               __be32 sip, __be32 tip)
+{
+       /* Private VLAN is only concerned about the same ethernet segment */
+       if (rt->u.dst.dev != dev)
+               return 0;
+
+       /* Don't reply on self probes (often done by windowz boxes)*/
+       if (sip == tip)
+               return 0;
+
+       if (IN_DEV_PROXY_ARP_PVLAN(in_dev))
+               return 1;
+       else
+               return 0;
+}
+
 /*
  *     Interface to link layer: send routine and receive handler.
  */
@@ -833,8 +874,11 @@ static int arp_process(struct sk_buff *skb)
                        }
                        goto out;
                } else if (IN_DEV_FORWARD(in_dev)) {
-                           if (addr_type == RTN_UNICAST  && rt->u.dst.dev != dev &&
-                            (arp_fwd_proxy(in_dev, rt) || pneigh_lookup(&arp_tbl, net, &tip, dev, 0))) {
+                       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)))
+                       {
                                n = neigh_event_ns(&arp_tbl, sha, &sip, dev);
                                if (n)
                                        neigh_release(n);
@@ -863,7 +907,8 @@ static int arp_process(struct sk_buff *skb)
                   devices (strip is candidate)
                 */
                if (n == NULL &&
-                   arp->ar_op == htons(ARPOP_REPLY) &&
+                   (arp->ar_op == htons(ARPOP_REPLY) ||
+                    (arp->ar_op == htons(ARPOP_REQUEST) && tip == sip)) &&
                    inet_addr_type(net, sip) == RTN_UNICAST)
                        n = __neigh_lookup(&arp_tbl, &sip, dev, 1);
        }
index 040c4f05b65321b6b2c6023bb0eba66eecb7c26a..cd71a39083910f21580275fd2ee2b6803c115c6c 100644 (file)
@@ -1408,6 +1408,7 @@ static struct devinet_sysctl_table {
                DEVINET_SYSCTL_RW_ENTRY(ARP_IGNORE, "arp_ignore"),
                DEVINET_SYSCTL_RW_ENTRY(ARP_ACCEPT, "arp_accept"),
                DEVINET_SYSCTL_RW_ENTRY(ARP_NOTIFY, "arp_notify"),
+               DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP_PVLAN, "proxy_arp_pvlan"),
 
                DEVINET_SYSCTL_FLUSHING_ENTRY(NOXFRM, "disable_xfrm"),
                DEVINET_SYSCTL_FLUSHING_ENTRY(NOPOLICY, "disable_policy"),
index 82dbf711d6d0ef2a704e6a636131242f379011c8..9b3e28ed524077860c8925894646163fe241f608 100644 (file)
@@ -883,7 +883,7 @@ static void nl_fib_input(struct sk_buff *skb)
        netlink_unicast(net->ipv4.fibnl, skb, pid, MSG_DONTWAIT);
 }
 
-static int nl_fib_lookup_init(struct net *net)
+static int __net_init nl_fib_lookup_init(struct net *net)
 {
        struct sock *sk;
        sk = netlink_kernel_create(net, NETLINK_FIB_LOOKUP, 0,
@@ -1004,7 +1004,7 @@ fail:
        return err;
 }
 
-static void __net_exit ip_fib_net_exit(struct net *net)
+static void ip_fib_net_exit(struct net *net)
 {
        unsigned int i;
 
index ed19aa6919c2fd73f02dafa390fef4093fb8bc34..96b21011a3e49dd422360abeda56baea36562c94 100644 (file)
@@ -62,8 +62,8 @@ static DEFINE_SPINLOCK(fib_multipath_lock);
 #define for_nexthops(fi) { int nhsel; const struct fib_nh * nh; \
 for (nhsel=0, nh = (fi)->fib_nh; nhsel < (fi)->fib_nhs; nh++, nhsel++)
 
-#define change_nexthops(fi) { int nhsel; struct fib_nh * nh; \
-for (nhsel=0, nh = (struct fib_nh *)((fi)->fib_nh); nhsel < (fi)->fib_nhs; nh++, nhsel++)
+#define change_nexthops(fi) { int nhsel; struct fib_nh *nexthop_nh; \
+for (nhsel=0, nexthop_nh = (struct fib_nh *)((fi)->fib_nh); nhsel < (fi)->fib_nhs; nexthop_nh++, nhsel++)
 
 #else /* CONFIG_IP_ROUTE_MULTIPATH */
 
@@ -72,7 +72,7 @@ for (nhsel=0, nh = (struct fib_nh *)((fi)->fib_nh); nhsel < (fi)->fib_nhs; nh++,
 #define for_nexthops(fi) { int nhsel = 0; const struct fib_nh * nh = (fi)->fib_nh; \
 for (nhsel=0; nhsel < 1; nhsel++)
 
-#define change_nexthops(fi) { int nhsel = 0; struct fib_nh * nh = (struct fib_nh *)((fi)->fib_nh); \
+#define change_nexthops(fi) { int nhsel = 0; struct fib_nh *nexthop_nh = (struct fib_nh *)((fi)->fib_nh); \
 for (nhsel=0; nhsel < 1; nhsel++)
 
 #endif /* CONFIG_IP_ROUTE_MULTIPATH */
@@ -145,9 +145,9 @@ void free_fib_info(struct fib_info *fi)
                return;
        }
        change_nexthops(fi) {
-               if (nh->nh_dev)
-                       dev_put(nh->nh_dev);
-               nh->nh_dev = NULL;
+               if (nexthop_nh->nh_dev)
+                       dev_put(nexthop_nh->nh_dev);
+               nexthop_nh->nh_dev = NULL;
        } endfor_nexthops(fi);
        fib_info_cnt--;
        release_net(fi->fib_net);
@@ -162,9 +162,9 @@ void fib_release_info(struct fib_info *fi)
                if (fi->fib_prefsrc)
                        hlist_del(&fi->fib_lhash);
                change_nexthops(fi) {
-                       if (!nh->nh_dev)
+                       if (!nexthop_nh->nh_dev)
                                continue;
-                       hlist_del(&nh->nh_hash);
+                       hlist_del(&nexthop_nh->nh_hash);
                } endfor_nexthops(fi)
                fi->fib_dead = 1;
                fib_info_put(fi);
@@ -395,19 +395,20 @@ static int fib_get_nhs(struct fib_info *fi, struct rtnexthop *rtnh,
                if (!rtnh_ok(rtnh, remaining))
                        return -EINVAL;
 
-               nh->nh_flags = (cfg->fc_flags & ~0xFF) | rtnh->rtnh_flags;
-               nh->nh_oif = rtnh->rtnh_ifindex;
-               nh->nh_weight = rtnh->rtnh_hops + 1;
+               nexthop_nh->nh_flags =
+                       (cfg->fc_flags & ~0xFF) | rtnh->rtnh_flags;
+               nexthop_nh->nh_oif = rtnh->rtnh_ifindex;
+               nexthop_nh->nh_weight = rtnh->rtnh_hops + 1;
 
                attrlen = rtnh_attrlen(rtnh);
                if (attrlen > 0) {
                        struct nlattr *nla, *attrs = rtnh_attrs(rtnh);
 
                        nla = nla_find(attrs, attrlen, RTA_GATEWAY);
-                       nh->nh_gw = nla ? nla_get_be32(nla) : 0;
+                       nexthop_nh->nh_gw = nla ? nla_get_be32(nla) : 0;
 #ifdef CONFIG_NET_CLS_ROUTE
                        nla = nla_find(attrs, attrlen, RTA_FLOW);
-                       nh->nh_tclassid = nla ? nla_get_u32(nla) : 0;
+                       nexthop_nh->nh_tclassid = nla ? nla_get_u32(nla) : 0;
 #endif
                }
 
@@ -738,7 +739,7 @@ struct fib_info *fib_create_info(struct fib_config *cfg)
 
        fi->fib_nhs = nhs;
        change_nexthops(fi) {
-               nh->nh_parent = fi;
+               nexthop_nh->nh_parent = fi;
        } endfor_nexthops(fi)
 
        if (cfg->fc_mx) {
@@ -808,7 +809,7 @@ struct fib_info *fib_create_info(struct fib_config *cfg)
                        goto failure;
        } else {
                change_nexthops(fi) {
-                       if ((err = fib_check_nh(cfg, fi, nh)) != 0)
+                       if ((err = fib_check_nh(cfg, fi, nexthop_nh)) != 0)
                                goto failure;
                } endfor_nexthops(fi)
        }
@@ -843,11 +844,11 @@ link_it:
                struct hlist_head *head;
                unsigned int hash;
 
-               if (!nh->nh_dev)
+               if (!nexthop_nh->nh_dev)
                        continue;
-               hash = fib_devindex_hashfn(nh->nh_dev->ifindex);
+               hash = fib_devindex_hashfn(nexthop_nh->nh_dev->ifindex);
                head = &fib_info_devhash[hash];
-               hlist_add_head(&nh->nh_hash, head);
+               hlist_add_head(&nexthop_nh->nh_hash, head);
        } endfor_nexthops(fi)
        spin_unlock_bh(&fib_info_lock);
        return fi;
@@ -1080,21 +1081,21 @@ int fib_sync_down_dev(struct net_device *dev, int force)
                prev_fi = fi;
                dead = 0;
                change_nexthops(fi) {
-                       if (nh->nh_flags&RTNH_F_DEAD)
+                       if (nexthop_nh->nh_flags&RTNH_F_DEAD)
                                dead++;
-                       else if (nh->nh_dev == dev &&
-                                       nh->nh_scope != scope) {
-                               nh->nh_flags |= RTNH_F_DEAD;
+                       else if (nexthop_nh->nh_dev == dev &&
+                                nexthop_nh->nh_scope != scope) {
+                               nexthop_nh->nh_flags |= RTNH_F_DEAD;
 #ifdef CONFIG_IP_ROUTE_MULTIPATH
                                spin_lock_bh(&fib_multipath_lock);
-                               fi->fib_power -= nh->nh_power;
-                               nh->nh_power = 0;
+                               fi->fib_power -= nexthop_nh->nh_power;
+                               nexthop_nh->nh_power = 0;
                                spin_unlock_bh(&fib_multipath_lock);
 #endif
                                dead++;
                        }
 #ifdef CONFIG_IP_ROUTE_MULTIPATH
-                       if (force > 1 && nh->nh_dev == dev) {
+                       if (force > 1 && nexthop_nh->nh_dev == dev) {
                                dead = fi->fib_nhs;
                                break;
                        }
@@ -1144,18 +1145,20 @@ int fib_sync_up(struct net_device *dev)
                prev_fi = fi;
                alive = 0;
                change_nexthops(fi) {
-                       if (!(nh->nh_flags&RTNH_F_DEAD)) {
+                       if (!(nexthop_nh->nh_flags&RTNH_F_DEAD)) {
                                alive++;
                                continue;
                        }
-                       if (nh->nh_dev == NULL || !(nh->nh_dev->flags&IFF_UP))
+                       if (nexthop_nh->nh_dev == NULL ||
+                           !(nexthop_nh->nh_dev->flags&IFF_UP))
                                continue;
-                       if (nh->nh_dev != dev || !__in_dev_get_rtnl(dev))
+                       if (nexthop_nh->nh_dev != dev ||
+                           !__in_dev_get_rtnl(dev))
                                continue;
                        alive++;
                        spin_lock_bh(&fib_multipath_lock);
-                       nh->nh_power = 0;
-                       nh->nh_flags &= ~RTNH_F_DEAD;
+                       nexthop_nh->nh_power = 0;
+                       nexthop_nh->nh_flags &= ~RTNH_F_DEAD;
                        spin_unlock_bh(&fib_multipath_lock);
                } endfor_nexthops(fi)
 
@@ -1182,9 +1185,9 @@ void fib_select_multipath(const struct flowi *flp, struct fib_result *res)
        if (fi->fib_power <= 0) {
                int power = 0;
                change_nexthops(fi) {
-                       if (!(nh->nh_flags&RTNH_F_DEAD)) {
-                               power += nh->nh_weight;
-                               nh->nh_power = nh->nh_weight;
+                       if (!(nexthop_nh->nh_flags&RTNH_F_DEAD)) {
+                               power += nexthop_nh->nh_weight;
+                               nexthop_nh->nh_power = nexthop_nh->nh_weight;
                        }
                } endfor_nexthops(fi);
                fi->fib_power = power;
@@ -1204,9 +1207,10 @@ void fib_select_multipath(const struct flowi *flp, struct fib_result *res)
        w = jiffies % fi->fib_power;
 
        change_nexthops(fi) {
-               if (!(nh->nh_flags&RTNH_F_DEAD) && nh->nh_power) {
-                       if ((w -= nh->nh_power) <= 0) {
-                               nh->nh_power--;
+               if (!(nexthop_nh->nh_flags&RTNH_F_DEAD) &&
+                   nexthop_nh->nh_power) {
+                       if ((w -= nexthop_nh->nh_power) <= 0) {
+                               nexthop_nh->nh_power--;
                                fi->fib_power--;
                                res->nh_sel = nhsel;
                                spin_unlock_bh(&fib_multipath_lock);
index fe11f60ce41ba645d7f9535e13524419f16dff90..4b4c2bcd15db4b4464be428a954ee8686769b68b 100644 (file)
@@ -114,7 +114,7 @@ struct icmp_bxm {
 /* An array of errno for error messages from dest unreach. */
 /* RFC 1122: 3.2.2.1 States that NET_UNREACH, HOST_UNREACH and SR_FAILED MUST be considered 'transient errs'. */
 
-struct icmp_err icmp_err_convert[] = {
+const struct icmp_err icmp_err_convert[] = {
        {
                .errno = ENETUNREACH,   /* ICMP_NET_UNREACH */
                .fatal = 0,
index 76c08402c933941ea475045545ff3206cc0cadb8..d28363998743a0bf72188695ef1f6db6fa580bdb 100644 (file)
@@ -1799,7 +1799,7 @@ int ip_mc_join_group(struct sock *sk , struct ip_mreqn *imr)
        iml->next = inet->mc_list;
        iml->sflist = NULL;
        iml->sfmode = MCAST_EXCLUDE;
-       inet->mc_list = iml;
+       rcu_assign_pointer(inet->mc_list, iml);
        ip_mc_inc_group(in_dev, addr);
        err = 0;
 done:
@@ -1807,24 +1807,46 @@ done:
        return err;
 }
 
+static void ip_sf_socklist_reclaim(struct rcu_head *rp)
+{
+       struct ip_sf_socklist *psf;
+
+       psf = container_of(rp, struct ip_sf_socklist, rcu);
+       /* sk_omem_alloc should have been decreased by the caller*/
+       kfree(psf);
+}
+
 static int ip_mc_leave_src(struct sock *sk, struct ip_mc_socklist *iml,
                           struct in_device *in_dev)
 {
+       struct ip_sf_socklist *psf = iml->sflist;
        int err;
 
-       if (iml->sflist == NULL) {
+       if (psf == NULL) {
                /* any-source empty exclude case */
                return ip_mc_del_src(in_dev, &iml->multi.imr_multiaddr.s_addr,
                        iml->sfmode, 0, NULL, 0);
        }
        err = ip_mc_del_src(in_dev, &iml->multi.imr_multiaddr.s_addr,
-                       iml->sfmode, iml->sflist->sl_count,
-                       iml->sflist->sl_addr, 0);
-       sock_kfree_s(sk, iml->sflist, IP_SFLSIZE(iml->sflist->sl_max));
-       iml->sflist = NULL;
+                       iml->sfmode, psf->sl_count, psf->sl_addr, 0);
+       rcu_assign_pointer(iml->sflist, NULL);
+       /* decrease mem now to avoid the memleak warning */
+       atomic_sub(IP_SFLSIZE(psf->sl_max), &sk->sk_omem_alloc);
+       call_rcu(&psf->rcu, ip_sf_socklist_reclaim);
        return err;
 }
 
+
+static void ip_mc_socklist_reclaim(struct rcu_head *rp)
+{
+       struct ip_mc_socklist *iml;
+
+       iml = container_of(rp, struct ip_mc_socklist, rcu);
+       /* sk_omem_alloc should have been decreased by the caller*/
+       kfree(iml);
+}
+
+
 /*
  *     Ask a socket to leave a group.
  */
@@ -1854,12 +1876,14 @@ int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr)
 
                (void) ip_mc_leave_src(sk, iml, in_dev);
 
-               *imlp = iml->next;
+               rcu_assign_pointer(*imlp, iml->next);
 
                if (in_dev)
                        ip_mc_dec_group(in_dev, group);
                rtnl_unlock();
-               sock_kfree_s(sk, iml, sizeof(*iml));
+               /* decrease mem now to avoid the memleak warning */
+               atomic_sub(sizeof(*iml), &sk->sk_omem_alloc);
+               call_rcu(&iml->rcu, ip_mc_socklist_reclaim);
                return 0;
        }
        if (!in_dev)
@@ -1974,9 +1998,12 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct
                if (psl) {
                        for (i=0; i<psl->sl_count; i++)
                                newpsl->sl_addr[i] = psl->sl_addr[i];
-                       sock_kfree_s(sk, psl, IP_SFLSIZE(psl->sl_max));
+                       /* decrease mem now to avoid the memleak warning */
+                       atomic_sub(IP_SFLSIZE(psl->sl_max), &sk->sk_omem_alloc);
+                       call_rcu(&psl->rcu, ip_sf_socklist_reclaim);
                }
-               pmc->sflist = psl = newpsl;
+               rcu_assign_pointer(pmc->sflist, newpsl);
+               psl = newpsl;
        }
        rv = 1; /* > 0 for insert logic below if sl_count is 0 */
        for (i=0; i<psl->sl_count; i++) {
@@ -2072,11 +2099,13 @@ int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf, int ifindex)
        if (psl) {
                (void) ip_mc_del_src(in_dev, &msf->imsf_multiaddr, pmc->sfmode,
                        psl->sl_count, psl->sl_addr, 0);
-               sock_kfree_s(sk, psl, IP_SFLSIZE(psl->sl_max));
+               /* decrease mem now to avoid the memleak warning */
+               atomic_sub(IP_SFLSIZE(psl->sl_max), &sk->sk_omem_alloc);
+               call_rcu(&psl->rcu, ip_sf_socklist_reclaim);
        } else
                (void) ip_mc_del_src(in_dev, &msf->imsf_multiaddr, pmc->sfmode,
                        0, NULL, 0);
-       pmc->sflist = newpsl;
+       rcu_assign_pointer(pmc->sflist, newpsl);
        pmc->sfmode = msf->imsf_fmode;
        err = 0;
 done:
@@ -2209,30 +2238,40 @@ int ip_mc_sf_allow(struct sock *sk, __be32 loc_addr, __be32 rmt_addr, int dif)
        struct ip_mc_socklist *pmc;
        struct ip_sf_socklist *psl;
        int i;
+       int ret;
 
+       ret = 1;
        if (!ipv4_is_multicast(loc_addr))
-               return 1;
+               goto out;
 
-       for (pmc=inet->mc_list; pmc; pmc=pmc->next) {
+       rcu_read_lock();
+       for (pmc=rcu_dereference(inet->mc_list); pmc; pmc=rcu_dereference(pmc->next)) {
                if (pmc->multi.imr_multiaddr.s_addr == loc_addr &&
                    pmc->multi.imr_ifindex == dif)
                        break;
        }
+       ret = inet->mc_all;
        if (!pmc)
-               return inet->mc_all;
+               goto unlock;
        psl = pmc->sflist;
+       ret = (pmc->sfmode == MCAST_EXCLUDE);
        if (!psl)
-               return pmc->sfmode == MCAST_EXCLUDE;
+               goto unlock;
 
        for (i=0; i<psl->sl_count; i++) {
                if (psl->sl_addr[i] == rmt_addr)
                        break;
        }
+       ret = 0;
        if (pmc->sfmode == MCAST_INCLUDE && i >= psl->sl_count)
-               return 0;
+               goto unlock;
        if (pmc->sfmode == MCAST_EXCLUDE && i < psl->sl_count)
-               return 0;
-       return 1;
+               goto unlock;
+       ret = 1;
+unlock:
+       rcu_read_unlock();
+out:
+       return ret;
 }
 
 /*
@@ -2251,7 +2290,7 @@ void ip_mc_drop_socket(struct sock *sk)
        rtnl_lock();
        while ((iml = inet->mc_list) != NULL) {
                struct in_device *in_dev;
-               inet->mc_list = iml->next;
+               rcu_assign_pointer(inet->mc_list, iml->next);
 
                in_dev = inetdev_by_index(net, iml->multi.imr_ifindex);
                (void) ip_mc_leave_src(sk, iml, in_dev);
@@ -2259,7 +2298,9 @@ void ip_mc_drop_socket(struct sock *sk)
                        ip_mc_dec_group(in_dev, iml->multi.imr_multiaddr.s_addr);
                        in_dev_put(in_dev);
                }
-               sock_kfree_s(sk, iml, sizeof(*iml));
+               /* decrease mem now to avoid the memleak warning */
+               atomic_sub(sizeof(*iml), &sk->sk_omem_alloc);
+               call_rcu(&iml->rcu, ip_mc_socklist_reclaim);
        }
        rtnl_unlock();
 }
@@ -2603,7 +2644,7 @@ static const struct file_operations igmp_mcf_seq_fops = {
        .release        =       seq_release_net,
 };
 
-static int igmp_net_init(struct net *net)
+static int __net_init igmp_net_init(struct net *net)
 {
        struct proc_dir_entry *pde;
 
@@ -2621,7 +2662,7 @@ out_igmp:
        return -ENOMEM;
 }
 
-static void igmp_net_exit(struct net *net)
+static void __net_exit igmp_net_exit(struct net *net)
 {
        proc_net_remove(net, "mcfilter");
        proc_net_remove(net, "igmp");
index ee16475f8fc33619eea9c9e247f06501e6aad45b..8da6429269dddd922f9c3fb4eda2b86a7bffe0d2 100644 (file)
@@ -529,6 +529,8 @@ void inet_csk_reqsk_queue_prune(struct sock *parent,
                                syn_ack_recalc(req, thresh, max_retries,
                                               queue->rskq_defer_accept,
                                               &expire, &resend);
+                               if (req->rsk_ops->syn_ack_timeout)
+                                       req->rsk_ops->syn_ack_timeout(parent, req);
                                if (!expire &&
                                    (!resend ||
                                     !req->rsk_ops->rtx_syn_ack(parent, req, NULL) ||
index 86964b353c31167fb613be24fd1779e0272ffa57..b59430bc041ca99d4d653e5a1791bd279392ffc5 100644 (file)
@@ -32,6 +32,8 @@
 #include <linux/netdevice.h>
 #include <linux/jhash.h>
 #include <linux/random.h>
+#include <net/route.h>
+#include <net/dst.h>
 #include <net/sock.h>
 #include <net/ip.h>
 #include <net/icmp.h>
@@ -205,11 +207,34 @@ static void ip_expire(unsigned long arg)
        if ((qp->q.last_in & INET_FRAG_FIRST_IN) && qp->q.fragments != NULL) {
                struct sk_buff *head = qp->q.fragments;
 
-               /* Send an ICMP "Fragment Reassembly Timeout" message. */
                rcu_read_lock();
                head->dev = dev_get_by_index_rcu(net, qp->iif);
-               if (head->dev)
-                       icmp_send(head, ICMP_TIME_EXCEEDED, ICMP_EXC_FRAGTIME, 0);
+               if (!head->dev)
+                       goto out_rcu_unlock;
+
+               /*
+                * Only search router table for the head fragment,
+                * when defraging timeout at PRE_ROUTING HOOK.
+                */
+               if (qp->user == IP_DEFRAG_CONNTRACK_IN && !skb_dst(head)) {
+                       const struct iphdr *iph = ip_hdr(head);
+                       int err = ip_route_input(head, iph->daddr, iph->saddr,
+                                                iph->tos, head->dev);
+                       if (unlikely(err))
+                               goto out_rcu_unlock;
+
+                       /*
+                        * Only an end host needs to send an ICMP
+                        * "Fragment Reassembly Timeout" message, per RFC792.
+                        */
+                       if (skb_rtable(head)->rt_type != RTN_LOCAL)
+                               goto out_rcu_unlock;
+
+               }
+
+               /* Send an ICMP "Fragment Reassembly Timeout" message. */
+               icmp_send(head, ICMP_TIME_EXCEEDED, ICMP_EXC_FRAGTIME, 0);
+out_rcu_unlock:
                rcu_read_unlock();
        }
 out:
@@ -646,7 +671,7 @@ static struct ctl_table ip4_frags_ctl_table[] = {
        { }
 };
 
-static int ip4_frags_ns_ctl_register(struct net *net)
+static int __net_init ip4_frags_ns_ctl_register(struct net *net)
 {
        struct ctl_table *table;
        struct ctl_table_header *hdr;
@@ -676,7 +701,7 @@ err_alloc:
        return -ENOMEM;
 }
 
-static void ip4_frags_ns_ctl_unregister(struct net *net)
+static void __net_exit ip4_frags_ns_ctl_unregister(struct net *net)
 {
        struct ctl_table *table;
 
@@ -704,7 +729,7 @@ static inline void ip4_frags_ctl_register(void)
 }
 #endif
 
-static int ipv4_frags_init_net(struct net *net)
+static int __net_init ipv4_frags_init_net(struct net *net)
 {
        /*
         * Fragment cache limits. We will commit 256K at one time. Should we
@@ -726,7 +751,7 @@ static int ipv4_frags_init_net(struct net *net)
        return ip4_frags_ns_ctl_register(net);
 }
 
-static void ipv4_frags_exit_net(struct net *net)
+static void __net_exit ipv4_frags_exit_net(struct net *net)
 {
        ip4_frags_ns_ctl_unregister(net);
        inet_frags_exit_net(&net->ipv4.frags, &ip4_frags);
index f36ce156cac6561da03d032e4f445f772d40b375..7631b20490f52d34dce1686ff48f2391812129b7 100644 (file)
@@ -1307,7 +1307,7 @@ static void ipgre_destroy_tunnels(struct ipgre_net *ign, struct list_head *head)
        }
 }
 
-static int ipgre_init_net(struct net *net)
+static int __net_init ipgre_init_net(struct net *net)
 {
        struct ipgre_net *ign = net_generic(net, ipgre_net_id);
        int err;
@@ -1334,7 +1334,7 @@ err_alloc_dev:
        return err;
 }
 
-static void ipgre_exit_net(struct net *net)
+static void __net_exit ipgre_exit_net(struct net *net)
 {
        struct ipgre_net *ign;
        LIST_HEAD(list);
index cafad9baff039b8c164e2da282a754c6822294a8..644dc43a55dec954dc7232b3edb58c3412951540 100644 (file)
@@ -451,7 +451,8 @@ static int do_ip_setsockopt(struct sock *sk, int level,
                             (1<<IP_TTL) | (1<<IP_HDRINCL) |
                             (1<<IP_MTU_DISCOVER) | (1<<IP_RECVERR) |
                             (1<<IP_ROUTER_ALERT) | (1<<IP_FREEBIND) |
-                            (1<<IP_PASSSEC) | (1<<IP_TRANSPARENT))) ||
+                            (1<<IP_PASSSEC) | (1<<IP_TRANSPARENT) |
+                            (1<<IP_MINTTL))) ||
            optname == IP_MULTICAST_TTL ||
            optname == IP_MULTICAST_ALL ||
            optname == IP_MULTICAST_LOOP ||
@@ -936,6 +937,14 @@ mc_msf_out:
                inet->transparent = !!val;
                break;
 
+       case IP_MINTTL:
+               if (optlen < 1)
+                       goto e_inval;
+               if (val < 0 || val > 255)
+                       goto e_inval;
+               inet->min_ttl = val;
+               break;
+
        default:
                err = -ENOPROTOOPT;
                break;
@@ -1198,6 +1207,9 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname,
        case IP_TRANSPARENT:
                val = inet->transparent;
                break;
+       case IP_MINTTL:
+               val = inet->min_ttl;
+               break;
        default:
                release_sock(sk);
                return -ENOPROTOOPT;
index 38fbf04150ae7ec60ccafa1a4bd740995fb13427..b55a0c3df82f6daeb0cd811e2e9f84b4193dd26e 100644 (file)
@@ -25,6 +25,7 @@
 
 static void ipcomp4_err(struct sk_buff *skb, u32 info)
 {
+       struct net *net = dev_net(skb->dev);
        __be32 spi;
        struct iphdr *iph = (struct iphdr *)skb->data;
        struct ip_comp_hdr *ipch = (struct ip_comp_hdr *)(skb->data+(iph->ihl<<2));
@@ -35,7 +36,7 @@ static void ipcomp4_err(struct sk_buff *skb, u32 info)
                return;
 
        spi = htonl(ntohs(ipch->cpi));
-       x = xfrm_state_lookup(&init_net, (xfrm_address_t *)&iph->daddr,
+       x = xfrm_state_lookup(net, (xfrm_address_t *)&iph->daddr,
                              spi, IPPROTO_COMP, AF_INET);
        if (!x)
                return;
@@ -47,9 +48,10 @@ static void ipcomp4_err(struct sk_buff *skb, u32 info)
 /* We always hold one tunnel user reference to indicate a tunnel */
 static struct xfrm_state *ipcomp_tunnel_create(struct xfrm_state *x)
 {
+       struct net *net = xs_net(x);
        struct xfrm_state *t;
 
-       t = xfrm_state_alloc(&init_net);
+       t = xfrm_state_alloc(net);
        if (t == NULL)
                goto out;
 
@@ -82,10 +84,11 @@ error:
  */
 static int ipcomp_tunnel_attach(struct xfrm_state *x)
 {
+       struct net *net = xs_net(x);
        int err = 0;
        struct xfrm_state *t;
 
-       t = xfrm_state_lookup(&init_net, (xfrm_address_t *)&x->id.daddr.a4,
+       t = xfrm_state_lookup(net, (xfrm_address_t *)&x->id.daddr.a4,
                              x->props.saddr.a4, IPPROTO_IPIP, AF_INET);
        if (!t) {
                t = ipcomp_tunnel_create(x);
index eda04fed337906fb87be32991fde83f49ff55b25..95db732e542b5b978d8ab82f1da681cd947576c7 100644 (file)
@@ -130,7 +130,6 @@ struct ipip_net {
        struct net_device *fb_tunnel_dev;
 };
 
-static void ipip_fb_tunnel_init(struct net_device *dev);
 static void ipip_tunnel_init(struct net_device *dev);
 static void ipip_tunnel_setup(struct net_device *dev);
 
@@ -730,7 +729,7 @@ static void ipip_tunnel_init(struct net_device *dev)
        ipip_tunnel_bind_dev(dev);
 }
 
-static void ipip_fb_tunnel_init(struct net_device *dev)
+static void __net_init ipip_fb_tunnel_init(struct net_device *dev)
 {
        struct ip_tunnel *tunnel = netdev_priv(dev);
        struct iphdr *iph = &tunnel->parms.iph;
@@ -773,7 +772,7 @@ static void ipip_destroy_tunnels(struct ipip_net *ipn, struct list_head *head)
        }
 }
 
-static int ipip_init_net(struct net *net)
+static int __net_init ipip_init_net(struct net *net)
 {
        struct ipip_net *ipn = net_generic(net, ipip_net_id);
        int err;
@@ -806,7 +805,7 @@ err_alloc_dev:
        return err;
 }
 
-static void ipip_exit_net(struct net *net)
+static void __net_exit ipip_exit_net(struct net *net)
 {
        struct ipip_net *ipn = net_generic(net, ipip_net_id);
        LIST_HEAD(list);
index f25542c48b7d938ebdbe77f0f4d6ac1e9f1c17cc..1b09a6dde7c00e02c7293f866210c50ad995db61 100644 (file)
@@ -127,8 +127,8 @@ static const struct snmp_mib snmp4_ipextstats_list[] = {
        SNMP_MIB_SENTINEL
 };
 
-static struct {
-       char *name;
+static const struct {
+       const char *name;
        int index;
 } icmpmibmap[] = {
        { "DestUnreachs", ICMP_DEST_UNREACH },
index d62b05d33384081b2a5e696f3e68f96967cf5595..b16dfadbe6d66946a736be5ca02a4c12c20dc3ab 100644 (file)
@@ -1990,8 +1990,13 @@ static int __mkroute_input(struct sk_buff *skb,
        if (skb->protocol != htons(ETH_P_IP)) {
                /* Not IP (i.e. ARP). Do not create route, if it is
                 * invalid for proxy arp. DNAT routes are always valid.
+                *
+                * Proxy arp feature have been extended to allow, ARP
+                * replies back to the same interface, to support
+                * Private VLAN switch technologies. See arp.c.
                 */
-               if (out_dev == in_dev) {
+               if (out_dev == in_dev &&
+                   IN_DEV_PROXY_ARP_PVLAN(in_dev) == 0) {
                        err = -EINVAL;
                        goto cleanup;
                }
index 66fd80ef247337d03f84fd264aab748f60346297..5c24db4a3c91a54d7d6b3b86e8d4d906999d7d76 100644 (file)
@@ -358,7 +358,8 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
 
        tcp_select_initial_window(tcp_full_space(sk), req->mss,
                                  &req->rcv_wnd, &req->window_clamp,
-                                 ireq->wscale_ok, &rcv_wscale);
+                                 ireq->wscale_ok, &rcv_wscale,
+                                 dst_metric(&rt->u.dst, RTAX_INITRWND));
 
        ireq->rcv_wscale  = rcv_wscale;
 
index b0a26bb25e2e3b341b2aad2e5f911fd99f6833fe..d5d69ea8f249d46384e3f42e975fe0d11364eb6c 100644 (file)
@@ -536,8 +536,7 @@ static inline void skb_entail(struct sock *sk, struct sk_buff *skb)
                tp->nonagle &= ~TCP_NAGLE_PUSH;
 }
 
-static inline void tcp_mark_urg(struct tcp_sock *tp, int flags,
-                               struct sk_buff *skb)
+static inline void tcp_mark_urg(struct tcp_sock *tp, int flags)
 {
        if (flags & MSG_OOB)
                tp->snd_up = tp->write_seq;
@@ -546,13 +545,13 @@ static inline void tcp_mark_urg(struct tcp_sock *tp, int flags,
 static inline void tcp_push(struct sock *sk, int flags, int mss_now,
                            int nonagle)
 {
-       struct tcp_sock *tp = tcp_sk(sk);
-
        if (tcp_send_head(sk)) {
-               struct sk_buff *skb = tcp_write_queue_tail(sk);
+               struct tcp_sock *tp = tcp_sk(sk);
+
                if (!(flags & MSG_MORE) || forced_push(tp))
-                       tcp_mark_push(tp, skb);
-               tcp_mark_urg(tp, flags, skb);
+                       tcp_mark_push(tp, tcp_write_queue_tail(sk));
+
+               tcp_mark_urg(tp, flags);
                __tcp_push_pending_frames(sk, mss_now,
                                          (flags & MSG_MORE) ? TCP_NAGLE_CORK : nonagle);
        }
@@ -877,12 +876,12 @@ ssize_t tcp_sendpage(struct socket *sock, struct page *page, int offset,
 #define TCP_PAGE(sk)   (sk->sk_sndmsg_page)
 #define TCP_OFF(sk)    (sk->sk_sndmsg_off)
 
-static inline int select_size(struct sock *sk)
+static inline int select_size(struct sock *sk, int sg)
 {
        struct tcp_sock *tp = tcp_sk(sk);
        int tmp = tp->mss_cache;
 
-       if (sk->sk_route_caps & NETIF_F_SG) {
+       if (sg) {
                if (sk_can_gso(sk))
                        tmp = 0;
                else {
@@ -906,7 +905,7 @@ int tcp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
        struct sk_buff *skb;
        int iovlen, flags;
        int mss_now, size_goal;
-       int err, copied;
+       int sg, err, copied;
        long timeo;
 
        lock_sock(sk);
@@ -934,6 +933,8 @@ int tcp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
        if (sk->sk_err || (sk->sk_shutdown & SEND_SHUTDOWN))
                goto out_err;
 
+       sg = sk->sk_route_caps & NETIF_F_SG;
+
        while (--iovlen >= 0) {
                int seglen = iov->iov_len;
                unsigned char __user *from = iov->iov_base;
@@ -959,8 +960,9 @@ new_segment:
                                if (!sk_stream_memory_free(sk))
                                        goto wait_for_sndbuf;
 
-                               skb = sk_stream_alloc_skb(sk, select_size(sk),
-                                               sk->sk_allocation);
+                               skb = sk_stream_alloc_skb(sk,
+                                                         select_size(sk, sg),
+                                                         sk->sk_allocation);
                                if (!skb)
                                        goto wait_for_memory;
 
@@ -997,9 +999,7 @@ new_segment:
                                        /* We can extend the last page
                                         * fragment. */
                                        merge = 1;
-                               } else if (i == MAX_SKB_FRAGS ||
-                                          (!i &&
-                                          !(sk->sk_route_caps & NETIF_F_SG))) {
+                               } else if (i == MAX_SKB_FRAGS || !sg) {
                                        /* Need to add new fragment and cannot
                                         * do this because interface is non-SG,
                                         * or because all the page slots are
index 65b8ebfd078a35e909c7cbf0c4e1c7bda594ac2f..c3588b4fd9798bcfa0c1fdf62ba2f2586136d441 100644 (file)
@@ -742,9 +742,9 @@ static void tcp_v4_reqsk_send_ack(struct sock *sk, struct sk_buff *skb,
  *     This still operates on a request_sock only, not on a big
  *     socket.
  */
-static int __tcp_v4_send_synack(struct sock *sk, struct dst_entry *dst,
-                               struct request_sock *req,
-                               struct request_values *rvp)
+static int tcp_v4_send_synack(struct sock *sk, struct dst_entry *dst,
+                             struct request_sock *req,
+                             struct request_values *rvp)
 {
        const struct inet_request_sock *ireq = inet_rsk(req);
        int err = -1;
@@ -775,10 +775,11 @@ static int __tcp_v4_send_synack(struct sock *sk, struct dst_entry *dst,
        return err;
 }
 
-static int tcp_v4_send_synack(struct sock *sk, struct request_sock *req,
+static int tcp_v4_rtx_synack(struct sock *sk, struct request_sock *req,
                              struct request_values *rvp)
 {
-       return __tcp_v4_send_synack(sk, NULL, req, rvp);
+       TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_RETRANSSEGS);
+       return tcp_v4_send_synack(sk, NULL, req, rvp);
 }
 
 /*
@@ -1192,10 +1193,11 @@ static int tcp_v4_inbound_md5_hash(struct sock *sk, struct sk_buff *skb)
 struct request_sock_ops tcp_request_sock_ops __read_mostly = {
        .family         =       PF_INET,
        .obj_size       =       sizeof(struct tcp_request_sock),
-       .rtx_syn_ack    =       tcp_v4_send_synack,
+       .rtx_syn_ack    =       tcp_v4_rtx_synack,
        .send_ack       =       tcp_v4_reqsk_send_ack,
        .destructor     =       tcp_v4_reqsk_destructor,
        .send_reset     =       tcp_v4_send_reset,
+       .syn_ack_timeout =      tcp_syn_ack_timeout,
 };
 
 #ifdef CONFIG_TCP_MD5SIG
@@ -1373,8 +1375,8 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
        }
        tcp_rsk(req)->snt_isn = isn;
 
-       if (__tcp_v4_send_synack(sk, dst, req,
-                                (struct request_values *)&tmp_ext) ||
+       if (tcp_v4_send_synack(sk, dst, req,
+                              (struct request_values *)&tmp_ext) ||
            want_cookie)
                goto drop_and_free;
 
@@ -1649,6 +1651,9 @@ int tcp_v4_rcv(struct sk_buff *skb)
        if (!sk)
                goto no_tcp_socket;
 
+       if (iph->ttl < inet_sk(sk)->min_ttl)
+               goto discard_and_relse;
+
 process:
        if (sk->sk_state == TCP_TIME_WAIT)
                goto do_time_wait;
@@ -2425,12 +2430,12 @@ static struct tcp_seq_afinfo tcp4_seq_afinfo = {
        },
 };
 
-static int tcp4_proc_init_net(struct net *net)
+static int __net_init tcp4_proc_init_net(struct net *net)
 {
        return tcp_proc_register(net, &tcp4_seq_afinfo);
 }
 
-static void tcp4_proc_exit_net(struct net *net)
+static void __net_exit tcp4_proc_exit_net(struct net *net)
 {
        tcp_proc_unregister(net, &tcp4_seq_afinfo);
 }
index 383ce237640fdb8b2d79d205fd8cb8a7f123ee7f..4a1605d3f909666321b6b6c1684354bbc58a22f6 100644 (file)
@@ -183,7 +183,8 @@ static inline void tcp_event_ack_sent(struct sock *sk, unsigned int pkts)
  */
 void tcp_select_initial_window(int __space, __u32 mss,
                               __u32 *rcv_wnd, __u32 *window_clamp,
-                              int wscale_ok, __u8 *rcv_wscale)
+                              int wscale_ok, __u8 *rcv_wscale,
+                              __u32 init_rcv_wnd)
 {
        unsigned int space = (__space < 0 ? 0 : __space);
 
@@ -232,7 +233,13 @@ void tcp_select_initial_window(int __space, __u32 mss,
                        init_cwnd = 2;
                else if (mss > 1460)
                        init_cwnd = 3;
-               if (*rcv_wnd > init_cwnd * mss)
+               /* when initializing use the value from init_rcv_wnd
+                * rather than the default from above
+                */
+               if (init_rcv_wnd &&
+                   (*rcv_wnd > init_rcv_wnd * mss))
+                       *rcv_wnd = init_rcv_wnd * mss;
+               else if (*rcv_wnd > init_cwnd * mss)
                        *rcv_wnd = init_cwnd * mss;
        }
 
@@ -1794,11 +1801,6 @@ static int tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle,
 void __tcp_push_pending_frames(struct sock *sk, unsigned int cur_mss,
                               int nonagle)
 {
-       struct sk_buff *skb = tcp_send_head(sk);
-
-       if (!skb)
-               return;
-
        /* If we are closed, the bytes will have to remain here.
         * In time closedown will finish, we empty the write queue and
         * all will be happy.
@@ -2422,7 +2424,8 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst,
                        &req->rcv_wnd,
                        &req->window_clamp,
                        ireq->wscale_ok,
-                       &rcv_wscale);
+                       &rcv_wscale,
+                       dst_metric(dst, RTAX_INITRWND));
                ireq->rcv_wscale = rcv_wscale;
        }
 
@@ -2549,7 +2552,8 @@ static void tcp_connect_init(struct sock *sk)
                                  &tp->rcv_wnd,
                                  &tp->window_clamp,
                                  sysctl_tcp_window_scaling,
-                                 &rcv_wscale);
+                                 &rcv_wscale,
+                                 dst_metric(dst, RTAX_INITRWND));
 
        tp->rx_opt.rcv_wscale = rcv_wscale;
        tp->rcv_ssthresh = tp->rcv_wnd;
index 8816a20c25970ad4fe9ae172a4890af74ee928ce..de7d1bf9114fe6d3bf6475be2f9031460c618e95 100644 (file)
@@ -474,6 +474,12 @@ static void tcp_synack_timer(struct sock *sk)
                                   TCP_TIMEOUT_INIT, TCP_RTO_MAX);
 }
 
+void tcp_syn_ack_timeout(struct sock *sk, struct request_sock *req)
+{
+       NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPTIMEOUTS);
+}
+EXPORT_SYMBOL(tcp_syn_ack_timeout);
+
 void tcp_set_keepalive(struct sock *sk, int val)
 {
        if ((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN))
index f0126fdd7e04ba8fd3da4b90aadd663411b0617d..4f7d2122d8183b95cd49387d282445de894b2c04 100644 (file)
@@ -2027,12 +2027,12 @@ static struct udp_seq_afinfo udp4_seq_afinfo = {
        },
 };
 
-static int udp4_proc_init_net(struct net *net)
+static int __net_init udp4_proc_init_net(struct net *net)
 {
        return udp_proc_register(net, &udp4_seq_afinfo);
 }
 
-static void udp4_proc_exit_net(struct net *net)
+static void __net_exit udp4_proc_exit_net(struct net *net)
 {
        udp_proc_unregister(net, &udp4_seq_afinfo);
 }
index 66f79513f4a5b2e6839369f4636713746eab9375..6610bf76369fadc5c22dafd76fd7552bf50c3277 100644 (file)
@@ -81,12 +81,12 @@ static struct udp_seq_afinfo udplite4_seq_afinfo = {
        },
 };
 
-static int udplite4_proc_init_net(struct net *net)
+static int __net_init udplite4_proc_init_net(struct net *net)
 {
        return udp_proc_register(net, &udplite4_seq_afinfo);
 }
 
-static void udplite4_proc_exit_net(struct net *net)
+static void __net_exit udplite4_proc_exit_net(struct net *net)
 {
        udp_proc_unregister(net, &udplite4_seq_afinfo);
 }
index de7a194a64ab4fa0cf864d1fe3f83a3974e3b727..1593289155ff7996b79b41bc3dcf484000369db3 100644 (file)
@@ -3027,14 +3027,14 @@ static const struct file_operations if6_fops = {
        .release        = seq_release_net,
 };
 
-static int if6_proc_net_init(struct net *net)
+static int __net_init if6_proc_net_init(struct net *net)
 {
        if (!proc_net_fops_create(net, "if_inet6", S_IRUGO, &if6_fops))
                return -ENOMEM;
        return 0;
 }
 
-static void if6_proc_net_exit(struct net *net)
+static void __net_exit if6_proc_net_exit(struct net *net)
 {
        proc_net_remove(net, "if_inet6");
 }
@@ -4418,7 +4418,7 @@ static void addrconf_sysctl_unregister(struct inet6_dev *idev)
 
 #endif
 
-static int addrconf_init_net(struct net *net)
+static int __net_init addrconf_init_net(struct net *net)
 {
        int err;
        struct ipv6_devconf *all, *dflt;
@@ -4467,7 +4467,7 @@ err_alloc_all:
        return err;
 }
 
-static void addrconf_exit_net(struct net *net)
+static void __net_exit addrconf_exit_net(struct net *net)
 {
 #ifdef CONFIG_SYSCTL
        __addrconf_sysctl_unregister(net->ipv6.devconf_dflt);
index 12e69d364dd56a1d7542ce73cf04268a52f667d7..e29160ff4a0fe2615fe53fa8c7b15953698701b3 100644 (file)
@@ -999,7 +999,7 @@ err_udplite_mib:
        return -ENOMEM;
 }
 
-static void __net_exit ipv6_cleanup_mibs(struct net *net)
+static void ipv6_cleanup_mibs(struct net *net)
 {
        snmp_mib_free((void **)net->mib.udp_stats_in6);
        snmp_mib_free((void **)net->mib.udplite_stats_in6);
@@ -1042,7 +1042,7 @@ out:
 #endif
 }
 
-static void inet6_net_exit(struct net *net)
+static void __net_exit inet6_net_exit(struct net *net)
 {
 #ifdef CONFIG_PROC_FS
        udp6_proc_exit(net);
index f1c74c8ef9dec24098fcd87b568a1fbd546310f4..c4f6ca32fa749f74d8e327488911113f9d0b9084 100644 (file)
@@ -538,7 +538,7 @@ static const struct file_operations ac6_seq_fops = {
        .release        =       seq_release_net,
 };
 
-int ac6_proc_init(struct net *net)
+int __net_init ac6_proc_init(struct net *net)
 {
        if (!proc_net_fops_create(net, "anycast6", S_IRUGO, &ac6_seq_fops))
                return -ENOMEM;
index b7aa7c64cc4a2895001f7f256cf26675304d3f24..551882b9dfd6c2229187a46e3c611b30d4164649 100644 (file)
@@ -262,7 +262,7 @@ static struct fib_rules_ops fib6_rules_ops_template = {
        .fro_net                = &init_net,
 };
 
-static int fib6_rules_net_init(struct net *net)
+static int __net_init fib6_rules_net_init(struct net *net)
 {
        struct fib_rules_ops *ops;
        int err = -ENOMEM;
@@ -291,7 +291,7 @@ out_fib6_rules_ops:
        goto out;
 }
 
-static void fib6_rules_net_exit(struct net *net)
+static void __net_exit fib6_rules_net_exit(struct net *net)
 {
        fib_rules_unregister(net->ipv6.fib6_rules_ops);
 }
index 4ae661bc3677b4efc9a5a205086f4922d8c6806e..217dbc2e28d4d600ae1b88654b2f56356d03382f 100644 (file)
@@ -951,7 +951,7 @@ ctl_table ipv6_icmp_table_template[] = {
        { },
 };
 
-struct ctl_table *ipv6_icmp_sysctl_init(struct net *net)
+struct ctl_table * __net_init ipv6_icmp_sysctl_init(struct net *net)
 {
        struct ctl_table *table;
 
index 0e93ca56eb694c39914c2295b9394c1e83775001..f626ea2b304f7fcf8d4f630252e51df2656ec54e 100644 (file)
@@ -239,7 +239,7 @@ struct fib6_table *fib6_get_table(struct net *net, u32 id)
        return NULL;
 }
 
-static void fib6_tables_init(struct net *net)
+static void __net_init fib6_tables_init(struct net *net)
 {
        fib6_link_table(net, net->ipv6.fib6_main_tbl);
        fib6_link_table(net, net->ipv6.fib6_local_tbl);
@@ -262,7 +262,7 @@ struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi *fl,
        return (struct dst_entry *) lookup(net, net->ipv6.fib6_main_tbl, fl, flags);
 }
 
-static void fib6_tables_init(struct net *net)
+static void __net_init fib6_tables_init(struct net *net)
 {
        fib6_link_table(net, net->ipv6.fib6_main_tbl);
 }
@@ -1469,7 +1469,7 @@ static void fib6_gc_timer_cb(unsigned long arg)
        fib6_run_gc(0, (struct net *)arg);
 }
 
-static int fib6_net_init(struct net *net)
+static int __net_init fib6_net_init(struct net *net)
 {
        setup_timer(&net->ipv6.ip6_fib_timer, fib6_gc_timer_cb, (unsigned long)net);
 
index 6e7bffa2205e07b947ed78faec4e3aa56ee1db25..e41eba8aacf15ce25eb3c7cca1d3baac1f1c884d 100644 (file)
@@ -154,7 +154,7 @@ static void ip6_fl_gc(unsigned long dummy)
        write_unlock(&ip6_fl_lock);
 }
 
-static void ip6_fl_purge(struct net *net)
+static void __net_exit ip6_fl_purge(struct net *net)
 {
        int i;
 
@@ -735,7 +735,7 @@ static const struct file_operations ip6fl_seq_fops = {
        .release        =       seq_release_net,
 };
 
-static int ip6_flowlabel_proc_init(struct net *net)
+static int __net_init ip6_flowlabel_proc_init(struct net *net)
 {
        if (!proc_net_fops_create(net, "ip6_flowlabel",
                                  S_IRUGO, &ip6fl_seq_fops))
@@ -743,7 +743,7 @@ static int ip6_flowlabel_proc_init(struct net *net)
        return 0;
 }
 
-static void ip6_flowlabel_proc_fini(struct net *net)
+static void __net_exit ip6_flowlabel_proc_fini(struct net *net)
 {
        proc_net_remove(net, "ip6_flowlabel");
 }
@@ -754,11 +754,10 @@ static inline int ip6_flowlabel_proc_init(struct net *net)
 }
 static inline void ip6_flowlabel_proc_fini(struct net *net)
 {
-       return ;
 }
 #endif
 
-static inline void ip6_flowlabel_net_exit(struct net *net)
+static void __net_exit ip6_flowlabel_net_exit(struct net *net)
 {
        ip6_fl_purge(net);
        ip6_flowlabel_proc_fini(net);
index d453d07b0dfe30efda7790f7c1d98d8451f1a21a..fbd786981aa9104ba5320834e63fe21dd4a30ace 100644 (file)
@@ -74,7 +74,6 @@ MODULE_LICENSE("GPL");
                     (addr)->s6_addr32[2] ^ (addr)->s6_addr32[3]) & \
                    (HASH_SIZE - 1))
 
-static void ip6_fb_tnl_dev_init(struct net_device *dev);
 static void ip6_tnl_dev_init(struct net_device *dev);
 static void ip6_tnl_dev_setup(struct net_device *dev);
 
@@ -1364,7 +1363,7 @@ static void ip6_tnl_dev_init(struct net_device *dev)
  * Return: 0
  **/
 
-static void ip6_fb_tnl_dev_init(struct net_device *dev)
+static void __net_init ip6_fb_tnl_dev_init(struct net_device *dev)
 {
        struct ip6_tnl *t = netdev_priv(dev);
        struct net *net = dev_net(dev);
@@ -1388,7 +1387,7 @@ static struct xfrm6_tunnel ip6ip6_handler = {
        .priority       =       1,
 };
 
-static void ip6_tnl_destroy_tunnels(struct ip6_tnl_net *ip6n)
+static void __net_exit ip6_tnl_destroy_tunnels(struct ip6_tnl_net *ip6n)
 {
        int h;
        struct ip6_tnl *t;
@@ -1407,7 +1406,7 @@ static void ip6_tnl_destroy_tunnels(struct ip6_tnl_net *ip6n)
        unregister_netdevice_many(&list);
 }
 
-static int ip6_tnl_init_net(struct net *net)
+static int __net_init ip6_tnl_init_net(struct net *net)
 {
        struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
        int err;
@@ -1436,7 +1435,7 @@ err_alloc_dev:
        return err;
 }
 
-static void ip6_tnl_exit_net(struct net *net)
+static void __net_exit ip6_tnl_exit_net(struct net *net)
 {
        struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
 
index 2f2a5ca2c8786599560f7328d64401f837ab5e38..a9fbb151bb7998c507a12f4f052a63465f81059a 100644 (file)
@@ -53,6 +53,7 @@
 static void ipcomp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
                                u8 type, u8 code, int offset, __be32 info)
 {
+       struct net *net = dev_net(skb->dev);
        __be32 spi;
        struct ipv6hdr *iph = (struct ipv6hdr*)skb->data;
        struct ip_comp_hdr *ipcomph =
@@ -63,7 +64,7 @@ static void ipcomp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
                return;
 
        spi = htonl(ntohs(ipcomph->cpi));
-       x = xfrm_state_lookup(&init_net, (xfrm_address_t *)&iph->daddr, spi, IPPROTO_COMP, AF_INET6);
+       x = xfrm_state_lookup(net, (xfrm_address_t *)&iph->daddr, spi, IPPROTO_COMP, AF_INET6);
        if (!x)
                return;
 
@@ -74,14 +75,15 @@ static void ipcomp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
 
 static struct xfrm_state *ipcomp6_tunnel_create(struct xfrm_state *x)
 {
+       struct net *net = xs_net(x);
        struct xfrm_state *t = NULL;
 
-       t = xfrm_state_alloc(&init_net);
+       t = xfrm_state_alloc(net);
        if (!t)
                goto out;
 
        t->id.proto = IPPROTO_IPV6;
-       t->id.spi = xfrm6_tunnel_alloc_spi((xfrm_address_t *)&x->props.saddr);
+       t->id.spi = xfrm6_tunnel_alloc_spi(net, (xfrm_address_t *)&x->props.saddr);
        if (!t->id.spi)
                goto error;
 
@@ -108,13 +110,14 @@ error:
 
 static int ipcomp6_tunnel_attach(struct xfrm_state *x)
 {
+       struct net *net = xs_net(x);
        int err = 0;
        struct xfrm_state *t = NULL;
        __be32 spi;
 
-       spi = xfrm6_tunnel_spi_lookup((xfrm_address_t *)&x->props.saddr);
+       spi = xfrm6_tunnel_spi_lookup(net, (xfrm_address_t *)&x->props.saddr);
        if (spi)
-               t = xfrm_state_lookup(&init_net, (xfrm_address_t *)&x->id.daddr,
+               t = xfrm_state_lookup(net, (xfrm_address_t *)&x->id.daddr,
                                              spi, IPPROTO_IPV6, AF_INET6);
        if (!t) {
                t = ipcomp6_tunnel_create(x);
index 1f9c44442e65ea70f8fa68ebd5ccbb8b996f0647..25f6cca79e6bb1d2f0ace9e8c5b3a0eba0a0ec53 100644 (file)
@@ -2646,7 +2646,7 @@ static const struct file_operations igmp6_mcf_seq_fops = {
        .release        =       seq_release_net,
 };
 
-static int igmp6_proc_init(struct net *net)
+static int __net_init igmp6_proc_init(struct net *net)
 {
        int err;
 
@@ -2666,23 +2666,22 @@ out_proc_net_igmp6:
        goto out;
 }
 
-static void igmp6_proc_exit(struct net *net)
+static void __net_exit igmp6_proc_exit(struct net *net)
 {
        proc_net_remove(net, "mcfilter6");
        proc_net_remove(net, "igmp6");
 }
 #else
-static int igmp6_proc_init(struct net *net)
+static inline int igmp6_proc_init(struct net *net)
 {
        return 0;
 }
-static void igmp6_proc_exit(struct net *net)
+static inline void igmp6_proc_exit(struct net *net)
 {
-       ;
 }
 #endif
 
-static int igmp6_net_init(struct net *net)
+static int __net_init igmp6_net_init(struct net *net)
 {
        int err;
 
@@ -2708,7 +2707,7 @@ out_sock_create:
        goto out;
 }
 
-static void igmp6_net_exit(struct net *net)
+static void __net_exit igmp6_net_exit(struct net *net)
 {
        inet_ctl_sock_destroy(net->ipv6.igmp_sk);
        igmp6_proc_exit(net);
index c45852798092edb9c0fcdd592c68798476761009..2dfec6bb8adaad2bb18b79f3f627af2689bfe148 100644 (file)
@@ -1772,7 +1772,7 @@ int ndisc_ifinfo_sysctl_change(struct ctl_table *ctl, int write, void __user *bu
 
 #endif
 
-static int ndisc_net_init(struct net *net)
+static int __net_init ndisc_net_init(struct net *net)
 {
        struct ipv6_pinfo *np;
        struct sock *sk;
@@ -1797,7 +1797,7 @@ static int ndisc_net_init(struct net *net)
        return 0;
 }
 
-static void ndisc_net_exit(struct net *net)
+static void __net_exit ndisc_net_exit(struct net *net)
 {
        inet_ctl_sock_destroy(net->ipv6.ndisc_sk);
 }
index c9605c3ad91fcf8927c4df2937fa10c8b8dafd94..bfe2598dd56386736aaf8c857b641f5b2d2c15f7 100644 (file)
@@ -59,7 +59,7 @@ static const struct file_operations sockstat6_seq_fops = {
        .release = single_release_net,
 };
 
-static struct snmp_mib snmp6_ipstats_list[] = {
+static const struct snmp_mib snmp6_ipstats_list[] = {
 /* ipv6 mib according to RFC 2465 */
        SNMP_MIB_ITEM("Ip6InReceives", IPSTATS_MIB_INPKTS),
        SNMP_MIB_ITEM("Ip6InHdrErrors", IPSTATS_MIB_INHDRERRORS),
@@ -92,7 +92,7 @@ static struct snmp_mib snmp6_ipstats_list[] = {
        SNMP_MIB_SENTINEL
 };
 
-static struct snmp_mib snmp6_icmp6_list[] = {
+static const struct snmp_mib snmp6_icmp6_list[] = {
 /* icmpv6 mib according to RFC 2466 */
        SNMP_MIB_ITEM("Icmp6InMsgs", ICMP6_MIB_INMSGS),
        SNMP_MIB_ITEM("Icmp6InErrors", ICMP6_MIB_INERRORS),
@@ -120,7 +120,7 @@ static const char *const icmp6type2name[256] = {
 };
 
 
-static struct snmp_mib snmp6_udp6_list[] = {
+static const struct snmp_mib snmp6_udp6_list[] = {
        SNMP_MIB_ITEM("Udp6InDatagrams", UDP_MIB_INDATAGRAMS),
        SNMP_MIB_ITEM("Udp6NoPorts", UDP_MIB_NOPORTS),
        SNMP_MIB_ITEM("Udp6InErrors", UDP_MIB_INERRORS),
@@ -128,7 +128,7 @@ static struct snmp_mib snmp6_udp6_list[] = {
        SNMP_MIB_SENTINEL
 };
 
-static struct snmp_mib snmp6_udplite6_list[] = {
+static const struct snmp_mib snmp6_udplite6_list[] = {
        SNMP_MIB_ITEM("UdpLite6InDatagrams", UDP_MIB_INDATAGRAMS),
        SNMP_MIB_ITEM("UdpLite6NoPorts", UDP_MIB_NOPORTS),
        SNMP_MIB_ITEM("UdpLite6InErrors", UDP_MIB_INERRORS),
@@ -170,8 +170,8 @@ static void snmp6_seq_show_icmpv6msg(struct seq_file *seq, void **mib)
        return;
 }
 
-static inline void
-snmp6_seq_show_item(struct seq_file *seq, void **mib, struct snmp_mib *itemlist)
+static void snmp6_seq_show_item(struct seq_file *seq, void **mib,
+                               const struct snmp_mib *itemlist)
 {
        int i;
        for (i=0; itemlist[i].name; i++)
@@ -259,7 +259,7 @@ int snmp6_unregister_dev(struct inet6_dev *idev)
        struct net *net = dev_net(idev->dev);
        if (!net->mib.proc_net_devsnmp6)
                return -ENOENT;
-       if (!idev || !idev->stats.proc_dir_entry)
+       if (!idev->stats.proc_dir_entry)
                return -EINVAL;
        remove_proc_entry(idev->stats.proc_dir_entry->name,
                          net->mib.proc_net_devsnmp6);
@@ -267,7 +267,7 @@ int snmp6_unregister_dev(struct inet6_dev *idev)
        return 0;
 }
 
-static int ipv6_proc_init_net(struct net *net)
+static int __net_init ipv6_proc_init_net(struct net *net)
 {
        if (!proc_net_fops_create(net, "sockstat6", S_IRUGO,
                        &sockstat6_seq_fops))
@@ -288,7 +288,7 @@ proc_dev_snmp6_fail:
        return -ENOMEM;
 }
 
-static void ipv6_proc_exit_net(struct net *net)
+static void __net_exit ipv6_proc_exit_net(struct net *net)
 {
        proc_net_remove(net, "sockstat6");
        proc_net_remove(net, "dev_snmp6");
index 926ce8eeffaf8ed9b0099005397be623301b9aa5..ed31c37c6e3906a817e751bfd86115f2246c7ca3 100644 (file)
@@ -1275,7 +1275,7 @@ static const struct file_operations raw6_seq_fops = {
        .release =      seq_release_net,
 };
 
-static int raw6_init_net(struct net *net)
+static int __net_init raw6_init_net(struct net *net)
 {
        if (!proc_net_fops_create(net, "raw6", S_IRUGO, &raw6_seq_fops))
                return -ENOMEM;
@@ -1283,7 +1283,7 @@ static int raw6_init_net(struct net *net)
        return 0;
 }
 
-static void raw6_exit_net(struct net *net)
+static void __net_exit raw6_exit_net(struct net *net)
 {
        proc_net_remove(net, "raw6");
 }
index 2cddea3bd6be9fcb935669ec26678e3b0c368b2e..fa38fc7cc6e96417714ad5e70e58e922d4366db2 100644 (file)
@@ -672,7 +672,7 @@ static struct ctl_table ip6_frags_ctl_table[] = {
        { }
 };
 
-static int ip6_frags_ns_sysctl_register(struct net *net)
+static int __net_init ip6_frags_ns_sysctl_register(struct net *net)
 {
        struct ctl_table *table;
        struct ctl_table_header *hdr;
@@ -702,7 +702,7 @@ err_alloc:
        return -ENOMEM;
 }
 
-static void ip6_frags_ns_sysctl_unregister(struct net *net)
+static void __net_exit ip6_frags_ns_sysctl_unregister(struct net *net)
 {
        struct ctl_table *table;
 
@@ -745,7 +745,7 @@ static inline void ip6_frags_sysctl_unregister(void)
 }
 #endif
 
-static int ipv6_frags_init_net(struct net *net)
+static int __net_init ipv6_frags_init_net(struct net *net)
 {
        net->ipv6.frags.high_thresh = 256 * 1024;
        net->ipv6.frags.low_thresh = 192 * 1024;
@@ -756,7 +756,7 @@ static int ipv6_frags_init_net(struct net *net)
        return ip6_frags_ns_sysctl_register(net);
 }
 
-static void ipv6_frags_exit_net(struct net *net)
+static void __net_exit ipv6_frags_exit_net(struct net *net)
 {
        ip6_frags_ns_sysctl_unregister(net);
        inet_frags_exit_net(&net->ipv6.frags, &ip6_frags);
index c2bd74c5f8d979dee714b169750250250f1022e6..8500156f263720e5042286da5a9109496ed3902d 100644 (file)
@@ -2612,7 +2612,7 @@ ctl_table ipv6_route_table_template[] = {
        { }
 };
 
-struct ctl_table *ipv6_route_sysctl_init(struct net *net)
+struct ctl_table * __net_init ipv6_route_sysctl_init(struct net *net)
 {
        struct ctl_table *table;
 
@@ -2637,7 +2637,7 @@ struct ctl_table *ipv6_route_sysctl_init(struct net *net)
 }
 #endif
 
-static int ip6_route_net_init(struct net *net)
+static int __net_init ip6_route_net_init(struct net *net)
 {
        int ret = -ENOMEM;
 
@@ -2702,7 +2702,7 @@ out_ip6_dst_ops:
        goto out;
 }
 
-static void ip6_route_net_exit(struct net *net)
+static void __net_exit ip6_route_net_exit(struct net *net)
 {
 #ifdef CONFIG_PROC_FS
        proc_net_remove(net, "ipv6_route");
index 976e68244b998fd2a7f78536f0042fc504b083eb..10207cc8cc0e2d4da01f2e7d069d01988a38997a 100644 (file)
@@ -62,7 +62,6 @@
 #define HASH_SIZE  16
 #define HASH(addr) (((__force u32)addr^((__force u32)addr>>4))&0xF)
 
-static void ipip6_fb_tunnel_init(struct net_device *dev);
 static void ipip6_tunnel_init(struct net_device *dev);
 static void ipip6_tunnel_setup(struct net_device *dev);
 
@@ -1120,7 +1119,7 @@ static void ipip6_tunnel_init(struct net_device *dev)
        ipip6_tunnel_bind_dev(dev);
 }
 
-static void ipip6_fb_tunnel_init(struct net_device *dev)
+static void __net_init ipip6_fb_tunnel_init(struct net_device *dev)
 {
        struct ip_tunnel *tunnel = netdev_priv(dev);
        struct iphdr *iph = &tunnel->parms.iph;
@@ -1145,7 +1144,7 @@ static struct xfrm_tunnel sit_handler = {
        .priority       =       1,
 };
 
-static void sit_destroy_tunnels(struct sit_net *sitn, struct list_head *head)
+static void __net_exit sit_destroy_tunnels(struct sit_net *sitn, struct list_head *head)
 {
        int prio;
 
@@ -1162,7 +1161,7 @@ static void sit_destroy_tunnels(struct sit_net *sitn, struct list_head *head)
        }
 }
 
-static int sit_init_net(struct net *net)
+static int __net_init sit_init_net(struct net *net)
 {
        struct sit_net *sitn = net_generic(net, sit_net_id);
        int err;
@@ -1195,7 +1194,7 @@ err_alloc_dev:
        return err;
 }
 
-static void sit_exit_net(struct net *net)
+static void __net_exit sit_exit_net(struct net *net)
 {
        struct sit_net *sitn = net_generic(net, sit_net_id);
        LIST_HEAD(list);
index 7208a06576c6843996a02796804d33e61a524ee8..34d1f0690d7e4f6031172fd4640da207b07c25b3 100644 (file)
@@ -269,7 +269,8 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
        req->window_clamp = tp->window_clamp ? :dst_metric(dst, RTAX_WINDOW);
        tcp_select_initial_window(tcp_full_space(sk), req->mss,
                                  &req->rcv_wnd, &req->window_clamp,
-                                 ireq->wscale_ok, &rcv_wscale);
+                                 ireq->wscale_ok, &rcv_wscale,
+                                 dst_metric(dst, RTAX_INITRWND));
 
        ireq->rcv_wscale = rcv_wscale;
 
index c690736885b4695f9e96f8b1991d01684fbeebcf..f841d93bf987eb07ce03864be359be91b656583a 100644 (file)
@@ -55,7 +55,7 @@ struct ctl_path net_ipv6_ctl_path[] = {
 };
 EXPORT_SYMBOL_GPL(net_ipv6_ctl_path);
 
-static int ipv6_sysctl_net_init(struct net *net)
+static int __net_init ipv6_sysctl_net_init(struct net *net)
 {
        struct ctl_table *ipv6_table;
        struct ctl_table *ipv6_route_table;
@@ -98,7 +98,7 @@ out_ipv6_table:
        goto out;
 }
 
-static void ipv6_sysctl_net_exit(struct net *net)
+static void __net_exit ipv6_sysctl_net_exit(struct net *net)
 {
        struct ctl_table *ipv6_table;
        struct ctl_table *ipv6_route_table;
index febfd595a40dd517d9deb5b2c574a0912669fff7..6963a6b6763e74f8aca6e95888bcd62793b89745 100644 (file)
@@ -520,6 +520,13 @@ done:
        return err;
 }
 
+static int tcp_v6_rtx_synack(struct sock *sk, struct request_sock *req,
+                            struct request_values *rvp)
+{
+       TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_RETRANSSEGS);
+       return tcp_v6_send_synack(sk, req, rvp);
+}
+
 static inline void syn_flood_warning(struct sk_buff *skb)
 {
 #ifdef CONFIG_SYN_COOKIES
@@ -876,7 +883,7 @@ static int tcp_v6_inbound_md5_hash (struct sock *sk, struct sk_buff *skb)
 
        if (genhash || memcmp(hash_location, newhash, 16) != 0) {
                if (net_ratelimit()) {
-                       printk(KERN_INFO "MD5 Hash %s for (%pI6, %u)->(%pI6, %u)\n",
+                       printk(KERN_INFO "MD5 Hash %s for [%pI6c]:%u->[%pI6c]:%u\n",
                               genhash ? "failed" : "mismatch",
                               &ip6h->saddr, ntohs(th->source),
                               &ip6h->daddr, ntohs(th->dest));
@@ -890,10 +897,11 @@ static int tcp_v6_inbound_md5_hash (struct sock *sk, struct sk_buff *skb)
 struct request_sock_ops tcp6_request_sock_ops __read_mostly = {
        .family         =       AF_INET6,
        .obj_size       =       sizeof(struct tcp6_request_sock),
-       .rtx_syn_ack    =       tcp_v6_send_synack,
+       .rtx_syn_ack    =       tcp_v6_rtx_synack,
        .send_ack       =       tcp_v6_reqsk_send_ack,
        .destructor     =       tcp_v6_reqsk_destructor,
-       .send_reset     =       tcp_v6_send_reset
+       .send_reset     =       tcp_v6_send_reset,
+       .syn_ack_timeout =      tcp_syn_ack_timeout,
 };
 
 #ifdef CONFIG_TCP_MD5SIG
@@ -2105,7 +2113,7 @@ static struct tcp_seq_afinfo tcp6_seq_afinfo = {
        },
 };
 
-int tcp6_proc_init(struct net *net)
+int __net_init tcp6_proc_init(struct net *net)
 {
        return tcp_proc_register(net, &tcp6_seq_afinfo);
 }
@@ -2174,18 +2182,18 @@ static struct inet_protosw tcpv6_protosw = {
                                INET_PROTOSW_ICSK,
 };
 
-static int tcpv6_net_init(struct net *net)
+static int __net_init tcpv6_net_init(struct net *net)
 {
        return inet_ctl_sock_create(&net->ipv6.tcp_sk, PF_INET6,
                                    SOCK_RAW, IPPROTO_TCP, net);
 }
 
-static void tcpv6_net_exit(struct net *net)
+static void __net_exit tcpv6_net_exit(struct net *net)
 {
        inet_ctl_sock_destroy(net->ipv6.tcp_sk);
 }
 
-static void tcpv6_net_exit_batch(struct list_head *net_exit_list)
+static void __net_exit tcpv6_net_exit_batch(struct list_head *net_exit_list)
 {
        inet_twsk_purge(&tcp_hashinfo, &tcp_death_row, AF_INET6);
 }
index 69ebdbe78c47cb1e24657d21710b7f4b81af8ea7..34efb3589ffac1dc4050132d7cf926c86e87a499 100644 (file)
@@ -1396,7 +1396,7 @@ static struct udp_seq_afinfo udp6_seq_afinfo = {
        },
 };
 
-int udp6_proc_init(struct net *net)
+int __net_init udp6_proc_init(struct net *net)
 {
        return udp_proc_register(net, &udp6_seq_afinfo);
 }
index 6ea6938919e69de8223dd982690730ec64a2e3e0..5f48fadc27f7a62aa13632fc31bea73e1d1e6aec 100644 (file)
@@ -104,12 +104,12 @@ static struct udp_seq_afinfo udplite6_seq_afinfo = {
        },
 };
 
-static int udplite6_proc_init_net(struct net *net)
+static int __net_init udplite6_proc_init_net(struct net *net)
 {
        return udp_proc_register(net, &udplite6_seq_afinfo);
 }
 
-static void udplite6_proc_exit_net(struct net *net)
+static void __net_exit udplite6_proc_exit_net(struct net *net)
 {
        udp_proc_unregister(net, &udplite6_seq_afinfo);
 }
index 438831d3359315718ff5cca2ca11ca01f878ae02..d6f9aeec69f79a2b99098e2cd653a11552a7a016 100644 (file)
 #include <linux/ipv6.h>
 #include <linux/icmpv6.h>
 #include <linux/mutex.h>
+#include <net/netns/generic.h>
+
+#define XFRM6_TUNNEL_SPI_BYADDR_HSIZE 256
+#define XFRM6_TUNNEL_SPI_BYSPI_HSIZE 256
+
+#define XFRM6_TUNNEL_SPI_MIN   1
+#define XFRM6_TUNNEL_SPI_MAX   0xffffffff
+
+struct xfrm6_tunnel_net {
+       struct hlist_head spi_byaddr[XFRM6_TUNNEL_SPI_BYADDR_HSIZE];
+       struct hlist_head spi_byspi[XFRM6_TUNNEL_SPI_BYSPI_HSIZE];
+       u32 spi;
+};
+
+static int xfrm6_tunnel_net_id __read_mostly;
+static inline struct xfrm6_tunnel_net *xfrm6_tunnel_pernet(struct net *net)
+{
+       return net_generic(net, xfrm6_tunnel_net_id);
+}
 
 /*
  * xfrm_tunnel_spi things are for allocating unique id ("spi")
@@ -46,19 +65,8 @@ struct xfrm6_tunnel_spi {
 
 static DEFINE_SPINLOCK(xfrm6_tunnel_spi_lock);
 
-static u32 xfrm6_tunnel_spi;
-
-#define XFRM6_TUNNEL_SPI_MIN   1
-#define XFRM6_TUNNEL_SPI_MAX   0xffffffff
-
 static struct kmem_cache *xfrm6_tunnel_spi_kmem __read_mostly;
 
-#define XFRM6_TUNNEL_SPI_BYADDR_HSIZE 256
-#define XFRM6_TUNNEL_SPI_BYSPI_HSIZE 256
-
-static struct hlist_head xfrm6_tunnel_spi_byaddr[XFRM6_TUNNEL_SPI_BYADDR_HSIZE];
-static struct hlist_head xfrm6_tunnel_spi_byspi[XFRM6_TUNNEL_SPI_BYSPI_HSIZE];
-
 static inline unsigned xfrm6_tunnel_spi_hash_byaddr(xfrm_address_t *addr)
 {
        unsigned h;
@@ -77,49 +85,30 @@ static inline unsigned xfrm6_tunnel_spi_hash_byspi(u32 spi)
 }
 
 
-static int xfrm6_tunnel_spi_init(void)
+static int __init xfrm6_tunnel_spi_init(void)
 {
-       int i;
-
-       xfrm6_tunnel_spi = 0;
        xfrm6_tunnel_spi_kmem = kmem_cache_create("xfrm6_tunnel_spi",
                                                  sizeof(struct xfrm6_tunnel_spi),
                                                  0, SLAB_HWCACHE_ALIGN,
                                                  NULL);
        if (!xfrm6_tunnel_spi_kmem)
                return -ENOMEM;
-
-       for (i = 0; i < XFRM6_TUNNEL_SPI_BYADDR_HSIZE; i++)
-               INIT_HLIST_HEAD(&xfrm6_tunnel_spi_byaddr[i]);
-       for (i = 0; i < XFRM6_TUNNEL_SPI_BYSPI_HSIZE; i++)
-               INIT_HLIST_HEAD(&xfrm6_tunnel_spi_byspi[i]);
        return 0;
 }
 
 static void xfrm6_tunnel_spi_fini(void)
 {
-       int i;
-
-       for (i = 0; i < XFRM6_TUNNEL_SPI_BYADDR_HSIZE; i++) {
-               if (!hlist_empty(&xfrm6_tunnel_spi_byaddr[i]))
-                       return;
-       }
-       for (i = 0; i < XFRM6_TUNNEL_SPI_BYSPI_HSIZE; i++) {
-               if (!hlist_empty(&xfrm6_tunnel_spi_byspi[i]))
-                       return;
-       }
-       rcu_barrier();
        kmem_cache_destroy(xfrm6_tunnel_spi_kmem);
-       xfrm6_tunnel_spi_kmem = NULL;
 }
 
-static struct xfrm6_tunnel_spi *__xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr)
+static struct xfrm6_tunnel_spi *__xfrm6_tunnel_spi_lookup(struct net *net, xfrm_address_t *saddr)
 {
+       struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net);
        struct xfrm6_tunnel_spi *x6spi;
        struct hlist_node *pos;
 
        hlist_for_each_entry_rcu(x6spi, pos,
-                            &xfrm6_tunnel_spi_byaddr[xfrm6_tunnel_spi_hash_byaddr(saddr)],
+                            &xfrm6_tn->spi_byaddr[xfrm6_tunnel_spi_hash_byaddr(saddr)],
                             list_byaddr) {
                if (memcmp(&x6spi->addr, saddr, sizeof(x6spi->addr)) == 0)
                        return x6spi;
@@ -128,13 +117,13 @@ static struct xfrm6_tunnel_spi *__xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr)
        return NULL;
 }
 
-__be32 xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr)
+__be32 xfrm6_tunnel_spi_lookup(struct net *net, xfrm_address_t *saddr)
 {
        struct xfrm6_tunnel_spi *x6spi;
        u32 spi;
 
        rcu_read_lock_bh();
-       x6spi = __xfrm6_tunnel_spi_lookup(saddr);
+       x6spi = __xfrm6_tunnel_spi_lookup(net, saddr);
        spi = x6spi ? x6spi->spi : 0;
        rcu_read_unlock_bh();
        return htonl(spi);
@@ -142,14 +131,15 @@ __be32 xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr)
 
 EXPORT_SYMBOL(xfrm6_tunnel_spi_lookup);
 
-static int __xfrm6_tunnel_spi_check(u32 spi)
+static int __xfrm6_tunnel_spi_check(struct net *net, u32 spi)
 {
+       struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net);
        struct xfrm6_tunnel_spi *x6spi;
        int index = xfrm6_tunnel_spi_hash_byspi(spi);
        struct hlist_node *pos;
 
        hlist_for_each_entry(x6spi, pos,
-                            &xfrm6_tunnel_spi_byspi[index],
+                            &xfrm6_tn->spi_byspi[index],
                             list_byspi) {
                if (x6spi->spi == spi)
                        return -1;
@@ -157,32 +147,33 @@ static int __xfrm6_tunnel_spi_check(u32 spi)
        return index;
 }
 
-static u32 __xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr)
+static u32 __xfrm6_tunnel_alloc_spi(struct net *net, xfrm_address_t *saddr)
 {
+       struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net);
        u32 spi;
        struct xfrm6_tunnel_spi *x6spi;
        int index;
 
-       if (xfrm6_tunnel_spi < XFRM6_TUNNEL_SPI_MIN ||
-           xfrm6_tunnel_spi >= XFRM6_TUNNEL_SPI_MAX)
-               xfrm6_tunnel_spi = XFRM6_TUNNEL_SPI_MIN;
+       if (xfrm6_tn->spi < XFRM6_TUNNEL_SPI_MIN ||
+           xfrm6_tn->spi >= XFRM6_TUNNEL_SPI_MAX)
+               xfrm6_tn->spi = XFRM6_TUNNEL_SPI_MIN;
        else
-               xfrm6_tunnel_spi++;
+               xfrm6_tn->spi++;
 
-       for (spi = xfrm6_tunnel_spi; spi <= XFRM6_TUNNEL_SPI_MAX; spi++) {
-               index = __xfrm6_tunnel_spi_check(spi);
+       for (spi = xfrm6_tn->spi; spi <= XFRM6_TUNNEL_SPI_MAX; spi++) {
+               index = __xfrm6_tunnel_spi_check(net, spi);
                if (index >= 0)
                        goto alloc_spi;
        }
-       for (spi = XFRM6_TUNNEL_SPI_MIN; spi < xfrm6_tunnel_spi; spi++) {
-               index = __xfrm6_tunnel_spi_check(spi);
+       for (spi = XFRM6_TUNNEL_SPI_MIN; spi < xfrm6_tn->spi; spi++) {
+               index = __xfrm6_tunnel_spi_check(net, spi);
                if (index >= 0)
                        goto alloc_spi;
        }
        spi = 0;
        goto out;
 alloc_spi:
-       xfrm6_tunnel_spi = spi;
+       xfrm6_tn->spi = spi;
        x6spi = kmem_cache_alloc(xfrm6_tunnel_spi_kmem, GFP_ATOMIC);
        if (!x6spi)
                goto out;
@@ -192,26 +183,26 @@ alloc_spi:
        x6spi->spi = spi;
        atomic_set(&x6spi->refcnt, 1);
 
-       hlist_add_head_rcu(&x6spi->list_byspi, &xfrm6_tunnel_spi_byspi[index]);
+       hlist_add_head_rcu(&x6spi->list_byspi, &xfrm6_tn->spi_byspi[index]);
 
        index = xfrm6_tunnel_spi_hash_byaddr(saddr);
-       hlist_add_head_rcu(&x6spi->list_byaddr, &xfrm6_tunnel_spi_byaddr[index]);
+       hlist_add_head_rcu(&x6spi->list_byaddr, &xfrm6_tn->spi_byaddr[index]);
 out:
        return spi;
 }
 
-__be32 xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr)
+__be32 xfrm6_tunnel_alloc_spi(struct net *net, xfrm_address_t *saddr)
 {
        struct xfrm6_tunnel_spi *x6spi;
        u32 spi;
 
        spin_lock_bh(&xfrm6_tunnel_spi_lock);
-       x6spi = __xfrm6_tunnel_spi_lookup(saddr);
+       x6spi = __xfrm6_tunnel_spi_lookup(net, saddr);
        if (x6spi) {
                atomic_inc(&x6spi->refcnt);
                spi = x6spi->spi;
        } else
-               spi = __xfrm6_tunnel_alloc_spi(saddr);
+               spi = __xfrm6_tunnel_alloc_spi(net, saddr);
        spin_unlock_bh(&xfrm6_tunnel_spi_lock);
 
        return htonl(spi);
@@ -225,15 +216,16 @@ static void x6spi_destroy_rcu(struct rcu_head *head)
                        container_of(head, struct xfrm6_tunnel_spi, rcu_head));
 }
 
-void xfrm6_tunnel_free_spi(xfrm_address_t *saddr)
+void xfrm6_tunnel_free_spi(struct net *net, xfrm_address_t *saddr)
 {
+       struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net);
        struct xfrm6_tunnel_spi *x6spi;
        struct hlist_node *pos, *n;
 
        spin_lock_bh(&xfrm6_tunnel_spi_lock);
 
        hlist_for_each_entry_safe(x6spi, pos, n,
-                                 &xfrm6_tunnel_spi_byaddr[xfrm6_tunnel_spi_hash_byaddr(saddr)],
+                                 &xfrm6_tn->spi_byaddr[xfrm6_tunnel_spi_hash_byaddr(saddr)],
                                  list_byaddr)
        {
                if (memcmp(&x6spi->addr, saddr, sizeof(x6spi->addr)) == 0) {
@@ -263,10 +255,11 @@ static int xfrm6_tunnel_input(struct xfrm_state *x, struct sk_buff *skb)
 
 static int xfrm6_tunnel_rcv(struct sk_buff *skb)
 {
+       struct net *net = dev_net(skb->dev);
        struct ipv6hdr *iph = ipv6_hdr(skb);
        __be32 spi;
 
-       spi = xfrm6_tunnel_spi_lookup((xfrm_address_t *)&iph->saddr);
+       spi = xfrm6_tunnel_spi_lookup(net, (xfrm_address_t *)&iph->saddr);
        return xfrm6_rcv_spi(skb, IPPROTO_IPV6, spi) > 0 ? : 0;
 }
 
@@ -326,7 +319,9 @@ static int xfrm6_tunnel_init_state(struct xfrm_state *x)
 
 static void xfrm6_tunnel_destroy(struct xfrm_state *x)
 {
-       xfrm6_tunnel_free_spi((xfrm_address_t *)&x->props.saddr);
+       struct net *net = xs_net(x);
+
+       xfrm6_tunnel_free_spi(net, (xfrm_address_t *)&x->props.saddr);
 }
 
 static const struct xfrm_type xfrm6_tunnel_type = {
@@ -351,18 +346,54 @@ static struct xfrm6_tunnel xfrm46_tunnel_handler = {
        .priority       = 2,
 };
 
+static int __net_init xfrm6_tunnel_net_init(struct net *net)
+{
+       struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net);
+       unsigned int i;
+
+       for (i = 0; i < XFRM6_TUNNEL_SPI_BYADDR_HSIZE; i++)
+               INIT_HLIST_HEAD(&xfrm6_tn->spi_byaddr[i]);
+       for (i = 0; i < XFRM6_TUNNEL_SPI_BYSPI_HSIZE; i++)
+               INIT_HLIST_HEAD(&xfrm6_tn->spi_byspi[i]);
+       xfrm6_tn->spi = 0;
+
+       return 0;
+}
+
+static void __net_exit xfrm6_tunnel_net_exit(struct net *net)
+{
+}
+
+static struct pernet_operations xfrm6_tunnel_net_ops = {
+       .init   = xfrm6_tunnel_net_init,
+       .exit   = xfrm6_tunnel_net_exit,
+       .id     = &xfrm6_tunnel_net_id,
+       .size   = sizeof(struct xfrm6_tunnel_net),
+};
+
 static int __init xfrm6_tunnel_init(void)
 {
-       if (xfrm_register_type(&xfrm6_tunnel_type, AF_INET6) < 0)
+       int rv;
+
+       rv = xfrm_register_type(&xfrm6_tunnel_type, AF_INET6);
+       if (rv < 0)
                goto err;
-       if (xfrm6_tunnel_register(&xfrm6_tunnel_handler, AF_INET6))
+       rv = xfrm6_tunnel_register(&xfrm6_tunnel_handler, AF_INET6);
+       if (rv < 0)
                goto unreg;
-       if (xfrm6_tunnel_register(&xfrm46_tunnel_handler, AF_INET))
+       rv = xfrm6_tunnel_register(&xfrm46_tunnel_handler, AF_INET);
+       if (rv < 0)
                goto dereg6;
-       if (xfrm6_tunnel_spi_init() < 0)
+       rv = xfrm6_tunnel_spi_init();
+       if (rv < 0)
                goto dereg46;
+       rv = register_pernet_subsys(&xfrm6_tunnel_net_ops);
+       if (rv < 0)
+               goto deregspi;
        return 0;
 
+deregspi:
+       xfrm6_tunnel_spi_fini();
 dereg46:
        xfrm6_tunnel_deregister(&xfrm46_tunnel_handler, AF_INET);
 dereg6:
@@ -370,11 +401,12 @@ dereg6:
 unreg:
        xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6);
 err:
-       return -EAGAIN;
+       return rv;
 }
 
 static void __exit xfrm6_tunnel_fini(void)
 {
+       unregister_pernet_subsys(&xfrm6_tunnel_net_ops);
        xfrm6_tunnel_spi_fini();
        xfrm6_tunnel_deregister(&xfrm46_tunnel_handler, AF_INET);
        xfrm6_tunnel_deregister(&xfrm6_tunnel_handler, AF_INET6);
index 811984d9324b6ea0f925d4d3124db1bc7c0e575a..8b85d774e47fe5dbe2d526eaff6bdf7215a2057b 100644 (file)
@@ -496,9 +496,6 @@ static void ircomm_tty_close(struct tty_struct *tty, struct file *filp)
 
        IRDA_DEBUG(0, "%s()\n", __func__ );
 
-       if (!tty)
-               return;
-
        IRDA_ASSERT(self != NULL, return;);
        IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
 
@@ -1007,9 +1004,6 @@ static void ircomm_tty_hangup(struct tty_struct *tty)
        IRDA_ASSERT(self != NULL, return;);
        IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
 
-       if (!tty)
-               return;
-
        /* ircomm_tty_flush_buffer(tty); */
        ircomm_tty_shutdown(self);
 
index 539f43bc97db79955925b4b6e6442df64548fffc..41dd2cb07ef308817188d8543a8f5ffce77b4f8a 100644 (file)
@@ -3019,12 +3019,11 @@ static int pfkey_send_policy_notify(struct xfrm_policy *xp, int dir, struct km_e
 static u32 get_acqseq(void)
 {
        u32 res;
-       static u32 acqseq;
-       static DEFINE_SPINLOCK(acqseq_lock);
+       static atomic_t acqseq;
 
-       spin_lock_bh(&acqseq_lock);
-       res = (++acqseq ? : ++acqseq);
-       spin_unlock_bh(&acqseq_lock);
+       do {
+               res = atomic_inc_return(&acqseq);
+       } while (!res);
        return res;
 }
 
@@ -3738,17 +3737,17 @@ static int __net_init pfkey_init_proc(struct net *net)
        return 0;
 }
 
-static void pfkey_exit_proc(struct net *net)
+static void __net_exit pfkey_exit_proc(struct net *net)
 {
        proc_net_remove(net, "pfkey");
 }
 #else
-static int __net_init pfkey_init_proc(struct net *net)
+static inline int pfkey_init_proc(struct net *net)
 {
        return 0;
 }
 
-static void pfkey_exit_proc(struct net *net)
+static inline void pfkey_exit_proc(struct net *net)
 {
 }
 #endif
index 3a66546cad06b1c2be3ab9ab9bba833766947bbf..e35d907fba2c20e5b931751584ecacd68f0c4c9e 100644 (file)
@@ -47,6 +47,10 @@ static int llc_ui_wait_for_busy_core(struct sock *sk, long timeout);
 #define dprintk(args...)
 #endif
 
+/* Maybe we'll add some more in the future. */
+#define LLC_CMSG_PKTINFO       1
+
+
 /**
  *     llc_ui_next_link_no - return the next unused link number for a sap
  *     @sap: Address of sap to get link number from.
@@ -136,6 +140,7 @@ static struct proto llc_proto = {
        .name     = "LLC",
        .owner    = THIS_MODULE,
        .obj_size = sizeof(struct llc_sock),
+       .slab_flags = SLAB_DESTROY_BY_RCU,
 };
 
 /**
@@ -192,10 +197,8 @@ static int llc_ui_release(struct socket *sock)
                llc->laddr.lsap, llc->daddr.lsap);
        if (!llc_send_disc(sk))
                llc_ui_wait_for_disc(sk, sk->sk_rcvtimeo);
-       if (!sock_flag(sk, SOCK_ZAPPED)) {
-               llc_sap_put(llc->sap);
+       if (!sock_flag(sk, SOCK_ZAPPED))
                llc_sap_remove_socket(llc->sap, sk);
-       }
        release_sock(sk);
        if (llc->dev)
                dev_put(llc->dev);
@@ -255,7 +258,14 @@ static int llc_ui_autobind(struct socket *sock, struct sockaddr_llc *addr)
        if (!sock_flag(sk, SOCK_ZAPPED))
                goto out;
        rc = -ENODEV;
-       llc->dev = dev_getfirstbyhwtype(&init_net, addr->sllc_arphrd);
+       if (sk->sk_bound_dev_if) {
+               llc->dev = dev_get_by_index(&init_net, sk->sk_bound_dev_if);
+               if (llc->dev && addr->sllc_arphrd != llc->dev->type) {
+                       dev_put(llc->dev);
+                       llc->dev = NULL;
+               }
+       } else
+               llc->dev = dev_getfirstbyhwtype(&init_net, addr->sllc_arphrd);
        if (!llc->dev)
                goto out;
        rc = -EUSERS;
@@ -306,7 +316,25 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen)
                goto out;
        rc = -ENODEV;
        rtnl_lock();
-       llc->dev = dev_getbyhwaddr(&init_net, addr->sllc_arphrd, addr->sllc_mac);
+       if (sk->sk_bound_dev_if) {
+               llc->dev = dev_get_by_index(&init_net, sk->sk_bound_dev_if);
+               if (llc->dev) {
+                       if (!addr->sllc_arphrd)
+                               addr->sllc_arphrd = llc->dev->type;
+                       if (llc_mac_null(addr->sllc_mac))
+                               memcpy(addr->sllc_mac, llc->dev->dev_addr,
+                                      IFHWADDRLEN);
+                       if (addr->sllc_arphrd != llc->dev->type ||
+                           !llc_mac_match(addr->sllc_mac,
+                                          llc->dev->dev_addr)) {
+                               rc = -EINVAL;
+                               dev_put(llc->dev);
+                               llc->dev = NULL;
+                       }
+               }
+       } else
+               llc->dev = dev_getbyhwaddr(&init_net, addr->sllc_arphrd,
+                                          addr->sllc_mac);
        rtnl_unlock();
        if (!llc->dev)
                goto out;
@@ -322,7 +350,6 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen)
                rc = -EBUSY; /* some other network layer is using the sap */
                if (!sap)
                        goto out;
-               llc_sap_hold(sap);
        } else {
                struct llc_addr laddr, daddr;
                struct sock *ask;
@@ -591,6 +618,20 @@ static int llc_wait_data(struct sock *sk, long timeo)
        return rc;
 }
 
+static void llc_cmsg_rcv(struct msghdr *msg, struct sk_buff *skb)
+{
+       struct llc_sock *llc = llc_sk(skb->sk);
+
+       if (llc->cmsg_flags & LLC_CMSG_PKTINFO) {
+               struct llc_pktinfo info;
+
+               info.lpi_ifindex = llc_sk(skb->sk)->dev->ifindex;
+               llc_pdu_decode_dsap(skb, &info.lpi_sap);
+               llc_pdu_decode_da(skb, info.lpi_mac);
+               put_cmsg(msg, SOL_LLC, LLC_OPT_PKTINFO, sizeof(info), &info);
+       }
+}
+
 /**
  *     llc_ui_accept - accept a new incoming connection.
  *     @sock: Socket which connections arrive on.
@@ -812,6 +853,8 @@ copy_uaddr:
                memcpy(uaddr, llc_ui_skb_cb(skb), sizeof(*uaddr));
                msg->msg_namelen = sizeof(*uaddr);
        }
+       if (llc_sk(sk)->cmsg_flags)
+               llc_cmsg_rcv(msg, skb);
        goto out;
 }
 
@@ -1030,6 +1073,12 @@ static int llc_ui_setsockopt(struct socket *sock, int level, int optname,
                        goto out;
                llc->rw = opt;
                break;
+       case LLC_OPT_PKTINFO:
+               if (opt)
+                       llc->cmsg_flags |= LLC_CMSG_PKTINFO;
+               else
+                       llc->cmsg_flags &= ~LLC_CMSG_PKTINFO;
+               break;
        default:
                rc = -ENOPROTOOPT;
                goto out;
@@ -1083,6 +1132,9 @@ static int llc_ui_getsockopt(struct socket *sock, int level, int optname,
                val = llc->k;                           break;
        case LLC_OPT_RX_WIN:
                val = llc->rw;                          break;
+       case LLC_OPT_PKTINFO:
+               val = (llc->cmsg_flags & LLC_CMSG_PKTINFO) != 0;
+               break;
        default:
                rc = -ENOPROTOOPT;
                goto out;
index c6bab39b018e75174874432ff06edb1890f3fd5e..a8dde9b010da7e44cb407d5954f7678ac2d585dd 100644 (file)
@@ -468,6 +468,19 @@ static int llc_exec_conn_trans_actions(struct sock *sk,
        return rc;
 }
 
+static inline bool llc_estab_match(const struct llc_sap *sap,
+                                  const struct llc_addr *daddr,
+                                  const struct llc_addr *laddr,
+                                  const struct sock *sk)
+{
+       struct llc_sock *llc = llc_sk(sk);
+
+       return llc->laddr.lsap == laddr->lsap &&
+               llc->daddr.lsap == daddr->lsap &&
+               llc_mac_match(llc->laddr.mac, laddr->mac) &&
+               llc_mac_match(llc->daddr.mac, daddr->mac);
+}
+
 /**
  *     __llc_lookup_established - Finds connection for the remote/local sap/mac
  *     @sap: SAP
@@ -484,23 +497,35 @@ static struct sock *__llc_lookup_established(struct llc_sap *sap,
                                             struct llc_addr *laddr)
 {
        struct sock *rc;
-       struct hlist_node *node;
-
-       read_lock(&sap->sk_list.lock);
-       sk_for_each(rc, node, &sap->sk_list.list) {
-               struct llc_sock *llc = llc_sk(rc);
-
-               if (llc->laddr.lsap == laddr->lsap &&
-                   llc->daddr.lsap == daddr->lsap &&
-                   llc_mac_match(llc->laddr.mac, laddr->mac) &&
-                   llc_mac_match(llc->daddr.mac, daddr->mac)) {
-                       sock_hold(rc);
+       struct hlist_nulls_node *node;
+       int slot = llc_sk_laddr_hashfn(sap, laddr);
+       struct hlist_nulls_head *laddr_hb = &sap->sk_laddr_hash[slot];
+
+       rcu_read_lock();
+again:
+       sk_nulls_for_each_rcu(rc, node, laddr_hb) {
+               if (llc_estab_match(sap, daddr, laddr, rc)) {
+                       /* Extra checks required by SLAB_DESTROY_BY_RCU */
+                       if (unlikely(!atomic_inc_not_zero(&rc->sk_refcnt)))
+                               goto again;
+                       if (unlikely(llc_sk(rc)->sap != sap ||
+                                    !llc_estab_match(sap, daddr, laddr, rc))) {
+                               sock_put(rc);
+                               continue;
+                       }
                        goto found;
                }
        }
        rc = NULL;
+       /*
+        * if the nulls value we got at the end of this lookup is
+        * not the expected one, we must restart lookup.
+        * We probably met an item that was moved to another chain.
+        */
+       if (unlikely(get_nulls_value(node) != slot))
+               goto again;
 found:
-       read_unlock(&sap->sk_list.lock);
+       rcu_read_unlock();
        return rc;
 }
 
@@ -516,6 +541,53 @@ struct sock *llc_lookup_established(struct llc_sap *sap,
        return sk;
 }
 
+static inline bool llc_listener_match(const struct llc_sap *sap,
+                                     const struct llc_addr *laddr,
+                                     const struct sock *sk)
+{
+       struct llc_sock *llc = llc_sk(sk);
+
+       return sk->sk_type == SOCK_STREAM && sk->sk_state == TCP_LISTEN &&
+               llc->laddr.lsap == laddr->lsap &&
+               llc_mac_match(llc->laddr.mac, laddr->mac);
+}
+
+static struct sock *__llc_lookup_listener(struct llc_sap *sap,
+                                         struct llc_addr *laddr)
+{
+       struct sock *rc;
+       struct hlist_nulls_node *node;
+       int slot = llc_sk_laddr_hashfn(sap, laddr);
+       struct hlist_nulls_head *laddr_hb = &sap->sk_laddr_hash[slot];
+
+       rcu_read_lock();
+again:
+       sk_nulls_for_each_rcu(rc, node, laddr_hb) {
+               if (llc_listener_match(sap, laddr, rc)) {
+                       /* Extra checks required by SLAB_DESTROY_BY_RCU */
+                       if (unlikely(!atomic_inc_not_zero(&rc->sk_refcnt)))
+                               goto again;
+                       if (unlikely(llc_sk(rc)->sap != sap ||
+                                    !llc_listener_match(sap, laddr, rc))) {
+                               sock_put(rc);
+                               continue;
+                       }
+                       goto found;
+               }
+       }
+       rc = NULL;
+       /*
+        * if the nulls value we got at the end of this lookup is
+        * not the expected one, we must restart lookup.
+        * We probably met an item that was moved to another chain.
+        */
+       if (unlikely(get_nulls_value(node) != slot))
+               goto again;
+found:
+       rcu_read_unlock();
+       return rc;
+}
+
 /**
  *     llc_lookup_listener - Finds listener for local MAC + SAP
  *     @sap: SAP
@@ -529,24 +601,12 @@ struct sock *llc_lookup_established(struct llc_sap *sap,
 static struct sock *llc_lookup_listener(struct llc_sap *sap,
                                        struct llc_addr *laddr)
 {
-       struct sock *rc;
-       struct hlist_node *node;
+       static struct llc_addr null_addr;
+       struct sock *rc = __llc_lookup_listener(sap, laddr);
 
-       read_lock(&sap->sk_list.lock);
-       sk_for_each(rc, node, &sap->sk_list.list) {
-               struct llc_sock *llc = llc_sk(rc);
+       if (!rc)
+               rc = __llc_lookup_listener(sap, &null_addr);
 
-               if (rc->sk_type == SOCK_STREAM && rc->sk_state == TCP_LISTEN &&
-                   llc->laddr.lsap == laddr->lsap &&
-                   (llc_mac_match(llc->laddr.mac, laddr->mac) ||
-                    llc_mac_null(llc->laddr.mac))) {
-                       sock_hold(rc);
-                       goto found;
-               }
-       }
-       rc = NULL;
-found:
-       read_unlock(&sap->sk_list.lock);
        return rc;
 }
 
@@ -647,15 +707,22 @@ static int llc_find_offset(int state, int ev_type)
  *     @sap: SAP
  *     @sk: socket
  *
- *     This function adds a socket to sk_list of a SAP.
+ *     This function adds a socket to the hash tables of a SAP.
  */
 void llc_sap_add_socket(struct llc_sap *sap, struct sock *sk)
 {
+       struct llc_sock *llc = llc_sk(sk);
+       struct hlist_head *dev_hb = llc_sk_dev_hash(sap, llc->dev->ifindex);
+       struct hlist_nulls_head *laddr_hb = llc_sk_laddr_hash(sap, &llc->laddr);
+
        llc_sap_hold(sap);
-       write_lock_bh(&sap->sk_list.lock);
        llc_sk(sk)->sap = sap;
-       sk_add_node(sk, &sap->sk_list.list);
-       write_unlock_bh(&sap->sk_list.lock);
+
+       spin_lock_bh(&sap->sk_lock);
+       sap->sk_count++;
+       sk_nulls_add_node_rcu(sk, laddr_hb);
+       hlist_add_head(&llc->dev_hash_node, dev_hb);
+       spin_unlock_bh(&sap->sk_lock);
 }
 
 /**
@@ -663,14 +730,18 @@ void llc_sap_add_socket(struct llc_sap *sap, struct sock *sk)
  *     @sap: SAP
  *     @sk: socket
  *
- *     This function removes a connection from sk_list.list of a SAP if
+ *     This function removes a connection from the hash tables of a SAP if
  *     the connection was in this list.
  */
 void llc_sap_remove_socket(struct llc_sap *sap, struct sock *sk)
 {
-       write_lock_bh(&sap->sk_list.lock);
-       sk_del_node_init(sk);
-       write_unlock_bh(&sap->sk_list.lock);
+       struct llc_sock *llc = llc_sk(sk);
+
+       spin_lock_bh(&sap->sk_lock);
+       sk_nulls_del_node_init_rcu(sk);
+       hlist_del(&llc->dev_hash_node);
+       sap->sk_count--;
+       spin_unlock_bh(&sap->sk_lock);
        llc_sap_put(sap);
 }
 
index ff4c0ab96a69364eaca829618dcf9a66d7c5022e..78167e81dfebdf0be0510df3ff82b7c82da68b38 100644 (file)
@@ -23,7 +23,7 @@
 #include <net/llc.h>
 
 LIST_HEAD(llc_sap_list);
-DEFINE_RWLOCK(llc_sap_list_lock);
+DEFINE_SPINLOCK(llc_sap_list_lock);
 
 /**
  *     llc_sap_alloc - allocates and initializes sap.
@@ -33,40 +33,19 @@ DEFINE_RWLOCK(llc_sap_list_lock);
 static struct llc_sap *llc_sap_alloc(void)
 {
        struct llc_sap *sap = kzalloc(sizeof(*sap), GFP_ATOMIC);
+       int i;
 
        if (sap) {
                /* sap->laddr.mac - leave as a null, it's filled by bind */
                sap->state = LLC_SAP_STATE_ACTIVE;
-               rwlock_init(&sap->sk_list.lock);
+               spin_lock_init(&sap->sk_lock);
+               for (i = 0; i < LLC_SK_LADDR_HASH_ENTRIES; i++)
+                       INIT_HLIST_NULLS_HEAD(&sap->sk_laddr_hash[i], i);
                atomic_set(&sap->refcnt, 1);
        }
        return sap;
 }
 
-/**
- *     llc_add_sap - add sap to station list
- *     @sap: Address of the sap
- *
- *     Adds a sap to the LLC's station sap list.
- */
-static void llc_add_sap(struct llc_sap *sap)
-{
-       list_add_tail(&sap->node, &llc_sap_list);
-}
-
-/**
- *     llc_del_sap - del sap from station list
- *     @sap: Address of the sap
- *
- *     Removes a sap to the LLC's station sap list.
- */
-static void llc_del_sap(struct llc_sap *sap)
-{
-       write_lock_bh(&llc_sap_list_lock);
-       list_del(&sap->node);
-       write_unlock_bh(&llc_sap_list_lock);
-}
-
 static struct llc_sap *__llc_sap_find(unsigned char sap_value)
 {
        struct llc_sap* sap;
@@ -90,13 +69,13 @@ out:
  */
 struct llc_sap *llc_sap_find(unsigned char sap_value)
 {
-       struct llc_sapsap;
+       struct llc_sap *sap;
 
-       read_lock_bh(&llc_sap_list_lock);
+       rcu_read_lock_bh();
        sap = __llc_sap_find(sap_value);
        if (sap)
                llc_sap_hold(sap);
-       read_unlock_bh(&llc_sap_list_lock);
+       rcu_read_unlock_bh();
        return sap;
 }
 
@@ -117,7 +96,7 @@ struct llc_sap *llc_sap_open(unsigned char lsap,
 {
        struct llc_sap *sap = NULL;
 
-       write_lock_bh(&llc_sap_list_lock);
+       spin_lock_bh(&llc_sap_list_lock);
        if (__llc_sap_find(lsap)) /* SAP already exists */
                goto out;
        sap = llc_sap_alloc();
@@ -125,9 +104,9 @@ struct llc_sap *llc_sap_open(unsigned char lsap,
                goto out;
        sap->laddr.lsap = lsap;
        sap->rcv_func   = func;
-       llc_add_sap(sap);
+       list_add_tail_rcu(&sap->node, &llc_sap_list);
 out:
-       write_unlock_bh(&llc_sap_list_lock);
+       spin_unlock_bh(&llc_sap_list_lock);
        return sap;
 }
 
@@ -142,8 +121,14 @@ out:
  */
 void llc_sap_close(struct llc_sap *sap)
 {
-       WARN_ON(!hlist_empty(&sap->sk_list.list));
-       llc_del_sap(sap);
+       WARN_ON(sap->sk_count);
+
+       spin_lock_bh(&llc_sap_list_lock);
+       list_del_rcu(&sap->node);
+       spin_unlock_bh(&llc_sap_list_lock);
+
+       synchronize_rcu();
+
        kfree(sap);
 }
 
index 754f4fedc852fb6181d5c5bed0146096d5ff12f4..b38a1079a98eac59dd1737b6f5bb7e7bf5437a54 100644 (file)
 int llc_mac_hdr_init(struct sk_buff *skb,
                     const unsigned char *sa, const unsigned char *da)
 {
-       int rc = 0;
+       int rc = -EINVAL;
 
        switch (skb->dev->type) {
-#ifdef CONFIG_TR
-       case ARPHRD_IEEE802_TR: {
-               struct net_device *dev = skb->dev;
-               struct trh_hdr *trh;
-
-               skb_push(skb, sizeof(*trh));
-               skb_reset_mac_header(skb);
-               trh = tr_hdr(skb);
-               trh->ac = AC;
-               trh->fc = LLC_FRAME;
-               if (sa)
-                       memcpy(trh->saddr, sa, dev->addr_len);
-               else
-                       memset(trh->saddr, 0, dev->addr_len);
-               if (da) {
-                       memcpy(trh->daddr, da, dev->addr_len);
-                       tr_source_route(skb, trh, dev);
-                       skb_reset_mac_header(skb);
-               }
-               break;
-       }
-#endif
+       case ARPHRD_IEEE802_TR:
        case ARPHRD_ETHER:
-       case ARPHRD_LOOPBACK: {
-               unsigned short len = skb->len;
-               struct ethhdr *eth;
-
-               skb_push(skb, sizeof(*eth));
-               skb_reset_mac_header(skb);
-               eth = eth_hdr(skb);
-               eth->h_proto = htons(len);
-               memcpy(eth->h_dest, da, ETH_ALEN);
-               memcpy(eth->h_source, sa, ETH_ALEN);
+       case ARPHRD_LOOPBACK:
+               rc = dev_hard_header(skb, skb->dev, ETH_P_802_2, da, sa,
+                                    skb->len);
+               if (rc > 0)
+                       rc = 0;
                break;
-       }
        default:
-               printk(KERN_WARNING "device type not supported: %d\n",
-                      skb->dev->type);
-               rc = -EINVAL;
+               WARN(1, "device type not supported: %d\n", skb->dev->type);
        }
        return rc;
 }
index be47ac427f6b23afc23888081ab1edf89346c280..7af1ff2d1f1974ff339865beece31e8c09d6d449 100644 (file)
@@ -32,21 +32,23 @@ static void llc_ui_format_mac(struct seq_file *seq, u8 *addr)
 
 static struct sock *llc_get_sk_idx(loff_t pos)
 {
-       struct list_head *sap_entry;
        struct llc_sap *sap;
-       struct hlist_node *node;
        struct sock *sk = NULL;
-
-       list_for_each(sap_entry, &llc_sap_list) {
-               sap = list_entry(sap_entry, struct llc_sap, node);
-
-               read_lock_bh(&sap->sk_list.lock);
-               sk_for_each(sk, node, &sap->sk_list.list) {
-                       if (!pos)
-                               goto found;
-                       --pos;
+       int i;
+
+       list_for_each_entry_rcu(sap, &llc_sap_list, node) {
+               spin_lock_bh(&sap->sk_lock);
+               for (i = 0; i < LLC_SK_LADDR_HASH_ENTRIES; i++) {
+                       struct hlist_nulls_head *head = &sap->sk_laddr_hash[i];
+                       struct hlist_nulls_node *node;
+
+                       sk_nulls_for_each(sk, node, head) {
+                               if (!pos)
+                                       goto found; /* keep the lock */
+                               --pos;
+                       }
                }
-               read_unlock_bh(&sap->sk_list.lock);
+               spin_unlock_bh(&sap->sk_lock);
        }
        sk = NULL;
 found:
@@ -57,10 +59,23 @@ static void *llc_seq_start(struct seq_file *seq, loff_t *pos)
 {
        loff_t l = *pos;
 
-       read_lock_bh(&llc_sap_list_lock);
+       rcu_read_lock_bh();
        return l ? llc_get_sk_idx(--l) : SEQ_START_TOKEN;
 }
 
+static struct sock *laddr_hash_next(struct llc_sap *sap, int bucket)
+{
+       struct hlist_nulls_node *node;
+       struct sock *sk = NULL;
+
+       while (++bucket < LLC_SK_LADDR_HASH_ENTRIES)
+               sk_nulls_for_each(sk, node, &sap->sk_laddr_hash[bucket])
+                       goto out;
+
+out:
+       return sk;
+}
+
 static void *llc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 {
        struct sock* sk, *next;
@@ -73,25 +88,23 @@ static void *llc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
                goto out;
        }
        sk = v;
-       next = sk_next(sk);
+       next = sk_nulls_next(sk);
        if (next) {
                sk = next;
                goto out;
        }
        llc = llc_sk(sk);
        sap = llc->sap;
-       read_unlock_bh(&sap->sk_list.lock);
-       sk = NULL;
-       for (;;) {
-               if (sap->node.next == &llc_sap_list)
-                       break;
-               sap = list_entry(sap->node.next, struct llc_sap, node);
-               read_lock_bh(&sap->sk_list.lock);
-               if (!hlist_empty(&sap->sk_list.list)) {
-                       sk = sk_head(&sap->sk_list.list);
-                       break;
-               }
-               read_unlock_bh(&sap->sk_list.lock);
+       sk = laddr_hash_next(sap, llc_sk_laddr_hashfn(sap, &llc->laddr));
+       if (sk)
+               goto out;
+       spin_unlock_bh(&sap->sk_lock);
+       list_for_each_entry_continue_rcu(sap, &llc_sap_list, node) {
+               spin_lock_bh(&sap->sk_lock);
+               sk = laddr_hash_next(sap, -1);
+               if (sk)
+                       break; /* keep the lock */
+               spin_unlock_bh(&sap->sk_lock);
        }
 out:
        return sk;
@@ -104,9 +117,9 @@ static void llc_seq_stop(struct seq_file *seq, void *v)
                struct llc_sock *llc = llc_sk(sk);
                struct llc_sap *sap = llc->sap;
 
-               read_unlock_bh(&sap->sk_list.lock);
+               spin_unlock_bh(&sap->sk_lock);
        }
-       read_unlock_bh(&llc_sap_list_lock);
+       rcu_read_unlock_bh();
 }
 
 static int llc_seq_socket_show(struct seq_file *seq, void *v)
index 008de1fc42ca79b07cafed68ccb3e7e396161dc9..ad6e6e1cf22fce1eefa43d1726537d3b5bf644dc 100644 (file)
@@ -297,6 +297,17 @@ static void llc_sap_rcv(struct llc_sap *sap, struct sk_buff *skb,
        llc_sap_state_process(sap, skb);
 }
 
+static inline bool llc_dgram_match(const struct llc_sap *sap,
+                                  const struct llc_addr *laddr,
+                                  const struct sock *sk)
+{
+     struct llc_sock *llc = llc_sk(sk);
+
+     return sk->sk_type == SOCK_DGRAM &&
+         llc->laddr.lsap == laddr->lsap &&
+         llc_mac_match(llc->laddr.mac, laddr->mac);
+}
+
 /**
  *     llc_lookup_dgram - Finds dgram socket for the local sap/mac
  *     @sap: SAP
@@ -309,25 +320,68 @@ static struct sock *llc_lookup_dgram(struct llc_sap *sap,
                                     const struct llc_addr *laddr)
 {
        struct sock *rc;
-       struct hlist_node *node;
-
-       read_lock_bh(&sap->sk_list.lock);
-       sk_for_each(rc, node, &sap->sk_list.list) {
-               struct llc_sock *llc = llc_sk(rc);
-
-               if (rc->sk_type == SOCK_DGRAM &&
-                   llc->laddr.lsap == laddr->lsap &&
-                   llc_mac_match(llc->laddr.mac, laddr->mac)) {
-                       sock_hold(rc);
+       struct hlist_nulls_node *node;
+       int slot = llc_sk_laddr_hashfn(sap, laddr);
+       struct hlist_nulls_head *laddr_hb = &sap->sk_laddr_hash[slot];
+
+       rcu_read_lock_bh();
+again:
+       sk_nulls_for_each_rcu(rc, node, laddr_hb) {
+               if (llc_dgram_match(sap, laddr, rc)) {
+                       /* Extra checks required by SLAB_DESTROY_BY_RCU */
+                       if (unlikely(!atomic_inc_not_zero(&rc->sk_refcnt)))
+                               goto again;
+                       if (unlikely(llc_sk(rc)->sap != sap ||
+                                    !llc_dgram_match(sap, laddr, rc))) {
+                               sock_put(rc);
+                               continue;
+                       }
                        goto found;
                }
        }
        rc = NULL;
+       /*
+        * if the nulls value we got at the end of this lookup is
+        * not the expected one, we must restart lookup.
+        * We probably met an item that was moved to another chain.
+        */
+       if (unlikely(get_nulls_value(node) != slot))
+               goto again;
 found:
-       read_unlock_bh(&sap->sk_list.lock);
+       rcu_read_unlock_bh();
        return rc;
 }
 
+static inline bool llc_mcast_match(const struct llc_sap *sap,
+                                  const struct llc_addr *laddr,
+                                  const struct sk_buff *skb,
+                                  const struct sock *sk)
+{
+     struct llc_sock *llc = llc_sk(sk);
+
+     return sk->sk_type == SOCK_DGRAM &&
+         llc->laddr.lsap == laddr->lsap &&
+         llc->dev == skb->dev;
+}
+
+static void llc_do_mcast(struct llc_sap *sap, struct sk_buff *skb,
+                        struct sock **stack, int count)
+{
+       struct sk_buff *skb1;
+       int i;
+
+       for (i = 0; i < count; i++) {
+               skb1 = skb_clone(skb, GFP_ATOMIC);
+               if (!skb1) {
+                       sock_put(stack[i]);
+                       continue;
+               }
+
+               llc_sap_rcv(sap, skb1, stack[i]);
+               sock_put(stack[i]);
+       }
+}
+
 /**
  *     llc_sap_mcast - Deliver multicast PDU's to all matching datagram sockets.
  *     @sap: SAP
@@ -340,32 +394,31 @@ static void llc_sap_mcast(struct llc_sap *sap,
                          const struct llc_addr *laddr,
                          struct sk_buff *skb)
 {
-       struct sock *sk;
+       int i = 0, count = 256 / sizeof(struct sock *);
+       struct sock *sk, *stack[count];
        struct hlist_node *node;
+       struct llc_sock *llc;
+       struct hlist_head *dev_hb = llc_sk_dev_hash(sap, skb->dev->ifindex);
 
-       read_lock_bh(&sap->sk_list.lock);
-       sk_for_each(sk, node, &sap->sk_list.list) {
-               struct llc_sock *llc = llc_sk(sk);
-               struct sk_buff *skb1;
+       spin_lock_bh(&sap->sk_lock);
+       hlist_for_each_entry(llc, node, dev_hb, dev_hash_node) {
 
-               if (sk->sk_type != SOCK_DGRAM)
-                       continue;
+               sk = &llc->sk;
 
-               if (llc->laddr.lsap != laddr->lsap)
+               if (!llc_mcast_match(sap, laddr, skb, sk))
                        continue;
 
-               if (llc->dev != skb->dev)
-                       continue;
-
-               skb1 = skb_clone(skb, GFP_ATOMIC);
-               if (!skb1)
-                       break;
-
                sock_hold(sk);
-               llc_sap_rcv(sap, skb1, sk);
-               sock_put(sk);
+               if (i < count)
+                       stack[i++] = sk;
+               else {
+                       llc_do_mcast(sap, skb, stack, i);
+                       i = 0;
+               }
        }
-       read_unlock_bh(&sap->sk_list.lock);
+       spin_unlock_bh(&sap->sk_lock);
+
+       llc_do_mcast(sap, skb, stack, i);
 }
 
 
index a10d508b07e146daabe99ad21306fc99ecdc8c2f..a952b7f8c6482ae76b6a14aed59c5f4c63e113d8 100644 (file)
@@ -96,18 +96,6 @@ menuconfig MAC80211_DEBUG_MENU
        ---help---
          This option collects various mac80211 debug settings.
 
-config MAC80211_DEBUG_PACKET_ALIGNMENT
-       bool "Enable packet alignment debugging"
-       depends on MAC80211_DEBUG_MENU
-       ---help---
-         This option is recommended for driver authors and strongly
-         discouraged for everybody else, it will trigger a warning
-         when a driver hands mac80211 a buffer that is aligned in
-         a way that will cause problems with the IP stack on some
-         architectures.
-
-         Say N unless you're writing a mac80211 based driver.
-
 config MAC80211_NOINLINE
        bool "Do not inline TX/RX handlers"
        depends on MAC80211_DEBUG_MENU
index 298cfcc1bf8d205c78ff826116655652af8247ae..04420291e7ad7b0d85e3456cbe93c5804dd2d6f9 100644 (file)
@@ -6,10 +6,10 @@ mac80211-y := \
        sta_info.o \
        wep.o \
        wpa.o \
-       scan.o \
+       scan.o offchannel.o \
        ht.o agg-tx.o agg-rx.o \
        ibss.o \
-       mlme.o \
+       mlme.o work.o \
        iface.o \
        rate.o \
        michael.o \
index 51c7dc3c4c3bac28e849dfd31fb5501ce858e82e..a978e666ed6f06a79fa4b7529feec540a7ab2908 100644 (file)
@@ -41,8 +41,7 @@ void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
               sta->sta.addr, tid);
 #endif /* CONFIG_MAC80211_HT_DEBUG */
 
-       if (drv_ampdu_action(local, &sta->sdata->vif,
-                            IEEE80211_AMPDU_RX_STOP,
+       if (drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_STOP,
                             &sta->sta, tid, NULL))
                printk(KERN_DEBUG "HW problem - can not stop rx "
                                "aggregation for tid %d\n", tid);
@@ -83,12 +82,11 @@ void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
 void ieee80211_sta_stop_rx_ba_session(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid,
                                        u16 initiator, u16 reason)
 {
-       struct ieee80211_local *local = sdata->local;
        struct sta_info *sta;
 
        rcu_read_lock();
 
-       sta = sta_info_get(local, ra);
+       sta = sta_info_get(sdata, ra);
        if (!sta) {
                rcu_read_unlock();
                return;
@@ -136,7 +134,7 @@ static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *d
 
        if (!skb) {
                printk(KERN_DEBUG "%s: failed to allocate buffer "
-                      "for addba resp frame\n", sdata->dev->name);
+                      "for addba resp frame\n", sdata->name);
                return;
        }
 
@@ -144,10 +142,10 @@ static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *d
        mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
        memset(mgmt, 0, 24);
        memcpy(mgmt->da, da, ETH_ALEN);
-       memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
+       memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
        if (sdata->vif.type == NL80211_IFTYPE_AP ||
            sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
-               memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN);
+               memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
        else if (sdata->vif.type == NL80211_IFTYPE_STATION)
                memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
 
@@ -281,8 +279,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
                goto end;
        }
 
-       ret = drv_ampdu_action(local, &sta->sdata->vif,
-                              IEEE80211_AMPDU_RX_START,
+       ret = drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_START,
                               &sta->sta, tid, &start_seq_num);
 #ifdef CONFIG_MAC80211_HT_DEBUG
        printk(KERN_DEBUG "Rx A-MPDU request on tid %d result %d\n", tid, ret);
index 5e3a7eccef5ae4c7a52dd65a3e8f310183582433..718fbcff84d24e230fadd5808a80d12aee889020 100644 (file)
@@ -58,17 +58,17 @@ static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata,
 
        if (!skb) {
                printk(KERN_ERR "%s: failed to allocate buffer "
-                               "for addba request frame\n", sdata->dev->name);
+                               "for addba request frame\n", sdata->name);
                return;
        }
        skb_reserve(skb, local->hw.extra_tx_headroom);
        mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
        memset(mgmt, 0, 24);
        memcpy(mgmt->da, da, ETH_ALEN);
-       memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
+       memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
        if (sdata->vif.type == NL80211_IFTYPE_AP ||
            sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
-               memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN);
+               memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
        else if (sdata->vif.type == NL80211_IFTYPE_STATION)
                memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
 
@@ -104,7 +104,7 @@ void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u1
        skb = dev_alloc_skb(sizeof(*bar) + local->hw.extra_tx_headroom);
        if (!skb) {
                printk(KERN_ERR "%s: failed to allocate buffer for "
-                       "bar frame\n", sdata->dev->name);
+                       "bar frame\n", sdata->name);
                return;
        }
        skb_reserve(skb, local->hw.extra_tx_headroom);
@@ -113,7 +113,7 @@ void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u1
        bar->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL |
                                         IEEE80211_STYPE_BACK_REQ);
        memcpy(bar->ra, ra, ETH_ALEN);
-       memcpy(bar->ta, sdata->dev->dev_addr, ETH_ALEN);
+       memcpy(bar->ta, sdata->vif.addr, ETH_ALEN);
        bar_control |= (u16)IEEE80211_BAR_CTRL_ACK_POLICY_NORMAL;
        bar_control |= (u16)IEEE80211_BAR_CTRL_CBMTID_COMPRESSED_BA;
        bar_control |= (u16)(tid << 12);
@@ -144,7 +144,7 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
        *state = HT_AGG_STATE_REQ_STOP_BA_MSK |
                (initiator << HT_AGG_STATE_INITIATOR_SHIFT);
 
-       ret = drv_ampdu_action(local, &sta->sdata->vif,
+       ret = drv_ampdu_action(local, sta->sdata,
                               IEEE80211_AMPDU_TX_STOP,
                               &sta->sta, tid, NULL);
 
@@ -179,7 +179,8 @@ static void sta_addba_resp_timer_expired(unsigned long data)
 
        /* check if the TID waits for addBA response */
        spin_lock_bh(&sta->lock);
-       if ((*state & (HT_ADDBA_REQUESTED_MSK | HT_ADDBA_RECEIVED_MSK)) !=
+       if ((*state & (HT_ADDBA_REQUESTED_MSK | HT_ADDBA_RECEIVED_MSK |
+                      HT_AGG_STATE_REQ_STOP_BA_MSK)) !=
                                                HT_ADDBA_REQUESTED_MSK) {
                spin_unlock_bh(&sta->lock);
                *state = HT_AGG_STATE_IDLE;
@@ -301,10 +302,9 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid)
         * call back right away, it must see that the flow has begun */
        *state |= HT_ADDBA_REQUESTED_MSK;
 
-       start_seq_num = sta->tid_seq[tid];
+       start_seq_num = sta->tid_seq[tid] >> 4;
 
-       ret = drv_ampdu_action(local, &sdata->vif,
-                              IEEE80211_AMPDU_TX_START,
+       ret = drv_ampdu_action(local, sdata, IEEE80211_AMPDU_TX_START,
                               pubsta, tid, &start_seq_num);
 
        if (ret) {
@@ -420,7 +420,7 @@ static void ieee80211_agg_tx_operational(struct ieee80211_local *local,
        ieee80211_agg_splice_finish(local, sta, tid);
        spin_unlock(&local->ampdu_lock);
 
-       drv_ampdu_action(local, &sta->sdata->vif,
+       drv_ampdu_action(local, sta->sdata,
                         IEEE80211_AMPDU_TX_OPERATIONAL,
                         &sta->sta, tid, NULL);
 }
@@ -441,7 +441,7 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid)
        }
 
        rcu_read_lock();
-       sta = sta_info_get(local, ra);
+       sta = sta_info_get(sdata, ra);
        if (!sta) {
                rcu_read_unlock();
 #ifdef CONFIG_MAC80211_HT_DEBUG
@@ -489,7 +489,7 @@ void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_vif *vif,
 #ifdef CONFIG_MAC80211_HT_DEBUG
                if (net_ratelimit())
                        printk(KERN_WARNING "%s: Not enough memory, "
-                              "dropping start BA session", skb->dev->name);
+                              "dropping start BA session", sdata->name);
 #endif
                return;
        }
@@ -564,7 +564,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid)
 #endif /* CONFIG_MAC80211_HT_DEBUG */
 
        rcu_read_lock();
-       sta = sta_info_get(local, ra);
+       sta = sta_info_get(sdata, ra);
        if (!sta) {
 #ifdef CONFIG_MAC80211_HT_DEBUG
                printk(KERN_DEBUG "Could not find station: %pM\n", ra);
@@ -621,7 +621,7 @@ void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_vif *vif,
 #ifdef CONFIG_MAC80211_HT_DEBUG
                if (net_ratelimit())
                        printk(KERN_WARNING "%s: Not enough memory, "
-                              "dropping stop BA session", skb->dev->name);
+                              "dropping stop BA session", sdata->name);
 #endif
                return;
        }
index 9ae1a4760b58b76ffa991031329b10e23cb51778..facf233843e0ed8dddd3577b6716ef15b1831a7c 100644 (file)
@@ -78,17 +78,15 @@ static int ieee80211_change_iface(struct wiphy *wiphy,
                                  enum nl80211_iftype type, u32 *flags,
                                  struct vif_params *params)
 {
-       struct ieee80211_sub_if_data *sdata;
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        int ret;
 
-       if (netif_running(dev))
+       if (ieee80211_sdata_running(sdata))
                return -EBUSY;
 
        if (!nl80211_params_check(type, params))
                return -EINVAL;
 
-       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
        ret = ieee80211_if_change_type(sdata, type);
        if (ret)
                return ret;
@@ -150,7 +148,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
        rcu_read_lock();
 
        if (mac_addr) {
-               sta = sta_info_get(sdata->local, mac_addr);
+               sta = sta_info_get_bss(sdata, mac_addr);
                if (!sta) {
                        ieee80211_key_free(key);
                        err = -ENOENT;
@@ -181,7 +179,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
        if (mac_addr) {
                ret = -ENOENT;
 
-               sta = sta_info_get(sdata->local, mac_addr);
+               sta = sta_info_get_bss(sdata, mac_addr);
                if (!sta)
                        goto out_unlock;
 
@@ -228,7 +226,7 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
        rcu_read_lock();
 
        if (mac_addr) {
-               sta = sta_info_get(sdata->local, mac_addr);
+               sta = sta_info_get_bss(sdata, mac_addr);
                if (!sta)
                        goto out;
 
@@ -415,15 +413,13 @@ static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev,
 static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev,
                                 u8 *mac, struct station_info *sinfo)
 {
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct sta_info *sta;
        int ret = -ENOENT;
 
        rcu_read_lock();
 
-       /* XXX: verify sta->dev == dev */
-
-       sta = sta_info_get(local, mac);
+       sta = sta_info_get_bss(sdata, mac);
        if (sta) {
                ret = 0;
                sta_set_sinfo(sta, sinfo);
@@ -732,7 +728,7 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
        } else
                sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-       if (compare_ether_addr(mac, dev->dev_addr) == 0)
+       if (compare_ether_addr(mac, sdata->vif.addr) == 0)
                return -EINVAL;
 
        if (is_multicast_ether_addr(mac))
@@ -779,8 +775,7 @@ static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev,
        if (mac) {
                rcu_read_lock();
 
-               /* XXX: get sta belonging to dev */
-               sta = sta_info_get(local, mac);
+               sta = sta_info_get_bss(sdata, mac);
                if (!sta) {
                        rcu_read_unlock();
                        return -ENOENT;
@@ -801,14 +796,14 @@ static int ieee80211_change_station(struct wiphy *wiphy,
                                    u8 *mac,
                                    struct station_parameters *params)
 {
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ieee80211_local *local = wiphy_priv(wiphy);
        struct sta_info *sta;
        struct ieee80211_sub_if_data *vlansdata;
 
        rcu_read_lock();
 
-       /* XXX: get sta belonging to dev */
-       sta = sta_info_get(local, mac);
+       sta = sta_info_get_bss(sdata, mac);
        if (!sta) {
                rcu_read_unlock();
                return -ENOENT;
@@ -847,7 +842,6 @@ static int ieee80211_change_station(struct wiphy *wiphy,
 static int ieee80211_add_mpath(struct wiphy *wiphy, struct net_device *dev,
                                 u8 *dst, u8 *next_hop)
 {
-       struct ieee80211_local *local = wiphy_priv(wiphy);
        struct ieee80211_sub_if_data *sdata;
        struct mesh_path *mpath;
        struct sta_info *sta;
@@ -856,7 +850,7 @@ static int ieee80211_add_mpath(struct wiphy *wiphy, struct net_device *dev,
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
        rcu_read_lock();
-       sta = sta_info_get(local, next_hop);
+       sta = sta_info_get(sdata, next_hop);
        if (!sta) {
                rcu_read_unlock();
                return -ENOENT;
@@ -895,7 +889,6 @@ static int ieee80211_change_mpath(struct wiphy *wiphy,
                                    struct net_device *dev,
                                    u8 *dst, u8 *next_hop)
 {
-       struct ieee80211_local *local = wiphy_priv(wiphy);
        struct ieee80211_sub_if_data *sdata;
        struct mesh_path *mpath;
        struct sta_info *sta;
@@ -904,7 +897,7 @@ static int ieee80211_change_mpath(struct wiphy *wiphy,
 
        rcu_read_lock();
 
-       sta = sta_info_get(local, next_hop);
+       sta = sta_info_get(sdata, next_hop);
        if (!sta) {
                rcu_read_unlock();
                return -ENOENT;
@@ -1092,6 +1085,13 @@ static int ieee80211_change_bss(struct wiphy *wiphy,
                        params->use_short_preamble;
                changed |= BSS_CHANGED_ERP_PREAMBLE;
        }
+
+       if (!sdata->vif.bss_conf.use_short_slot &&
+           sdata->local->hw.conf.channel->band == IEEE80211_BAND_5GHZ) {
+               sdata->vif.bss_conf.use_short_slot = true;
+               changed |= BSS_CHANGED_ERP_SLOT;
+       }
+
        if (params->use_short_slot_time >= 0) {
                sdata->vif.bss_conf.use_short_slot =
                        params->use_short_slot_time;
@@ -1135,6 +1135,13 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy,
        p.cw_max = params->cwmax;
        p.cw_min = params->cwmin;
        p.txop = params->txop;
+
+       /*
+        * Setting tx queue params disables u-apsd because it's only
+        * called in master mode.
+        */
+       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",
@@ -1237,6 +1244,13 @@ static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
        struct ieee80211_local *local = wiphy_priv(wiphy);
        int err;
 
+       if (changed & WIPHY_PARAM_COVERAGE_CLASS) {
+               err = drv_set_coverage_class(local, wiphy->coverage_class);
+
+               if (err)
+                       return err;
+       }
+
        if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
                err = drv_set_rts_threshold(local, wiphy->rts_threshold);
 
@@ -1324,6 +1338,50 @@ static int ieee80211_testmode_cmd(struct wiphy *wiphy, void *data, int len)
 }
 #endif
 
+int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata,
+                            enum ieee80211_smps_mode smps_mode)
+{
+       const u8 *ap;
+       enum ieee80211_smps_mode old_req;
+       int err;
+
+       old_req = sdata->u.mgd.req_smps;
+       sdata->u.mgd.req_smps = smps_mode;
+
+       if (old_req == smps_mode &&
+           smps_mode != IEEE80211_SMPS_AUTOMATIC)
+               return 0;
+
+       /*
+        * If not associated, or current association is not an HT
+        * association, there's no need to send an action frame.
+        */
+       if (!sdata->u.mgd.associated ||
+           sdata->local->oper_channel_type == NL80211_CHAN_NO_HT) {
+               mutex_lock(&sdata->local->iflist_mtx);
+               ieee80211_recalc_smps(sdata->local, sdata);
+               mutex_unlock(&sdata->local->iflist_mtx);
+               return 0;
+       }
+
+       ap = sdata->u.mgd.associated->bssid;
+
+       if (smps_mode == IEEE80211_SMPS_AUTOMATIC) {
+               if (sdata->u.mgd.powersave)
+                       smps_mode = IEEE80211_SMPS_DYNAMIC;
+               else
+                       smps_mode = IEEE80211_SMPS_OFF;
+       }
+
+       /* send SM PS frame to AP */
+       err = ieee80211_send_smps_action(sdata, smps_mode,
+                                        ap, ap);
+       if (err)
+               sdata->u.mgd.req_smps = old_req;
+
+       return err;
+}
+
 static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
                                    bool enabled, int timeout)
 {
@@ -1344,6 +1402,11 @@ static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
        sdata->u.mgd.powersave = enabled;
        conf->dynamic_ps_timeout = timeout;
 
+       /* no change, but if automatic follow powersave */
+       mutex_lock(&sdata->u.mgd.mtx);
+       __ieee80211_request_smps(sdata, sdata->u.mgd.req_smps);
+       mutex_unlock(&sdata->u.mgd.mtx);
+
        if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS)
                ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
 
@@ -1359,39 +1422,43 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy,
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       int i, err = -EINVAL;
-       u32 target_rate;
-       struct ieee80211_supported_band *sband;
+       int i;
 
-       sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+       /*
+        * This _could_ be supported by providing a hook for
+        * drivers for this function, but at this point it
+        * doesn't seem worth bothering.
+        */
+       if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL)
+               return -EOPNOTSUPP;
 
-       /* target_rate = -1, rate->fixed = 0 means auto only, so use all rates
-        * target_rate = X, rate->fixed = 1 means only rate X
-        * target_rate = X, rate->fixed = 0 means all rates <= X */
-       sdata->max_ratectrl_rateidx = -1;
-       sdata->force_unicast_rateidx = -1;
 
-       if (mask->fixed)
-               target_rate = mask->fixed / 100;
-       else if (mask->maxrate)
-               target_rate = mask->maxrate / 100;
-       else
-               return 0;
+       for (i = 0; i < IEEE80211_NUM_BANDS; i++)
+               sdata->rc_rateidx_mask[i] = mask->control[i].legacy;
 
-       for (i=0; i< sband->n_bitrates; i++) {
-               struct ieee80211_rate *brate = &sband->bitrates[i];
-               int this_rate = brate->bitrate;
+       return 0;
+}
 
-               if (target_rate == this_rate) {
-                       sdata->max_ratectrl_rateidx = i;
-                       if (mask->fixed)
-                               sdata->force_unicast_rateidx = i;
-                       err = 0;
-                       break;
-               }
-       }
+static int ieee80211_remain_on_channel(struct wiphy *wiphy,
+                                      struct net_device *dev,
+                                      struct ieee80211_channel *chan,
+                                      enum nl80211_channel_type channel_type,
+                                      unsigned int duration,
+                                      u64 *cookie)
+{
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-       return err;
+       return ieee80211_wk_remain_on_channel(sdata, chan, channel_type,
+                                             duration, cookie);
+}
+
+static int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy,
+                                             struct net_device *dev,
+                                             u64 cookie)
+{
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+       return ieee80211_wk_cancel_remain_on_channel(sdata, cookie);
 }
 
 struct cfg80211_ops mac80211_config_ops = {
@@ -1440,4 +1507,6 @@ struct cfg80211_ops mac80211_config_ops = {
        CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd)
        .set_power_mgmt = ieee80211_set_power_mgmt,
        .set_bitrate_mask = ieee80211_set_bitrate_mask,
+       .remain_on_channel = ieee80211_remain_on_channel,
+       .cancel_remain_on_channel = ieee80211_cancel_remain_on_channel,
 };
index e4b54093d41b3bafd4bdc3458040bc57ad5fc6cb..b3bc32b62a5a66002ad289a18a22dbb7a455d6a2 100644 (file)
@@ -158,6 +158,98 @@ static const struct file_operations noack_ops = {
        .open = mac80211_open_file_generic
 };
 
+static ssize_t uapsd_queues_read(struct file *file, char __user *user_buf,
+                                size_t count, loff_t *ppos)
+{
+       struct ieee80211_local *local = file->private_data;
+       int res;
+       char buf[10];
+
+       res = scnprintf(buf, sizeof(buf), "0x%x\n", local->uapsd_queues);
+
+       return simple_read_from_buffer(user_buf, count, ppos, buf, res);
+}
+
+static ssize_t uapsd_queues_write(struct file *file,
+                                 const char __user *user_buf,
+                                 size_t count, loff_t *ppos)
+{
+       struct ieee80211_local *local = file->private_data;
+       unsigned long val;
+       char buf[10];
+       size_t len;
+       int ret;
+
+       len = min(count, sizeof(buf) - 1);
+       if (copy_from_user(buf, user_buf, len))
+               return -EFAULT;
+       buf[len] = '\0';
+
+       ret = strict_strtoul(buf, 0, &val);
+
+       if (ret)
+               return -EINVAL;
+
+       if (val & ~IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK)
+               return -ERANGE;
+
+       local->uapsd_queues = val;
+
+       return count;
+}
+
+static const struct file_operations uapsd_queues_ops = {
+       .read = uapsd_queues_read,
+       .write = uapsd_queues_write,
+       .open = mac80211_open_file_generic
+};
+
+static ssize_t uapsd_max_sp_len_read(struct file *file, char __user *user_buf,
+                                    size_t count, loff_t *ppos)
+{
+       struct ieee80211_local *local = file->private_data;
+       int res;
+       char buf[10];
+
+       res = scnprintf(buf, sizeof(buf), "0x%x\n", local->uapsd_max_sp_len);
+
+       return simple_read_from_buffer(user_buf, count, ppos, buf, res);
+}
+
+static ssize_t uapsd_max_sp_len_write(struct file *file,
+                                     const char __user *user_buf,
+                                     size_t count, loff_t *ppos)
+{
+       struct ieee80211_local *local = file->private_data;
+       unsigned long val;
+       char buf[10];
+       size_t len;
+       int ret;
+
+       len = min(count, sizeof(buf) - 1);
+       if (copy_from_user(buf, user_buf, len))
+               return -EFAULT;
+       buf[len] = '\0';
+
+       ret = strict_strtoul(buf, 0, &val);
+
+       if (ret)
+               return -EINVAL;
+
+       if (val & ~IEEE80211_WMM_IE_STA_QOSINFO_SP_MASK)
+               return -ERANGE;
+
+       local->uapsd_max_sp_len = val;
+
+       return count;
+}
+
+static const struct file_operations uapsd_max_sp_len_ops = {
+       .read = uapsd_max_sp_len_read,
+       .write = uapsd_max_sp_len_write,
+       .open = mac80211_open_file_generic
+};
+
 static ssize_t queues_read(struct file *file, char __user *user_buf,
                           size_t count, loff_t *ppos)
 {
@@ -314,6 +406,8 @@ void debugfs_hw_add(struct ieee80211_local *local)
        DEBUGFS_ADD(queues);
        DEBUGFS_ADD_MODE(reset, 0200);
        DEBUGFS_ADD(noack);
+       DEBUGFS_ADD(uapsd_queues);
+       DEBUGFS_ADD(uapsd_max_sp_len);
 
        statsd = debugfs_create_dir("statistics", phyd);
 
index e0f5224630dafede797663bb834ffa017086237a..d12e743cb4e1b7716ddd5beeed9954d43e75c9cb 100644 (file)
@@ -56,7 +56,7 @@ KEY_CONF_FILE(keyidx, D);
 KEY_CONF_FILE(hw_key_idx, D);
 KEY_FILE(flags, X);
 KEY_FILE(tx_rx_count, D);
-KEY_READ(ifindex, sdata->dev->ifindex, 20, "%d\n");
+KEY_READ(ifindex, sdata->name, IFNAMSIZ + 2, "%s\n");
 KEY_OPS(ifindex);
 
 static ssize_t key_algorithm_read(struct file *file,
index 472b2039906c89dbd1081b6c8b2cabc2d8f79b55..9affe2cd185f2ec3cae1b5a8e8ad3ce046db5746 100644 (file)
@@ -41,6 +41,30 @@ static ssize_t ieee80211_if_read(
        return ret;
 }
 
+static ssize_t ieee80211_if_write(
+       struct ieee80211_sub_if_data *sdata,
+       const char __user *userbuf,
+       size_t count, loff_t *ppos,
+       ssize_t (*write)(struct ieee80211_sub_if_data *, const char *, int))
+{
+       u8 *buf;
+       ssize_t ret = -ENODEV;
+
+       buf = kzalloc(count, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       if (copy_from_user(buf, userbuf, count))
+               return -EFAULT;
+
+       rtnl_lock();
+       if (sdata->dev->reg_state == NETREG_REGISTERED)
+               ret = (*write)(sdata, buf, count);
+       rtnl_unlock();
+
+       return ret;
+}
+
 #define IEEE80211_IF_FMT(name, field, format_string)                   \
 static ssize_t ieee80211_if_fmt_##name(                                        \
        const struct ieee80211_sub_if_data *sdata, char *buf,           \
@@ -71,7 +95,7 @@ static ssize_t ieee80211_if_fmt_##name(                                       \
        return scnprintf(buf, buflen, "%pM\n", sdata->field);           \
 }
 
-#define __IEEE80211_IF_FILE(name)                                      \
+#define __IEEE80211_IF_FILE(name, _write)                              \
 static ssize_t ieee80211_if_read_##name(struct file *file,             \
                                        char __user *userbuf,           \
                                        size_t count, loff_t *ppos)     \
@@ -82,22 +106,99 @@ static ssize_t ieee80211_if_read_##name(struct file *file,         \
 }                                                                      \
 static const struct file_operations name##_ops = {                     \
        .read = ieee80211_if_read_##name,                               \
+       .write = (_write),                                              \
        .open = mac80211_open_file_generic,                             \
 }
 
+#define __IEEE80211_IF_FILE_W(name)                                    \
+static ssize_t ieee80211_if_write_##name(struct file *file,            \
+                                        const char __user *userbuf,    \
+                                        size_t count, loff_t *ppos)    \
+{                                                                      \
+       return ieee80211_if_write(file->private_data, userbuf, count,   \
+                                 ppos, ieee80211_if_parse_##name);     \
+}                                                                      \
+__IEEE80211_IF_FILE(name, ieee80211_if_write_##name)
+
+
 #define IEEE80211_IF_FILE(name, field, format)                         \
                IEEE80211_IF_FMT_##format(name, field)                  \
-               __IEEE80211_IF_FILE(name)
+               __IEEE80211_IF_FILE(name, NULL)
 
 /* common attributes */
 IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC);
-IEEE80211_IF_FILE(force_unicast_rateidx, force_unicast_rateidx, DEC);
-IEEE80211_IF_FILE(max_ratectrl_rateidx, max_ratectrl_rateidx, DEC);
+IEEE80211_IF_FILE(rc_rateidx_mask_2ghz, rc_rateidx_mask[IEEE80211_BAND_2GHZ],
+                 HEX);
+IEEE80211_IF_FILE(rc_rateidx_mask_5ghz, rc_rateidx_mask[IEEE80211_BAND_5GHZ],
+                 HEX);
 
 /* STA attributes */
 IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC);
 IEEE80211_IF_FILE(aid, u.mgd.aid, DEC);
-IEEE80211_IF_FILE(capab, u.mgd.capab, HEX);
+
+static int ieee80211_set_smps(struct ieee80211_sub_if_data *sdata,
+                             enum ieee80211_smps_mode smps_mode)
+{
+       struct ieee80211_local *local = sdata->local;
+       int err;
+
+       if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_STATIC_SMPS) &&
+           smps_mode == IEEE80211_SMPS_STATIC)
+               return -EINVAL;
+
+       /* auto should be dynamic if in PS mode */
+       if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS) &&
+           (smps_mode == IEEE80211_SMPS_DYNAMIC ||
+            smps_mode == IEEE80211_SMPS_AUTOMATIC))
+               return -EINVAL;
+
+       /* supported only on managed interfaces for now */
+       if (sdata->vif.type != NL80211_IFTYPE_STATION)
+               return -EOPNOTSUPP;
+
+       mutex_lock(&local->iflist_mtx);
+       err = __ieee80211_request_smps(sdata, smps_mode);
+       mutex_unlock(&local->iflist_mtx);
+
+       return err;
+}
+
+static const char *smps_modes[IEEE80211_SMPS_NUM_MODES] = {
+       [IEEE80211_SMPS_AUTOMATIC] = "auto",
+       [IEEE80211_SMPS_OFF] = "off",
+       [IEEE80211_SMPS_STATIC] = "static",
+       [IEEE80211_SMPS_DYNAMIC] = "dynamic",
+};
+
+static ssize_t ieee80211_if_fmt_smps(const struct ieee80211_sub_if_data *sdata,
+                                    char *buf, int buflen)
+{
+       if (sdata->vif.type != NL80211_IFTYPE_STATION)
+               return -EOPNOTSUPP;
+
+       return snprintf(buf, buflen, "request: %s\nused: %s\n",
+                       smps_modes[sdata->u.mgd.req_smps],
+                       smps_modes[sdata->u.mgd.ap_smps]);
+}
+
+static ssize_t ieee80211_if_parse_smps(struct ieee80211_sub_if_data *sdata,
+                                      const char *buf, int buflen)
+{
+       enum ieee80211_smps_mode mode;
+
+       for (mode = 0; mode < IEEE80211_SMPS_NUM_MODES; mode++) {
+               if (strncmp(buf, smps_modes[mode], buflen) == 0) {
+                       int err = ieee80211_set_smps(sdata, mode);
+                       if (!err)
+                               return buflen;
+                       return err;
+               }
+       }
+
+       return -EINVAL;
+}
+
+__IEEE80211_IF_FILE_W(smps);
 
 /* AP attributes */
 IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC);
@@ -109,7 +210,7 @@ static ssize_t ieee80211_if_fmt_num_buffered_multicast(
        return scnprintf(buf, buflen, "%u\n",
                         skb_queue_len(&sdata->u.ap.ps_bc_buf));
 }
-__IEEE80211_IF_FILE(num_buffered_multicast);
+__IEEE80211_IF_FILE(num_buffered_multicast, NULL);
 
 /* WDS attributes */
 IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC);
@@ -154,46 +255,50 @@ IEEE80211_IF_FILE(dot11MeshHWMPRootMode,
 #endif
 
 
-#define DEBUGFS_ADD(name, type) \
+#define DEBUGFS_ADD(name) \
        debugfs_create_file(#name, 0400, sdata->debugfs.dir, \
                            sdata, &name##_ops);
 
+#define DEBUGFS_ADD_MODE(name, mode) \
+       debugfs_create_file(#name, mode, sdata->debugfs.dir, \
+                           sdata, &name##_ops);
+
 static void add_sta_files(struct ieee80211_sub_if_data *sdata)
 {
-       DEBUGFS_ADD(drop_unencrypted, sta);
-       DEBUGFS_ADD(force_unicast_rateidx, sta);
-       DEBUGFS_ADD(max_ratectrl_rateidx, sta);
+       DEBUGFS_ADD(drop_unencrypted);
+       DEBUGFS_ADD(rc_rateidx_mask_2ghz);
+       DEBUGFS_ADD(rc_rateidx_mask_5ghz);
 
-       DEBUGFS_ADD(bssid, sta);
-       DEBUGFS_ADD(aid, sta);
-       DEBUGFS_ADD(capab, sta);
+       DEBUGFS_ADD(bssid);
+       DEBUGFS_ADD(aid);
+       DEBUGFS_ADD_MODE(smps, 0600);
 }
 
 static void add_ap_files(struct ieee80211_sub_if_data *sdata)
 {
-       DEBUGFS_ADD(drop_unencrypted, ap);
-       DEBUGFS_ADD(force_unicast_rateidx, ap);
-       DEBUGFS_ADD(max_ratectrl_rateidx, ap);
+       DEBUGFS_ADD(drop_unencrypted);
+       DEBUGFS_ADD(rc_rateidx_mask_2ghz);
+       DEBUGFS_ADD(rc_rateidx_mask_5ghz);
 
-       DEBUGFS_ADD(num_sta_ps, ap);
-       DEBUGFS_ADD(dtim_count, ap);
-       DEBUGFS_ADD(num_buffered_multicast, ap);
+       DEBUGFS_ADD(num_sta_ps);
+       DEBUGFS_ADD(dtim_count);
+       DEBUGFS_ADD(num_buffered_multicast);
 }
 
 static void add_wds_files(struct ieee80211_sub_if_data *sdata)
 {
-       DEBUGFS_ADD(drop_unencrypted, wds);
-       DEBUGFS_ADD(force_unicast_rateidx, wds);
-       DEBUGFS_ADD(max_ratectrl_rateidx, wds);
+       DEBUGFS_ADD(drop_unencrypted);
+       DEBUGFS_ADD(rc_rateidx_mask_2ghz);
+       DEBUGFS_ADD(rc_rateidx_mask_5ghz);
 
-       DEBUGFS_ADD(peer, wds);
+       DEBUGFS_ADD(peer);
 }
 
 static void add_vlan_files(struct ieee80211_sub_if_data *sdata)
 {
-       DEBUGFS_ADD(drop_unencrypted, vlan);
-       DEBUGFS_ADD(force_unicast_rateidx, vlan);
-       DEBUGFS_ADD(max_ratectrl_rateidx, vlan);
+       DEBUGFS_ADD(drop_unencrypted);
+       DEBUGFS_ADD(rc_rateidx_mask_2ghz);
+       DEBUGFS_ADD(rc_rateidx_mask_5ghz);
 }
 
 static void add_monitor_files(struct ieee80211_sub_if_data *sdata)
@@ -280,16 +385,11 @@ static void add_files(struct ieee80211_sub_if_data *sdata)
        }
 }
 
-static int notif_registered;
-
 void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata)
 {
        char buf[10+IFNAMSIZ];
 
-       if (!notif_registered)
-               return;
-
-       sprintf(buf, "netdev:%s", sdata->dev->name);
+       sprintf(buf, "netdev:%s", sdata->name);
        sdata->debugfs.dir = debugfs_create_dir(buf,
                sdata->local->hw.wiphy->debugfsdir);
        add_files(sdata);
@@ -304,58 +404,18 @@ void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata)
        sdata->debugfs.dir = NULL;
 }
 
-static int netdev_notify(struct notifier_block *nb,
-                        unsigned long state,
-                        void *ndev)
+void ieee80211_debugfs_rename_netdev(struct ieee80211_sub_if_data *sdata)
 {
-       struct net_device *dev = ndev;
        struct dentry *dir;
-       struct ieee80211_sub_if_data *sdata;
-       char buf[10+IFNAMSIZ];
-
-       if (state != NETDEV_CHANGENAME)
-               return 0;
-
-       if (!dev->ieee80211_ptr || !dev->ieee80211_ptr->wiphy)
-               return 0;
-
-       if (dev->ieee80211_ptr->wiphy->privid != mac80211_wiphy_privid)
-               return 0;
-
-       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       char buf[10 + IFNAMSIZ];
 
        dir = sdata->debugfs.dir;
 
        if (!dir)
-               return 0;
+               return;
 
-       sprintf(buf, "netdev:%s", dev->name);
+       sprintf(buf, "netdev:%s", sdata->name);
        if (!debugfs_rename(dir->d_parent, dir, dir->d_parent, buf))
                printk(KERN_ERR "mac80211: debugfs: failed to rename debugfs "
                       "dir to %s\n", buf);
-
-       return 0;
-}
-
-static struct notifier_block mac80211_debugfs_netdev_notifier = {
-       .notifier_call = netdev_notify,
-};
-
-void ieee80211_debugfs_netdev_init(void)
-{
-       int err;
-
-       err = register_netdevice_notifier(&mac80211_debugfs_netdev_notifier);
-       if (err) {
-               printk(KERN_ERR
-                      "mac80211: failed to install netdev notifier,"
-                      " disabling per-netdev debugfs!\n");
-       } else
-               notif_registered = 1;
-}
-
-void ieee80211_debugfs_netdev_exit(void)
-{
-       unregister_netdevice_notifier(&mac80211_debugfs_netdev_notifier);
-       notif_registered = 0;
 }
index 7af731f0b73113182c54756b53aa3b0b88a37e1d..79025e79f4d6459dd99de5ad496e351e123f53b7 100644 (file)
@@ -6,8 +6,7 @@
 #ifdef CONFIG_MAC80211_DEBUGFS
 void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata);
 void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata);
-void ieee80211_debugfs_netdev_init(void);
-void ieee80211_debugfs_netdev_exit(void);
+void ieee80211_debugfs_rename_netdev(struct ieee80211_sub_if_data *sdata);
 #else
 static inline void ieee80211_debugfs_add_netdev(
        struct ieee80211_sub_if_data *sdata)
@@ -15,10 +14,8 @@ static inline void ieee80211_debugfs_add_netdev(
 static inline void ieee80211_debugfs_remove_netdev(
        struct ieee80211_sub_if_data *sdata)
 {}
-static inline void ieee80211_debugfs_netdev_init(void)
-{}
-
-static inline void ieee80211_debugfs_netdev_exit(void)
+static inline void ieee80211_debugfs_rename_netdev(
+       struct ieee80211_sub_if_data *sdata)
 {}
 #endif
 
index 3f41608c8081c3e59f86acc76e94b91cad8219e8..0d4a759ba72c1ae0e60129dd3d095002f0da9eb9 100644 (file)
@@ -44,7 +44,7 @@ static const struct file_operations sta_ ##name## _ops = {            \
                STA_OPS(name)
 
 STA_FILE(aid, sta.aid, D);
-STA_FILE(dev, sdata->dev->name, S);
+STA_FILE(dev, sdata->name, S);
 STA_FILE(rx_packets, rx_packets, LU);
 STA_FILE(tx_packets, tx_packets, LU);
 STA_FILE(rx_bytes, rx_bytes, LU);
@@ -160,7 +160,12 @@ STA_OPS(agg_status);
 static ssize_t sta_ht_capa_read(struct file *file, char __user *userbuf,
                                size_t count, loff_t *ppos)
 {
-       char buf[200], *p = buf;
+#define PRINT_HT_CAP(_cond, _str) \
+       do { \
+       if (_cond) \
+                       p += scnprintf(p, sizeof(buf)+buf-p, "\t" _str "\n"); \
+       } while (0)
+       char buf[1024], *p = buf;
        int i;
        struct sta_info *sta = file->private_data;
        struct ieee80211_sta_ht_cap *htc = &sta->sta.ht_cap;
@@ -168,15 +173,64 @@ static ssize_t sta_ht_capa_read(struct file *file, char __user *userbuf,
        p += scnprintf(p, sizeof(buf) + buf - p, "ht %ssupported\n",
                        htc->ht_supported ? "" : "not ");
        if (htc->ht_supported) {
-               p += scnprintf(p, sizeof(buf)+buf-p, "cap: %#.2x\n", htc->cap);
+               p += scnprintf(p, sizeof(buf)+buf-p, "cap: %#.4x\n", htc->cap);
+
+               PRINT_HT_CAP((htc->cap & BIT(0)), "RX LDCP");
+               PRINT_HT_CAP((htc->cap & BIT(1)), "HT20/HT40");
+               PRINT_HT_CAP(!(htc->cap & BIT(1)), "HT20");
+
+               PRINT_HT_CAP(((htc->cap >> 2) & 0x3) == 0, "Static SM Power Save");
+               PRINT_HT_CAP(((htc->cap >> 2) & 0x3) == 1, "Dynamic SM Power Save");
+               PRINT_HT_CAP(((htc->cap >> 2) & 0x3) == 3, "SM Power Save disabled");
+
+               PRINT_HT_CAP((htc->cap & BIT(4)), "RX Greenfield");
+               PRINT_HT_CAP((htc->cap & BIT(5)), "RX HT20 SGI");
+               PRINT_HT_CAP((htc->cap & BIT(6)), "RX HT40 SGI");
+               PRINT_HT_CAP((htc->cap & BIT(7)), "TX STBC");
+
+               PRINT_HT_CAP(((htc->cap >> 8) & 0x3) == 0, "No RX STBC");
+               PRINT_HT_CAP(((htc->cap >> 8) & 0x3) == 1, "RX STBC 1-stream");
+               PRINT_HT_CAP(((htc->cap >> 8) & 0x3) == 2, "RX STBC 2-streams");
+               PRINT_HT_CAP(((htc->cap >> 8) & 0x3) == 3, "RX STBC 3-streams");
+
+               PRINT_HT_CAP((htc->cap & BIT(10)), "HT Delayed Block Ack");
+
+               PRINT_HT_CAP((htc->cap & BIT(11)), "Max AMSDU length: "
+                            "3839 bytes");
+               PRINT_HT_CAP(!(htc->cap & BIT(11)), "Max AMSDU length: "
+                            "7935 bytes");
+
+               /*
+                * For beacons and probe response this would mean the BSS
+                * does or does not allow the usage of DSSS/CCK HT40.
+                * Otherwise it means the STA does or does not use
+                * DSSS/CCK HT40.
+                */
+               PRINT_HT_CAP((htc->cap & BIT(12)), "DSSS/CCK HT40");
+               PRINT_HT_CAP(!(htc->cap & BIT(12)), "No DSSS/CCK HT40");
+
+               /* BIT(13) is reserved */
+
+               PRINT_HT_CAP((htc->cap & BIT(14)), "40 MHz Intolerant");
+
+               PRINT_HT_CAP((htc->cap & BIT(15)), "L-SIG TXOP protection");
+
                p += scnprintf(p, sizeof(buf)+buf-p, "ampdu factor/density: %d/%d\n",
                                htc->ampdu_factor, htc->ampdu_density);
                p += scnprintf(p, sizeof(buf)+buf-p, "MCS mask:");
+
                for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++)
                        p += scnprintf(p, sizeof(buf)+buf-p, " %.2x",
                                        htc->mcs.rx_mask[i]);
-               p += scnprintf(p, sizeof(buf)+buf-p, "\nMCS rx highest: %d\n",
-                               le16_to_cpu(htc->mcs.rx_highest));
+               p += scnprintf(p, sizeof(buf)+buf-p, "\n");
+
+               /* If not set this is meaningless */
+               if (le16_to_cpu(htc->mcs.rx_highest)) {
+                       p += scnprintf(p, sizeof(buf)+buf-p,
+                                      "MCS rx highest: %d Mbps\n",
+                                      le16_to_cpu(htc->mcs.rx_highest));
+               }
+
                p += scnprintf(p, sizeof(buf)+buf-p, "MCS tx params: %x\n",
                                htc->mcs.tx_params);
        }
index 921dd9c9ff6225c8d7b942053313530ca8a3e666..de91d39e02762c496dc27a2c8e4bc8dd04884092 100644 (file)
@@ -14,6 +14,8 @@ static inline int drv_start(struct ieee80211_local *local)
 {
        int ret;
 
+       might_sleep();
+
        local->started = true;
        smp_mb();
        ret = local->ops->start(&local->hw);
@@ -23,6 +25,8 @@ static inline int drv_start(struct ieee80211_local *local)
 
 static inline void drv_stop(struct ieee80211_local *local)
 {
+       might_sleep();
+
        local->ops->stop(&local->hw);
        trace_drv_stop(local);
 
@@ -36,35 +40,47 @@ static inline void drv_stop(struct ieee80211_local *local)
 }
 
 static inline int drv_add_interface(struct ieee80211_local *local,
-                                   struct ieee80211_if_init_conf *conf)
+                                   struct ieee80211_vif *vif)
 {
-       int ret = local->ops->add_interface(&local->hw, conf);
-       trace_drv_add_interface(local, conf->mac_addr, conf->vif, ret);
+       int ret;
+
+       might_sleep();
+
+       ret = local->ops->add_interface(&local->hw, vif);
+       trace_drv_add_interface(local, vif_to_sdata(vif), ret);
        return ret;
 }
 
 static inline void drv_remove_interface(struct ieee80211_local *local,
-                                       struct ieee80211_if_init_conf *conf)
+                                       struct ieee80211_vif *vif)
 {
-       local->ops->remove_interface(&local->hw, conf);
-       trace_drv_remove_interface(local, conf->mac_addr, conf->vif);
+       might_sleep();
+
+       local->ops->remove_interface(&local->hw, vif);
+       trace_drv_remove_interface(local, vif_to_sdata(vif));
 }
 
 static inline int drv_config(struct ieee80211_local *local, u32 changed)
 {
-       int ret = local->ops->config(&local->hw, changed);
+       int ret;
+
+       might_sleep();
+
+       ret = local->ops->config(&local->hw, changed);
        trace_drv_config(local, changed, ret);
        return ret;
 }
 
 static inline void drv_bss_info_changed(struct ieee80211_local *local,
-                                       struct ieee80211_vif *vif,
+                                       struct ieee80211_sub_if_data *sdata,
                                        struct ieee80211_bss_conf *info,
                                        u32 changed)
 {
+       might_sleep();
+
        if (local->ops->bss_info_changed)
-               local->ops->bss_info_changed(&local->hw, vif, info, changed);
-       trace_drv_bss_info_changed(local, vif, info, changed);
+               local->ops->bss_info_changed(&local->hw, &sdata->vif, info, changed);
+       trace_drv_bss_info_changed(local, sdata, info, changed);
 }
 
 static inline u64 drv_prepare_multicast(struct ieee80211_local *local,
@@ -106,12 +122,17 @@ static inline int drv_set_tim(struct ieee80211_local *local,
 }
 
 static inline int drv_set_key(struct ieee80211_local *local,
-                             enum set_key_cmd cmd, struct ieee80211_vif *vif,
+                             enum set_key_cmd cmd,
+                             struct ieee80211_sub_if_data *sdata,
                              struct ieee80211_sta *sta,
                              struct ieee80211_key_conf *key)
 {
-       int ret = local->ops->set_key(&local->hw, cmd, vif, sta, key);
-       trace_drv_set_key(local, cmd, vif, sta, key, ret);
+       int ret;
+
+       might_sleep();
+
+       ret = local->ops->set_key(&local->hw, cmd, &sdata->vif, sta, key);
+       trace_drv_set_key(local, cmd, sdata, sta, key, ret);
        return ret;
 }
 
@@ -120,6 +141,8 @@ static inline void drv_update_tkip_key(struct ieee80211_local *local,
                                       const u8 *address, u32 iv32,
                                       u16 *phase1key)
 {
+       might_sleep();
+
        if (local->ops->update_tkip_key)
                local->ops->update_tkip_key(&local->hw, conf, address,
                                            iv32, phase1key);
@@ -129,13 +152,19 @@ static inline void drv_update_tkip_key(struct ieee80211_local *local,
 static inline int drv_hw_scan(struct ieee80211_local *local,
                              struct cfg80211_scan_request *req)
 {
-       int ret = local->ops->hw_scan(&local->hw, req);
+       int ret;
+
+       might_sleep();
+
+       ret = local->ops->hw_scan(&local->hw, req);
        trace_drv_hw_scan(local, req, ret);
        return ret;
 }
 
 static inline void drv_sw_scan_start(struct ieee80211_local *local)
 {
+       might_sleep();
+
        if (local->ops->sw_scan_start)
                local->ops->sw_scan_start(&local->hw);
        trace_drv_sw_scan_start(local);
@@ -143,6 +172,8 @@ static inline void drv_sw_scan_start(struct ieee80211_local *local)
 
 static inline void drv_sw_scan_complete(struct ieee80211_local *local)
 {
+       might_sleep();
+
        if (local->ops->sw_scan_complete)
                local->ops->sw_scan_complete(&local->hw);
        trace_drv_sw_scan_complete(local);
@@ -153,6 +184,8 @@ static inline int drv_get_stats(struct ieee80211_local *local,
 {
        int ret = -EOPNOTSUPP;
 
+       might_sleep();
+
        if (local->ops->get_stats)
                ret = local->ops->get_stats(&local->hw, stats);
        trace_drv_get_stats(local, stats, ret);
@@ -172,26 +205,47 @@ static inline int drv_set_rts_threshold(struct ieee80211_local *local,
                                        u32 value)
 {
        int ret = 0;
+
+       might_sleep();
+
        if (local->ops->set_rts_threshold)
                ret = local->ops->set_rts_threshold(&local->hw, value);
        trace_drv_set_rts_threshold(local, value, ret);
        return ret;
 }
 
+static inline int drv_set_coverage_class(struct ieee80211_local *local,
+                                        u8 value)
+{
+       int ret = 0;
+       might_sleep();
+
+       if (local->ops->set_coverage_class)
+               local->ops->set_coverage_class(&local->hw, value);
+       else
+               ret = -EOPNOTSUPP;
+
+       trace_drv_set_coverage_class(local, value, ret);
+       return ret;
+}
+
 static inline void drv_sta_notify(struct ieee80211_local *local,
-                                 struct ieee80211_vif *vif,
+                                 struct ieee80211_sub_if_data *sdata,
                                  enum sta_notify_cmd cmd,
                                  struct ieee80211_sta *sta)
 {
        if (local->ops->sta_notify)
-               local->ops->sta_notify(&local->hw, vif, cmd, sta);
-       trace_drv_sta_notify(local, vif, cmd, sta);
+               local->ops->sta_notify(&local->hw, &sdata->vif, cmd, sta);
+       trace_drv_sta_notify(local, sdata, cmd, sta);
 }
 
 static inline int drv_conf_tx(struct ieee80211_local *local, u16 queue,
                              const struct ieee80211_tx_queue_params *params)
 {
        int ret = -EOPNOTSUPP;
+
+       might_sleep();
+
        if (local->ops->conf_tx)
                ret = local->ops->conf_tx(&local->hw, queue, params);
        trace_drv_conf_tx(local, queue, params, ret);
@@ -209,6 +263,9 @@ static inline int drv_get_tx_stats(struct ieee80211_local *local,
 static inline u64 drv_get_tsf(struct ieee80211_local *local)
 {
        u64 ret = -1ULL;
+
+       might_sleep();
+
        if (local->ops->get_tsf)
                ret = local->ops->get_tsf(&local->hw);
        trace_drv_get_tsf(local, ret);
@@ -217,6 +274,8 @@ static inline u64 drv_get_tsf(struct ieee80211_local *local)
 
 static inline void drv_set_tsf(struct ieee80211_local *local, u64 tsf)
 {
+       might_sleep();
+
        if (local->ops->set_tsf)
                local->ops->set_tsf(&local->hw, tsf);
        trace_drv_set_tsf(local, tsf);
@@ -224,6 +283,8 @@ static inline void drv_set_tsf(struct ieee80211_local *local, u64 tsf)
 
 static inline void drv_reset_tsf(struct ieee80211_local *local)
 {
+       might_sleep();
+
        if (local->ops->reset_tsf)
                local->ops->reset_tsf(&local->hw);
        trace_drv_reset_tsf(local);
@@ -232,6 +293,9 @@ static inline void drv_reset_tsf(struct ieee80211_local *local)
 static inline int drv_tx_last_beacon(struct ieee80211_local *local)
 {
        int ret = 1;
+
+       might_sleep();
+
        if (local->ops->tx_last_beacon)
                ret = local->ops->tx_last_beacon(&local->hw);
        trace_drv_tx_last_beacon(local, ret);
@@ -239,23 +303,34 @@ static inline int drv_tx_last_beacon(struct ieee80211_local *local)
 }
 
 static inline int drv_ampdu_action(struct ieee80211_local *local,
-                                  struct ieee80211_vif *vif,
+                                  struct ieee80211_sub_if_data *sdata,
                                   enum ieee80211_ampdu_mlme_action action,
                                   struct ieee80211_sta *sta, u16 tid,
                                   u16 *ssn)
 {
        int ret = -EOPNOTSUPP;
        if (local->ops->ampdu_action)
-               ret = local->ops->ampdu_action(&local->hw, vif, action,
+               ret = local->ops->ampdu_action(&local->hw, &sdata->vif, action,
                                               sta, tid, ssn);
-       trace_drv_ampdu_action(local, vif, action, sta, tid, ssn, ret);
+       trace_drv_ampdu_action(local, sdata, action, sta, tid, ssn, ret);
        return ret;
 }
 
 
 static inline void drv_rfkill_poll(struct ieee80211_local *local)
 {
+       might_sleep();
+
        if (local->ops->rfkill_poll)
                local->ops->rfkill_poll(&local->hw);
 }
+
+static inline void drv_flush(struct ieee80211_local *local, bool drop)
+{
+       might_sleep();
+
+       trace_drv_flush(local, drop);
+       if (local->ops->flush)
+               local->ops->flush(&local->hw, drop);
+}
 #endif /* __MAC80211_DRIVER_OPS */
index da8497ef7063944a191653b1145a6b6a74627139..d6bd9f5174014655c9597dc0d36256c0c17a6f8a 100644 (file)
@@ -25,10 +25,12 @@ static inline void trace_ ## name(proto) {}
 #define STA_PR_FMT     " sta:%pM"
 #define STA_PR_ARG     __entry->sta_addr
 
-#define VIF_ENTRY      __field(enum nl80211_iftype, vif_type) __field(void *, vif)
-#define VIF_ASSIGN     __entry->vif_type = vif ? vif->type : 0; __entry->vif = vif
-#define VIF_PR_FMT     " vif:%p(%d)"
-#define VIF_PR_ARG     __entry->vif, __entry->vif_type
+#define VIF_ENTRY      __field(enum nl80211_iftype, vif_type) __field(void *, sdata) \
+                       __string(vif_name, sdata->dev ? sdata->dev->name : "<nodev>")
+#define VIF_ASSIGN     __entry->vif_type = sdata->vif.type; __entry->sdata = sdata; \
+                       __assign_str(vif_name, sdata->dev ? sdata->dev->name : "<nodev>")
+#define VIF_PR_FMT     " vif:%s(%d)"
+#define VIF_PR_ARG     __get_str(vif_name), __entry->vif_type
 
 TRACE_EVENT(drv_start,
        TP_PROTO(struct ieee80211_local *local, int ret),
@@ -70,11 +72,10 @@ TRACE_EVENT(drv_stop,
 
 TRACE_EVENT(drv_add_interface,
        TP_PROTO(struct ieee80211_local *local,
-                const u8 *addr,
-                struct ieee80211_vif *vif,
+                struct ieee80211_sub_if_data *sdata,
                 int ret),
 
-       TP_ARGS(local, addr, vif, ret),
+       TP_ARGS(local, sdata, ret),
 
        TP_STRUCT__entry(
                LOCAL_ENTRY
@@ -86,7 +87,7 @@ TRACE_EVENT(drv_add_interface,
        TP_fast_assign(
                LOCAL_ASSIGN;
                VIF_ASSIGN;
-               memcpy(__entry->addr, addr, 6);
+               memcpy(__entry->addr, sdata->vif.addr, 6);
                __entry->ret = ret;
        ),
 
@@ -97,10 +98,9 @@ TRACE_EVENT(drv_add_interface,
 );
 
 TRACE_EVENT(drv_remove_interface,
-       TP_PROTO(struct ieee80211_local *local,
-                const u8 *addr, struct ieee80211_vif *vif),
+       TP_PROTO(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata),
 
-       TP_ARGS(local, addr, vif),
+       TP_ARGS(local, sdata),
 
        TP_STRUCT__entry(
                LOCAL_ENTRY
@@ -111,7 +111,7 @@ TRACE_EVENT(drv_remove_interface,
        TP_fast_assign(
                LOCAL_ASSIGN;
                VIF_ASSIGN;
-               memcpy(__entry->addr, addr, 6);
+               memcpy(__entry->addr, sdata->vif.addr, 6);
        ),
 
        TP_printk(
@@ -140,6 +140,7 @@ TRACE_EVENT(drv_config,
                __field(u8, short_frame_max_tx_count)
                __field(int, center_freq)
                __field(int, channel_type)
+               __field(int, smps)
        ),
 
        TP_fast_assign(
@@ -155,6 +156,7 @@ TRACE_EVENT(drv_config,
                __entry->short_frame_max_tx_count = local->hw.conf.short_frame_max_tx_count;
                __entry->center_freq = local->hw.conf.channel->center_freq;
                __entry->channel_type = local->hw.conf.channel_type;
+               __entry->smps = local->hw.conf.smps_mode;
        ),
 
        TP_printk(
@@ -165,11 +167,11 @@ TRACE_EVENT(drv_config,
 
 TRACE_EVENT(drv_bss_info_changed,
        TP_PROTO(struct ieee80211_local *local,
-                struct ieee80211_vif *vif,
+                struct ieee80211_sub_if_data *sdata,
                 struct ieee80211_bss_conf *info,
                 u32 changed),
 
-       TP_ARGS(local, vif, info, changed),
+       TP_ARGS(local, sdata, info, changed),
 
        TP_STRUCT__entry(
                LOCAL_ENTRY
@@ -293,11 +295,11 @@ TRACE_EVENT(drv_set_tim,
 
 TRACE_EVENT(drv_set_key,
        TP_PROTO(struct ieee80211_local *local,
-                enum set_key_cmd cmd, struct ieee80211_vif *vif,
+                enum set_key_cmd cmd, struct ieee80211_sub_if_data *sdata,
                 struct ieee80211_sta *sta,
                 struct ieee80211_key_conf *key, int ret),
 
-       TP_ARGS(local, cmd, vif, sta, key, ret),
+       TP_ARGS(local, cmd, sdata, sta, key, ret),
 
        TP_STRUCT__entry(
                LOCAL_ENTRY
@@ -489,13 +491,36 @@ TRACE_EVENT(drv_set_rts_threshold,
        )
 );
 
+TRACE_EVENT(drv_set_coverage_class,
+       TP_PROTO(struct ieee80211_local *local, u8 value, int ret),
+
+       TP_ARGS(local, value, ret),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               __field(u8, value)
+               __field(int, ret)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               __entry->ret = ret;
+               __entry->value = value;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT " value:%d ret:%d",
+               LOCAL_PR_ARG, __entry->value, __entry->ret
+       )
+);
+
 TRACE_EVENT(drv_sta_notify,
        TP_PROTO(struct ieee80211_local *local,
-                struct ieee80211_vif *vif,
+                struct ieee80211_sub_if_data *sdata,
                 enum sta_notify_cmd cmd,
                 struct ieee80211_sta *sta),
 
-       TP_ARGS(local, vif, cmd, sta),
+       TP_ARGS(local, sdata, cmd, sta),
 
        TP_STRUCT__entry(
                LOCAL_ENTRY
@@ -656,12 +681,12 @@ TRACE_EVENT(drv_tx_last_beacon,
 
 TRACE_EVENT(drv_ampdu_action,
        TP_PROTO(struct ieee80211_local *local,
-                struct ieee80211_vif *vif,
+                struct ieee80211_sub_if_data *sdata,
                 enum ieee80211_ampdu_mlme_action action,
                 struct ieee80211_sta *sta, u16 tid,
                 u16 *ssn, int ret),
 
-       TP_ARGS(local, vif, action, sta, tid, ssn, ret),
+       TP_ARGS(local, sdata, action, sta, tid, ssn, ret),
 
        TP_STRUCT__entry(
                LOCAL_ENTRY
@@ -688,6 +713,27 @@ TRACE_EVENT(drv_ampdu_action,
                LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->action, __entry->tid, __entry->ret
        )
 );
+
+TRACE_EVENT(drv_flush,
+       TP_PROTO(struct ieee80211_local *local, bool drop),
+
+       TP_ARGS(local, drop),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               __field(bool, drop)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               __entry->drop = drop;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT " drop:%d",
+               LOCAL_PR_ARG, __entry->drop
+       )
+);
 #endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */
 
 #undef TRACE_INCLUDE_PATH
index d7dcee68072820764d0910c79e740db052512073..bb677a73b7c9d67a623e962ad9419231bb11e3f4 100644 (file)
@@ -125,7 +125,7 @@ void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata,
 
        if (!skb) {
                printk(KERN_ERR "%s: failed to allocate buffer "
-                                       "for delba frame\n", sdata->dev->name);
+                                       "for delba frame\n", sdata->name);
                return;
        }
 
@@ -133,10 +133,10 @@ void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata,
        mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
        memset(mgmt, 0, 24);
        memcpy(mgmt->da, da, ETH_ALEN);
-       memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
+       memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
        if (sdata->vif.type == NL80211_IFTYPE_AP ||
            sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
-               memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN);
+               memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
        else if (sdata->vif.type == NL80211_IFTYPE_STATION)
                memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
 
@@ -185,3 +185,50 @@ void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata,
                spin_unlock_bh(&sta->lock);
        }
 }
+
+int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata,
+                              enum ieee80211_smps_mode smps, const u8 *da,
+                              const u8 *bssid)
+{
+       struct ieee80211_local *local = sdata->local;
+       struct sk_buff *skb;
+       struct ieee80211_mgmt *action_frame;
+
+       /* 27 = header + category + action + smps mode */
+       skb = dev_alloc_skb(27 + local->hw.extra_tx_headroom);
+       if (!skb)
+               return -ENOMEM;
+
+       skb_reserve(skb, local->hw.extra_tx_headroom);
+       action_frame = (void *)skb_put(skb, 27);
+       memcpy(action_frame->da, da, ETH_ALEN);
+       memcpy(action_frame->sa, sdata->dev->dev_addr, ETH_ALEN);
+       memcpy(action_frame->bssid, bssid, ETH_ALEN);
+       action_frame->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+                                                 IEEE80211_STYPE_ACTION);
+       action_frame->u.action.category = WLAN_CATEGORY_HT;
+       action_frame->u.action.u.ht_smps.action = WLAN_HT_ACTION_SMPS;
+       switch (smps) {
+       case IEEE80211_SMPS_AUTOMATIC:
+       case IEEE80211_SMPS_NUM_MODES:
+               WARN_ON(1);
+       case IEEE80211_SMPS_OFF:
+               action_frame->u.action.u.ht_smps.smps_control =
+                               WLAN_HT_SMPS_CONTROL_DISABLED;
+               break;
+       case IEEE80211_SMPS_STATIC:
+               action_frame->u.action.u.ht_smps.smps_control =
+                               WLAN_HT_SMPS_CONTROL_STATIC;
+               break;
+       case IEEE80211_SMPS_DYNAMIC:
+               action_frame->u.action.u.ht_smps.smps_control =
+                               WLAN_HT_SMPS_CONTROL_DYNAMIC;
+               break;
+       }
+
+       /* we'll do more on status of this frame */
+       IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
+       ieee80211_tx_skb(sdata, skb);
+
+       return 0;
+}
index 1f2db647bb5ccd3526d8fc40ef3e6aeb3cb68da6..5bcde4c3fba1595569dd1675a18dbe48053d1fb0 100644 (file)
@@ -117,7 +117,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
        mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
                                          IEEE80211_STYPE_PROBE_RESP);
        memset(mgmt->da, 0xff, ETH_ALEN);
-       memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
+       memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
        memcpy(mgmt->bssid, ifibss->bssid, ETH_ALEN);
        mgmt->u.beacon.beacon_int = cpu_to_le16(beacon_int);
        mgmt->u.beacon.timestamp = cpu_to_le64(tsf);
@@ -187,15 +187,17 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
 static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
                                    struct ieee80211_bss *bss)
 {
+       struct cfg80211_bss *cbss =
+               container_of((void *)bss, struct cfg80211_bss, priv);
        struct ieee80211_supported_band *sband;
        u32 basic_rates;
        int i, j;
-       u16 beacon_int = bss->cbss.beacon_interval;
+       u16 beacon_int = cbss->beacon_interval;
 
        if (beacon_int < 10)
                beacon_int = 10;
 
-       sband = sdata->local->hw.wiphy->bands[bss->cbss.channel->band];
+       sband = sdata->local->hw.wiphy->bands[cbss->channel->band];
 
        basic_rates = 0;
 
@@ -212,12 +214,12 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
                }
        }
 
-       __ieee80211_sta_join_ibss(sdata, bss->cbss.bssid,
+       __ieee80211_sta_join_ibss(sdata, cbss->bssid,
                                  beacon_int,
-                                 bss->cbss.channel,
+                                 cbss->channel,
                                  basic_rates,
-                                 bss->cbss.capability,
-                                 bss->cbss.tsf);
+                                 cbss->capability,
+                                 cbss->tsf);
 }
 
 static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
@@ -229,6 +231,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
 {
        struct ieee80211_local *local = sdata->local;
        int freq;
+       struct cfg80211_bss *cbss;
        struct ieee80211_bss *bss;
        struct sta_info *sta;
        struct ieee80211_channel *channel;
@@ -252,7 +255,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
 
                rcu_read_lock();
 
-               sta = sta_info_get(local, mgmt->sa);
+               sta = sta_info_get(sdata, mgmt->sa);
                if (sta) {
                        u32 prev_rates;
 
@@ -266,7 +269,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
                                printk(KERN_DEBUG "%s: updated supp_rates set "
                                    "for %pM based on beacon info (0x%llx | "
                                    "0x%llx -> 0x%llx)\n",
-                                   sdata->dev->name,
+                                   sdata->name,
                                    sta->sta.addr,
                                    (unsigned long long) prev_rates,
                                    (unsigned long long) supp_rates,
@@ -283,8 +286,10 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
        if (!bss)
                return;
 
+       cbss = container_of((void *)bss, struct cfg80211_bss, priv);
+
        /* was just updated in ieee80211_bss_info_update */
-       beacon_timestamp = bss->cbss.tsf;
+       beacon_timestamp = cbss->tsf;
 
        /* check if we need to merge IBSS */
 
@@ -297,11 +302,11 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
                goto put_bss;
 
        /* not an IBSS */
-       if (!(bss->cbss.capability & WLAN_CAPABILITY_IBSS))
+       if (!(cbss->capability & WLAN_CAPABILITY_IBSS))
                goto put_bss;
 
        /* different channel */
-       if (bss->cbss.channel != local->oper_channel)
+       if (cbss->channel != local->oper_channel)
                goto put_bss;
 
        /* different SSID */
@@ -311,7 +316,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
                goto put_bss;
 
        /* same BSSID */
-       if (memcmp(bss->cbss.bssid, sdata->u.ibss.bssid, ETH_ALEN) == 0)
+       if (memcmp(cbss->bssid, sdata->u.ibss.bssid, ETH_ALEN) == 0)
                goto put_bss;
 
        if (rx_status->flag & RX_FLAG_TSFT) {
@@ -364,7 +369,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
 #ifdef CONFIG_MAC80211_IBSS_DEBUG
                printk(KERN_DEBUG "%s: beacon TSF higher than "
                       "local TSF - IBSS merge with BSSID %pM\n",
-                      sdata->dev->name, mgmt->bssid);
+                      sdata->name, mgmt->bssid);
 #endif
                ieee80211_sta_join_ibss(sdata, bss);
                ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, supp_rates);
@@ -394,7 +399,7 @@ struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
        if (local->num_sta >= IEEE80211_IBSS_MAX_STA_ENTRIES) {
                if (net_ratelimit())
                        printk(KERN_DEBUG "%s: No room for a new IBSS STA entry %pM\n",
-                              sdata->dev->name, addr);
+                              sdata->name, addr);
                return NULL;
        }
 
@@ -406,7 +411,7 @@ struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
 
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
        printk(KERN_DEBUG "%s: Adding new IBSS station %pM (dev=%s)\n",
-              wiphy_name(local->hw.wiphy), addr, sdata->dev->name);
+              wiphy_name(local->hw.wiphy), addr, sdata->name);
 #endif
 
        sta = sta_info_alloc(sdata, addr, GFP_ATOMIC);
@@ -470,7 +475,7 @@ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata)
                return;
 
        printk(KERN_DEBUG "%s: No active IBSS STAs - trying to scan for other "
-              "IBSS networks with same SSID (merge)\n", sdata->dev->name);
+              "IBSS networks with same SSID (merge)\n", sdata->name);
 
        ieee80211_request_internal_scan(sdata, ifibss->ssid, ifibss->ssid_len);
 }
@@ -492,13 +497,13 @@ static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata)
                 * random number generator get different BSSID. */
                get_random_bytes(bssid, ETH_ALEN);
                for (i = 0; i < ETH_ALEN; i++)
-                       bssid[i] ^= sdata->dev->dev_addr[i];
+                       bssid[i] ^= sdata->vif.addr[i];
                bssid[0] &= ~0x01;
                bssid[0] |= 0x02;
        }
 
        printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %pM\n",
-              sdata->dev->name, bssid);
+              sdata->name, bssid);
 
        sband = local->hw.wiphy->bands[ifibss->channel->band];
 
@@ -518,7 +523,7 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
 {
        struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
        struct ieee80211_local *local = sdata->local;
-       struct ieee80211_bss *bss;
+       struct cfg80211_bss *cbss;
        struct ieee80211_channel *chan = NULL;
        const u8 *bssid = NULL;
        int active_ibss;
@@ -527,7 +532,7 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
        active_ibss = ieee80211_sta_active_ibss(sdata);
 #ifdef CONFIG_MAC80211_IBSS_DEBUG
        printk(KERN_DEBUG "%s: sta_find_ibss (active_ibss=%d)\n",
-              sdata->dev->name, active_ibss);
+              sdata->name, active_ibss);
 #endif /* CONFIG_MAC80211_IBSS_DEBUG */
 
        if (active_ibss)
@@ -542,21 +547,23 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
                chan = ifibss->channel;
        if (!is_zero_ether_addr(ifibss->bssid))
                bssid = ifibss->bssid;
-       bss = (void *)cfg80211_get_bss(local->hw.wiphy, chan, bssid,
-                                      ifibss->ssid, ifibss->ssid_len,
-                                      WLAN_CAPABILITY_IBSS |
-                                      WLAN_CAPABILITY_PRIVACY,
-                                      capability);
+       cbss = cfg80211_get_bss(local->hw.wiphy, chan, bssid,
+                               ifibss->ssid, ifibss->ssid_len,
+                               WLAN_CAPABILITY_IBSS | WLAN_CAPABILITY_PRIVACY,
+                               capability);
+
+       if (cbss) {
+               struct ieee80211_bss *bss;
 
-       if (bss) {
+               bss = (void *)cbss->priv;
 #ifdef CONFIG_MAC80211_IBSS_DEBUG
                printk(KERN_DEBUG "   sta_find_ibss: selected %pM current "
-                      "%pM\n", bss->cbss.bssid, ifibss->bssid);
+                      "%pM\n", cbss->bssid, ifibss->bssid);
 #endif /* CONFIG_MAC80211_IBSS_DEBUG */
 
                printk(KERN_DEBUG "%s: Selected IBSS BSSID %pM"
                       " based on configured SSID\n",
-                      sdata->dev->name, bss->cbss.bssid);
+                      sdata->name, cbss->bssid);
 
                ieee80211_sta_join_ibss(sdata, bss);
                ieee80211_rx_bss_put(local, bss);
@@ -575,7 +582,7 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
        } else if (time_after(jiffies, ifibss->last_scan_completed +
                                        IEEE80211_SCAN_INTERVAL)) {
                printk(KERN_DEBUG "%s: Trigger new scan to find an IBSS to "
-                      "join\n", sdata->dev->name);
+                      "join\n", sdata->name);
 
                ieee80211_request_internal_scan(sdata, ifibss->ssid,
                                                ifibss->ssid_len);
@@ -589,7 +596,7 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
                                return;
                        }
                        printk(KERN_DEBUG "%s: IBSS not allowed on"
-                              " %d MHz\n", sdata->dev->name,
+                              " %d MHz\n", sdata->name,
                               local->hw.conf.channel->center_freq);
 
                        /* No IBSS found - decrease scan interval and continue
@@ -623,7 +630,7 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata,
 #ifdef CONFIG_MAC80211_IBSS_DEBUG
        printk(KERN_DEBUG "%s: RX ProbeReq SA=%pM DA=%pM BSSID=%pM"
               " (tx_last_beacon=%d)\n",
-              sdata->dev->name, mgmt->sa, mgmt->da,
+              sdata->name, mgmt->sa, mgmt->da,
               mgmt->bssid, tx_last_beacon);
 #endif /* CONFIG_MAC80211_IBSS_DEBUG */
 
@@ -641,7 +648,7 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata,
 #ifdef CONFIG_MAC80211_IBSS_DEBUG
                printk(KERN_DEBUG "%s: Invalid SSID IE in ProbeReq "
                       "from %pM\n",
-                      sdata->dev->name, mgmt->sa);
+                      sdata->name, mgmt->sa);
 #endif
                return;
        }
@@ -661,7 +668,7 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata,
        memcpy(resp->da, mgmt->sa, ETH_ALEN);
 #ifdef CONFIG_MAC80211_IBSS_DEBUG
        printk(KERN_DEBUG "%s: Sending ProbeResp to %pM\n",
-              sdata->dev->name, resp->da);
+              sdata->name, resp->da);
 #endif /* CONFIG_MAC80211_IBSS_DEBUG */
        IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
        ieee80211_tx_skb(sdata, skb);
@@ -675,7 +682,7 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
        size_t baselen;
        struct ieee802_11_elems elems;
 
-       if (memcmp(mgmt->da, sdata->dev->dev_addr, ETH_ALEN))
+       if (memcmp(mgmt->da, sdata->vif.addr, ETH_ALEN))
                return; /* ignore ProbeResp to foreign address */
 
        baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt;
@@ -748,7 +755,7 @@ static void ieee80211_ibss_work(struct work_struct *work)
        if (WARN_ON(local->suspended))
                return;
 
-       if (!netif_running(sdata->dev))
+       if (!ieee80211_sdata_running(sdata))
                return;
 
        if (local->scanning)
@@ -831,7 +838,7 @@ void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local)
 
        mutex_lock(&local->iflist_mtx);
        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_ADHOC)
                        continue;
index 91dc8636d64481bfefe15c063428f0df018b83a1..c18f576f18481fa31b587fdbd84a8c5e84edaa2b 100644 (file)
@@ -58,6 +58,15 @@ struct ieee80211_local;
 
 #define TU_TO_EXP_TIME(x)      (jiffies + usecs_to_jiffies((x) * 1024))
 
+#define IEEE80211_DEFAULT_UAPSD_QUEUES \
+       (IEEE80211_WMM_IE_STA_QOSINFO_AC_BK |   \
+        IEEE80211_WMM_IE_STA_QOSINFO_AC_BE |   \
+        IEEE80211_WMM_IE_STA_QOSINFO_AC_VI |   \
+        IEEE80211_WMM_IE_STA_QOSINFO_AC_VO)
+
+#define IEEE80211_DEFAULT_MAX_SP_LEN           \
+       IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL
+
 struct ieee80211_fragment_entry {
        unsigned long first_frag_time;
        unsigned int seq;
@@ -71,9 +80,6 @@ struct ieee80211_fragment_entry {
 
 
 struct ieee80211_bss {
-       /* Yes, this is a hack */
-       struct cfg80211_bss cbss;
-
        /* don't want to look up all the time */
        size_t ssid_len;
        u8 ssid[IEEE80211_MAX_SSID_LEN];
@@ -81,6 +87,7 @@ struct ieee80211_bss {
        u8 dtim_period;
 
        bool wmm_used;
+       bool uapsd_supported;
 
        unsigned long last_probe_resp;
 
@@ -140,7 +147,6 @@ typedef unsigned __bitwise__ ieee80211_tx_result;
 
 struct ieee80211_tx_data {
        struct sk_buff *skb;
-       struct net_device *dev;
        struct ieee80211_local *local;
        struct ieee80211_sub_if_data *sdata;
        struct sta_info *sta;
@@ -228,31 +234,78 @@ struct mesh_preq_queue {
        u8 flags;
 };
 
-enum ieee80211_mgd_state {
-       IEEE80211_MGD_STATE_IDLE,
-       IEEE80211_MGD_STATE_PROBE,
-       IEEE80211_MGD_STATE_AUTH,
-       IEEE80211_MGD_STATE_ASSOC,
+enum ieee80211_work_type {
+       IEEE80211_WORK_ABORT,
+       IEEE80211_WORK_DIRECT_PROBE,
+       IEEE80211_WORK_AUTH,
+       IEEE80211_WORK_ASSOC,
+       IEEE80211_WORK_REMAIN_ON_CHANNEL,
+};
+
+/**
+ * enum work_done_result - indicates what to do after work was done
+ *
+ * @WORK_DONE_DESTROY: This work item is no longer needed, destroy.
+ * @WORK_DONE_REQUEUE: This work item was reset to be reused, and
+ *     should be requeued.
+ */
+enum work_done_result {
+       WORK_DONE_DESTROY,
+       WORK_DONE_REQUEUE,
 };
 
-struct ieee80211_mgd_work {
+struct ieee80211_work {
        struct list_head list;
-       struct ieee80211_bss *bss;
-       int ie_len;
-       u8 prev_bssid[ETH_ALEN];
-       u8 ssid[IEEE80211_MAX_SSID_LEN];
-       u8 ssid_len;
+
+       struct rcu_head rcu_head;
+
+       struct ieee80211_sub_if_data *sdata;
+
+       enum work_done_result (*done)(struct ieee80211_work *wk,
+                                     struct sk_buff *skb);
+
+       struct ieee80211_channel *chan;
+       enum nl80211_channel_type chan_type;
+
        unsigned long timeout;
-       enum ieee80211_mgd_state state;
-       u16 auth_alg, auth_transaction;
+       enum ieee80211_work_type type;
 
-       int tries;
+       u8 filter_ta[ETH_ALEN];
 
-       u8 key[WLAN_KEY_LEN_WEP104];
-       u8 key_len, key_idx;
+       bool started;
+
+       union {
+               struct {
+                       int tries;
+                       u16 algorithm, transaction;
+                       u8 ssid[IEEE80211_MAX_SSID_LEN];
+                       u8 ssid_len;
+                       u8 key[WLAN_KEY_LEN_WEP104];
+                       u8 key_len, key_idx;
+                       bool privacy;
+               } probe_auth;
+               struct {
+                       struct cfg80211_bss *bss;
+                       const u8 *supp_rates;
+                       const u8 *ht_information_ie;
+                       enum ieee80211_smps_mode smps;
+                       int tries;
+                       u16 capability;
+                       u8 prev_bssid[ETH_ALEN];
+                       u8 ssid[IEEE80211_MAX_SSID_LEN];
+                       u8 ssid_len;
+                       u8 supp_rates_len;
+                       bool wmm_used, use_11n, uapsd_used;
+               } assoc;
+               struct {
+                       u32 duration;
+                       bool started;
+               } remain;
+       };
 
+       int ie_len;
        /* must be last */
-       u8 ie[0]; /* for auth or assoc frame, not probe */
+       u8 ie[0];
 };
 
 /* flags used in struct ieee80211_if_managed.flags */
@@ -260,15 +313,10 @@ enum ieee80211_sta_flags {
        IEEE80211_STA_BEACON_POLL       = BIT(0),
        IEEE80211_STA_CONNECTION_POLL   = BIT(1),
        IEEE80211_STA_CONTROL_PORT      = BIT(2),
-       IEEE80211_STA_WMM_ENABLED       = BIT(3),
        IEEE80211_STA_DISABLE_11N       = BIT(4),
        IEEE80211_STA_CSA_RECEIVED      = BIT(5),
        IEEE80211_STA_MFP_ENABLED       = BIT(6),
-};
-
-/* flags for MLME request */
-enum ieee80211_sta_request {
-       IEEE80211_STA_REQ_SCAN,
+       IEEE80211_STA_UAPSD_ENABLED     = BIT(7),
 };
 
 struct ieee80211_if_managed {
@@ -285,21 +333,18 @@ struct ieee80211_if_managed {
        int probe_send_count;
 
        struct mutex mtx;
-       struct ieee80211_bss *associated;
-       struct ieee80211_mgd_work *old_associate_work;
-       struct list_head work_list;
+       struct cfg80211_bss *associated;
 
        u8 bssid[ETH_ALEN];
 
        u16 aid;
-       u16 capab;
 
        struct sk_buff_head skb_queue;
 
        unsigned long timers_running; /* used for quiesce/restart */
        bool powersave; /* powersave requested for this iface */
-
-       unsigned long request;
+       enum ieee80211_smps_mode req_smps, /* requested smps mode */
+                                ap_smps; /* smps mode AP thinks we're in */
 
        unsigned int flags;
 
@@ -433,6 +478,8 @@ struct ieee80211_sub_if_data {
 
        int drop_unencrypted;
 
+       char name[IFNAMSIZ];
+
        /*
         * keep track of whether the HT opmode (stored in
         * vif.bss_info.ht_operation_mode) is valid.
@@ -458,8 +505,8 @@ struct ieee80211_sub_if_data {
         */
        struct ieee80211_if_ap *bss;
 
-       int force_unicast_rateidx; /* forced TX rateidx for unicast frames */
-       int max_ratectrl_rateidx; /* max TX rateidx for rate control */
+       /* bitmap of allowed (non-MCS) rate indexes for rate control */
+       u32 rc_rateidx_mask[IEEE80211_NUM_BANDS];
 
        union {
                struct ieee80211_if_ap ap;
@@ -564,6 +611,15 @@ struct ieee80211_local {
 
        const struct ieee80211_ops *ops;
 
+       /*
+        * 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;
+       struct sk_buff_head work_skb_queue;
+
        /*
         * private workqueue to mac80211. mac80211 makes this accessible
         * via ieee80211_queue_work()
@@ -586,6 +642,9 @@ struct ieee80211_local {
        /* used for uploading changed mc list */
        struct work_struct reconfig_filter;
 
+       /* used to reconfigure hardware SM PS */
+       struct work_struct recalc_smps;
+
        /* aggregated multicast list */
        struct dev_addr_list *mc_list;
        int mc_count;
@@ -689,6 +748,10 @@ struct ieee80211_local {
        enum nl80211_channel_type oper_channel_type;
        struct ieee80211_channel *oper_channel, *csa_channel;
 
+       /* Temporary remain-on-channel for off-channel operations */
+       struct ieee80211_channel *tmp_channel;
+       enum nl80211_channel_type tmp_channel_type;
+
        /* SNMP counters */
        /* dot11CountersTable */
        u32 dot11TransmittedFragmentCount;
@@ -745,8 +808,22 @@ struct ieee80211_local {
        int wifi_wme_noack_test;
        unsigned int wmm_acm; /* bit field of ACM bits (BIT(802.1D tag)) */
 
+       /*
+        * Bitmask of enabled u-apsd queues,
+        * IEEE80211_WMM_IE_STA_QOSINFO_AC_BE & co. Needs a new association
+        * to take effect.
+        */
+       unsigned int uapsd_queues;
+
+       /*
+        * Maximum number of buffered frames AP can deliver during a
+        * service period, IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL or similar.
+        * Needs a new association to take effect.
+        */
+       unsigned int uapsd_max_sp_len;
+
        bool pspolling;
-       bool scan_ps_enabled;
+       bool offchannel_ps_enabled;
        /*
         * PS can only be enabled when we have exactly one managed
         * interface (and monitors) in PS, this then points there.
@@ -760,6 +837,8 @@ struct ieee80211_local {
        int user_power_level; /* in dBm */
        int power_constr_level; /* in dBm */
 
+       enum ieee80211_smps_mode smps_mode;
+
        struct work_struct restart_work;
 
 #ifdef CONFIG_MAC80211_DEBUGFS
@@ -874,6 +953,8 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
 void ieee80211_configure_filter(struct ieee80211_local *local);
 u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata);
 
+extern bool ieee80211_disable_40mhz_24ghz;
+
 /* STA code */
 void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata);
 int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
@@ -937,7 +1018,15 @@ ieee80211_rx_bss_get(struct ieee80211_local *local, u8 *bssid, int freq,
 void ieee80211_rx_bss_put(struct ieee80211_local *local,
                          struct ieee80211_bss *bss);
 
+/* off-channel helpers */
+void ieee80211_offchannel_stop_beaconing(struct ieee80211_local *local);
+void ieee80211_offchannel_stop_station(struct ieee80211_local *local);
+void ieee80211_offchannel_return(struct ieee80211_local *local,
+                                bool enable_beaconing);
+
 /* interface handling */
+int ieee80211_iface_init(void);
+void ieee80211_iface_exit(void);
 int ieee80211_if_add(struct ieee80211_local *local, const char *name,
                     struct net_device **new_dev, enum nl80211_iftype type,
                     struct vif_params *params);
@@ -948,6 +1037,11 @@ void ieee80211_remove_interfaces(struct ieee80211_local *local);
 u32 __ieee80211_recalc_idle(struct ieee80211_local *local);
 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);
+}
+
 /* tx handling */
 void ieee80211_clear_tx_pending(struct ieee80211_local *local);
 void ieee80211_tx_pending(unsigned long data);
@@ -976,6 +1070,9 @@ void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u1
 void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata,
                          const u8 *da, u16 tid,
                          u16 initiator, u16 reason_code);
+int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata,
+                              enum ieee80211_smps_mode smps, const u8 *da,
+                              const u8 *bssid);
 
 void ieee80211_sta_stop_rx_ba_session(struct ieee80211_sub_if_data *sdata, u8 *da,
                                u16 tid, u16 initiator, u16 reason);
@@ -1086,6 +1183,28 @@ void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata,
 u32 ieee80211_sta_get_rates(struct ieee80211_local *local,
                            struct ieee802_11_elems *elems,
                            enum ieee80211_band band);
+int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata,
+                            enum ieee80211_smps_mode smps_mode);
+void ieee80211_recalc_smps(struct ieee80211_local *local,
+                          struct ieee80211_sub_if_data *forsdata);
+
+size_t ieee80211_ie_split(const u8 *ies, size_t ielen,
+                         const u8 *ids, int n_ids, size_t offset);
+size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset);
+
+/* internal work items */
+void ieee80211_work_init(struct ieee80211_local *local);
+void ieee80211_add_work(struct ieee80211_work *wk);
+void free_work(struct ieee80211_work *wk);
+void ieee80211_work_purge(struct ieee80211_sub_if_data *sdata);
+ieee80211_rx_result ieee80211_work_rx_mgmt(struct ieee80211_sub_if_data *sdata,
+                                          struct sk_buff *skb);
+int ieee80211_wk_remain_on_channel(struct ieee80211_sub_if_data *sdata,
+                                  struct ieee80211_channel *chan,
+                                  enum nl80211_channel_type channel_type,
+                                  unsigned int duration, u64 *cookie);
+int ieee80211_wk_cancel_remain_on_channel(
+       struct ieee80211_sub_if_data *sdata, u64 cookie);
 
 #ifdef CONFIG_MAC80211_NOINLINE
 #define debug_noinline noinline
index 32abae3ce32a52a4b126a8a26368b327d0771a21..edf21cebeee8984b5b5f1852520fea2065a51e21 100644 (file)
@@ -62,6 +62,23 @@ static int ieee80211_change_mtu(struct net_device *dev, int new_mtu)
        return 0;
 }
 
+static int ieee80211_change_mac(struct net_device *dev, void *addr)
+{
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct sockaddr *sa = addr;
+       int ret;
+
+       if (ieee80211_sdata_running(sdata))
+               return -EBUSY;
+
+       ret = eth_mac_addr(dev, sa);
+
+       if (ret == 0)
+               memcpy(sdata->vif.addr, sa->sa_data, ETH_ALEN);
+
+       return ret;
+}
+
 static inline int identical_mac_addr_allowed(int type1, int type2)
 {
        return type1 == NL80211_IFTYPE_MONITOR ||
@@ -82,7 +99,6 @@ static int ieee80211_open(struct net_device *dev)
        struct ieee80211_sub_if_data *nsdata;
        struct ieee80211_local *local = sdata->local;
        struct sta_info *sta;
-       struct ieee80211_if_init_conf conf;
        u32 changed = 0;
        int res;
        u32 hw_reconf_flags = 0;
@@ -97,7 +113,7 @@ static int ieee80211_open(struct net_device *dev)
        list_for_each_entry(nsdata, &local->interfaces, list) {
                struct net_device *ndev = nsdata->dev;
 
-               if (ndev != dev && netif_running(ndev)) {
+               if (ndev != dev && ieee80211_sdata_running(nsdata)) {
                        /*
                         * Allow only a single IBSS interface to be up at any
                         * time. This is restricted because beacon distribution
@@ -183,7 +199,7 @@ static int ieee80211_open(struct net_device *dev)
                struct net_device *ndev = nsdata->dev;
 
                /*
-                * No need to check netif_running since we do not allow
+                * 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) {
@@ -234,10 +250,7 @@ static int ieee80211_open(struct net_device *dev)
                ieee80211_configure_filter(local);
                break;
        default:
-               conf.vif = &sdata->vif;
-               conf.type = sdata->vif.type;
-               conf.mac_addr = dev->dev_addr;
-               res = drv_add_interface(local, &conf);
+               res = drv_add_interface(local, &sdata->vif);
                if (res)
                        goto err_stop;
 
@@ -320,7 +333,7 @@ static int ieee80211_open(struct net_device *dev)
 
        return 0;
  err_del_interface:
-       drv_remove_interface(local, &conf);
+       drv_remove_interface(local, &sdata->vif);
  err_stop:
        if (!local->open_count)
                drv_stop(local);
@@ -335,7 +348,6 @@ static int ieee80211_stop(struct net_device *dev)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ieee80211_local *local = sdata->local;
-       struct ieee80211_if_init_conf conf;
        struct sta_info *sta;
        unsigned long flags;
        struct sk_buff *skb, *tmp;
@@ -347,6 +359,11 @@ static int ieee80211_stop(struct net_device *dev)
         */
        netif_tx_stop_all_queues(dev);
 
+       /*
+        * Purge work for this interface.
+        */
+       ieee80211_work_purge(sdata);
+
        /*
         * Now delete all active aggregation sessions.
         */
@@ -514,12 +531,9 @@ static int ieee80211_stop(struct net_device *dev)
                                BSS_CHANGED_BEACON_ENABLED);
                }
 
-               conf.vif = &sdata->vif;
-               conf.type = sdata->vif.type;
-               conf.mac_addr = dev->dev_addr;
                /* disable all keys for as long as this netdev is down */
                ieee80211_disable_keys(sdata);
-               drv_remove_interface(local, &conf);
+               drv_remove_interface(local, &sdata->vif);
        }
 
        sdata->bss = NULL;
@@ -659,7 +673,7 @@ static const struct net_device_ops ieee80211_dataif_ops = {
        .ndo_start_xmit         = ieee80211_subif_start_xmit,
        .ndo_set_multicast_list = ieee80211_set_multicast_list,
        .ndo_change_mtu         = ieee80211_change_mtu,
-       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_set_mac_address    = ieee80211_change_mac,
        .ndo_select_queue       = ieee80211_netdev_select_queue,
 };
 
@@ -779,7 +793,7 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata,
         * and goes into the requested mode.
         */
 
-       if (netif_running(sdata->dev))
+       if (ieee80211_sdata_running(sdata))
                return -EBUSY;
 
        /* Purge and reset type-dependent state. */
@@ -833,6 +847,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
        /* don't use IEEE80211_DEV_TO_SUB_IF because it checks too much */
        sdata = netdev_priv(ndev);
        ndev->ieee80211_ptr = &sdata->wdev;
+       memcpy(sdata->vif.addr, ndev->dev_addr, ETH_ALEN);
+       memcpy(sdata->name, ndev->name, IFNAMSIZ);
 
        /* initialise type-independent data */
        sdata->wdev.wiphy = local->hw.wiphy;
@@ -844,8 +860,12 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
 
        INIT_LIST_HEAD(&sdata->key_list);
 
-       sdata->force_unicast_rateidx = -1;
-       sdata->max_ratectrl_rateidx = -1;
+       for (i = 0; i < IEEE80211_NUM_BANDS; i++) {
+               struct ieee80211_supported_band *sband;
+               sband = local->hw.wiphy->bands[i];
+               sdata->rc_rateidx_mask[i] =
+                       sband ? (1 << sband->n_bitrates) - 1 : 0;
+       }
 
        /* setup type-dependent data */
        ieee80211_setup_sdata(sdata, type);
@@ -938,6 +958,8 @@ static u32 ieee80211_idle_on(struct ieee80211_local *local)
               wiphy_name(local->hw.wiphy));
 #endif
 
+       drv_flush(local, false);
+
        local->hw.conf.flags |= IEEE80211_CONF_IDLE;
        return IEEE80211_CONF_CHANGE_IDLE;
 }
@@ -947,16 +969,18 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local)
        struct ieee80211_sub_if_data *sdata;
        int count = 0;
 
+       if (!list_empty(&local->work_list))
+               return ieee80211_idle_off(local, "working");
+
        if (local->scanning)
                return ieee80211_idle_off(local, "scanning");
 
        list_for_each_entry(sdata, &local->interfaces, list) {
-               if (!netif_running(sdata->dev))
+               if (!ieee80211_sdata_running(sdata))
                        continue;
                /* do not count disabled managed interfaces */
                if (sdata->vif.type == NL80211_IFTYPE_STATION &&
-                   !sdata->u.mgd.associated &&
-                   list_empty(&sdata->u.mgd.work_list))
+                   !sdata->u.mgd.associated)
                        continue;
                /* do not count unused IBSS interfaces */
                if (sdata->vif.type == NL80211_IFTYPE_ADHOC &&
@@ -984,3 +1008,41 @@ void ieee80211_recalc_idle(struct ieee80211_local *local)
        if (chg)
                ieee80211_hw_config(local, chg);
 }
+
+static int netdev_notify(struct notifier_block *nb,
+                        unsigned long state,
+                        void *ndev)
+{
+       struct net_device *dev = ndev;
+       struct ieee80211_sub_if_data *sdata;
+
+       if (state != NETDEV_CHANGENAME)
+               return 0;
+
+       if (!dev->ieee80211_ptr || !dev->ieee80211_ptr->wiphy)
+               return 0;
+
+       if (dev->ieee80211_ptr->wiphy->privid != mac80211_wiphy_privid)
+               return 0;
+
+       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+       memcpy(sdata->name, sdata->name, IFNAMSIZ);
+
+       ieee80211_debugfs_rename_netdev(sdata);
+       return 0;
+}
+
+static struct notifier_block mac80211_netdev_notifier = {
+       .notifier_call = netdev_notify,
+};
+
+int ieee80211_iface_init(void)
+{
+       return register_netdevice_notifier(&mac80211_netdev_notifier);
+}
+
+void ieee80211_iface_exit(void)
+{
+       unregister_netdevice_notifier(&mac80211_netdev_notifier);
+}
index 659a42d529e3cbcd20100452e018b5584fa970a9..8160d9c5372ea09e8fbc6c01b54c3e00703d3188 100644 (file)
@@ -139,7 +139,7 @@ static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
                                     struct ieee80211_sub_if_data,
                                     u.ap);
 
-       ret = drv_set_key(key->local, SET_KEY, &sdata->vif, sta, &key->conf);
+       ret = drv_set_key(key->local, SET_KEY, sdata, sta, &key->conf);
 
        if (!ret) {
                spin_lock_bh(&todo_lock);
@@ -181,7 +181,7 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
                                     struct ieee80211_sub_if_data,
                                     u.ap);
 
-       ret = drv_set_key(key->local, DISABLE_KEY, &sdata->vif,
+       ret = drv_set_key(key->local, DISABLE_KEY, sdata,
                          sta, &key->conf);
 
        if (ret)
@@ -421,7 +421,7 @@ void ieee80211_key_link(struct ieee80211_key *key,
                         */
 
                        /* same here, the AP could be using QoS */
-                       ap = sta_info_get(key->local, key->sdata->u.mgd.bssid);
+                       ap = sta_info_get(key->sdata, key->sdata->u.mgd.bssid);
                        if (ap) {
                                if (test_sta_flags(ap, WLAN_STA_WME))
                                        key->conf.flags |=
@@ -443,7 +443,7 @@ void ieee80211_key_link(struct ieee80211_key *key,
        add_todo(old_key, KEY_FLAG_TODO_DELETE);
 
        add_todo(key, KEY_FLAG_TODO_ADD_DEBUGFS);
-       if (netif_running(sdata->dev))
+       if (ieee80211_sdata_running(sdata))
                add_todo(key, KEY_FLAG_TODO_HWACCEL_ADD);
 
        spin_unlock_irqrestore(&sdata->local->key_lock, flags);
@@ -509,7 +509,7 @@ void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata)
 {
        ASSERT_RTNL();
 
-       if (WARN_ON(!netif_running(sdata->dev)))
+       if (WARN_ON(!ieee80211_sdata_running(sdata)))
                return;
 
        ieee80211_todo_for_each_key(sdata, KEY_FLAG_TODO_HWACCEL_ADD);
index a49f93b79e9299571eecaa714aef060a62999789..bdc2968c2bbe2d72cbe1c55d554a67ff65887b17 100644 (file)
@@ -59,11 +59,17 @@ enum ieee80211_internal_key_flags {
        KEY_FLAG_TODO_DEFMGMTKEY        = BIT(6),
 };
 
+enum ieee80211_internal_tkip_state {
+       TKIP_STATE_NOT_INIT,
+       TKIP_STATE_PHASE1_DONE,
+       TKIP_STATE_PHASE1_HW_UPLOADED,
+};
+
 struct tkip_ctx {
        u32 iv32;
        u16 iv16;
        u16 p1k[5];
-       int initialized;
+       enum ieee80211_internal_tkip_state state;
 };
 
 struct ieee80211_key {
index 0d2d94881f1f14fd3d42b692c144fea3b66909e3..ec8f767ba95b4979c334754866318f7767c15b08 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/skbuff.h>
 #include <linux/etherdevice.h>
 #include <linux/if_arp.h>
-#include <linux/wireless.h>
 #include <linux/rtnetlink.h>
 #include <linux/bitmap.h>
 #include <linux/pm_qos_params.h>
 #include "led.h"
 #include "cfg.h"
 #include "debugfs.h"
-#include "debugfs_netdev.h"
+
+
+bool ieee80211_disable_40mhz_24ghz;
+module_param(ieee80211_disable_40mhz_24ghz, bool, 0644);
+MODULE_PARM_DESC(ieee80211_disable_40mhz_24ghz,
+                "Disable 40MHz support in the 2.4GHz band");
 
 void ieee80211_configure_filter(struct ieee80211_local *local)
 {
@@ -102,6 +106,9 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
        if (scan_chan) {
                chan = scan_chan;
                channel_type = NL80211_CHAN_NO_HT;
+       } else if (local->tmp_channel) {
+               chan = scan_chan = local->tmp_channel;
+               channel_type = local->tmp_channel_type;
        } else {
                chan = local->oper_channel;
                channel_type = local->oper_channel_type;
@@ -114,6 +121,18 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
                changed |= IEEE80211_CONF_CHANGE_CHANNEL;
        }
 
+       if (!conf_is_ht(&local->hw.conf)) {
+               /*
+                * mac80211.h documents that this is only valid
+                * when the channel is set to an HT type, and
+                * that otherwise STATIC is used.
+                */
+               local->hw.conf.smps_mode = IEEE80211_SMPS_STATIC;
+       } else if (local->hw.conf.smps_mode != local->smps_mode) {
+               local->hw.conf.smps_mode = local->smps_mode;
+               changed |= IEEE80211_CONF_CHANGE_SMPS;
+       }
+
        if (scan_chan)
                power = chan->max_power;
        else
@@ -173,7 +192,7 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
        } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
                sdata->vif.bss_conf.bssid = sdata->u.ibss.bssid;
        else if (sdata->vif.type == NL80211_IFTYPE_AP)
-               sdata->vif.bss_conf.bssid = sdata->dev->dev_addr;
+               sdata->vif.bss_conf.bssid = sdata->vif.addr;
        else if (ieee80211_vif_is_mesh(&sdata->vif)) {
                sdata->vif.bss_conf.bssid = zero;
        } else {
@@ -195,7 +214,7 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
        }
 
        if (changed & BSS_CHANGED_BEACON_ENABLED) {
-               if (local->quiescing || !netif_running(sdata->dev) ||
+               if (local->quiescing || !ieee80211_sdata_running(sdata) ||
                    test_bit(SCAN_SW_SCANNING, &local->scanning)) {
                        sdata->vif.bss_conf.enable_beacon = false;
                } else {
@@ -223,8 +242,7 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
                }
        }
 
-       drv_bss_info_changed(local, &sdata->vif,
-                            &sdata->vif.bss_conf, changed);
+       drv_bss_info_changed(local, sdata, &sdata->vif.bss_conf, changed);
 }
 
 u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata)
@@ -299,6 +317,16 @@ void ieee80211_restart_hw(struct ieee80211_hw *hw)
 }
 EXPORT_SYMBOL(ieee80211_restart_hw);
 
+static void ieee80211_recalc_smps_work(struct work_struct *work)
+{
+       struct ieee80211_local *local =
+               container_of(work, struct ieee80211_local, recalc_smps);
+
+       mutex_lock(&local->iflist_mtx);
+       ieee80211_recalc_smps(local, NULL);
+       mutex_unlock(&local->iflist_mtx);
+}
+
 struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
                                        const struct ieee80211_ops *ops)
 {
@@ -333,9 +361,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
                        WIPHY_FLAG_4ADDR_STATION;
        wiphy->privid = mac80211_wiphy_privid;
 
-       /* Yes, putting cfg80211_bss into ieee80211_bss is a hack */
-       wiphy->bss_priv_size = sizeof(struct ieee80211_bss) -
-                              sizeof(struct cfg80211_bss);
+       wiphy->bss_priv_size = sizeof(struct ieee80211_bss);
 
        local = wiphy_priv(wiphy);
 
@@ -358,6 +384,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
        local->hw.conf.long_frame_max_tx_count = wiphy->retry_long;
        local->hw.conf.short_frame_max_tx_count = wiphy->retry_short;
        local->user_power_level = -1;
+       local->uapsd_queues = IEEE80211_DEFAULT_UAPSD_QUEUES;
+       local->uapsd_max_sp_len = IEEE80211_DEFAULT_MAX_SP_LEN;
 
        INIT_LIST_HEAD(&local->interfaces);
        mutex_init(&local->iflist_mtx);
@@ -369,9 +397,13 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
 
        INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work);
 
+       ieee80211_work_init(local);
+
        INIT_WORK(&local->restart_work, ieee80211_restart_work);
 
        INIT_WORK(&local->reconfig_filter, ieee80211_reconfig_filter);
+       INIT_WORK(&local->recalc_smps, ieee80211_recalc_smps_work);
+       local->smps_mode = IEEE80211_SMPS_OFF;
 
        INIT_WORK(&local->dynamic_ps_enable_work,
                  ieee80211_dynamic_ps_enable_work);
@@ -461,6 +493,10 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
        else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)
                local->hw.wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC;
 
+       WARN((local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD)
+            && (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK),
+            "U-APSD not supported with HW_PS_NULLFUNC_STACK\n");
+
        /*
         * Calculate scan IE length -- we need this to alloc
         * memory and to subtract from the driver limit. It
@@ -674,11 +710,19 @@ static int __init ieee80211_init(void)
 
        ret = rc80211_pid_init();
        if (ret)
-               return ret;
+               goto err_pid;
 
-       ieee80211_debugfs_netdev_init();
+       ret = ieee80211_iface_init();
+       if (ret)
+               goto err_netdev;
 
        return 0;
+ err_netdev:
+       rc80211_pid_exit();
+ err_pid:
+       rc80211_minstrel_exit();
+
+       return ret;
 }
 
 static void __exit ieee80211_exit(void)
@@ -695,7 +739,7 @@ static void __exit ieee80211_exit(void)
        if (mesh_allocated)
                ieee80211s_stop();
 
-       ieee80211_debugfs_netdev_exit();
+       ieee80211_iface_exit();
 }
 
 
index 6a43314295988c76067017be5d19de785e404d54..61080c5fad50f2ef859ac6461d6168d69cddaaa6 100644 (file)
@@ -457,7 +457,7 @@ static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata,
 
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
        printk(KERN_DEBUG "%s: running mesh housekeeping\n",
-              sdata->dev->name);
+              sdata->name);
 #endif
 
        ieee80211_sta_expire(sdata, IEEE80211_MESH_PEER_INACTIVITY_LIMIT);
@@ -565,7 +565,7 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
 
        /* ignore ProbeResp to foreign address */
        if (stype == IEEE80211_STYPE_PROBE_RESP &&
-           compare_ether_addr(mgmt->da, sdata->dev->dev_addr))
+           compare_ether_addr(mgmt->da, sdata->vif.addr))
                return;
 
        baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt;
@@ -645,7 +645,7 @@ static void ieee80211_mesh_work(struct work_struct *work)
        struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
        struct sk_buff *skb;
 
-       if (!netif_running(sdata->dev))
+       if (!ieee80211_sdata_running(sdata))
                return;
 
        if (local->scanning)
index d28acb6b1f8151e2a822ec5fc697231b5d76e698..ce84237ebad3b493d5c5d8dc3ea18662395dbfb7 100644 (file)
@@ -128,9 +128,9 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags,
                                          IEEE80211_STYPE_ACTION);
 
        memcpy(mgmt->da, da, ETH_ALEN);
-       memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
+       memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
        /* BSSID == SA */
-       memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN);
+       memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
        mgmt->u.action.category = MESH_PATH_SEL_CATEGORY;
        mgmt->u.action.u.mesh_action.action_code = MESH_PATH_SEL_ACTION;
 
@@ -222,7 +222,7 @@ int mesh_path_error_tx(u8 ttl, u8 *target, __le32 target_sn,
                                          IEEE80211_STYPE_ACTION);
 
        memcpy(mgmt->da, ra, ETH_ALEN);
-       memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
+       memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
        /* BSSID is left zeroed, wildcard value */
        mgmt->u.action.category = MESH_PATH_SEL_CATEGORY;
        mgmt->u.action.u.mesh_action.action_code = MESH_PATH_SEL_ACTION;
@@ -335,7 +335,7 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata,
        bool process = true;
 
        rcu_read_lock();
-       sta = sta_info_get(local, mgmt->sa);
+       sta = sta_info_get(sdata, mgmt->sa);
        if (!sta) {
                rcu_read_unlock();
                return 0;
@@ -374,7 +374,7 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata,
                new_metric = MAX_METRIC;
        exp_time = TU_TO_EXP_TIME(orig_lifetime);
 
-       if (memcmp(orig_addr, sdata->dev->dev_addr, ETH_ALEN) == 0) {
+       if (memcmp(orig_addr, sdata->vif.addr, ETH_ALEN) == 0) {
                /* This MP is the originator, we are not interested in this
                 * frame, except for updating transmitter's path info.
                 */
@@ -486,7 +486,7 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
 
        mhwmp_dbg("received PREQ from %pM\n", orig_addr);
 
-       if (memcmp(target_addr, sdata->dev->dev_addr, ETH_ALEN) == 0) {
+       if (memcmp(target_addr, sdata->vif.addr, ETH_ALEN) == 0) {
                mhwmp_dbg("PREQ is for us\n");
                forward = false;
                reply = true;
@@ -579,7 +579,7 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata,
         * replies
         */
        target_addr = PREP_IE_TARGET_ADDR(prep_elem);
-       if (memcmp(target_addr, sdata->dev->dev_addr, ETH_ALEN) == 0)
+       if (memcmp(target_addr, sdata->vif.addr, ETH_ALEN) == 0)
                /* destination, no forwarding required */
                return;
 
@@ -890,7 +890,7 @@ void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata)
                target_flags = MP_F_RF;
 
        spin_unlock_bh(&mpath->state_lock);
-       mesh_path_sel_frame_tx(MPATH_PREQ, 0, sdata->dev->dev_addr,
+       mesh_path_sel_frame_tx(MPATH_PREQ, 0, sdata->vif.addr,
                        cpu_to_le32(ifmsh->sn), target_flags, mpath->dst,
                        cpu_to_le32(mpath->sn), broadcast_addr, 0,
                        ttl, cpu_to_le32(lifetime), 0,
@@ -939,7 +939,7 @@ int mesh_nexthop_lookup(struct sk_buff *skb,
                if (time_after(jiffies,
                               mpath->exp_time -
                               msecs_to_jiffies(sdata->u.mesh.mshcfg.path_refresh_time)) &&
-                   !memcmp(sdata->dev->dev_addr, hdr->addr4, ETH_ALEN) &&
+                   !memcmp(sdata->vif.addr, hdr->addr4, ETH_ALEN) &&
                    !(mpath->flags & MESH_PATH_RESOLVING) &&
                    !(mpath->flags & MESH_PATH_FIXED)) {
                        mesh_queue_preq(mpath,
@@ -1010,7 +1010,7 @@ mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata)
 {
        struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
 
-       mesh_path_sel_frame_tx(MPATH_RANN, 0, sdata->dev->dev_addr,
+       mesh_path_sel_frame_tx(MPATH_RANN, 0, sdata->vif.addr,
                               cpu_to_le32(++ifmsh->sn),
                               0, NULL, 0, broadcast_addr,
                               0, MESH_TTL, 0, 0, 0, sdata);
index 0192cfdacae48cfefb84ea2c1fe73b51a7968277..2312efe04c62ea7116ca6de8302fa76f47b3e56a 100644 (file)
@@ -260,7 +260,7 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata)
        int err = 0;
        u32 hash_idx;
 
-       if (memcmp(dst, sdata->dev->dev_addr, ETH_ALEN) == 0)
+       if (memcmp(dst, sdata->vif.addr, ETH_ALEN) == 0)
                /* never add ourselves as neighbours */
                return -ENOTSUPP;
 
@@ -377,7 +377,7 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata)
        int err = 0;
        u32 hash_idx;
 
-       if (memcmp(dst, sdata->dev->dev_addr, ETH_ALEN) == 0)
+       if (memcmp(dst, sdata->vif.addr, ETH_ALEN) == 0)
                /* never add ourselves as neighbours */
                return -ENOTSUPP;
 
@@ -605,7 +605,7 @@ void mesh_path_discard_frame(struct sk_buff *skb,
        struct mesh_path *mpath;
        u32 sn = 0;
 
-       if (memcmp(hdr->addr4, sdata->dev->dev_addr, ETH_ALEN) != 0) {
+       if (memcmp(hdr->addr4, sdata->vif.addr, ETH_ALEN) != 0) {
                u8 *ra, *da;
 
                da = hdr->addr3;
index 0f7c6e6a4248cf6300b79e21b363b776dd4a5da7..7985e51508987393667dad0feb934bbdec0d09b0 100644 (file)
@@ -169,7 +169,7 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
        mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
                                          IEEE80211_STYPE_ACTION);
        memcpy(mgmt->da, da, ETH_ALEN);
-       memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
+       memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
        /* BSSID is left zeroed, wildcard value */
        mgmt->u.action.category = MESH_PLINK_CATEGORY;
        mgmt->u.action.u.plink_action.action_code = action;
@@ -234,7 +234,7 @@ void mesh_neighbour_update(u8 *hw_addr, u32 rates, struct ieee80211_sub_if_data
 
        rcu_read_lock();
 
-       sta = sta_info_get(local, hw_addr);
+       sta = sta_info_get(sdata, hw_addr);
        if (!sta) {
                sta = mesh_plink_alloc(sdata, hw_addr, rates);
                if (!sta) {
@@ -455,7 +455,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
 
        rcu_read_lock();
 
-       sta = sta_info_get(local, mgmt->sa);
+       sta = sta_info_get(sdata, mgmt->sa);
        if (!sta && ftype != PLINK_OPEN) {
                mpl_dbg("Mesh plink: cls or cnf from unknown peer\n");
                rcu_read_unlock();
index 05a18f43e1bf73fd34f029b1e35aa0a0193f7162..1e1d16c55ee57be5e9c4366d7c8094454e943e5d 100644 (file)
@@ -75,11 +75,8 @@ enum rx_mgmt_action {
        /* caller must call cfg80211_send_disassoc() */
        RX_MGMT_CFG80211_DISASSOC,
 
-       /* caller must call cfg80211_auth_timeout() & free work */
-       RX_MGMT_CFG80211_AUTH_TO,
-
-       /* caller must call cfg80211_assoc_timeout() & free work */
-       RX_MGMT_CFG80211_ASSOC_TO,
+       /* caller must tell cfg80211 about internal error */
+       RX_MGMT_CFG80211_ASSOC_ERROR,
 };
 
 /* utils */
@@ -122,27 +119,6 @@ static int ecw2cw(int ecw)
        return (1 << ecw) - 1;
 }
 
-static int ieee80211_compatible_rates(struct ieee80211_bss *bss,
-                                     struct ieee80211_supported_band *sband,
-                                     u32 *rates)
-{
-       int i, j, count;
-       *rates = 0;
-       count = 0;
-       for (i = 0; i < bss->supp_rates_len; i++) {
-               int rate = (bss->supp_rates[i] & 0x7F) * 5;
-
-               for (j = 0; j < sband->n_bitrates; j++)
-                       if (sband->bitrates[j].bitrate == rate) {
-                               *rates |= BIT(j);
-                               count++;
-                               break;
-                       }
-       }
-
-       return count;
-}
-
 /*
  * ieee80211_enable_ht should be called only after the operating band
  * has been determined as ht configuration depends on the hw's
@@ -202,7 +178,7 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
                ieee80211_hw_config(local, 0);
 
                rcu_read_lock();
-               sta = sta_info_get(local, bssid);
+               sta = sta_info_get(sdata, bssid);
                if (sta)
                        rate_control_rate_update(local, sband, sta,
                                                 IEEE80211_RC_HT_CHANGED);
@@ -228,209 +204,6 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
 
 /* frame sending functions */
 
-static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
-                                struct ieee80211_mgd_work *wk)
-{
-       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
-       struct ieee80211_local *local = sdata->local;
-       struct sk_buff *skb;
-       struct ieee80211_mgmt *mgmt;
-       u8 *pos;
-       const u8 *ies, *ht_ie;
-       int i, len, count, rates_len, supp_rates_len;
-       u16 capab;
-       int wmm = 0;
-       struct ieee80211_supported_band *sband;
-       u32 rates = 0;
-
-       skb = dev_alloc_skb(local->hw.extra_tx_headroom +
-                           sizeof(*mgmt) + 200 + wk->ie_len +
-                           wk->ssid_len);
-       if (!skb) {
-               printk(KERN_DEBUG "%s: failed to allocate buffer for assoc "
-                      "frame\n", sdata->dev->name);
-               return;
-       }
-       skb_reserve(skb, local->hw.extra_tx_headroom);
-
-       sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
-
-       capab = ifmgd->capab;
-
-       if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ) {
-               if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE))
-                       capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME;
-               if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE))
-                       capab |= WLAN_CAPABILITY_SHORT_PREAMBLE;
-       }
-
-       if (wk->bss->cbss.capability & WLAN_CAPABILITY_PRIVACY)
-               capab |= WLAN_CAPABILITY_PRIVACY;
-       if (wk->bss->wmm_used)
-               wmm = 1;
-
-       /* get all rates supported by the device and the AP as
-        * some APs don't like getting a superset of their rates
-        * in the association request (e.g. D-Link DAP 1353 in
-        * b-only mode) */
-       rates_len = ieee80211_compatible_rates(wk->bss, sband, &rates);
-
-       if ((wk->bss->cbss.capability & WLAN_CAPABILITY_SPECTRUM_MGMT) &&
-           (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT))
-               capab |= WLAN_CAPABILITY_SPECTRUM_MGMT;
-
-       mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
-       memset(mgmt, 0, 24);
-       memcpy(mgmt->da, wk->bss->cbss.bssid, ETH_ALEN);
-       memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
-       memcpy(mgmt->bssid, wk->bss->cbss.bssid, ETH_ALEN);
-
-       if (!is_zero_ether_addr(wk->prev_bssid)) {
-               skb_put(skb, 10);
-               mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
-                                                 IEEE80211_STYPE_REASSOC_REQ);
-               mgmt->u.reassoc_req.capab_info = cpu_to_le16(capab);
-               mgmt->u.reassoc_req.listen_interval =
-                               cpu_to_le16(local->hw.conf.listen_interval);
-               memcpy(mgmt->u.reassoc_req.current_ap, wk->prev_bssid,
-                      ETH_ALEN);
-       } else {
-               skb_put(skb, 4);
-               mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
-                                                 IEEE80211_STYPE_ASSOC_REQ);
-               mgmt->u.assoc_req.capab_info = cpu_to_le16(capab);
-               mgmt->u.assoc_req.listen_interval =
-                               cpu_to_le16(local->hw.conf.listen_interval);
-       }
-
-       /* SSID */
-       ies = pos = skb_put(skb, 2 + wk->ssid_len);
-       *pos++ = WLAN_EID_SSID;
-       *pos++ = wk->ssid_len;
-       memcpy(pos, wk->ssid, wk->ssid_len);
-
-       /* add all rates which were marked to be used above */
-       supp_rates_len = rates_len;
-       if (supp_rates_len > 8)
-               supp_rates_len = 8;
-
-       len = sband->n_bitrates;
-       pos = skb_put(skb, supp_rates_len + 2);
-       *pos++ = WLAN_EID_SUPP_RATES;
-       *pos++ = supp_rates_len;
-
-       count = 0;
-       for (i = 0; i < sband->n_bitrates; i++) {
-               if (BIT(i) & rates) {
-                       int rate = sband->bitrates[i].bitrate;
-                       *pos++ = (u8) (rate / 5);
-                       if (++count == 8)
-                               break;
-               }
-       }
-
-       if (rates_len > count) {
-               pos = skb_put(skb, rates_len - count + 2);
-               *pos++ = WLAN_EID_EXT_SUPP_RATES;
-               *pos++ = rates_len - count;
-
-               for (i++; i < sband->n_bitrates; i++) {
-                       if (BIT(i) & rates) {
-                               int rate = sband->bitrates[i].bitrate;
-                               *pos++ = (u8) (rate / 5);
-                       }
-               }
-       }
-
-       if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT) {
-               /* 1. power capabilities */
-               pos = skb_put(skb, 4);
-               *pos++ = WLAN_EID_PWR_CAPABILITY;
-               *pos++ = 2;
-               *pos++ = 0; /* min tx power */
-               *pos++ = local->hw.conf.channel->max_power; /* max tx power */
-
-               /* 2. supported channels */
-               /* TODO: get this in reg domain format */
-               pos = skb_put(skb, 2 * sband->n_channels + 2);
-               *pos++ = WLAN_EID_SUPPORTED_CHANNELS;
-               *pos++ = 2 * sband->n_channels;
-               for (i = 0; i < sband->n_channels; i++) {
-                       *pos++ = ieee80211_frequency_to_channel(
-                                       sband->channels[i].center_freq);
-                       *pos++ = 1; /* one channel in the subband*/
-               }
-       }
-
-       if (wk->ie_len && wk->ie) {
-               pos = skb_put(skb, wk->ie_len);
-               memcpy(pos, wk->ie, wk->ie_len);
-       }
-
-       if (wmm && (ifmgd->flags & IEEE80211_STA_WMM_ENABLED)) {
-               pos = skb_put(skb, 9);
-               *pos++ = WLAN_EID_VENDOR_SPECIFIC;
-               *pos++ = 7; /* len */
-               *pos++ = 0x00; /* Microsoft OUI 00:50:F2 */
-               *pos++ = 0x50;
-               *pos++ = 0xf2;
-               *pos++ = 2; /* WME */
-               *pos++ = 0; /* WME info */
-               *pos++ = 1; /* WME ver */
-               *pos++ = 0;
-       }
-
-       /* wmm support is a must to HT */
-       /*
-        * IEEE802.11n does not allow TKIP/WEP as pairwise
-        * ciphers in HT mode. We still associate in non-ht
-        * mode (11a/b/g) if any one of these ciphers is
-        * configured as pairwise.
-        */
-       if (wmm && (ifmgd->flags & IEEE80211_STA_WMM_ENABLED) &&
-           sband->ht_cap.ht_supported &&
-           (ht_ie = ieee80211_bss_get_ie(&wk->bss->cbss, WLAN_EID_HT_INFORMATION)) &&
-           ht_ie[1] >= sizeof(struct ieee80211_ht_info) &&
-           (!(ifmgd->flags & IEEE80211_STA_DISABLE_11N))) {
-               struct ieee80211_ht_info *ht_info =
-                       (struct ieee80211_ht_info *)(ht_ie + 2);
-               u16 cap = sband->ht_cap.cap;
-               __le16 tmp;
-               u32 flags = local->hw.conf.channel->flags;
-
-               switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
-               case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
-                       if (flags & IEEE80211_CHAN_NO_HT40PLUS) {
-                               cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
-                               cap &= ~IEEE80211_HT_CAP_SGI_40;
-                       }
-                       break;
-               case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
-                       if (flags & IEEE80211_CHAN_NO_HT40MINUS) {
-                               cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
-                               cap &= ~IEEE80211_HT_CAP_SGI_40;
-                       }
-                       break;
-               }
-
-               tmp = cpu_to_le16(cap);
-               pos = skb_put(skb, sizeof(struct ieee80211_ht_cap)+2);
-               *pos++ = WLAN_EID_HT_CAPABILITY;
-               *pos++ = sizeof(struct ieee80211_ht_cap);
-               memset(pos, 0, sizeof(struct ieee80211_ht_cap));
-               memcpy(pos, &tmp, sizeof(u16));
-               pos += sizeof(u16);
-               /* TODO: needs a define here for << 2 */
-               *pos++ = sband->ht_cap.ampdu_factor |
-                        (sband->ht_cap.ampdu_density << 2);
-               memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs));
-       }
-
-       IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
-       ieee80211_tx_skb(sdata, skb);
-}
-
-
 static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
                                           const u8 *bssid, u16 stype, u16 reason,
                                           void *cookie)
@@ -443,7 +216,7 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
        skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt));
        if (!skb) {
                printk(KERN_DEBUG "%s: failed to allocate buffer for "
-                      "deauth/disassoc frame\n", sdata->dev->name);
+                      "deauth/disassoc frame\n", sdata->name);
                return;
        }
        skb_reserve(skb, local->hw.extra_tx_headroom);
@@ -451,7 +224,7 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
        mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
        memset(mgmt, 0, 24);
        memcpy(mgmt->da, bssid, ETH_ALEN);
-       memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
+       memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
        memcpy(mgmt->bssid, bssid, ETH_ALEN);
        mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | stype);
        skb_put(skb, 2);
@@ -476,30 +249,15 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
 void ieee80211_send_pspoll(struct ieee80211_local *local,
                           struct ieee80211_sub_if_data *sdata)
 {
-       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        struct ieee80211_pspoll *pspoll;
        struct sk_buff *skb;
-       u16 fc;
 
-       skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*pspoll));
-       if (!skb) {
-               printk(KERN_DEBUG "%s: failed to allocate buffer for "
-                      "pspoll frame\n", sdata->dev->name);
+       skb = ieee80211_pspoll_get(&local->hw, &sdata->vif);
+       if (!skb)
                return;
-       }
-       skb_reserve(skb, local->hw.extra_tx_headroom);
 
-       pspoll = (struct ieee80211_pspoll *) skb_put(skb, sizeof(*pspoll));
-       memset(pspoll, 0, sizeof(*pspoll));
-       fc = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL | IEEE80211_FCTL_PM;
-       pspoll->frame_control = cpu_to_le16(fc);
-       pspoll->aid = cpu_to_le16(ifmgd->aid);
-
-       /* aid in PS-Poll has its two MSBs each set to 1 */
-       pspoll->aid |= cpu_to_le16(1 << 15 | 1 << 14);
-
-       memcpy(pspoll->bssid, ifmgd->bssid, ETH_ALEN);
-       memcpy(pspoll->ta, sdata->dev->dev_addr, ETH_ALEN);
+       pspoll = (struct ieee80211_pspoll *) skb->data;
+       pspoll->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);
 
        IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
        ieee80211_tx_skb(sdata, skb);
@@ -508,6 +266,24 @@ void ieee80211_send_pspoll(struct ieee80211_local *local,
 void ieee80211_send_nullfunc(struct ieee80211_local *local,
                             struct ieee80211_sub_if_data *sdata,
                             int powersave)
+{
+       struct sk_buff *skb;
+       struct ieee80211_hdr_3addr *nullfunc;
+
+       skb = ieee80211_nullfunc_get(&local->hw, &sdata->vif);
+       if (!skb)
+               return;
+
+       nullfunc = (struct ieee80211_hdr_3addr *) skb->data;
+       if (powersave)
+               nullfunc->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);
+
+       IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
+       ieee80211_tx_skb(sdata, skb);
+}
+
+static void ieee80211_send_4addr_nullfunc(struct ieee80211_local *local,
+                                         struct ieee80211_sub_if_data *sdata)
 {
        struct sk_buff *skb;
        struct ieee80211_hdr *nullfunc;
@@ -516,24 +292,23 @@ void ieee80211_send_nullfunc(struct ieee80211_local *local,
        if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION))
                return;
 
-       skb = dev_alloc_skb(local->hw.extra_tx_headroom + 24);
+       skb = dev_alloc_skb(local->hw.extra_tx_headroom + 30);
        if (!skb) {
-               printk(KERN_DEBUG "%s: failed to allocate buffer for nullfunc "
-                      "frame\n", sdata->dev->name);
+               printk(KERN_DEBUG "%s: failed to allocate buffer for 4addr "
+                      "nullfunc frame\n", sdata->name);
                return;
        }
        skb_reserve(skb, local->hw.extra_tx_headroom);
 
-       nullfunc = (struct ieee80211_hdr *) skb_put(skb, 24);
-       memset(nullfunc, 0, 24);
+       nullfunc = (struct ieee80211_hdr *) skb_put(skb, 30);
+       memset(nullfunc, 0, 30);
        fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC |
-                        IEEE80211_FCTL_TODS);
-       if (powersave)
-               fc |= cpu_to_le16(IEEE80211_FCTL_PM);
+                        IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
        nullfunc->frame_control = fc;
        memcpy(nullfunc->addr1, sdata->u.mgd.bssid, ETH_ALEN);
-       memcpy(nullfunc->addr2, sdata->dev->dev_addr, ETH_ALEN);
+       memcpy(nullfunc->addr2, sdata->vif.addr, ETH_ALEN);
        memcpy(nullfunc->addr3, sdata->u.mgd.bssid, ETH_ALEN);
+       memcpy(nullfunc->addr4, sdata->vif.addr, ETH_ALEN);
 
        IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
        ieee80211_tx_skb(sdata, skb);
@@ -546,7 +321,7 @@ static void ieee80211_chswitch_work(struct work_struct *work)
                container_of(work, struct ieee80211_sub_if_data, u.mgd.chswitch_work);
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 
-       if (!netif_running(sdata->dev))
+       if (!ieee80211_sdata_running(sdata))
                return;
 
        mutex_lock(&ifmgd->mtx);
@@ -557,7 +332,7 @@ static void ieee80211_chswitch_work(struct work_struct *work)
        ieee80211_hw_config(sdata->local, IEEE80211_CONF_CHANGE_CHANNEL);
 
        /* XXX: shouldn't really modify cfg80211-owned data! */
-       ifmgd->associated->cbss.channel = sdata->local->oper_channel;
+       ifmgd->associated->channel = sdata->local->oper_channel;
 
        ieee80211_wake_queues_by_reason(&sdata->local->hw,
                                        IEEE80211_QUEUE_STOP_REASON_CSA);
@@ -584,6 +359,8 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
                                      struct ieee80211_channel_sw_ie *sw_elem,
                                      struct ieee80211_bss *bss)
 {
+       struct cfg80211_bss *cbss =
+               container_of((void *)bss, struct cfg80211_bss, priv);
        struct ieee80211_channel *new_ch;
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        int new_freq = ieee80211_channel_to_frequency(sw_elem->new_ch_num);
@@ -617,7 +394,7 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
                mod_timer(&ifmgd->chswitch_timer,
                          jiffies +
                          msecs_to_jiffies(sw_elem->count *
-                                          bss->cbss.beacon_interval));
+                                          cbss->beacon_interval));
        }
 }
 
@@ -691,8 +468,13 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
                return;
        }
 
+       if (!list_empty(&local->work_list)) {
+               local->ps_sdata = NULL;
+               goto change;
+       }
+
        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)
                        continue;
@@ -701,7 +483,7 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
        }
 
        if (count == 1 && found->u.mgd.powersave &&
-           found->u.mgd.associated && list_empty(&found->u.mgd.work_list) &&
+           found->u.mgd.associated &&
            !(found->u.mgd.flags & (IEEE80211_STA_BEACON_POLL |
                                    IEEE80211_STA_CONNECTION_POLL))) {
                s32 beaconint_us;
@@ -729,6 +511,7 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
                local->ps_sdata = NULL;
        }
 
+ change:
        ieee80211_change_ps(local);
 }
 
@@ -786,9 +569,9 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
        struct ieee80211_tx_queue_params params;
        size_t left;
        int count;
-       u8 *pos;
+       u8 *pos, uapsd_queues = 0;
 
-       if (!(ifmgd->flags & IEEE80211_STA_WMM_ENABLED))
+       if (local->hw.queues < 4)
                return;
 
        if (!wmm_param)
@@ -796,6 +579,10 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
 
        if (wmm_param_len < 8 || wmm_param[5] /* version */ != 1)
                return;
+
+       if (ifmgd->flags & IEEE80211_STA_UAPSD_ENABLED)
+               uapsd_queues = local->uapsd_queues;
+
        count = wmm_param[6] & 0x0f;
        if (count == ifmgd->wmm_last_param_set)
                return;
@@ -810,6 +597,7 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
        for (; left >= 4; left -= 4, pos += 4) {
                int aci = (pos[0] >> 5) & 0x03;
                int acm = (pos[0] >> 4) & 0x01;
+               bool uapsd = false;
                int queue;
 
                switch (aci) {
@@ -817,22 +605,30 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
                        queue = 3;
                        if (acm)
                                local->wmm_acm |= BIT(1) | BIT(2); /* BK/- */
+                       if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BK)
+                               uapsd = true;
                        break;
                case 2: /* AC_VI */
                        queue = 1;
                        if (acm)
                                local->wmm_acm |= BIT(4) | BIT(5); /* CL/VI */
+                       if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VI)
+                               uapsd = true;
                        break;
                case 3: /* AC_VO */
                        queue = 0;
                        if (acm)
                                local->wmm_acm |= BIT(6) | BIT(7); /* VO/NC */
+                       if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO)
+                               uapsd = true;
                        break;
                case 0: /* AC_BE */
                default:
                        queue = 2;
                        if (acm)
                                local->wmm_acm |= BIT(0) | BIT(3); /* BE/EE */
+                       if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BE)
+                               uapsd = true;
                        break;
                }
 
@@ -840,11 +636,14 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
                params.cw_max = ecw2cw((pos[1] & 0xf0) >> 4);
                params.cw_min = ecw2cw(pos[1] & 0x0f);
                params.txop = get_unaligned_le16(pos + 2);
+               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\n",
+                      "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.aifs, params.cw_min, params.cw_max, params.txop,
+                      params.uapsd);
 #endif
                if (drv_conf_tx(local, queue, &params) && local->ops->conf_tx)
                        printk(KERN_DEBUG "%s: failed to set TX queue "
@@ -871,6 +670,8 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata,
        }
 
        use_short_slot = !!(capab & WLAN_CAPABILITY_SHORT_SLOT_TIME);
+       if (sdata->local->hw.conf.channel->band == IEEE80211_BAND_5GHZ)
+               use_short_slot = true;
 
        if (use_protection != bss_conf->use_cts_prot) {
                bss_conf->use_cts_prot = use_protection;
@@ -891,25 +692,24 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata,
 }
 
 static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
-                                    struct ieee80211_mgd_work *wk,
+                                    struct cfg80211_bss *cbss,
                                     u32 bss_info_changed)
 {
+       struct ieee80211_bss *bss = (void *)cbss->priv;
        struct ieee80211_local *local = sdata->local;
-       struct ieee80211_bss *bss = wk->bss;
 
        bss_info_changed |= BSS_CHANGED_ASSOC;
        /* set timing information */
-       sdata->vif.bss_conf.beacon_int = bss->cbss.beacon_interval;
-       sdata->vif.bss_conf.timestamp = bss->cbss.tsf;
+       sdata->vif.bss_conf.beacon_int = cbss->beacon_interval;
+       sdata->vif.bss_conf.timestamp = cbss->tsf;
        sdata->vif.bss_conf.dtim_period = bss->dtim_period;
 
        bss_info_changed |= BSS_CHANGED_BEACON_INT;
        bss_info_changed |= ieee80211_handle_bss_capability(sdata,
-               bss->cbss.capability, bss->has_erp_value, bss->erp_value);
+               cbss->capability, bss->has_erp_value, bss->erp_value);
 
-       sdata->u.mgd.associated = bss;
-       sdata->u.mgd.old_associate_work = wk;
-       memcpy(sdata->u.mgd.bssid, bss->cbss.bssid, ETH_ALEN);
+       sdata->u.mgd.associated = cbss;
+       memcpy(sdata->u.mgd.bssid, cbss->bssid, ETH_ALEN);
 
        /* just to be sure */
        sdata->u.mgd.flags &= ~(IEEE80211_STA_CONNECTION_POLL |
@@ -940,99 +740,14 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
 
        mutex_lock(&local->iflist_mtx);
        ieee80211_recalc_ps(local, -1);
+       ieee80211_recalc_smps(local, sdata);
        mutex_unlock(&local->iflist_mtx);
 
        netif_tx_start_all_queues(sdata->dev);
        netif_carrier_on(sdata->dev);
 }
 
-static enum rx_mgmt_action __must_check
-ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata,
-                      struct ieee80211_mgd_work *wk)
-{
-       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
-       struct ieee80211_local *local = sdata->local;
-
-       wk->tries++;
-       if (wk->tries > IEEE80211_AUTH_MAX_TRIES) {
-               printk(KERN_DEBUG "%s: direct probe to AP %pM timed out\n",
-                      sdata->dev->name, wk->bss->cbss.bssid);
-
-               /*
-                * Most likely AP is not in the range so remove the
-                * bss struct for that AP.
-                */
-               cfg80211_unlink_bss(local->hw.wiphy, &wk->bss->cbss);
-
-               /*
-                * We might have a pending scan which had no chance to run yet
-                * due to work needing to be done. Hence, queue the STAs work
-                * again for that.
-                */
-               ieee80211_queue_work(&local->hw, &ifmgd->work);
-               return RX_MGMT_CFG80211_AUTH_TO;
-       }
-
-       printk(KERN_DEBUG "%s: direct probe to AP %pM (try %d)\n",
-                       sdata->dev->name, wk->bss->cbss.bssid,
-                       wk->tries);
-
-       /*
-        * Direct probe is sent to broadcast address as some APs
-        * will not answer to direct packet in unassociated state.
-        */
-       ieee80211_send_probe_req(sdata, NULL, wk->ssid, wk->ssid_len, NULL, 0);
-
-       wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT;
-       run_again(ifmgd, wk->timeout);
-
-       return RX_MGMT_NONE;
-}
-
-
-static enum rx_mgmt_action __must_check
-ieee80211_authenticate(struct ieee80211_sub_if_data *sdata,
-                      struct ieee80211_mgd_work *wk)
-{
-       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
-       struct ieee80211_local *local = sdata->local;
-
-       wk->tries++;
-       if (wk->tries > IEEE80211_AUTH_MAX_TRIES) {
-               printk(KERN_DEBUG "%s: authentication with AP %pM"
-                      " timed out\n",
-                      sdata->dev->name, wk->bss->cbss.bssid);
-
-               /*
-                * Most likely AP is not in the range so remove the
-                * bss struct for that AP.
-                */
-               cfg80211_unlink_bss(local->hw.wiphy, &wk->bss->cbss);
-
-               /*
-                * We might have a pending scan which had no chance to run yet
-                * due to work needing to be done. Hence, queue the STAs work
-                * again for that.
-                */
-               ieee80211_queue_work(&local->hw, &ifmgd->work);
-               return RX_MGMT_CFG80211_AUTH_TO;
-       }
-
-       printk(KERN_DEBUG "%s: authenticate with AP %pM (try %d)\n",
-              sdata->dev->name, wk->bss->cbss.bssid, wk->tries);
-
-       ieee80211_send_auth(sdata, 1, wk->auth_alg, wk->ie, wk->ie_len,
-                           wk->bss->cbss.bssid, NULL, 0, 0);
-       wk->auth_transaction = 2;
-
-       wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT;
-       run_again(ifmgd, wk->timeout);
-
-       return RX_MGMT_NONE;
-}
-
-static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
-                                  bool deauth)
+static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata)
 {
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        struct ieee80211_local *local = sdata->local;
@@ -1045,21 +760,11 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
        if (WARN_ON(!ifmgd->associated))
                return;
 
-       memcpy(bssid, ifmgd->associated->cbss.bssid, ETH_ALEN);
+       memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN);
 
        ifmgd->associated = NULL;
        memset(ifmgd->bssid, 0, ETH_ALEN);
 
-       if (deauth) {
-               kfree(ifmgd->old_associate_work);
-               ifmgd->old_associate_work = NULL;
-       } else {
-               struct ieee80211_mgd_work *wk = ifmgd->old_associate_work;
-
-               wk->state = IEEE80211_MGD_STATE_IDLE;
-               list_add(&wk->list, &ifmgd->work_list);
-       }
-
        /*
         * we need to commit the associated = NULL change because the
         * scan code uses that to determine whether this iface should
@@ -1078,7 +783,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
        netif_carrier_off(sdata->dev);
 
        rcu_read_lock();
-       sta = sta_info_get(local, bssid);
+       sta = sta_info_get(sdata, bssid);
        if (sta)
                ieee80211_sta_tear_down_BA_sessions(sta);
        rcu_read_unlock();
@@ -1115,7 +820,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
 
        rcu_read_lock();
 
-       sta = sta_info_get(local, bssid);
+       sta = sta_info_get(sdata, bssid);
        if (!sta) {
                rcu_read_unlock();
                return;
@@ -1128,44 +833,6 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
        sta_info_destroy(sta);
 }
 
-static enum rx_mgmt_action __must_check
-ieee80211_associate(struct ieee80211_sub_if_data *sdata,
-                   struct ieee80211_mgd_work *wk)
-{
-       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
-       struct ieee80211_local *local = sdata->local;
-
-       wk->tries++;
-       if (wk->tries > IEEE80211_ASSOC_MAX_TRIES) {
-               printk(KERN_DEBUG "%s: association with AP %pM"
-                      " timed out\n",
-                      sdata->dev->name, wk->bss->cbss.bssid);
-
-               /*
-                * Most likely AP is not in the range so remove the
-                * bss struct for that AP.
-                */
-               cfg80211_unlink_bss(local->hw.wiphy, &wk->bss->cbss);
-
-               /*
-                * We might have a pending scan which had no chance to run yet
-                * due to work needing to be done. Hence, queue the STAs work
-                * again for that.
-                */
-               ieee80211_queue_work(&local->hw, &ifmgd->work);
-               return RX_MGMT_CFG80211_ASSOC_TO;
-       }
-
-       printk(KERN_DEBUG "%s: associate with AP %pM (try %d)\n",
-              sdata->dev->name, wk->bss->cbss.bssid, wk->tries);
-       ieee80211_send_assoc(sdata, wk);
-
-       wk->timeout = jiffies + IEEE80211_ASSOC_TIMEOUT;
-       run_again(ifmgd, wk->timeout);
-
-       return RX_MGMT_NONE;
-}
-
 void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata,
                             struct ieee80211_hdr *hdr)
 {
@@ -1189,8 +856,8 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata)
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        const u8 *ssid;
 
-       ssid = ieee80211_bss_get_ie(&ifmgd->associated->cbss, WLAN_EID_SSID);
-       ieee80211_send_probe_req(sdata, ifmgd->associated->cbss.bssid,
+       ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID);
+       ieee80211_send_probe_req(sdata, ifmgd->associated->bssid,
                                 ssid + 2, ssid[1], NULL, 0);
 
        ifmgd->probe_send_count++;
@@ -1204,12 +871,15 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata,
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        bool already = false;
 
-       if (!netif_running(sdata->dev))
+       if (!ieee80211_sdata_running(sdata))
                return;
 
        if (sdata->local->scanning)
                return;
 
+       if (sdata->local->tmp_channel)
+               return;
+
        mutex_lock(&ifmgd->mtx);
 
        if (!ifmgd->associated)
@@ -1218,7 +888,7 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata,
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
        if (beacon && net_ratelimit())
                printk(KERN_DEBUG "%s: detected beacon loss from AP "
-                      "- sending probe request\n", sdata->dev->name);
+                      "- sending probe request\n", sdata->name);
 #endif
 
        /*
@@ -1271,88 +941,8 @@ void ieee80211_beacon_loss(struct ieee80211_vif *vif)
 }
 EXPORT_SYMBOL(ieee80211_beacon_loss);
 
-static void ieee80211_auth_completed(struct ieee80211_sub_if_data *sdata,
-                                    struct ieee80211_mgd_work *wk)
-{
-       wk->state = IEEE80211_MGD_STATE_IDLE;
-       printk(KERN_DEBUG "%s: authenticated\n", sdata->dev->name);
-}
-
-
-static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata,
-                                    struct ieee80211_mgd_work *wk,
-                                    struct ieee80211_mgmt *mgmt,
-                                    size_t len)
-{
-       u8 *pos;
-       struct ieee802_11_elems elems;
-
-       pos = mgmt->u.auth.variable;
-       ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems);
-       if (!elems.challenge)
-               return;
-       ieee80211_send_auth(sdata, 3, wk->auth_alg,
-                           elems.challenge - 2, elems.challenge_len + 2,
-                           wk->bss->cbss.bssid,
-                           wk->key, wk->key_len, wk->key_idx);
-       wk->auth_transaction = 4;
-}
-
-static enum rx_mgmt_action __must_check
-ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
-                      struct ieee80211_mgd_work *wk,
-                      struct ieee80211_mgmt *mgmt, size_t len)
-{
-       u16 auth_alg, auth_transaction, status_code;
-
-       if (wk->state != IEEE80211_MGD_STATE_AUTH)
-               return RX_MGMT_NONE;
-
-       if (len < 24 + 6)
-               return RX_MGMT_NONE;
-
-       if (memcmp(wk->bss->cbss.bssid, mgmt->sa, ETH_ALEN) != 0)
-               return RX_MGMT_NONE;
-
-       if (memcmp(wk->bss->cbss.bssid, mgmt->bssid, ETH_ALEN) != 0)
-               return RX_MGMT_NONE;
-
-       auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg);
-       auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction);
-       status_code = le16_to_cpu(mgmt->u.auth.status_code);
-
-       if (auth_alg != wk->auth_alg ||
-           auth_transaction != wk->auth_transaction)
-               return RX_MGMT_NONE;
-
-       if (status_code != WLAN_STATUS_SUCCESS) {
-               list_del(&wk->list);
-               kfree(wk);
-               return RX_MGMT_CFG80211_AUTH;
-       }
-
-       switch (wk->auth_alg) {
-       case WLAN_AUTH_OPEN:
-       case WLAN_AUTH_LEAP:
-       case WLAN_AUTH_FT:
-               ieee80211_auth_completed(sdata, wk);
-               return RX_MGMT_CFG80211_AUTH;
-       case WLAN_AUTH_SHARED_KEY:
-               if (wk->auth_transaction == 4) {
-                       ieee80211_auth_completed(sdata, wk);
-                       return RX_MGMT_CFG80211_AUTH;
-               } else
-                       ieee80211_auth_challenge(sdata, wk, mgmt, len);
-               break;
-       }
-
-       return RX_MGMT_NONE;
-}
-
-
 static enum rx_mgmt_action __must_check
 ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata,
-                        struct ieee80211_mgd_work *wk,
                         struct ieee80211_mgmt *mgmt, size_t len)
 {
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
@@ -1364,23 +954,15 @@ ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata,
 
        ASSERT_MGD_MTX(ifmgd);
 
-       if (wk)
-               bssid = wk->bss->cbss.bssid;
-       else
-               bssid = ifmgd->associated->cbss.bssid;
+       bssid = ifmgd->associated->bssid;
 
        reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);
 
        printk(KERN_DEBUG "%s: deauthenticated from %pM (Reason: %u)\n",
-                       sdata->dev->name, bssid, reason_code);
+                       sdata->name, bssid, reason_code);
 
-       if (!wk) {
-               ieee80211_set_disassoc(sdata, true);
-               ieee80211_recalc_idle(sdata->local);
-       } else {
-               list_del(&wk->list);
-               kfree(wk);
-       }
+       ieee80211_set_disassoc(sdata);
+       ieee80211_recalc_idle(sdata->local);
 
        return RX_MGMT_CFG80211_DEAUTH;
 }
@@ -1401,123 +983,72 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata,
        if (WARN_ON(!ifmgd->associated))
                return RX_MGMT_NONE;
 
-       if (WARN_ON(memcmp(ifmgd->associated->cbss.bssid, mgmt->sa, ETH_ALEN)))
+       if (WARN_ON(memcmp(ifmgd->associated->bssid, mgmt->sa, ETH_ALEN)))
                return RX_MGMT_NONE;
 
        reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
 
        printk(KERN_DEBUG "%s: disassociated from %pM (Reason: %u)\n",
-                       sdata->dev->name, mgmt->sa, reason_code);
+                       sdata->name, mgmt->sa, reason_code);
 
-       ieee80211_set_disassoc(sdata, false);
+       ieee80211_set_disassoc(sdata);
        ieee80211_recalc_idle(sdata->local);
        return RX_MGMT_CFG80211_DISASSOC;
 }
 
 
-static enum rx_mgmt_action __must_check
-ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
-                            struct ieee80211_mgd_work *wk,
-                            struct ieee80211_mgmt *mgmt, size_t len,
-                            bool reassoc)
+static bool ieee80211_assoc_success(struct ieee80211_work *wk,
+                                   struct ieee80211_mgmt *mgmt, size_t len)
 {
+       struct ieee80211_sub_if_data *sdata = wk->sdata;
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_supported_band *sband;
        struct sta_info *sta;
+       struct cfg80211_bss *cbss = wk->assoc.bss;
+       u8 *pos;
        u32 rates, basic_rates;
-       u16 capab_info, status_code, aid;
+       u16 capab_info, aid;
        struct ieee802_11_elems elems;
        struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
-       u8 *pos;
        u32 changed = 0;
-       int i, j;
-       bool have_higher_than_11mbit = false, newsta = false;
+       int i, j, err;
+       bool have_higher_than_11mbit = false;
        u16 ap_ht_cap_flags;
 
-       /*
-        * AssocResp and ReassocResp have identical structure, so process both
-        * of them in this function.
-        */
-
-       if (len < 24 + 6)
-               return RX_MGMT_NONE;
-
-       if (memcmp(wk->bss->cbss.bssid, mgmt->sa, ETH_ALEN) != 0)
-               return RX_MGMT_NONE;
+       /* AssocResp and ReassocResp have identical structure */
 
-       capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info);
-       status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code);
        aid = le16_to_cpu(mgmt->u.assoc_resp.aid);
-
-       printk(KERN_DEBUG "%s: RX %sssocResp from %pM (capab=0x%x "
-              "status=%d aid=%d)\n",
-              sdata->dev->name, reassoc ? "Rea" : "A", mgmt->sa,
-              capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14))));
-
-       pos = mgmt->u.assoc_resp.variable;
-       ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems);
-
-       if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY &&
-           elems.timeout_int && elems.timeout_int_len == 5 &&
-           elems.timeout_int[0] == WLAN_TIMEOUT_ASSOC_COMEBACK) {
-               u32 tu, ms;
-               tu = get_unaligned_le32(elems.timeout_int + 1);
-               ms = tu * 1024 / 1000;
-               printk(KERN_DEBUG "%s: AP rejected association temporarily; "
-                      "comeback duration %u TU (%u ms)\n",
-                      sdata->dev->name, tu, ms);
-               wk->timeout = jiffies + msecs_to_jiffies(ms);
-               if (ms > IEEE80211_ASSOC_TIMEOUT)
-                       run_again(ifmgd, jiffies + msecs_to_jiffies(ms));
-               return RX_MGMT_NONE;
-       }
-
-       if (status_code != WLAN_STATUS_SUCCESS) {
-               printk(KERN_DEBUG "%s: AP denied association (code=%d)\n",
-                      sdata->dev->name, status_code);
-               wk->state = IEEE80211_MGD_STATE_IDLE;
-               return RX_MGMT_CFG80211_ASSOC;
-       }
+       capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info);
 
        if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14)))
                printk(KERN_DEBUG "%s: invalid aid value %d; bits 15:14 not "
-                      "set\n", sdata->dev->name, aid);
+                      "set\n", sdata->name, aid);
        aid &= ~(BIT(15) | BIT(14));
 
+       pos = mgmt->u.assoc_resp.variable;
+       ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems);
+
        if (!elems.supp_rates) {
                printk(KERN_DEBUG "%s: no SuppRates element in AssocResp\n",
-                      sdata->dev->name);
-               return RX_MGMT_NONE;
+                      sdata->name);
+               return false;
        }
 
-       printk(KERN_DEBUG "%s: associated\n", sdata->dev->name);
        ifmgd->aid = aid;
 
-       rcu_read_lock();
-
-       /* Add STA entry for the AP */
-       sta = sta_info_get(local, wk->bss->cbss.bssid);
+       sta = sta_info_alloc(sdata, cbss->bssid, GFP_KERNEL);
        if (!sta) {
-               newsta = true;
-
-               rcu_read_unlock();
-
-               sta = sta_info_alloc(sdata, wk->bss->cbss.bssid, GFP_KERNEL);
-               if (!sta) {
-                       printk(KERN_DEBUG "%s: failed to alloc STA entry for"
-                              " the AP\n", sdata->dev->name);
-                       return RX_MGMT_NONE;
-               }
-
-               set_sta_flags(sta, WLAN_STA_AUTH | WLAN_STA_ASSOC |
-                                  WLAN_STA_ASSOC_AP);
-               if (!(ifmgd->flags & IEEE80211_STA_CONTROL_PORT))
-                       set_sta_flags(sta, WLAN_STA_AUTHORIZED);
-
-               rcu_read_lock();
+               printk(KERN_DEBUG "%s: failed to alloc STA entry for"
+                      " the AP\n", sdata->name);
+               return false;
        }
 
+       set_sta_flags(sta, WLAN_STA_AUTH | WLAN_STA_ASSOC |
+                          WLAN_STA_ASSOC_AP);
+       if (!(ifmgd->flags & IEEE80211_STA_CONTROL_PORT))
+               set_sta_flags(sta, WLAN_STA_AUTHORIZED);
+
        rates = 0;
        basic_rates = 0;
        sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
@@ -1580,40 +1111,40 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
        if (elems.wmm_param)
                set_sta_flags(sta, WLAN_STA_WME);
 
-       if (newsta) {
-               int err = sta_info_insert(sta);
-               if (err) {
-                       printk(KERN_DEBUG "%s: failed to insert STA entry for"
-                              " the AP (error %d)\n", sdata->dev->name, err);
-                       rcu_read_unlock();
-                       return RX_MGMT_NONE;
-               }
+       err = sta_info_insert(sta);
+       sta = NULL;
+       if (err) {
+               printk(KERN_DEBUG "%s: failed to insert STA entry for"
+                      " the AP (error %d)\n", sdata->name, err);
+               return false;
        }
 
-       rcu_read_unlock();
-
        if (elems.wmm_param)
                ieee80211_sta_wmm_params(local, ifmgd, elems.wmm_param,
                                         elems.wmm_param_len);
        else
                ieee80211_set_wmm_default(sdata);
 
+       local->oper_channel = wk->chan;
+
        if (elems.ht_info_elem && elems.wmm_param &&
-           (ifmgd->flags & IEEE80211_STA_WMM_ENABLED) &&
+           (sdata->local->hw.queues >= 4) &&
            !(ifmgd->flags & IEEE80211_STA_DISABLE_11N))
                changed |= ieee80211_enable_ht(sdata, elems.ht_info_elem,
-                                              wk->bss->cbss.bssid,
-                                              ap_ht_cap_flags);
-
-        /* delete work item -- must be before set_associated for PS */
-       list_del(&wk->list);
+                                              cbss->bssid, ap_ht_cap_flags);
 
        /* set AID and assoc capability,
         * ieee80211_set_associated() will tell the driver */
        bss_conf->aid = aid;
        bss_conf->assoc_capability = capab_info;
-       /* this will take ownership of wk */
-       ieee80211_set_associated(sdata, wk, changed);
+       ieee80211_set_associated(sdata, cbss, changed);
+
+       /*
+        * If we're using 4-addr mode, let the AP know that we're
+        * doing so, so that it can create the STA VLAN on its side
+        */
+       if (ifmgd->use_4addr)
+               ieee80211_send_4addr_nullfunc(local, sdata);
 
        /*
         * Start timer to probe the connection to the AP now.
@@ -1622,7 +1153,7 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
        ieee80211_sta_rx_notify(sdata, (struct ieee80211_hdr *)mgmt);
        mod_beacon_timer(sdata);
 
-       return RX_MGMT_CFG80211_ASSOC;
+       return true;
 }
 
 
@@ -1657,7 +1188,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
                return;
 
        if (elems->ch_switch_elem && (elems->ch_switch_elem_len == 3) &&
-           (memcmp(mgmt->bssid, sdata->u.mgd.associated->cbss.bssid,
+           (memcmp(mgmt->bssid, sdata->u.mgd.associated->bssid,
                                                        ETH_ALEN) == 0)) {
                struct ieee80211_channel_sw_ie *sw_elem =
                        (struct ieee80211_channel_sw_ie *)elems->ch_switch_elem;
@@ -1667,19 +1198,19 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
 
 
 static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
-                                        struct ieee80211_mgd_work *wk,
-                                        struct ieee80211_mgmt *mgmt, size_t len,
-                                        struct ieee80211_rx_status *rx_status)
+                                        struct sk_buff *skb)
 {
+       struct ieee80211_mgmt *mgmt = (void *)skb->data;
        struct ieee80211_if_managed *ifmgd;
-       size_t baselen;
+       struct ieee80211_rx_status *rx_status = (void *) skb->cb;
+       size_t baselen, len = skb->len;
        struct ieee802_11_elems elems;
 
        ifmgd = &sdata->u.mgd;
 
        ASSERT_MGD_MTX(ifmgd);
 
-       if (memcmp(mgmt->da, sdata->dev->dev_addr, ETH_ALEN))
+       if (memcmp(mgmt->da, sdata->vif.addr, ETH_ALEN))
                return; /* ignore ProbeResp to foreign address */
 
        baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt;
@@ -1691,17 +1222,8 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
 
        ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, false);
 
-       /* direct probe may be part of the association flow */
-       if (wk && wk->state == IEEE80211_MGD_STATE_PROBE) {
-               printk(KERN_DEBUG "%s: direct probe responded\n",
-                      sdata->dev->name);
-               wk->tries = 0;
-               wk->state = IEEE80211_MGD_STATE_AUTH;
-               WARN_ON(ieee80211_authenticate(sdata, wk) != RX_MGMT_NONE);
-       }
-
        if (ifmgd->associated &&
-           memcmp(mgmt->bssid, ifmgd->associated->cbss.bssid, ETH_ALEN) == 0 &&
+           memcmp(mgmt->bssid, ifmgd->associated->bssid, ETH_ALEN) == 0 &&
            ifmgd->flags & (IEEE80211_STA_BEACON_POLL |
                            IEEE80211_STA_CONNECTION_POLL)) {
                ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL |
@@ -1774,7 +1296,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
        if (!ifmgd->associated)
                return;
 
-       bssid = ifmgd->associated->cbss.bssid;
+       bssid = ifmgd->associated->bssid;
 
        /*
         * And in theory even frames from a different AP we were just
@@ -1787,7 +1309,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
                if (net_ratelimit()) {
                        printk(KERN_DEBUG "%s: cancelling probereq poll due "
-                              "to a received beacon\n", sdata->dev->name);
+                              "to a received beacon\n", sdata->name);
                }
 #endif
                ifmgd->flags &= ~IEEE80211_STA_BEACON_POLL;
@@ -1865,7 +1387,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
 
                rcu_read_lock();
 
-               sta = sta_info_get(local, bssid);
+               sta = sta_info_get(sdata, bssid);
                if (WARN_ON(!sta)) {
                        rcu_read_unlock();
                        return;
@@ -1913,9 +1435,6 @@ ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata,
        switch (fc & IEEE80211_FCTL_STYPE) {
        case IEEE80211_STYPE_PROBE_RESP:
        case IEEE80211_STYPE_BEACON:
-       case IEEE80211_STYPE_AUTH:
-       case IEEE80211_STYPE_ASSOC_RESP:
-       case IEEE80211_STYPE_REASSOC_RESP:
        case IEEE80211_STYPE_DEAUTH:
        case IEEE80211_STYPE_DISASSOC:
        case IEEE80211_STYPE_ACTION:
@@ -1933,7 +1452,6 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        struct ieee80211_rx_status *rx_status;
        struct ieee80211_mgmt *mgmt;
-       struct ieee80211_mgd_work *wk;
        enum rx_mgmt_action rma = RX_MGMT_NONE;
        u16 fc;
 
@@ -1944,20 +1462,17 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
        mutex_lock(&ifmgd->mtx);
 
        if (ifmgd->associated &&
-           memcmp(ifmgd->associated->cbss.bssid, mgmt->bssid,
-                                                       ETH_ALEN) == 0) {
+           memcmp(ifmgd->associated->bssid, mgmt->bssid, ETH_ALEN) == 0) {
                switch (fc & IEEE80211_FCTL_STYPE) {
                case IEEE80211_STYPE_BEACON:
                        ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len,
                                                 rx_status);
                        break;
                case IEEE80211_STYPE_PROBE_RESP:
-                       ieee80211_rx_mgmt_probe_resp(sdata, NULL, mgmt,
-                                                    skb->len, rx_status);
+                       ieee80211_rx_mgmt_probe_resp(sdata, skb);
                        break;
                case IEEE80211_STYPE_DEAUTH:
-                       rma = ieee80211_rx_mgmt_deauth(sdata, NULL,
-                                                      mgmt, skb->len);
+                       rma = ieee80211_rx_mgmt_deauth(sdata, mgmt, skb->len);
                        break;
                case IEEE80211_STYPE_DISASSOC:
                        rma = ieee80211_rx_mgmt_disassoc(sdata, mgmt, skb->len);
@@ -1968,7 +1483,7 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
 
                        ieee80211_sta_process_chanswitch(sdata,
                                        &mgmt->u.action.u.chan_switch.sw_elem,
-                                       ifmgd->associated);
+                                       (void *)ifmgd->associated->priv);
                        break;
                }
                mutex_unlock(&ifmgd->mtx);
@@ -1989,58 +1504,11 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
                goto out;
        }
 
-       list_for_each_entry(wk, &ifmgd->work_list, list) {
-               if (memcmp(wk->bss->cbss.bssid, mgmt->bssid, ETH_ALEN) != 0)
-                       continue;
-
-               switch (fc & IEEE80211_FCTL_STYPE) {
-               case IEEE80211_STYPE_PROBE_RESP:
-                       ieee80211_rx_mgmt_probe_resp(sdata, wk, mgmt, skb->len,
-                                                    rx_status);
-                       break;
-               case IEEE80211_STYPE_AUTH:
-                       rma = ieee80211_rx_mgmt_auth(sdata, wk, mgmt, skb->len);
-                       break;
-               case IEEE80211_STYPE_ASSOC_RESP:
-                       rma = ieee80211_rx_mgmt_assoc_resp(sdata, wk, mgmt,
-                                                          skb->len, false);
-                       break;
-               case IEEE80211_STYPE_REASSOC_RESP:
-                       rma = ieee80211_rx_mgmt_assoc_resp(sdata, wk, mgmt,
-                                                          skb->len, true);
-                       break;
-               case IEEE80211_STYPE_DEAUTH:
-                       rma = ieee80211_rx_mgmt_deauth(sdata, wk, mgmt,
-                                                      skb->len);
-                       break;
-               }
-               /*
-                * We've processed this frame for that work, so it can't
-                * belong to another work struct.
-                * NB: this is also required for correctness because the
-                * called functions can free 'wk', and for 'rma'!
-                */
-               break;
-       }
-
        mutex_unlock(&ifmgd->mtx);
 
-       switch (rma) {
-       case RX_MGMT_NONE:
-               /* no action */
-               break;
-       case RX_MGMT_CFG80211_AUTH:
-               cfg80211_send_rx_auth(sdata->dev, (u8 *) mgmt, skb->len);
-               break;
-       case RX_MGMT_CFG80211_ASSOC:
-               cfg80211_send_rx_assoc(sdata->dev, (u8 *) mgmt, skb->len);
-               break;
-       case RX_MGMT_CFG80211_DEAUTH:
+       if (skb->len >= 24 + 2 /* mgmt + deauth reason */ &&
+           (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_DEAUTH)
                cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len);
-               break;
-       default:
-               WARN(1, "unexpected: %d", rma);
-       }
 
  out:
        kfree_skb(skb);
@@ -2068,12 +1536,8 @@ static void ieee80211_sta_work(struct work_struct *work)
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_if_managed *ifmgd;
        struct sk_buff *skb;
-       struct ieee80211_mgd_work *wk, *tmp;
-       LIST_HEAD(free_work);
-       enum rx_mgmt_action rma;
-       bool anybusy = false;
 
-       if (!netif_running(sdata->dev))
+       if (!ieee80211_sdata_running(sdata))
                return;
 
        if (local->scanning)
@@ -2104,7 +1568,7 @@ static void ieee80211_sta_work(struct work_struct *work)
            ifmgd->associated) {
                u8 bssid[ETH_ALEN];
 
-               memcpy(bssid, ifmgd->associated->cbss.bssid, ETH_ALEN);
+               memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN);
                if (time_is_after_jiffies(ifmgd->probe_timeout))
                        run_again(ifmgd, ifmgd->probe_timeout);
 
@@ -2126,7 +1590,7 @@ static void ieee80211_sta_work(struct work_struct *work)
                        printk(KERN_DEBUG "No probe response from AP %pM"
                                " after %dms, disconnecting.\n",
                                bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ);
-                       ieee80211_set_disassoc(sdata, true);
+                       ieee80211_set_disassoc(sdata);
                        ieee80211_recalc_idle(local);
                        mutex_unlock(&ifmgd->mtx);
                        /*
@@ -2141,87 +1605,7 @@ static void ieee80211_sta_work(struct work_struct *work)
                }
        }
 
-
-       ieee80211_recalc_idle(local);
-
-       list_for_each_entry_safe(wk, tmp, &ifmgd->work_list, list) {
-               if (time_is_after_jiffies(wk->timeout)) {
-                       /*
-                        * This work item isn't supposed to be worked on
-                        * right now, but take care to adjust the timer
-                        * properly.
-                        */
-                       run_again(ifmgd, wk->timeout);
-                       continue;
-               }
-
-               switch (wk->state) {
-               default:
-                       WARN_ON(1);
-                       /* fall through */
-               case IEEE80211_MGD_STATE_IDLE:
-                       /* nothing */
-                       rma = RX_MGMT_NONE;
-                       break;
-               case IEEE80211_MGD_STATE_PROBE:
-                       rma = ieee80211_direct_probe(sdata, wk);
-                       break;
-               case IEEE80211_MGD_STATE_AUTH:
-                       rma = ieee80211_authenticate(sdata, wk);
-                       break;
-               case IEEE80211_MGD_STATE_ASSOC:
-                       rma = ieee80211_associate(sdata, wk);
-                       break;
-               }
-
-               switch (rma) {
-               case RX_MGMT_NONE:
-                       /* no action required */
-                       break;
-               case RX_MGMT_CFG80211_AUTH_TO:
-               case RX_MGMT_CFG80211_ASSOC_TO:
-                       list_del(&wk->list);
-                       list_add(&wk->list, &free_work);
-                       wk->tries = rma; /* small abuse but only local */
-                       break;
-               default:
-                       WARN(1, "unexpected: %d", rma);
-               }
-       }
-
-       list_for_each_entry(wk, &ifmgd->work_list, list) {
-               if (wk->state != IEEE80211_MGD_STATE_IDLE) {
-                       anybusy = true;
-                       break;
-               }
-       }
-       if (!anybusy &&
-           test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request))
-               ieee80211_queue_delayed_work(&local->hw,
-                                            &local->scan_work,
-                                            round_jiffies_relative(0));
-
        mutex_unlock(&ifmgd->mtx);
-
-       list_for_each_entry_safe(wk, tmp, &free_work, list) {
-               switch (wk->tries) {
-               case RX_MGMT_CFG80211_AUTH_TO:
-                       cfg80211_send_auth_timeout(sdata->dev,
-                                                  wk->bss->cbss.bssid);
-                       break;
-               case RX_MGMT_CFG80211_ASSOC_TO:
-                       cfg80211_send_assoc_timeout(sdata->dev,
-                                                   wk->bss->cbss.bssid);
-                       break;
-               default:
-                       WARN(1, "unexpected: %d", wk->tries);
-               }
-
-               list_del(&wk->list);
-               kfree(wk);
-       }
-
-       ieee80211_recalc_idle(local);
 }
 
 static void ieee80211_sta_bcn_mon_timer(unsigned long data)
@@ -2330,14 +1714,14 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
                    (unsigned long) sdata);
        skb_queue_head_init(&ifmgd->skb_queue);
 
-       INIT_LIST_HEAD(&ifmgd->work_list);
-
-       ifmgd->capab = WLAN_CAPABILITY_ESS;
        ifmgd->flags = 0;
-       if (sdata->local->hw.queues >= 4)
-               ifmgd->flags |= IEEE80211_STA_WMM_ENABLED;
 
        mutex_init(&ifmgd->mtx);
+
+       if (sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS)
+               ifmgd->req_smps = IEEE80211_SMPS_AUTOMATIC;
+       else
+               ifmgd->req_smps = IEEE80211_SMPS_OFF;
 }
 
 /* scan finished notification */
@@ -2368,12 +1752,34 @@ int ieee80211_max_network_latency(struct notifier_block *nb,
 }
 
 /* config hooks */
+static enum work_done_result
+ieee80211_probe_auth_done(struct ieee80211_work *wk,
+                         struct sk_buff *skb)
+{
+       if (!skb) {
+               cfg80211_send_auth_timeout(wk->sdata->dev, wk->filter_ta);
+               return WORK_DONE_DESTROY;
+       }
+
+       if (wk->type == IEEE80211_WORK_AUTH) {
+               cfg80211_send_rx_auth(wk->sdata->dev, skb->data, skb->len);
+               return WORK_DONE_DESTROY;
+       }
+
+       mutex_lock(&wk->sdata->u.mgd.mtx);
+       ieee80211_rx_mgmt_probe_resp(wk->sdata, skb);
+       mutex_unlock(&wk->sdata->u.mgd.mtx);
+
+       wk->type = IEEE80211_WORK_AUTH;
+       wk->probe_auth.tries = 0;
+       return WORK_DONE_REQUEUE;
+}
+
 int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
                       struct cfg80211_auth_request *req)
 {
-       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        const u8 *ssid;
-       struct ieee80211_mgd_work *wk;
+       struct ieee80211_work *wk;
        u16 auth_alg;
 
        switch (req->auth_type) {
@@ -2397,7 +1803,7 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
        if (!wk)
                return -ENOMEM;
 
-       wk->bss = (void *)req->bss;
+       memcpy(wk->filter_ta, req->bss->bssid, ETH_ALEN);
 
        if (req->ie && req->ie_len) {
                memcpy(wk->ie, req->ie, req->ie_len);
@@ -2405,66 +1811,76 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
        }
 
        if (req->key && req->key_len) {
-               wk->key_len = req->key_len;
-               wk->key_idx = req->key_idx;
-               memcpy(wk->key, req->key, req->key_len);
+               wk->probe_auth.key_len = req->key_len;
+               wk->probe_auth.key_idx = req->key_idx;
+               memcpy(wk->probe_auth.key, req->key, req->key_len);
        }
 
        ssid = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID);
-       memcpy(wk->ssid, ssid + 2, ssid[1]);
-       wk->ssid_len = ssid[1];
+       memcpy(wk->probe_auth.ssid, ssid + 2, ssid[1]);
+       wk->probe_auth.ssid_len = ssid[1];
 
-       wk->state = IEEE80211_MGD_STATE_PROBE;
-       wk->auth_alg = auth_alg;
-       wk->timeout = jiffies; /* run right away */
+       wk->probe_auth.algorithm = auth_alg;
+       wk->probe_auth.privacy = req->bss->capability & WLAN_CAPABILITY_PRIVACY;
 
-       /*
-        * XXX: if still associated need to tell AP that we're going
-        *      to sleep and then change channel etc.
-        */
-       sdata->local->oper_channel = req->bss->channel;
-       ieee80211_hw_config(sdata->local, 0);
-
-       mutex_lock(&ifmgd->mtx);
-       list_add(&wk->list, &sdata->u.mgd.work_list);
-       mutex_unlock(&ifmgd->mtx);
+       wk->type = IEEE80211_WORK_DIRECT_PROBE;
+       wk->chan = req->bss->channel;
+       wk->sdata = sdata;
+       wk->done = ieee80211_probe_auth_done;
 
-       ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.work);
+       ieee80211_add_work(wk);
        return 0;
 }
 
-int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
-                       struct cfg80211_assoc_request *req)
+static enum work_done_result ieee80211_assoc_done(struct ieee80211_work *wk,
+                                                 struct sk_buff *skb)
 {
-       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
-       struct ieee80211_mgd_work *wk, *found = NULL;
-       int i, err;
+       struct ieee80211_mgmt *mgmt;
+       u16 status;
 
-       mutex_lock(&ifmgd->mtx);
+       if (!skb) {
+               cfg80211_send_assoc_timeout(wk->sdata->dev, wk->filter_ta);
+               return WORK_DONE_DESTROY;
+       }
 
-       list_for_each_entry(wk, &ifmgd->work_list, list) {
-               if (&wk->bss->cbss == req->bss &&
-                   wk->state == IEEE80211_MGD_STATE_IDLE) {
-                       found = wk;
-                       break;
+       mgmt = (void *)skb->data;
+       status = le16_to_cpu(mgmt->u.assoc_resp.status_code);
+
+       if (status == WLAN_STATUS_SUCCESS) {
+               mutex_lock(&wk->sdata->u.mgd.mtx);
+               if (!ieee80211_assoc_success(wk, mgmt, skb->len)) {
+                       mutex_unlock(&wk->sdata->u.mgd.mtx);
+                       /* oops -- internal error -- send timeout for now */
+                       cfg80211_send_assoc_timeout(wk->sdata->dev,
+                                                   wk->filter_ta);
+                       return WORK_DONE_DESTROY;
                }
+               mutex_unlock(&wk->sdata->u.mgd.mtx);
        }
 
-       if (!found) {
-               err = -ENOLINK;
-               goto out;
-       }
+       cfg80211_send_rx_assoc(wk->sdata->dev, skb->data, skb->len);
+       return WORK_DONE_DESTROY;
+}
 
-       list_del(&found->list);
+int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
+                       struct cfg80211_assoc_request *req)
+{
+       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+       struct ieee80211_bss *bss = (void *)req->bss->priv;
+       struct ieee80211_work *wk;
+       const u8 *ssid;
+       int i;
 
-       wk = krealloc(found, sizeof(*wk) + req->ie_len, GFP_KERNEL);
-       if (!wk) {
-               list_add(&found->list, &ifmgd->work_list);
-               err = -ENOMEM;
-               goto out;
+       mutex_lock(&ifmgd->mtx);
+       if (ifmgd->associated) {
+               mutex_unlock(&ifmgd->mtx);
+               return -EALREADY;
        }
+       mutex_unlock(&ifmgd->mtx);
 
-       list_add(&wk->list, &ifmgd->work_list);
+       wk = kzalloc(sizeof(*wk) + req->ie_len, GFP_KERNEL);
+       if (!wk)
+               return -ENOMEM;
 
        ifmgd->flags &= ~IEEE80211_STA_DISABLE_11N;
 
@@ -2474,8 +1890,6 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
                    req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104)
                        ifmgd->flags |= IEEE80211_STA_DISABLE_11N;
 
-       sdata->local->oper_channel = req->bss->channel;
-       ieee80211_hw_config(sdata->local, 0);
 
        if (req->ie && req->ie_len) {
                memcpy(wk->ie, req->ie, req->ie_len);
@@ -2483,12 +1897,55 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
        } else
                wk->ie_len = 0;
 
+       wk->assoc.bss = req->bss;
+
+       memcpy(wk->filter_ta, req->bss->bssid, ETH_ALEN);
+
+       /* new association always uses requested smps mode */
+       if (ifmgd->req_smps == IEEE80211_SMPS_AUTOMATIC) {
+               if (ifmgd->powersave)
+                       ifmgd->ap_smps = IEEE80211_SMPS_DYNAMIC;
+               else
+                       ifmgd->ap_smps = IEEE80211_SMPS_OFF;
+       } else
+               ifmgd->ap_smps = ifmgd->req_smps;
+
+       wk->assoc.smps = ifmgd->ap_smps;
+       /*
+        * IEEE802.11n does not allow TKIP/WEP as pairwise ciphers in HT mode.
+        * We still associate in non-HT mode (11a/b/g) if any one of these
+        * ciphers is configured as pairwise.
+        * We can set this to true for non-11n hardware, that'll be checked
+        * separately along with the peer capabilities.
+        */
+       wk->assoc.use_11n = !(ifmgd->flags & IEEE80211_STA_DISABLE_11N);
+       wk->assoc.capability = req->bss->capability;
+       wk->assoc.wmm_used = bss->wmm_used;
+       wk->assoc.supp_rates = bss->supp_rates;
+       wk->assoc.supp_rates_len = bss->supp_rates_len;
+       wk->assoc.ht_information_ie =
+               ieee80211_bss_get_ie(req->bss, WLAN_EID_HT_INFORMATION);
+
+       if (bss->wmm_used && bss->uapsd_supported &&
+           (sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD)) {
+               wk->assoc.uapsd_used = true;
+               ifmgd->flags |= IEEE80211_STA_UAPSD_ENABLED;
+       } else {
+               wk->assoc.uapsd_used = false;
+               ifmgd->flags &= ~IEEE80211_STA_UAPSD_ENABLED;
+       }
+
+       ssid = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID);
+       memcpy(wk->assoc.ssid, ssid + 2, ssid[1]);
+       wk->assoc.ssid_len = ssid[1];
+
        if (req->prev_bssid)
-               memcpy(wk->prev_bssid, req->prev_bssid, ETH_ALEN);
+               memcpy(wk->assoc.prev_bssid, req->prev_bssid, ETH_ALEN);
 
-       wk->state = IEEE80211_MGD_STATE_ASSOC;
-       wk->tries = 0;
-       wk->timeout = jiffies; /* run right away */
+       wk->type = IEEE80211_WORK_ASSOC;
+       wk->chan = req->bss->channel;
+       wk->sdata = sdata;
+       wk->done = ieee80211_assoc_done;
 
        if (req->use_mfp) {
                ifmgd->mfp = IEEE80211_MFP_REQUIRED;
@@ -2503,69 +1960,59 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
        else
                ifmgd->flags &= ~IEEE80211_STA_CONTROL_PORT;
 
-       ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.work);
-
-       err = 0;
-
- out:
-       mutex_unlock(&ifmgd->mtx);
-       return err;
+       ieee80211_add_work(wk);
+       return 0;
 }
 
 int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
                         struct cfg80211_deauth_request *req,
                         void *cookie)
 {
+       struct ieee80211_local *local = sdata->local;
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
-       struct ieee80211_mgd_work *wk;
-       const u8 *bssid = NULL;
-       bool not_auth_yet = false;
+       struct ieee80211_work *wk;
+       const u8 *bssid = req->bss->bssid;
 
        mutex_lock(&ifmgd->mtx);
 
-       if (ifmgd->associated && &ifmgd->associated->cbss == req->bss) {
+       if (ifmgd->associated == req->bss) {
                bssid = req->bss->bssid;
-               ieee80211_set_disassoc(sdata, true);
-       } else list_for_each_entry(wk, &ifmgd->work_list, list) {
-               if (&wk->bss->cbss == req->bss) {
-                       bssid = req->bss->bssid;
-                       if (wk->state == IEEE80211_MGD_STATE_PROBE)
-                               not_auth_yet = true;
+               ieee80211_set_disassoc(sdata);
+               mutex_unlock(&ifmgd->mtx);
+       } else {
+               bool not_auth_yet = false;
+
+               mutex_unlock(&ifmgd->mtx);
+
+               mutex_lock(&local->work_mtx);
+               list_for_each_entry(wk, &local->work_list, list) {
+                       if (wk->type != IEEE80211_WORK_DIRECT_PROBE)
+                               continue;
+                       if (memcmp(req->bss->bssid, wk->filter_ta, ETH_ALEN))
+                               continue;
+                       not_auth_yet = true;
                        list_del(&wk->list);
-                       kfree(wk);
+                       free_work(wk);
                        break;
                }
-       }
-
-       /*
-        * If somebody requests authentication and we haven't
-        * sent out an auth frame yet there's no need to send
-        * out a deauth frame either. If the state was PROBE,
-        * then this is the case. If it's AUTH we have sent a
-        * frame, and if it's IDLE we have completed the auth
-        * process already.
-        */
-       if (not_auth_yet) {
-               mutex_unlock(&ifmgd->mtx);
-               __cfg80211_auth_canceled(sdata->dev, bssid);
-               return 0;
-       }
+               mutex_unlock(&local->work_mtx);
 
-       /*
-        * cfg80211 should catch this ... but it's racy since
-        * we can receive a deauth frame, process it, hand it
-        * to cfg80211 while that's in a locked section already
-        * trying to tell us that the user wants to disconnect.
-        */
-       if (!bssid) {
-               mutex_unlock(&ifmgd->mtx);
-               return -ENOLINK;
+               /*
+                * If somebody requests authentication and we haven't
+                * sent out an auth frame yet there's no need to send
+                * out a deauth frame either. If the state was PROBE,
+                * then this is the case. If it's AUTH we have sent a
+                * frame, and if it's IDLE we have completed the auth
+                * process already.
+                */
+               if (not_auth_yet) {
+                       __cfg80211_auth_canceled(sdata->dev, bssid);
+                       return 0;
+               }
        }
 
-       mutex_unlock(&ifmgd->mtx);
-
        printk(KERN_DEBUG "%s: deauthenticating from %pM by local choice (reason=%d)\n",
-              sdata->dev->name, bssid, req->reason_code);
+              sdata->name, bssid, req->reason_code);
 
        ieee80211_send_deauth_disassoc(sdata, bssid,
                        IEEE80211_STYPE_DEAUTH, req->reason_code,
@@ -2590,15 +2037,15 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
         * to cfg80211 while that's in a locked section already
         * trying to tell us that the user wants to disconnect.
         */
-       if (&ifmgd->associated->cbss != req->bss) {
+       if (ifmgd->associated != req->bss) {
                mutex_unlock(&ifmgd->mtx);
                return -ENOLINK;
        }
 
        printk(KERN_DEBUG "%s: disassociating from %pM by local choice (reason=%d)\n",
-              sdata->dev->name, req->bss->bssid, req->reason_code);
+              sdata->name, req->bss->bssid, req->reason_code);
 
-       ieee80211_set_disassoc(sdata, false);
+       ieee80211_set_disassoc(sdata);
 
        mutex_unlock(&ifmgd->mtx);
 
diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c
new file mode 100644 (file)
index 0000000..c36b191
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * Off-channel operation helpers
+ *
+ * Copyright 2003, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright 2004, Instant802 Networks, Inc.
+ * Copyright 2005, Devicescape Software, Inc.
+ * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
+ * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
+ * Copyright 2009      Johannes Berg <johannes@sipsolutions.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <net/mac80211.h>
+#include "ieee80211_i.h"
+
+/*
+ * inform AP that we will go to sleep so that it will buffer the frames
+ * while we scan
+ */
+static void ieee80211_offchannel_ps_enable(struct ieee80211_sub_if_data *sdata)
+{
+       struct ieee80211_local *local = sdata->local;
+
+       local->offchannel_ps_enabled = false;
+
+       /* FIXME: what to do when local->pspolling is true? */
+
+       del_timer_sync(&local->dynamic_ps_timer);
+       cancel_work_sync(&local->dynamic_ps_enable_work);
+
+       if (local->hw.conf.flags & IEEE80211_CONF_PS) {
+               local->offchannel_ps_enabled = true;
+               local->hw.conf.flags &= ~IEEE80211_CONF_PS;
+               ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
+       }
+
+       if (!(local->offchannel_ps_enabled) ||
+           !(local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK))
+               /*
+                * If power save was enabled, no need to send a nullfunc
+                * frame because AP knows that we are sleeping. But if the
+                * hardware is creating the nullfunc frame for power save
+                * status (ie. IEEE80211_HW_PS_NULLFUNC_STACK is not
+                * enabled) and power save was enabled, the firmware just
+                * sent a null frame with power save disabled. So we need
+                * to send a new nullfunc frame to inform the AP that we
+                * are again sleeping.
+                */
+               ieee80211_send_nullfunc(local, sdata, 1);
+}
+
+/* inform AP that we are awake again, unless power save is enabled */
+static void ieee80211_offchannel_ps_disable(struct ieee80211_sub_if_data *sdata)
+{
+       struct ieee80211_local *local = sdata->local;
+
+       if (!local->ps_sdata)
+               ieee80211_send_nullfunc(local, sdata, 0);
+       else if (local->offchannel_ps_enabled) {
+               /*
+                * In !IEEE80211_HW_PS_NULLFUNC_STACK case the hardware
+                * will send a nullfunc frame with the powersave bit set
+                * even though the AP already knows that we are sleeping.
+                * This could be avoided by sending a null frame with power
+                * save bit disabled before enabling the power save, but
+                * this doesn't gain anything.
+                *
+                * When IEEE80211_HW_PS_NULLFUNC_STACK is enabled, no need
+                * to send a nullfunc frame because AP already knows that
+                * we are sleeping, let's just enable power save mode in
+                * hardware.
+                */
+               local->hw.conf.flags |= IEEE80211_CONF_PS;
+               ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
+       } else if (local->hw.conf.dynamic_ps_timeout > 0) {
+               /*
+                * If IEEE80211_CONF_PS was not set and the dynamic_ps_timer
+                * had been running before leaving the operating channel,
+                * restart the timer now and send a nullfunc frame to inform
+                * the AP that we are awake.
+                */
+               ieee80211_send_nullfunc(local, sdata, 0);
+               mod_timer(&local->dynamic_ps_timer, jiffies +
+                         msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout));
+       }
+}
+
+void ieee80211_offchannel_stop_beaconing(struct ieee80211_local *local)
+{
+       struct ieee80211_sub_if_data *sdata;
+
+       mutex_lock(&local->iflist_mtx);
+       list_for_each_entry(sdata, &local->interfaces, list) {
+               if (!ieee80211_sdata_running(sdata))
+                       continue;
+
+               /* disable beaconing */
+               if (sdata->vif.type == NL80211_IFTYPE_AP ||
+                   sdata->vif.type == NL80211_IFTYPE_ADHOC ||
+                   sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
+                       ieee80211_bss_info_change_notify(
+                               sdata, BSS_CHANGED_BEACON_ENABLED);
+
+               /*
+                * only handle non-STA interfaces here, STA interfaces
+                * are handled in ieee80211_offchannel_stop_station(),
+                * e.g., from the background scan state machine.
+                *
+                * In addition, do not stop monitor interface to allow it to be
+                * used from user space controlled off-channel operations.
+                */
+               if (sdata->vif.type != NL80211_IFTYPE_STATION &&
+                   sdata->vif.type != NL80211_IFTYPE_MONITOR)
+                       netif_tx_stop_all_queues(sdata->dev);
+       }
+       mutex_unlock(&local->iflist_mtx);
+}
+
+void ieee80211_offchannel_stop_station(struct ieee80211_local *local)
+{
+       struct ieee80211_sub_if_data *sdata;
+
+       /*
+        * notify the AP about us leaving the channel and stop all STA interfaces
+        */
+       mutex_lock(&local->iflist_mtx);
+       list_for_each_entry(sdata, &local->interfaces, list) {
+               if (!ieee80211_sdata_running(sdata))
+                       continue;
+
+               if (sdata->vif.type == NL80211_IFTYPE_STATION) {
+                       netif_tx_stop_all_queues(sdata->dev);
+                       if (sdata->u.mgd.associated)
+                               ieee80211_offchannel_ps_enable(sdata);
+               }
+       }
+       mutex_unlock(&local->iflist_mtx);
+}
+
+void ieee80211_offchannel_return(struct ieee80211_local *local,
+                                bool enable_beaconing)
+{
+       struct ieee80211_sub_if_data *sdata;
+
+       mutex_lock(&local->iflist_mtx);
+       list_for_each_entry(sdata, &local->interfaces, list) {
+               if (!ieee80211_sdata_running(sdata))
+                       continue;
+
+               /* Tell AP we're back */
+               if (sdata->vif.type == NL80211_IFTYPE_STATION) {
+                       if (sdata->u.mgd.associated)
+                               ieee80211_offchannel_ps_disable(sdata);
+               }
+
+               if (sdata->vif.type != NL80211_IFTYPE_MONITOR)
+                       netif_tx_wake_all_queues(sdata->dev);
+
+               /* re-enable beaconing */
+               if (enable_beaconing &&
+                   (sdata->vif.type == NL80211_IFTYPE_AP ||
+                    sdata->vif.type == NL80211_IFTYPE_ADHOC ||
+                    sdata->vif.type == NL80211_IFTYPE_MESH_POINT))
+                       ieee80211_bss_info_change_notify(
+                               sdata, BSS_CHANGED_BEACON_ENABLED);
+       }
+       mutex_unlock(&local->iflist_mtx);
+}
index e535f1c988fe74cd2f5b147977b8904e3d74ee36..47f818959ad7a556ee24d6380fc6da440f6fc830 100644 (file)
@@ -10,7 +10,6 @@ int __ieee80211_suspend(struct ieee80211_hw *hw)
 {
        struct ieee80211_local *local = hw_to_local(hw);
        struct ieee80211_sub_if_data *sdata;
-       struct ieee80211_if_init_conf conf;
        struct sta_info *sta;
        unsigned long flags;
 
@@ -65,7 +64,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw)
                                             struct ieee80211_sub_if_data,
                                             u.ap);
 
-                       drv_sta_notify(local, &sdata->vif, STA_NOTIFY_REMOVE,
+                       drv_sta_notify(local, sdata, STA_NOTIFY_REMOVE,
                                       &sta->sta);
                }
 
@@ -93,17 +92,14 @@ int __ieee80211_suspend(struct ieee80211_hw *hw)
                        break;
                }
 
-               if (!netif_running(sdata->dev))
+               if (!ieee80211_sdata_running(sdata))
                        continue;
 
                /* disable beaconing */
                ieee80211_bss_info_change_notify(sdata,
                        BSS_CHANGED_BEACON_ENABLED);
 
-               conf.vif = &sdata->vif;
-               conf.type = sdata->vif.type;
-               conf.mac_addr = sdata->dev->dev_addr;
-               drv_remove_interface(local, &conf);
+               drv_remove_interface(local, &sdata->vif);
        }
 
        /* stop hardware - this must stop RX */
index b9007f80cb9231bb99bb9a726d3e286ccabfb8ff..c74b7c85403cdaab407b6e8d490e9999c9b267d9 100644 (file)
@@ -207,6 +207,27 @@ static bool rc_no_data_or_no_ack(struct ieee80211_tx_rate_control *txrc)
        return ((info->flags & IEEE80211_TX_CTL_NO_ACK) || !ieee80211_is_data(fc));
 }
 
+static void rc_send_low_broadcast(s8 *idx, u32 basic_rates, u8 max_rate_idx)
+{
+       u8 i;
+
+       if (basic_rates == 0)
+               return; /* assume basic rates unknown and accept rate */
+       if (*idx < 0)
+               return;
+       if (basic_rates & (1 << *idx))
+               return; /* selected rate is a basic rate */
+
+       for (i = *idx + 1; i <= max_rate_idx; i++) {
+               if (basic_rates & (1 << i)) {
+                       *idx = i;
+                       return;
+               }
+       }
+
+       /* could not find a basic rate; use original selection */
+}
+
 bool rate_control_send_low(struct ieee80211_sta *sta,
                           void *priv_sta,
                           struct ieee80211_tx_rate_control *txrc)
@@ -218,12 +239,48 @@ bool rate_control_send_low(struct ieee80211_sta *sta,
                info->control.rates[0].count =
                        (info->flags & IEEE80211_TX_CTL_NO_ACK) ?
                        1 : txrc->hw->max_rate_tries;
+               if (!sta && txrc->ap)
+                       rc_send_low_broadcast(&info->control.rates[0].idx,
+                                             txrc->bss_conf->basic_rates,
+                                             txrc->sband->n_bitrates);
                return true;
        }
        return false;
 }
 EXPORT_SYMBOL(rate_control_send_low);
 
+static void rate_idx_match_mask(struct ieee80211_tx_rate *rate,
+                               int n_bitrates, u32 mask)
+{
+       int j;
+
+       /* See whether the selected rate or anything below it is allowed. */
+       for (j = rate->idx; j >= 0; j--) {
+               if (mask & (1 << j)) {
+                       /* Okay, found a suitable rate. Use it. */
+                       rate->idx = j;
+                       return;
+               }
+       }
+
+       /* Try to find a higher rate that would be allowed */
+       for (j = rate->idx + 1; j < n_bitrates; j++) {
+               if (mask & (1 << j)) {
+                       /* Okay, found a suitable rate. Use it. */
+                       rate->idx = j;
+                       return;
+               }
+       }
+
+       /*
+        * Uh.. No suitable rate exists. This should not really happen with
+        * sane TX rate mask configurations. However, should someone manage to
+        * configure supported rates and TX rate mask in incompatible way,
+        * allow the frame to be transmitted with whatever the rate control
+        * selected.
+        */
+}
+
 void rate_control_get_rate(struct ieee80211_sub_if_data *sdata,
                           struct sta_info *sta,
                           struct ieee80211_tx_rate_control *txrc)
@@ -233,6 +290,7 @@ void rate_control_get_rate(struct ieee80211_sub_if_data *sdata,
        struct ieee80211_sta *ista = NULL;
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(txrc->skb);
        int i;
+       u32 mask;
 
        if (sta) {
                ista = &sta->sta;
@@ -245,23 +303,31 @@ void rate_control_get_rate(struct ieee80211_sub_if_data *sdata,
                info->control.rates[i].count = 1;
        }
 
-       if (sta && sdata->force_unicast_rateidx > -1) {
-               info->control.rates[0].idx = sdata->force_unicast_rateidx;
-       } else {
-               ref->ops->get_rate(ref->priv, ista, priv_sta, txrc);
-               info->flags |= IEEE80211_TX_INTFL_RCALGO;
-       }
+       ref->ops->get_rate(ref->priv, ista, priv_sta, txrc);
 
        /*
-        * try to enforce the maximum rate the user wanted
+        * Try to enforce the rateidx mask the user wanted. skip this if the
+        * default mask (allow all rates) is used to save some processing for
+        * the common case.
         */
-       if (sdata->max_ratectrl_rateidx > -1)
+       mask = sdata->rc_rateidx_mask[info->band];
+       if (mask != (1 << txrc->sband->n_bitrates) - 1) {
+               if (sta) {
+                       /* Filter out rates that the STA does not support */
+                       mask &= sta->sta.supp_rates[info->band];
+               }
+               /*
+                * Make sure the rate index selected for each TX rate is
+                * included in the configured mask and change the rate indexes
+                * if needed.
+                */
                for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
+                       /* Rate masking supports only legacy rates for now */
                        if (info->control.rates[i].flags & IEEE80211_TX_RC_MCS)
                                continue;
-                       info->control.rates[i].idx =
-                               min_t(s8, info->control.rates[i].idx,
-                                     sdata->max_ratectrl_rateidx);
+                       rate_idx_match_mask(&info->control.rates[i],
+                                           txrc->sband->n_bitrates, mask);
+               }
        }
 
        BUG_ON(info->control.rates[0].idx < 0);
index cb9bd1f65e2710bb9931abb3bcc32e5d577d7a39..669dddd405210551a58cabc61d9c1580cf71edac 100644 (file)
@@ -44,10 +44,7 @@ static inline void rate_control_tx_status(struct ieee80211_local *local,
        struct rate_control_ref *ref = local->rate_ctrl;
        struct ieee80211_sta *ista = &sta->sta;
        void *priv_sta = sta->rate_ctrl_priv;
-       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-
-       if (likely(info->flags & IEEE80211_TX_INTFL_RCALGO))
-               ref->ops->tx_status(ref->priv, sband, ista, priv_sta, skb);
+       ref->ops->tx_status(ref->priv, sband, ista, priv_sta, skb);
 }
 
 
index 82a30c1bf3abf6c2874b9aff0088bf250e4a8f64..a8e15b84c05ba7c88cca76a25f4370a95ba9765d 100644 (file)
@@ -283,15 +283,15 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
        skb->protocol = htons(ETH_P_802_2);
 
        list_for_each_entry_rcu(sdata, &local->interfaces, list) {
-               if (!netif_running(sdata->dev))
-                       continue;
-
                if (sdata->vif.type != NL80211_IFTYPE_MONITOR)
                        continue;
 
                if (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES)
                        continue;
 
+               if (!ieee80211_sdata_running(sdata))
+                       continue;
+
                if (prev_dev) {
                        skb2 = skb_clone(skb, GFP_ATOMIC);
                        if (skb2) {
@@ -361,7 +361,9 @@ static void ieee80211_parse_qos(struct ieee80211_rx_data *rx)
  * boundary. In the case of regular frames, this simply means aligning the
  * payload to a four-byte boundary (because either the IP header is directly
  * contained, or IV/RFC1042 headers that have a length divisible by four are
- * in front of it).
+ * in front of it).  If the payload data is not properly aligned and the
+ * architecture doesn't support efficient unaligned operations, mac80211
+ * will align the data.
  *
  * With A-MSDU frames, however, the payload data address must yield two modulo
  * four because there are 14-byte 802.3 headers within the A-MSDU frames that
@@ -375,25 +377,10 @@ static void ieee80211_parse_qos(struct ieee80211_rx_data *rx)
  */
 static void ieee80211_verify_alignment(struct ieee80211_rx_data *rx)
 {
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
-       int hdrlen;
-
-#ifndef CONFIG_MAC80211_DEBUG_PACKET_ALIGNMENT
-       return;
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+       WARN_ONCE((unsigned long)rx->skb->data & 1,
+                 "unaligned packet at 0x%p\n", rx->skb->data);
 #endif
-
-       if (WARN_ONCE((unsigned long)rx->skb->data & 1,
-                     "unaligned packet at 0x%p\n", rx->skb->data))
-               return;
-
-       if (!ieee80211_is_data_present(hdr->frame_control))
-               return;
-
-       hdrlen = ieee80211_hdrlen(hdr->frame_control);
-       if (rx->flags & IEEE80211_RX_AMSDU)
-               hdrlen += ETH_HLEN;
-       WARN_ONCE(((unsigned long)(rx->skb->data + hdrlen)) & 3,
-                 "unaligned IP payload at 0x%p\n", rx->skb->data + hdrlen);
 }
 
 
@@ -476,7 +463,7 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
 {
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
        unsigned int hdrlen = ieee80211_hdrlen(hdr->frame_control);
-       char *dev_addr = rx->sdata->dev->dev_addr;
+       char *dev_addr = rx->sdata->vif.addr;
 
        if (ieee80211_is_data(hdr->frame_control)) {
                if (is_multicast_ether_addr(hdr->addr1)) {
@@ -1021,10 +1008,10 @@ static void ap_sta_ps_start(struct sta_info *sta)
 
        atomic_inc(&sdata->bss->num_sta_ps);
        set_sta_flags(sta, WLAN_STA_PS_STA);
-       drv_sta_notify(local, &sdata->vif, STA_NOTIFY_SLEEP, &sta->sta);
+       drv_sta_notify(local, sdata, STA_NOTIFY_SLEEP, &sta->sta);
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
        printk(KERN_DEBUG "%s: STA %pM aid %d enters power save mode\n",
-              sdata->dev->name, sta->sta.addr, sta->sta.aid);
+              sdata->name, sta->sta.addr, sta->sta.aid);
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
 }
 
@@ -1038,13 +1025,13 @@ static void ap_sta_ps_end(struct sta_info *sta)
 
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
        printk(KERN_DEBUG "%s: STA %pM aid %d exits power save mode\n",
-              sdata->dev->name, sta->sta.addr, sta->sta.aid);
+              sdata->name, sta->sta.addr, sta->sta.aid);
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
 
        if (test_sta_flags(sta, WLAN_STA_PS_DRIVER)) {
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
                printk(KERN_DEBUG "%s: STA %pM aid %d driver-ps-blocked\n",
-                      sdata->dev->name, sta->sta.addr, sta->sta.aid);
+                      sdata->name, sta->sta.addr, sta->sta.aid);
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
                return;
        }
@@ -1124,6 +1111,18 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
        if (ieee80211_is_nullfunc(hdr->frame_control) ||
            ieee80211_is_qos_nullfunc(hdr->frame_control)) {
                I802_DEBUG_INC(rx->local->rx_handlers_drop_nullfunc);
+
+               /*
+                * If we receive a 4-addr nullfunc frame from a STA
+                * that was not moved to a 4-addr STA vlan yet, drop
+                * the frame to the monitor interface, to make sure
+                * that hostapd sees it
+                */
+               if (ieee80211_has_a4(hdr->frame_control) &&
+                   (rx->sdata->vif.type == NL80211_IFTYPE_AP ||
+                    (rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
+                     !rx->sdata->u.vlan.sta)))
+                       return RX_DROP_MONITOR;
                /*
                 * Update counter and free packet here to avoid
                 * counting this as a dropped packed.
@@ -1156,7 +1155,7 @@ ieee80211_reassemble_add(struct ieee80211_sub_if_data *sdata,
                printk(KERN_DEBUG "%s: RX reassembly removed oldest "
                       "fragment entry (idx=%d age=%lu seq=%d last_frag=%d "
                       "addr1=%pM addr2=%pM\n",
-                      sdata->dev->name, idx,
+                      sdata->name, idx,
                       jiffies - entry->first_frag_time, entry->seq,
                       entry->last_frag, hdr->addr1, hdr->addr2);
 #endif
@@ -1424,7 +1423,6 @@ static int
 __ieee80211_data_to_8023(struct ieee80211_rx_data *rx)
 {
        struct ieee80211_sub_if_data *sdata = rx->sdata;
-       struct net_device *dev = sdata->dev;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
 
        if (ieee80211_has_a4(hdr->frame_control) &&
@@ -1436,7 +1434,7 @@ __ieee80211_data_to_8023(struct ieee80211_rx_data *rx)
             (sdata->vif.type == NL80211_IFTYPE_STATION && sdata->u.mgd.use_4addr)))
                return -1;
 
-       return ieee80211_data_to_8023(rx->skb, dev->dev_addr, sdata->vif.type);
+       return ieee80211_data_to_8023(rx->skb, sdata->vif.addr, sdata->vif.type);
 }
 
 /*
@@ -1453,7 +1451,7 @@ static bool ieee80211_frame_allowed(struct ieee80211_rx_data *rx, __le16 fc)
         * of whether the frame was encrypted or not.
         */
        if (ehdr->h_proto == htons(ETH_P_PAE) &&
-           (compare_ether_addr(ehdr->h_dest, rx->sdata->dev->dev_addr) == 0 ||
+           (compare_ether_addr(ehdr->h_dest, rx->sdata->vif.addr) == 0 ||
             compare_ether_addr(ehdr->h_dest, pae_group_addr) == 0))
                return true;
 
@@ -1472,7 +1470,6 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
 {
        struct ieee80211_sub_if_data *sdata = rx->sdata;
        struct net_device *dev = sdata->dev;
-       struct ieee80211_local *local = rx->local;
        struct sk_buff *skb, *xmit_skb;
        struct ethhdr *ehdr = (struct ethhdr *) rx->skb->data;
        struct sta_info *dsta;
@@ -1495,8 +1492,8 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
                                printk(KERN_DEBUG "%s: failed to clone "
                                       "multicast frame\n", dev->name);
                } else {
-                       dsta = sta_info_get(local, skb->data);
-                       if (dsta && dsta->sdata->dev == dev) {
+                       dsta = sta_info_get(sdata, skb->data);
+                       if (dsta) {
                                /*
                                 * The destination station is associated to
                                 * this AP (in this VLAN), so send the frame
@@ -1512,7 +1509,7 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
        if (skb) {
                int align __maybe_unused;
 
-#if defined(CONFIG_MAC80211_DEBUG_PACKET_ALIGNMENT) || !defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
+#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
                /*
                 * 'align' will only take the values 0 or 2 here
                 * since all frames are required to be aligned
@@ -1556,16 +1553,10 @@ static ieee80211_rx_result debug_noinline
 ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)
 {
        struct net_device *dev = rx->sdata->dev;
-       struct ieee80211_local *local = rx->local;
-       u16 ethertype;
-       u8 *payload;
-       struct sk_buff *skb = rx->skb, *frame = NULL;
+       struct sk_buff *skb = rx->skb;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
        __le16 fc = hdr->frame_control;
-       const struct ethhdr *eth;
-       int remaining, err;
-       u8 dst[ETH_ALEN];
-       u8 src[ETH_ALEN];
+       struct sk_buff_head frame_list;
 
        if (unlikely(!ieee80211_is_data(fc)))
                return RX_CONTINUE;
@@ -1576,94 +1567,34 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)
        if (!(rx->flags & IEEE80211_RX_AMSDU))
                return RX_CONTINUE;
 
-       err = __ieee80211_data_to_8023(rx);
-       if (unlikely(err))
+       if (ieee80211_has_a4(hdr->frame_control) &&
+           rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
+           !rx->sdata->u.vlan.sta)
                return RX_DROP_UNUSABLE;
 
-       skb->dev = dev;
-
-       dev->stats.rx_packets++;
-       dev->stats.rx_bytes += skb->len;
-
-       /* skip the wrapping header */
-       eth = (struct ethhdr *) skb_pull(skb, sizeof(struct ethhdr));
-       if (!eth)
+       if (is_multicast_ether_addr(hdr->addr1) &&
+           ((rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
+             rx->sdata->u.vlan.sta) ||
+            (rx->sdata->vif.type == NL80211_IFTYPE_STATION &&
+             rx->sdata->u.mgd.use_4addr)))
                return RX_DROP_UNUSABLE;
 
-       while (skb != frame) {
-               u8 padding;
-               __be16 len = eth->h_proto;
-               unsigned int subframe_len = sizeof(struct ethhdr) + ntohs(len);
-
-               remaining = skb->len;
-               memcpy(dst, eth->h_dest, ETH_ALEN);
-               memcpy(src, eth->h_source, ETH_ALEN);
+       skb->dev = dev;
+       __skb_queue_head_init(&frame_list);
 
-               padding = ((4 - subframe_len) & 0x3);
-               /* the last MSDU has no padding */
-               if (subframe_len > remaining)
-                       return RX_DROP_UNUSABLE;
+       ieee80211_amsdu_to_8023s(skb, &frame_list, dev->dev_addr,
+                                rx->sdata->vif.type,
+                                rx->local->hw.extra_tx_headroom);
 
-               skb_pull(skb, sizeof(struct ethhdr));
-               /* if last subframe reuse skb */
-               if (remaining <= subframe_len + padding)
-                       frame = skb;
-               else {
-                       /*
-                        * Allocate and reserve two bytes more for payload
-                        * alignment since sizeof(struct ethhdr) is 14.
-                        */
-                       frame = dev_alloc_skb(
-                               ALIGN(local->hw.extra_tx_headroom, 4) +
-                               subframe_len + 2);
-
-                       if (frame == NULL)
-                               return RX_DROP_UNUSABLE;
-
-                       skb_reserve(frame,
-                                   ALIGN(local->hw.extra_tx_headroom, 4) +
-                                   sizeof(struct ethhdr) + 2);
-                       memcpy(skb_put(frame, ntohs(len)), skb->data,
-                               ntohs(len));
-
-                       eth = (struct ethhdr *) skb_pull(skb, ntohs(len) +
-                                                       padding);
-                       if (!eth) {
-                               dev_kfree_skb(frame);
-                               return RX_DROP_UNUSABLE;
-                       }
-               }
-
-               skb_reset_network_header(frame);
-               frame->dev = dev;
-               frame->priority = skb->priority;
-               rx->skb = frame;
-
-               payload = frame->data;
-               ethertype = (payload[6] << 8) | payload[7];
-
-               if (likely((compare_ether_addr(payload, rfc1042_header) == 0 &&
-                           ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) ||
-                          compare_ether_addr(payload,
-                                             bridge_tunnel_header) == 0)) {
-                       /* remove RFC1042 or Bridge-Tunnel
-                        * encapsulation and replace EtherType */
-                       skb_pull(frame, 6);
-                       memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN);
-                       memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN);
-               } else {
-                       memcpy(skb_push(frame, sizeof(__be16)),
-                              &len, sizeof(__be16));
-                       memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN);
-                       memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN);
-               }
+       while (!skb_queue_empty(&frame_list)) {
+               rx->skb = __skb_dequeue(&frame_list);
 
                if (!ieee80211_frame_allowed(rx, fc)) {
-                       if (skb == frame) /* last frame */
-                               return RX_DROP_UNUSABLE;
-                       dev_kfree_skb(frame);
+                       dev_kfree_skb(rx->skb);
                        continue;
                }
+               dev->stats.rx_packets++;
+               dev->stats.rx_bytes += rx->skb->len;
 
                ieee80211_deliver_skb(rx);
        }
@@ -1721,7 +1652,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
 
        /* Frame has reached destination.  Don't forward */
        if (!is_multicast_ether_addr(hdr->addr1) &&
-           compare_ether_addr(sdata->dev->dev_addr, hdr->addr3) == 0)
+           compare_ether_addr(sdata->vif.addr, hdr->addr3) == 0)
                return RX_CONTINUE;
 
        mesh_hdr->ttl--;
@@ -1738,10 +1669,10 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
 
                        if (!fwd_skb && net_ratelimit())
                                printk(KERN_DEBUG "%s: failed to clone mesh frame\n",
-                                                  sdata->dev->name);
+                                                  sdata->name);
 
                        fwd_hdr =  (struct ieee80211_hdr *) fwd_skb->data;
-                       memcpy(fwd_hdr->addr2, sdata->dev->dev_addr, ETH_ALEN);
+                       memcpy(fwd_hdr->addr2, sdata->vif.addr, ETH_ALEN);
                        info = IEEE80211_SKB_CB(fwd_skb);
                        memset(info, 0, sizeof(*info));
                        info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
@@ -1872,7 +1803,7 @@ static void ieee80211_process_sa_query_req(struct ieee80211_sub_if_data *sdata,
        struct sk_buff *skb;
        struct ieee80211_mgmt *resp;
 
-       if (compare_ether_addr(mgmt->da, sdata->dev->dev_addr) != 0) {
+       if (compare_ether_addr(mgmt->da, sdata->vif.addr) != 0) {
                /* Not to own unicast address */
                return;
        }
@@ -1896,7 +1827,7 @@ static void ieee80211_process_sa_query_req(struct ieee80211_sub_if_data *sdata,
        resp = (struct ieee80211_mgmt *) skb_put(skb, 24);
        memset(resp, 0, 24);
        memcpy(resp->da, mgmt->sa, ETH_ALEN);
-       memcpy(resp->sa, sdata->dev->dev_addr, ETH_ALEN);
+       memcpy(resp->sa, sdata->vif.addr, ETH_ALEN);
        memcpy(resp->bssid, sdata->u.mgd.bssid, ETH_ALEN);
        resp->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
                                          IEEE80211_STYPE_ACTION);
@@ -2032,6 +1963,7 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx)
 {
        struct ieee80211_sub_if_data *sdata = rx->sdata;
        struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data;
+       ieee80211_rx_result rxs;
 
        if (!(rx->flags & IEEE80211_RX_RA_MATCH))
                return RX_DROP_MONITOR;
@@ -2039,6 +1971,10 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx)
        if (ieee80211_drop_unencrypted(rx, mgmt->frame_control))
                return RX_DROP_MONITOR;
 
+       rxs = ieee80211_work_rx_mgmt(rx->sdata, rx->skb);
+       if (rxs != RX_CONTINUE)
+               return rxs;
+
        if (ieee80211_vif_is_mesh(&sdata->vif))
                return ieee80211_mesh_rx_mgmt(sdata, rx->skb);
 
@@ -2143,7 +2079,7 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx,
        skb->protocol = htons(ETH_P_802_2);
 
        list_for_each_entry_rcu(sdata, &local->interfaces, list) {
-               if (!netif_running(sdata->dev))
+               if (!ieee80211_sdata_running(sdata))
                        continue;
 
                if (sdata->vif.type != NL80211_IFTYPE_MONITOR ||
@@ -2280,7 +2216,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
                if (!bssid && !sdata->u.mgd.use_4addr)
                        return 0;
                if (!multicast &&
-                   compare_ether_addr(sdata->dev->dev_addr, hdr->addr1) != 0) {
+                   compare_ether_addr(sdata->vif.addr, hdr->addr1) != 0) {
                        if (!(sdata->dev->flags & IFF_PROMISC))
                                return 0;
                        rx->flags &= ~IEEE80211_RX_RA_MATCH;
@@ -2297,7 +2233,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
                                return 0;
                        rx->flags &= ~IEEE80211_RX_RA_MATCH;
                } else if (!multicast &&
-                          compare_ether_addr(sdata->dev->dev_addr,
+                          compare_ether_addr(sdata->vif.addr,
                                              hdr->addr1) != 0) {
                        if (!(sdata->dev->flags & IFF_PROMISC))
                                return 0;
@@ -2314,7 +2250,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
                break;
        case NL80211_IFTYPE_MESH_POINT:
                if (!multicast &&
-                   compare_ether_addr(sdata->dev->dev_addr,
+                   compare_ether_addr(sdata->vif.addr,
                                       hdr->addr1) != 0) {
                        if (!(sdata->dev->flags & IFF_PROMISC))
                                return 0;
@@ -2325,11 +2261,11 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
        case NL80211_IFTYPE_AP_VLAN:
        case NL80211_IFTYPE_AP:
                if (!bssid) {
-                       if (compare_ether_addr(sdata->dev->dev_addr,
+                       if (compare_ether_addr(sdata->vif.addr,
                                               hdr->addr1))
                                return 0;
                } else if (!ieee80211_bssid_match(bssid,
-                                       sdata->dev->dev_addr)) {
+                                       sdata->vif.addr)) {
                        if (!(rx->flags & IEEE80211_RX_IN_SCAN))
                                return 0;
                        rx->flags &= ~IEEE80211_RX_RA_MATCH;
@@ -2368,6 +2304,8 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
        int prepares;
        struct ieee80211_sub_if_data *prev = NULL;
        struct sk_buff *skb_new;
+       struct sta_info *sta, *tmp;
+       bool found_sta = false;
 
        hdr = (struct ieee80211_hdr *)skb->data;
        memset(&rx, 0, sizeof(rx));
@@ -2384,68 +2322,76 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
        ieee80211_parse_qos(&rx);
        ieee80211_verify_alignment(&rx);
 
-       rx.sta = sta_info_get(local, hdr->addr2);
-       if (rx.sta)
-               rx.sdata = rx.sta->sdata;
-
-       if (rx.sdata && ieee80211_is_data(hdr->frame_control)) {
-               rx.flags |= IEEE80211_RX_RA_MATCH;
-               prepares = prepare_for_handlers(rx.sdata, &rx, hdr);
-               if (prepares) {
-                       if (status->flag & RX_FLAG_MMIC_ERROR) {
-                               if (rx.flags & IEEE80211_RX_RA_MATCH)
-                                       ieee80211_rx_michael_mic_report(hdr, &rx);
-                       } else
-                               prev = rx.sdata;
+       if (ieee80211_is_data(hdr->frame_control)) {
+               for_each_sta_info(local, hdr->addr2, sta, tmp) {
+                       rx.sta = sta;
+                       found_sta = true;
+                       rx.sdata = sta->sdata;
+
+                       rx.flags |= IEEE80211_RX_RA_MATCH;
+                       prepares = prepare_for_handlers(rx.sdata, &rx, hdr);
+                       if (prepares) {
+                               if (status->flag & RX_FLAG_MMIC_ERROR) {
+                                       if (rx.flags & IEEE80211_RX_RA_MATCH)
+                                               ieee80211_rx_michael_mic_report(hdr, &rx);
+                               } else
+                                       prev = rx.sdata;
+                       }
                }
-       } else list_for_each_entry_rcu(sdata, &local->interfaces, list) {
-               if (!netif_running(sdata->dev))
-                       continue;
+       }
+       if (!found_sta) {
+               list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+                       if (!ieee80211_sdata_running(sdata))
+                               continue;
 
-               if (sdata->vif.type == NL80211_IFTYPE_MONITOR ||
-                   sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
-                       continue;
+                       if (sdata->vif.type == NL80211_IFTYPE_MONITOR ||
+                           sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
+                               continue;
 
-               rx.flags |= IEEE80211_RX_RA_MATCH;
-               prepares = prepare_for_handlers(sdata, &rx, hdr);
+                       rx.sta = sta_info_get(sdata, hdr->addr2);
 
-               if (!prepares)
-                       continue;
+                       rx.flags |= IEEE80211_RX_RA_MATCH;
+                       prepares = prepare_for_handlers(sdata, &rx, hdr);
 
-               if (status->flag & RX_FLAG_MMIC_ERROR) {
-                       rx.sdata = sdata;
-                       if (rx.flags & IEEE80211_RX_RA_MATCH)
-                               ieee80211_rx_michael_mic_report(hdr, &rx);
-                       continue;
-               }
+                       if (!prepares)
+                               continue;
 
-               /*
-                * frame is destined for this interface, but if it's not
-                * also for the previous one we handle that after the
-                * loop to avoid copying the SKB once too much
-                */
+                       if (status->flag & RX_FLAG_MMIC_ERROR) {
+                               rx.sdata = sdata;
+                               if (rx.flags & IEEE80211_RX_RA_MATCH)
+                                       ieee80211_rx_michael_mic_report(hdr,
+                                                                       &rx);
+                               continue;
+                       }
 
-               if (!prev) {
-                       prev = sdata;
-                       continue;
-               }
+                       /*
+                        * frame is destined for this interface, but if it's
+                        * not also for the previous one we handle that after
+                        * the loop to avoid copying the SKB once too much
+                        */
 
-               /*
-                * frame was destined for the previous interface
-                * so invoke RX handlers for it
-                */
+                       if (!prev) {
+                               prev = sdata;
+                               continue;
+                       }
 
-               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->dev->name);
-                       continue;
+                       /*
+                        * frame was destined for the previous interface
+                        * so invoke RX handlers for it
+                        */
+
+                       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);
+                               continue;
+                       }
+                       ieee80211_invoke_rx_handlers(prev, &rx, skb_new, rate);
+                       prev = sdata;
                }
-               ieee80211_invoke_rx_handlers(prev, &rx, skb_new, rate);
-               prev = sdata;
        }
        if (prev)
                ieee80211_invoke_rx_handlers(prev, &rx, skb, rate);
index f934c9620b738a393429fba09ece0a80da912106..9afe2f9885dc93f68582809bcc778c5a9f2b3d25 100644 (file)
@@ -12,7 +12,6 @@
  * published by the Free Software Foundation.
  */
 
-#include <linux/wireless.h>
 #include <linux/if_arp.h>
 #include <linux/rtnetlink.h>
 #include <net/mac80211.h>
@@ -29,16 +28,19 @@ struct ieee80211_bss *
 ieee80211_rx_bss_get(struct ieee80211_local *local, u8 *bssid, int freq,
                     u8 *ssid, u8 ssid_len)
 {
-       return (void *)cfg80211_get_bss(local->hw.wiphy,
-                                       ieee80211_get_channel(local->hw.wiphy,
-                                                             freq),
-                                       bssid, ssid, ssid_len,
-                                       0, 0);
+       struct cfg80211_bss *cbss;
+
+       cbss = cfg80211_get_bss(local->hw.wiphy,
+                               ieee80211_get_channel(local->hw.wiphy, freq),
+                               bssid, ssid, ssid_len, 0, 0);
+       if (!cbss)
+               return NULL;
+       return (void *)cbss->priv;
 }
 
 static void ieee80211_rx_bss_free(struct cfg80211_bss *cbss)
 {
-       struct ieee80211_bss *bss = (void *)cbss;
+       struct ieee80211_bss *bss = (void *)cbss->priv;
 
        kfree(bss_mesh_id(bss));
        kfree(bss_mesh_cfg(bss));
@@ -47,7 +49,26 @@ static void ieee80211_rx_bss_free(struct cfg80211_bss *cbss)
 void ieee80211_rx_bss_put(struct ieee80211_local *local,
                          struct ieee80211_bss *bss)
 {
-       cfg80211_put_bss((struct cfg80211_bss *)bss);
+       if (!bss)
+               return;
+       cfg80211_put_bss(container_of((void *)bss, struct cfg80211_bss, priv));
+}
+
+static bool is_uapsd_supported(struct ieee802_11_elems *elems)
+{
+       u8 qos_info;
+
+       if (elems->wmm_info && elems->wmm_info_len == 7
+           && elems->wmm_info[5] == 1)
+               qos_info = elems->wmm_info[6];
+       else if (elems->wmm_param && elems->wmm_param_len == 24
+                && elems->wmm_param[5] == 1)
+               qos_info = elems->wmm_param[6];
+       else
+               /* no valid wmm information or parameter element found */
+               return false;
+
+       return qos_info & IEEE80211_WMM_IE_AP_QOSINFO_UAPSD;
 }
 
 struct ieee80211_bss *
@@ -59,6 +80,7 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
                          struct ieee80211_channel *channel,
                          bool beacon)
 {
+       struct cfg80211_bss *cbss;
        struct ieee80211_bss *bss;
        int clen;
        s32 signal = 0;
@@ -68,13 +90,14 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
        else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)
                signal = (rx_status->signal * 100) / local->hw.max_signal;
 
-       bss = (void *)cfg80211_inform_bss_frame(local->hw.wiphy, channel,
-                                               mgmt, len, signal, GFP_ATOMIC);
+       cbss = cfg80211_inform_bss_frame(local->hw.wiphy, channel,
+                                        mgmt, len, signal, GFP_ATOMIC);
 
-       if (!bss)
+       if (!cbss)
                return NULL;
 
-       bss->cbss.free_priv = ieee80211_rx_bss_free;
+       cbss->free_priv = ieee80211_rx_bss_free;
+       bss = (void *)cbss->priv;
 
        /* save the ERP value so that it is available at association time */
        if (elems->erp_info && elems->erp_info_len >= 1) {
@@ -111,6 +134,7 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
        }
 
        bss->wmm_used = elems->wmm_param || elems->wmm_info;
+       bss->uapsd_supported = is_uapsd_supported(elems);
 
        if (!beacon)
                bss->last_probe_resp = jiffies;
@@ -147,7 +171,7 @@ ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
        presp = ieee80211_is_probe_resp(fc);
        if (presp) {
                /* ignore ProbeResp to foreign address */
-               if (memcmp(mgmt->da, sdata->dev->dev_addr, ETH_ALEN))
+               if (memcmp(mgmt->da, sdata->vif.addr, ETH_ALEN))
                        return RX_DROP_MONITOR;
 
                presp = true;
@@ -220,82 +244,9 @@ static bool ieee80211_prep_hw_scan(struct ieee80211_local *local)
        return true;
 }
 
-/*
- * inform AP that we will go to sleep so that it will buffer the frames
- * while we scan
- */
-static void ieee80211_scan_ps_enable(struct ieee80211_sub_if_data *sdata)
-{
-       struct ieee80211_local *local = sdata->local;
-
-       local->scan_ps_enabled = false;
-
-       /* FIXME: what to do when local->pspolling is true? */
-
-       del_timer_sync(&local->dynamic_ps_timer);
-       cancel_work_sync(&local->dynamic_ps_enable_work);
-
-       if (local->hw.conf.flags & IEEE80211_CONF_PS) {
-               local->scan_ps_enabled = true;
-               local->hw.conf.flags &= ~IEEE80211_CONF_PS;
-               ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
-       }
-
-       if (!(local->scan_ps_enabled) ||
-           !(local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK))
-               /*
-                * If power save was enabled, no need to send a nullfunc
-                * frame because AP knows that we are sleeping. But if the
-                * hardware is creating the nullfunc frame for power save
-                * status (ie. IEEE80211_HW_PS_NULLFUNC_STACK is not
-                * enabled) and power save was enabled, the firmware just
-                * sent a null frame with power save disabled. So we need
-                * to send a new nullfunc frame to inform the AP that we
-                * are again sleeping.
-                */
-               ieee80211_send_nullfunc(local, sdata, 1);
-}
-
-/* inform AP that we are awake again, unless power save is enabled */
-static void ieee80211_scan_ps_disable(struct ieee80211_sub_if_data *sdata)
-{
-       struct ieee80211_local *local = sdata->local;
-
-       if (!local->ps_sdata)
-               ieee80211_send_nullfunc(local, sdata, 0);
-       else if (local->scan_ps_enabled) {
-               /*
-                * In !IEEE80211_HW_PS_NULLFUNC_STACK case the hardware
-                * will send a nullfunc frame with the powersave bit set
-                * even though the AP already knows that we are sleeping.
-                * This could be avoided by sending a null frame with power
-                * save bit disabled before enabling the power save, but
-                * this doesn't gain anything.
-                *
-                * When IEEE80211_HW_PS_NULLFUNC_STACK is enabled, no need
-                * to send a nullfunc frame because AP already knows that
-                * we are sleeping, let's just enable power save mode in
-                * hardware.
-                */
-               local->hw.conf.flags |= IEEE80211_CONF_PS;
-               ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
-       } else if (local->hw.conf.dynamic_ps_timeout > 0) {
-               /*
-                * If IEEE80211_CONF_PS was not set and the dynamic_ps_timer
-                * had been running before leaving the operating channel,
-                * restart the timer now and send a nullfunc frame to inform
-                * the AP that we are awake.
-                */
-               ieee80211_send_nullfunc(local, sdata, 0);
-               mod_timer(&local->dynamic_ps_timer, jiffies +
-                         msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout));
-       }
-}
-
 void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
 {
        struct ieee80211_local *local = hw_to_local(hw);
-       struct ieee80211_sub_if_data *sdata;
        bool was_hw_scan;
 
        mutex_lock(&local->scan_mtx);
@@ -344,41 +295,19 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
 
        drv_sw_scan_complete(local);
 
-       mutex_lock(&local->iflist_mtx);
-       list_for_each_entry(sdata, &local->interfaces, list) {
-               if (!netif_running(sdata->dev))
-                       continue;
-
-               /* Tell AP we're back */
-               if (sdata->vif.type == NL80211_IFTYPE_STATION) {
-                       if (sdata->u.mgd.associated) {
-                               ieee80211_scan_ps_disable(sdata);
-                               netif_tx_wake_all_queues(sdata->dev);
-                       }
-               } else
-                       netif_tx_wake_all_queues(sdata->dev);
-
-               /* re-enable beaconing */
-               if (sdata->vif.type == NL80211_IFTYPE_AP ||
-                   sdata->vif.type == NL80211_IFTYPE_ADHOC ||
-                   sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
-                       ieee80211_bss_info_change_notify(
-                               sdata, BSS_CHANGED_BEACON_ENABLED);
-       }
-       mutex_unlock(&local->iflist_mtx);
+       ieee80211_offchannel_return(local, true);
 
  done:
        ieee80211_recalc_idle(local);
        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);
 }
 EXPORT_SYMBOL(ieee80211_scan_completed);
 
 static int ieee80211_start_sw_scan(struct ieee80211_local *local)
 {
-       struct ieee80211_sub_if_data *sdata;
-
        /*
         * Hardware/driver doesn't support hw_scan, so use software
         * scanning instead. First send a nullfunc frame with power save
@@ -394,33 +323,15 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local)
         */
        drv_sw_scan_start(local);
 
-       mutex_lock(&local->iflist_mtx);
-       list_for_each_entry(sdata, &local->interfaces, list) {
-               if (!netif_running(sdata->dev))
-                       continue;
-
-               /* disable beaconing */
-               if (sdata->vif.type == NL80211_IFTYPE_AP ||
-                   sdata->vif.type == NL80211_IFTYPE_ADHOC ||
-                   sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
-                       ieee80211_bss_info_change_notify(
-                               sdata, BSS_CHANGED_BEACON_ENABLED);
-
-               /*
-                * only handle non-STA interfaces here, STA interfaces
-                * are handled in the scan state machine
-                */
-               if (sdata->vif.type != NL80211_IFTYPE_STATION)
-                       netif_tx_stop_all_queues(sdata->dev);
-       }
-       mutex_unlock(&local->iflist_mtx);
+       ieee80211_offchannel_stop_beaconing(local);
 
        local->next_scan_state = SCAN_DECISION;
        local->scan_channel_idx = 0;
 
+       drv_flush(local, false);
+
        ieee80211_configure_filter(local);
 
-       /* TODO: start scan as soon as all nullfunc frames are ACKed */
        ieee80211_queue_delayed_work(&local->hw,
                                     &local->scan_work,
                                     IEEE80211_CHANNEL_TIME);
@@ -433,7 +344,6 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
                                  struct cfg80211_scan_request *req)
 {
        struct ieee80211_local *local = sdata->local;
-       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        int rc;
 
        if (local->scan_req)
@@ -463,11 +373,8 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
        local->scan_req = req;
        local->scan_sdata = sdata;
 
-       if (req != local->int_scan_req &&
-           sdata->vif.type == NL80211_IFTYPE_STATION &&
-           !list_empty(&ifmgd->work_list)) {
-               /* actually wait for the work it's doing to finish/time out */
-               set_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request);
+       if (!list_empty(&local->work_list)) {
+               /* wait for the work to finish/time out */
                return 0;
        }
 
@@ -526,7 +433,7 @@ static int ieee80211_scan_state_decision(struct ieee80211_local *local,
        /* check if at least one STA interface is associated */
        mutex_lock(&local->iflist_mtx);
        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) {
@@ -564,56 +471,35 @@ static int ieee80211_scan_state_decision(struct ieee80211_local *local,
 static void ieee80211_scan_state_leave_oper_channel(struct ieee80211_local *local,
                                                    unsigned long *next_delay)
 {
-       struct ieee80211_sub_if_data *sdata;
+       ieee80211_offchannel_stop_station(local);
+
+       __set_bit(SCAN_OFF_CHANNEL, &local->scanning);
 
        /*
-        * notify the AP about us leaving the channel and stop all STA interfaces
+        * What if the nullfunc frames didn't arrive?
         */
-       mutex_lock(&local->iflist_mtx);
-       list_for_each_entry(sdata, &local->interfaces, list) {
-               if (!netif_running(sdata->dev))
-                       continue;
-
-               if (sdata->vif.type == NL80211_IFTYPE_STATION) {
-                       netif_tx_stop_all_queues(sdata->dev);
-                       if (sdata->u.mgd.associated)
-                               ieee80211_scan_ps_enable(sdata);
-               }
-       }
-       mutex_unlock(&local->iflist_mtx);
-
-       __set_bit(SCAN_OFF_CHANNEL, &local->scanning);
+       drv_flush(local, false);
+       if (local->ops->flush)
+               *next_delay = 0;
+       else
+               *next_delay = HZ / 10;
 
        /* advance to the next channel to be scanned */
-       *next_delay = HZ / 10;
        local->next_scan_state = SCAN_SET_CHANNEL;
 }
 
 static void ieee80211_scan_state_enter_oper_channel(struct ieee80211_local *local,
                                                    unsigned long *next_delay)
 {
-       struct ieee80211_sub_if_data *sdata = local->scan_sdata;
-
        /* switch back to the operating channel */
        local->scan_channel = NULL;
        ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
 
        /*
-        * notify the AP about us being back and restart all STA interfaces
+        * Only re-enable station mode interface now; beaconing will be
+        * re-enabled once the full scan has been completed.
         */
-       mutex_lock(&local->iflist_mtx);
-       list_for_each_entry(sdata, &local->interfaces, list) {
-               if (!netif_running(sdata->dev))
-                       continue;
-
-               /* Tell AP we're back */
-               if (sdata->vif.type == NL80211_IFTYPE_STATION) {
-                       if (sdata->u.mgd.associated)
-                               ieee80211_scan_ps_disable(sdata);
-                       netif_tx_wake_all_queues(sdata->dev);
-               }
-       }
-       mutex_unlock(&local->iflist_mtx);
+       ieee80211_offchannel_return(local, false);
 
        __clear_bit(SCAN_OFF_CHANNEL, &local->scanning);
 
@@ -727,7 +613,7 @@ void ieee80211_scan_work(struct work_struct *work)
        /*
         * Avoid re-scheduling when the sdata is going away.
         */
-       if (!netif_running(sdata->dev)) {
+       if (!ieee80211_sdata_running(sdata)) {
                ieee80211_scan_completed(&local->hw, true);
                return;
        }
index aa743a895cf90f4a801758a9f0a4fd090b7ef784..7733f66ee2c411021b2232b70cee1382e51492c7 100644 (file)
@@ -35,7 +35,7 @@ static void ieee80211_send_refuse_measurement_request(struct ieee80211_sub_if_da
 
        if (!skb) {
                printk(KERN_ERR "%s: failed to allocate buffer for "
-                               "measurement report frame\n", sdata->dev->name);
+                               "measurement report frame\n", sdata->name);
                return;
        }
 
@@ -43,7 +43,7 @@ static void ieee80211_send_refuse_measurement_request(struct ieee80211_sub_if_da
        msr_report = (struct ieee80211_mgmt *)skb_put(skb, 24);
        memset(msr_report, 0, 24);
        memcpy(msr_report->da, da, ETH_ALEN);
-       memcpy(msr_report->sa, sdata->dev->dev_addr, ETH_ALEN);
+       memcpy(msr_report->sa, sdata->vif.addr, ETH_ALEN);
        memcpy(msr_report->bssid, bssid, ETH_ALEN);
        msr_report->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
                                                IEEE80211_STYPE_ACTION);
index 71f370dd24bcee545775eb6f9489c0d14b868aee..f735826f055c2bfd3cf2ab2790372c568f917768 100644 (file)
@@ -103,13 +103,37 @@ static int sta_info_hash_del(struct ieee80211_local *local,
 }
 
 /* protected by RCU */
-struct sta_info *sta_info_get(struct ieee80211_local *local, const u8 *addr)
+struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata,
+                             const u8 *addr)
 {
+       struct ieee80211_local *local = sdata->local;
        struct sta_info *sta;
 
        sta = rcu_dereference(local->sta_hash[STA_HASH(addr)]);
        while (sta) {
-               if (memcmp(sta->sta.addr, addr, ETH_ALEN) == 0)
+               if (sta->sdata == sdata &&
+                   memcmp(sta->sta.addr, addr, ETH_ALEN) == 0)
+                       break;
+               sta = rcu_dereference(sta->hnext);
+       }
+       return sta;
+}
+
+/*
+ * Get sta info either from the specified interface
+ * or from one of its vlans
+ */
+struct sta_info *sta_info_get_bss(struct ieee80211_sub_if_data *sdata,
+                                 const u8 *addr)
+{
+       struct ieee80211_local *local = sdata->local;
+       struct sta_info *sta;
+
+       sta = rcu_dereference(local->sta_hash[STA_HASH(addr)]);
+       while (sta) {
+               if ((sta->sdata == sdata ||
+                    sta->sdata->bss == sdata->bss) &&
+                   memcmp(sta->sta.addr, addr, ETH_ALEN) == 0)
                        break;
                sta = rcu_dereference(sta->hnext);
        }
@@ -356,6 +380,7 @@ int sta_info_insert(struct sta_info *sta)
 {
        struct ieee80211_local *local = sta->local;
        struct ieee80211_sub_if_data *sdata = sta->sdata;
+       struct station_info sinfo;
        unsigned long flags;
        int err = 0;
 
@@ -364,12 +389,12 @@ int sta_info_insert(struct sta_info *sta)
         * something inserts a STA (on one CPU) without holding the RTNL
         * and another CPU turns off the net device.
         */
-       if (unlikely(!netif_running(sdata->dev))) {
+       if (unlikely(!ieee80211_sdata_running(sdata))) {
                err = -ENETDOWN;
                goto out_free;
        }
 
-       if (WARN_ON(compare_ether_addr(sta->sta.addr, sdata->dev->dev_addr) == 0 ||
+       if (WARN_ON(compare_ether_addr(sta->sta.addr, sdata->vif.addr) == 0 ||
                    is_multicast_ether_addr(sta->sta.addr))) {
                err = -EINVAL;
                goto out_free;
@@ -377,7 +402,7 @@ int sta_info_insert(struct sta_info *sta)
 
        spin_lock_irqsave(&local->sta_lock, flags);
        /* check if STA exists already */
-       if (sta_info_get(local, sta->sta.addr)) {
+       if (sta_info_get(sdata, sta->sta.addr)) {
                spin_unlock_irqrestore(&local->sta_lock, flags);
                err = -EEXIST;
                goto out_free;
@@ -394,7 +419,7 @@ int sta_info_insert(struct sta_info *sta)
                                             struct ieee80211_sub_if_data,
                                             u.ap);
 
-               drv_sta_notify(local, &sdata->vif, STA_NOTIFY_ADD, &sta->sta);
+               drv_sta_notify(local, sdata, STA_NOTIFY_ADD, &sta->sta);
                sdata = sta->sdata;
        }
 
@@ -405,6 +430,10 @@ int sta_info_insert(struct sta_info *sta)
 
        spin_unlock_irqrestore(&local->sta_lock, flags);
 
+       sinfo.filled = 0;
+       sinfo.generation = local->sta_generation;
+       cfg80211_new_sta(sdata->dev, sta->sta.addr, &sinfo, GFP_ATOMIC);
+
 #ifdef CONFIG_MAC80211_DEBUGFS
        /*
         * Debugfs entry adding might sleep, so schedule process
@@ -534,7 +563,7 @@ static void __sta_info_unlink(struct sta_info **sta)
                                             struct ieee80211_sub_if_data,
                                             u.ap);
 
-               drv_sta_notify(local, &sdata->vif, STA_NOTIFY_REMOVE,
+               drv_sta_notify(local, sdata, STA_NOTIFY_REMOVE,
                               &(*sta)->sta);
                sdata = (*sta)->sdata;
        }
@@ -828,7 +857,7 @@ void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata,
                if (time_after(jiffies, sta->last_rx + exp_time)) {
 #ifdef CONFIG_MAC80211_IBSS_DEBUG
                        printk(KERN_DEBUG "%s: expiring inactive STA %pM\n",
-                              sdata->dev->name, sta->sta.addr);
+                              sdata->name, sta->sta.addr);
 #endif
                        __sta_info_unlink(&sta);
                        if (sta)
@@ -843,11 +872,12 @@ void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata,
 struct ieee80211_sta *ieee80211_find_sta_by_hw(struct ieee80211_hw *hw,
                                               const u8 *addr)
 {
-       struct sta_info *sta = sta_info_get(hw_to_local(hw), addr);
+       struct sta_info *sta, *nxt;
 
-       if (!sta)
-               return NULL;
-       return &sta->sta;
+       /* Just return a random station ... first in list ... */
+       for_each_sta_info(hw_to_local(hw), addr, sta, nxt)
+               return &sta->sta;
+       return NULL;
 }
 EXPORT_SYMBOL_GPL(ieee80211_find_sta_by_hw);
 
@@ -872,7 +902,7 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
        struct ieee80211_local *local = sdata->local;
        int sent, buffered;
 
-       drv_sta_notify(local, &sdata->vif, STA_NOTIFY_AWAKE, &sta->sta);
+       drv_sta_notify(local, sdata, STA_NOTIFY_AWAKE, &sta->sta);
 
        if (!skb_queue_empty(&sta->ps_tx_buf))
                sta_info_clear_tim_bit(sta);
@@ -885,7 +915,7 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
 
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
        printk(KERN_DEBUG "%s: STA %pM aid %d sending %d filtered/%d PS frames "
-              "since STA not sleeping anymore\n", sdata->dev->name,
+              "since STA not sleeping anymore\n", sdata->name,
               sta->sta.addr, sta->sta.aid, sent - buffered, buffered);
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
 }
@@ -944,7 +974,7 @@ void ieee80211_sta_ps_deliver_poll_response(struct sta_info *sta)
                 */
                printk(KERN_DEBUG "%s: STA %pM sent PS Poll even "
                       "though there are no buffered frames for it\n",
-                      sdata->dev->name, sta->sta.addr);
+                      sdata->name, sta->sta.addr);
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
        }
 }
index b4810f6aa94fa0ccfbe90af0e20f71882418701e..6f79bba5706e2bb4d4b13a5ee81aea00e01ae5da 100644 (file)
@@ -403,9 +403,37 @@ static inline u32 get_sta_flags(struct sta_info *sta)
 #define STA_INFO_CLEANUP_INTERVAL (10 * HZ)
 
 /*
- * Get a STA info, must have be under RCU read lock.
+ * Get a STA info, must be under RCU read lock.
  */
-struct sta_info *sta_info_get(struct ieee80211_local *local, const u8 *addr);
+struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata,
+                             const u8 *addr);
+
+struct sta_info *sta_info_get_bss(struct ieee80211_sub_if_data *sdata,
+                                 const u8 *addr);
+
+static inline
+void for_each_sta_info_type_check(struct ieee80211_local *local,
+                                 const u8 *addr,
+                                 struct sta_info *sta,
+                                 struct sta_info *nxt)
+{
+}
+
+#define for_each_sta_info(local, _addr, sta, nxt)                      \
+       for (   /* initialise loop */                                   \
+               sta = rcu_dereference(local->sta_hash[STA_HASH(_addr)]),\
+               nxt = sta ? rcu_dereference(sta->hnext) : NULL;         \
+               /* typecheck */                                         \
+               for_each_sta_info_type_check(local, (_addr), sta, nxt), \
+               /* continue condition */                                \
+               sta;                                                    \
+               /* advance loop */                                      \
+               sta = nxt,                                              \
+               nxt = sta ? rcu_dereference(sta->hnext) : NULL          \
+            )                                                          \
+       /* compare address and run code only if it matches */           \
+       if (memcmp(sta->sta.addr, (_addr), ETH_ALEN) == 0)
+
 /*
  * Get STA info by index, BROKEN!
  */
index d78f36c64c7bf72830303af60c3e2d2a71e7ac55..0ebcdda2420028819c0ed4f90e299d9f28f39f53 100644 (file)
@@ -134,6 +134,40 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
        dev_kfree_skb(skb);
 }
 
+static void ieee80211_frame_acked(struct sta_info *sta, struct sk_buff *skb)
+{
+       struct ieee80211_mgmt *mgmt = (void *) skb->data;
+       struct ieee80211_local *local = sta->local;
+       struct ieee80211_sub_if_data *sdata = sta->sdata;
+
+       if (ieee80211_is_action(mgmt->frame_control) &&
+           sdata->vif.type == NL80211_IFTYPE_STATION &&
+           mgmt->u.action.category == WLAN_CATEGORY_HT &&
+           mgmt->u.action.u.ht_smps.action == WLAN_HT_ACTION_SMPS) {
+               /*
+                * This update looks racy, but isn't -- if we come
+                * here we've definitely got a station that we're
+                * talking to, and on a managed interface that can
+                * only be the AP. And the only other place updating
+                * this variable is before we're associated.
+                */
+               switch (mgmt->u.action.u.ht_smps.smps_control) {
+               case WLAN_HT_SMPS_CONTROL_DYNAMIC:
+                       sta->sdata->u.mgd.ap_smps = IEEE80211_SMPS_DYNAMIC;
+                       break;
+               case WLAN_HT_SMPS_CONTROL_STATIC:
+                       sta->sdata->u.mgd.ap_smps = IEEE80211_SMPS_STATIC;
+                       break;
+               case WLAN_HT_SMPS_CONTROL_DISABLED:
+               default: /* shouldn't happen since we don't send that */
+                       sta->sdata->u.mgd.ap_smps = IEEE80211_SMPS_OFF;
+                       break;
+               }
+
+               ieee80211_queue_work(&local->hw, &local->recalc_smps);
+       }
+}
+
 void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
 {
        struct sk_buff *skb2;
@@ -146,7 +180,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
        struct ieee80211_tx_status_rtap_hdr *rthdr;
        struct ieee80211_sub_if_data *sdata;
        struct net_device *prev_dev = NULL;
-       struct sta_info *sta;
+       struct sta_info *sta, *tmp;
        int retry_count = -1, i;
        bool injected;
 
@@ -166,9 +200,11 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
 
        sband = local->hw.wiphy->bands[info->band];
 
-       sta = sta_info_get(local, hdr->addr1);
+       for_each_sta_info(local, hdr->addr1, sta, tmp) {
+               /* skip wrong virtual interface */
+               if (memcmp(hdr->addr2, sta->sdata->vif.addr, ETH_ALEN))
+                       continue;
 
-       if (sta) {
                if (!(info->flags & IEEE80211_TX_STAT_ACK) &&
                    test_sta_flags(sta, WLAN_STA_PS_STA)) {
                        /*
@@ -208,6 +244,10 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
                rate_control_tx_status(local, sband, sta, skb);
                if (ieee80211_vif_is_mesh(&sta->sdata->vif))
                        ieee80211s_update_metric(local, sta, skb);
+
+               if (!(info->flags & IEEE80211_TX_CTL_INJECTED) &&
+                   (info->flags & IEEE80211_TX_STAT_ACK))
+                       ieee80211_frame_acked(sta, skb);
        }
 
        rcu_read_unlock();
@@ -311,7 +351,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
        rcu_read_lock();
        list_for_each_entry_rcu(sdata, &local->interfaces, list) {
                if (sdata->vif.type == NL80211_IFTYPE_MONITOR) {
-                       if (!netif_running(sdata->dev))
+                       if (!ieee80211_sdata_running(sdata))
                                continue;
 
                        if ((sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) &&
index 4921d724b6c7bad2ed75897d3f75e03c3ef5e659..b73454a507f9cfd2dc89b45bac88352d32c75f2c 100644 (file)
@@ -100,7 +100,7 @@ static void tkip_mixing_phase1(const u8 *tk, struct tkip_ctx *ctx,
                p1k[3] += tkipS(p1k[2] ^ get_unaligned_le16(tk + 12 + j));
                p1k[4] += tkipS(p1k[3] ^ get_unaligned_le16(tk + 0 + j)) + i;
        }
-       ctx->initialized = 1;
+       ctx->state = TKIP_STATE_PHASE1_DONE;
 }
 
 static void tkip_mixing_phase2(const u8 *tk, struct tkip_ctx *ctx,
@@ -183,7 +183,7 @@ void ieee80211_get_tkip_key(struct ieee80211_key_conf *keyconf,
        /* Update the p1k only when the iv16 in the packet wraps around, this
         * might occur after the wrap around of iv16 in the key in case of
         * fragmented packets. */
-       if (iv16 == 0 || !ctx->initialized)
+       if (iv16 == 0 || ctx->state == TKIP_STATE_NOT_INIT)
                tkip_mixing_phase1(tk, ctx, hdr->addr2, iv32);
 
        if (type == IEEE80211_TKIP_P1_KEY) {
@@ -209,7 +209,7 @@ void ieee80211_tkip_encrypt_data(struct crypto_blkcipher *tfm,
        const u8 *tk = &key->conf.key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY];
 
        /* Calculate per-packet key */
-       if (ctx->iv16 == 0 || !ctx->initialized)
+       if (ctx->iv16 == 0 || ctx->state == TKIP_STATE_NOT_INIT)
                tkip_mixing_phase1(tk, ctx, ta, ctx->iv32);
 
        tkip_mixing_phase2(tk, ctx, ctx->iv16, rc4key);
@@ -259,7 +259,7 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
        if ((keyid >> 6) != key->conf.keyidx)
                return TKIP_DECRYPT_INVALID_KEYIDX;
 
-       if (key->u.tkip.rx[queue].initialized &&
+       if (key->u.tkip.rx[queue].state != TKIP_STATE_NOT_INIT &&
            (iv32 < key->u.tkip.rx[queue].iv32 ||
             (iv32 == key->u.tkip.rx[queue].iv32 &&
              iv16 <= key->u.tkip.rx[queue].iv16))) {
@@ -275,11 +275,11 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
 
        if (only_iv) {
                res = TKIP_DECRYPT_OK;
-               key->u.tkip.rx[queue].initialized = 1;
+               key->u.tkip.rx[queue].state = TKIP_STATE_PHASE1_HW_UPLOADED;
                goto done;
        }
 
-       if (!key->u.tkip.rx[queue].initialized ||
+       if (key->u.tkip.rx[queue].state == TKIP_STATE_NOT_INIT ||
            key->u.tkip.rx[queue].iv32 != iv32) {
                /* IV16 wrapped around - perform TKIP phase 1 */
                tkip_mixing_phase1(tk, &key->u.tkip.rx[queue], ta, iv32);
@@ -299,18 +299,20 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
                        printk("\n");
                }
 #endif
-               if (key->local->ops->update_tkip_key &&
-                       key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) {
-                       static const u8 bcast[ETH_ALEN] =
-                               {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
-                       const u8 *sta_addr = key->sta->sta.addr;
-
-                       if (is_multicast_ether_addr(ra))
-                               sta_addr = bcast;
-
-                       drv_update_tkip_key(key->local, &key->conf, sta_addr,
-                                           iv32, key->u.tkip.rx[queue].p1k);
-               }
+       }
+       if (key->local->ops->update_tkip_key &&
+           key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE &&
+           key->u.tkip.rx[queue].state != TKIP_STATE_PHASE1_HW_UPLOADED) {
+               static const u8 bcast[ETH_ALEN] =
+               {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+               const u8 *sta_addr = key->sta->sta.addr;
+
+               if (is_multicast_ether_addr(ra))
+                       sta_addr = bcast;
+
+               drv_update_tkip_key(key->local, &key->conf, sta_addr,
+                               iv32, key->u.tkip.rx[queue].p1k);
+               key->u.tkip.rx[queue].state = TKIP_STATE_PHASE1_HW_UPLOADED;
        }
 
        tkip_mixing_phase2(tk, &key->u.tkip.rx[queue], iv16, rc4key);
index ac210b58670223bdee80d46b8a9792a2a9115d80..daf81048c1f74ab103b55bc1d79fbbc343221d2e 100644 (file)
@@ -180,6 +180,71 @@ static int inline is_ieee80211_device(struct ieee80211_local *local,
 }
 
 /* tx handlers */
+static ieee80211_tx_result debug_noinline
+ieee80211_tx_h_dynamic_ps(struct ieee80211_tx_data *tx)
+{
+       struct ieee80211_local *local = tx->local;
+       struct ieee80211_if_managed *ifmgd;
+
+       /* driver doesn't support power save */
+       if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS))
+               return TX_CONTINUE;
+
+       /* hardware does dynamic power save */
+       if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS)
+               return TX_CONTINUE;
+
+       /* dynamic power save disabled */
+       if (local->hw.conf.dynamic_ps_timeout <= 0)
+               return TX_CONTINUE;
+
+       /* we are scanning, don't enable power save */
+       if (local->scanning)
+               return TX_CONTINUE;
+
+       if (!local->ps_sdata)
+               return TX_CONTINUE;
+
+       /* No point if we're going to suspend */
+       if (local->quiescing)
+               return TX_CONTINUE;
+
+       /* dynamic ps is supported only in managed mode */
+       if (tx->sdata->vif.type != NL80211_IFTYPE_STATION)
+               return TX_CONTINUE;
+
+       ifmgd = &tx->sdata->u.mgd;
+
+       /*
+        * Don't wakeup from power save if u-apsd is enabled, voip ac has
+        * u-apsd enabled and the frame is in voip class. This effectively
+        * means that even if all access categories have u-apsd enabled, in
+        * practise u-apsd is only used with the voip ac. This is a
+        * workaround for the case when received voip class packets do not
+        * have correct qos tag for some reason, due the network or the
+        * peer application.
+        *
+        * Note: local->uapsd_queues access is racy here. If the value is
+        * changed via debugfs, user needs to reassociate manually to have
+        * everything in sync.
+        */
+       if ((ifmgd->flags & IEEE80211_STA_UAPSD_ENABLED)
+           && (local->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO)
+           && skb_get_queue_mapping(tx->skb) == 0)
+               return TX_CONTINUE;
+
+       if (local->hw.conf.flags & IEEE80211_CONF_PS) {
+               ieee80211_stop_queues_by_reason(&local->hw,
+                                               IEEE80211_QUEUE_STOP_REASON_PS);
+               ieee80211_queue_work(&local->hw,
+                                    &local->dynamic_ps_disable_work);
+       }
+
+       mod_timer(&local->dynamic_ps_timer, jiffies +
+                 msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout));
+
+       return TX_CONTINUE;
+}
 
 static ieee80211_tx_result debug_noinline
 ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx)
@@ -223,7 +288,7 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx)
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
                        printk(KERN_DEBUG "%s: dropped data frame to not "
                               "associated station %pM\n",
-                              tx->dev->name, hdr->addr1);
+                              tx->sdata->name, hdr->addr1);
 #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
                        I802_DEBUG_INC(tx->local->tx_handlers_drop_not_assoc);
                        return TX_DROP;
@@ -331,7 +396,7 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx)
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
                if (net_ratelimit())
                        printk(KERN_DEBUG "%s: BC TX buffer full - dropping the oldest frame\n",
-                              tx->dev->name);
+                              tx->sdata->name);
 #endif
                dev_kfree_skb(skb_dequeue(&tx->sdata->bss->ps_bc_buf));
        } else
@@ -391,7 +456,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
                        if (net_ratelimit()) {
                                printk(KERN_DEBUG "%s: STA %pM TX "
                                       "buffer full - dropping oldest frame\n",
-                                      tx->dev->name, sta->sta.addr);
+                                      tx->sdata->name, sta->sta.addr);
                        }
 #endif
                        dev_kfree_skb(old);
@@ -416,7 +481,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
        else if (unlikely(staflags & WLAN_STA_PS_STA)) {
                printk(KERN_DEBUG "%s: STA %pM in PS mode, but pspoll "
-                      "set -> send frame\n", tx->dev->name,
+                      "set -> send frame\n", tx->sdata->name,
                       sta->sta.addr);
        }
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
@@ -519,7 +584,12 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
        txrc.bss_conf = &tx->sdata->vif.bss_conf;
        txrc.skb = tx->skb;
        txrc.reported_rate.idx = -1;
-       txrc.max_rate_idx = tx->sdata->max_ratectrl_rateidx;
+       txrc.rate_idx_mask = tx->sdata->rc_rateidx_mask[tx->channel->band];
+       if (txrc.rate_idx_mask == (1 << sband->n_bitrates) - 1)
+               txrc.max_rate_idx = -1;
+       else
+               txrc.max_rate_idx = fls(txrc.rate_idx_mask) - 1;
+       txrc.ap = tx->sdata->vif.type == NL80211_IFTYPE_AP;
 
        /* set up RTS protection if desired */
        if (len > tx->local->hw.wiphy->rts_threshold) {
@@ -549,7 +619,7 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
                 "%s: Dropped data frame as no usable bitrate found while "
                 "scanning and associated. Target station: "
                 "%pM on %d GHz band\n",
-                tx->dev->name, hdr->addr1,
+                tx->sdata->name, hdr->addr1,
                 tx->channel->band ? 5 : 2))
                return TX_DROP;
 
@@ -1021,7 +1091,6 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
 
        memset(tx, 0, sizeof(*tx));
        tx->skb = skb;
-       tx->dev = sdata->dev; /* use original interface */
        tx->local = local;
        tx->sdata = sdata;
        tx->channel = local->hw.conf.channel;
@@ -1052,10 +1121,13 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
 
        hdr = (struct ieee80211_hdr *) skb->data;
 
-       if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
+       if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
                tx->sta = rcu_dereference(sdata->u.vlan.sta);
+               if (!tx->sta && sdata->dev->ieee80211_ptr->use_4addr)
+                       return TX_DROP;
+       }
        if (!tx->sta)
-               tx->sta = sta_info_get(local, hdr->addr1);
+               tx->sta = sta_info_get(sdata, hdr->addr1);
 
        if (tx->sta && ieee80211_is_data_qos(hdr->frame_control) &&
            (local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION)) {
@@ -1216,6 +1288,7 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx)
                        goto txh_done;  \
        } while (0)
 
+       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_select_key);
@@ -1398,34 +1471,6 @@ static int ieee80211_skb_resize(struct ieee80211_local *local,
        return 0;
 }
 
-static bool need_dynamic_ps(struct ieee80211_local *local)
-{
-       /* driver doesn't support power save */
-       if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS))
-               return false;
-
-       /* hardware does dynamic power save */
-       if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS)
-               return false;
-
-       /* dynamic power save disabled */
-       if (local->hw.conf.dynamic_ps_timeout <= 0)
-               return false;
-
-       /* we are scanning, don't enable power save */
-       if (local->scanning)
-               return false;
-
-       if (!local->ps_sdata)
-               return false;
-
-       /* No point if we're going to suspend */
-       if (local->quiescing)
-               return false;
-
-       return true;
-}
-
 static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
                           struct sk_buff *skb)
 {
@@ -1436,18 +1481,6 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
        int headroom;
        bool may_encrypt;
 
-       if (need_dynamic_ps(local)) {
-               if (local->hw.conf.flags & IEEE80211_CONF_PS) {
-                       ieee80211_stop_queues_by_reason(&local->hw,
-                                       IEEE80211_QUEUE_STOP_REASON_PS);
-                       ieee80211_queue_work(&local->hw,
-                                       &local->dynamic_ps_disable_work);
-               }
-
-               mod_timer(&local->dynamic_ps_timer, jiffies +
-                       msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout));
-       }
-
        rcu_read_lock();
 
        if (unlikely(sdata->vif.type == NL80211_IFTYPE_MONITOR)) {
@@ -1474,11 +1507,11 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
 
                        list_for_each_entry_rcu(tmp_sdata, &local->interfaces,
                                                list) {
-                               if (!netif_running(tmp_sdata->dev))
+                               if (!ieee80211_sdata_running(tmp_sdata))
                                        continue;
                                if (tmp_sdata->vif.type != NL80211_IFTYPE_AP)
                                        continue;
-                               if (compare_ether_addr(tmp_sdata->dev->dev_addr,
+                               if (compare_ether_addr(tmp_sdata->vif.addr,
                                                       hdr->addr2) == 0) {
                                        sdata = tmp_sdata;
                                        break;
@@ -1642,7 +1675,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
                        fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
                        /* RA TA DA SA */
                        memcpy(hdr.addr1, sta->sta.addr, ETH_ALEN);
-                       memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN);
+                       memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN);
                        memcpy(hdr.addr3, skb->data, ETH_ALEN);
                        memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);
                        hdrlen = 30;
@@ -1656,7 +1689,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
                fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS);
                /* DA BSSID SA */
                memcpy(hdr.addr1, skb->data, ETH_ALEN);
-               memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN);
+               memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN);
                memcpy(hdr.addr3, skb->data + ETH_ALEN, ETH_ALEN);
                hdrlen = 24;
                break;
@@ -1664,7 +1697,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
                fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
                /* RA TA DA SA */
                memcpy(hdr.addr1, sdata->u.wds.remote_addr, ETH_ALEN);
-               memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN);
+               memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN);
                memcpy(hdr.addr3, skb->data, ETH_ALEN);
                memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);
                hdrlen = 30;
@@ -1678,8 +1711,8 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
                        goto fail;
                }
 
-               if (compare_ether_addr(dev->dev_addr,
-                                         skb->data + ETH_ALEN) == 0) {
+               if (compare_ether_addr(sdata->vif.addr,
+                                      skb->data + ETH_ALEN) == 0) {
                        hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc,
                                        skb->data, skb->data + ETH_ALEN);
                        meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr,
@@ -1709,7 +1742,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
                                }
                        }
                        hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc,
-                                       mesh_da, dev->dev_addr);
+                                       mesh_da, sdata->vif.addr);
                        rcu_read_unlock();
                        if (is_mesh_mcast)
                                meshhdrlen =
@@ -1734,7 +1767,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
                if (sdata->u.mgd.use_4addr && ethertype != ETH_P_PAE) {
                        fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
                        /* RA TA DA SA */
-                       memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN);
+                       memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN);
                        memcpy(hdr.addr3, skb->data, ETH_ALEN);
                        memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);
                        hdrlen = 30;
@@ -1765,9 +1798,8 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
         */
        if (!is_multicast_ether_addr(hdr.addr1)) {
                rcu_read_lock();
-               sta = sta_info_get(local, hdr.addr1);
-               /* XXX: in the future, use sdata to look up the sta */
-               if (sta && sta->sdata == sdata)
+               sta = sta_info_get(sdata, hdr.addr1);
+               if (sta)
                        sta_flags = get_sta_flags(sta);
                rcu_read_unlock();
        }
@@ -1786,7 +1818,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
                unlikely(!is_multicast_ether_addr(hdr.addr1) &&
                      !(sta_flags & WLAN_STA_AUTHORIZED) &&
                      !(ethertype == ETH_P_PAE &&
-                      compare_ether_addr(dev->dev_addr,
+                      compare_ether_addr(sdata->vif.addr,
                                          skb->data + ETH_ALEN) == 0))) {
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
                if (net_ratelimit())
@@ -1926,7 +1958,7 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local,
                ieee80211_tx(sdata, skb, true);
        } else {
                hdr = (struct ieee80211_hdr *)skb->data;
-               sta = sta_info_get(local, hdr->addr1);
+               sta = sta_info_get(sdata, hdr->addr1);
 
                ret = __ieee80211_tx(local, &skb, sta, true);
                if (ret != IEEE80211_TX_OK)
@@ -2062,6 +2094,7 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
        struct beacon_data *beacon;
        struct ieee80211_supported_band *sband;
        enum ieee80211_band band = local->hw.conf.channel->band;
+       struct ieee80211_tx_rate_control txrc;
 
        sband = local->hw.wiphy->bands[band];
 
@@ -2150,8 +2183,8 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
                mgmt->frame_control =
                    cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON);
                memset(mgmt->da, 0xff, ETH_ALEN);
-               memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
-               memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN);
+               memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
+               memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
                mgmt->u.beacon.beacon_int =
                        cpu_to_le16(sdata->vif.bss_conf.beacon_int);
                mgmt->u.beacon.capab_info = 0x0; /* 0x0 for MPs */
@@ -2169,21 +2202,25 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
        info = IEEE80211_SKB_CB(skb);
 
        info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
+       info->flags |= IEEE80211_TX_CTL_NO_ACK;
        info->band = band;
-       /*
-        * XXX: For now, always use the lowest rate
-        */
-       info->control.rates[0].idx = 0;
-       info->control.rates[0].count = 1;
-       info->control.rates[1].idx = -1;
-       info->control.rates[2].idx = -1;
-       info->control.rates[3].idx = -1;
-       info->control.rates[4].idx = -1;
-       BUILD_BUG_ON(IEEE80211_TX_MAX_RATES != 5);
+
+       memset(&txrc, 0, sizeof(txrc));
+       txrc.hw = hw;
+       txrc.sband = sband;
+       txrc.bss_conf = &sdata->vif.bss_conf;
+       txrc.skb = skb;
+       txrc.reported_rate.idx = -1;
+       txrc.rate_idx_mask = sdata->rc_rateidx_mask[band];
+       if (txrc.rate_idx_mask == (1 << sband->n_bitrates) - 1)
+               txrc.max_rate_idx = -1;
+       else
+               txrc.max_rate_idx = fls(txrc.rate_idx_mask) - 1;
+       txrc.ap = true;
+       rate_control_get_rate(sdata, NULL, &txrc);
 
        info->control.vif = vif;
 
-       info->flags |= IEEE80211_TX_CTL_NO_ACK;
        info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT;
        info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ;
  out:
@@ -2192,6 +2229,134 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
 }
 EXPORT_SYMBOL(ieee80211_beacon_get_tim);
 
+struct sk_buff *ieee80211_pspoll_get(struct ieee80211_hw *hw,
+                                    struct ieee80211_vif *vif)
+{
+       struct ieee80211_sub_if_data *sdata;
+       struct ieee80211_if_managed *ifmgd;
+       struct ieee80211_pspoll *pspoll;
+       struct ieee80211_local *local;
+       struct sk_buff *skb;
+
+       if (WARN_ON(vif->type != NL80211_IFTYPE_STATION))
+               return NULL;
+
+       sdata = vif_to_sdata(vif);
+       ifmgd = &sdata->u.mgd;
+       local = sdata->local;
+
+       skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*pspoll));
+       if (!skb) {
+               printk(KERN_DEBUG "%s: failed to allocate buffer for "
+                      "pspoll template\n", sdata->name);
+               return NULL;
+       }
+       skb_reserve(skb, local->hw.extra_tx_headroom);
+
+       pspoll = (struct ieee80211_pspoll *) skb_put(skb, sizeof(*pspoll));
+       memset(pspoll, 0, sizeof(*pspoll));
+       pspoll->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL |
+                                           IEEE80211_STYPE_PSPOLL);
+       pspoll->aid = cpu_to_le16(ifmgd->aid);
+
+       /* aid in PS-Poll has its two MSBs each set to 1 */
+       pspoll->aid |= cpu_to_le16(1 << 15 | 1 << 14);
+
+       memcpy(pspoll->bssid, ifmgd->bssid, ETH_ALEN);
+       memcpy(pspoll->ta, vif->addr, ETH_ALEN);
+
+       return skb;
+}
+EXPORT_SYMBOL(ieee80211_pspoll_get);
+
+struct sk_buff *ieee80211_nullfunc_get(struct ieee80211_hw *hw,
+                                      struct ieee80211_vif *vif)
+{
+       struct ieee80211_hdr_3addr *nullfunc;
+       struct ieee80211_sub_if_data *sdata;
+       struct ieee80211_if_managed *ifmgd;
+       struct ieee80211_local *local;
+       struct sk_buff *skb;
+
+       if (WARN_ON(vif->type != NL80211_IFTYPE_STATION))
+               return NULL;
+
+       sdata = vif_to_sdata(vif);
+       ifmgd = &sdata->u.mgd;
+       local = sdata->local;
+
+       skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*nullfunc));
+       if (!skb) {
+               printk(KERN_DEBUG "%s: failed to allocate buffer for nullfunc "
+                      "template\n", sdata->name);
+               return NULL;
+       }
+       skb_reserve(skb, local->hw.extra_tx_headroom);
+
+       nullfunc = (struct ieee80211_hdr_3addr *) skb_put(skb,
+                                                         sizeof(*nullfunc));
+       memset(nullfunc, 0, sizeof(*nullfunc));
+       nullfunc->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
+                                             IEEE80211_STYPE_NULLFUNC |
+                                             IEEE80211_FCTL_TODS);
+       memcpy(nullfunc->addr1, ifmgd->bssid, ETH_ALEN);
+       memcpy(nullfunc->addr2, vif->addr, ETH_ALEN);
+       memcpy(nullfunc->addr3, ifmgd->bssid, ETH_ALEN);
+
+       return skb;
+}
+EXPORT_SYMBOL(ieee80211_nullfunc_get);
+
+struct sk_buff *ieee80211_probereq_get(struct ieee80211_hw *hw,
+                                      struct ieee80211_vif *vif,
+                                      const u8 *ssid, size_t ssid_len,
+                                      const u8 *ie, size_t ie_len)
+{
+       struct ieee80211_sub_if_data *sdata;
+       struct ieee80211_local *local;
+       struct ieee80211_hdr_3addr *hdr;
+       struct sk_buff *skb;
+       size_t ie_ssid_len;
+       u8 *pos;
+
+       sdata = vif_to_sdata(vif);
+       local = sdata->local;
+       ie_ssid_len = 2 + ssid_len;
+
+       skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*hdr) +
+                           ie_ssid_len + ie_len);
+       if (!skb) {
+               printk(KERN_DEBUG "%s: failed to allocate buffer for probe "
+                      "request template\n", sdata->name);
+               return NULL;
+       }
+
+       skb_reserve(skb, local->hw.extra_tx_headroom);
+
+       hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
+       memset(hdr, 0, sizeof(*hdr));
+       hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+                                        IEEE80211_STYPE_PROBE_REQ);
+       memset(hdr->addr1, 0xff, ETH_ALEN);
+       memcpy(hdr->addr2, vif->addr, ETH_ALEN);
+       memset(hdr->addr3, 0xff, ETH_ALEN);
+
+       pos = skb_put(skb, ie_ssid_len);
+       *pos++ = WLAN_EID_SSID;
+       *pos++ = ssid_len;
+       if (ssid)
+               memcpy(pos, ssid, ssid_len);
+       pos += ssid_len;
+
+       if (ie) {
+               pos = skb_put(skb, ie_len);
+               memcpy(pos, ie, ie_len);
+       }
+
+       return skb;
+}
+EXPORT_SYMBOL(ieee80211_probereq_get);
+
 void ieee80211_rts_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                       const void *frame, size_t frame_len,
                       const struct ieee80211_tx_info *frame_txctl,
index 3848140313f50dad60759e5fd55a7923fa46f5ff..ca170b417da670ed5d900accfed5d81a09e94588 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/skbuff.h>
 #include <linux/etherdevice.h>
 #include <linux/if_arp.h>
-#include <linux/wireless.h>
 #include <linux/bitmap.h>
 #include <linux/crc32.h>
 #include <net/net_namespace.h>
@@ -480,8 +479,8 @@ void ieee80211_iterate_active_interfaces(
                case NL80211_IFTYPE_MESH_POINT:
                        break;
                }
-               if (netif_running(sdata->dev))
-                       iterator(data, sdata->dev->dev_addr,
+               if (ieee80211_sdata_running(sdata))
+                       iterator(data, sdata->vif.addr,
                                 &sdata->vif);
        }
 
@@ -514,8 +513,8 @@ void ieee80211_iterate_active_interfaces_atomic(
                case NL80211_IFTYPE_MESH_POINT:
                        break;
                }
-               if (netif_running(sdata->dev))
-                       iterator(data, sdata->dev->dev_addr,
+               if (ieee80211_sdata_running(sdata))
+                       iterator(data, sdata->vif.addr,
                                 &sdata->vif);
        }
 
@@ -793,6 +792,8 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata)
                        break;
                }
 
+               qparam.uapsd = false;
+
                drv_conf_tx(local, queue, &qparam);
        }
 }
@@ -860,7 +861,7 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
                            sizeof(*mgmt) + 6 + extra_len);
        if (!skb) {
                printk(KERN_DEBUG "%s: failed to allocate buffer for auth "
-                      "frame\n", sdata->dev->name);
+                      "frame\n", sdata->name);
                return;
        }
        skb_reserve(skb, local->hw.extra_tx_headroom);
@@ -870,7 +871,7 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
        mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
                                          IEEE80211_STYPE_AUTH);
        memcpy(mgmt->da, bssid, ETH_ALEN);
-       memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
+       memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
        memcpy(mgmt->bssid, bssid, ETH_ALEN);
        mgmt->u.auth.auth_alg = cpu_to_le16(auth_alg);
        mgmt->u.auth.auth_transaction = cpu_to_le16(transaction);
@@ -893,43 +894,87 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
                             enum ieee80211_band band)
 {
        struct ieee80211_supported_band *sband;
-       u8 *pos, *supp_rates_len, *esupp_rates_len = NULL;
-       int i;
+       u8 *pos;
+       size_t offset = 0, noffset;
+       int supp_rates_len, i;
 
        sband = local->hw.wiphy->bands[band];
 
        pos = buffer;
 
+       supp_rates_len = min_t(int, sband->n_bitrates, 8);
+
        *pos++ = WLAN_EID_SUPP_RATES;
-       supp_rates_len = pos;
-       *pos++ = 0;
-
-       for (i = 0; i < sband->n_bitrates; i++) {
-               struct ieee80211_rate *rate = &sband->bitrates[i];
-
-               if (esupp_rates_len) {
-                       *esupp_rates_len += 1;
-               } else if (*supp_rates_len == 8) {
-                       *pos++ = WLAN_EID_EXT_SUPP_RATES;
-                       esupp_rates_len = pos;
-                       *pos++ = 1;
-               } else
-                       *supp_rates_len += 1;
+       *pos++ = supp_rates_len;
+
+       for (i = 0; i < supp_rates_len; i++) {
+               int rate = sband->bitrates[i].bitrate;
+               *pos++ = (u8) (rate / 5);
+       }
+
+       /* insert "request information" if in custom IEs */
+       if (ie && ie_len) {
+               static const u8 before_extrates[] = {
+                       WLAN_EID_SSID,
+                       WLAN_EID_SUPP_RATES,
+                       WLAN_EID_REQUEST,
+               };
+               noffset = ieee80211_ie_split(ie, ie_len,
+                                            before_extrates,
+                                            ARRAY_SIZE(before_extrates),
+                                            offset);
+               memcpy(pos, ie + offset, noffset - offset);
+               pos += noffset - offset;
+               offset = noffset;
+       }
+
+       if (sband->n_bitrates > i) {
+               *pos++ = WLAN_EID_EXT_SUPP_RATES;
+               *pos++ = sband->n_bitrates - i;
 
-               *pos++ = rate->bitrate / 5;
+               for (; i < sband->n_bitrates; i++) {
+                       int rate = sband->bitrates[i].bitrate;
+                       *pos++ = (u8) (rate / 5);
+               }
+       }
+
+       /* insert custom IEs that go before HT */
+       if (ie && ie_len) {
+               static const u8 before_ht[] = {
+                       WLAN_EID_SSID,
+                       WLAN_EID_SUPP_RATES,
+                       WLAN_EID_REQUEST,
+                       WLAN_EID_EXT_SUPP_RATES,
+                       WLAN_EID_DS_PARAMS,
+                       WLAN_EID_SUPPORTED_REGULATORY_CLASSES,
+               };
+               noffset = ieee80211_ie_split(ie, ie_len,
+                                            before_ht, ARRAY_SIZE(before_ht),
+                                            offset);
+               memcpy(pos, ie + offset, noffset - offset);
+               pos += noffset - offset;
+               offset = noffset;
        }
 
        if (sband->ht_cap.ht_supported) {
-               __le16 tmp = cpu_to_le16(sband->ht_cap.cap);
+               u16 cap = sband->ht_cap.cap;
+               __le16 tmp;
+
+               if (ieee80211_disable_40mhz_24ghz &&
+                   sband->band == IEEE80211_BAND_2GHZ) {
+                       cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+                       cap &= ~IEEE80211_HT_CAP_SGI_40;
+               }
 
                *pos++ = WLAN_EID_HT_CAPABILITY;
                *pos++ = sizeof(struct ieee80211_ht_cap);
                memset(pos, 0, sizeof(struct ieee80211_ht_cap));
+               tmp = cpu_to_le16(cap);
                memcpy(pos, &tmp, sizeof(u16));
                pos += sizeof(u16);
-               /* TODO: needs a define here for << 2 */
                *pos++ = sband->ht_cap.ampdu_factor |
-                        (sband->ht_cap.ampdu_density << 2);
+                        (sband->ht_cap.ampdu_density <<
+                               IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT);
                memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs));
                pos += sizeof(sband->ht_cap.mcs);
                pos += 2 + 4 + 1; /* ext info, BF cap, antsel */
@@ -940,9 +985,11 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
         * that calculates local->scan_ies_len.
         */
 
-       if (ie) {
-               memcpy(pos, ie, ie_len);
-               pos += ie_len;
+       /* add any remaining custom IEs */
+       if (ie && ie_len) {
+               noffset = ie_len;
+               memcpy(pos, ie + offset, noffset - offset);
+               pos += noffset - offset;
        }
 
        return pos - buffer;
@@ -955,40 +1002,33 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
        struct ieee80211_local *local = sdata->local;
        struct sk_buff *skb;
        struct ieee80211_mgmt *mgmt;
-       u8 *pos;
-
-       skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + 200 +
-                           ie_len);
-       if (!skb) {
-               printk(KERN_DEBUG "%s: failed to allocate buffer for probe "
-                      "request\n", sdata->dev->name);
+       size_t buf_len;
+       u8 *buf;
+
+       /* FIXME: come up with a proper value */
+       buf = kmalloc(200 + ie_len, GFP_KERNEL);
+       if (!buf) {
+               printk(KERN_DEBUG "%s: failed to allocate temporary IE "
+                      "buffer\n", sdata->name);
                return;
        }
-       skb_reserve(skb, local->hw.extra_tx_headroom);
 
-       mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
-       memset(mgmt, 0, 24);
-       mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
-                                         IEEE80211_STYPE_PROBE_REQ);
-       memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
+       buf_len = ieee80211_build_preq_ies(local, buf, ie, ie_len,
+                                          local->hw.conf.channel->band);
+
+       skb = ieee80211_probereq_get(&local->hw, &sdata->vif,
+                                    ssid, ssid_len,
+                                    buf, buf_len);
+
        if (dst) {
+               mgmt = (struct ieee80211_mgmt *) skb->data;
                memcpy(mgmt->da, dst, ETH_ALEN);
                memcpy(mgmt->bssid, dst, ETH_ALEN);
-       } else {
-               memset(mgmt->da, 0xff, ETH_ALEN);
-               memset(mgmt->bssid, 0xff, ETH_ALEN);
        }
-       pos = skb_put(skb, 2 + ssid_len);
-       *pos++ = WLAN_EID_SSID;
-       *pos++ = ssid_len;
-       memcpy(pos, ssid, ssid_len);
-       pos += ssid_len;
-
-       skb_put(skb, ieee80211_build_preq_ies(local, pos, ie, ie_len,
-                                             local->hw.conf.channel->band));
 
        IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
        ieee80211_tx_skb(sdata, skb);
+       kfree(buf);
 }
 
 u32 ieee80211_sta_get_rates(struct ieee80211_local *local,
@@ -1032,16 +1072,15 @@ void ieee80211_stop_device(struct ieee80211_local *local)
        ieee80211_led_radio(local, false);
 
        cancel_work_sync(&local->reconfig_filter);
-       drv_stop(local);
 
        flush_workqueue(local->workqueue);
+       drv_stop(local);
 }
 
 int ieee80211_reconfig(struct ieee80211_local *local)
 {
        struct ieee80211_hw *hw = &local->hw;
        struct ieee80211_sub_if_data *sdata;
-       struct ieee80211_if_init_conf conf;
        struct sta_info *sta;
        unsigned long flags;
        int res;
@@ -1061,7 +1100,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
                if (res) {
                        WARN(local->suspended, "Harware became unavailable "
                             "upon resume. This is could be a software issue"
-                            "prior to suspend or a harware issue\n");
+                            "prior to suspend or a hardware issue\n");
                        return res;
                }
 
@@ -1072,12 +1111,8 @@ int ieee80211_reconfig(struct ieee80211_local *local)
        list_for_each_entry(sdata, &local->interfaces, list) {
                if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
                    sdata->vif.type != NL80211_IFTYPE_MONITOR &&
-                   netif_running(sdata->dev)) {
-                       conf.vif = &sdata->vif;
-                       conf.type = sdata->vif.type;
-                       conf.mac_addr = sdata->dev->dev_addr;
-                       res = drv_add_interface(local, &conf);
-               }
+                   ieee80211_sdata_running(sdata))
+                       res = drv_add_interface(local, &sdata->vif);
        }
 
        /* add STAs back */
@@ -1090,7 +1125,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
                                             struct ieee80211_sub_if_data,
                                             u.ap);
 
-                       drv_sta_notify(local, &sdata->vif, STA_NOTIFY_ADD,
+                       drv_sta_notify(local, sdata, STA_NOTIFY_ADD,
                                       &sta->sta);
                }
                spin_unlock_irqrestore(&local->sta_lock, flags);
@@ -1119,7 +1154,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
        /* Finally also reconfigure all the BSS information */
        list_for_each_entry(sdata, &local->interfaces, list) {
                u32 changed = ~0;
-               if (!netif_running(sdata->dev))
+               if (!ieee80211_sdata_running(sdata))
                        continue;
                switch (sdata->vif.type) {
                case NL80211_IFTYPE_STATION:
@@ -1147,7 +1182,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
 
        /* add back keys */
        list_for_each_entry(sdata, &local->interfaces, list)
-               if (netif_running(sdata->dev))
+               if (ieee80211_sdata_running(sdata))
                        ieee80211_enable_keys(sdata);
 
        ieee80211_wake_queues_by_reason(hw,
@@ -1194,3 +1229,133 @@ int ieee80211_reconfig(struct ieee80211_local *local)
        return 0;
 }
 
+static int check_mgd_smps(struct ieee80211_if_managed *ifmgd,
+                         enum ieee80211_smps_mode *smps_mode)
+{
+       if (ifmgd->associated) {
+               *smps_mode = ifmgd->ap_smps;
+
+               if (*smps_mode == IEEE80211_SMPS_AUTOMATIC) {
+                       if (ifmgd->powersave)
+                               *smps_mode = IEEE80211_SMPS_DYNAMIC;
+                       else
+                               *smps_mode = IEEE80211_SMPS_OFF;
+               }
+
+               return 1;
+       }
+
+       return 0;
+}
+
+/* must hold iflist_mtx */
+void ieee80211_recalc_smps(struct ieee80211_local *local,
+                          struct ieee80211_sub_if_data *forsdata)
+{
+       struct ieee80211_sub_if_data *sdata;
+       enum ieee80211_smps_mode smps_mode = IEEE80211_SMPS_OFF;
+       int count = 0;
+
+       if (forsdata)
+               WARN_ON(!mutex_is_locked(&forsdata->u.mgd.mtx));
+
+       WARN_ON(!mutex_is_locked(&local->iflist_mtx));
+
+       /*
+        * This function could be improved to handle multiple
+        * interfaces better, but right now it makes any
+        * non-station interfaces force SM PS to be turned
+        * off. If there are multiple station interfaces it
+        * could also use the best possible mode, e.g. if
+        * one is in static and the other in dynamic then
+        * dynamic is ok.
+        */
+
+       list_for_each_entry(sdata, &local->interfaces, list) {
+               if (!netif_running(sdata->dev))
+                       continue;
+               if (sdata->vif.type != NL80211_IFTYPE_STATION)
+                       goto set;
+               if (sdata != forsdata) {
+                       /*
+                        * This nested is ok -- we are holding the iflist_mtx
+                        * so can't get here twice or so. But it's required
+                        * since normally we acquire it first and then the
+                        * iflist_mtx.
+                        */
+                       mutex_lock_nested(&sdata->u.mgd.mtx, SINGLE_DEPTH_NESTING);
+                       count += check_mgd_smps(&sdata->u.mgd, &smps_mode);
+                       mutex_unlock(&sdata->u.mgd.mtx);
+               } else
+                       count += check_mgd_smps(&sdata->u.mgd, &smps_mode);
+
+               if (count > 1) {
+                       smps_mode = IEEE80211_SMPS_OFF;
+                       break;
+               }
+       }
+
+       if (smps_mode == local->smps_mode)
+               return;
+
+ set:
+       local->smps_mode = smps_mode;
+       /* changed flag is auto-detected for this */
+       ieee80211_hw_config(local, 0);
+}
+
+static bool ieee80211_id_in_list(const u8 *ids, int n_ids, u8 id)
+{
+       int i;
+
+       for (i = 0; i < n_ids; i++)
+               if (ids[i] == id)
+                       return true;
+       return false;
+}
+
+/**
+ * ieee80211_ie_split - split an IE buffer according to ordering
+ *
+ * @ies: the IE buffer
+ * @ielen: the length of the IE buffer
+ * @ids: an array with element IDs that are allowed before
+ *     the split
+ * @n_ids: the size of the element ID array
+ * @offset: offset where to start splitting in the buffer
+ *
+ * This function splits an IE buffer by updating the @offset
+ * variable to point to the location where the buffer should be
+ * split.
+ *
+ * It assumes that the given IE buffer is well-formed, this
+ * has to be guaranteed by the caller!
+ *
+ * It also assumes that the IEs in the buffer are ordered
+ * correctly, if not the result of using this function will not
+ * be ordered correctly either, i.e. it does no reordering.
+ *
+ * The function returns the offset where the next part of the
+ * buffer starts, which may be @ielen if the entire (remainder)
+ * of the buffer should be used.
+ */
+size_t ieee80211_ie_split(const u8 *ies, size_t ielen,
+                         const u8 *ids, int n_ids, size_t offset)
+{
+       size_t pos = offset;
+
+       while (pos < ielen && ieee80211_id_in_list(ids, n_ids, ies[pos]))
+               pos += 2 + ies[pos + 1];
+
+       return pos;
+}
+
+size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset)
+{
+       size_t pos = offset;
+
+       while (pos < ielen && ies[pos] != WLAN_EID_VENDOR_SPECIFIC)
+               pos += 2 + ies[pos + 1];
+
+       return pos;
+}
index 79d887dae7381b841d6ca8ea25ddf9694e6ba768..34e6d02da779f89731a33261745eea8949d14490 100644 (file)
@@ -96,7 +96,7 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
        }
 
        if (!sta && ra && !is_multicast_ether_addr(ra)) {
-               sta = sta_info_get(local, ra);
+               sta = sta_info_get(sdata, ra);
                if (sta)
                        sta_flags = get_sta_flags(sta);
        }
diff --git a/net/mac80211/work.c b/net/mac80211/work.c
new file mode 100644 (file)
index 0000000..81bd5d5
--- /dev/null
@@ -0,0 +1,1098 @@
+/*
+ * mac80211 work implementation
+ *
+ * Copyright 2003-2008, Jouni Malinen <j@w1.fi>
+ * Copyright 2004, Instant802 Networks, Inc.
+ * Copyright 2005, Devicescape Software, Inc.
+ * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
+ * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
+ * Copyright 2009, Johannes Berg <johannes@sipsolutions.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/delay.h>
+#include <linux/if_ether.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/etherdevice.h>
+#include <linux/crc32.h>
+#include <net/mac80211.h>
+#include <asm/unaligned.h>
+
+#include "ieee80211_i.h"
+#include "rate.h"
+
+#define IEEE80211_AUTH_TIMEOUT (HZ / 5)
+#define IEEE80211_AUTH_MAX_TRIES 3
+#define IEEE80211_ASSOC_TIMEOUT (HZ / 5)
+#define IEEE80211_ASSOC_MAX_TRIES 3
+#define IEEE80211_MAX_PROBE_TRIES 5
+
+enum work_action {
+       WORK_ACT_NONE,
+       WORK_ACT_TIMEOUT,
+       WORK_ACT_DONE,
+};
+
+
+/* utils */
+static inline void ASSERT_WORK_MTX(struct ieee80211_local *local)
+{
+       WARN_ON(!mutex_is_locked(&local->work_mtx));
+}
+
+/*
+ * We can have multiple work items (and connection probing)
+ * scheduling this timer, but we need to take care to only
+ * reschedule it when it should fire _earlier_ than it was
+ * asked for before, or if it's not pending right now. This
+ * function ensures that. Note that it then is required to
+ * run this function for all timeouts after the first one
+ * has happened -- the work that runs from this timer will
+ * do that.
+ */
+static void run_again(struct ieee80211_local *local,
+                     unsigned long timeout)
+{
+       ASSERT_WORK_MTX(local);
+
+       if (!timer_pending(&local->work_timer) ||
+           time_before(timeout, local->work_timer.expires))
+               mod_timer(&local->work_timer, timeout);
+}
+
+static void work_free_rcu(struct rcu_head *head)
+{
+       struct ieee80211_work *wk =
+               container_of(head, struct ieee80211_work, rcu_head);
+
+       kfree(wk);
+}
+
+void free_work(struct ieee80211_work *wk)
+{
+       call_rcu(&wk->rcu_head, work_free_rcu);
+}
+
+static int ieee80211_compatible_rates(const u8 *supp_rates, int supp_rates_len,
+                                     struct ieee80211_supported_band *sband,
+                                     u32 *rates)
+{
+       int i, j, count;
+       *rates = 0;
+       count = 0;
+       for (i = 0; i < supp_rates_len; i++) {
+               int rate = (supp_rates[i] & 0x7F) * 5;
+
+               for (j = 0; j < sband->n_bitrates; j++)
+                       if (sband->bitrates[j].bitrate == rate) {
+                               *rates |= BIT(j);
+                               count++;
+                               break;
+                       }
+       }
+
+       return count;
+}
+
+/* frame sending functions */
+
+static void ieee80211_add_ht_ie(struct sk_buff *skb, const u8 *ht_info_ie,
+                               struct ieee80211_supported_band *sband,
+                               struct ieee80211_channel *channel,
+                               enum ieee80211_smps_mode smps)
+{
+       struct ieee80211_ht_info *ht_info;
+       u8 *pos;
+       u32 flags = channel->flags;
+       u16 cap = sband->ht_cap.cap;
+       __le16 tmp;
+
+       if (!sband->ht_cap.ht_supported)
+               return;
+
+       if (!ht_info_ie)
+               return;
+
+       if (ht_info_ie[1] < sizeof(struct ieee80211_ht_info))
+               return;
+
+       ht_info = (struct ieee80211_ht_info *)(ht_info_ie + 2);
+
+       /* determine capability flags */
+
+       if (ieee80211_disable_40mhz_24ghz &&
+           sband->band == IEEE80211_BAND_2GHZ) {
+               cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+               cap &= ~IEEE80211_HT_CAP_SGI_40;
+       }
+
+       switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
+       case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
+               if (flags & IEEE80211_CHAN_NO_HT40PLUS) {
+                       cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+                       cap &= ~IEEE80211_HT_CAP_SGI_40;
+               }
+               break;
+       case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
+               if (flags & IEEE80211_CHAN_NO_HT40MINUS) {
+                       cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+                       cap &= ~IEEE80211_HT_CAP_SGI_40;
+               }
+               break;
+       }
+
+       /* set SM PS mode properly */
+       cap &= ~IEEE80211_HT_CAP_SM_PS;
+       switch (smps) {
+       case IEEE80211_SMPS_AUTOMATIC:
+       case IEEE80211_SMPS_NUM_MODES:
+               WARN_ON(1);
+       case IEEE80211_SMPS_OFF:
+               cap |= WLAN_HT_CAP_SM_PS_DISABLED <<
+                       IEEE80211_HT_CAP_SM_PS_SHIFT;
+               break;
+       case IEEE80211_SMPS_STATIC:
+               cap |= WLAN_HT_CAP_SM_PS_STATIC <<
+                       IEEE80211_HT_CAP_SM_PS_SHIFT;
+               break;
+       case IEEE80211_SMPS_DYNAMIC:
+               cap |= WLAN_HT_CAP_SM_PS_DYNAMIC <<
+                       IEEE80211_HT_CAP_SM_PS_SHIFT;
+               break;
+       }
+
+       /* reserve and fill IE */
+
+       pos = skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2);
+       *pos++ = WLAN_EID_HT_CAPABILITY;
+       *pos++ = sizeof(struct ieee80211_ht_cap);
+       memset(pos, 0, sizeof(struct ieee80211_ht_cap));
+
+       /* capability flags */
+       tmp = cpu_to_le16(cap);
+       memcpy(pos, &tmp, sizeof(u16));
+       pos += sizeof(u16);
+
+       /* AMPDU parameters */
+       *pos++ = sband->ht_cap.ampdu_factor |
+                (sband->ht_cap.ampdu_density <<
+                       IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT);
+
+       /* MCS set */
+       memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs));
+       pos += sizeof(sband->ht_cap.mcs);
+
+       /* extended capabilities */
+       pos += sizeof(__le16);
+
+       /* BF capabilities */
+       pos += sizeof(__le32);
+
+       /* antenna selection */
+       pos += sizeof(u8);
+}
+
+static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
+                                struct ieee80211_work *wk)
+{
+       struct ieee80211_local *local = sdata->local;
+       struct sk_buff *skb;
+       struct ieee80211_mgmt *mgmt;
+       u8 *pos, qos_info;
+       const u8 *ies;
+       size_t offset = 0, noffset;
+       int i, len, count, rates_len, supp_rates_len;
+       u16 capab;
+       struct ieee80211_supported_band *sband;
+       u32 rates = 0;
+
+       sband = local->hw.wiphy->bands[wk->chan->band];
+
+       /*
+        * Get all rates supported by the device and the AP as
+        * some APs don't like getting a superset of their rates
+        * in the association request (e.g. D-Link DAP 1353 in
+        * b-only mode)...
+        */
+       rates_len = ieee80211_compatible_rates(wk->assoc.supp_rates,
+                                              wk->assoc.supp_rates_len,
+                                              sband, &rates);
+
+       skb = alloc_skb(local->hw.extra_tx_headroom +
+                       sizeof(*mgmt) + /* bit too much but doesn't matter */
+                       2 + wk->assoc.ssid_len + /* SSID */
+                       4 + rates_len + /* (extended) rates */
+                       4 + /* power capability */
+                       2 + 2 * sband->n_channels + /* supported channels */
+                       2 + sizeof(struct ieee80211_ht_cap) + /* HT */
+                       wk->ie_len + /* extra IEs */
+                       9, /* WMM */
+                       GFP_KERNEL);
+       if (!skb) {
+               printk(KERN_DEBUG "%s: failed to allocate buffer for assoc "
+                      "frame\n", sdata->name);
+               return;
+       }
+       skb_reserve(skb, local->hw.extra_tx_headroom);
+
+       capab = WLAN_CAPABILITY_ESS;
+
+       if (sband->band == IEEE80211_BAND_2GHZ) {
+               if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE))
+                       capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME;
+               if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE))
+                       capab |= WLAN_CAPABILITY_SHORT_PREAMBLE;
+       }
+
+       if (wk->assoc.capability & WLAN_CAPABILITY_PRIVACY)
+               capab |= WLAN_CAPABILITY_PRIVACY;
+
+       if ((wk->assoc.capability & WLAN_CAPABILITY_SPECTRUM_MGMT) &&
+           (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT))
+               capab |= WLAN_CAPABILITY_SPECTRUM_MGMT;
+
+       mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
+       memset(mgmt, 0, 24);
+       memcpy(mgmt->da, wk->filter_ta, ETH_ALEN);
+       memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
+       memcpy(mgmt->bssid, wk->filter_ta, ETH_ALEN);
+
+       if (!is_zero_ether_addr(wk->assoc.prev_bssid)) {
+               skb_put(skb, 10);
+               mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+                                                 IEEE80211_STYPE_REASSOC_REQ);
+               mgmt->u.reassoc_req.capab_info = cpu_to_le16(capab);
+               mgmt->u.reassoc_req.listen_interval =
+                               cpu_to_le16(local->hw.conf.listen_interval);
+               memcpy(mgmt->u.reassoc_req.current_ap, wk->assoc.prev_bssid,
+                      ETH_ALEN);
+       } else {
+               skb_put(skb, 4);
+               mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+                                                 IEEE80211_STYPE_ASSOC_REQ);
+               mgmt->u.assoc_req.capab_info = cpu_to_le16(capab);
+               mgmt->u.assoc_req.listen_interval =
+                               cpu_to_le16(local->hw.conf.listen_interval);
+       }
+
+       /* SSID */
+       ies = pos = skb_put(skb, 2 + wk->assoc.ssid_len);
+       *pos++ = WLAN_EID_SSID;
+       *pos++ = wk->assoc.ssid_len;
+       memcpy(pos, wk->assoc.ssid, wk->assoc.ssid_len);
+
+       /* add all rates which were marked to be used above */
+       supp_rates_len = rates_len;
+       if (supp_rates_len > 8)
+               supp_rates_len = 8;
+
+       len = sband->n_bitrates;
+       pos = skb_put(skb, supp_rates_len + 2);
+       *pos++ = WLAN_EID_SUPP_RATES;
+       *pos++ = supp_rates_len;
+
+       count = 0;
+       for (i = 0; i < sband->n_bitrates; i++) {
+               if (BIT(i) & rates) {
+                       int rate = sband->bitrates[i].bitrate;
+                       *pos++ = (u8) (rate / 5);
+                       if (++count == 8)
+                               break;
+               }
+       }
+
+       if (rates_len > count) {
+               pos = skb_put(skb, rates_len - count + 2);
+               *pos++ = WLAN_EID_EXT_SUPP_RATES;
+               *pos++ = rates_len - count;
+
+               for (i++; i < sband->n_bitrates; i++) {
+                       if (BIT(i) & rates) {
+                               int rate = sband->bitrates[i].bitrate;
+                               *pos++ = (u8) (rate / 5);
+                       }
+               }
+       }
+
+       if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT) {
+               /* 1. power capabilities */
+               pos = skb_put(skb, 4);
+               *pos++ = WLAN_EID_PWR_CAPABILITY;
+               *pos++ = 2;
+               *pos++ = 0; /* min tx power */
+               *pos++ = wk->chan->max_power; /* max tx power */
+
+               /* 2. supported channels */
+               /* TODO: get this in reg domain format */
+               pos = skb_put(skb, 2 * sband->n_channels + 2);
+               *pos++ = WLAN_EID_SUPPORTED_CHANNELS;
+               *pos++ = 2 * sband->n_channels;
+               for (i = 0; i < sband->n_channels; i++) {
+                       *pos++ = ieee80211_frequency_to_channel(
+                                       sband->channels[i].center_freq);
+                       *pos++ = 1; /* one channel in the subband*/
+               }
+       }
+
+       /* if present, add any custom IEs that go before HT */
+       if (wk->ie_len && wk->ie) {
+               static const u8 before_ht[] = {
+                       WLAN_EID_SSID,
+                       WLAN_EID_SUPP_RATES,
+                       WLAN_EID_EXT_SUPP_RATES,
+                       WLAN_EID_PWR_CAPABILITY,
+                       WLAN_EID_SUPPORTED_CHANNELS,
+                       WLAN_EID_RSN,
+                       WLAN_EID_QOS_CAPA,
+                       WLAN_EID_RRM_ENABLED_CAPABILITIES,
+                       WLAN_EID_MOBILITY_DOMAIN,
+                       WLAN_EID_SUPPORTED_REGULATORY_CLASSES,
+               };
+               noffset = ieee80211_ie_split(wk->ie, wk->ie_len,
+                                            before_ht, ARRAY_SIZE(before_ht),
+                                            offset);
+               pos = skb_put(skb, noffset - offset);
+               memcpy(pos, wk->ie + offset, noffset - offset);
+               offset = noffset;
+       }
+
+       if (wk->assoc.use_11n && wk->assoc.wmm_used &&
+           local->hw.queues >= 4)
+               ieee80211_add_ht_ie(skb, wk->assoc.ht_information_ie,
+                                   sband, wk->chan, wk->assoc.smps);
+
+       /* if present, add any custom non-vendor IEs that go after HT */
+       if (wk->ie_len && wk->ie) {
+               noffset = ieee80211_ie_split_vendor(wk->ie, wk->ie_len,
+                                                   offset);
+               pos = skb_put(skb, noffset - offset);
+               memcpy(pos, wk->ie + offset, noffset - offset);
+               offset = noffset;
+       }
+
+       if (wk->assoc.wmm_used && local->hw.queues >= 4) {
+               if (wk->assoc.uapsd_used) {
+                       qos_info = local->uapsd_queues;
+                       qos_info |= (local->uapsd_max_sp_len <<
+                                    IEEE80211_WMM_IE_STA_QOSINFO_SP_SHIFT);
+               } else {
+                       qos_info = 0;
+               }
+
+               pos = skb_put(skb, 9);
+               *pos++ = WLAN_EID_VENDOR_SPECIFIC;
+               *pos++ = 7; /* len */
+               *pos++ = 0x00; /* Microsoft OUI 00:50:F2 */
+               *pos++ = 0x50;
+               *pos++ = 0xf2;
+               *pos++ = 2; /* WME */
+               *pos++ = 0; /* WME info */
+               *pos++ = 1; /* WME ver */
+               *pos++ = qos_info;
+       }
+
+       /* add any remaining custom (i.e. vendor specific here) IEs */
+       if (wk->ie_len && wk->ie) {
+               noffset = wk->ie_len;
+               pos = skb_put(skb, noffset - offset);
+               memcpy(pos, wk->ie + offset, noffset - offset);
+       }
+
+       IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
+       ieee80211_tx_skb(sdata, skb);
+}
+
+static void ieee80211_remove_auth_bss(struct ieee80211_local *local,
+                                     struct ieee80211_work *wk)
+{
+       struct cfg80211_bss *cbss;
+       u16 capa_val = WLAN_CAPABILITY_ESS;
+
+       if (wk->probe_auth.privacy)
+               capa_val |= WLAN_CAPABILITY_PRIVACY;
+
+       cbss = cfg80211_get_bss(local->hw.wiphy, wk->chan, wk->filter_ta,
+                               wk->probe_auth.ssid, wk->probe_auth.ssid_len,
+                               WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_PRIVACY,
+                               capa_val);
+       if (!cbss)
+               return;
+
+       cfg80211_unlink_bss(local->hw.wiphy, cbss);
+       cfg80211_put_bss(cbss);
+}
+
+static enum work_action __must_check
+ieee80211_direct_probe(struct ieee80211_work *wk)
+{
+       struct ieee80211_sub_if_data *sdata = wk->sdata;
+       struct ieee80211_local *local = sdata->local;
+
+       wk->probe_auth.tries++;
+       if (wk->probe_auth.tries > IEEE80211_AUTH_MAX_TRIES) {
+               printk(KERN_DEBUG "%s: direct probe to %pM timed out\n",
+                      sdata->name, wk->filter_ta);
+
+               /*
+                * Most likely AP is not in the range so remove the
+                * bss struct for that AP.
+                */
+               ieee80211_remove_auth_bss(local, wk);
+
+               return WORK_ACT_TIMEOUT;
+       }
+
+       printk(KERN_DEBUG "%s: direct probe to %pM (try %d)\n",
+                       sdata->name, wk->filter_ta, wk->probe_auth.tries);
+
+       /*
+        * Direct probe is sent to broadcast address as some APs
+        * will not answer to direct packet in unassociated state.
+        */
+       ieee80211_send_probe_req(sdata, NULL, wk->probe_auth.ssid,
+                                wk->probe_auth.ssid_len, NULL, 0);
+
+       wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT;
+       run_again(local, wk->timeout);
+
+       return WORK_ACT_NONE;
+}
+
+
+static enum work_action __must_check
+ieee80211_authenticate(struct ieee80211_work *wk)
+{
+       struct ieee80211_sub_if_data *sdata = wk->sdata;
+       struct ieee80211_local *local = sdata->local;
+
+       wk->probe_auth.tries++;
+       if (wk->probe_auth.tries > IEEE80211_AUTH_MAX_TRIES) {
+               printk(KERN_DEBUG "%s: authentication with %pM"
+                      " timed out\n", sdata->name, wk->filter_ta);
+
+               /*
+                * Most likely AP is not in the range so remove the
+                * bss struct for that AP.
+                */
+               ieee80211_remove_auth_bss(local, wk);
+
+               return WORK_ACT_TIMEOUT;
+       }
+
+       printk(KERN_DEBUG "%s: authenticate with %pM (try %d)\n",
+              sdata->name, wk->filter_ta, wk->probe_auth.tries);
+
+       ieee80211_send_auth(sdata, 1, wk->probe_auth.algorithm, wk->ie,
+                           wk->ie_len, wk->filter_ta, NULL, 0, 0);
+       wk->probe_auth.transaction = 2;
+
+       wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT;
+       run_again(local, wk->timeout);
+
+       return WORK_ACT_NONE;
+}
+
+static enum work_action __must_check
+ieee80211_associate(struct ieee80211_work *wk)
+{
+       struct ieee80211_sub_if_data *sdata = wk->sdata;
+       struct ieee80211_local *local = sdata->local;
+
+       wk->assoc.tries++;
+       if (wk->assoc.tries > IEEE80211_ASSOC_MAX_TRIES) {
+               printk(KERN_DEBUG "%s: association with %pM"
+                      " timed out\n",
+                      sdata->name, wk->filter_ta);
+
+               /*
+                * Most likely AP is not in the range so remove the
+                * bss struct for that AP.
+                */
+               if (wk->assoc.bss)
+                       cfg80211_unlink_bss(local->hw.wiphy, wk->assoc.bss);
+
+               return WORK_ACT_TIMEOUT;
+       }
+
+       printk(KERN_DEBUG "%s: associate with %pM (try %d)\n",
+              sdata->name, wk->filter_ta, wk->assoc.tries);
+       ieee80211_send_assoc(sdata, wk);
+
+       wk->timeout = jiffies + IEEE80211_ASSOC_TIMEOUT;
+       run_again(local, wk->timeout);
+
+       return WORK_ACT_NONE;
+}
+
+static enum work_action __must_check
+ieee80211_remain_on_channel_timeout(struct ieee80211_work *wk)
+{
+       /*
+        * First time we run, do nothing -- the generic code will
+        * have switched to the right channel etc.
+        */
+       if (!wk->remain.started) {
+               wk->remain.started = true;
+               wk->timeout = jiffies + msecs_to_jiffies(wk->remain.duration);
+
+               cfg80211_ready_on_channel(wk->sdata->dev, (unsigned long) wk,
+                                         wk->chan, wk->chan_type,
+                                         wk->remain.duration, GFP_KERNEL);
+
+               return WORK_ACT_NONE;
+       }
+
+       return WORK_ACT_TIMEOUT;
+}
+
+static void ieee80211_auth_challenge(struct ieee80211_work *wk,
+                                    struct ieee80211_mgmt *mgmt,
+                                    size_t len)
+{
+       struct ieee80211_sub_if_data *sdata = wk->sdata;
+       u8 *pos;
+       struct ieee802_11_elems elems;
+
+       pos = mgmt->u.auth.variable;
+       ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems);
+       if (!elems.challenge)
+               return;
+       ieee80211_send_auth(sdata, 3, wk->probe_auth.algorithm,
+                           elems.challenge - 2, elems.challenge_len + 2,
+                           wk->filter_ta, wk->probe_auth.key,
+                           wk->probe_auth.key_len, wk->probe_auth.key_idx);
+       wk->probe_auth.transaction = 4;
+}
+
+static enum work_action __must_check
+ieee80211_rx_mgmt_auth(struct ieee80211_work *wk,
+                      struct ieee80211_mgmt *mgmt, size_t len)
+{
+       u16 auth_alg, auth_transaction, status_code;
+
+       if (wk->type != IEEE80211_WORK_AUTH)
+               return WORK_ACT_NONE;
+
+       if (len < 24 + 6)
+               return WORK_ACT_NONE;
+
+       auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg);
+       auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction);
+       status_code = le16_to_cpu(mgmt->u.auth.status_code);
+
+       if (auth_alg != wk->probe_auth.algorithm ||
+           auth_transaction != wk->probe_auth.transaction)
+               return WORK_ACT_NONE;
+
+       if (status_code != WLAN_STATUS_SUCCESS) {
+               printk(KERN_DEBUG "%s: %pM denied authentication (status %d)\n",
+                      wk->sdata->name, mgmt->sa, status_code);
+               return WORK_ACT_DONE;
+       }
+
+       switch (wk->probe_auth.algorithm) {
+       case WLAN_AUTH_OPEN:
+       case WLAN_AUTH_LEAP:
+       case WLAN_AUTH_FT:
+               break;
+       case WLAN_AUTH_SHARED_KEY:
+               if (wk->probe_auth.transaction != 4) {
+                       ieee80211_auth_challenge(wk, mgmt, len);
+                       /* need another frame */
+                       return WORK_ACT_NONE;
+               }
+               break;
+       default:
+               WARN_ON(1);
+               return WORK_ACT_NONE;
+       }
+
+       printk(KERN_DEBUG "%s: authenticated\n", wk->sdata->name);
+       return WORK_ACT_DONE;
+}
+
+static enum work_action __must_check
+ieee80211_rx_mgmt_assoc_resp(struct ieee80211_work *wk,
+                            struct ieee80211_mgmt *mgmt, size_t len,
+                            bool reassoc)
+{
+       struct ieee80211_sub_if_data *sdata = wk->sdata;
+       struct ieee80211_local *local = sdata->local;
+       u16 capab_info, status_code, aid;
+       struct ieee802_11_elems elems;
+       u8 *pos;
+
+       /*
+        * AssocResp and ReassocResp have identical structure, so process both
+        * of them in this function.
+        */
+
+       if (len < 24 + 6)
+               return WORK_ACT_NONE;
+
+       capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info);
+       status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code);
+       aid = le16_to_cpu(mgmt->u.assoc_resp.aid);
+
+       printk(KERN_DEBUG "%s: RX %sssocResp from %pM (capab=0x%x "
+              "status=%d aid=%d)\n",
+              sdata->name, reassoc ? "Rea" : "A", mgmt->sa,
+              capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14))));
+
+       pos = mgmt->u.assoc_resp.variable;
+       ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems);
+
+       if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY &&
+           elems.timeout_int && elems.timeout_int_len == 5 &&
+           elems.timeout_int[0] == WLAN_TIMEOUT_ASSOC_COMEBACK) {
+               u32 tu, ms;
+               tu = get_unaligned_le32(elems.timeout_int + 1);
+               ms = tu * 1024 / 1000;
+               printk(KERN_DEBUG "%s: %pM rejected association temporarily; "
+                      "comeback duration %u TU (%u ms)\n",
+                      sdata->name, mgmt->sa, tu, ms);
+               wk->timeout = jiffies + msecs_to_jiffies(ms);
+               if (ms > IEEE80211_ASSOC_TIMEOUT)
+                       run_again(local, wk->timeout);
+               return WORK_ACT_NONE;
+       }
+
+       if (status_code != WLAN_STATUS_SUCCESS)
+               printk(KERN_DEBUG "%s: %pM denied association (code=%d)\n",
+                      sdata->name, mgmt->sa, status_code);
+       else
+               printk(KERN_DEBUG "%s: associated\n", sdata->name);
+
+       return WORK_ACT_DONE;
+}
+
+static enum work_action __must_check
+ieee80211_rx_mgmt_probe_resp(struct ieee80211_work *wk,
+                            struct ieee80211_mgmt *mgmt, size_t len,
+                            struct ieee80211_rx_status *rx_status)
+{
+       struct ieee80211_sub_if_data *sdata = wk->sdata;
+       struct ieee80211_local *local = sdata->local;
+       size_t baselen;
+
+       ASSERT_WORK_MTX(local);
+
+       baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt;
+       if (baselen > len)
+               return WORK_ACT_NONE;
+
+       printk(KERN_DEBUG "%s: direct probe responded\n", sdata->name);
+       return WORK_ACT_DONE;
+}
+
+static void ieee80211_work_rx_queued_mgmt(struct ieee80211_local *local,
+                                         struct sk_buff *skb)
+{
+       struct ieee80211_rx_status *rx_status;
+       struct ieee80211_mgmt *mgmt;
+       struct ieee80211_work *wk;
+       enum work_action rma = WORK_ACT_NONE;
+       u16 fc;
+
+       rx_status = (struct ieee80211_rx_status *) skb->cb;
+       mgmt = (struct ieee80211_mgmt *) skb->data;
+       fc = le16_to_cpu(mgmt->frame_control);
+
+       mutex_lock(&local->work_mtx);
+
+       list_for_each_entry(wk, &local->work_list, list) {
+               const u8 *bssid = NULL;
+
+               switch (wk->type) {
+               case IEEE80211_WORK_DIRECT_PROBE:
+               case IEEE80211_WORK_AUTH:
+               case IEEE80211_WORK_ASSOC:
+                       bssid = wk->filter_ta;
+                       break;
+               default:
+                       continue;
+               }
+
+               /*
+                * Before queuing, we already verified mgmt->sa,
+                * so this is needed just for matching.
+                */
+               if (compare_ether_addr(bssid, mgmt->bssid))
+                       continue;
+
+               switch (fc & IEEE80211_FCTL_STYPE) {
+               case IEEE80211_STYPE_PROBE_RESP:
+                       rma = ieee80211_rx_mgmt_probe_resp(wk, mgmt, skb->len,
+                                                          rx_status);
+                       break;
+               case IEEE80211_STYPE_AUTH:
+                       rma = ieee80211_rx_mgmt_auth(wk, mgmt, skb->len);
+                       break;
+               case IEEE80211_STYPE_ASSOC_RESP:
+                       rma = ieee80211_rx_mgmt_assoc_resp(wk, mgmt,
+                                                          skb->len, false);
+                       break;
+               case IEEE80211_STYPE_REASSOC_RESP:
+                       rma = ieee80211_rx_mgmt_assoc_resp(wk, mgmt,
+                                                          skb->len, true);
+                       break;
+               default:
+                       WARN_ON(1);
+               }
+               /*
+                * We've processed this frame for that work, so it can't
+                * belong to another work struct.
+                * NB: this is also required for correctness for 'rma'!
+                */
+               break;
+       }
+
+       switch (rma) {
+       case WORK_ACT_NONE:
+               break;
+       case WORK_ACT_DONE:
+               list_del_rcu(&wk->list);
+               break;
+       default:
+               WARN(1, "unexpected: %d", rma);
+       }
+
+       mutex_unlock(&local->work_mtx);
+
+       if (rma != WORK_ACT_DONE)
+               goto out;
+
+       switch (wk->done(wk, skb)) {
+       case WORK_DONE_DESTROY:
+               free_work(wk);
+               break;
+       case WORK_DONE_REQUEUE:
+               synchronize_rcu();
+               wk->started = false; /* restart */
+               mutex_lock(&local->work_mtx);
+               list_add_tail(&wk->list, &local->work_list);
+               mutex_unlock(&local->work_mtx);
+       }
+
+ out:
+       kfree_skb(skb);
+}
+
+static void ieee80211_work_timer(unsigned long data)
+{
+       struct ieee80211_local *local = (void *) data;
+
+       if (local->quiescing)
+               return;
+
+       ieee80211_queue_work(&local->hw, &local->work_work);
+}
+
+static void ieee80211_work_work(struct work_struct *work)
+{
+       struct ieee80211_local *local =
+               container_of(work, struct ieee80211_local, work_work);
+       struct sk_buff *skb;
+       struct ieee80211_work *wk, *tmp;
+       LIST_HEAD(free_work);
+       enum work_action rma;
+       bool remain_off_channel = false;
+
+       if (local->scanning)
+               return;
+
+       /*
+        * ieee80211_queue_work() should have picked up most cases,
+        * here we'll pick the the rest.
+        */
+       if (WARN(local->suspended, "work scheduled while going to suspend\n"))
+               return;
+
+       /* first process frames to avoid timing out while a frame is pending */
+       while ((skb = skb_dequeue(&local->work_skb_queue)))
+               ieee80211_work_rx_queued_mgmt(local, skb);
+
+       ieee80211_recalc_idle(local);
+
+       mutex_lock(&local->work_mtx);
+
+       list_for_each_entry_safe(wk, tmp, &local->work_list, list) {
+               /* mark work as started if it's on the current off-channel */
+               if (!wk->started && local->tmp_channel &&
+                   wk->chan == local->tmp_channel &&
+                   wk->chan_type == local->tmp_channel_type) {
+                       wk->started = true;
+                       wk->timeout = jiffies;
+               }
+
+               if (!wk->started && !local->tmp_channel) {
+                       /*
+                        * TODO: could optimize this by leaving the
+                        *       station vifs in awake mode if they
+                        *       happen to be on the same channel as
+                        *       the requested channel
+                        */
+                       ieee80211_offchannel_stop_beaconing(local);
+                       ieee80211_offchannel_stop_station(local);
+
+                       local->tmp_channel = wk->chan;
+                       local->tmp_channel_type = wk->chan_type;
+                       ieee80211_hw_config(local, 0);
+                       wk->started = true;
+                       wk->timeout = jiffies;
+               }
+
+               /* don't try to work with items that aren't started */
+               if (!wk->started)
+                       continue;
+
+               if (time_is_after_jiffies(wk->timeout)) {
+                       /*
+                        * This work item isn't supposed to be worked on
+                        * right now, but take care to adjust the timer
+                        * properly.
+                        */
+                       run_again(local, wk->timeout);
+                       continue;
+               }
+
+               switch (wk->type) {
+               default:
+                       WARN_ON(1);
+                       /* nothing */
+                       rma = WORK_ACT_NONE;
+                       break;
+               case IEEE80211_WORK_ABORT:
+                       rma = WORK_ACT_TIMEOUT;
+               case IEEE80211_WORK_DIRECT_PROBE:
+                       rma = ieee80211_direct_probe(wk);
+                       break;
+               case IEEE80211_WORK_AUTH:
+                       rma = ieee80211_authenticate(wk);
+                       break;
+               case IEEE80211_WORK_ASSOC:
+                       rma = ieee80211_associate(wk);
+                       break;
+               case IEEE80211_WORK_REMAIN_ON_CHANNEL:
+                       rma = ieee80211_remain_on_channel_timeout(wk);
+                       break;
+               }
+
+               switch (rma) {
+               case WORK_ACT_NONE:
+                       /* might have changed the timeout */
+                       run_again(local, wk->timeout);
+                       break;
+               case WORK_ACT_TIMEOUT:
+                       list_del_rcu(&wk->list);
+                       synchronize_rcu();
+                       list_add(&wk->list, &free_work);
+                       break;
+               default:
+                       WARN(1, "unexpected: %d", rma);
+               }
+       }
+
+       list_for_each_entry(wk, &local->work_list, list) {
+               if (!wk->started)
+                       continue;
+               if (wk->chan != local->tmp_channel)
+                       continue;
+               if (wk->chan_type != local->tmp_channel_type)
+                       continue;
+               remain_off_channel = true;
+       }
+
+       if (!remain_off_channel && local->tmp_channel) {
+               local->tmp_channel = NULL;
+               ieee80211_hw_config(local, 0);
+               ieee80211_offchannel_return(local, true);
+               /* give connection some time to breathe */
+               run_again(local, jiffies + HZ/2);
+       }
+
+       if (list_empty(&local->work_list) && local->scan_req)
+               ieee80211_queue_delayed_work(&local->hw,
+                                            &local->scan_work,
+                                            round_jiffies_relative(0));
+
+       mutex_unlock(&local->work_mtx);
+
+       ieee80211_recalc_idle(local);
+
+       list_for_each_entry_safe(wk, tmp, &free_work, list) {
+               wk->done(wk, NULL);
+               list_del(&wk->list);
+               kfree(wk);
+       }
+}
+
+void ieee80211_add_work(struct ieee80211_work *wk)
+{
+       struct ieee80211_local *local;
+
+       if (WARN_ON(!wk->chan))
+               return;
+
+       if (WARN_ON(!wk->sdata))
+               return;
+
+       if (WARN_ON(!wk->done))
+               return;
+
+       if (WARN_ON(!ieee80211_sdata_running(wk->sdata)))
+               return;
+
+       wk->started = false;
+
+       local = wk->sdata->local;
+       mutex_lock(&local->work_mtx);
+       list_add_tail(&wk->list, &local->work_list);
+       mutex_unlock(&local->work_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);
+       INIT_WORK(&local->work_work, ieee80211_work_work);
+       skb_queue_head_init(&local->work_skb_queue);
+}
+
+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);
+       list_for_each_entry(wk, &local->work_list, list) {
+               if (wk->sdata != sdata)
+                       continue;
+               wk->type = IEEE80211_WORK_ABORT;
+               wk->started = true;
+               wk->timeout = jiffies;
+       }
+       mutex_unlock(&local->work_mtx);
+
+       /* run cleanups etc. */
+       ieee80211_work_work(&local->work_work);
+
+       mutex_lock(&local->work_mtx);
+       list_for_each_entry(wk, &local->work_list, list) {
+               if (wk->sdata != sdata)
+                       continue;
+               WARN_ON(1);
+               break;
+       }
+       mutex_unlock(&local->work_mtx);
+}
+
+ieee80211_rx_result ieee80211_work_rx_mgmt(struct ieee80211_sub_if_data *sdata,
+                                          struct sk_buff *skb)
+{
+       struct ieee80211_local *local = sdata->local;
+       struct ieee80211_mgmt *mgmt;
+       struct ieee80211_work *wk;
+       u16 fc;
+
+       if (skb->len < 24)
+               return RX_DROP_MONITOR;
+
+       mgmt = (struct ieee80211_mgmt *) skb->data;
+       fc = le16_to_cpu(mgmt->frame_control);
+
+       list_for_each_entry_rcu(wk, &local->work_list, list) {
+               if (sdata != wk->sdata)
+                       continue;
+               if (compare_ether_addr(wk->filter_ta, mgmt->sa))
+                       continue;
+               if (compare_ether_addr(wk->filter_ta, mgmt->bssid))
+                       continue;
+
+               switch (fc & IEEE80211_FCTL_STYPE) {
+               case IEEE80211_STYPE_AUTH:
+               case IEEE80211_STYPE_PROBE_RESP:
+               case IEEE80211_STYPE_ASSOC_RESP:
+               case IEEE80211_STYPE_REASSOC_RESP:
+               case IEEE80211_STYPE_DEAUTH:
+               case IEEE80211_STYPE_DISASSOC:
+                       skb_queue_tail(&local->work_skb_queue, skb);
+                       ieee80211_queue_work(&local->hw, &local->work_work);
+                       return RX_QUEUED;
+               }
+       }
+
+       return RX_CONTINUE;
+}
+
+static enum work_done_result ieee80211_remain_done(struct ieee80211_work *wk,
+                                                  struct sk_buff *skb)
+{
+       /*
+        * We are done serving the remain-on-channel command.
+        */
+       cfg80211_remain_on_channel_expired(wk->sdata->dev, (unsigned long) wk,
+                                          wk->chan, wk->chan_type,
+                                          GFP_KERNEL);
+
+       return WORK_DONE_DESTROY;
+}
+
+int ieee80211_wk_remain_on_channel(struct ieee80211_sub_if_data *sdata,
+                                  struct ieee80211_channel *chan,
+                                  enum nl80211_channel_type channel_type,
+                                  unsigned int duration, u64 *cookie)
+{
+       struct ieee80211_work *wk;
+
+       wk = kzalloc(sizeof(*wk), GFP_KERNEL);
+       if (!wk)
+               return -ENOMEM;
+
+       wk->type = IEEE80211_WORK_REMAIN_ON_CHANNEL;
+       wk->chan = chan;
+       wk->chan_type = channel_type;
+       wk->sdata = sdata;
+       wk->done = ieee80211_remain_done;
+
+       wk->remain.duration = duration;
+
+       *cookie = (unsigned long) wk;
+
+       ieee80211_add_work(wk);
+
+       return 0;
+}
+
+int ieee80211_wk_cancel_remain_on_channel(struct ieee80211_sub_if_data *sdata,
+                                         u64 cookie)
+{
+       struct ieee80211_local *local = sdata->local;
+       struct ieee80211_work *wk, *tmp;
+       bool found = false;
+
+       mutex_lock(&local->work_mtx);
+       list_for_each_entry_safe(wk, tmp, &local->work_list, list) {
+               if ((unsigned long) wk == cookie) {
+                       wk->timeout = jiffies;
+                       found = true;
+                       break;
+               }
+       }
+       mutex_unlock(&local->work_mtx);
+
+       if (!found)
+               return -ENOENT;
+
+       ieee80211_queue_work(&local->hw, &local->work_work);
+
+       return 0;
+}
index d07ecda0a92d22c805216a5933e304721f9e8665..a4b6e148c5dec4ceba8a4aa5ef964353433e2d6a 100644 (file)
@@ -681,9 +681,7 @@ static int ctrl_dumpfamily(struct sk_buff *skb, struct netlink_callback *cb)
        int chains_to_skip = cb->args[0];
        int fams_to_skip = cb->args[1];
 
-       for (i = 0; i < GENL_FAM_TAB_SIZE; i++) {
-               if (i < chains_to_skip)
-                       continue;
+       for (i = chains_to_skip; i < GENL_FAM_TAB_SIZE; i++) {
                n = 0;
                list_for_each_entry(rt, genl_family_chain(i), family_list) {
                        if (!rt->netnsok && !net_eq(net, &init_net))
index f126d18dbdc481598fcd4de58c74fd434b0a18f9..53633c5fdb1d612070911a484904906c280a2abf 100644 (file)
@@ -2457,7 +2457,7 @@ static const struct file_operations packet_seq_fops = {
 
 #endif
 
-static int packet_net_init(struct net *net)
+static int __net_init packet_net_init(struct net *net)
 {
        rwlock_init(&net->packet.sklist_lock);
        INIT_HLIST_HEAD(&net->packet.sklist);
@@ -2468,7 +2468,7 @@ static int packet_net_init(struct net *net)
        return 0;
 }
 
-static void packet_net_exit(struct net *net)
+static void __net_exit packet_net_exit(struct net *net)
 {
        proc_net_remove(net, "packet");
 }
index 67f072e94d00f78394af72f2ad53014ad6e2b235..387197b579b1c430bd511b695740c7724fb4c9c7 100644 (file)
@@ -75,7 +75,8 @@ static int pn_sendmsg(struct kiocb *iocb, struct sock *sk,
        struct sk_buff *skb;
        int err;
 
-       if (msg->msg_flags & MSG_OOB)
+       if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR|MSG_NOSIGNAL|
+                               MSG_CMSG_COMPAT))
                return -EOPNOTSUPP;
 
        if (msg->msg_name == NULL)
@@ -119,7 +120,8 @@ static int pn_recvmsg(struct kiocb *iocb, struct sock *sk,
        int rval = -EOPNOTSUPP;
        int copylen;
 
-       if (flags & MSG_OOB)
+       if (flags & ~(MSG_PEEK|MSG_TRUNC|MSG_DONTWAIT|MSG_NOSIGNAL|
+                       MSG_CMSG_COMPAT))
                goto out_nofree;
 
        if (addr_len)
index d183509d3fa65f6de5035af387319ac1575f3240..d01208968c830c5fa7a7484ea15ae059fc7015d6 100644 (file)
@@ -96,11 +96,11 @@ static int gprs_recv(struct gprs_dev *gp, struct sk_buff *skb)
                goto drop;
        }
 
-       if (likely(skb_headroom(skb) & 3)) {
+       if (skb_headroom(skb) & 3) {
                struct sk_buff *rskb, *fs;
                int flen = 0;
 
-               /* Phonet Pipe data header is misaligned (3 bytes),
+               /* Phonet Pipe data header may be misaligned (3 bytes),
                 * so wrap the IP packet as a single fragment of an head-less
                 * socket buffer. The network stack will pull what it needs,
                 * but at least, the whole IP payload is not memcpy'd. */
index b6356f3832f6e69cdc3fc7c2a076fab9f22efcd1..360cf377693eeee42008d6f0e5f1e34f12259b25 100644 (file)
@@ -354,6 +354,9 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb)
                queue = &pn->ctrlreq_queue;
                goto queue;
 
+       case PNS_PIPE_ALIGNED_DATA:
+               __skb_pull(skb, 1);
+               /* fall through */
        case PNS_PIPE_DATA:
                __skb_pull(skb, 3); /* Pipe data header */
                if (!pn_flow_safe(pn->rx_fc)) {
@@ -441,6 +444,7 @@ static int pep_connreq_rcv(struct sock *sk, struct sk_buff *skb)
        struct sockaddr_pn dst;
        u16 peer_type;
        u8 pipe_handle, enabled, n_sb;
+       u8 aligned = 0;
 
        if (!pskb_pull(skb, sizeof(*hdr) + 4))
                return -EINVAL;
@@ -479,6 +483,9 @@ static int pep_connreq_rcv(struct sock *sk, struct sk_buff *skb)
                                return -EINVAL;
                        peer_type = (peer_type & 0xff00) | data[0];
                        break;
+               case PN_PIPE_SB_ALIGNED_DATA:
+                       aligned = data[0] != 0;
+                       break;
                }
                n_sb--;
        }
@@ -510,6 +517,7 @@ static int pep_connreq_rcv(struct sock *sk, struct sk_buff *skb)
        newpn->rx_credits = 0;
        newpn->rx_fc = newpn->tx_fc = PN_LEGACY_FLOW_CONTROL;
        newpn->init_enable = enabled;
+       newpn->aligned = aligned;
 
        BUG_ON(!skb_queue_empty(&newsk->sk_receive_queue));
        skb_queue_head(&newsk->sk_receive_queue, skb);
@@ -829,11 +837,15 @@ static int pipe_skb_send(struct sock *sk, struct sk_buff *skb)
                return -ENOBUFS;
        }
 
-       skb_push(skb, 3);
+       skb_push(skb, 3 + pn->aligned);
        skb_reset_transport_header(skb);
        ph = pnp_hdr(skb);
        ph->utid = 0;
-       ph->message_id = PNS_PIPE_DATA;
+       if (pn->aligned) {
+               ph->message_id = PNS_PIPE_ALIGNED_DATA;
+               ph->data[0] = 0; /* padding */
+       } else
+               ph->message_id = PNS_PIPE_DATA;
        ph->pipe_handle = pn->pipe_handle;
 
        return pn_skb_send(sk, skb, &pipe_srv);
@@ -848,7 +860,9 @@ static int pep_sendmsg(struct kiocb *iocb, struct sock *sk,
        int flags = msg->msg_flags;
        int err, done;
 
-       if (msg->msg_flags & MSG_OOB || !(msg->msg_flags & MSG_EOR))
+       if ((msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR|MSG_NOSIGNAL|
+                               MSG_CMSG_COMPAT)) ||
+                       !(msg->msg_flags & MSG_EOR))
                return -EOPNOTSUPP;
 
        skb = sock_alloc_send_skb(sk, MAX_PNPIPE_HEADER + len,
@@ -927,6 +941,9 @@ int pep_write(struct sock *sk, struct sk_buff *skb)
        struct sk_buff *rskb, *fs;
        int flen = 0;
 
+       if (pep_sk(sk)->aligned)
+               return pipe_skb_send(sk, skb);
+
        rskb = alloc_skb(MAX_PNPIPE_HEADER, GFP_ATOMIC);
        if (!rskb) {
                kfree_skb(skb);
@@ -966,6 +983,10 @@ static int pep_recvmsg(struct kiocb *iocb, struct sock *sk,
        struct sk_buff *skb;
        int err;
 
+       if (flags & ~(MSG_OOB|MSG_PEEK|MSG_TRUNC|MSG_DONTWAIT|MSG_WAITALL|
+                       MSG_NOSIGNAL|MSG_CMSG_COMPAT))
+               return -EOPNOTSUPP;
+
        if (unlikely(1 << sk->sk_state & (TCPF_LISTEN | TCPF_CLOSE)))
                return -ENOTCONN;
 
@@ -973,6 +994,8 @@ static int pep_recvmsg(struct kiocb *iocb, struct sock *sk,
                /* Dequeue and acknowledge control request */
                struct pep_sock *pn = pep_sk(sk);
 
+               if (flags & MSG_PEEK)
+                       return -EOPNOTSUPP;
                skb = skb_dequeue(&pn->ctrlreq_queue);
                if (skb) {
                        pep_ctrlreq_error(sk, skb, PN_PIPE_NO_ERROR,
index bc4a33bf2d3d9ec17ab5188d695f345bc9c7cb12..c597cc53a6fb2d3433c70beea0f05fdc982d5a21 100644 (file)
@@ -311,7 +311,7 @@ static struct notifier_block phonet_device_notifier = {
 };
 
 /* Per-namespace Phonet devices handling */
-static int phonet_init_net(struct net *net)
+static int __net_init phonet_init_net(struct net *net)
 {
        struct phonet_net *pnn = net_generic(net, phonet_net_id);
 
@@ -324,7 +324,7 @@ static int phonet_init_net(struct net *net)
        return 0;
 }
 
-static void phonet_exit_net(struct net *net)
+static void __net_exit phonet_exit_net(struct net *net)
 {
        struct phonet_net *pnn = net_generic(net, phonet_net_id);
        struct net_device *dev;
index 75fd1c672c61a4292e34fd18966de9f1a9a163f6..6cd491013b503f264fe210545a118f45cb8df0d0 100644 (file)
@@ -1707,6 +1707,7 @@ static int __init pktsched_init(void)
 {
        register_qdisc(&pfifo_qdisc_ops);
        register_qdisc(&bfifo_qdisc_ops);
+       register_qdisc(&pfifo_head_drop_qdisc_ops);
        register_qdisc(&mq_qdisc_ops);
        proc_net_fops_create(&init_net, "psched", 0, &psched_fops);
 
index 69188e8358b4cd6c73e1861bacbea27c6564f7bd..4b0a6cc44c77b6c50e02247333f8b9ed42ae4e3c 100644 (file)
@@ -43,6 +43,26 @@ static int pfifo_enqueue(struct sk_buff *skb, struct Qdisc* sch)
        return qdisc_reshape_fail(skb, sch);
 }
 
+static int pfifo_tail_enqueue(struct sk_buff *skb, struct Qdisc* sch)
+{
+       struct sk_buff *skb_head;
+       struct fifo_sched_data *q = qdisc_priv(sch);
+
+       if (likely(skb_queue_len(&sch->q) < q->limit))
+               return qdisc_enqueue_tail(skb, sch);
+
+       /* queue full, remove one skb to fulfill the limit */
+       skb_head = qdisc_dequeue_head(sch);
+       sch->bstats.bytes -= qdisc_pkt_len(skb_head);
+       sch->bstats.packets--;
+       sch->qstats.drops++;
+       kfree_skb(skb_head);
+
+       qdisc_enqueue_tail(skb, sch);
+
+       return NET_XMIT_CN;
+}
+
 static int fifo_init(struct Qdisc *sch, struct nlattr *opt)
 {
        struct fifo_sched_data *q = qdisc_priv(sch);
@@ -108,6 +128,20 @@ struct Qdisc_ops bfifo_qdisc_ops __read_mostly = {
 };
 EXPORT_SYMBOL(bfifo_qdisc_ops);
 
+struct Qdisc_ops pfifo_head_drop_qdisc_ops __read_mostly = {
+       .id             =       "pfifo_head_drop",
+       .priv_size      =       sizeof(struct fifo_sched_data),
+       .enqueue        =       pfifo_tail_enqueue,
+       .dequeue        =       qdisc_dequeue_head,
+       .peek           =       qdisc_peek_head,
+       .drop           =       qdisc_queue_drop_head,
+       .init           =       fifo_init,
+       .reset          =       qdisc_reset_queue,
+       .change         =       fifo_init,
+       .dump           =       fifo_dump,
+       .owner          =       THIS_MODULE,
+};
+
 /* Pass size change message down to embedded FIFO */
 int fifo_set_limit(struct Qdisc *q, unsigned int limit)
 {
index d093cbfeaac449855fcb89fcb87fe74daa523d90..a5ac6e0a8d9c11f1b40c191cbebf6e21ca14d0ef 100644 (file)
@@ -40,7 +40,7 @@
 #include <net/sctp/sctp.h>
 #include <net/ip.h> /* for snmp_fold_field */
 
-static struct snmp_mib sctp_snmp_list[] = {
+static const struct snmp_mib sctp_snmp_list[] = {
        SNMP_MIB_ITEM("SctpCurrEstab", SCTP_MIB_CURRESTAB),
        SNMP_MIB_ITEM("SctpActiveEstabs", SCTP_MIB_ACTIVEESTABS),
        SNMP_MIB_ITEM("SctpPassiveEstabs", SCTP_MIB_PASSIVEESTABS),
index 67fdac9d2d3382e566c2f91d26d13d2bde4a5689..f6d1e59c4151845b9dcfd0dc53428c88fdf079af 100644 (file)
@@ -6359,7 +6359,7 @@ void sctp_copy_sock(struct sock *newsk, struct sock *sk,
                    struct sctp_association *asoc)
 {
        struct inet_sock *inet = inet_sk(sk);
-       struct inet_sock *newinet = inet_sk(newsk);
+       struct inet_sock *newinet;
 
        newsk->sk_type = sk->sk_type;
        newsk->sk_bound_dev_if = sk->sk_bound_dev_if;
index 0b15d7250c401356cf0c6e87679437788f157ac8..53196009160a031ae4909fc5bc65e8ad098ef22c 100644 (file)
@@ -71,7 +71,7 @@ static struct ctl_table_root net_sysctl_ro_root = {
        .permissions = net_ctl_ro_header_perms,
 };
 
-static int sysctl_net_init(struct net *net)
+static int __net_init sysctl_net_init(struct net *net)
 {
        setup_sysctl_set(&net->sysctls,
                         &net_sysctl_ro_root.default_set,
@@ -79,7 +79,7 @@ static int sysctl_net_init(struct net *net)
        return 0;
 }
 
-static void sysctl_net_exit(struct net *net)
+static void __net_exit sysctl_net_exit(struct net *net)
 {
        WARN_ON(!list_empty(&net->sysctls.list));
        return;
index 3b30d1130b615fa75db3d2f4a5f8d308cff21164..b74f78d0c0338a467bccc1914a51e977b6f8b7b5 100644 (file)
@@ -10,7 +10,7 @@ menuconfig TIPC
          specially designed for intra cluster communication. This protocol
          originates from Ericsson where it has been used in carrier grade
          cluster applications for many years.
-       
+
          For more information about TIPC, see http://tipc.sourceforge.net.
 
          This protocol support is also available as a module ( = code which
@@ -23,91 +23,76 @@ menuconfig TIPC
 if TIPC
 
 config TIPC_ADVANCED
-       bool "TIPC: Advanced configuration"
+       bool "Advanced TIPC configuration"
        default n
        help
-         Saying Y here will open some advanced configuration
-          for TIPC. Most users do not need to bother, so if
-          unsure, just say N.
+         Saying Y here will open some advanced configuration for TIPC.
+         Most users do not need to bother; if unsure, just say N.
 
 config TIPC_ZONES
-       int "Maximum number of zones in network"
+       int "Maximum number of zones in network"
        depends on TIPC_ADVANCED
+       range 1 255
        default "3"
        help
-        Max number of zones inside TIPC network. Max supported value 
-         is 255 zones, minimum is 1
+         Specifies how many zones can be supported in a TIPC network.
+         Can range from 1 to 255 zones; default is 3.
 
-        Default is 3 zones in a network; setting this to higher
-        allows more zones but might use more memory.
+         Setting this to a smaller value saves some memory;
+         setting it to a higher value allows for more zones.
 
 config TIPC_CLUSTERS
        int "Maximum number of clusters in a zone"
        depends on TIPC_ADVANCED
+       range 1 1
        default "1"
        help
-          ***Only 1 (one cluster in a zone) is supported by current code.
-          Any value set here will be overridden.***
-
-          (Max number of clusters inside TIPC zone. Max supported 
-          value is 4095 clusters, minimum is 1.
+         Specifies how many clusters can be supported in a TIPC zone.
 
-         Default is 1; setting this to smaller value might save 
-          some memory, setting it to higher
-         allows more clusters and might consume more memory.)
+         *** Currently TIPC only supports a single cluster per zone. ***
 
 config TIPC_NODES
-       int "Maximum number of nodes in cluster"
+       int "Maximum number of nodes in cluster"
        depends on TIPC_ADVANCED
+       range 8 2047
        default "255"
        help
-         Maximum number of nodes inside a TIPC cluster. Maximum 
-          supported value is 2047 nodes, minimum is 8. 
-
-         Setting this to a smaller value saves some memory, 
-         setting it to higher allows more nodes.
-
-config TIPC_SLAVE_NODES
-       int "Maximum number of slave nodes in cluster"
-       depends on TIPC_ADVANCED
-       default "0"
-       help
-          ***This capability is not supported by current code.***
-         
-         Maximum number of slave nodes inside a TIPC cluster. Maximum 
-          supported value is 2047 nodes, minimum is 0. 
+         Specifies how many nodes can be supported in a TIPC cluster.
+         Can range from 8 to 2047 nodes; default is 255.
 
-         Setting this to a smaller value saves some memory
-         setting it to higher allows more nodes.
+         Setting this to a smaller value saves some memory;
+         setting it to higher allows for more nodes.
 
 config TIPC_PORTS
        int "Maximum number of ports in a node"
        depends on TIPC_ADVANCED
+       range 127 65535
        default "8191"
        help
-         Maximum number of ports within a node. Maximum 
-          supported value is 64535 nodes, minimum is 127. 
+         Specifies how many ports can be supported by a node.
+         Can range from 127 to 65535 ports; default is 8191.
 
          Setting this to a smaller value saves some memory, 
-         setting it to higher allows more ports.
+         setting it to higher allows for more ports.
 
 config TIPC_LOG
        int "Size of log buffer"
        depends on TIPC_ADVANCED
-       default 0
+       range 0 32768
+       default "0"
        help
-         Size (in bytes) of TIPC's internal log buffer, which records the
-         occurrence of significant events.  Maximum supported value
-         is 32768 bytes, minimum is 0.
+         Size (in bytes) of TIPC's internal log buffer, which records the
+         occurrence of significant events.  Can range from 0 to 32768 bytes;
+         default is 0.
 
          There is no need to enable the log buffer unless the node will be
          managed remotely via TIPC.
 
 config TIPC_DEBUG
-       bool "Enable debugging support"
+       bool "Enable debug messages"
        default n
        help
-         This will enable debugging of TIPC.
+         This enables debugging of TIPC.
 
          Only say Y here if you are having trouble with TIPC.  It will
          enable the display of detailed information about what is going on.
index 3256bd7d398fb0850a4e2fdd5a294ad2d6405c40..52c571fedbe05892ed9e7690e68063af7aabf1e6 100644 (file)
@@ -189,11 +189,11 @@ static int __init tipc_init(void)
        tipc_remote_management = 1;
        tipc_max_publications = 10000;
        tipc_max_subscriptions = 2000;
-       tipc_max_ports = delimit(CONFIG_TIPC_PORTS, 127, 65536);
-       tipc_max_zones = delimit(CONFIG_TIPC_ZONES, 1, 255);
-       tipc_max_clusters = delimit(CONFIG_TIPC_CLUSTERS, 1, 1);
-       tipc_max_nodes = delimit(CONFIG_TIPC_NODES, 8, 2047);
-       tipc_max_slaves = delimit(CONFIG_TIPC_SLAVE_NODES, 0, 2047);
+       tipc_max_ports = CONFIG_TIPC_PORTS;
+       tipc_max_zones = CONFIG_TIPC_ZONES;
+       tipc_max_clusters = CONFIG_TIPC_CLUSTERS;
+       tipc_max_nodes = CONFIG_TIPC_NODES;
+       tipc_max_slaves = CONFIG_TIPC_SLAVE_NODES;
        tipc_net_id = 4711;
 
        if ((res = tipc_core_start()))
index f25511903115bbc937f68b21fcfb99048fba21cf..9bc9b92bc099b65527813494eb833a4178c4e4bf 100644 (file)
@@ -2224,7 +2224,7 @@ static const struct net_proto_family unix_family_ops = {
 };
 
 
-static int unix_net_init(struct net *net)
+static int __net_init unix_net_init(struct net *net)
 {
        int error = -ENOMEM;
 
@@ -2243,7 +2243,7 @@ out:
        return error;
 }
 
-static void unix_net_exit(struct net *net)
+static void __net_exit unix_net_exit(struct net *net)
 {
        unix_sysctl_unregister(net);
        proc_net_remove(net, "unix");
index 708f5df6b7f08e7217ce7a1f2a89f83b856b1ddd..d095c7be10d03bd1514e8fae584a3b31cc30d5ce 100644 (file)
@@ -31,7 +31,7 @@ static struct ctl_path unix_path[] = {
        { },
 };
 
-int unix_sysctl_register(struct net *net)
+int __net_init unix_sysctl_register(struct net *net)
 {
        struct ctl_table *table;
 
diff --git a/net/wireless/.gitignore b/net/wireless/.gitignore
new file mode 100644 (file)
index 0000000..c33451b
--- /dev/null
@@ -0,0 +1 @@
+regdb.c
index 90e93a5701aacdd933384419d591e2e72d936d6b..d0ee29063e5d80190412672552a5b2cfe4886c74 100644 (file)
@@ -94,20 +94,21 @@ config CFG80211_DEBUGFS
 
          If unsure, say N.
 
-config WIRELESS_OLD_REGULATORY
-       bool "Old wireless static regulatory definitions"
+config CFG80211_INTERNAL_REGDB
+       bool "use statically compiled regulatory rules database" if EMBEDDED
        default n
        depends on CFG80211
        ---help---
-         This option enables the old static regulatory information
-         and uses it within the new framework. This option is available
-         for historical reasons and it is advised to leave it off.
+         This option generates an internal data structure representing
+         the wireless regulatory rules described in net/wireless/db.txt
+         and includes code to query that database.  This is an alternative
+         to using CRDA for defining regulatory rules for the kernel.
 
          For details see:
 
          http://wireless.kernel.org/en/developers/Regulatory
 
-         Say N and if you say Y, please tell us why. The default is N.
+         Most distributions have a CRDA package.  So if unsure, say N.
 
 config CFG80211_WEXT
        bool "cfg80211 wireless extensions compatibility"
index f07c8dc7aab2990d543db566028fa1d460426e85..e77e508126fa4870890d330f2d8f653a72a104b6 100644 (file)
@@ -13,5 +13,11 @@ cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o
 cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o
 cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o
 cfg80211-$(CONFIG_CFG80211_WEXT) += wext-compat.o wext-sme.o
+cfg80211-$(CONFIG_CFG80211_INTERNAL_REGDB) += regdb.o
 
 ccflags-y += -D__CHECK_ENDIAN__
+
+$(obj)/regdb.c: $(src)/db.txt $(src)/genregdb.awk
+       @$(AWK) -f $(srctree)/$(src)/genregdb.awk < $< > $@
+
+clean-files := regdb.c
index a46ac6c9b3655dbc056b8a20846a972b2bba9fdb..bf1737fc9a7e47fe448e71a058334fb5fdb1b068 100644 (file)
@@ -41,44 +41,57 @@ rdev_fixed_channel(struct cfg80211_registered_device *rdev,
        return result;
 }
 
-int rdev_set_freq(struct cfg80211_registered_device *rdev,
-                 struct wireless_dev *for_wdev,
+struct ieee80211_channel *
+rdev_freq_to_chan(struct cfg80211_registered_device *rdev,
                  int freq, enum nl80211_channel_type channel_type)
 {
        struct ieee80211_channel *chan;
        struct ieee80211_sta_ht_cap *ht_cap;
-       int result;
-
-       if (rdev_fixed_channel(rdev, for_wdev))
-               return -EBUSY;
-
-       if (!rdev->ops->set_channel)
-               return -EOPNOTSUPP;
 
        chan = ieee80211_get_channel(&rdev->wiphy, freq);
 
        /* Primary channel not allowed */
        if (!chan || chan->flags & IEEE80211_CHAN_DISABLED)
-               return -EINVAL;
+               return NULL;
 
        if (channel_type == NL80211_CHAN_HT40MINUS &&
            chan->flags & IEEE80211_CHAN_NO_HT40MINUS)
-               return -EINVAL;
+               return NULL;
        else if (channel_type == NL80211_CHAN_HT40PLUS &&
                 chan->flags & IEEE80211_CHAN_NO_HT40PLUS)
-               return -EINVAL;
+               return NULL;
 
        ht_cap = &rdev->wiphy.bands[chan->band]->ht_cap;
 
        if (channel_type != NL80211_CHAN_NO_HT) {
                if (!ht_cap->ht_supported)
-                       return -EINVAL;
+                       return NULL;
 
                if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) ||
                    ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT)
-                       return -EINVAL;
+                       return NULL;
        }
 
+       return chan;
+}
+
+int rdev_set_freq(struct cfg80211_registered_device *rdev,
+                 struct wireless_dev *for_wdev,
+                 int freq, enum nl80211_channel_type channel_type)
+{
+       struct ieee80211_channel *chan;
+       int result;
+
+       if (rdev_fixed_channel(rdev, for_wdev))
+               return -EBUSY;
+
+       if (!rdev->ops->set_channel)
+               return -EOPNOTSUPP;
+
+       chan = rdev_freq_to_chan(rdev, freq, channel_type);
+       if (!chan)
+               return -EINVAL;
+
        result = rdev->ops->set_channel(&rdev->wiphy, chan, channel_type);
        if (result)
                return result;
index 92b81244248840fa9ff4437dddf02cbd4beda711..20db90246de5a04889cce289d13edd0f4f5bae5c 100644 (file)
@@ -402,6 +402,7 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
        rdev->wiphy.retry_long = 4;
        rdev->wiphy.frag_threshold = (u32) -1;
        rdev->wiphy.rts_threshold = (u32) -1;
+       rdev->wiphy.coverage_class = 0;
 
        return &rdev->wiphy;
 }
index 4ef3efc941066119ddbea37766b8081219aa01a6..2d6a6b9c0c438f6f06ab691bffc94f4d7e794dad 100644 (file)
@@ -111,7 +111,8 @@ struct cfg80211_internal_bss {
        unsigned long ts;
        struct kref ref;
        atomic_t hold;
-       bool ies_allocated;
+       bool beacon_ies_allocated;
+       bool proberesp_ies_allocated;
 
        /* must be last because of priv member */
        struct cfg80211_bss pub;
@@ -374,10 +375,15 @@ void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev);
 struct ieee80211_channel *
 rdev_fixed_channel(struct cfg80211_registered_device *rdev,
                   struct wireless_dev *for_wdev);
+struct ieee80211_channel *
+rdev_freq_to_chan(struct cfg80211_registered_device *rdev,
+                 int freq, enum nl80211_channel_type channel_type);
 int rdev_set_freq(struct cfg80211_registered_device *rdev,
                  struct wireless_dev *for_wdev,
                  int freq, enum nl80211_channel_type channel_type);
 
+u16 cfg80211_calculate_bitrate(struct rate_info *rate);
+
 #ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS
 #define CFG80211_DEV_WARN_ON(cond)     WARN_ON(cond)
 #else
diff --git a/net/wireless/db.txt b/net/wireless/db.txt
new file mode 100644 (file)
index 0000000..a2fc3a0
--- /dev/null
@@ -0,0 +1,17 @@
+#
+# This file is a placeholder to prevent accidental build breakage if someone
+# enables CONFIG_CFG80211_INTERNAL_REGDB.  Almost no one actually needs to
+# enable that build option.
+#
+# You should be using CRDA instead.  It is even better if you use the CRDA
+# package provided by your distribution, since they will probably keep it
+# up-to-date on your behalf.
+#
+# If you _really_ intend to use CONFIG_CFG80211_INTERNAL_REGDB then you will
+# need to replace this file with one containing appropriately formatted
+# regulatory rules that cover the regulatory domains you will be using.  Your
+# best option is to extract the db.txt file from the wireless-regdb git
+# repository:
+#
+#   git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-regdb.git
+#
diff --git a/net/wireless/genregdb.awk b/net/wireless/genregdb.awk
new file mode 100644 (file)
index 0000000..3cc9e69
--- /dev/null
@@ -0,0 +1,118 @@
+#!/usr/bin/awk -f
+#
+# genregdb.awk -- generate regdb.c from db.txt
+#
+# Actually, it reads from stdin (presumed to be db.txt) and writes
+# to stdout (presumed to be regdb.c), but close enough...
+#
+# Copyright 2009 John W. Linville <linville@tuxdriver.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.
+#
+
+BEGIN {
+       active = 0
+       rules = 0;
+       print "/*"
+       print " * DO NOT EDIT -- file generated from data in db.txt"
+       print " */"
+       print ""
+       print "#include <linux/nl80211.h>"
+       print "#include <net/cfg80211.h>"
+       print ""
+       regdb = "const struct ieee80211_regdomain *reg_regdb[] = {\n"
+}
+
+/^[ \t]*#/ {
+       # Ignore
+}
+
+!active && /^[ \t]*$/ {
+       # Ignore
+}
+
+!active && /country/ {
+       country=$2
+       sub(/:/, "", country)
+       printf "static const struct ieee80211_regdomain regdom_%s = {\n", country
+       printf "\t.alpha2 = \"%s\",\n", country
+       printf "\t.reg_rules = {\n"
+       active = 1
+       regdb = regdb "\t&regdom_" country ",\n"
+}
+
+active && /^[ \t]*\(/ {
+       start = $1
+       sub(/\(/, "", start)
+       end = $3
+       bw = $5
+       sub(/\),/, "", bw)
+       gain = $6
+       sub(/\(/, "", gain)
+       sub(/,/, "", gain)
+       power = $7
+       sub(/\)/, "", power)
+       sub(/,/, "", power)
+       # power might be in mW...
+       units = $8
+       sub(/\)/, "", units)
+       sub(/,/, "", units)
+       if (units == "mW") {
+               if (power == 100) {
+                       power = 20
+               } else if (power == 200) {
+                       power = 23
+               } else if (power == 500) {
+                       power = 27
+               } else if (power == 1000) {
+                       power = 30
+               } else {
+                       print "Unknown power value in database!"
+               }
+       }
+       flagstr = ""
+       for (i=8; i<=NF; i++)
+               flagstr = flagstr $i
+       split(flagstr, flagarray, ",")
+       flags = ""
+       for (arg in flagarray) {
+               if (flagarray[arg] == "NO-OFDM") {
+                       flags = flags "\n\t\t\tNL80211_RRF_NO_OFDM | "
+               } else if (flagarray[arg] == "NO-CCK") {
+                       flags = flags "\n\t\t\tNL80211_RRF_NO_CCK | "
+               } else if (flagarray[arg] == "NO-INDOOR") {
+                       flags = flags "\n\t\t\tNL80211_RRF_NO_INDOOR | "
+               } else if (flagarray[arg] == "NO-OUTDOOR") {
+                       flags = flags "\n\t\t\tNL80211_RRF_NO_OUTDOOR | "
+               } else if (flagarray[arg] == "DFS") {
+                       flags = flags "\n\t\t\tNL80211_RRF_DFS | "
+               } else if (flagarray[arg] == "PTP-ONLY") {
+                       flags = flags "\n\t\t\tNL80211_RRF_PTP_ONLY | "
+               } else if (flagarray[arg] == "PTMP-ONLY") {
+                       flags = flags "\n\t\t\tNL80211_RRF_PTMP_ONLY | "
+               } else if (flagarray[arg] == "PASSIVE-SCAN") {
+                       flags = flags "\n\t\t\tNL80211_RRF_PASSIVE_SCAN | "
+               } else if (flagarray[arg] == "NO-IBSS") {
+                       flags = flags "\n\t\t\tNL80211_RRF_NO_IBSS | "
+               }
+       }
+       flags = flags "0"
+       printf "\t\tREG_RULE(%d, %d, %d, %d, %d, %s),\n", start, end, bw, gain, power, flags
+       rules++
+}
+
+active && /^[ \t]*$/ {
+       active = 0
+       printf "\t},\n"
+       printf "\t.n_reg_rules = %d\n", rules
+       printf "};\n\n"
+       rules = 0;
+}
+
+END {
+       print regdb "};"
+       print ""
+       print "int reg_regdb_size = ARRAY_SIZE(reg_regdb);"
+}
index 82e6002c8d678654f2cdfd7c88baa4ee53586a0b..94d151f6f73e8539e1ab789b684da38c1833f9ac 100644 (file)
@@ -148,22 +148,23 @@ 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;
 
        ASSERT_WDEV_LOCK(wdev);
 
-       nl80211_send_deauth(rdev, dev, buf, len, GFP_KERNEL);
-
        if (wdev->current_bss &&
            memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) {
                cfg80211_unhold_bss(wdev->current_bss);
                cfg80211_put_bss(&wdev->current_bss->pub);
                wdev->current_bss = NULL;
+               found = 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) {
                        cfg80211_unhold_bss(wdev->auth_bsses[i]);
                        cfg80211_put_bss(&wdev->auth_bsses[i]->pub);
                        wdev->auth_bsses[i] = NULL;
+                       found = true;
                        break;
                }
                if (wdev->authtry_bsses[i] &&
@@ -171,10 +172,16 @@ void __cfg80211_send_deauth(struct net_device *dev,
                        cfg80211_unhold_bss(wdev->authtry_bsses[i]);
                        cfg80211_put_bss(&wdev->authtry_bsses[i]->pub);
                        wdev->authtry_bsses[i] = NULL;
+                       found = true;
                        break;
                }
        }
 
+       if (!found)
+               return;
+
+       nl80211_send_deauth(rdev, dev, buf, len, GFP_KERNEL);
+
        if (wdev->sme_state == CFG80211_SME_CONNECTED) {
                u16 reason_code;
                bool from_ap;
@@ -684,3 +691,40 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
                }
        }
 }
+
+void cfg80211_ready_on_channel(struct net_device *dev, u64 cookie,
+                              struct ieee80211_channel *chan,
+                              enum nl80211_channel_type channel_type,
+                              unsigned int duration, gfp_t gfp)
+{
+       struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+
+       nl80211_send_remain_on_channel(rdev, dev, cookie, chan, channel_type,
+                                      duration, gfp);
+}
+EXPORT_SYMBOL(cfg80211_ready_on_channel);
+
+void cfg80211_remain_on_channel_expired(struct net_device *dev,
+                                       u64 cookie,
+                                       struct ieee80211_channel *chan,
+                                       enum nl80211_channel_type channel_type,
+                                       gfp_t gfp)
+{
+       struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+
+       nl80211_send_remain_on_channel_cancel(rdev, dev, cookie, chan,
+                                             channel_type, gfp);
+}
+EXPORT_SYMBOL(cfg80211_remain_on_channel_expired);
+
+void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr,
+                     struct station_info *sinfo, gfp_t gfp)
+{
+       struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+
+       nl80211_send_sta_event(rdev, dev, mac_addr, sinfo, gfp);
+}
+EXPORT_SYMBOL(cfg80211_new_sta);
index a6028433e3a0f9583e48c5b2369abed53ed0ddd5..4af7991a9ec8745bc0adc42ec5357d76c1f38d86 100644 (file)
@@ -69,6 +69,7 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
        [NL80211_ATTR_WIPHY_RETRY_LONG] = { .type = NLA_U8 },
        [NL80211_ATTR_WIPHY_FRAG_THRESHOLD] = { .type = NLA_U32 },
        [NL80211_ATTR_WIPHY_RTS_THRESHOLD] = { .type = NLA_U32 },
+       [NL80211_ATTR_WIPHY_COVERAGE_CLASS] = { .type = NLA_U8 },
 
        [NL80211_ATTR_IFTYPE] = { .type = NLA_U32 },
        [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 },
@@ -141,6 +142,9 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
        [NL80211_ATTR_4ADDR] = { .type = NLA_U8 },
        [NL80211_ATTR_PMKID] = { .type = NLA_BINARY,
                                 .len = WLAN_PMKID_LEN },
+       [NL80211_ATTR_DURATION] = { .type = NLA_U32 },
+       [NL80211_ATTR_COOKIE] = { .type = NLA_U64 },
+       [NL80211_ATTR_TX_RATES] = { .type = NLA_NESTED },
 };
 
 /* policy for the attributes */
@@ -442,6 +446,8 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
                    dev->wiphy.frag_threshold);
        NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD,
                    dev->wiphy.rts_threshold);
+       NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_COVERAGE_CLASS,
+                   dev->wiphy.coverage_class);
 
        NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS,
                   dev->wiphy.max_scan_ssids);
@@ -569,6 +575,8 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
        CMD(set_pmksa, SET_PMKSA);
        CMD(del_pmksa, DEL_PMKSA);
        CMD(flush_pmksa, FLUSH_PMKSA);
+       CMD(remain_on_channel, REMAIN_ON_CHANNEL);
+       CMD(set_bitrate_mask, SET_TX_BITRATE_MASK);
        if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) {
                i++;
                NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS);
@@ -681,6 +689,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
        u32 changed;
        u8 retry_short = 0, retry_long = 0;
        u32 frag_threshold = 0, rts_threshold = 0;
+       u8 coverage_class = 0;
 
        rtnl_lock();
 
@@ -803,9 +812,16 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
                changed |= WIPHY_PARAM_RTS_THRESHOLD;
        }
 
+       if (info->attrs[NL80211_ATTR_WIPHY_COVERAGE_CLASS]) {
+               coverage_class = nla_get_u8(
+                       info->attrs[NL80211_ATTR_WIPHY_COVERAGE_CLASS]);
+               changed |= WIPHY_PARAM_COVERAGE_CLASS;
+       }
+
        if (changed) {
                u8 old_retry_short, old_retry_long;
                u32 old_frag_threshold, old_rts_threshold;
+               u8 old_coverage_class;
 
                if (!rdev->ops->set_wiphy_params) {
                        result = -EOPNOTSUPP;
@@ -816,6 +832,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
                old_retry_long = rdev->wiphy.retry_long;
                old_frag_threshold = rdev->wiphy.frag_threshold;
                old_rts_threshold = rdev->wiphy.rts_threshold;
+               old_coverage_class = rdev->wiphy.coverage_class;
 
                if (changed & WIPHY_PARAM_RETRY_SHORT)
                        rdev->wiphy.retry_short = retry_short;
@@ -825,6 +842,8 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
                        rdev->wiphy.frag_threshold = frag_threshold;
                if (changed & WIPHY_PARAM_RTS_THRESHOLD)
                        rdev->wiphy.rts_threshold = rts_threshold;
+               if (changed & WIPHY_PARAM_COVERAGE_CLASS)
+                       rdev->wiphy.coverage_class = coverage_class;
 
                result = rdev->ops->set_wiphy_params(&rdev->wiphy, changed);
                if (result) {
@@ -832,6 +851,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
                        rdev->wiphy.retry_long = old_retry_long;
                        rdev->wiphy.frag_threshold = old_frag_threshold;
                        rdev->wiphy.rts_threshold = old_rts_threshold;
+                       rdev->wiphy.coverage_class = old_coverage_class;
                }
        }
 
@@ -1637,42 +1657,9 @@ static int parse_station_flags(struct genl_info *info,
        return 0;
 }
 
-static u16 nl80211_calculate_bitrate(struct rate_info *rate)
-{
-       int modulation, streams, bitrate;
-
-       if (!(rate->flags & RATE_INFO_FLAGS_MCS))
-               return rate->legacy;
-
-       /* the formula below does only work for MCS values smaller than 32 */
-       if (rate->mcs >= 32)
-               return 0;
-
-       modulation = rate->mcs & 7;
-       streams = (rate->mcs >> 3) + 1;
-
-       bitrate = (rate->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH) ?
-                       13500000 : 6500000;
-
-       if (modulation < 4)
-               bitrate *= (modulation + 1);
-       else if (modulation == 4)
-               bitrate *= (modulation + 2);
-       else
-               bitrate *= (modulation + 3);
-
-       bitrate *= streams;
-
-       if (rate->flags & RATE_INFO_FLAGS_SHORT_GI)
-               bitrate = (bitrate / 9) * 10;
-
-       /* do NOT round down here */
-       return (bitrate + 50000) / 100000;
-}
-
 static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq,
                                int flags, struct net_device *dev,
-                               u8 *mac_addr, struct station_info *sinfo)
+                               const u8 *mac_addr, struct station_info *sinfo)
 {
        void *hdr;
        struct nlattr *sinfoattr, *txrate;
@@ -1716,8 +1703,8 @@ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq,
                if (!txrate)
                        goto nla_put_failure;
 
-               /* nl80211_calculate_bitrate will return 0 for mcs >= 32 */
-               bitrate = nl80211_calculate_bitrate(&sinfo->txrate);
+               /* cfg80211_calculate_bitrate will return 0 for mcs >= 32 */
+               bitrate = cfg80211_calculate_bitrate(&sinfo->txrate);
                if (bitrate > 0)
                        NLA_PUT_U16(msg, NL80211_RATE_INFO_BITRATE, bitrate);
 
@@ -2583,12 +2570,6 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
 
        data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]);
 
-#ifdef CONFIG_WIRELESS_OLD_REGULATORY
-       /* We ignore world regdom requests with the old regdom setup */
-       if (is_world_regdom(data))
-               return -EINVAL;
-#endif
-
        r = regulatory_hint_user(data);
 
        return r;
@@ -3182,6 +3163,10 @@ static int nl80211_send_bss(struct sk_buff *msg, u32 pid, u32 seq, int flags,
                NLA_PUT(msg, NL80211_BSS_INFORMATION_ELEMENTS,
                        res->len_information_elements,
                        res->information_elements);
+       if (res->beacon_ies && res->len_beacon_ies &&
+           res->beacon_ies != res->information_elements)
+               NLA_PUT(msg, NL80211_BSS_BEACON_IES,
+                       res->len_beacon_ies, res->beacon_ies);
        if (res->tsf)
                NLA_PUT_U64(msg, NL80211_BSS_TSF, res->tsf);
        if (res->beacon_interval)
@@ -4322,6 +4307,246 @@ static int nl80211_flush_pmksa(struct sk_buff *skb, struct genl_info *info)
 
 }
 
+static int nl80211_remain_on_channel(struct sk_buff *skb,
+                                    struct genl_info *info)
+{
+       struct cfg80211_registered_device *rdev;
+       struct net_device *dev;
+       struct ieee80211_channel *chan;
+       struct sk_buff *msg;
+       void *hdr;
+       u64 cookie;
+       enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
+       u32 freq, duration;
+       int err;
+
+       if (!info->attrs[NL80211_ATTR_WIPHY_FREQ] ||
+           !info->attrs[NL80211_ATTR_DURATION])
+               return -EINVAL;
+
+       duration = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]);
+
+       /*
+        * We should be on that channel for at least one jiffie,
+        * and more than 5 seconds seems excessive.
+        */
+       if (!duration || !msecs_to_jiffies(duration) || duration > 5000)
+               return -EINVAL;
+
+       rtnl_lock();
+
+       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
+       if (err)
+               goto unlock_rtnl;
+
+       if (!rdev->ops->remain_on_channel) {
+               err = -EOPNOTSUPP;
+               goto out;
+       }
+
+       if (!netif_running(dev)) {
+               err = -ENETDOWN;
+               goto out;
+       }
+
+       if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
+               channel_type = nla_get_u32(
+                       info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
+               if (channel_type != NL80211_CHAN_NO_HT &&
+                   channel_type != NL80211_CHAN_HT20 &&
+                   channel_type != NL80211_CHAN_HT40PLUS &&
+                   channel_type != NL80211_CHAN_HT40MINUS)
+                       err = -EINVAL;
+                       goto out;
+       }
+
+       freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
+       chan = rdev_freq_to_chan(rdev, freq, channel_type);
+       if (chan == NULL) {
+               err = -EINVAL;
+               goto out;
+       }
+
+       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+       if (!msg) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
+                            NL80211_CMD_REMAIN_ON_CHANNEL);
+
+       if (IS_ERR(hdr)) {
+               err = PTR_ERR(hdr);
+               goto free_msg;
+       }
+
+       err = rdev->ops->remain_on_channel(&rdev->wiphy, dev, chan,
+                                          channel_type, duration, &cookie);
+
+       if (err)
+               goto free_msg;
+
+       NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie);
+
+       genlmsg_end(msg, hdr);
+       err = genlmsg_reply(msg, info);
+       goto out;
+
+ nla_put_failure:
+       err = -ENOBUFS;
+ free_msg:
+       nlmsg_free(msg);
+ out:
+       cfg80211_unlock_rdev(rdev);
+       dev_put(dev);
+ unlock_rtnl:
+       rtnl_unlock();
+       return err;
+}
+
+static int nl80211_cancel_remain_on_channel(struct sk_buff *skb,
+                                           struct genl_info *info)
+{
+       struct cfg80211_registered_device *rdev;
+       struct net_device *dev;
+       u64 cookie;
+       int err;
+
+       if (!info->attrs[NL80211_ATTR_COOKIE])
+               return -EINVAL;
+
+       rtnl_lock();
+
+       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
+       if (err)
+               goto unlock_rtnl;
+
+       if (!rdev->ops->cancel_remain_on_channel) {
+               err = -EOPNOTSUPP;
+               goto out;
+       }
+
+       if (!netif_running(dev)) {
+               err = -ENETDOWN;
+               goto out;
+       }
+
+       cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]);
+
+       err = rdev->ops->cancel_remain_on_channel(&rdev->wiphy, dev, cookie);
+
+ out:
+       cfg80211_unlock_rdev(rdev);
+       dev_put(dev);
+ unlock_rtnl:
+       rtnl_unlock();
+       return err;
+}
+
+static u32 rateset_to_mask(struct ieee80211_supported_band *sband,
+                          u8 *rates, u8 rates_len)
+{
+       u8 i;
+       u32 mask = 0;
+
+       for (i = 0; i < rates_len; i++) {
+               int rate = (rates[i] & 0x7f) * 5;
+               int ridx;
+               for (ridx = 0; ridx < sband->n_bitrates; ridx++) {
+                       struct ieee80211_rate *srate =
+                               &sband->bitrates[ridx];
+                       if (rate == srate->bitrate) {
+                               mask |= 1 << ridx;
+                               break;
+                       }
+               }
+               if (ridx == sband->n_bitrates)
+                       return 0; /* rate not found */
+       }
+
+       return mask;
+}
+
+static struct nla_policy
+nl80211_txattr_policy[NL80211_TXRATE_MAX + 1] __read_mostly = {
+       [NL80211_TXRATE_LEGACY] = { .type = NLA_BINARY,
+                                   .len = NL80211_MAX_SUPP_RATES },
+};
+
+static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb,
+                                      struct genl_info *info)
+{
+       struct nlattr *tb[NL80211_TXRATE_MAX + 1];
+       struct cfg80211_registered_device *rdev;
+       struct cfg80211_bitrate_mask mask;
+       int err, rem, i;
+       struct net_device *dev;
+       struct nlattr *tx_rates;
+       struct ieee80211_supported_band *sband;
+
+       if (info->attrs[NL80211_ATTR_TX_RATES] == NULL)
+               return -EINVAL;
+
+       rtnl_lock();
+
+       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
+       if (err)
+               goto unlock_rtnl;
+
+       if (!rdev->ops->set_bitrate_mask) {
+               err = -EOPNOTSUPP;
+               goto unlock;
+       }
+
+       memset(&mask, 0, sizeof(mask));
+       /* Default to all rates enabled */
+       for (i = 0; i < IEEE80211_NUM_BANDS; i++) {
+               sband = rdev->wiphy.bands[i];
+               mask.control[i].legacy =
+                       sband ? (1 << sband->n_bitrates) - 1 : 0;
+       }
+
+       /*
+        * The nested attribute uses enum nl80211_band as the index. This maps
+        * directly to the enum ieee80211_band values used in cfg80211.
+        */
+       nla_for_each_nested(tx_rates, info->attrs[NL80211_ATTR_TX_RATES], rem)
+       {
+               enum ieee80211_band band = nla_type(tx_rates);
+               if (band < 0 || band >= IEEE80211_NUM_BANDS) {
+                       err = -EINVAL;
+                       goto unlock;
+               }
+               sband = rdev->wiphy.bands[band];
+               if (sband == NULL) {
+                       err = -EINVAL;
+                       goto unlock;
+               }
+               nla_parse(tb, NL80211_TXRATE_MAX, nla_data(tx_rates),
+                         nla_len(tx_rates), nl80211_txattr_policy);
+               if (tb[NL80211_TXRATE_LEGACY]) {
+                       mask.control[band].legacy = rateset_to_mask(
+                               sband,
+                               nla_data(tb[NL80211_TXRATE_LEGACY]),
+                               nla_len(tb[NL80211_TXRATE_LEGACY]));
+                       if (mask.control[band].legacy == 0) {
+                               err = -EINVAL;
+                               goto unlock;
+                       }
+               }
+       }
+
+       err = rdev->ops->set_bitrate_mask(&rdev->wiphy, dev, NULL, &mask);
+
+ unlock:
+       dev_put(dev);
+       cfg80211_unlock_rdev(rdev);
+ unlock_rtnl:
+       rtnl_unlock();
+       return err;
+}
+
 static struct genl_ops nl80211_ops[] = {
        {
                .cmd = NL80211_CMD_GET_WIPHY,
@@ -4584,8 +4809,26 @@ static struct genl_ops nl80211_ops[] = {
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
        },
-
+       {
+               .cmd = NL80211_CMD_REMAIN_ON_CHANNEL,
+               .doit = nl80211_remain_on_channel,
+               .policy = nl80211_policy,
+               .flags = GENL_ADMIN_PERM,
+       },
+       {
+               .cmd = NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL,
+               .doit = nl80211_cancel_remain_on_channel,
+               .policy = nl80211_policy,
+               .flags = GENL_ADMIN_PERM,
+       },
+       {
+               .cmd = NL80211_CMD_SET_TX_BITRATE_MASK,
+               .doit = nl80211_set_tx_bitrate_mask,
+               .policy = nl80211_policy,
+               .flags = GENL_ADMIN_PERM,
+       },
 };
+
 static struct genl_multicast_group nl80211_mlme_mcgrp = {
        .name = "mlme",
 };
@@ -5173,6 +5416,89 @@ nla_put_failure:
        nlmsg_free(msg);
 }
 
+static void nl80211_send_remain_on_chan_event(
+       int cmd, struct cfg80211_registered_device *rdev,
+       struct net_device *netdev, u64 cookie,
+       struct ieee80211_channel *chan,
+       enum nl80211_channel_type channel_type,
+       unsigned int duration, gfp_t gfp)
+{
+       struct sk_buff *msg;
+       void *hdr;
+
+       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
+       if (!msg)
+               return;
+
+       hdr = nl80211hdr_put(msg, 0, 0, 0, cmd);
+       if (!hdr) {
+               nlmsg_free(msg);
+               return;
+       }
+
+       NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
+       NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, chan->center_freq);
+       NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, channel_type);
+       NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie);
+
+       if (cmd == NL80211_CMD_REMAIN_ON_CHANNEL)
+               NLA_PUT_U32(msg, NL80211_ATTR_DURATION, duration);
+
+       if (genlmsg_end(msg, hdr) < 0) {
+               nlmsg_free(msg);
+               return;
+       }
+
+       genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+                               nl80211_mlme_mcgrp.id, gfp);
+       return;
+
+ nla_put_failure:
+       genlmsg_cancel(msg, hdr);
+       nlmsg_free(msg);
+}
+
+void nl80211_send_remain_on_channel(struct cfg80211_registered_device *rdev,
+                                   struct net_device *netdev, u64 cookie,
+                                   struct ieee80211_channel *chan,
+                                   enum nl80211_channel_type channel_type,
+                                   unsigned int duration, gfp_t gfp)
+{
+       nl80211_send_remain_on_chan_event(NL80211_CMD_REMAIN_ON_CHANNEL,
+                                         rdev, netdev, cookie, chan,
+                                         channel_type, duration, gfp);
+}
+
+void nl80211_send_remain_on_channel_cancel(
+       struct cfg80211_registered_device *rdev, struct net_device *netdev,
+       u64 cookie, struct ieee80211_channel *chan,
+       enum nl80211_channel_type channel_type, gfp_t gfp)
+{
+       nl80211_send_remain_on_chan_event(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL,
+                                         rdev, netdev, cookie, chan,
+                                         channel_type, 0, gfp);
+}
+
+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)
+{
+       struct sk_buff *msg;
+
+       msg = nlmsg_new(NLMSG_GOODSIZE, gfp);
+       if (!msg)
+               return;
+
+       if (nl80211_send_station(msg, 0, 0, 0, dev, mac_addr, sinfo) < 0) {
+               nlmsg_free(msg);
+               return;
+       }
+
+       genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+                               nl80211_mlme_mcgrp.id, gfp);
+}
+
 /* initialisation/exit functions */
 
 int nl80211_init(void)
index 44cc2a76a1b094149d6f292fd337512d157465e9..14855b8fb4303945a06e20045a6c31a2f1a51488 100644 (file)
@@ -59,4 +59,19 @@ void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev,
                             struct net_device *netdev, const u8 *bssid,
                             gfp_t gfp);
 
+void nl80211_send_remain_on_channel(struct cfg80211_registered_device *rdev,
+                                   struct net_device *netdev,
+                                   u64 cookie,
+                                   struct ieee80211_channel *chan,
+                                   enum nl80211_channel_type channel_type,
+                                   unsigned int duration, gfp_t gfp);
+void nl80211_send_remain_on_channel_cancel(
+       struct cfg80211_registered_device *rdev, struct net_device *netdev,
+       u64 cookie, struct ieee80211_channel *chan,
+       enum nl80211_channel_type channel_type, gfp_t gfp);
+
+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);
+
 #endif /* __NET_WIRELESS_NL80211_H */
index 7a0754c92df4702ed1c72c2cdb10945dd1eb56fd..5f8071de7950d5f769d2d8a5a0f8179101f95bb3 100644 (file)
 #include <net/cfg80211.h>
 #include "core.h"
 #include "reg.h"
+#include "regdb.h"
 #include "nl80211.h"
 
+#ifdef CONFIG_CFG80211_REG_DEBUG
+#define REG_DBG_PRINT(format, args...) \
+       do { \
+               printk(KERN_DEBUG format , ## args); \
+       } while (0)
+#else
+#define REG_DBG_PRINT(args...)
+#endif
+
 /* Receipt of information from last regulatory request */
 static struct regulatory_request *last_request;
 
@@ -128,78 +138,6 @@ static char *ieee80211_regdom = "00";
 module_param(ieee80211_regdom, charp, 0444);
 MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code");
 
-#ifdef CONFIG_WIRELESS_OLD_REGULATORY
-/*
- * We assume 40 MHz bandwidth for the old regulatory work.
- * We make emphasis we are using the exact same frequencies
- * as before
- */
-
-static const struct ieee80211_regdomain us_regdom = {
-       .n_reg_rules = 6,
-       .alpha2 =  "US",
-       .reg_rules = {
-               /* IEEE 802.11b/g, channels 1..11 */
-               REG_RULE(2412-10, 2462+10, 40, 6, 27, 0),
-               /* IEEE 802.11a, channel 36..48 */
-               REG_RULE(5180-10, 5240+10, 40, 6, 17, 0),
-               /* IEEE 802.11a, channels 48..64 */
-               REG_RULE(5260-10, 5320+10, 40, 6, 20, NL80211_RRF_DFS),
-               /* IEEE 802.11a, channels 100..124 */
-               REG_RULE(5500-10, 5590+10, 40, 6, 20, NL80211_RRF_DFS),
-               /* IEEE 802.11a, channels 132..144 */
-               REG_RULE(5660-10, 5700+10, 40, 6, 20, NL80211_RRF_DFS),
-               /* IEEE 802.11a, channels 149..165, outdoor */
-               REG_RULE(5745-10, 5825+10, 40, 6, 30, 0),
-       }
-};
-
-static const struct ieee80211_regdomain jp_regdom = {
-       .n_reg_rules = 6,
-       .alpha2 =  "JP",
-       .reg_rules = {
-               /* IEEE 802.11b/g, channels 1..11 */
-               REG_RULE(2412-10, 2462+10, 40, 6, 20, 0),
-               /* IEEE 802.11b/g, channels 12..13 */
-               REG_RULE(2467-10, 2472+10, 20, 6, 20, 0),
-               /* IEEE 802.11b/g, channel 14 */
-               REG_RULE(2484-10, 2484+10, 20, 6, 20, NL80211_RRF_NO_OFDM),
-               /* IEEE 802.11a, channels 36..48 */
-               REG_RULE(5180-10, 5240+10, 40, 6, 20, 0),
-               /* IEEE 802.11a, channels 52..64 */
-               REG_RULE(5260-10, 5320+10, 40, 6, 20, NL80211_RRF_DFS),
-               /* IEEE 802.11a, channels 100..144 */
-               REG_RULE(5500-10, 5700+10, 40, 6, 23, NL80211_RRF_DFS),
-       }
-};
-
-static const struct ieee80211_regdomain *static_regdom(char *alpha2)
-{
-       if (alpha2[0] == 'U' && alpha2[1] == 'S')
-               return &us_regdom;
-       if (alpha2[0] == 'J' && alpha2[1] == 'P')
-               return &jp_regdom;
-       /* Use world roaming rules for "EU", since it was a pseudo
-          domain anyway... */
-       if (alpha2[0] == 'E' && alpha2[1] == 'U')
-               return &world_regdom;
-       /* Default, world roaming rules */
-       return &world_regdom;
-}
-
-static bool is_old_static_regdom(const struct ieee80211_regdomain *rd)
-{
-       if (rd == &us_regdom || rd == &jp_regdom || rd == &world_regdom)
-               return true;
-       return false;
-}
-#else
-static inline bool is_old_static_regdom(const struct ieee80211_regdomain *rd)
-{
-       return false;
-}
-#endif
-
 static void reset_regdomains(void)
 {
        /* avoid freeing static information or freeing something twice */
@@ -209,8 +147,6 @@ static void reset_regdomains(void)
                cfg80211_world_regdom = NULL;
        if (cfg80211_regdomain == &world_regdom)
                cfg80211_regdomain = NULL;
-       if (is_old_static_regdom(cfg80211_regdomain))
-               cfg80211_regdomain = NULL;
 
        kfree(cfg80211_regdomain);
        kfree(cfg80211_world_regdom);
@@ -335,6 +271,98 @@ static bool country_ie_integrity_changes(u32 checksum)
        return false;
 }
 
+static int reg_copy_regd(const struct ieee80211_regdomain **dst_regd,
+                        const struct ieee80211_regdomain *src_regd)
+{
+       struct ieee80211_regdomain *regd;
+       int size_of_regd = 0;
+       unsigned int i;
+
+       size_of_regd = sizeof(struct ieee80211_regdomain) +
+         ((src_regd->n_reg_rules + 1) * sizeof(struct ieee80211_reg_rule));
+
+       regd = kzalloc(size_of_regd, GFP_KERNEL);
+       if (!regd)
+               return -ENOMEM;
+
+       memcpy(regd, src_regd, sizeof(struct ieee80211_regdomain));
+
+       for (i = 0; i < src_regd->n_reg_rules; i++)
+               memcpy(&regd->reg_rules[i], &src_regd->reg_rules[i],
+                       sizeof(struct ieee80211_reg_rule));
+
+       *dst_regd = regd;
+       return 0;
+}
+
+#ifdef CONFIG_CFG80211_INTERNAL_REGDB
+struct reg_regdb_search_request {
+       char alpha2[2];
+       struct list_head list;
+};
+
+static LIST_HEAD(reg_regdb_search_list);
+static DEFINE_SPINLOCK(reg_regdb_search_lock);
+
+static void reg_regdb_search(struct work_struct *work)
+{
+       struct reg_regdb_search_request *request;
+       const struct ieee80211_regdomain *curdom, *regdom;
+       int i, r;
+
+       spin_lock(&reg_regdb_search_lock);
+       while (!list_empty(&reg_regdb_search_list)) {
+               request = list_first_entry(&reg_regdb_search_list,
+                                          struct reg_regdb_search_request,
+                                          list);
+               list_del(&request->list);
+
+               for (i=0; i<reg_regdb_size; i++) {
+                       curdom = reg_regdb[i];
+
+                       if (!memcmp(request->alpha2, curdom->alpha2, 2)) {
+                               r = reg_copy_regd(&regdom, curdom);
+                               if (r)
+                                       break;
+                               spin_unlock(&reg_regdb_search_lock);
+                               mutex_lock(&cfg80211_mutex);
+                               set_regdom(regdom);
+                               mutex_unlock(&cfg80211_mutex);
+                               spin_lock(&reg_regdb_search_lock);
+                               break;
+                       }
+               }
+
+               kfree(request);
+       }
+       spin_unlock(&reg_regdb_search_lock);
+}
+
+static DECLARE_WORK(reg_regdb_work, reg_regdb_search);
+
+static void reg_regdb_query(const char *alpha2)
+{
+       struct reg_regdb_search_request *request;
+
+       if (!alpha2)
+               return;
+
+       request = kzalloc(sizeof(struct reg_regdb_search_request), GFP_KERNEL);
+       if (!request)
+               return;
+
+       memcpy(request->alpha2, alpha2, 2);
+
+       spin_lock(&reg_regdb_search_lock);
+       list_add_tail(&request->list, &reg_regdb_search_list);
+       spin_unlock(&reg_regdb_search_lock);
+
+       schedule_work(&reg_regdb_work);
+}
+#else
+static inline void reg_regdb_query(const char *alpha2) {}
+#endif /* CONFIG_CFG80211_INTERNAL_REGDB */
+
 /*
  * This lets us keep regulatory code which is updated on a regulatory
  * basis in userspace.
@@ -354,6 +382,9 @@ static int call_crda(const char *alpha2)
                printk(KERN_INFO "cfg80211: Calling CRDA to update world "
                        "regulatory domain\n");
 
+       /* query internal regulatory database (if it exists) */
+       reg_regdb_query(alpha2);
+
        country_env[8] = alpha2[0];
        country_env[9] = alpha2[1];
 
@@ -453,6 +484,205 @@ static bool freq_in_rule_band(const struct ieee80211_freq_range *freq_range,
 #undef ONE_GHZ_IN_KHZ
 }
 
+/*
+ * This is a work around for sanity checking ieee80211_channel_to_frequency()'s
+ * work. ieee80211_channel_to_frequency() can for example currently provide a
+ * 2 GHz channel when in fact a 5 GHz channel was desired. An example would be
+ * an AP providing channel 8 on a country IE triplet when it sent this on the
+ * 5 GHz band, that channel is designed to be channel 8 on 5 GHz, not a 2 GHz
+ * channel.
+ *
+ * This can be removed once ieee80211_channel_to_frequency() takes in a band.
+ */
+static bool chan_in_band(int chan, enum ieee80211_band band)
+{
+       int center_freq = ieee80211_channel_to_frequency(chan);
+
+       switch (band) {
+       case IEEE80211_BAND_2GHZ:
+               if (center_freq <= 2484)
+                       return true;
+               return false;
+       case IEEE80211_BAND_5GHZ:
+               if (center_freq >= 5005)
+                       return true;
+               return false;
+       default:
+               return false;
+       }
+}
+
+/*
+ * Some APs may send a country IE triplet for each channel they
+ * support and while this is completely overkill and silly we still
+ * need to support it. We avoid making a single rule for each channel
+ * though and to help us with this we use this helper to find the
+ * actual subband end channel. These type of country IE triplet
+ * scenerios are handled then, all yielding two regulaotry rules from
+ * parsing a country IE:
+ *
+ * [1]
+ * [2]
+ * [36]
+ * [40]
+ *
+ * [1]
+ * [2-4]
+ * [5-12]
+ * [36]
+ * [40-44]
+ *
+ * [1-4]
+ * [5-7]
+ * [36-44]
+ * [48-64]
+ *
+ * [36-36]
+ * [40-40]
+ * [44-44]
+ * [48-48]
+ * [52-52]
+ * [56-56]
+ * [60-60]
+ * [64-64]
+ * [100-100]
+ * [104-104]
+ * [108-108]
+ * [112-112]
+ * [116-116]
+ * [120-120]
+ * [124-124]
+ * [128-128]
+ * [132-132]
+ * [136-136]
+ * [140-140]
+ *
+ * Returns 0 if the IE has been found to be invalid in the middle
+ * somewhere.
+ */
+static int max_subband_chan(enum ieee80211_band band,
+                           int orig_cur_chan,
+                           int orig_end_channel,
+                           s8 orig_max_power,
+                           u8 **country_ie,
+                           u8 *country_ie_len)
+{
+       u8 *triplets_start = *country_ie;
+       u8 len_at_triplet = *country_ie_len;
+       int end_subband_chan = orig_end_channel;
+
+       /*
+        * We'll deal with padding for the caller unless
+        * its not immediate and we don't process any channels
+        */
+       if (*country_ie_len == 1) {
+               *country_ie += 1;
+               *country_ie_len -= 1;
+               return orig_end_channel;
+       }
+
+       /* Move to the next triplet and then start search */
+       *country_ie += 3;
+       *country_ie_len -= 3;
+
+       if (!chan_in_band(orig_cur_chan, band))
+               return 0;
+
+       while (*country_ie_len >= 3) {
+               int end_channel = 0;
+               struct ieee80211_country_ie_triplet *triplet =
+                       (struct ieee80211_country_ie_triplet *) *country_ie;
+               int cur_channel = 0, next_expected_chan;
+
+               /* means last triplet is completely unrelated to this one */
+               if (triplet->ext.reg_extension_id >=
+                               IEEE80211_COUNTRY_EXTENSION_ID) {
+                       *country_ie -= 3;
+                       *country_ie_len += 3;
+                       break;
+               }
+
+               if (triplet->chans.first_channel == 0) {
+                       *country_ie += 1;
+                       *country_ie_len -= 1;
+                       if (*country_ie_len != 0)
+                               return 0;
+                       break;
+               }
+
+               if (triplet->chans.num_channels == 0)
+                       return 0;
+
+               /* Monitonically increasing channel order */
+               if (triplet->chans.first_channel <= end_subband_chan)
+                       return 0;
+
+               if (!chan_in_band(triplet->chans.first_channel, band))
+                       return 0;
+
+               /* 2 GHz */
+               if (triplet->chans.first_channel <= 14) {
+                       end_channel = triplet->chans.first_channel +
+                               triplet->chans.num_channels - 1;
+               }
+               else {
+                       end_channel =  triplet->chans.first_channel +
+                               (4 * (triplet->chans.num_channels - 1));
+               }
+
+               if (!chan_in_band(end_channel, band))
+                       return 0;
+
+               if (orig_max_power != triplet->chans.max_power) {
+                       *country_ie -= 3;
+                       *country_ie_len += 3;
+                       break;
+               }
+
+               cur_channel = triplet->chans.first_channel;
+
+               /* The key is finding the right next expected channel */
+               if (band == IEEE80211_BAND_2GHZ)
+                       next_expected_chan = end_subband_chan + 1;
+                else
+                       next_expected_chan = end_subband_chan + 4;
+
+               if (cur_channel != next_expected_chan) {
+                       *country_ie -= 3;
+                       *country_ie_len += 3;
+                       break;
+               }
+
+               end_subband_chan = end_channel;
+
+               /* Move to the next one */
+               *country_ie += 3;
+               *country_ie_len -= 3;
+
+               /*
+                * Padding needs to be dealt with if we processed
+                * some channels.
+                */
+               if (*country_ie_len == 1) {
+                       *country_ie += 1;
+                       *country_ie_len -= 1;
+                       break;
+               }
+
+               /* If seen, the IE is invalid */
+               if (*country_ie_len == 2)
+                       return 0;
+       }
+
+       if (end_subband_chan == orig_end_channel) {
+               *country_ie = triplets_start;
+               *country_ie_len = len_at_triplet;
+               return orig_end_channel;
+       }
+
+       return end_subband_chan;
+}
+
 /*
  * Converts a country IE to a regulatory domain. A regulatory domain
  * structure has a lot of information which the IE doesn't yet have,
@@ -460,6 +690,7 @@ static bool freq_in_rule_band(const struct ieee80211_freq_range *freq_range,
  * with our userspace regulatory agent to get lower bounds.
  */
 static struct ieee80211_regdomain *country_ie_2_rd(
+                               enum ieee80211_band band,
                                u8 *country_ie,
                                u8 country_ie_len,
                                u32 *checksum)
@@ -521,10 +752,29 @@ static struct ieee80211_regdomain *country_ie_2_rd(
                        continue;
                }
 
+               /*
+                * APs can add padding to make length divisible
+                * by two, required by the spec.
+                */
+               if (triplet->chans.first_channel == 0) {
+                       country_ie++;
+                       country_ie_len--;
+                       /* This is expected to be at the very end only */
+                       if (country_ie_len != 0)
+                               return NULL;
+                       break;
+               }
+
+               if (triplet->chans.num_channels == 0)
+                       return NULL;
+
+               if (!chan_in_band(triplet->chans.first_channel, band))
+                       return NULL;
+
                /* 2 GHz */
-               if (triplet->chans.first_channel <= 14)
+               if (band == IEEE80211_BAND_2GHZ)
                        end_channel = triplet->chans.first_channel +
-                               triplet->chans.num_channels;
+                               triplet->chans.num_channels - 1;
                else
                        /*
                         * 5 GHz -- For example in country IEs if the first
@@ -539,6 +789,24 @@ static struct ieee80211_regdomain *country_ie_2_rd(
                                (4 * (triplet->chans.num_channels - 1));
 
                cur_channel = triplet->chans.first_channel;
+
+               /*
+                * Enhancement for APs that send a triplet for every channel
+                * or for whatever reason sends triplets with multiple channels
+                * separated when in fact they should be together.
+                */
+               end_channel = max_subband_chan(band,
+                                              cur_channel,
+                                              end_channel,
+                                              triplet->chans.max_power,
+                                              &country_ie,
+                                              &country_ie_len);
+               if (!end_channel)
+                       return NULL;
+
+               if (!chan_in_band(end_channel, band))
+                       return NULL;
+
                cur_sub_max_channel = end_channel;
 
                /* Basic sanity check */
@@ -569,10 +837,13 @@ static struct ieee80211_regdomain *country_ie_2_rd(
 
                last_sub_max_channel = cur_sub_max_channel;
 
-               country_ie += 3;
-               country_ie_len -= 3;
                num_rules++;
 
+               if (country_ie_len >= 3) {
+                       country_ie += 3;
+                       country_ie_len -= 3;
+               }
+
                /*
                 * Note: this is not a IEEE requirement but
                 * simply a memory requirement
@@ -615,6 +886,12 @@ static struct ieee80211_regdomain *country_ie_2_rd(
                        continue;
                }
 
+               if (triplet->chans.first_channel == 0) {
+                       country_ie++;
+                       country_ie_len--;
+                       break;
+               }
+
                reg_rule = &rd->reg_rules[i];
                freq_range = &reg_rule->freq_range;
                power_rule = &reg_rule->power_rule;
@@ -622,13 +899,20 @@ static struct ieee80211_regdomain *country_ie_2_rd(
                reg_rule->flags = flags;
 
                /* 2 GHz */
-               if (triplet->chans.first_channel <= 14)
+               if (band == IEEE80211_BAND_2GHZ)
                        end_channel = triplet->chans.first_channel +
-                               triplet->chans.num_channels;
+                               triplet->chans.num_channels -1;
                else
                        end_channel =  triplet->chans.first_channel +
                                (4 * (triplet->chans.num_channels - 1));
 
+               end_channel = max_subband_chan(band,
+                                              triplet->chans.first_channel,
+                                              end_channel,
+                                              triplet->chans.max_power,
+                                              &country_ie,
+                                              &country_ie_len);
+
                /*
                 * The +10 is since the regulatory domain expects
                 * the actual band edge, not the center of freq for
@@ -649,12 +933,15 @@ static struct ieee80211_regdomain *country_ie_2_rd(
                 */
                freq_range->max_bandwidth_khz = MHZ_TO_KHZ(40);
                power_rule->max_antenna_gain = DBI_TO_MBI(100);
-               power_rule->max_eirp = DBM_TO_MBM(100);
+               power_rule->max_eirp = DBM_TO_MBM(triplet->chans.max_power);
 
-               country_ie += 3;
-               country_ie_len -= 3;
                i++;
 
+               if (country_ie_len >= 3) {
+                       country_ie += 3;
+                       country_ie_len -= 3;
+               }
+
                BUG_ON(i > NL80211_MAX_SUPP_REG_RULES);
        }
 
@@ -950,25 +1237,21 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band,
                if (r == -ERANGE &&
                    last_request->initiator ==
                    NL80211_REGDOM_SET_BY_COUNTRY_IE) {
-#ifdef CONFIG_CFG80211_REG_DEBUG
-                       printk(KERN_DEBUG "cfg80211: Leaving channel %d MHz "
+                       REG_DBG_PRINT("cfg80211: Leaving channel %d MHz "
                                "intact on %s - no rule found in band on "
                                "Country IE\n",
-                               chan->center_freq, wiphy_name(wiphy));
-#endif
+                       chan->center_freq, wiphy_name(wiphy));
                } else {
                /*
                 * In this case we know the country IE has at least one reg rule
                 * for the band so we respect its band definitions
                 */
-#ifdef CONFIG_CFG80211_REG_DEBUG
                        if (last_request->initiator ==
                            NL80211_REGDOM_SET_BY_COUNTRY_IE)
-                               printk(KERN_DEBUG "cfg80211: Disabling "
+                               REG_DBG_PRINT("cfg80211: Disabling "
                                        "channel %d MHz on %s due to "
                                        "Country IE\n",
                                        chan->center_freq, wiphy_name(wiphy));
-#endif
                        flags |= IEEE80211_CHAN_DISABLED;
                        chan->flags = flags;
                }
@@ -1342,30 +1625,6 @@ void wiphy_apply_custom_regulatory(struct wiphy *wiphy,
 }
 EXPORT_SYMBOL(wiphy_apply_custom_regulatory);
 
-static int reg_copy_regd(const struct ieee80211_regdomain **dst_regd,
-                        const struct ieee80211_regdomain *src_regd)
-{
-       struct ieee80211_regdomain *regd;
-       int size_of_regd = 0;
-       unsigned int i;
-
-       size_of_regd = sizeof(struct ieee80211_regdomain) +
-         ((src_regd->n_reg_rules + 1) * sizeof(struct ieee80211_reg_rule));
-
-       regd = kzalloc(size_of_regd, GFP_KERNEL);
-       if (!regd)
-               return -ENOMEM;
-
-       memcpy(regd, src_regd, sizeof(struct ieee80211_regdomain));
-
-       for (i = 0; i < src_regd->n_reg_rules; i++)
-               memcpy(&regd->reg_rules[i], &src_regd->reg_rules[i],
-                       sizeof(struct ieee80211_reg_rule));
-
-       *dst_regd = regd;
-       return 0;
-}
-
 /*
  * Return value which can be used by ignore_request() to indicate
  * it has been determined we should intersect two regulatory domains
@@ -1418,8 +1677,6 @@ static int ignore_request(struct wiphy *wiphy,
                return REG_INTERSECT;
        case NL80211_REGDOM_SET_BY_DRIVER:
                if (last_request->initiator == NL80211_REGDOM_SET_BY_CORE) {
-                       if (is_old_static_regdom(cfg80211_regdomain))
-                               return 0;
                        if (regdom_changes(pending_request->alpha2))
                                return 0;
                        return -EALREADY;
@@ -1456,8 +1713,7 @@ static int ignore_request(struct wiphy *wiphy,
                                return -EAGAIN;
                }
 
-               if (!is_old_static_regdom(cfg80211_regdomain) &&
-                   !regdom_changes(pending_request->alpha2))
+               if (!regdom_changes(pending_request->alpha2))
                        return -EALREADY;
 
                return 0;
@@ -1758,8 +2014,9 @@ static bool reg_same_country_ie_hint(struct wiphy *wiphy,
  * therefore cannot iterate over the rdev list here.
  */
 void regulatory_hint_11d(struct wiphy *wiphy,
-                       u8 *country_ie,
-                       u8 country_ie_len)
+                        enum ieee80211_band band,
+                        u8 *country_ie,
+                        u8 country_ie_len)
 {
        struct ieee80211_regdomain *rd = NULL;
        char alpha2[2];
@@ -1805,9 +2062,11 @@ void regulatory_hint_11d(struct wiphy *wiphy,
            wiphy_idx_valid(last_request->wiphy_idx)))
                goto out;
 
-       rd = country_ie_2_rd(country_ie, country_ie_len, &checksum);
-       if (!rd)
+       rd = country_ie_2_rd(band, country_ie, country_ie_len, &checksum);
+       if (!rd) {
+               REG_DBG_PRINT("cfg80211: Ignoring bogus country IE\n");
                goto out;
+       }
 
        /*
         * This will not happen right now but we leave it here for the
@@ -1875,13 +2134,12 @@ int regulatory_hint_found_beacon(struct wiphy *wiphy,
        if (!reg_beacon)
                return -ENOMEM;
 
-#ifdef CONFIG_CFG80211_REG_DEBUG
-       printk(KERN_DEBUG "cfg80211: Found new beacon on "
-               "frequency: %d MHz (Ch %d) on %s\n",
-               beacon_chan->center_freq,
-               ieee80211_frequency_to_channel(beacon_chan->center_freq),
-               wiphy_name(wiphy));
-#endif
+       REG_DBG_PRINT("cfg80211: Found new beacon on "
+                     "frequency: %d MHz (Ch %d) on %s\n",
+                     beacon_chan->center_freq,
+                     ieee80211_frequency_to_channel(beacon_chan->center_freq),
+                     wiphy_name(wiphy));
+
        memcpy(&reg_beacon->chan, beacon_chan,
                sizeof(struct ieee80211_channel));
 
@@ -2039,8 +2297,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
                 * If someone else asked us to change the rd lets only bother
                 * checking if the alpha2 changes if CRDA was already called
                 */
-               if (!is_old_static_regdom(cfg80211_regdomain) &&
-                   !regdom_changes(rd->alpha2))
+               if (!regdom_changes(rd->alpha2))
                        return -EINVAL;
        }
 
@@ -2239,15 +2496,8 @@ int regulatory_init(void)
        spin_lock_init(&reg_requests_lock);
        spin_lock_init(&reg_pending_beacons_lock);
 
-#ifdef CONFIG_WIRELESS_OLD_REGULATORY
-       cfg80211_regdomain = static_regdom(ieee80211_regdom);
-
-       printk(KERN_INFO "cfg80211: Using static regulatory domain info\n");
-       print_regdomain_info(cfg80211_regdomain);
-#else
        cfg80211_regdomain = cfg80211_world_regdom;
 
-#endif
        /* We always try to get an update for the static regdomain */
        err = regulatory_hint_core(cfg80211_regdomain->alpha2);
        if (err) {
index 3362c7c069b2161aa2bc2d296d597803303bbb2e..3018508226ab3efae623bef25112347f9d92b9ae 100644 (file)
@@ -41,14 +41,25 @@ int regulatory_hint_found_beacon(struct wiphy *wiphy,
  * regulatory_hint_11d - hints a country IE as a regulatory domain
  * @wiphy: the wireless device giving the hint (used only for reporting
  *     conflicts)
+ * @band: the band on which the country IE was received on. This determines
+ *     the band we'll process the country IE channel triplets for.
  * @country_ie: pointer to the country IE
  * @country_ie_len: length of the country IE
  *
  * We will intersect the rd with the what CRDA tells us should apply
  * for the alpha2 this country IE belongs to, this prevents APs from
  * sending us incorrect or outdated information against a country.
+ *
+ * The AP is expected to provide Country IE channel triplets for the
+ * band it is on. It is technically possible for APs to send channel
+ * country IE triplets even for channels outside of the band they are
+ * in but for that they would have to use the regulatory extension
+ * in combination with a triplet but this behaviour is currently
+ * not observed. For this reason if a triplet is seen with channel
+ * information for a band the BSS is not present in it will be ignored.
  */
 void regulatory_hint_11d(struct wiphy *wiphy,
+                        enum ieee80211_band band,
                         u8 *country_ie,
                         u8 country_ie_len);
 
diff --git a/net/wireless/regdb.h b/net/wireless/regdb.h
new file mode 100644 (file)
index 0000000..818222c
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef __REGDB_H__
+#define __REGDB_H__
+
+extern const struct ieee80211_regdomain *reg_regdb[];
+extern int reg_regdb_size;
+
+#endif /* __REGDB_H__ */
index 0c2cbbebca95572d3897a30285aa03f9032f814e..06b0231ee5e3145db236ca4ccaff2d34ac0ff3f5 100644 (file)
@@ -100,8 +100,10 @@ static void bss_release(struct kref *ref)
        if (bss->pub.free_priv)
                bss->pub.free_priv(&bss->pub);
 
-       if (bss->ies_allocated)
-               kfree(bss->pub.information_elements);
+       if (bss->beacon_ies_allocated)
+               kfree(bss->pub.beacon_ies);
+       if (bss->proberesp_ies_allocated)
+               kfree(bss->pub.proberesp_ies);
 
        BUG_ON(atomic_read(&bss->hold));
 
@@ -375,8 +377,7 @@ rb_find_bss(struct cfg80211_registered_device *dev,
 
 static struct cfg80211_internal_bss *
 cfg80211_bss_update(struct cfg80211_registered_device *dev,
-                   struct cfg80211_internal_bss *res,
-                   bool overwrite)
+                   struct cfg80211_internal_bss *res)
 {
        struct cfg80211_internal_bss *found = NULL;
        const u8 *meshid, *meshcfg;
@@ -418,28 +419,64 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
                found->pub.capability = res->pub.capability;
                found->ts = res->ts;
 
-               /* overwrite IEs */
-               if (overwrite) {
+               /* Update IEs */
+               if (res->pub.proberesp_ies) {
                        size_t used = dev->wiphy.bss_priv_size + sizeof(*res);
-                       size_t ielen = res->pub.len_information_elements;
+                       size_t ielen = res->pub.len_proberesp_ies;
+
+                       if (found->pub.proberesp_ies &&
+                           !found->proberesp_ies_allocated &&
+                           ksize(found) >= used + ielen) {
+                               memcpy(found->pub.proberesp_ies,
+                                      res->pub.proberesp_ies, ielen);
+                               found->pub.len_proberesp_ies = ielen;
+                       } else {
+                               u8 *ies = found->pub.proberesp_ies;
+
+                               if (found->proberesp_ies_allocated)
+                                       ies = krealloc(ies, ielen, GFP_ATOMIC);
+                               else
+                                       ies = kmalloc(ielen, GFP_ATOMIC);
+
+                               if (ies) {
+                                       memcpy(ies, res->pub.proberesp_ies,
+                                              ielen);
+                                       found->proberesp_ies_allocated = true;
+                                       found->pub.proberesp_ies = ies;
+                                       found->pub.len_proberesp_ies = ielen;
+                               }
+                       }
 
-                       if (!found->ies_allocated && ksize(found) >= used + ielen) {
-                               memcpy(found->pub.information_elements,
-                                      res->pub.information_elements, ielen);
-                               found->pub.len_information_elements = ielen;
+                       /* Override possible earlier Beacon frame IEs */
+                       found->pub.information_elements =
+                               found->pub.proberesp_ies;
+                       found->pub.len_information_elements =
+                               found->pub.len_proberesp_ies;
+               }
+               if (res->pub.beacon_ies) {
+                       size_t used = dev->wiphy.bss_priv_size + sizeof(*res);
+                       size_t ielen = res->pub.len_beacon_ies;
+
+                       if (found->pub.beacon_ies &&
+                           !found->beacon_ies_allocated &&
+                           ksize(found) >= used + ielen) {
+                               memcpy(found->pub.beacon_ies,
+                                      res->pub.beacon_ies, ielen);
+                               found->pub.len_beacon_ies = ielen;
                        } else {
-                               u8 *ies = found->pub.information_elements;
+                               u8 *ies = found->pub.beacon_ies;
 
-                               if (found->ies_allocated)
+                               if (found->beacon_ies_allocated)
                                        ies = krealloc(ies, ielen, GFP_ATOMIC);
                                else
                                        ies = kmalloc(ielen, GFP_ATOMIC);
 
                                if (ies) {
-                                       memcpy(ies, res->pub.information_elements, ielen);
-                                       found->ies_allocated = true;
-                                       found->pub.information_elements = ies;
-                                       found->pub.len_information_elements = ielen;
+                                       memcpy(ies, res->pub.beacon_ies,
+                                              ielen);
+                                       found->beacon_ies_allocated = true;
+                                       found->pub.beacon_ies = ies;
+                                       found->pub.len_beacon_ies = ielen;
                                }
                        }
                }
@@ -489,14 +526,26 @@ cfg80211_inform_bss(struct wiphy *wiphy,
        res->pub.tsf = timestamp;
        res->pub.beacon_interval = beacon_interval;
        res->pub.capability = capability;
-       /* point to after the private area */
-       res->pub.information_elements = (u8 *)res + sizeof(*res) + privsz;
-       memcpy(res->pub.information_elements, ie, ielen);
-       res->pub.len_information_elements = ielen;
+       /*
+        * Since we do not know here whether the IEs are from a Beacon or Probe
+        * Response frame, we need to pick one of the options and only use it
+        * with the driver that does not provide the full Beacon/Probe Response
+        * frame. Use Beacon frame pointer to avoid indicating that this should
+        * override the information_elements pointer should we have received an
+        * earlier indication of Probe Response data.
+        *
+        * The initial buffer for the IEs is allocated with the BSS entry and
+        * is located after the private area.
+        */
+       res->pub.beacon_ies = (u8 *)res + sizeof(*res) + privsz;
+       memcpy(res->pub.beacon_ies, ie, ielen);
+       res->pub.len_beacon_ies = ielen;
+       res->pub.information_elements = res->pub.beacon_ies;
+       res->pub.len_information_elements = res->pub.len_beacon_ies;
 
        kref_init(&res->ref);
 
-       res = cfg80211_bss_update(wiphy_to_dev(wiphy), res, 0);
+       res = cfg80211_bss_update(wiphy_to_dev(wiphy), res);
        if (!res)
                return NULL;
 
@@ -517,7 +566,6 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy,
        struct cfg80211_internal_bss *res;
        size_t ielen = len - offsetof(struct ieee80211_mgmt,
                                      u.probe_resp.variable);
-       bool overwrite;
        size_t privsz = wiphy->bss_priv_size;
 
        if (WARN_ON(wiphy->signal_type == NL80211_BSS_SIGNAL_UNSPEC &&
@@ -538,16 +586,28 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy,
        res->pub.tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp);
        res->pub.beacon_interval = le16_to_cpu(mgmt->u.probe_resp.beacon_int);
        res->pub.capability = le16_to_cpu(mgmt->u.probe_resp.capab_info);
-       /* point to after the private area */
-       res->pub.information_elements = (u8 *)res + sizeof(*res) + privsz;
-       memcpy(res->pub.information_elements, mgmt->u.probe_resp.variable, ielen);
-       res->pub.len_information_elements = ielen;
+       /*
+        * The initial buffer for the IEs is allocated with the BSS entry and
+        * is located after the private area.
+        */
+       if (ieee80211_is_probe_resp(mgmt->frame_control)) {
+               res->pub.proberesp_ies = (u8 *) res + sizeof(*res) + privsz;
+               memcpy(res->pub.proberesp_ies, mgmt->u.probe_resp.variable,
+                      ielen);
+               res->pub.len_proberesp_ies = ielen;
+               res->pub.information_elements = res->pub.proberesp_ies;
+               res->pub.len_information_elements = res->pub.len_proberesp_ies;
+       } else {
+               res->pub.beacon_ies = (u8 *) res + sizeof(*res) + privsz;
+               memcpy(res->pub.beacon_ies, mgmt->u.beacon.variable, ielen);
+               res->pub.len_beacon_ies = ielen;
+               res->pub.information_elements = res->pub.beacon_ies;
+               res->pub.len_information_elements = res->pub.len_beacon_ies;
+       }
 
        kref_init(&res->ref);
 
-       overwrite = ieee80211_is_probe_resp(mgmt->frame_control);
-
-       res = cfg80211_bss_update(wiphy_to_dev(wiphy), res, overwrite);
+       res = cfg80211_bss_update(wiphy_to_dev(wiphy), res);
        if (!res)
                return NULL;
 
index dc0fc4989d54b1f92738ead9f911f309db863372..745c37e7992e1e410972dcfff89b332fdf619f30 100644 (file)
@@ -454,6 +454,7 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
         * - and country_ie[1] which is the IE length
         */
        regulatory_hint_11d(wdev->wiphy,
+                           bss->channel->band,
                            country_ie + 2,
                            country_ie[1]);
 }
index 59361fdcb5d03898b8d16ce5c7fbe637954a8cbf..23557c1d0a9caafd0e8c7b211846c9bd0f8a32b0 100644 (file)
@@ -285,7 +285,7 @@ static int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr)
        }
 }
 
-int ieee80211_data_to_8023(struct sk_buff *skb, u8 *addr,
+int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
                           enum nl80211_iftype iftype)
 {
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
@@ -383,7 +383,7 @@ int ieee80211_data_to_8023(struct sk_buff *skb, u8 *addr,
 }
 EXPORT_SYMBOL(ieee80211_data_to_8023);
 
-int ieee80211_data_from_8023(struct sk_buff *skb, u8 *addr,
+int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr,
                             enum nl80211_iftype iftype, u8 *bssid, bool qos)
 {
        struct ieee80211_hdr hdr;
@@ -497,6 +497,101 @@ int ieee80211_data_from_8023(struct sk_buff *skb, u8 *addr,
 }
 EXPORT_SYMBOL(ieee80211_data_from_8023);
 
+
+void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
+                             const u8 *addr, enum nl80211_iftype iftype,
+                             const unsigned int extra_headroom)
+{
+       struct sk_buff *frame = NULL;
+       u16 ethertype;
+       u8 *payload;
+       const struct ethhdr *eth;
+       int remaining, err;
+       u8 dst[ETH_ALEN], src[ETH_ALEN];
+
+       err = ieee80211_data_to_8023(skb, addr, iftype);
+       if (err)
+               goto out;
+
+       /* skip the wrapping header */
+       eth = (struct ethhdr *) skb_pull(skb, sizeof(struct ethhdr));
+       if (!eth)
+               goto out;
+
+       while (skb != frame) {
+               u8 padding;
+               __be16 len = eth->h_proto;
+               unsigned int subframe_len = sizeof(struct ethhdr) + ntohs(len);
+
+               remaining = skb->len;
+               memcpy(dst, eth->h_dest, ETH_ALEN);
+               memcpy(src, eth->h_source, ETH_ALEN);
+
+               padding = (4 - subframe_len) & 0x3;
+               /* the last MSDU has no padding */
+               if (subframe_len > remaining)
+                       goto purge;
+
+               skb_pull(skb, sizeof(struct ethhdr));
+               /* reuse skb for the last subframe */
+               if (remaining <= subframe_len + padding)
+                       frame = skb;
+               else {
+                       unsigned int hlen = ALIGN(extra_headroom, 4);
+                       /*
+                        * Allocate and reserve two bytes more for payload
+                        * alignment since sizeof(struct ethhdr) is 14.
+                        */
+                       frame = dev_alloc_skb(hlen + subframe_len + 2);
+                       if (!frame)
+                               goto purge;
+
+                       skb_reserve(frame, hlen + sizeof(struct ethhdr) + 2);
+                       memcpy(skb_put(frame, ntohs(len)), skb->data,
+                               ntohs(len));
+
+                       eth = (struct ethhdr *)skb_pull(skb, ntohs(len) +
+                                                       padding);
+                       if (!eth) {
+                               dev_kfree_skb(frame);
+                               goto purge;
+                       }
+               }
+
+               skb_reset_network_header(frame);
+               frame->dev = skb->dev;
+               frame->priority = skb->priority;
+
+               payload = frame->data;
+               ethertype = (payload[6] << 8) | payload[7];
+
+               if (likely((compare_ether_addr(payload, rfc1042_header) == 0 &&
+                           ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) ||
+                          compare_ether_addr(payload,
+                                             bridge_tunnel_header) == 0)) {
+                       /* remove RFC1042 or Bridge-Tunnel
+                        * encapsulation and replace EtherType */
+                       skb_pull(frame, 6);
+                       memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN);
+                       memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN);
+               } else {
+                       memcpy(skb_push(frame, sizeof(__be16)), &len,
+                               sizeof(__be16));
+                       memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN);
+                       memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN);
+               }
+               __skb_queue_tail(list, frame);
+       }
+
+       return;
+
+ purge:
+       __skb_queue_purge(list);
+ out:
+       dev_kfree_skb(skb);
+}
+EXPORT_SYMBOL(ieee80211_amsdu_to_8023s);
+
 /* Given a data frame determine the 802.1p/1d tag to use. */
 unsigned int cfg80211_classify8021d(struct sk_buff *skb)
 {
@@ -720,3 +815,36 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
 
        return err;
 }
+
+u16 cfg80211_calculate_bitrate(struct rate_info *rate)
+{
+       int modulation, streams, bitrate;
+
+       if (!(rate->flags & RATE_INFO_FLAGS_MCS))
+               return rate->legacy;
+
+       /* the formula below does only work for MCS values smaller than 32 */
+       if (rate->mcs >= 32)
+               return 0;
+
+       modulation = rate->mcs & 7;
+       streams = (rate->mcs >> 3) + 1;
+
+       bitrate = (rate->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH) ?
+                       13500000 : 6500000;
+
+       if (modulation < 4)
+               bitrate *= (modulation + 1);
+       else if (modulation == 4)
+               bitrate *= (modulation + 2);
+       else
+               bitrate *= (modulation + 3);
+
+       bitrate *= streams;
+
+       if (rate->flags & RATE_INFO_FLAGS_SHORT_GI)
+               bitrate = (bitrate / 9) * 10;
+
+       /* do NOT round down here */
+       return (bitrate + 50000) / 100000;
+}
index 54face3d4424c973ab6b297ea9582daba6c0beab..966d2f01beac2a26060df2bd284369fc3656f251 100644 (file)
@@ -1204,21 +1204,47 @@ int cfg80211_wext_siwrate(struct net_device *dev,
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
        struct cfg80211_bitrate_mask mask;
+       u32 fixed, maxrate;
+       struct ieee80211_supported_band *sband;
+       int band, ridx;
+       bool match = false;
 
        if (!rdev->ops->set_bitrate_mask)
                return -EOPNOTSUPP;
 
-       mask.fixed = 0;
-       mask.maxrate = 0;
+       memset(&mask, 0, sizeof(mask));
+       fixed = 0;
+       maxrate = 0;
 
        if (rate->value < 0) {
                /* nothing */
        } else if (rate->fixed) {
-               mask.fixed = rate->value / 1000; /* kbps */
+               fixed = rate->value / 100000;
        } else {
-               mask.maxrate = rate->value / 1000; /* kbps */
+               maxrate = rate->value / 100000;
        }
 
+       for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+               sband = wdev->wiphy->bands[band];
+               if (sband == NULL)
+                       continue;
+               for (ridx = 0; ridx < sband->n_bitrates; ridx++) {
+                       struct ieee80211_rate *srate = &sband->bitrates[ridx];
+                       if (fixed == srate->bitrate) {
+                               mask.control[band].legacy = 1 << ridx;
+                               match = true;
+                               break;
+                       }
+                       if (srate->bitrate <= maxrate) {
+                               mask.control[band].legacy |= 1 << ridx;
+                               match = true;
+                       }
+               }
+       }
+
+       if (!match)
+               return -EINVAL;
+
        return rdev->ops->set_bitrate_mask(wdev->wiphy, dev, NULL, &mask);
 }
 EXPORT_SYMBOL_GPL(cfg80211_wext_siwrate);
@@ -1257,10 +1283,7 @@ int cfg80211_wext_giwrate(struct net_device *dev,
        if (!(sinfo.filled & STATION_INFO_TX_BITRATE))
                return -EOPNOTSUPP;
 
-       rate->value = 0;
-
-       if (!(sinfo.txrate.flags & RATE_INFO_FLAGS_MCS))
-               rate->value = 100000 * sinfo.txrate.legacy;
+       rate->value = 100000 * cfg80211_calculate_bitrate(&sinfo.txrate);
 
        return 0;
 }
index 273a7f77c8340ce876655a06ee570b5fa687b2f1..8bafa31fa9f83d25909770b6b0202d6e2a282a37 100644 (file)
@@ -140,7 +140,7 @@ static const struct file_operations wireless_seq_fops = {
        .release = seq_release_net,
 };
 
-int wext_proc_init(struct net *net)
+int __net_init wext_proc_init(struct net *net)
 {
        /* Create /proc/net/wireless entry */
        if (!proc_net_fops_create(net, "wireless", S_IRUGO, &wireless_seq_fops))
@@ -149,7 +149,7 @@ int wext_proc_init(struct net *net)
        return 0;
 }
 
-void wext_proc_exit(struct net *net)
+void __net_exit wext_proc_exit(struct net *net)
 {
        proc_net_remove(net, "wireless");
 }
index fef8db553e8d63b3f0859459f59d0c4103663ad3..c083a4e4e796d277511ff7c90d8d8b2d3d7a7cb5 100644 (file)
@@ -15,7 +15,7 @@
 #include <net/snmp.h>
 #include <net/xfrm.h>
 
-static struct snmp_mib xfrm_mib_list[] = {
+static const struct snmp_mib xfrm_mib_list[] = {
        SNMP_MIB_ITEM("XfrmInError", LINUX_MIB_XFRMINERROR),
        SNMP_MIB_ITEM("XfrmInBufferError", LINUX_MIB_XFRMINBUFFERERROR),
        SNMP_MIB_ITEM("XfrmInHdrError", LINUX_MIB_XFRMINHDRERROR),
index 2e221f2cad7e150c52655b30e72d0e8efdd99333..2c4d6cdcba492cd2f70ac32a3e71b5b0abd17691 100644 (file)
@@ -2,7 +2,7 @@
 #include <net/net_namespace.h>
 #include <net/xfrm.h>
 
-static void __xfrm_sysctl_init(struct net *net)
+static void __net_init __xfrm_sysctl_init(struct net *net)
 {
        net->xfrm.sysctl_aevent_etime = XFRM_AE_ETIME;
        net->xfrm.sysctl_aevent_rseqth = XFRM_AE_SEQT_SIZE;
@@ -64,7 +64,7 @@ out_kmemdup:
        return -ENOMEM;
 }
 
-void xfrm_sysctl_fini(struct net *net)
+void __net_exit xfrm_sysctl_fini(struct net *net)
 {
        struct ctl_table *table;